ResourceManager.cs 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484
  1. using System;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using System.Diagnostics;
  5. using UnityEngine;
  6. using UnityEngine.SceneManagement;
  7. namespace YooAsset
  8. {
  9. internal class ResourceManager
  10. {
  11. // 全局场景句柄集合
  12. private readonly static Dictionary<string, SceneHandle> _sceneHandles = new Dictionary<string, SceneHandle>(100);
  13. private static long _sceneCreateCount = 0;
  14. private readonly Dictionary<string, ProviderBase> _providerDic = new Dictionary<string, ProviderBase>(5000);
  15. private readonly Dictionary<string, BundleLoaderBase> _loaderDic = new Dictionary<string, BundleLoaderBase>(5000);
  16. private readonly List<BundleLoaderBase> _loaderList = new List<BundleLoaderBase>(5000);
  17. private bool _simulationOnEditor;
  18. private bool _autoDestroyAssetProvider;
  19. private IBundleQuery _bundleQuery;
  20. /// <summary>
  21. /// 所属包裹
  22. /// </summary>
  23. public readonly string PackageName;
  24. public ResourceManager(string packageName)
  25. {
  26. PackageName = packageName;
  27. }
  28. /// <summary>
  29. /// 初始化
  30. /// </summary>
  31. public void Initialize(bool simulationOnEditor, bool autoDestroyAssetProvider, IBundleQuery bundleServices)
  32. {
  33. _simulationOnEditor = simulationOnEditor;
  34. _autoDestroyAssetProvider = autoDestroyAssetProvider;
  35. _bundleQuery = bundleServices;
  36. }
  37. /// <summary>
  38. /// 更新
  39. /// </summary>
  40. public void Update()
  41. {
  42. foreach (var loader in _loaderList)
  43. {
  44. loader.Update();
  45. if (_autoDestroyAssetProvider)
  46. loader.TryDestroyProviders();
  47. }
  48. }
  49. /// <summary>
  50. /// 资源回收(卸载引用计数为零的资源)
  51. /// </summary>
  52. public void UnloadUnusedAssets()
  53. {
  54. for (int i = _loaderList.Count - 1; i >= 0; i--)
  55. {
  56. BundleLoaderBase loader = _loaderList[i];
  57. loader.TryDestroyProviders();
  58. }
  59. for (int i = _loaderList.Count - 1; i >= 0; i--)
  60. {
  61. BundleLoaderBase loader = _loaderList[i];
  62. if (loader.CanDestroy())
  63. {
  64. string bundleName = loader.MainBundleInfo.Bundle.BundleName;
  65. loader.Destroy();
  66. _loaderList.RemoveAt(i);
  67. _loaderDic.Remove(bundleName);
  68. }
  69. }
  70. }
  71. /// <summary>
  72. /// 尝试卸载指定资源的资源包(包括依赖资源)
  73. /// </summary>
  74. public void TryUnloadUnusedAsset(AssetInfo assetInfo)
  75. {
  76. if (assetInfo.IsInvalid)
  77. {
  78. YooLogger.Error($"Failed to unload asset ! {assetInfo.Error}");
  79. return;
  80. }
  81. // 卸载主资源包加载器
  82. string manBundleName = _bundleQuery.GetMainBundleName(assetInfo);
  83. var mainLoader = TryGetAssetBundleLoader(manBundleName);
  84. if (mainLoader != null)
  85. {
  86. mainLoader.TryDestroyProviders();
  87. if (mainLoader.CanDestroy())
  88. {
  89. string bundleName = mainLoader.MainBundleInfo.Bundle.BundleName;
  90. mainLoader.Destroy();
  91. _loaderList.Remove(mainLoader);
  92. _loaderDic.Remove(bundleName);
  93. }
  94. }
  95. // 卸载依赖资源包加载器
  96. string[] dependBundleNames = _bundleQuery.GetDependBundleNames(assetInfo);
  97. foreach (var dependBundleName in dependBundleNames)
  98. {
  99. var dependLoader = TryGetAssetBundleLoader(dependBundleName);
  100. if (dependLoader != null)
  101. {
  102. if (dependLoader.CanDestroy())
  103. {
  104. string bundleName = dependLoader.MainBundleInfo.Bundle.BundleName;
  105. dependLoader.Destroy();
  106. _loaderList.Remove(dependLoader);
  107. _loaderDic.Remove(bundleName);
  108. }
  109. }
  110. }
  111. }
  112. /// <summary>
  113. /// 强制回收所有资源
  114. /// 注意:加载器在销毁后关联的下载器还会继续下载!
  115. /// </summary>
  116. public void ForceUnloadAllAssets()
  117. {
  118. #if UNITY_WEBGL
  119. throw new Exception($"WebGL not support invoke {nameof(ForceUnloadAllAssets)}");
  120. #else
  121. // 注意:因为场景无法异步转同步,需要等待所有场景加载完毕!
  122. foreach (var sceneHandlePair in _sceneHandles)
  123. {
  124. var sceneHandle = sceneHandlePair.Value;
  125. if (sceneHandle.PackageName == PackageName)
  126. {
  127. if (sceneHandle.IsDone == false)
  128. throw new Exception($"{nameof(ForceUnloadAllAssets)} cannot be called when loading the scene !");
  129. }
  130. }
  131. // 释放所有资源句柄
  132. foreach (var provider in _providerDic.Values)
  133. {
  134. provider.ReleaseAllHandles();
  135. }
  136. // 强制销毁资源提供者
  137. foreach (var provider in _providerDic.Values)
  138. {
  139. provider.ForceDestroyComplete();
  140. provider.Destroy();
  141. }
  142. // 强制销毁资源加载器
  143. foreach (var loader in _loaderList)
  144. {
  145. loader.ForceDestroyComplete();
  146. loader.Destroy();
  147. }
  148. // 清空数据
  149. _providerDic.Clear();
  150. _loaderList.Clear();
  151. _loaderDic.Clear();
  152. ClearSceneHandle();
  153. // 注意:调用底层接口释放所有资源
  154. Resources.UnloadUnusedAssets();
  155. #endif
  156. }
  157. /// <summary>
  158. /// 加载场景对象
  159. /// 注意:返回的场景句柄是唯一的,每个场景句柄对应自己的场景提供者对象。
  160. /// 注意:业务逻辑层应该避免同时加载一个子场景。
  161. /// </summary>
  162. public SceneHandle LoadSceneAsync(AssetInfo assetInfo, LoadSceneMode sceneMode, bool suspendLoad, uint priority)
  163. {
  164. if (assetInfo.IsInvalid)
  165. {
  166. YooLogger.Error($"Failed to load scene ! {assetInfo.Error}");
  167. CompletedProvider completedProvider = new CompletedProvider(assetInfo);
  168. completedProvider.SetCompleted(assetInfo.Error);
  169. return completedProvider.CreateHandle<SceneHandle>();
  170. }
  171. // 如果加载的是主场景,则卸载所有缓存的场景
  172. if (sceneMode == LoadSceneMode.Single)
  173. {
  174. UnloadAllScene();
  175. }
  176. // 注意:同一个场景的ProviderGUID每次加载都会变化
  177. string providerGUID = $"{assetInfo.GUID}-{++_sceneCreateCount}";
  178. ProviderBase provider;
  179. {
  180. if (_simulationOnEditor)
  181. provider = new DatabaseSceneProvider(this, providerGUID, assetInfo, sceneMode, suspendLoad);
  182. else
  183. provider = new BundledSceneProvider(this, providerGUID, assetInfo, sceneMode, suspendLoad);
  184. provider.InitSpawnDebugInfo();
  185. _providerDic.Add(providerGUID, provider);
  186. OperationSystem.StartOperation(PackageName, provider);
  187. }
  188. provider.Priority = priority;
  189. var handle = provider.CreateHandle<SceneHandle>();
  190. handle.PackageName = PackageName;
  191. _sceneHandles.Add(providerGUID, handle);
  192. return handle;
  193. }
  194. /// <summary>
  195. /// 加载资源对象
  196. /// </summary>
  197. public AssetHandle LoadAssetAsync(AssetInfo assetInfo, uint priority)
  198. {
  199. if (assetInfo.IsInvalid)
  200. {
  201. YooLogger.Error($"Failed to load asset ! {assetInfo.Error}");
  202. CompletedProvider completedProvider = new CompletedProvider(assetInfo);
  203. completedProvider.SetCompleted(assetInfo.Error);
  204. return completedProvider.CreateHandle<AssetHandle>();
  205. }
  206. string providerGUID = nameof(LoadAssetAsync) + assetInfo.GUID;
  207. ProviderBase provider = TryGetProvider(providerGUID);
  208. if (provider == null)
  209. {
  210. if (_simulationOnEditor)
  211. provider = new DatabaseAssetProvider(this, providerGUID, assetInfo);
  212. else
  213. provider = new BundledAssetProvider(this, providerGUID, assetInfo);
  214. provider.InitSpawnDebugInfo();
  215. _providerDic.Add(providerGUID, provider);
  216. OperationSystem.StartOperation(PackageName, provider);
  217. }
  218. provider.Priority = priority;
  219. return provider.CreateHandle<AssetHandle>();
  220. }
  221. /// <summary>
  222. /// 加载子资源对象
  223. /// </summary>
  224. public SubAssetsHandle LoadSubAssetsAsync(AssetInfo assetInfo, uint priority)
  225. {
  226. if (assetInfo.IsInvalid)
  227. {
  228. YooLogger.Error($"Failed to load sub assets ! {assetInfo.Error}");
  229. CompletedProvider completedProvider = new CompletedProvider(assetInfo);
  230. completedProvider.SetCompleted(assetInfo.Error);
  231. return completedProvider.CreateHandle<SubAssetsHandle>();
  232. }
  233. string providerGUID = nameof(LoadSubAssetsAsync) + assetInfo.GUID;
  234. ProviderBase provider = TryGetProvider(providerGUID);
  235. if (provider == null)
  236. {
  237. if (_simulationOnEditor)
  238. provider = new DatabaseSubAssetsProvider(this, providerGUID, assetInfo);
  239. else
  240. provider = new BundledSubAssetsProvider(this, providerGUID, assetInfo);
  241. provider.InitSpawnDebugInfo();
  242. _providerDic.Add(providerGUID, provider);
  243. OperationSystem.StartOperation(PackageName, provider);
  244. }
  245. provider.Priority = priority;
  246. return provider.CreateHandle<SubAssetsHandle>();
  247. }
  248. /// <summary>
  249. /// 加载所有资源对象
  250. /// </summary>
  251. public AllAssetsHandle LoadAllAssetsAsync(AssetInfo assetInfo, uint priority)
  252. {
  253. if (assetInfo.IsInvalid)
  254. {
  255. YooLogger.Error($"Failed to load all assets ! {assetInfo.Error}");
  256. CompletedProvider completedProvider = new CompletedProvider(assetInfo);
  257. completedProvider.SetCompleted(assetInfo.Error);
  258. return completedProvider.CreateHandle<AllAssetsHandle>();
  259. }
  260. string providerGUID = nameof(LoadAllAssetsAsync) + assetInfo.GUID;
  261. ProviderBase provider = TryGetProvider(providerGUID);
  262. if (provider == null)
  263. {
  264. if (_simulationOnEditor)
  265. provider = new DatabaseAllAssetsProvider(this, providerGUID, assetInfo);
  266. else
  267. provider = new BundledAllAssetsProvider(this, providerGUID, assetInfo);
  268. provider.InitSpawnDebugInfo();
  269. _providerDic.Add(providerGUID, provider);
  270. OperationSystem.StartOperation(PackageName, provider);
  271. }
  272. provider.Priority = priority;
  273. return provider.CreateHandle<AllAssetsHandle>();
  274. }
  275. /// <summary>
  276. /// 加载原生文件
  277. /// </summary>
  278. public RawFileHandle LoadRawFileAsync(AssetInfo assetInfo, uint priority)
  279. {
  280. if (assetInfo.IsInvalid)
  281. {
  282. YooLogger.Error($"Failed to load raw file ! {assetInfo.Error}");
  283. CompletedProvider completedProvider = new CompletedProvider(assetInfo);
  284. completedProvider.SetCompleted(assetInfo.Error);
  285. return completedProvider.CreateHandle<RawFileHandle>();
  286. }
  287. string providerGUID = nameof(LoadRawFileAsync) + assetInfo.GUID;
  288. ProviderBase provider = TryGetProvider(providerGUID);
  289. if (provider == null)
  290. {
  291. if (_simulationOnEditor)
  292. provider = new DatabaseRawFileProvider(this, providerGUID, assetInfo);
  293. else
  294. provider = new BundledRawFileProvider(this, providerGUID, assetInfo);
  295. provider.InitSpawnDebugInfo();
  296. _providerDic.Add(providerGUID, provider);
  297. OperationSystem.StartOperation(PackageName, provider);
  298. }
  299. provider.Priority = priority;
  300. return provider.CreateHandle<RawFileHandle>();
  301. }
  302. internal void UnloadSubScene(string sceneName)
  303. {
  304. List<string> removeKeys = new List<string>();
  305. foreach (var valuePair in _sceneHandles)
  306. {
  307. var sceneHandle = valuePair.Value;
  308. if (sceneHandle.SceneName == sceneName)
  309. {
  310. // 释放子场景句柄
  311. sceneHandle.ReleaseInternal();
  312. removeKeys.Add(valuePair.Key);
  313. }
  314. }
  315. foreach (string key in removeKeys)
  316. {
  317. _sceneHandles.Remove(key);
  318. }
  319. }
  320. private void UnloadAllScene()
  321. {
  322. // 释放所有场景句柄
  323. foreach (var valuePair in _sceneHandles)
  324. {
  325. valuePair.Value.ReleaseInternal();
  326. }
  327. _sceneHandles.Clear();
  328. }
  329. private void ClearSceneHandle()
  330. {
  331. // 释放资源包下的所有场景
  332. if (_bundleQuery.ManifestValid())
  333. {
  334. string packageName = PackageName;
  335. List<string> removeList = new List<string>();
  336. foreach (var valuePair in _sceneHandles)
  337. {
  338. if (valuePair.Value.PackageName == packageName)
  339. {
  340. removeList.Add(valuePair.Key);
  341. }
  342. }
  343. foreach (var key in removeList)
  344. {
  345. _sceneHandles.Remove(key);
  346. }
  347. }
  348. }
  349. internal BundleLoaderBase CreateOwnerAssetBundleLoader(AssetInfo assetInfo)
  350. {
  351. BundleInfo bundleInfo = _bundleQuery.GetMainBundleInfo(assetInfo);
  352. return CreateAssetBundleLoaderInternal(bundleInfo);
  353. }
  354. internal List<BundleLoaderBase> CreateDependAssetBundleLoaders(AssetInfo assetInfo)
  355. {
  356. BundleInfo[] depends = _bundleQuery.GetDependBundleInfos(assetInfo);
  357. List<BundleLoaderBase> result = new List<BundleLoaderBase>(depends.Length);
  358. foreach (var bundleInfo in depends)
  359. {
  360. BundleLoaderBase dependLoader = CreateAssetBundleLoaderInternal(bundleInfo);
  361. result.Add(dependLoader);
  362. }
  363. return result;
  364. }
  365. internal void RemoveBundleProviders(List<ProviderBase> removeList)
  366. {
  367. foreach (var provider in removeList)
  368. {
  369. _providerDic.Remove(provider.ProviderGUID);
  370. }
  371. }
  372. internal bool HasAnyLoader()
  373. {
  374. return _loaderList.Count > 0;
  375. }
  376. private BundleLoaderBase CreateAssetBundleLoaderInternal(BundleInfo bundleInfo)
  377. {
  378. // 如果加载器已经存在
  379. string bundleName = bundleInfo.Bundle.BundleName;
  380. BundleLoaderBase loader = TryGetAssetBundleLoader(bundleName);
  381. if (loader != null)
  382. return loader;
  383. // 新增下载需求
  384. if (_simulationOnEditor)
  385. {
  386. loader = new VirtualBundleFileLoader(this, bundleInfo);
  387. }
  388. else
  389. {
  390. #if UNITY_WEBGL
  391. if (bundleInfo.Bundle.Buildpipeline== EDefaultBuildPipeline.RawFileBuildPipeline.ToString())
  392. loader = new RawBundleWebLoader(this, bundleInfo);
  393. else
  394. loader = new AssetBundleWebLoader(this, bundleInfo);
  395. #else
  396. if (bundleInfo.Bundle.Buildpipeline == EDefaultBuildPipeline.RawFileBuildPipeline.ToString())
  397. loader = new RawBundleFileLoader(this, bundleInfo);
  398. else
  399. loader = new AssetBundleFileLoader(this, bundleInfo);
  400. #endif
  401. }
  402. _loaderList.Add(loader);
  403. _loaderDic.Add(bundleName, loader);
  404. return loader;
  405. }
  406. private BundleLoaderBase TryGetAssetBundleLoader(string bundleName)
  407. {
  408. if (_loaderDic.TryGetValue(bundleName, out BundleLoaderBase value))
  409. return value;
  410. else
  411. return null;
  412. }
  413. private ProviderBase TryGetProvider(string providerGUID)
  414. {
  415. if (_providerDic.TryGetValue(providerGUID, out ProviderBase value))
  416. return value;
  417. else
  418. return null;
  419. }
  420. #region 调试信息
  421. internal List<DebugProviderInfo> GetDebugReportInfos()
  422. {
  423. List<DebugProviderInfo> result = new List<DebugProviderInfo>(_providerDic.Count);
  424. foreach (var provider in _providerDic.Values)
  425. {
  426. DebugProviderInfo providerInfo = new DebugProviderInfo();
  427. providerInfo.AssetPath = provider.MainAssetInfo.AssetPath;
  428. providerInfo.SpawnScene = provider.SpawnScene;
  429. providerInfo.SpawnTime = provider.SpawnTime;
  430. providerInfo.LoadingTime = provider.LoadingTime;
  431. providerInfo.RefCount = provider.RefCount;
  432. providerInfo.Status = provider.Status.ToString();
  433. providerInfo.DependBundleInfos = new List<DebugBundleInfo>();
  434. provider.GetBundleDebugInfos(providerInfo.DependBundleInfos);
  435. result.Add(providerInfo);
  436. }
  437. return result;
  438. }
  439. #endregion
  440. }
  441. }