当前位置:   article > 正文

Unity AssetBundle引用计数+时间缓存_unity ab引用计数

unity ab引用计数

在Unity开发过程中,经常需要对各类资源进行内存维护,eg:图片,音效,视频, Prefab 等。

下面给大家提供一个简单的AssetBundle管理方案:

  1. using Game.Utils;
  2. using LitJson;
  3. using System;
  4. using System.Collections;
  5. using System.Collections.Generic;
  6. using System.IO;
  7. using System.Linq;
  8. using TMPro;
  9. using Unity.VisualScripting;
  10. using UnityEngine;
  11. using static UnityEditor.Progress;
  12. namespace Game.Load
  13. {
  14. public class BundleCatalog
  15. {
  16. public Dictionary<string, string> mPathMapping = new Dictionary<string, string>();
  17. public Dictionary<string, string[]> mDepensMapping = new Dictionary<string, string[]>();
  18. public Dictionary<string, string> bundleName2MD5 = new Dictionary<string, string>();
  19. }
  20. public class Reference
  21. {
  22. public int count;
  23. public float time;
  24. public void AddCount() { count++; }
  25. public void RemoveCount() { count--; }
  26. public void ResetTime() { time = 0; }
  27. }
  28. public class BundleLoader
  29. {
  30. public AssetBundleCreateRequest abRequest;
  31. public string path;
  32. public bool isDone = false;
  33. public int cacheCount;
  34. public List<string> cacheDepens;
  35. public List<Action<AssetBundle>> actions;
  36. public bool GetRequestIsDone()
  37. {
  38. if (isDone) return true;
  39. if (abRequest == null) return false;
  40. return abRequest.isDone;
  41. }
  42. public bool GetBundleIsDone()
  43. {
  44. if (!GetRequestIsDone()) return false;
  45. return cacheCount == cacheDepens.Count;
  46. }
  47. }
  48. public class BundleOperation
  49. {
  50. public BundleCatalog mBundleCalalog;
  51. // 记录已加载的AssetBundle引用计数
  52. private Dictionary<string, Reference> assetBundleReferenceCounts = new Dictionary<string, Reference>();
  53. // 记录已加载的AssetBundle
  54. private Dictionary<string, AssetBundle> loadedAssetBundles = new Dictionary<string, AssetBundle>();
  55. // 正在加载中的AssetBundle
  56. private Dictionary<string, BundleLoader> AssetBundlesLoader = new Dictionary<string, BundleLoader>();
  57. // 缓存时间
  58. private int mCacheTime = 3;
  59. public BundleOperation()
  60. {
  61. mBundleCalalog = JsonMapper.ToObject<BundleCatalog>(
  62. FileTools.GetFile(
  63. AssetUtils.GetRealPath(
  64. GameConst.GetAssetBundlePath(GameConst.Catalog)
  65. )
  66. )
  67. );
  68. }
  69. public string[] FindDepend(string assetBundlePath, List<string> mark = null)
  70. {
  71. if (mark == null)
  72. mark = new List<string>();
  73. assetBundlePath = GetPathByCatalog(assetBundlePath);
  74. if (mark.Contains(assetBundlePath))
  75. return default;
  76. else
  77. mark.Add(assetBundlePath);
  78. if (mBundleCalalog.mDepensMapping.ContainsKey(assetBundlePath))
  79. {
  80. foreach (var depend in mBundleCalalog.mDepensMapping[assetBundlePath])
  81. {
  82. FindDepend(depend, mark);
  83. }
  84. }
  85. return mark.ToArray();
  86. }
  87. public void LoadBundleAsync(string assetBundlePath, Action<AssetBundle> action = null)
  88. {
  89. LoadBundleAsync(assetBundlePath, action, new List<string>());
  90. }
  91. private void LoadBundleAsync(string assetBundlePath, Action<AssetBundle> action = null, List<string> mark = null)
  92. {
  93. if (mark == null)
  94. mark = new List<string>();
  95. assetBundlePath = GetPathByCatalog(assetBundlePath);
  96. if (mark.Contains(assetBundlePath))
  97. return;
  98. else
  99. mark.Add(assetBundlePath);
  100. if (loadedAssetBundles.ContainsKey(assetBundlePath))
  101. {
  102. action?.Invoke(loadedAssetBundles[assetBundlePath]);
  103. return;
  104. }
  105. if (AssetBundlesLoader.ContainsKey(assetBundlePath))
  106. {
  107. AssetBundlesLoader[assetBundlePath].actions.Add(action);
  108. return;
  109. }
  110. if (mBundleCalalog.mDepensMapping.ContainsKey(assetBundlePath))
  111. {
  112. foreach (var depend in mBundleCalalog.mDepensMapping[assetBundlePath])
  113. {
  114. LoadBundleAsync(depend, null, mark);
  115. }
  116. }
  117. AssetBundleCreateRequest ab = AssetBundle.LoadFromFileAsync(AssetUtils.GetRealPath(GameConst.GetAssetBundlePath(assetBundlePath)));
  118. AssetBundlesLoader.Add(assetBundlePath, new BundleLoader()
  119. {
  120. cacheDepens = mBundleCalalog.mDepensMapping[assetBundlePath].ToList(),
  121. isDone = false,
  122. path = assetBundlePath,
  123. abRequest = ab,
  124. actions = new List<Action<AssetBundle>> { action },
  125. cacheCount = 0
  126. });
  127. }
  128. public AssetBundle LoadBundleSync(string assetBundlePath)
  129. {
  130. return LoadBundleSync(assetBundlePath, new List<string>());
  131. }
  132. private AssetBundle LoadBundleSync(string assetBundlePath, List<string> mark = null)
  133. {
  134. if (mark == null)
  135. mark = new List<string>();
  136. assetBundlePath = GetPathByCatalog(assetBundlePath);
  137. if (mark.Contains(assetBundlePath))
  138. return default;
  139. else
  140. mark.Add(assetBundlePath);
  141. if (loadedAssetBundles.ContainsKey(assetBundlePath))
  142. {
  143. return loadedAssetBundles[assetBundlePath];
  144. }
  145. if (mBundleCalalog.mDepensMapping.ContainsKey(assetBundlePath))
  146. {
  147. foreach (var depend in mBundleCalalog.mDepensMapping[assetBundlePath])
  148. {
  149. LoadBundleSync(depend, mark);
  150. }
  151. }
  152. AssetBundle ab = AssetBundle.LoadFromFile(
  153. AssetUtils.GetRealPath(
  154. GameConst.GetAssetBundlePath(assetBundlePath)
  155. )
  156. );
  157. loadedAssetBundles.Add(assetBundlePath, ab);
  158. return loadedAssetBundles[assetBundlePath];
  159. }
  160. public string GetPathByCatalog(string assetBundlePath)
  161. {
  162. foreach (var item in mBundleCalalog.mPathMapping)
  163. {
  164. if (item.Key.Contains(assetBundlePath))
  165. {
  166. return item.Value;
  167. }
  168. }
  169. return assetBundlePath;
  170. }
  171. public string GetPathByCatalogKey(string assetBundlePath)
  172. {
  173. foreach (var item in mBundleCalalog.mPathMapping)
  174. {
  175. if (item.Key.Contains(assetBundlePath))
  176. {
  177. return item.Key;
  178. }
  179. }
  180. return assetBundlePath;
  181. }
  182. private void UnloadAssetBundle(string assetBundlePath)
  183. {
  184. assetBundlePath = GetPathByCatalog(assetBundlePath);
  185. if (loadedAssetBundles.ContainsKey(assetBundlePath))
  186. {
  187. loadedAssetBundles[assetBundlePath].Unload(true);
  188. loadedAssetBundles.Remove(assetBundlePath);
  189. }
  190. }
  191. public void IncreaseAssetBundleReferenceCount(string assetBundlePath)
  192. {
  193. IncreaseAssetBundleReferenceCount(assetBundlePath, new List<string>());
  194. }
  195. private void IncreaseAssetBundleReferenceCount(string assetBundlePath, List<string> mark = null)
  196. {
  197. if (mark == null)
  198. mark = new List<string>();
  199. assetBundlePath = GetPathByCatalog(assetBundlePath);
  200. if (mark.Contains(assetBundlePath))
  201. return;
  202. else
  203. mark.Add(assetBundlePath);
  204. if (mBundleCalalog.mDepensMapping.ContainsKey(assetBundlePath))
  205. {
  206. foreach (var depend in mBundleCalalog.mDepensMapping[assetBundlePath])
  207. {
  208. IncreaseAssetBundleReferenceCount(depend, mark);
  209. }
  210. }
  211. if (!assetBundleReferenceCounts.ContainsKey(assetBundlePath))
  212. {
  213. assetBundleReferenceCounts.Add(assetBundlePath, new Reference() { count = 0, time = 0 });
  214. }
  215. assetBundleReferenceCounts[assetBundlePath].AddCount();
  216. }
  217. public void DecreaseAssetBundleReferenceCount(string assetBundlePath)
  218. {
  219. DecreaseAssetBundleReferenceCount(assetBundlePath, new List<string>());
  220. }
  221. private void DecreaseAssetBundleReferenceCount(string assetBundlePath, List<string> mark = null)
  222. {
  223. if (mark == null)
  224. mark = new List<string>();
  225. assetBundlePath = GetPathByCatalog(assetBundlePath);
  226. if (mark.Contains(assetBundlePath))
  227. return;
  228. else
  229. mark.Add(assetBundlePath);
  230. if (mBundleCalalog.mDepensMapping.ContainsKey(assetBundlePath))
  231. {
  232. foreach (var depend in mBundleCalalog.mDepensMapping[assetBundlePath])
  233. {
  234. DecreaseAssetBundleReferenceCount(depend, mark);
  235. }
  236. }
  237. if (assetBundleReferenceCounts.ContainsKey(assetBundlePath))
  238. {
  239. assetBundleReferenceCounts[assetBundlePath].RemoveCount();
  240. if (assetBundleReferenceCounts[assetBundlePath].count < 0)
  241. {
  242. Log.Error("引用计数小于0:", assetBundlePath);
  243. }
  244. }
  245. else
  246. {
  247. Log.Error("引用不存在:", assetBundlePath);
  248. }
  249. }
  250. public string GetReferenceCount(string assetBundlePath)
  251. {
  252. assetBundlePath = GetPathByCatalog(assetBundlePath);
  253. if (assetBundleReferenceCounts.ContainsKey(assetBundlePath))
  254. {
  255. return "引用:" + assetBundleReferenceCounts[assetBundlePath].count.ToString();
  256. }
  257. return "引用:不存在";
  258. }
  259. public void OnTick()
  260. {
  261. UpdateReference();
  262. UpdateLoader();
  263. }
  264. public void UpdateLoader()
  265. {
  266. foreach (var item in AssetBundlesLoader)
  267. {
  268. if (item.Value.GetRequestIsDone() && !loadedAssetBundles.ContainsKey(item.Key))
  269. {
  270. foreach (var item2 in AssetBundlesLoader)
  271. {
  272. if (item2.Value.cacheDepens.Contains(item.Key))
  273. {
  274. item2.Value.cacheCount++;
  275. }
  276. }
  277. }
  278. }
  279. List<string> succKey = new List<string>();
  280. foreach (var item in AssetBundlesLoader)
  281. {
  282. if (item.Value.GetBundleIsDone())
  283. {
  284. succKey.Add(item.Key);
  285. }
  286. }
  287. foreach (var item in succKey)
  288. {
  289. loadedAssetBundles.Add(item, AssetBundlesLoader[item].abRequest.assetBundle);
  290. foreach (var action in AssetBundlesLoader[item].actions)
  291. {
  292. action?.Invoke(AssetBundlesLoader[item].abRequest.assetBundle);
  293. }
  294. AssetBundlesLoader.Remove(item);
  295. }
  296. }
  297. public void UpdateReference()
  298. {
  299. List<string> overtime = new List<string>();
  300. foreach (var item in assetBundleReferenceCounts)
  301. {
  302. if (item.Value.count <= 0)
  303. {
  304. item.Value.time += Time.deltaTime;
  305. if (item.Value.time > mCacheTime)
  306. {
  307. overtime.Add(item.Key);
  308. }
  309. }
  310. else
  311. {
  312. item.Value.ResetTime();
  313. }
  314. }
  315. foreach (var item in overtime)
  316. {
  317. assetBundleReferenceCounts.Remove(item);
  318. UnloadAssetBundle(item);
  319. }
  320. }
  321. }
  322. }

 简单的说:

在外部调用 LoadBundleSync/LoadBundleAsync 后进行IncreaseAssetBundleReferenceCount

在Destroy时进行DecreaseAssetBundleReferenceCount

OnTick 刷新检测异步加载 以及释放缓存

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

闽ICP备14008679号