Unity 框架

ResourceManager.cs 18KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450
  1. using Cysharp.Threading.Tasks;
  2. using System;
  3. using System.Collections;
  4. using System.Collections.Generic;
  5. using System.Threading.Tasks;
  6. using UnityEngine;
  7. using UnityEngine.SceneManagement;
  8. namespace TFramework
  9. {
  10. public class ResourceManager : BaseManager
  11. {
  12. /// <summary>
  13. /// 所有AssetBundle资源包清单
  14. /// </summary>
  15. public AssetBundleManifest AssetBundleManifest { get; private set; }
  16. /// <summary>
  17. /// 缓存的所有AssetBundle包【AB包名称、AB包】
  18. /// </summary>
  19. public Dictionary<string, AssetBundle> AssetBundles { get; private set; } = new Dictionary<string, AssetBundle>();
  20. /// <summary>
  21. /// 当前激活的场景
  22. /// </summary>
  23. public Scene CurrentScene { get; private set; }
  24. public void Awake()
  25. {
  26. CurrentScene= SceneManager.GetActiveScene();
  27. }
  28. public T LoadAsset<T>(LoadResHandle<T> resHandle) where T : UnityEngine.Object
  29. {
  30. return LoadAsset<T>(resHandle.ResourcePath, resHandle.AssetPath, resHandle.AssetBundleName, resHandle.LoadMode);
  31. }
  32. /// <summary>
  33. /// 同步加载资源
  34. /// </summary>
  35. /// <typeparam name="T"></typeparam>
  36. /// <param name="resPath"></param>
  37. /// <param name="assetPath"></param>
  38. /// <param name="assetBundleName"></param>
  39. /// <param name="resLoadMode"></param>
  40. /// <returns></returns>
  41. public T LoadAsset<T>(string resPath, string assetPath, string assetBundleName = "", ResLoadMode resLoadMode = ResLoadMode.Resourece) where T : UnityEngine.Object
  42. {
  43. if (resLoadMode == ResLoadMode.Resourece)
  44. return Resources.Load<T>(resPath);
  45. else
  46. {
  47. #if UNITY_EDITOR
  48. if (AssetConfig.RuntimeMode == UpdateMode.Editor)
  49. return UnityEditor.AssetDatabase.LoadAssetAtPath<T>(assetPath);
  50. #endif
  51. assetBundleName = assetBundleName.ToLower();
  52. if (AssetBundleManifest == null)
  53. {
  54. if (!AssetBundles.ContainsKey(AssetConfig.AssetBundleManifestName))
  55. AssetBundles.Add(AssetConfig.AssetBundleManifestName,
  56. AssetBundle.LoadFromFile(AssetConfig.AssetBundleRootPath + AssetConfig.AssetBundleManifestName));
  57. AssetBundleManifest = AssetBundles[AssetConfig.AssetBundleManifestName].LoadAsset<AssetBundleManifest>("AssetBundleManifest");
  58. }
  59. string[] dependencies = AssetBundleManifest.GetAllDependencies(assetBundleName);
  60. for (int i = 0; i < dependencies.Length; i++)
  61. {
  62. if (!AssetBundles.ContainsKey(dependencies[i]))
  63. AssetBundles.Add(dependencies[i], AssetBundle.LoadFromFile(AssetConfig.AssetBundleRootPath + dependencies[i]));
  64. }
  65. if (!AssetBundles.ContainsKey(assetBundleName))
  66. AssetBundles.Add(assetBundleName, AssetBundle.LoadFromFile(AssetConfig.AssetBundleRootPath + assetBundleName));
  67. return AssetBundles[assetBundleName].LoadAsset<T>(assetPath);
  68. }
  69. }
  70. /// <summary>
  71. /// 同步加载Resources下的资源
  72. /// </summary>
  73. /// <typeparam name="T">资源类型</typeparam>
  74. /// <param name="resPath">资源路径</param>
  75. /// <returns></returns>
  76. public T LoadAsset<T>(string resPath) where T : UnityEngine.Object => LoadAsset<T>(resPath, "", "");
  77. /// <summary>
  78. /// 同步加载AssetBundle资源
  79. /// </summary>
  80. /// <typeparam name="T">资源类型</typeparam>
  81. /// <param name="assetPath">资源路径</param>
  82. /// <param name="assetBundleName">AB包名</param>
  83. /// <returns></returns>
  84. public T LoadAsset<T>(string assetPath, string assetBundleName) where T : UnityEngine.Object => LoadAsset<T>("", assetPath, assetBundleName, ResLoadMode.AssetBundle);
  85. /// <summary>
  86. /// 异步加载资源
  87. /// </summary>
  88. /// <typeparam name="T">资源类型</typeparam>
  89. /// <param name="resPath">资源路径</param>
  90. /// <param name="onLoading">加载中事件</param>
  91. /// <param name="onLoadDone">加载完成事件</param>
  92. /// <returns></returns>
  93. public async UniTask<T> LoadAssetAsync<T>(LoadResHandle<T> resHandle) where T : UnityEngine.Object
  94. {
  95. return await LoadAsync(resHandle);
  96. }
  97. private async UniTask<T> LoadAsync<T>(LoadResHandle<T> resHandle) where T : UnityEngine.Object
  98. {
  99. UnityEngine.Object asset = null;
  100. if (resHandle.LoadMode == ResLoadMode.Resourece)
  101. {
  102. ResourceRequest request = Resources.LoadAsync<T>(resHandle.ResourcePath);
  103. await request.ToUniTask(Progress.Create<float>(pro =>
  104. {
  105. resHandle.OnLoading?.Invoke(pro);
  106. }));
  107. if (!request.asset)
  108. throw new UnityException($"资源加载失败:Resources文件夹中不存在资源 {resHandle.ResourcePath}!");
  109. else
  110. asset = request.asset;
  111. }
  112. else
  113. {
  114. #if UNITY_EDITOR
  115. if (AssetConfig.RuntimeMode == UpdateMode.Editor)
  116. {
  117. resHandle.OnLoading?.Invoke(1);
  118. asset = UnityEditor.AssetDatabase.LoadAssetAtPath<T>(resHandle.AssetPath);
  119. if (asset)
  120. asset = asset as T;
  121. else
  122. throw new UnityException($"加载资源失败:路径{resHandle.AssetPath}中不存在资源 {resHandle.AssetPath}!");
  123. }
  124. else
  125. {
  126. //等待相关依赖资源的加载
  127. await LoadDependenciesAssetBundleAsync(resHandle.AssetBundleName.ToLower());
  128. await LoadAssetBundleAsync(resHandle.AssetBundleName.ToLower(), resHandle.OnLoading);
  129. if (AssetBundles.ContainsKey(resHandle.AssetBundleName.ToLower()))
  130. {
  131. //asset = AssetBundles[resHandle.AssetBundleName].LoadAsset<T>(resHandle.AssetPath);
  132. AssetBundleRequest request = AssetBundles[resHandle.AssetBundleName.ToLower()].LoadAssetAsync<T>(resHandle.AssetPath);
  133. await request;
  134. await request.ToUniTask(Progress.Create<float>(pro =>
  135. {
  136. resHandle.OnLoading?.Invoke(pro);
  137. }));
  138. asset = request.asset;
  139. if (!asset)
  140. throw new UnityException(string.Format("加载资源失败:AB包 {0} 中不存在资源 {1}!", resHandle.AssetBundleName, resHandle.AssetPath));
  141. }
  142. }
  143. #else
  144. await LoadDependenciesAssetBundleAsync(resHandle.AssetBundleName.ToLower());
  145. await LoadAssetBundleAsync(resHandle.AssetBundleName.ToLower(), resHandle.OnLoading);
  146. if (AssetBundles.ContainsKey(resHandle.AssetBundleName.ToLower()))
  147. {
  148. AssetBundleRequest request = AssetBundles[resHandle.AssetBundleName.ToLower()].LoadAssetAsync<T>(resHandle.AssetPath);
  149. await request;
  150. await request.ToUniTask(Progress.Create<float>(pro =>
  151. {
  152. resHandle.OnLoading?.Invoke(pro);
  153. }));
  154. asset = request.asset;
  155. if (!asset)
  156. throw new UnityException(string.Format("加载资源失败:AB包 {0} 中不存在资源 {1}!", resHandle.AssetBundleName, resHandle.AssetPath));
  157. }
  158. #endif
  159. }
  160. if (asset)
  161. {
  162. resHandle.OnLoadOver?.Invoke(asset as T);
  163. }
  164. else
  165. resHandle.OnLoadOver?.Invoke(null);
  166. return asset as T;
  167. }
  168. /// <summary>
  169. /// 异步加载场景(Resource模式)
  170. /// </summary>
  171. /// <param name="scenePath">场景路径</param>
  172. /// <param name="onLoading">加载中事件</param>
  173. /// <param name="onLoadDone">加载完成事件</param>
  174. /// <returns></returns>
  175. public async UniTask<Scene> LoadSceneAsync(string scenePath, TAction<float> OnLoading, TFuncAsync<Scene, bool> OnLoadOver, LoadSceneMode loadSceneMode = LoadSceneMode.Single)
  176. {
  177. return await LoadScene(scenePath, ResLoadMode.Resourece, "", OnLoading, OnLoadOver, loadSceneMode);
  178. }
  179. /// <summary>
  180. /// 异步加载场景
  181. /// </summary>
  182. /// <param name="scenePath">场景路径</param>
  183. /// <param name="onLoading">加载中事件</param>
  184. /// <param name="onLoadDone">加载完成事件</param>
  185. /// <returns></returns>
  186. public async UniTask<Scene> LoadSceneAsync(LoadResHandle<Scene> resHandle, LoadSceneMode loadSceneMode = LoadSceneMode.Single)
  187. {
  188. return await LoadScene(resHandle.AssetPath,resHandle.LoadMode,resHandle.AssetBundleName,resHandle.OnLoading,resHandle.OnLoadOver, loadSceneMode);
  189. }
  190. private async UniTask<Scene> LoadScene(string scenePath, ResLoadMode loadMode ,string assetBundleName ,TAction<float> OnLoading,TFuncAsync<Scene, bool> OnLoadOver, LoadSceneMode loadSceneMode)
  191. {
  192. if (SceneManager.GetSceneByPath(scenePath) == CurrentScene)
  193. {
  194. Debug.LogWarning($"场景{scenePath}已加载!");
  195. return CurrentScene;
  196. }
  197. AsyncOperation ao;
  198. if (loadMode == ResLoadMode.Resourece)
  199. {
  200. ao = SceneManager.LoadSceneAsync(scenePath, loadSceneMode);
  201. }
  202. else
  203. {
  204. await LoadDependenciesAssetBundleAsync(assetBundleName.ToLower());
  205. #if UNITY_EDITOR
  206. if (AssetConfig.RuntimeMode == UpdateMode.Editor)
  207. {
  208. LoadSceneParameters parameters = new LoadSceneParameters()
  209. {
  210. loadSceneMode = LoadSceneMode.Single,
  211. localPhysicsMode = LocalPhysicsMode.None
  212. };
  213. ao = UnityEditor.SceneManagement.EditorSceneManager.LoadSceneAsyncInPlayMode(scenePath, parameters);
  214. }
  215. else
  216. {
  217. await LoadAssetBundleAsync(assetBundleName.ToLower(), OnLoading);
  218. ao = SceneManager.LoadSceneAsync(scenePath, loadSceneMode);
  219. }
  220. #else
  221. await LoadAssetBundleAsync(assetBundleName, OnLoading);
  222. ao = SceneManager.LoadSceneAsync(scenePath, loadSceneMode);
  223. #endif
  224. }
  225. ao.allowSceneActivation = false;
  226. while (ao.progress < 0.9f)
  227. {
  228. OnLoading?.Invoke(ao.progress);
  229. await UniTask.Yield();
  230. }
  231. Debug.Log($"加载场景{scenePath}完成");
  232. OnLoading?.Invoke(1);
  233. if(OnLoadOver != null)
  234. {
  235. if (await OnLoadOver.Invoke(SceneManager.GetSceneByPath(scenePath)))
  236. {
  237. ao.allowSceneActivation = true;
  238. }
  239. }
  240. else
  241. ao.allowSceneActivation = true;
  242. await ao.ToUniTask();
  243. SceneManager.SetActiveScene(SceneManager.GetSceneByPath(scenePath));
  244. CurrentScene = SceneManager.GetActiveScene();
  245. return CurrentScene;
  246. }
  247. /// <summary>
  248. /// 异步清理内存 回收垃圾
  249. /// </summary>
  250. /// <returns></returns>
  251. public async UniTask ClearMemoryAsync()
  252. {
  253. await ClearMemory();
  254. }
  255. /// <summary>
  256. /// 清理内存,释放空闲内存(异步)
  257. /// </summary>
  258. /// <returns>协程迭代器</returns>
  259. private async UniTask ClearMemory()
  260. {
  261. await Resources.UnloadUnusedAssets();
  262. GC.Collect();
  263. GC.WaitForPendingFinalizers();
  264. }
  265. /// <summary>
  266. /// 异步卸载资源
  267. /// </summary>
  268. /// <returns></returns>
  269. public async UniTask UnLoadAsstAsync(ResLoadMode resLoadMode, string assetBundleName, bool unloadAllLoadedObjects = false)
  270. {
  271. await UnLoadAsst(resLoadMode, assetBundleName, unloadAllLoadedObjects);
  272. }
  273. private async UniTask UnLoadAsst(ResLoadMode resLoadMode, string assetBundleName, bool unloadAllLoadedObjects = false)
  274. {
  275. await UnLoadAsset(ResLoadMode.Resourece, assetBundleName, unloadAllLoadedObjects);
  276. }
  277. /// <summary>
  278. /// 异步卸载场景
  279. /// </summary>
  280. /// <param name="scene"></param>
  281. /// <returns></returns>
  282. public async UniTask UnloadSceneAsync(Scene scene, TAction<float> OnUnloading = null, TAction OnUnloadOver = null)
  283. {
  284. Debug.Log($"卸载场景{scene.name}");
  285. await UnloadScene(scene, OnUnloading, OnUnloadOver);
  286. }
  287. private async UniTask UnloadScene(Scene scene, TAction<float> OnUnloading, TAction OnUnloadOver)
  288. {
  289. AsyncOperation ao = SceneManager.UnloadSceneAsync(scene);
  290. while (!ao.isDone)
  291. {
  292. OnUnloading?.Invoke(ao.progress);
  293. await UniTask.Yield();
  294. }
  295. OnUnloadOver?.Invoke();
  296. CurrentScene = SceneManager.GetActiveScene();
  297. }
  298. public async UniTask UnLoadAsset(ResLoadMode resLoadMode, string assetBundleName, bool unloadAllLoadedObjects = false)
  299. {
  300. if (resLoadMode == ResLoadMode.Resourece)
  301. {
  302. await Resources.UnloadUnusedAssets();
  303. }
  304. else
  305. {
  306. assetBundleName = assetBundleName.ToLower();
  307. if (AssetBundles.ContainsKey(assetBundleName))
  308. {
  309. AssetBundles[assetBundleName].Unload(unloadAllLoadedObjects);
  310. AssetBundles.Remove(assetBundleName);
  311. }
  312. await UniTask.Yield();
  313. }
  314. }
  315. public async UniTask UnLoadAllABAssetAsync(bool unloadAllLoadedObjects = false)
  316. {
  317. List<string> keys = new List<string>(AssetBundles.Keys);
  318. for (int i = 0; i < keys.Count; i++)
  319. {
  320. Debug.Log($"卸载AB包{keys[i]}");
  321. await AssetBundles[keys[i]].UnloadAsync(unloadAllLoadedObjects);
  322. AssetBundles.Remove(keys[i]);
  323. }
  324. }
  325. /// <summary>
  326. /// 异步加载AB包清单
  327. /// </summary>
  328. /// <returns>协程迭代器</returns>
  329. private async UniTask LoadAssetBundleManifestAsync()
  330. {
  331. if (string.IsNullOrEmpty(AssetConfig.AssetBundleManifestName))
  332. {
  333. throw new UnityException("请设置资源配置文件的 AssetBundleManifestName 属性,为所有AB包提供依赖清单!");
  334. }
  335. else
  336. {
  337. if (AssetBundleManifest == null)
  338. {
  339. await LoadAssetBundleAsync(AssetConfig.AssetBundleManifestName, null);
  340. if (AssetBundles.ContainsKey(AssetConfig.AssetBundleManifestName))
  341. {
  342. AssetBundleManifest = AssetBundles[AssetConfig.AssetBundleManifestName].LoadAsset<AssetBundleManifest>("AssetBundleManifest");
  343. await UnLoadAsset(ResLoadMode.AssetBundle, AssetConfig.AssetBundleManifestName);
  344. }
  345. }
  346. }
  347. }
  348. /// <summary>
  349. /// 异步加载AB包(提供进度回调)
  350. /// </summary>
  351. /// <param name="assetBundleName">AB包名称</param>
  352. /// <param name="onLoading">加载中事件</param>
  353. /// <param name="isManifest">是否是加载清单</param>
  354. /// <returns>协程迭代器</returns>
  355. private async UniTask LoadAssetBundleAsync(string assetBundleName, TAction<float> onLoading)
  356. {
  357. if (!AssetBundles.ContainsKey(assetBundleName))
  358. {
  359. AssetBundleCreateRequest abRequst = AssetBundle.LoadFromFileAsync(AssetConfig.AssetBundleRootPath + assetBundleName);
  360. await abRequst;
  361. while (!abRequst.isDone)
  362. {
  363. onLoading?.Invoke(abRequst.progress / 2);
  364. await UniTask.Yield();
  365. }
  366. if (abRequst.assetBundle)
  367. AssetBundles.Add(assetBundleName, abRequst.assetBundle);
  368. else
  369. throw new UnityException($" 未加载到AB包【{assetBundleName}】!");
  370. }
  371. onLoading?.Invoke(1);
  372. }
  373. /// <summary>
  374. /// 异步加载依赖AB包
  375. /// </summary>
  376. /// <param name="assetBundleName">AB包名称</param>
  377. /// <returns>协程迭代器</returns>
  378. private async UniTask LoadDependenciesAssetBundleAsync(string assetBundleName)
  379. {
  380. #if UNITY_EDITOR
  381. if (AssetConfig.RuntimeMode != UpdateMode.Editor)
  382. {
  383. await LoadAssetBundleManifestAsync();
  384. if (AssetBundleManifest != null)
  385. {
  386. string[] dependencies = AssetBundleManifest.GetAllDependencies(assetBundleName);
  387. foreach (string item in dependencies)
  388. {
  389. if (AssetBundles.ContainsKey(item))
  390. continue;
  391. await LoadAssetBundleAsync(item, null);
  392. }
  393. }
  394. }
  395. #else
  396. await LoadAssetBundleManifestAsync();
  397. if (AssetBundleManifest != null)
  398. {
  399. string[] dependencies = AssetBundleManifest.GetAllDependencies(assetBundleName);
  400. foreach (string item in dependencies)
  401. {
  402. if (AssetBundles.ContainsKey(item))
  403. continue;
  404. await LoadAssetBundleAsync(item, null);
  405. }
  406. }
  407. #endif
  408. }
  409. }
  410. }