2023-04-03 11:04:31 +08:00

359 lines
13 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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