using UnityEngine; using System.Collections; using System.Collections.Generic; using CommonUnity3D.XMUnity.LoadUtil; //依赖在外部维护比较好 //卸载依赖的逻辑需要用计数器 public class XMUnityAssetBundle { public string Name { get; private set; } private AssetBundle mAssetBundle = null; public AssetBundle AssetBundle { get { return mAssetBundle; } } Stack mCache = new Stack(); HashSet mChildAB = new HashSet(); Dictionary mPrefabs = new Dictionary(); private Status mBundleStatus = Status.NONE; public Status BundleStatus { get { return mBundleStatus; } } public int Version { get; private set; } private AssetBundleRequest Request = null; //System.Diagnostics.Stopwatch sw; public delegate void LoadResCallBack(string name, Object o, object userdata, bool isLoadOK); public class ABCallBackInfo { public string Name { get; set; } public LoadResCallBack CallBack { get; set; } public object UserData { get; set; } public ABCallBackInfo(string name, LoadResCallBack callback, object userdata) { this.Name = name; this.CallBack = callback; this.UserData = userdata; } } List mLoadingAssetTask = new List(); public enum Status { NONE, LoadDep, LoadDepDone, LoadAssetBundle, LoadAssetBundleDone, LoadAsset, LoadAssetDone, Unloaded, } public enum Type { MAIN_ASSET, DEP_ASSET, } private Type mType = Type.MAIN_ASSET; public Type BundleType { get { return mType; } } public XMUnityAssetBundle(string name) { Name = name; } public XMUnityAssetBundle(string name, AssetBundle ab, int version) { Name = name; mAssetBundle = ab; mBundleStatus = Status.LoadAssetBundleDone; Version = version; } bool AddChild(string name) { return mChildAB.Add(name); } bool RemoveChild(string name) { return mChildAB.Remove(name); } bool GetFromCache(out Object obj) { if(mCache.Count > 0) { obj = mCache.Pop(); return true; } else { obj = null; return false; } } void PushCache(Object obj) { mCache.Push(obj); } public Object GetAsset(string name) { Object obj = null; mPrefabs.TryGetValue(name, out obj); return obj; } //public void LoadAsset(string asset, bool isAsync) //{ // Object obj = null; // //缓存里没有现成的 // if (!GetFromCache(out obj)) // { // } //} public void GetAsset(string asset, bool isAsync, LoadResCallBack callback, object userdata, System.Type type = null) { Object o = null; if(mPrefabs.TryGetValue(asset, out o)) { callback(asset, o, userdata, true); } else { LoadAsset(asset, isAsync, callback, userdata, type); } } public void LoadAsset(string asset, bool isAsync, LoadResCallBack callback, object userdata, System.Type type = null) { //TODO 先按照之前的代码只支持一个AB1个物件,以后改成多个 if (mBundleStatus == Status.LoadAsset || mBundleStatus == Status.LoadAssetDone) { //Debug.Log("LoadAsset Done"); AddLoadingAssetTask(asset, callback, userdata); return; } if(type == null) { type = typeof(Object); } if(isAsync) { //sw = System.Diagnostics.Stopwatch.StartNew(); Request = mAssetBundle.LoadAssetAsync(asset, type); mBundleStatus = Status.LoadAsset; AddLoadingAssetTask(asset, callback, userdata); XMUnityAssetBundleManager.GetInstance().StartCoroutine(CheckRequestAsset(asset)); } else { //sw = System.Diagnostics.Stopwatch.StartNew(); if(mAssetBundle == null) { int i = 0; } Object o = mAssetBundle.LoadAsset(asset, type); if(o != null) { mPrefabs[asset] = o; mBundleStatus = Status.LoadAssetDone; callback(asset, o, userdata, true); } else { mBundleStatus = Status.LoadAssetDone; callback(asset, o, userdata, false); } } mType = Type.MAIN_ASSET; } void AddLoadingAssetTask(string asset, LoadResCallBack callback, object userdata) { ABCallBackInfo info = new ABCallBackInfo(asset, callback, userdata); mLoadingAssetTask.Add(info); } void DoLoadAssetCallback(Object asset, bool isLoadOK) { var iter = mLoadingAssetTask.GetEnumerator(); while (iter.MoveNext()) { iter.Current.CallBack(iter.Current.Name, asset, iter.Current.UserData, isLoadOK); } mLoadingAssetTask.Clear(); } public void LoadDeps(bool isAsync, LoadResCallBack callback, object userdata, string childAB) { //TODO 处理依赖关系 if(childAB != null) { mChildAB.Add(childAB); } if (mBundleStatus == Status.LoadDep) { AddLoadingAssetTask(null, callback, userdata); } else if(mBundleStatus == Status.LoadDepDone) { //Debug.Log("LoadDeps Done"); callback(null, null, userdata, true); } else { //sw = System.Diagnostics.Stopwatch.StartNew(); if (isAsync) { Request = mAssetBundle.LoadAllAssetsAsync(); mBundleStatus = Status.LoadDep; AddLoadingAssetTask(null, callback, userdata); XMUnityAssetBundleManager.GetInstance().StartCoroutine(CheckRequestDeps()); } else { mAssetBundle.LoadAllAssets(); mBundleStatus = Status.LoadDepDone; //sw.Stop(); //Debug.LogError("[zzzzzzzzzzzzzzzz] " + Name.ToString() + " "+sw.ElapsedMilliseconds/1000f); callback(null, null, userdata, true); } } mType = Type.DEP_ASSET; } public void MarkAsDeps(string childAB) { //TODO 处理依赖关系 if (childAB != null) { mChildAB.Add(childAB); } mBundleStatus = Status.LoadDepDone; mType = Type.DEP_ASSET; } public bool TryUnloadDep(string child, bool isUnloadAll = false, bool force = false) { if(mChildAB.Remove(child)) { if(mChildAB.Count < 1) { return Unload(isUnloadAll, force); //return true; } else { return false; } } else { Debug.LogWarning("[策划测试请无视]XMUnityAssetBundle TryUnloadDep Error! Child not exists: [" + child + "] parent: [" + Name + "]"); return false; } } public bool Unload(bool all, bool force = false) { //TODO 被其他包引用的包不能被Unload if(mBundleStatus == Status.NONE || mBundleStatus == Status.LoadAssetBundle || mBundleStatus == Status.LoadDep || mBundleStatus == Status.LoadAsset) { Debug.LogError("[策划测试请无视]XMUnityAssetBundle Unload Error! Status: " + mBundleStatus); return false; } if(force) { if(mType == Type.DEP_ASSET && mChildAB.Count > 0) { Debug.LogWarning("[策划测试请无视]XMUnityAssetBundle Force Unload Error! Child Referenced :" + Name + " " + mChildAB.Count); } } else { if (mType == Type.DEP_ASSET && mChildAB.Count > 0) { Debug.LogError("[策划测试请无视]XMUnityAssetBundle Unload Error! Child Referenced :" + Name + " " + mChildAB.Count); return false; } } //Debug.LogError("[Unload]" + Name + " " + all); mBundleStatus = Status.Unloaded; mPrefabs.Clear(); mAssetBundle.Unload(all); mAssetBundle = null; mChildAB.Clear(); return true; } IEnumerator CheckRequestDeps() { //if (Request != null) { while (!Request.isDone) { yield return null; } mBundleStatus = Status.LoadDepDone; Request = null; //sw.Stop(); //Debug.LogError("[zzzzzzzzzzzzzzzz] " + Name.ToString() + " "+sw.ElapsedMilliseconds/1000f); DoLoadAssetCallback(null, true); } } IEnumerator CheckRequestAsset(string asset) { //if (Request != null) { while (!Request.isDone) { yield return null; } Object o = Request.asset; //sw.Stop(); //Debug.LogError("[zzzzzzzzzzzzzzzz] " + Name.ToString() + " "+sw.ElapsedMilliseconds/1000f); if (o != null) { mPrefabs[asset] = o; mBundleStatus = Status.LoadAssetDone; Request = null; DoLoadAssetCallback(o, true); } else { mBundleStatus = Status.LoadAssetDone; Request = null; DoLoadAssetCallback(null, false); } } } }