using UnityEngine;
using System.Collections;
using System.Collections.Generic;
namespace CommonUnity3D.XMUnity.LoadUtil
{
///
/// XMUnityAssetBundle加载管理器.
///
public class XMUnityAssetBundleManager : MonoBehaviour
{
private static XMUnityAssetBundleManager mInstance = null;
private Dictionary mABMap = null;
private Dictionary mLoadTaskMap = null;
public AssetBundleManifest Manifest { get; private set; }
public List ShaderList { get; private set; }
private Dictionary> mDepsList = new Dictionary>();
public int PrefabCapacity = 50;
private bool mNeedCleanUp = false;
private List mTempLoadTask = null;
private AsyncOperation mUnloadOp = null;
private bool mNeedUnload = false;
void Awake()
{
mInstance = this;
Init();
}
void Start()
{
}
void Update()
{
//检查加载任务
mTempLoadTask = new List(mLoadTaskMap.Values);
var iter = mTempLoadTask.GetEnumerator();
while (iter.MoveNext())
{
if(iter.Current.OnAdapterUpdate())
{
iter.Current.Dispose();
mLoadTaskMap.Remove(iter.Current.GetURL());
}
}
mTempLoadTask.Clear();
//是否存在加载任务
bool isLoading = false;
if (mLoadTaskMap.Count == 0)
{
var item = mABMap.GetEnumerator();
while (item.MoveNext())
{
if (item.Current.Value.BundleStatus == XMUnityAssetBundle.Status.LoadAsset || item.Current.Value.BundleStatus == XMUnityAssetBundle.Status.LoadDep)
{
isLoading = true;
break;
}
}
}
else
{
isLoading = true;
}
//在合适的时候执行Cleanup
if (!isLoading && mNeedCleanUp)
{
CleanAssetBundleMap(false);
//Resources.UnloadUnusedAssets ();
System.GC.Collect();
mNeedCleanUp = false;
}
//检查unload进度
if(mUnloadOp != null && mUnloadOp.isDone)
{
mUnloadOp = null;
}
//在合适的时候执行unload
if (!isLoading && mNeedUnload)
{
mUnloadOp = Resources.UnloadUnusedAssets();
mNeedUnload = false;
}
}
private void Init()
{
mABMap = new Dictionary();
mLoadTaskMap = new Dictionary();
mTempLoadTask = new List();
ShaderList = new List();
StartLoadManifest();
StartLoadShaderList();
}
void StartLoadManifest()
{
XMUnityABLoadAdapter load = new XMUnityABLoadAdapter();
load.LoadAsync = false;
load.SetFinishCallBack(OnManifestFinish);
load.Load("/res/" + GetPlatformForAssetBundles(), null);
StartCoroutine(CheckLoadManifest(load));
}
IEnumerator CheckLoadManifest(XMUnityABLoadAdapter load)
{
while (!load.HasDone)
{
load.OnAdapterUpdate();
yield return null;
}
}
private void OnManifestFinish(XMUnityABLoadAdapter adapter)
{
if (adapter.GetAssetBundle() != null)
{
Manifest = adapter.GetAssetBundle().LoadAsset("AssetBundleManifest");
}
else
{
Debug.LogError("XMUnityAssetBundleManager can not find Manifest");
}
}
void StartLoadShaderList()
{
XMUnityABLoadAdapter load = new XMUnityABLoadAdapter();
load.LoadAsync = false;
load.SetFinishCallBack(OnShaderListFinish);
load.Load("/res/shaderslist.assetbundles", null);
StartCoroutine(CheckLoadShaderList(load));
}
IEnumerator CheckLoadShaderList(XMUnityABLoadAdapter load)
{
while (!load.HasDone)
{
load.OnAdapterUpdate();
yield return null;
}
}
private void OnShaderListFinish(XMUnityABLoadAdapter adapter)
{
if (adapter.GetAssetBundle() != null)
{
Object[] shaderobject = adapter.GetAssetBundle().LoadAllAssets();
foreach (Object sb in shaderobject)
{
if (sb is Shader)
{
ShaderList.Add((Shader)sb);
}
else
{
Debug.Log("ShaderList add dif type=" + sb.GetType());
}
}
Shader.WarmupAllShaders();
}
else
{
Debug.LogWarning("XMUnityAssetBundleManager can not find ShaderList");
}
}
public void Dispose()
{
CleanAssetBundleMap(true);
mInstance = null;
}
public static XMUnityAssetBundleManager GetInstance()
{
if (mInstance == null)
{
Debug.LogError("XMUnityAssetBundleManager must create before use");
}
return mInstance;
}
public void UnloadUnusedAssets()
{
if(mUnloadOp == null)
{
mNeedUnload = true;
}
}
public List GetDepList(string name)
{
name = name.ToLower();
string dep_key = name.ToLower().Replace("/res/", "");
if (!mDepsList.ContainsKey(name))
{
string[] deps = Manifest.GetAllDependencies(dep_key);
List ds = new List(deps.Length);
for (int i = 0; i < deps.Length; i++)
{
if(deps[i] != "shaderslist.assetbundles")
{
string key = "/res/" + deps[i];
//if (name != key)
//{
ds.Add(key);
//}
//else
//{
// Debug.LogError("what the fuck");
//}
}
}
mDepsList[name] = (ds);
}
return mDepsList[name];
}
public void GetAssetBundle(string name, XMUnityABLoadAdapter.XMUnityLoadAdapterCallBack callBack, bool async = true)
{
name = name.ToLower();
XMUnityAssetBundle ab = null;
XMUnityABLoadAdapter adapter = null;
if (mABMap.TryGetValue(name, out ab)) //从AB中寻找AssetBundle.
{
if (callBack != null)
{
callBack.Invoke(ab);
//return null;
}
}
else if (mLoadTaskMap.TryGetValue(name, out adapter)) //从正在加载的map中寻找.
{
if (callBack != null)
{
adapter.AddCallBack(callBack);
}
//return null;
}
else //创建加载器.
{
XMUnityABLoadAdapter load = new XMUnityABLoadAdapter();
load.LoadAsync = async;
mLoadTaskMap.Add(name, load);
load.SetFinishCallBack(OnAdapterFinish);
load.Load(name, callBack);
//return load;
}
//return null;
}
public AssetBundle GetAssetBundle(string name)
{
name = name.ToLower();
XMUnityAssetBundle ret = null;
mABMap.TryGetValue(name, out ret);
return ret.AssetBundle;
}
public XMUnityAssetBundle GetXMUnityAssetBundle(string name)
{
name = name.ToLower();
XMUnityAssetBundle ret = null;
mABMap.TryGetValue(name, out ret);
if (ret == null)
{
return null;
}
return ret;
}
public bool AddAssetBundle(string name, XMUnityAssetBundle ab)
{
if (!string.IsNullOrEmpty(name) && ab != null)
{
mABMap.Add(name, ab);
return true;
}
Debug.Log("XMUnityAssetBundleManager AddAssetBundle Error: Invaild Data");
return false;
}
///
/// 将remove操作push到一个队列中执行,只有当当前没有加载任务时才会触发.
///
///
///
public void UnloadAssetBundle(string name, bool isUnloadAll = false, bool force = false)
{
XMUnityAssetBundle ab = null;
if (mABMap.TryGetValue(name, out ab))
{
if (ab != null)
{
if(ab.BundleType == XMUnityAssetBundle.Type.DEP_ASSET)
{
Debug.LogError("Cant unload a dep assetbundle: " + name);
}
List deps = GetDepList(name);
foreach (var item in deps)
{
XMUnityAssetBundle mfab = null;
if (mABMap.TryGetValue(item, out mfab))
{
if (mfab != null)
{
if (mfab.TryUnloadDep(name, isUnloadAll, force))
{
mABMap.Remove(item);
}
}
}
}
UnloadAssetBundleImmediate(name, isUnloadAll, force);
}
}
else
{
//通常只有切换场景时没有清除资源的情况下强制卸载了所有ab才会出,可以用来监控逻辑加载卸载成对的情况
Debug.LogWarning("[策划,测试请无视]UnloadAssetBundle Error, bundle not exists: " + name);
}
}
public void UnloadAssetBundleImmediate(string name, bool isUnloadAll, bool force = false)
{
// 内部自动处理
XMUnityAssetBundle ab = null;
if (mABMap.TryGetValue(name, out ab))
{
if (ab != null)
{
//TODO 销毁XMUnityAssetBundle,主要是缓存和prefab
if (ab.Unload(isUnloadAll, force))
{
mABMap.Remove(name);
}
}
}
else
{
Debug.LogWarning("[策划,测试请无视]UnloadAssetBundleImmediate Error, bundle not exists: " + name);
}
}
public void LoadDep(string name, bool loadABASync, bool loadAssetASync, XMUnityAssetBundle.LoadResCallBack callback, object userdata, string childAB)
{
XMUnityAssetBundleManager.GetInstance().GetAssetBundle(name, (XMUnityAssetBundle mfab) =>
{
if (mfab != null)
{
mfab.MarkAsDeps(childAB);
}
//else
{
callback(null, null, userdata, false);
}
}, loadABASync);
}
public void LoadAsset(string name, string asset, bool loadABASync, bool loadAssetASync, XMUnityAssetBundle.LoadResCallBack callback, object userdata, System.Type type = null)
{
GetAssetBundle(name, (XMUnityAssetBundle mfab) =>
{
if (mfab != null)
{
mfab.GetAsset(asset, loadAssetASync, callback, userdata, type);
}
else
{
callback(asset, null, userdata, false);
}
}, loadABASync);
}
public void LoadAsset(string name, bool loadABASync, bool loadAssetASync, XMUnityAssetBundle.LoadResCallBack callback, object userdata, System.Type type = null)
{
int starIndex = name.LastIndexOf('/') + 1;
int length = name.Length - starIndex - ".assetbundles".Length;
string objectName = name.Substring(starIndex, length);
LoadAsset(name.ToLower(), objectName, loadABASync, loadAssetASync, callback, userdata, type);
}
public void CleanAssetBundleMap(bool isUnloadAll)
{
var temp = new Dictionary();
foreach (KeyValuePair kvp in mABMap)
{
if (kvp.Value != null)
{
if(!kvp.Value.Unload(isUnloadAll, true))
{
temp.Add(kvp.Key, kvp.Value);
}
}
}
mABMap.Clear();
mABMap = temp;
AssetObject.ClearRefs();
}
public void CleanAssetBundleMapInQueue()
{
mNeedCleanUp = true;
}
private void OnAdapterFinish(XMUnityABLoadAdapter adapter)
{
XMUnityAssetBundle mfab = adapter.GetXMUnityAssetBundle();
if (mfab != null)
{
mABMap.Add(adapter.GetURL(), mfab);
}
if (mLoadTaskMap.ContainsKey(adapter.GetURL()))
{
mLoadTaskMap.Remove(adapter.GetURL());
}
else
{
Debug.Log("XMUnityAssetBundleManager can not find Adapter");
}
adapter.DispatchCallBack();
}
public bool ContainsBundle(string name) { return mABMap.ContainsKey(name); }
public static string GetPlatformForAssetBundles()
{
RuntimePlatform platform = Application.platform;
switch (platform)
{
case RuntimePlatform.Android:
return "android";
case RuntimePlatform.IPhonePlayer:
return "ios";
case RuntimePlatform.WebGLPlayer:
return "webgl";
case RuntimePlatform.OSXWebPlayer:
case RuntimePlatform.WindowsWebPlayer:
return "standalonewindows";
case RuntimePlatform.WindowsEditor:
#if UNITY_ANDROID
return "android";
#else
return "standalonewindows";
#endif
case RuntimePlatform.WindowsPlayer:
return "standalonewindows";
case RuntimePlatform.OSXPlayer:
return "osx";
default:
return null;
}
}
}
}