359 lines
13 KiB
C#
359 lines
13 KiB
C#
using System;
|
||
using System.Collections.Generic;
|
||
using UnityEngine;
|
||
|
||
namespace BF
|
||
{
|
||
public class AssetBundleLoader : LoaderBase
|
||
{
|
||
private Dictionary<string, AssetBundleObject> assetbundleCache; //所有assetbundleobject对象缓存
|
||
|
||
private Dictionary<string, AssetObject> waitABComplete; //等待对应ab加载的资源
|
||
|
||
private BFQueue<AssetBundleObject> waitLoadQueue; //等待加载队列
|
||
|
||
private int waitLoadCount; //等待加载队列数量
|
||
|
||
private List<AssetBundleObject> loadingArray; //加载中
|
||
|
||
private int loadingCount; //正在加载数量
|
||
|
||
private List<AssetObjectBase> delayUnload; //延迟卸载列表
|
||
|
||
public const int MAX_LOADING = 120;
|
||
|
||
private Action<AssetBundleObject> 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<string, AssetBundleObject>(32); // 预分配空间
|
||
waitABComplete = new Dictionary<string, AssetObject>();
|
||
waitLoadQueue = new BFQueue<AssetBundleObject>();
|
||
loadingArray = new List<AssetBundleObject>(MAX_LOADING); // 最多同时加载120个bundle,可以考虑配置在机型性能分档上面,猜测unity内部也做了max_loading机制
|
||
delayUnload = new List<AssetObjectBase>();
|
||
}
|
||
|
||
public override AssetObject LoadAssetAsync(string assetPath, Type type, Action<string, UnityEngine.Object> 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;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 对象加载出错后,再次加载
|
||
/// </summary>
|
||
/// <param name="assetObject"></param>
|
||
public override void LoadAssetAsync(AssetObject assetObject)
|
||
{
|
||
//LoadStatus != Unloading 后,会自动从delayunload列表移除
|
||
LoadAssetAsyncByConfig(assetObject);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 加载依赖bundle
|
||
/// </summary>
|
||
public void LoadDependBundleAsync(string bundlePath, Action<AssetBundleObject> complete)
|
||
{
|
||
BFLog.LogDebug(BFLog.DEBUG_RESMGR, "green", "[ResMgr] LoadDependBundleAsync, bundlePath : {0} ", bundlePath);
|
||
|
||
LoadBundleAsync(bundlePath, complete);
|
||
}
|
||
|
||
public void LoadBundleAsync(string bundlePath, Action<AssetBundleObject> 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<AssetBundleObject> 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<AssetBundleObject> 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;
|
||
}
|
||
}
|
||
} |