using UnityEngine; using System; using System.Collections.Generic; using System.IO; namespace BF { public class AssetBundleObject : AssetObjectBase { public static Dictionary fullpathDict = new Dictionary(); public AssetBundleConfig AssetBundleConfig { get; private set; } public AssetBundle Assetbundle { get; private set; } private AssetBundleCreateRequest request; private BFEvent loadComplete; private BFEvent unloadComplete; public float Timeout { get; private set; } //异步加载的超时机制,保证不会一直卡在这里 private int recordDependCount; private string[] dependAB; private AssetBundleLoader assetBundleLoader; private bool dependABComplete = false; public AssetBundleObject(AssetBundleConfig config, AssetBundleLoader loader) : base(config.assetBundlePath, null) { AssetBundleConfig = config; assetBundleLoader = loader; loadComplete = new BFEvent(); unloadComplete = new BFEvent(); dependAB = loader.Manifest.GetAllDependencies(config.assetBundlePath); dependABComplete = dependAB.Length == 0; recordDependCount = dependAB.Length; for (int i = 0; i < dependAB.Length; i++) { BFLog.LogDebug(BFLog.DEBUG_RESMGR, "green", "[ResMgr] [AssetBundleObject] assetpath : {2} index : {0}, depend : {1}", i, dependAB[i], AssetPath); assetBundleLoader.LoadDependBundleAsync(dependAB[i], LoadCompleteDepenedAsset); } } public void LoadBundleAsync(Action callback) { ++RefCount; if (EAssetLoadStatus.Complete == LoadStatus || EAssetLoadStatus.Error == LoadStatus) { callback(this); } else if (EAssetLoadStatus.Unloading == LoadStatus) { LoadStatus = EAssetLoadStatus.Complete; callback(this); } else { loadComplete += callback; } } public void StartLoadAsync() { LoadStatus = EAssetLoadStatus.Loading; if (!fullpathDict.TryGetValue(AssetPath, out string fullpath)) { if (AssetBundleConfig.location == 1) { fullpath = Path.Combine(Application.persistentDataPath, "update", AssetPath); } else { fullpath = Path.Combine(Application.streamingAssetsPath, AssetPath); } fullpathDict.Add(AssetPath, fullpath); } request = AssetBundle.LoadFromFileAsync(fullpath); Timeout = ResourceManager.TIME_OUT_LOAD + Time.time; BFLog.LogDebug(BFLog.DEBUG_RESMGR, "green", "StartLoadAsync assetpath : {0}. timeout : {1}", fullpath, Timeout); } public void LoadSync(bool ignoreRefCount = false) { if (!ignoreRefCount) { ++RefCount; } if(EAssetLoadStatus.Complete == LoadStatus) { return; } if (EAssetLoadStatus.Loading != LoadStatus) { for (int i = 0; i < dependAB.Length; i++) { assetBundleLoader.LoadDependBundleSync(dependAB[i]); } if (!fullpathDict.TryGetValue(AssetPath, out string fullpath)) { if (AssetBundleConfig.location == 1) { fullpath = Path.Combine(Application.persistentDataPath, "update", AssetPath); } else { fullpath = Path.Combine(Application.streamingAssetsPath, AssetPath); } fullpathDict.Add(AssetPath, fullpath); } var ab = AssetBundle.LoadFromFile(fullpath); Complete(ab); } else { // 异步过程中转同步 for (int i = 0; i < dependAB.Length; i++) { assetBundleLoader.LoadDependBundleSync(dependAB[i]); } var ab = request.assetBundle; Complete(ab); } } private void LoadCompleteDepenedAsset(AssetBundleObject assetBundleObject) { recordDependCount--; if (recordDependCount == 0) { dependABComplete = true; } BFLog.LogDebug(BFLog.DEBUG_RESMGR, "green", "[AssetBundleObject] [LoadCompleteDepenedAsset] : {0}, record dependent count : {1}", assetBundleObject.AssetPath, recordDependCount); } /// /// 加载完成,返回true, 否则返回false. 超时机制确保不会无法结束 /// /// public override bool Tick() { try { if (EAssetLoadStatus.Loading == LoadStatus) { if (request != null && request.isDone && dependABComplete) { Complete(request.assetBundle); return true; } else { if (Timeout < Time.time) //超时机制 { BFLog.LogError("[ResMgr] bundlepath : {0}, timeout ! assetbunle is null = {1}", AssetPath, (null == Assetbundle)); Timeout += ResourceManager.TIME_OUT_LOAD; return false; } } } else if (EAssetLoadStatus.Complete == LoadStatus) { return true; } return false; } catch (Exception ex) //需要测试!!!! 尝试捕获异常,保证单个资源加载出错不卡住游戏。比如异步过程中被同步调用等。 { BFLog.LogError("[ResMgr] loading exception! assetpath : {0}, exception : {1}", AssetPath, ex.ToString()); return true; } } public void Complete(AssetBundle ab) { Assetbundle = ab; LoadStatus = ab == null ? EAssetLoadStatus.Error : EAssetLoadStatus.Complete; request = null; loadComplete.Invoke(this); loadComplete.Clear(); } public void AddUnloadCallback(Action unloadCallback) { unloadComplete += unloadCallback; } public override bool Unload(bool immediately) { BFLog.LogDebug(BFLog.DEBUG_RESMGR, "green", "[ResMgr] assetBundleobject base unload assetpath : {0}, refcount : {1}", AssetPath, RefCount); if (RefCount == 0) return false; --RefCount; if (RefCount == 0) { loadComplete.Clear(); LoadStatus = EAssetLoadStatus.Unloading; BFLog.LogDebug(BFLog.DEBUG_RESMGR, "green", "[ResMgr] assetobject unloaded immediately"); UnloadCountdown(true); // assetbundle目前都是立即卸载 return false; } return false; } protected override bool OnUnloadComplete() { BFLog.LogDebug(BFLog.DEBUG_RESMGR, "green", "[ResMgr] AssetBundleObject OnUnloadComplete start LoadStatus : {0}", LoadStatus); if (EAssetLoadStatus.Complete == LoadStatus) { return false; } if (!ReferenceEquals(null, request)) { var assetbundle = request.assetBundle; assetbundle.Unload(true); request = null; } if (!ReferenceEquals(null, Assetbundle)) { Assetbundle.Unload(true); Assetbundle = null; } LoadStatus = EAssetLoadStatus.Unloaded; assetBundleLoader.RemoveCache(this); unloadComplete.Invoke(); unloadComplete.Clear(); for (int i = 0; i < dependAB.Length; i++) { assetBundleLoader.UnLoadBundle(dependAB[i], true); } BFLog.LogDebug(BFLog.DEBUG_RESMGR, "green", "[ResMgr] OnUnloadComplete end "); return true; } } }