XMUnityAssetBundle.cs 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334
  1. using UnityEngine;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using CommonUnity3D.XMUnity.LoadUtil;
  5. //依赖在外部维护比较好
  6. //卸载依赖的逻辑需要用计数器
  7. public class XMUnityAssetBundle {
  8. public string Name { get; private set; }
  9. private AssetBundle mAssetBundle = null;
  10. public AssetBundle AssetBundle { get { return mAssetBundle; } }
  11. Stack<Object> mCache = new Stack<Object>();
  12. HashSet<string> mChildAB = new HashSet<string>();
  13. Dictionary<string, Object> mPrefabs = new Dictionary<string, Object>();
  14. private Status mBundleStatus = Status.NONE;
  15. public Status BundleStatus { get { return mBundleStatus; } }
  16. public int Version { get; private set; }
  17. private AssetBundleRequest Request = null;
  18. //System.Diagnostics.Stopwatch sw;
  19. public delegate void LoadResCallBack(string name, Object o, object userdata, bool isLoadOK);
  20. public class ABCallBackInfo
  21. {
  22. public string Name { get; set; }
  23. public LoadResCallBack CallBack { get; set; }
  24. public object UserData { get; set; }
  25. public ABCallBackInfo(string name, LoadResCallBack callback, object userdata)
  26. {
  27. this.Name = name;
  28. this.CallBack = callback;
  29. this.UserData = userdata;
  30. }
  31. }
  32. List<ABCallBackInfo> mLoadingAssetTask = new List<ABCallBackInfo>();
  33. public enum Status
  34. {
  35. NONE,
  36. LoadDep,
  37. LoadDepDone,
  38. LoadAssetBundle,
  39. LoadAssetBundleDone,
  40. LoadAsset,
  41. LoadAssetDone,
  42. Unloaded,
  43. }
  44. public enum Type
  45. {
  46. MAIN_ASSET,
  47. DEP_ASSET,
  48. }
  49. private Type mType = Type.MAIN_ASSET;
  50. public Type BundleType { get { return mType; } }
  51. public XMUnityAssetBundle(string name)
  52. {
  53. Name = name;
  54. }
  55. public XMUnityAssetBundle(string name, AssetBundle ab, int version)
  56. {
  57. Name = name;
  58. mAssetBundle = ab;
  59. mBundleStatus = Status.LoadAssetBundleDone;
  60. Version = version;
  61. }
  62. bool AddChild(string name)
  63. {
  64. return mChildAB.Add(name);
  65. }
  66. bool RemoveChild(string name)
  67. {
  68. return mChildAB.Remove(name);
  69. }
  70. bool GetFromCache(out Object obj)
  71. {
  72. if(mCache.Count > 0)
  73. {
  74. obj = mCache.Pop();
  75. return true;
  76. }
  77. else
  78. {
  79. obj = null;
  80. return false;
  81. }
  82. }
  83. void PushCache(Object obj)
  84. {
  85. mCache.Push(obj);
  86. }
  87. public Object GetAsset(string name)
  88. {
  89. Object obj = null;
  90. mPrefabs.TryGetValue(name, out obj);
  91. return obj;
  92. }
  93. //public void LoadAsset(string asset, bool isAsync)
  94. //{
  95. // Object obj = null;
  96. // //缓存里没有现成的
  97. // if (!GetFromCache(out obj))
  98. // {
  99. // }
  100. //}
  101. public void GetAsset(string asset, bool isAsync, LoadResCallBack callback, object userdata, System.Type type = null)
  102. {
  103. Object o = null;
  104. if(mPrefabs.TryGetValue(asset, out o))
  105. {
  106. callback(asset, o, userdata, true);
  107. }
  108. else
  109. {
  110. LoadAsset(asset, isAsync, callback, userdata, type);
  111. }
  112. }
  113. public void LoadAsset(string asset, bool isAsync, LoadResCallBack callback, object userdata, System.Type type = null)
  114. {
  115. //TODO 先按照之前的代码只支持一个AB1个物件,以后改成多个
  116. if (mBundleStatus == Status.LoadAsset || mBundleStatus == Status.LoadAssetDone)
  117. {
  118. //Debug.Log("LoadAsset Done");
  119. AddLoadingAssetTask(asset, callback, userdata);
  120. return;
  121. }
  122. if(type == null)
  123. {
  124. type = typeof(Object);
  125. }
  126. if(isAsync)
  127. {
  128. //sw = System.Diagnostics.Stopwatch.StartNew();
  129. Request = mAssetBundle.LoadAssetAsync(asset, type);
  130. mBundleStatus = Status.LoadAsset;
  131. AddLoadingAssetTask(asset, callback, userdata);
  132. XMUnityAssetBundleManager.GetInstance().StartCoroutine(CheckRequestAsset(asset));
  133. }
  134. else
  135. {
  136. //sw = System.Diagnostics.Stopwatch.StartNew();
  137. if(mAssetBundle == null)
  138. {
  139. int i = 0;
  140. }
  141. Object o = mAssetBundle.LoadAsset(asset, type);
  142. if(o != null)
  143. {
  144. mPrefabs[asset] = o;
  145. mBundleStatus = Status.LoadAssetDone;
  146. callback(asset, o, userdata, true);
  147. }
  148. else
  149. {
  150. mBundleStatus = Status.LoadAssetDone;
  151. callback(asset, o, userdata, false);
  152. }
  153. }
  154. mType = Type.MAIN_ASSET;
  155. }
  156. void AddLoadingAssetTask(string asset, LoadResCallBack callback, object userdata)
  157. {
  158. ABCallBackInfo info = new ABCallBackInfo(asset, callback, userdata);
  159. mLoadingAssetTask.Add(info);
  160. }
  161. void DoLoadAssetCallback(Object asset, bool isLoadOK)
  162. {
  163. var iter = mLoadingAssetTask.GetEnumerator();
  164. while (iter.MoveNext())
  165. {
  166. iter.Current.CallBack(iter.Current.Name, asset, iter.Current.UserData, isLoadOK);
  167. }
  168. mLoadingAssetTask.Clear();
  169. }
  170. public void LoadDeps(bool isAsync, LoadResCallBack callback, object userdata, string childAB)
  171. {
  172. //TODO 处理依赖关系
  173. if(childAB != null)
  174. {
  175. mChildAB.Add(childAB);
  176. }
  177. if (mBundleStatus == Status.LoadDep)
  178. {
  179. AddLoadingAssetTask(null, callback, userdata);
  180. }
  181. else if(mBundleStatus == Status.LoadDepDone)
  182. {
  183. //Debug.Log("LoadDeps Done");
  184. callback(null, null, userdata, true);
  185. }
  186. else
  187. {
  188. //sw = System.Diagnostics.Stopwatch.StartNew();
  189. if (isAsync)
  190. {
  191. Request = mAssetBundle.LoadAllAssetsAsync();
  192. mBundleStatus = Status.LoadDep;
  193. AddLoadingAssetTask(null, callback, userdata);
  194. XMUnityAssetBundleManager.GetInstance().StartCoroutine(CheckRequestDeps());
  195. }
  196. else
  197. {
  198. mAssetBundle.LoadAllAssets();
  199. mBundleStatus = Status.LoadDepDone;
  200. //sw.Stop();
  201. //Debug.LogError("[zzzzzzzzzzzzzzzz] " + Name.ToString() + " "+sw.ElapsedMilliseconds/1000f);
  202. callback(null, null, userdata, true);
  203. }
  204. }
  205. mType = Type.DEP_ASSET;
  206. }
  207. public void MarkAsDeps(string childAB)
  208. {
  209. //TODO 处理依赖关系
  210. if (childAB != null)
  211. {
  212. mChildAB.Add(childAB);
  213. }
  214. mBundleStatus = Status.LoadDepDone;
  215. mType = Type.DEP_ASSET;
  216. }
  217. public bool TryUnloadDep(string child, bool isUnloadAll = false, bool force = false)
  218. {
  219. if(mChildAB.Remove(child))
  220. {
  221. if(mChildAB.Count < 1)
  222. {
  223. return Unload(isUnloadAll, force);
  224. //return true;
  225. }
  226. else
  227. {
  228. return false;
  229. }
  230. }
  231. else
  232. {
  233. Debug.LogWarning("[策划测试请无视]XMUnityAssetBundle TryUnloadDep Error! Child not exists: [" + child + "] parent: [" + Name + "]");
  234. return false;
  235. }
  236. }
  237. public bool Unload(bool all, bool force = false)
  238. {
  239. //TODO 被其他包引用的包不能被Unload
  240. if(mBundleStatus == Status.NONE || mBundleStatus == Status.LoadAssetBundle || mBundleStatus == Status.LoadDep || mBundleStatus == Status.LoadAsset)
  241. {
  242. Debug.LogError("[策划测试请无视]XMUnityAssetBundle Unload Error! Status: " + mBundleStatus);
  243. return false;
  244. }
  245. if(force)
  246. {
  247. if(mType == Type.DEP_ASSET && mChildAB.Count > 0)
  248. {
  249. Debug.LogWarning("[策划测试请无视]XMUnityAssetBundle Force Unload Error! Child Referenced :" + Name + " " + mChildAB.Count);
  250. }
  251. }
  252. else
  253. {
  254. if (mType == Type.DEP_ASSET && mChildAB.Count > 0)
  255. {
  256. Debug.LogError("[策划测试请无视]XMUnityAssetBundle Unload Error! Child Referenced :" + Name + " " + mChildAB.Count);
  257. return false;
  258. }
  259. }
  260. //Debug.LogError("[Unload]" + Name + " " + all);
  261. mBundleStatus = Status.Unloaded;
  262. mPrefabs.Clear();
  263. mAssetBundle.Unload(all);
  264. mAssetBundle = null;
  265. mChildAB.Clear();
  266. return true;
  267. }
  268. IEnumerator<YieldInstruction> CheckRequestDeps()
  269. {
  270. //if (Request != null)
  271. {
  272. while (!Request.isDone)
  273. {
  274. yield return null;
  275. }
  276. mBundleStatus = Status.LoadDepDone;
  277. Request = null;
  278. //sw.Stop();
  279. //Debug.LogError("[zzzzzzzzzzzzzzzz] " + Name.ToString() + " "+sw.ElapsedMilliseconds/1000f);
  280. DoLoadAssetCallback(null, true);
  281. }
  282. }
  283. IEnumerator<YieldInstruction> CheckRequestAsset(string asset)
  284. {
  285. //if (Request != null)
  286. {
  287. while (!Request.isDone)
  288. {
  289. yield return null;
  290. }
  291. Object o = Request.asset;
  292. //sw.Stop();
  293. //Debug.LogError("[zzzzzzzzzzzzzzzz] " + Name.ToString() + " "+sw.ElapsedMilliseconds/1000f);
  294. if (o != null)
  295. {
  296. mPrefabs[asset] = o;
  297. mBundleStatus = Status.LoadAssetDone;
  298. Request = null;
  299. DoLoadAssetCallback(o, true);
  300. }
  301. else
  302. {
  303. mBundleStatus = Status.LoadAssetDone;
  304. Request = null;
  305. DoLoadAssetCallback(null, false);
  306. }
  307. }
  308. }
  309. }