AssetModule.cs 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  1. using System.Collections.Generic;
  2. using System.Linq;
  3. using UnityEngine;
  4. using XGame.Framework.Asyncs;
  5. namespace XGame.Framework.Asset
  6. {
  7. /// <summary>
  8. /// 游戏加载模块
  9. /// 运行时允许同时存在多个
  10. /// </summary>
  11. public class AssetModule : IAssetModule, IAssetEventListener, System.IDisposable
  12. {
  13. /// <summary>
  14. /// 已加载的资源
  15. /// </summary>
  16. private Dictionary<long, AssetInstance> _loadedAssetMap = new Dictionary<long, AssetInstance>();
  17. /// <summary>
  18. /// key: IAssetLoadAsync<TResult>
  19. /// value: assetTag
  20. /// </summary>
  21. private List<IAsync> _loadingAsyncs = new List<IAsync>();
  22. /// <summary>
  23. /// 预加载的资源名字
  24. /// </summary>
  25. private HashSet<string> _preloadedAssetNames = new HashSet<string>();
  26. public string ConvertAddressableName(string addressableName)
  27. {
  28. return AssetManager.ConvertAddressableName(addressableName);
  29. }
  30. public IAssetLoadAsync<TResult> LoadAsync<TResult>(string addressableName)
  31. {
  32. var loadAsync = AssetManager.LoadAsync<TResult>(addressableName);
  33. AddAssetLoadAsync(loadAsync);
  34. return loadAsync;
  35. }
  36. ///// <summary>
  37. ///// 不推荐业务使用同步加载,先屏蔽
  38. ///// </summary>
  39. ///// <typeparam name="TResult"></typeparam>
  40. ///// <param name="addressableName"></param>
  41. ///// <returns></returns>
  42. //public TResult LoadSync<TResult>(string addressableName)
  43. //{
  44. // var result = AssetManager.LoadSync<TResult>(addressableName);
  45. // if (result != null)
  46. // {
  47. // //储存
  48. // OnGetResult(ConvertAddressableName(addressableName), result);
  49. // }
  50. // return result;
  51. //}
  52. public void Recycle(object obj)
  53. {
  54. if (obj is Component component && component != null)
  55. {
  56. obj = component.gameObject;
  57. }
  58. if (obj == null) return;
  59. InternalRecycle(obj);
  60. AssetManager.Recycle(obj);
  61. }
  62. internal void Recycle(GameObject obj, bool destroyImmediate)
  63. {
  64. if (obj == null) return;
  65. InternalRecycle(obj);
  66. AssetManager.Recycle(new RecycleObject(obj)
  67. {
  68. destroyImmediate = destroyImmediate,
  69. });
  70. }
  71. //public void StopAsync<TResult>(IAssetLoadAsync<TResult> loadAsync)
  72. //{
  73. // loadAsync.RemoveAll();
  74. //}
  75. public void StopAllAsyncs()
  76. {
  77. ClearLoadingAsyncs();
  78. }
  79. public void UnloadUnusedAssets()
  80. {
  81. AssetManager.UnloadUnusedAssets();
  82. }
  83. public IAsync LoadSceneBundleAsync(string sceneName)
  84. {
  85. var async = AssetManager.LoadSceneBundle(sceneName);
  86. return async;
  87. }
  88. public void UnLoadSceneBundle(string sceneName)
  89. {
  90. AssetManager.UnLoadSceneBundle(sceneName);
  91. }
  92. #region 预加载
  93. public IAssetPreloadAsync PreloadAsync<TResult>(string addressableName)
  94. {
  95. var loadAsync = LoadAsync<TResult>(addressableName);
  96. AddAssetLoadAsync(loadAsync);
  97. loadAsync?.On(_ =>
  98. {
  99. var assetName = loadAsync.AddressableName;
  100. AssetManager.SetPreloadTag(assetName, true);
  101. _preloadedAssetNames.Add(assetName);
  102. });
  103. return loadAsync as IAssetPreloadAsync;
  104. }
  105. public void UnloadPreloadAsset(string addressableName)
  106. {
  107. if (_preloadedAssetNames.Count == 0)
  108. return;
  109. addressableName = ConvertAddressableName(addressableName);
  110. if (_preloadedAssetNames.Contains(addressableName))
  111. {
  112. _preloadedAssetNames.Remove(addressableName);
  113. AssetManager.SetPreloadTag(addressableName, false);
  114. }
  115. }
  116. #endregion
  117. void System.IDisposable.Dispose()
  118. {
  119. ClearLoadingAsyncs();
  120. foreach (var assetName in _preloadedAssetNames)
  121. {
  122. AssetManager.SetPreloadTag(assetName, false);
  123. }
  124. _preloadedAssetNames.Clear();
  125. foreach (var it in _loadedAssetMap)
  126. {
  127. //var component = it.Value.Asset != null && it.Value.Asset is UnityEngine.Component;
  128. //GameObject被销毁后,System.object对象判断还是非空,只能通过UnityEngine.Object来判断非空
  129. bool isNull = it.Value.Asset == null || (it.Value.Asset as UnityEngine.Object == null);
  130. if (isNull)
  131. { //资源被业务销毁
  132. AssetsLog.Warn($"AssetModule try to recycle asset. But asset has been destroyed. {it.Value}");
  133. }
  134. if (isNull || it.Value.Reference > 1)
  135. {
  136. AssetManager.Recycle(new RecycleObject()
  137. {
  138. asset = isNull ? null : it.Value.Asset,
  139. hashcode = it.Key,
  140. reference = it.Value.Reference,
  141. destroyImmediate = false,
  142. });
  143. }
  144. else if (it.Value.Reference < 1)
  145. {
  146. AssetsLog.Error($"Asset referece count error. {it.Value}");
  147. }
  148. else
  149. {
  150. AssetManager.Recycle(it.Value.Asset);
  151. }
  152. //for (int i = 0; i < it.Value.Reference; i++)
  153. //{//该步骤待优化
  154. // assetMgr.Recycle(it.Value.Asset);
  155. //}
  156. }
  157. _loadedAssetMap.Clear();
  158. }
  159. void InternalRecycle(object obj)
  160. {
  161. if (obj != null && _loadedAssetMap != null)
  162. {
  163. var hashCode = obj.GetLongHashCode();
  164. if (_loadedAssetMap.TryGetValue(hashCode, out AssetInstance asset))
  165. {
  166. if (asset.Release())
  167. {
  168. _loadedAssetMap.Remove(hashCode);
  169. }
  170. }
  171. }
  172. }
  173. #region 加载中的异步
  174. private void AddAssetLoadAsync(IAsync loadAsync)
  175. {
  176. //AssetsLog.Debug($"AddAssetLoadAsync:{loadAsync}");
  177. if (loadAsync is IAssetEventListenerSetter setter)
  178. {
  179. setter.AssetEventListener = this;
  180. }
  181. if (loadAsync == null || loadAsync.IsCompleted)
  182. return;
  183. _loadingAsyncs.Add(loadAsync);
  184. }
  185. /// <summary>
  186. /// 清空加载中的异步加载回调
  187. /// </summary>
  188. private void ClearLoadingAsyncs()
  189. {
  190. if (_loadingAsyncs.Count == 0)
  191. return;
  192. for(var i = _loadingAsyncs.Count - 1; i >= 0; i--)
  193. {
  194. _loadingAsyncs[i].RemoveAll();
  195. }
  196. _loadingAsyncs.Clear();
  197. }
  198. #endregion
  199. #region IAssetEventListener 实现
  200. void IAssetEventListener.OnGetResult(string addressableName, object result)
  201. {
  202. Assert.IsNotNull(result);
  203. if (_preloadedAssetNames.Contains(addressableName))
  204. { // 删除预加载记录,AssetManager内部会自动清除预加载标记
  205. _preloadedAssetNames.Remove(addressableName);
  206. }
  207. //储存对象
  208. if (result is Component component && component != null)
  209. { //Component脚本改为存储GameObject的hash
  210. result = component.gameObject;
  211. }
  212. var hashCode = result.GetLongHashCode();
  213. if (_loadedAssetMap.TryGetValue(hashCode, out AssetInstance asset))
  214. {
  215. asset.Retain();
  216. }
  217. else
  218. {
  219. asset = new AssetInstance(result, addressableName);
  220. _loadedAssetMap.Add(hashCode, asset);
  221. }
  222. }
  223. void IAssetEventListener.ReleaseAsync(IAsync loadAsync)
  224. {
  225. //AssetsLog.Debug($"IAssetResultHandle.ReleaseAsync:{loadAsync}");
  226. _loadingAsyncs.Remove(loadAsync);
  227. }
  228. #endregion
  229. #region 注册加载资源的Component信息,主要是预防业务将动态加载的GameObject下依赖的贴图等资源Recycle
  230. internal bool IsRegister(long assetHash, long parentHash)
  231. {
  232. if (_loadedAssetMap.TryGetValue(assetHash, out var asset))
  233. {
  234. return asset.IsContainParent(parentHash);
  235. }
  236. return false;
  237. }
  238. internal bool Register(long assetHash, long parentHash)
  239. {
  240. if (_loadedAssetMap.TryGetValue(assetHash, out var asset))
  241. {
  242. return asset.AddParent(parentHash);
  243. }
  244. return false;
  245. }
  246. public bool UnRegister(long assetHash, long parentHash)
  247. {
  248. if (_loadedAssetMap.TryGetValue(assetHash, out var asset))
  249. {
  250. return asset.RemoveParent(parentHash);
  251. }
  252. return false;
  253. }
  254. #endregion
  255. }
  256. }