123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278 |
- using System.Collections.Generic;
- using System.Linq;
- using UnityEngine;
- using XGame.Framework.Asyncs;
- namespace XGame.Framework.Asset
- {
- /// <summary>
- /// 游戏加载模块
- /// 运行时允许同时存在多个
- /// </summary>
- public class AssetModule : IAssetModule, IAssetEventListener, System.IDisposable
- {
- /// <summary>
- /// 已加载的资源
- /// </summary>
- private Dictionary<long, AssetInstance> _loadedAssetMap = new Dictionary<long, AssetInstance>();
- /// <summary>
- /// key: IAssetLoadAsync<TResult>
- /// value: assetTag
- /// </summary>
- private List<IAsync> _loadingAsyncs = new List<IAsync>();
- /// <summary>
- /// 预加载的资源名字
- /// </summary>
- private HashSet<string> _preloadedAssetNames = new HashSet<string>();
- public string ConvertAddressableName(string addressableName)
- {
- return AssetManager.ConvertAddressableName(addressableName);
- }
- public IAssetLoadAsync<TResult> LoadAsync<TResult>(string addressableName)
- {
- var loadAsync = AssetManager.LoadAsync<TResult>(addressableName);
- AddAssetLoadAsync(loadAsync);
- return loadAsync;
- }
- ///// <summary>
- ///// 不推荐业务使用同步加载,先屏蔽
- ///// </summary>
- ///// <typeparam name="TResult"></typeparam>
- ///// <param name="addressableName"></param>
- ///// <returns></returns>
- //public TResult LoadSync<TResult>(string addressableName)
- //{
- // var result = AssetManager.LoadSync<TResult>(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<TResult>(IAssetLoadAsync<TResult> 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<TResult>(string addressableName)
- {
- var loadAsync = LoadAsync<TResult>(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);
- }
- /// <summary>
- /// 清空加载中的异步加载回调
- /// </summary>
- 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
- }
- }
|