Unity 框架

ResourceManager.cs 19KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458
  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 Coroutine LoadAssetAsync<T>(LoadResHandle<T> resHandle) where T : UnityEngine.Object
  94. {
  95. return StartCoroutine(LoadAsync(resHandle));
  96. }
  97. private IEnumerator 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. while (!request.isDone)
  104. {
  105. resHandle.OnLoading?.Invoke(request.progress);
  106. yield return null;
  107. }
  108. resHandle.OnLoading?.Invoke(1);
  109. if (!request.asset)
  110. throw new UnityException($"资源加载失败:Resources文件夹中不存在资源 {resHandle.ResourcePath}!");
  111. else
  112. asset = request.asset;
  113. }
  114. else
  115. {
  116. #if UNITY_EDITOR
  117. if (AssetConfig.RuntimeMode == UpdateMode.Editor)
  118. {
  119. resHandle.OnLoading?.Invoke(1);
  120. asset = UnityEditor.AssetDatabase.LoadAssetAtPath<T>(resHandle.AssetPath);
  121. if (asset)
  122. asset = asset as T;
  123. else
  124. throw new UnityException($"加载资源失败:路径{resHandle.AssetPath}中不存在资源 {resHandle.AssetPath}!");
  125. }
  126. else
  127. {
  128. //等待相关依赖资源的加载
  129. yield return LoadDependenciesAssetBundleAsync(resHandle.AssetBundleName.ToLower());
  130. yield return LoadAssetBundleAsync(resHandle.AssetBundleName.ToLower(), resHandle.OnLoading);
  131. if (AssetBundles.ContainsKey(resHandle.AssetBundleName.ToLower()))
  132. {
  133. //asset = AssetBundles[resHandle.AssetBundleName].LoadAsset<T>(resHandle.AssetPath);
  134. AssetBundleRequest request = AssetBundles[resHandle.AssetBundleName.ToLower()].LoadAssetAsync<T>(resHandle.AssetPath);
  135. yield return request;
  136. while (!request.isDone)
  137. {
  138. resHandle.OnLoading(request.progress / 2 + 0.5f);
  139. yield return null;
  140. }
  141. asset = request.asset;
  142. if (!asset)
  143. throw new UnityException(string.Format("加载资源失败:AB包 {0} 中不存在资源 {1}!", resHandle.AssetBundleName, resHandle.AssetPath));
  144. }
  145. }
  146. #else
  147. yield return LoadDependenciesAssetBundleAsync(resHandle.AssetBundleName);
  148. yield return LoadAssetBundleAsync(resHandle.AssetBundleName, resHandle.OnLoading);
  149. if (AssetBundles.ContainsKey(resHandle.AssetBundleName.ToLower()))
  150. {
  151. AssetBundleRequest request = AssetBundles[resHandle.AssetBundleName.ToLower()].LoadAssetAsync<T>(resHandle.AssetPath);
  152. yield return request;
  153. while(!request.isDone)
  154. {
  155. resHandle.OnLoading(request.progress / 2+0.5f);
  156. yield return null;
  157. }
  158. asset = request.asset;
  159. if (!asset)
  160. throw new UnityException(string.Format("加载资源失败:AB包 {0} 中不存在资源 {1}!", resHandle.AssetBundleName, resHandle.AssetPath));
  161. }
  162. #endif
  163. }
  164. if (asset)
  165. {
  166. resHandle.OnLoadOver?.Invoke(asset as T);
  167. }
  168. else
  169. resHandle.OnLoadOver?.Invoke(null);
  170. }
  171. /// <summary>
  172. /// 异步加载场景(Resource模式)
  173. /// </summary>
  174. /// <param name="scenePath">场景路径</param>
  175. /// <param name="onLoading">加载中事件</param>
  176. /// <param name="onLoadDone">加载完成事件</param>
  177. /// <returns></returns>
  178. public Coroutine LoadSceneAsync(string scenePath, TAction<float> OnLoading, TAction<Scene> OnLoadOver, LoadSceneMode loadSceneMode = LoadSceneMode.Single)
  179. {
  180. return StartCoroutine(LoadScene(scenePath, ResLoadMode.Resourece, "", OnLoading, OnLoadOver, loadSceneMode));
  181. }
  182. /// <summary>
  183. /// 异步加载场景
  184. /// </summary>
  185. /// <param name="scenePath">场景路径</param>
  186. /// <param name="onLoading">加载中事件</param>
  187. /// <param name="onLoadDone">加载完成事件</param>
  188. /// <returns></returns>
  189. public Coroutine LoadSceneAsync(LoadResHandle<Scene> resHandle, LoadSceneMode loadSceneMode = LoadSceneMode.Single)
  190. {
  191. return StartCoroutine(LoadScene(resHandle.AssetPath,resHandle.LoadMode,resHandle.AssetBundleName,resHandle.OnLoading,resHandle.OnLoadOver, loadSceneMode));
  192. }
  193. private IEnumerator LoadScene(string scenePath, ResLoadMode loadMode ,string assetBundleName ,TAction<float> OnLoading,TAction<Scene> OnLoadOver, LoadSceneMode loadSceneMode)
  194. {
  195. if (SceneManager.GetSceneByPath(scenePath) == CurrentScene)
  196. {
  197. Debug.LogWarning($"场景{scenePath}已加载!");
  198. yield break;
  199. }
  200. if (loadMode == ResLoadMode.Resourece)
  201. {
  202. AsyncOperation ao = SceneManager.LoadSceneAsync(scenePath, loadSceneMode);
  203. while (!ao.isDone)
  204. {
  205. OnLoading?.Invoke(ao.progress);
  206. yield return null;
  207. }
  208. }
  209. else
  210. {
  211. yield return LoadDependenciesAssetBundleAsync(assetBundleName.ToLower());
  212. #if UNITY_EDITOR
  213. if (AssetConfig.RuntimeMode == UpdateMode.Editor)
  214. {
  215. LoadSceneParameters parameters = new LoadSceneParameters()
  216. {
  217. loadSceneMode = LoadSceneMode.Single,
  218. localPhysicsMode = LocalPhysicsMode.None
  219. };
  220. AsyncOperation ao = UnityEditor.SceneManagement.EditorSceneManager.LoadSceneAsyncInPlayMode(scenePath, parameters);
  221. while (!ao.isDone)
  222. {
  223. OnLoading?.Invoke(ao.progress);
  224. yield return null;
  225. }
  226. }
  227. else
  228. {
  229. yield return LoadAssetBundleAsync(assetBundleName.ToLower(), OnLoading);
  230. AsyncOperation ao = SceneManager.LoadSceneAsync(scenePath, loadSceneMode);
  231. while (!ao.isDone)
  232. {
  233. Debug.Log($"加载场景=={ao.isDone}==完成");
  234. OnLoading?.Invoke(ao.progress);
  235. yield return null;
  236. }
  237. Debug.Log($"加载场景{scenePath}完成");
  238. }
  239. #else
  240. yield return LoadAssetBundleAsync(assetBundleName, OnLoading);
  241. AsyncOperation ao = SceneManager.LoadSceneAsync(scenePath, loadSceneMode);
  242. while (!ao.isDone)
  243. {
  244. OnLoading?.Invoke(ao.progress);
  245. yield return null;
  246. }
  247. #endif
  248. }
  249. Debug.Log($"加载场景{scenePath}完成");
  250. OnLoading?.Invoke(1);
  251. OnLoadOver?.Invoke(SceneManager.GetSceneByPath(scenePath));
  252. CurrentScene = SceneManager.GetActiveScene();
  253. //SceneManager.SetActiveScene(CurrentScene);
  254. }
  255. /// <summary>
  256. /// 异步清理内存 回收垃圾
  257. /// </summary>
  258. /// <returns></returns>
  259. public Coroutine ClearMemoryAsync()
  260. {
  261. return StartCoroutine(ClearMemory());
  262. }
  263. /// <summary>
  264. /// 清理内存,释放空闲内存(异步)
  265. /// </summary>
  266. /// <returns>协程迭代器</returns>
  267. private IEnumerator ClearMemory()
  268. {
  269. yield return Resources.UnloadUnusedAssets();
  270. GC.Collect();
  271. GC.WaitForPendingFinalizers();
  272. }
  273. /// <summary>
  274. /// 异步卸载资源
  275. /// </summary>
  276. /// <returns></returns>
  277. public Coroutine UnLoadAsstAsync(ResLoadMode resLoadMode, string assetBundleName, bool unloadAllLoadedObjects = false)
  278. {
  279. return StartCoroutine(UnLoadAsst(resLoadMode, assetBundleName, unloadAllLoadedObjects));
  280. }
  281. private IEnumerator UnLoadAsst(ResLoadMode resLoadMode, string assetBundleName, bool unloadAllLoadedObjects = false)
  282. {
  283. yield return UnLoadAsset(ResLoadMode.Resourece, assetBundleName, unloadAllLoadedObjects);
  284. }
  285. /// <summary>
  286. /// 异步卸载场景
  287. /// </summary>
  288. /// <param name="scene"></param>
  289. /// <returns></returns>
  290. public Coroutine UnloadSceneAsync(Scene scene, TAction<float> OnUnloading = null, TAction OnUnloadOver = null)
  291. {
  292. Debug.Log($"卸载场景{scene.name}");
  293. return StartCoroutine(UnloadScene(scene, OnUnloading, OnUnloadOver));
  294. }
  295. private IEnumerator UnloadScene(Scene scene, TAction<float> OnUnloading, TAction OnUnloadOver)
  296. {
  297. AsyncOperation ao = SceneManager.UnloadSceneAsync(scene);
  298. while (!ao.isDone)
  299. {
  300. OnUnloading?.Invoke(ao.progress);
  301. yield return null;
  302. }
  303. OnUnloadOver?.Invoke();
  304. CurrentScene = SceneManager.GetActiveScene();
  305. }
  306. public IEnumerator UnLoadAsset(ResLoadMode resLoadMode, string assetBundleName, bool unloadAllLoadedObjects = false)
  307. {
  308. if (resLoadMode == ResLoadMode.Resourece)
  309. {
  310. yield return Resources.UnloadUnusedAssets();
  311. }
  312. else
  313. {
  314. assetBundleName = assetBundleName.ToLower();
  315. if (AssetBundles.ContainsKey(assetBundleName))
  316. {
  317. AssetBundles[assetBundleName].Unload(unloadAllLoadedObjects);
  318. AssetBundles.Remove(assetBundleName);
  319. }
  320. yield return null;
  321. }
  322. }
  323. public async UniTask UnLoadAllABAssetAsync(bool unloadAllLoadedObjects = false)
  324. {
  325. List<string> keys = new List<string>(AssetBundles.Keys);
  326. for (int i = 0; i < keys.Count; i++)
  327. {
  328. Debug.Log($"卸载AB包{keys[i]}");
  329. await AssetBundles[keys[i]].UnloadAsync(unloadAllLoadedObjects);
  330. AssetBundles.Remove(keys[i]);
  331. }
  332. }
  333. /// <summary>
  334. /// 异步加载AB包清单
  335. /// </summary>
  336. /// <returns>协程迭代器</returns>
  337. private IEnumerator LoadAssetBundleManifestAsync()
  338. {
  339. if (string.IsNullOrEmpty(AssetConfig.AssetBundleManifestName))
  340. {
  341. throw new UnityException("请设置资源配置文件的 AssetBundleManifestName 属性,为所有AB包提供依赖清单!");
  342. }
  343. else
  344. {
  345. if (AssetBundleManifest == null)
  346. {
  347. yield return LoadAssetBundleAsync(AssetConfig.AssetBundleManifestName, null);
  348. if (AssetBundles.ContainsKey(AssetConfig.AssetBundleManifestName))
  349. {
  350. AssetBundleManifest = AssetBundles[AssetConfig.AssetBundleManifestName].LoadAsset<AssetBundleManifest>("AssetBundleManifest");
  351. UnLoadAsset(ResLoadMode.AssetBundle, AssetConfig.AssetBundleManifestName);
  352. }
  353. }
  354. }
  355. yield return null;
  356. }
  357. /// <summary>
  358. /// 异步加载AB包(提供进度回调)
  359. /// </summary>
  360. /// <param name="assetBundleName">AB包名称</param>
  361. /// <param name="onLoading">加载中事件</param>
  362. /// <param name="isManifest">是否是加载清单</param>
  363. /// <returns>协程迭代器</returns>
  364. private IEnumerator LoadAssetBundleAsync(string assetBundleName, TAction<float> onLoading)
  365. {
  366. if (!AssetBundles.ContainsKey(assetBundleName))
  367. {
  368. AssetBundleCreateRequest abRequst = AssetBundle.LoadFromFileAsync(AssetConfig.AssetBundleRootPath + assetBundleName);
  369. yield return abRequst;
  370. while (!abRequst.isDone)
  371. {
  372. onLoading?.Invoke(abRequst.progress / 2);
  373. yield return null;
  374. }
  375. if (abRequst.assetBundle)
  376. AssetBundles.Add(assetBundleName, abRequst.assetBundle);
  377. else
  378. throw new UnityException($" 未加载到AB包【{assetBundleName}】!");
  379. }
  380. onLoading?.Invoke(1);
  381. }
  382. /// <summary>
  383. /// 异步加载依赖AB包
  384. /// </summary>
  385. /// <param name="assetBundleName">AB包名称</param>
  386. /// <returns>协程迭代器</returns>
  387. private IEnumerator LoadDependenciesAssetBundleAsync(string assetBundleName)
  388. {
  389. #if UNITY_EDITOR
  390. if (AssetConfig.RuntimeMode != UpdateMode.Editor)
  391. {
  392. yield return LoadAssetBundleManifestAsync();
  393. if (AssetBundleManifest != null)
  394. {
  395. string[] dependencies = AssetBundleManifest.GetAllDependencies(assetBundleName);
  396. foreach (string item in dependencies)
  397. {
  398. if (AssetBundles.ContainsKey(item))
  399. continue;
  400. yield return LoadAssetBundleAsync(item, null);
  401. }
  402. }
  403. }
  404. #else
  405. yield return LoadAssetBundleManifestAsync();
  406. if (AssetBundleManifest != null)
  407. {
  408. string[] dependencies = AssetBundleManifest.GetAllDependencies(assetBundleName);
  409. foreach (string item in dependencies)
  410. {
  411. if (AssetBundles.ContainsKey(item))
  412. {
  413. continue;
  414. }
  415. yield return LoadAssetBundleAsync(item,null);
  416. }
  417. }
  418. #endif
  419. yield return null;
  420. }
  421. }
  422. }