using System; using System.Collections.Generic; using UnityEngine; namespace BF { public class AssetBundleLoader : LoaderBase { private Dictionary assetbundleCache; //所有assetbundleobject对象缓存 private Dictionary waitABComplete; //等待对应ab加载的资源 private BFQueue waitLoadQueue; //等待加载队列 private int waitLoadCount; //等待加载队列数量 private List loadingArray; //加载中 private int loadingCount; //正在加载数量 private List delayUnload; //延迟卸载列表 public const int MAX_LOADING = 120; private Action loadABComplete; public AssetBundleConfigCollection Config { get { return BFMain.Instance.ResMgr.AbConfigCollection; } } public AssetBundleManifest Manifest { get { return BFMain.Instance.ResMgr.Manifest; } } public AssetBundleLoader() { loadABComplete = LoadABComplete; assetbundleCache = new Dictionary(32); // 预分配空间 waitABComplete = new Dictionary(); waitLoadQueue = new BFQueue(); loadingArray = new List(MAX_LOADING); // 最多同时加载120个bundle,可以考虑配置在机型性能分档上面,猜测unity内部也做了max_loading机制 delayUnload = new List(); } public override AssetObject LoadAssetAsync(string assetPath, Type type, Action complete) { BFLog.LogDebug(BFLog.DEBUG_RESMGR, "green", "[ResMgr] AssetObject LoadAssetAsync, assetpath : {0}, type = {1} ", assetPath, type); var assetObject = new AssetObject(assetPath, type); LoadAssetAsyncByConfig(assetObject); return assetObject; } /// /// 对象加载出错后,再次加载 /// /// public override void LoadAssetAsync(AssetObject assetObject) { //LoadStatus != Unloading 后,会自动从delayunload列表移除 LoadAssetAsyncByConfig(assetObject); } /// /// 加载依赖bundle /// public void LoadDependBundleAsync(string bundlePath, Action complete) { BFLog.LogDebug(BFLog.DEBUG_RESMGR, "green", "[ResMgr] LoadDependBundleAsync, bundlePath : {0} ", bundlePath); LoadBundleAsync(bundlePath, complete); } public void LoadBundleAsync(string bundlePath, Action complete) { var cfg = Config.GetConfigByBundlePath(bundlePath); LoadBundleAsync(cfg, complete); } private void LoadAssetAsyncByConfig(AssetObject assetObject) { var assetPath = assetObject.AssetPath; BFLog.LogAssert(!waitABComplete.ContainsKey(assetPath), "[ResMgr] Load Asset already waiting! asset path : {0}", assetPath); waitABComplete.Add(assetPath, assetObject); var cfg = Config.GetConfigByAssetPath(assetPath); LoadBundleAsync(cfg, loadABComplete); } private AssetBundleObject LoadBundleAsync(AssetBundleConfig bundleConfig, Action complete) { if (bundleConfig == null) { return null; } assetbundleCache.TryGetValue(bundleConfig.assetBundlePath, out AssetBundleObject abo); if (abo == null) //没有加载或者已经卸载,则加入加载队列,等待开始加载 { abo = new AssetBundleObject(bundleConfig, this); abo.LoadStatus = EAssetLoadStatus.Wait; assetbundleCache.Add(bundleConfig.assetBundlePath, abo); waitLoadQueue.Enqueue(abo); ++waitLoadCount; } else if (EAssetLoadStatus.Error == abo.LoadStatus) //上一次加载已经完成,但是出错了 { abo.LoadStatus = EAssetLoadStatus.Wait; waitLoadQueue.Enqueue(abo); ++waitLoadCount; } abo.LoadBundleAsync(complete); return abo; } private void LoadABComplete(AssetBundleObject abo) { BFLog.LogDebug(BFLog.DEBUG_RESMGR, "green", "LoadABComplete assetpath : {0}. status : {1}, assetbundle : {2}, use time : {3}", abo.AssetPath, abo.LoadStatus, abo.Assetbundle, Time.time - abo.Timeout + ResourceManager.TIME_OUT_LOAD); var ab = abo.Assetbundle; var assetPath = abo.AssetBundleConfig.assetsPath; for (int i = 0; i < assetPath.Length; i++) { var p = assetPath[i]; if (waitABComplete.TryGetValue(p, out AssetObject ao)) { ao.StartLoadAsset(ab); waitABComplete.Remove(p); } } } public override void LoadAssetSync(AssetObject assetObject) { var cfg = Config.GetConfigByAssetPath(assetObject.AssetPath); assetObject.StartLoadAsset(LoadAssetSyncByConfig(cfg)); } public void LoadDependBundleSync(string bundlePath) { var cfg = Config.GetConfigByBundlePath(bundlePath); LoadAssetSyncByConfig(cfg, true); } public override AssetObject LoadAssetSync(string assetPath, Type type) { var assetObject = new AssetObject(assetPath, type, true); var cfg = Config.GetConfigByAssetPath(assetObject.AssetPath); assetObject.StartLoadAsset(LoadAssetSyncByConfig(cfg)); return assetObject; } private AssetBundle LoadAssetSyncByConfig(AssetBundleConfig cfg, bool isDepend = false) { assetbundleCache.TryGetValue(cfg.assetBundlePath, out AssetBundleObject abo); if (abo == null) { abo = new AssetBundleObject(cfg, this); assetbundleCache.Add(cfg.assetBundlePath, abo); abo.LoadSync(); } else if (abo.LoadStatus != EAssetLoadStatus.Complete) { var status = abo.LoadStatus; if (EAssetLoadStatus.Wait == status) { waitLoadQueue.Remove(abo); --waitLoadCount; } else if (EAssetLoadStatus.Loading == status) { var index = loadingArray.IndexOf(abo); if (index > -1) { loadingArray.RemoveAt(index); --loadingCount; } } abo.LoadSync(isDepend); } else { abo.LoadSync(isDepend); } loadABComplete(abo); return abo.Assetbundle; } public override void Unload(AssetObject asset, bool immediately) { BFLog.LogDebug(BFLog.DEBUG_RESMGR, "green", "[ResMgr] assetbundleloader Unload asset : {0}, LoadStatus : {1}", asset.AssetPath, asset.LoadStatus); if (EAssetLoadStatus.Unloading == asset.LoadStatus) { return; } if (EAssetLoadStatus.Unloaded == asset.LoadStatus) { resMgr.RemoveAsset(asset.AssetPath); UnLoadBundle(asset, immediately); } else if (asset.Unload(immediately)) { delayUnload.Add(asset); } } public void UnLoadBundle(AssetObject assetObject, bool immediately) { var bundleConfig = Config.GetConfigByAssetPath(assetObject.AssetPath); if (null == bundleConfig) { return; } UnLoadBundle(bundleConfig.assetBundlePath, immediately, assetObject.UnloadAsset); } public void UnLoadBundle(string assetBundlePath, bool immediately) { BFLog.LogDebug(BFLog.DEBUG_RESMGR, "green", "[ResMgr] assetbundleloader Unload bundle : {0}, immediately : {1}", assetBundlePath, immediately); if (assetbundleCache.TryGetValue(assetBundlePath, out AssetBundleObject abo)) { if (abo.Unload(immediately)) { delayUnload.Add(abo); } } } public void UnLoadBundle(string assetBundlePath, bool immediately, Action unloadCallback) { BFLog.LogDebug(BFLog.DEBUG_RESMGR, "green", "[ResMgr] assetbundleloader Unload bundle : {0}, immediately : {1}", assetBundlePath, immediately); if (assetbundleCache.TryGetValue(assetBundlePath, out AssetBundleObject abo)) { abo.AddUnloadCallback(unloadCallback); if (abo.Unload(immediately)) { delayUnload.Add(abo); } } } public void RemoveCache(AssetBundleObject abo) { if (assetbundleCache.ContainsKey(abo.AssetPath)) { assetbundleCache.Remove(abo.AssetPath); } } public override void Tick() { TickLoad(); TickDelayUnload(false); } void TickLoad() { //准备加载 //当加载队列没有达到最大加载数的时候,从waitload队列放入元素 while (loadingCount < MAX_LOADING && waitLoadCount > 0) { var abObject = waitLoadQueue.Dequeue().item; --waitLoadCount; loadingArray.Add(abObject); ++loadingCount; abObject.StartLoadAsync(); } //检查加载中资源是否完成 for (int i = 0; i < loadingCount;) { var abObject = loadingArray[i]; if (abObject.Tick()) //加载结束 { var lastIndex = loadingCount - 1; var temp = loadingArray[lastIndex]; loadingArray[lastIndex] = abObject; loadingArray[i] = temp; loadingArray.RemoveAt(lastIndex); --loadingCount; } else { ++i; } } } void TickDelayUnload(bool immediately) { var length = delayUnload.Count; for (int i = 0; i < length;) { var unload = delayUnload[i]; unload.UnloadCountdown(immediately); //卸载完成,或者卸载过程中,重新被加载使用 if (EAssetLoadStatus.Unloaded == unload.LoadStatus || EAssetLoadStatus.Unloading != unload.LoadStatus) { delayUnload.RemoveAt(i); --length; } else { ++i; } } } public override void UnloadAllDelayAssets() { BFLog.LogDebug("yellow", "UnloadAllDelayImmediately"); TickDelayUnload(true); } public override string GetSceneLoadPath(string assetBundlePath) { assetbundleCache.TryGetValue(assetBundlePath, out AssetBundleObject abo); if (abo == null) { return assetBundlePath; } else { var scenePaths = abo.Assetbundle.GetAllScenePaths(); return scenePaths[0]; } } public override void LoadSceneAsync(string assetBundlePath, Action complete) { LoadBundleAsync(assetBundlePath, complete); } public override void UnloadScene(string assetBundlePath) { UnLoadBundle(assetBundlePath, true); } public override void Clear() { foreach (var abo in assetbundleCache.Values) { abo.Assetbundle.Unload(false); } assetbundleCache.Clear(); waitABComplete.Clear(); waitLoadQueue.Clear(); waitLoadCount = 0; loadingArray.Clear(); loadingCount = 0; delayUnload.Clear(); } public override bool ContainsAsset(string assetPath) { var cfg = Config.GetConfigByAssetPath(assetPath); return cfg != null; } } }