当前位置:   article > 正文

U3D客户端框架(资源管理篇)之资源加载管理器_unity中资源管理模块设计

unity中资源管理模块设计

一、资源加载管理器模块设计

模块设计

资源加载管理器模块的主要职责就是资源加载的管理,从物理结构上对该模块进行了拆分成了一个单独的文件,资源加载管理器是加载器中偏底层的一个部分;资源加载管理器负责AssetBundle的加载、Asset资源的加载、资源加载完成后缓存进对预制池、卸载功能;

UML静态图

 

二、代码实现

  1. using System;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using System.Linq;
  5. using System.Text;
  6. using System.Threading.Tasks;
  7. using YouYou;
  8. using UnityEngine;
  9. namespace Myh
  10. {
  11. //资源加载管理
  12. public class ResourceLoaderManager : ManagerBase, IDisposable
  13. {
  14. //资源加载管理器
  15. //资源分类:{资源名:资源实体}
  16. private Dictionary<AssetCategory, Dictionary<string, AssetEntity>> m_dicAssetInfo;
  17. //资源包加载器链表
  18. private LinkedList<AssetBundleLoaderRoutine> m_ListAssetBundleLoader;
  19. //资源加载链表
  20. private LinkedList<AssetLoaderRoutine> m_ListAssetLoader;
  21. //加载中的资源
  22. private Dictionary<string, LinkedList<Action<UnityEngine.Object>>> m_dicLoadingAsset = new Dictionary<string, LinkedList<Action<UnityEngine.Object>>>();
  23. //初始化资源信息完毕
  24. private BaseAction m_InitAssetInfoComplete;
  25. private Dictionary<string, LinkedList<Action<AssetBundle>>> m_dicLoadingAssetBundle = new Dictionary<string, LinkedList<Action<AssetBundle>>>();
  26. public ResourceLoaderManager()
  27. {
  28. m_dicAssetInfo = new Dictionary<AssetCategory, Dictionary<string, AssetEntity>>();
  29. m_ListAssetBundleLoader = new LinkedList<AssetBundleLoaderRoutine>();
  30. m_ListAssetLoader = new LinkedList<AssetLoaderRoutine>();
  31. }
  32. //初始化
  33. public override void Init()
  34. {
  35. //确保游戏刚开始运行的时候,分类字典已经初始化好了
  36. IEnumerator iter = Enum.GetValues(typeof(AssetCategory)).GetEnumerator();
  37. while (iter.MoveNext())
  38. {
  39. AssetCategory assetCategory = (AssetCategory)iter.Current;
  40. m_dicAssetInfo[assetCategory] = new Dictionary<string, AssetEntity>();
  41. }
  42. }
  43. #region 初始化资源信息
  44. //初始化资源信息(这个才是真正的初始化函数)
  45. private void InitAssetInfo(byte[] buffer)
  46. {
  47. buffer = ZlibHelper.DeCompressBytes(buffer);
  48. MMO_MemoryStream ms = new MMO_MemoryStream(buffer);
  49. int len = ms.ReadInt();
  50. int depLen = 0;
  51. for (int i = 0; i < len; ++i)
  52. {
  53. AssetEntity entity = new AssetEntity();
  54. entity.Category = (AssetCategory)ms.ReadByte();
  55. entity.AssetFullName = ms.ReadUTF8String();
  56. entity.AssetBundleName = ms.ReadUTF8String();
  57. depLen = ms.ReadInt();
  58. //有依赖的资源包
  59. if (depLen > 0)
  60. {
  61. entity.ListDependsAsset = new List<AssetDependsEntity>();
  62. //对依赖的资源包进行循环
  63. for (int j = 0; j < depLen; ++j)
  64. {
  65. AssetDependsEntity assetDependsEntity = new AssetDependsEntity();
  66. assetDependsEntity.Category = (AssetCategory)ms.ReadByte();
  67. assetDependsEntity.AssetFullName = ms.ReadUTF8String();
  68. entity.ListDependsAsset.Add(assetDependsEntity);
  69. }
  70. }
  71. m_dicAssetInfo[entity.Category][entity.AssetFullName] = entity;
  72. }
  73. m_InitAssetInfoComplete?.Invoke();
  74. }
  75. //从CDN加载资源信息
  76. private void OnLoadAssetInfoFromCDN(HttpCallBackArgs args)
  77. {
  78. if (!args.HasError)
  79. {
  80. InitAssetInfo(args.Data);
  81. }
  82. else
  83. {
  84. GameEntry.Log(LogCategory.Resource, args.Value);
  85. }
  86. }
  87. #region 初始化资源信息
  88. //初始化资源信息
  89. public void InitAssetInfo(BaseAction initAssetInfoComplete)
  90. {
  91. m_InitAssetInfoComplete = initAssetInfoComplete;
  92. //资源信息?
  93. byte[] buffer = GameEntry.Resource.ResManager.LocalAssetsManager.GetFileBuffer(ConstDefine.AssetInfoName);
  94. if (buffer == null)
  95. {
  96. //如果只读区没有,从CDN读
  97. string url = string.Format("{0}{1}", GameEntry.Data.SysDataManager.CurrChannelConfig.RealSourceUrl, ConstDefine.AssetInfoName);
  98. GameEntry.Http.SendData(url, OnLoadAssetInfoFromCDN, isGetData: true);
  99. }
  100. else
  101. {
  102. InitAssetInfo(buffer);
  103. }
  104. }
  105. //根据资源分类和资源路径 获取资源信息
  106. public AssetEntity GetAssetEntity(AssetCategory assetCategory, string assetFullName)
  107. {
  108. Dictionary<string, AssetEntity> dicCategory = null;
  109. if (m_dicAssetInfo.TryGetValue(assetCategory, out dicCategory))
  110. {
  111. AssetEntity entity = null;
  112. if (dicCategory.TryGetValue(assetFullName, out entity))
  113. {
  114. return entity;
  115. }
  116. }
  117. return null;
  118. }
  119. #endregion
  120. #endregion
  121. #region 加载资源包 LoadAssetBundle
  122. //加载中的资源包
  123. //{资源包名:加载资源包完成的回调list}
  124. /// <summary>
  125. /// 加载资源包
  126. /// </summary>
  127. /// <param name="assetBundlePath">ab包路径</param>
  128. /// <param name="onUpdate">加载中回调</param>
  129. /// <param name="onComplete">加载完成回调</param>
  130. public void LoadAssetBundle(string assetBundlePath, Action<float> onUpdate = null, Action<AssetBundle> onComplete = null)
  131. {
  132. //1.判断资源包是否存在于AssetBundlePool中
  133. ResourceEntity resourceEntity = GameEntry.Pool.AssetBundlePool.Spawn(assetBundlePath);
  134. //资源在资源包池中 存在
  135. if (resourceEntity != null)
  136. {
  137. AssetBundle assetBundle = resourceEntity.Target as AssetBundle;
  138. onComplete?.Invoke(assetBundle);
  139. return;
  140. }
  141. //资源在资源包池中 不存在
  142. LinkedList<Action<AssetBundle>> lst = null;
  143. if (m_dicLoadingAssetBundle.TryGetValue(assetBundlePath, out lst))
  144. {
  145. //如果存在加载中的assetbundle,把加载完成的回调函数 加入这个资源加载的链表,然后返回
  146. lst.AddLast(onComplete);
  147. return;
  148. }
  149. else
  150. {
  151. lst = GameEntry.Pool.DequeueClassObject<LinkedList<Action<AssetBundle>>>();
  152. lst.AddLast(onComplete);
  153. m_dicLoadingAssetBundle[assetBundlePath] = lst;
  154. }
  155. //资源包加载routine
  156. AssetBundleLoaderRoutine routine = GameEntry.Pool.DequeueClassObject<AssetBundleLoaderRoutine>();
  157. //这句话可以不加,Dequeue的时候如果没有一定会new一个
  158. if (null == routine)
  159. {
  160. routine = new AssetBundleLoaderRoutine();
  161. }
  162. //加入链表还是循环加载
  163. m_ListAssetBundleLoader.AddLast(routine);
  164. //开始加载assetBundle
  165. routine.LoadAssetBundle(assetBundlePath);
  166. //注册更新回调
  167. routine.OnAssetBundleCreateUpdate = (float progress) =>
  168. {
  169. onUpdate?.Invoke(progress);
  170. };
  171. routine.OnLoadAssetBundleComplete = (AssetBundle assetBundle) =>
  172. {
  173. //把资源包注册到资源池
  174. resourceEntity = GameEntry.Pool.DequeueClassObject<ResourceEntity>();
  175. resourceEntity.ResourceName = assetBundlePath;
  176. resourceEntity.IsAssetBundle = true;
  177. resourceEntity.Target = assetBundle;
  178. GameEntry.Pool.AssetBundlePool.Register(resourceEntity);
  179. //加载完成后,执行所有回调函数
  180. for (LinkedListNode<Action<AssetBundle>> iter = lst.First; iter != null; iter = iter.Next)
  181. {
  182. iter.Value?.Invoke(assetBundle);
  183. }
  184. //一定要清空
  185. lst.Clear();
  186. GameEntry.Pool.EnqueueClassObject(lst);
  187. //下载完成后,从下载中字段中清除这个字典
  188. m_dicLoadingAssetBundle.Remove(assetBundlePath);
  189. //结束循环 routine回池
  190. m_ListAssetBundleLoader.Remove(routine);
  191. GameEntry.Pool.EnqueueClassObject(routine);
  192. };
  193. }
  194. #endregion
  195. #region 从资源包中加载资源 LoadAsset
  196. /// <param name="assetName">资源名</param>
  197. /// <param name="assetBundle">assetBundle包</param>
  198. /// <param name="onUpdate">加载中回调</param>
  199. /// <param name="onComplete">加载完成回调</param>
  200. public void LoadAsset(string assetName, AssetBundle assetBundle, Action<float> onUpdate = null, Action<UnityEngine.Object> onComplete = null)
  201. {
  202. LinkedList<Action<UnityEngine.Object>> lst = null;
  203. //这个资源在加载中
  204. if (m_dicLoadingAsset.TryGetValue(assetName, out lst))
  205. {
  206. //把加载完成回调函数(委托)加入到对应的链表中,然后直接返回
  207. lst.AddLast(onComplete);
  208. return;
  209. }
  210. else
  211. {
  212. //如果不在加载中
  213. //从类对象池取一个对象,把链表保存到字典中
  214. lst = GameEntry.Pool.DequeueClassObject<LinkedList<Action<UnityEngine.Object>>>();
  215. lst.AddLast(onComplete);
  216. m_dicLoadingAsset[assetName] = lst;
  217. }
  218. AssetLoaderRoutine routine = GameEntry.Pool.DequeueClassObject<AssetLoaderRoutine>();
  219. if (routine == null)
  220. routine = new AssetLoaderRoutine();
  221. m_ListAssetLoader.AddLast(routine);
  222. //开始加载资源
  223. routine.LoadAsset(assetName, assetBundle);
  224. //下载中更新回调
  225. routine.OnAssetUpdate = (float progress) =>
  226. {
  227. onUpdate?.Invoke(progress);
  228. };
  229. //下载完成回调
  230. routine.OnLoadAssetComplete = (UnityEngine.Object obj) =>
  231. {
  232. for (LinkedListNode<Action<UnityEngine.Object>> iter = lst.First; iter != null; iter = iter.Next)
  233. {
  234. iter.Value?.Invoke(obj);
  235. }
  236. //一定要清空
  237. lst.Clear();
  238. //链表回池
  239. GameEntry.Pool.EnqueueClassObject(lst);
  240. //资源对应的链表从字典删除
  241. m_dicLoadingAsset.Remove(assetName);
  242. //结束循环
  243. m_ListAssetLoader.Remove(routine);
  244. //资源加载器回池
  245. GameEntry.Pool.EnqueueClassObject(routine);
  246. };
  247. }
  248. #endregion
  249. /// <summary>
  250. /// 加载主资源
  251. /// </summary>
  252. /// <param name="assetCategory">资源分类</param>
  253. /// <param name="assetFullName">资源完整名称</param>
  254. /// <param name="onComplete">加载完成回调</param>
  255. public void LoadMainAsset(AssetCategory assetCategory, string assetFullName, BaseAction<ResourceEntity> onComplete = null)
  256. {
  257. MainAssetLoaderRoutine routine = GameEntry.Pool.DequeueClassObject<MainAssetLoaderRoutine>();
  258. //加载
  259. routine.LoadAsset(assetCategory, assetFullName,(ResourceEntity resEntity)=>
  260. {
  261. onComplete?.Invoke(resEntity);
  262. });
  263. }
  264. //释放资源
  265. public void UnLoadGameObject(GameObject go)
  266. {
  267. GameEntry.Pool.ReleaseInstanceResource(go.GetInstanceID());
  268. }
  269. // 更新所有 AssetBundleLoaderRoutine
  270. // 更新所有 AssetLoaderRoutine
  271. public void OnUpdate()
  272. {
  273. for (LinkedListNode<AssetBundleLoaderRoutine> iter = m_ListAssetBundleLoader.First; iter!=null; iter= iter.Next)
  274. {
  275. iter.Value.OnUpdate();
  276. }
  277. for (LinkedListNode<AssetLoaderRoutine> iter = m_ListAssetLoader.First; iter != null; iter = iter.Next)
  278. {
  279. iter.Value.OnUpdate();
  280. }
  281. }
  282. public void Dispose()
  283. {
  284. m_dicAssetInfo.Clear();
  285. m_ListAssetBundleLoader.Clear();
  286. m_ListAssetLoader.Clear();
  287. }
  288. }
  289. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小小林熬夜学编程/article/detail/125511
推荐阅读
相关标签
  

闽ICP备14008679号