using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using XGame.Framework.Asyncs;
namespace XGame.Framework.Asset
{
///
/// 游戏加载模块
/// 运行时允许同时存在多个
///
public class AssetModule : IAssetModule, IAssetEventListener, System.IDisposable
{
///
/// 已加载的资源
///
private Dictionary _loadedAssetMap = new Dictionary();
///
/// key: IAssetLoadAsync
/// value: assetTag
///
private List _loadingAsyncs = new List();
///
/// 预加载的资源名字
///
private HashSet _preloadedAssetNames = new HashSet();
public string ConvertAddressableName(string addressableName)
{
return AssetManager.ConvertAddressableName(addressableName);
}
public IAssetLoadAsync LoadAsync(string addressableName)
{
var loadAsync = AssetManager.LoadAsync(addressableName);
AddAssetLoadAsync(loadAsync);
return loadAsync;
}
/////
///// 不推荐业务使用同步加载,先屏蔽
/////
/////
/////
/////
//public TResult LoadSync(string addressableName)
//{
// var result = AssetManager.LoadSync(addressableName);
// if (result != null)
// {
// //储存
// OnGetResult(ConvertAddressableName(addressableName), result);
// }
// return result;
//}
public void Recycle(object obj)
{
if (obj is Component component && component != null)
{
obj = component.gameObject;
}
if (obj == null) return;
InternalRecycle(obj);
AssetManager.Recycle(obj);
}
internal void Recycle(GameObject obj, bool destroyImmediate)
{
if (obj == null) return;
InternalRecycle(obj);
AssetManager.Recycle(new RecycleObject(obj)
{
destroyImmediate = destroyImmediate,
});
}
//public void StopAsync(IAssetLoadAsync loadAsync)
//{
// loadAsync.RemoveAll();
//}
public void StopAllAsyncs()
{
ClearLoadingAsyncs();
}
public void UnloadUnusedAssets()
{
AssetManager.UnloadUnusedAssets();
}
public IAsync LoadSceneBundleAsync(string sceneName)
{
var async = AssetManager.LoadSceneBundle(sceneName);
return async;
}
public void UnLoadSceneBundle(string sceneName)
{
AssetManager.UnLoadSceneBundle(sceneName);
}
#region 预加载
public IAssetPreloadAsync PreloadAsync(string addressableName)
{
var loadAsync = LoadAsync(addressableName);
AddAssetLoadAsync(loadAsync);
loadAsync?.On(_ =>
{
var assetName = loadAsync.AddressableName;
AssetManager.SetPreloadTag(assetName, true);
_preloadedAssetNames.Add(assetName);
});
return loadAsync as IAssetPreloadAsync;
}
public void UnloadPreloadAsset(string addressableName)
{
if (_preloadedAssetNames.Count == 0)
return;
addressableName = ConvertAddressableName(addressableName);
if (_preloadedAssetNames.Contains(addressableName))
{
_preloadedAssetNames.Remove(addressableName);
AssetManager.SetPreloadTag(addressableName, false);
}
}
#endregion
void System.IDisposable.Dispose()
{
ClearLoadingAsyncs();
foreach (var assetName in _preloadedAssetNames)
{
AssetManager.SetPreloadTag(assetName, false);
}
_preloadedAssetNames.Clear();
foreach (var it in _loadedAssetMap)
{
//var component = it.Value.Asset != null && it.Value.Asset is UnityEngine.Component;
//GameObject被销毁后,System.object对象判断还是非空,只能通过UnityEngine.Object来判断非空
bool isNull = it.Value.Asset == null || (it.Value.Asset as UnityEngine.Object == null);
if (isNull)
{ //资源被业务销毁
AssetsLog.Warn($"AssetModule try to recycle asset. But asset has been destroyed. {it.Value}");
}
if (isNull || it.Value.Reference > 1)
{
AssetManager.Recycle(new RecycleObject()
{
asset = isNull ? null : it.Value.Asset,
hashcode = it.Key,
reference = it.Value.Reference,
destroyImmediate = false,
});
}
else if (it.Value.Reference < 1)
{
AssetsLog.Error($"Asset referece count error. {it.Value}");
}
else
{
AssetManager.Recycle(it.Value.Asset);
}
//for (int i = 0; i < it.Value.Reference; i++)
//{//该步骤待优化
// assetMgr.Recycle(it.Value.Asset);
//}
}
_loadedAssetMap.Clear();
}
void InternalRecycle(object obj)
{
if (obj != null && _loadedAssetMap != null)
{
var hashCode = obj.GetLongHashCode();
if (_loadedAssetMap.TryGetValue(hashCode, out AssetInstance asset))
{
if (asset.Release())
{
_loadedAssetMap.Remove(hashCode);
}
}
}
}
#region 加载中的异步
private void AddAssetLoadAsync(IAsync loadAsync)
{
//AssetsLog.Debug($"AddAssetLoadAsync:{loadAsync}");
if (loadAsync is IAssetEventListenerSetter setter)
{
setter.AssetEventListener = this;
}
if (loadAsync == null || loadAsync.IsCompleted)
return;
_loadingAsyncs.Add(loadAsync);
}
///
/// 清空加载中的异步加载回调
///
private void ClearLoadingAsyncs()
{
if (_loadingAsyncs.Count == 0)
return;
for(var i = _loadingAsyncs.Count - 1; i >= 0; i--)
{
_loadingAsyncs[i].RemoveAll();
}
_loadingAsyncs.Clear();
}
#endregion
#region IAssetEventListener 实现
void IAssetEventListener.OnGetResult(string addressableName, object result)
{
Assert.IsNotNull(result);
if (_preloadedAssetNames.Contains(addressableName))
{ // 删除预加载记录,AssetManager内部会自动清除预加载标记
_preloadedAssetNames.Remove(addressableName);
}
//储存对象
if (result is Component component && component != null)
{ //Component脚本改为存储GameObject的hash
result = component.gameObject;
}
var hashCode = result.GetLongHashCode();
if (_loadedAssetMap.TryGetValue(hashCode, out AssetInstance asset))
{
asset.Retain();
}
else
{
asset = new AssetInstance(result, addressableName);
_loadedAssetMap.Add(hashCode, asset);
}
}
void IAssetEventListener.ReleaseAsync(IAsync loadAsync)
{
//AssetsLog.Debug($"IAssetResultHandle.ReleaseAsync:{loadAsync}");
_loadingAsyncs.Remove(loadAsync);
}
#endregion
#region 注册加载资源的Component信息,主要是预防业务将动态加载的GameObject下依赖的贴图等资源Recycle
internal bool IsRegister(long assetHash, long parentHash)
{
if (_loadedAssetMap.TryGetValue(assetHash, out var asset))
{
return asset.IsContainParent(parentHash);
}
return false;
}
internal bool Register(long assetHash, long parentHash)
{
if (_loadedAssetMap.TryGetValue(assetHash, out var asset))
{
return asset.AddParent(parentHash);
}
return false;
}
public bool UnRegister(long assetHash, long parentHash)
{
if (_loadedAssetMap.TryGetValue(assetHash, out var asset))
{
return asset.RemoveParent(parentHash);
}
return false;
}
#endregion
}
}