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; } } } }