Unity 框架

ResourceManager.cs 18KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443
  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, TAction<Scene> 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,TAction<Scene> 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. ao.allowSceneActivation = true;
  233. await ao.ToUniTask();
  234. OnLoading?.Invoke(1);
  235. OnLoadOver?.Invoke(SceneManager.GetSceneByPath(scenePath));
  236. SceneManager.SetActiveScene(SceneManager.GetSceneByPath(scenePath));
  237. CurrentScene = SceneManager.GetActiveScene();
  238. return CurrentScene;
  239. }
  240. /// <summary>
  241. /// 异步清理内存 回收垃圾
  242. /// </summary>
  243. /// <returns></returns>
  244. public async UniTask ClearMemoryAsync()
  245. {
  246. await ClearMemory();
  247. }
  248. /// <summary>
  249. /// 清理内存,释放空闲内存(异步)
  250. /// </summary>
  251. /// <returns>协程迭代器</returns>
  252. private async UniTask ClearMemory()
  253. {
  254. await Resources.UnloadUnusedAssets();
  255. GC.Collect();
  256. GC.WaitForPendingFinalizers();
  257. }
  258. /// <summary>
  259. /// 异步卸载资源
  260. /// </summary>
  261. /// <returns></returns>
  262. public async UniTask UnLoadAsstAsync(ResLoadMode resLoadMode, string assetBundleName, bool unloadAllLoadedObjects = false)
  263. {
  264. await UnLoadAsst(resLoadMode, assetBundleName, unloadAllLoadedObjects);
  265. }
  266. private async UniTask UnLoadAsst(ResLoadMode resLoadMode, string assetBundleName, bool unloadAllLoadedObjects = false)
  267. {
  268. await UnLoadAsset(ResLoadMode.Resourece, assetBundleName, unloadAllLoadedObjects);
  269. }
  270. /// <summary>
  271. /// 异步卸载场景
  272. /// </summary>
  273. /// <param name="scene"></param>
  274. /// <returns></returns>
  275. public async UniTask UnloadSceneAsync(Scene scene, TAction<float> OnUnloading = null, TAction OnUnloadOver = null)
  276. {
  277. Debug.Log($"卸载场景{scene.name}");
  278. await UnloadScene(scene, OnUnloading, OnUnloadOver);
  279. }
  280. private async UniTask UnloadScene(Scene scene, TAction<float> OnUnloading, TAction OnUnloadOver)
  281. {
  282. AsyncOperation ao = SceneManager.UnloadSceneAsync(scene);
  283. while (!ao.isDone)
  284. {
  285. OnUnloading?.Invoke(ao.progress);
  286. await UniTask.Yield();
  287. }
  288. OnUnloadOver?.Invoke();
  289. CurrentScene = SceneManager.GetActiveScene();
  290. }
  291. public async UniTask UnLoadAsset(ResLoadMode resLoadMode, string assetBundleName, bool unloadAllLoadedObjects = false)
  292. {
  293. if (resLoadMode == ResLoadMode.Resourece)
  294. {
  295. await Resources.UnloadUnusedAssets();
  296. }
  297. else
  298. {
  299. assetBundleName = assetBundleName.ToLower();
  300. if (AssetBundles.ContainsKey(assetBundleName))
  301. {
  302. AssetBundles[assetBundleName].Unload(unloadAllLoadedObjects);
  303. AssetBundles.Remove(assetBundleName);
  304. }
  305. await UniTask.Yield();
  306. }
  307. }
  308. public async UniTask UnLoadAllABAssetAsync(bool unloadAllLoadedObjects = false)
  309. {
  310. List<string> keys = new List<string>(AssetBundles.Keys);
  311. for (int i = 0; i < keys.Count; i++)
  312. {
  313. Debug.Log($"卸载AB包{keys[i]}");
  314. await AssetBundles[keys[i]].UnloadAsync(unloadAllLoadedObjects);
  315. AssetBundles.Remove(keys[i]);
  316. }
  317. }
  318. /// <summary>
  319. /// 异步加载AB包清单
  320. /// </summary>
  321. /// <returns>协程迭代器</returns>
  322. private async UniTask LoadAssetBundleManifestAsync()
  323. {
  324. if (string.IsNullOrEmpty(AssetConfig.AssetBundleManifestName))
  325. {
  326. throw new UnityException("请设置资源配置文件的 AssetBundleManifestName 属性,为所有AB包提供依赖清单!");
  327. }
  328. else
  329. {
  330. if (AssetBundleManifest == null)
  331. {
  332. await LoadAssetBundleAsync(AssetConfig.AssetBundleManifestName, null);
  333. if (AssetBundles.ContainsKey(AssetConfig.AssetBundleManifestName))
  334. {
  335. AssetBundleManifest = AssetBundles[AssetConfig.AssetBundleManifestName].LoadAsset<AssetBundleManifest>("AssetBundleManifest");
  336. await UnLoadAsset(ResLoadMode.AssetBundle, AssetConfig.AssetBundleManifestName);
  337. }
  338. }
  339. }
  340. }
  341. /// <summary>
  342. /// 异步加载AB包(提供进度回调)
  343. /// </summary>
  344. /// <param name="assetBundleName">AB包名称</param>
  345. /// <param name="onLoading">加载中事件</param>
  346. /// <param name="isManifest">是否是加载清单</param>
  347. /// <returns>协程迭代器</returns>
  348. private async UniTask LoadAssetBundleAsync(string assetBundleName, TAction<float> onLoading)
  349. {
  350. if (!AssetBundles.ContainsKey(assetBundleName))
  351. {
  352. AssetBundleCreateRequest abRequst = AssetBundle.LoadFromFileAsync(AssetConfig.AssetBundleRootPath + assetBundleName);
  353. await abRequst;
  354. while (!abRequst.isDone)
  355. {
  356. onLoading?.Invoke(abRequst.progress / 2);
  357. await UniTask.Yield();
  358. }
  359. if (abRequst.assetBundle)
  360. AssetBundles.Add(assetBundleName, abRequst.assetBundle);
  361. else
  362. throw new UnityException($" 未加载到AB包【{assetBundleName}】!");
  363. }
  364. onLoading?.Invoke(1);
  365. }
  366. /// <summary>
  367. /// 异步加载依赖AB包
  368. /// </summary>
  369. /// <param name="assetBundleName">AB包名称</param>
  370. /// <returns>协程迭代器</returns>
  371. private async UniTask LoadDependenciesAssetBundleAsync(string assetBundleName)
  372. {
  373. #if UNITY_EDITOR
  374. if (AssetConfig.RuntimeMode != UpdateMode.Editor)
  375. {
  376. await LoadAssetBundleManifestAsync();
  377. if (AssetBundleManifest != null)
  378. {
  379. string[] dependencies = AssetBundleManifest.GetAllDependencies(assetBundleName);
  380. foreach (string item in dependencies)
  381. {
  382. if (AssetBundles.ContainsKey(item))
  383. continue;
  384. await LoadAssetBundleAsync(item, null);
  385. }
  386. }
  387. }
  388. #else
  389. await LoadAssetBundleManifestAsync();
  390. if (AssetBundleManifest != null)
  391. {
  392. string[] dependencies = AssetBundleManifest.GetAllDependencies(assetBundleName);
  393. foreach (string item in dependencies)
  394. {
  395. if (AssetBundles.ContainsKey(item))
  396. continue;
  397. await LoadAssetBundleAsync(item, null);
  398. }
  399. }
  400. #endif
  401. }
  402. }
  403. }