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