AssetBundleLoader.cs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358
  1. using XGame.Framework.Asyncs;
  2. using XGame.Framework.Utils;
  3. using System.Collections.Generic;
  4. using UnityEngine;
  5. namespace XGame.Framework.Asset
  6. {
  7. /// <summary>
  8. /// AssetBundle的加载方式,需要先实现Bundle的Manifest管理
  9. /// </summary>
  10. internal partial class AssetBundleLoader : BaseLoader, IAssetLoader
  11. {
  12. private IAssetBundleManifest _bundleManifest;
  13. private IAssetReferencesManifest _referenceManifest;
  14. private ISceneInfosManifest _sceneInfosManifest;
  15. /// <summary>
  16. /// 已加载的Bundle仓库
  17. /// </summary>
  18. private BundleRepository Repository { set; get; }
  19. public bool IsBundleEncrypt { set; get; }
  20. public AssetBundleLoader(IAssetBundleManifest bundleManifest, IAssetReferencesManifest referenceManifest, ISceneInfosManifest sceneInfosManifest)
  21. {
  22. Repository = new BundleRepository();
  23. _bundleManifest = bundleManifest;
  24. _referenceManifest = referenceManifest;
  25. _sceneInfosManifest = sceneInfosManifest;
  26. }
  27. public IAssetAsync LoadAsync<TResult>(string addressableName)
  28. {
  29. if (!TryGetBundleInfo(addressableName, out string bundleName, out string[] dependencies))
  30. { //找不到bundle信息
  31. AssetsLog.Error($"Can't find bundleInfo. Name:{addressableName}");
  32. return null;
  33. }
  34. var assetFromCacheAsync = CreateAssetFromCacheAsync(addressableName);
  35. if (assetFromCacheAsync != null)
  36. { //从Repository拿出来的asset,可以直接结束该异步
  37. assetFromCacheAsync.Start();
  38. return assetFromCacheAsync;
  39. }
  40. if (AsyncPool.GetAssetAsync(addressableName) is AssetLoadFromBundleAsync assetLoadAsync)
  41. {
  42. //Asset 正在加载
  43. return assetLoadAsync;
  44. }
  45. assetLoadAsync = new AssetLoadFromBundleAsync
  46. {
  47. AddressableName = addressableName,
  48. BundleName = bundleName,
  49. IsSprite = typeof(TResult) == typeof(Sprite),
  50. GetBundleFromCache = GetAssetBundleByName,
  51. };
  52. List<IAssetAsync> asyncs = new List<IAssetAsync>();
  53. if (dependencies != null)
  54. {//收集依赖的bundle Async
  55. foreach (var dep in dependencies)
  56. {
  57. var async = CreateBundleAsync(dep);
  58. if (async != null)
  59. {
  60. asyncs.Add(async);
  61. }
  62. }
  63. }
  64. var bundleAsync = CreateBundleAsync(bundleName);
  65. if (bundleAsync != null)
  66. { //自己的bundle Async
  67. asyncs.Add(bundleAsync);
  68. }
  69. if (asyncs.Count > 0)
  70. {
  71. AsyncGroup group = new AsyncGroup();
  72. foreach (var async in asyncs)
  73. {
  74. group.AddAsync(async);
  75. }
  76. //先赋值
  77. assetLoadAsync.BundleAsyncGroup = group;
  78. //再将Async加进Pool
  79. foreach (var async in asyncs)
  80. {
  81. AsyncPool.AddAsync(async);
  82. }
  83. group.End();
  84. asyncs.Clear();
  85. }
  86. assetLoadAsync.On(OnAssetCompleted);
  87. AsyncPool.AddAsync(assetLoadAsync);
  88. return assetLoadAsync;
  89. }
  90. public object LoadSync<TResult>(string addressableName)
  91. {
  92. if (!TryGetBundleInfo(addressableName, out string bundleName, out string[] dependencies))
  93. { //找不到bundle信息
  94. AssetsLog.Error($"Can't find bundleInfo. Name:{addressableName}");
  95. return null;
  96. }
  97. //先从Repository查找缓存的Asset
  98. if (Repository.ContainsUnusedAsset(addressableName))
  99. {
  100. return Repository.PopUnusedAsset(addressableName);
  101. }
  102. if (AsyncPool.ContainsAssetAsync(addressableName))
  103. {//该Asset正在加载使用异步加载
  104. AssetsLog.Info($"{addressableName} is loading asynchronously, but load synchronously again.");
  105. }
  106. //先加载依赖的bundle
  107. if (dependencies != null)
  108. {
  109. foreach (var dep in dependencies)
  110. {
  111. LoadBundleSync(dep);
  112. }
  113. }
  114. //加载bundle
  115. var assetType = typeof(TResult);
  116. var isSprite = assetType == typeof(Sprite);
  117. var bundle = LoadBundleSync(bundleName);
  118. var asset = isSprite ? bundle?.LoadAsset(addressableName, assetType) : bundle?.LoadAsset(addressableName);
  119. if (asset != null)
  120. Repository.RegistAssetHash(asset.GetInstanceID(), addressableName);
  121. return asset;
  122. }
  123. public IAssetAsync LoadSceneBundleAsync(string sceneName)
  124. {
  125. //获取bundle信息
  126. if (!TryGetSceneBundleInfo(sceneName, out string bundleName, out string[] dependencies))
  127. { //找不到bundle信息
  128. AssetsLog.Error($"Can't find bundleInfo. Name:{sceneName}");
  129. return null;
  130. }
  131. if (AsyncPool.GetAssetAsync(sceneName) is SceneLoadAsync sceneLoadAsync)
  132. {
  133. //AssetBundle 正在加载
  134. return sceneLoadAsync;
  135. }
  136. sceneLoadAsync = new SceneLoadAsync
  137. {
  138. AddressableName = sceneName,
  139. };
  140. List<IAssetAsync> asyncs = new List<IAssetAsync>();
  141. if (dependencies != null)
  142. {//收集依赖的bundle Async
  143. foreach (var dep in dependencies)
  144. {
  145. var async = CreateBundleAsync(dep);
  146. if (async != null)
  147. {
  148. asyncs.Add(async);
  149. }
  150. }
  151. }
  152. var bundleAsync = CreateBundleAsync(bundleName);
  153. if (bundleAsync != null)
  154. { //自己的bundle Async
  155. asyncs.Add(bundleAsync);
  156. }
  157. if (asyncs.Count > 0)
  158. {
  159. AsyncGroup group = new AsyncGroup();
  160. foreach (var async in asyncs)
  161. {
  162. group.AddAsync(async);
  163. }
  164. //先赋值
  165. sceneLoadAsync.BundleAsyncGroup = group;
  166. //再将Async加进Pool
  167. foreach (var async in asyncs)
  168. {
  169. AsyncPool.AddAsync(async);
  170. }
  171. group.End();
  172. asyncs.Clear();
  173. }
  174. sceneLoadAsync.On(OnSceneComplete);
  175. AsyncPool.AddAsync(sceneLoadAsync);
  176. return sceneLoadAsync;
  177. }
  178. public void UnLoadSceneBundle(string sceneName)
  179. {
  180. if (TryGetSceneBundleInfo(sceneName, out string bundleName, out string[] dependencies))
  181. {
  182. //更新引用计数
  183. Repository.ReleaseBundle(bundleName);
  184. if (dependencies != null)
  185. {
  186. foreach (var dep in dependencies)
  187. {
  188. Repository.ReleaseBundle(dep);
  189. }
  190. }
  191. }
  192. }
  193. AssetBundle LoadBundleSync(string bundleName)
  194. {
  195. AssetBundle bundle;
  196. var bundleAsset = Repository.GetBundle(bundleName);
  197. if (bundleAsset != null)
  198. {
  199. bundle = bundleAsset.Clone() as AssetBundle;
  200. }
  201. else
  202. {
  203. if (AsyncPool.ContainsAssetAsync(bundleName))
  204. {//Bundle正在加载使用异步加载
  205. AssetsLog.Info($"{bundleName} is loading asynchronously, but load synchronously again.");
  206. }
  207. var path = FileUtils.GetAssetBundlePath(bundleName);
  208. var offset = GetBundleOffest(bundleName);
  209. bundle = LoadFromFile(path, offset);
  210. bundleAsset = AssetCreator.Create(bundleName, bundle) as BundleAsset;
  211. if (bundleAsset != null)
  212. {
  213. bundleAsset.Retain();
  214. Repository.AddBundle(bundleAsset);
  215. }
  216. else
  217. {
  218. AssetsLog.Warn("Asset Error: Load Bundle Failed. bundle:{0}", bundleName);
  219. }
  220. }
  221. return bundle;
  222. }
  223. private uint GetBundleOffest(string bundleName)
  224. {
  225. #if UNITY_EDITOR
  226. if (!IsBundleEncrypt)
  227. {
  228. return 0;
  229. }
  230. #endif
  231. return _bundleManifest.GetBundleOffest(bundleName);
  232. }
  233. /// <summary>
  234. /// AssetBundle.LoadFromFile的包装
  235. /// </summary>
  236. /// <param name="path"></param>
  237. /// <param name="offset"></param>
  238. /// <returns></returns>
  239. private AssetBundle LoadFromFile(string path, ulong offset)
  240. {
  241. var bundle = offset > 0 ? AssetBundle.LoadFromFile(path, 0, offset) : AssetBundle.LoadFromFile(path);
  242. return bundle;
  243. }
  244. bool TryGetBundleInfo(string addressableName, out string bundleName, out string[] dependencies)
  245. {
  246. if (_bundleManifest == null || string.IsNullOrEmpty(addressableName))
  247. {
  248. bundleName = string.Empty;
  249. dependencies = null;
  250. return false;
  251. }
  252. bundleName = _bundleManifest.GetBundleNameByAssetName(addressableName);
  253. dependencies = _bundleManifest.GetDependenciesByBundleName(bundleName);
  254. return !string.IsNullOrEmpty(bundleName);
  255. }
  256. bool TryGetSceneBundleInfo(string sceneName, out string bundleName, out string[] dependencies)
  257. {
  258. var assetName = _sceneInfosManifest?.GetSceneAssetName(sceneName) ?? string.Empty;
  259. return TryGetBundleInfo(assetName, out bundleName, out dependencies);
  260. }
  261. /// <summary>
  262. /// 检查某个资源是否被引用着
  263. /// </summary>
  264. /// <param name="addressableName"></param>
  265. /// <returns></returns>
  266. bool IsReferencing(string addressableName)
  267. {
  268. if (AsyncPool.ContainsAssetAsync(addressableName))
  269. {//该资源正在加载中
  270. return true;
  271. }
  272. var references = _referenceManifest.GetReferencesByAssetName(addressableName);
  273. if (references == null)
  274. return false;
  275. foreach (var reference in references)
  276. {
  277. if (AsyncPool.ContainsAssetAsync(reference))
  278. { //加载中
  279. return true;
  280. }
  281. if (Repository.ContainsAsset(reference) && Repository.ContainsUnusedAsset(reference) == false)
  282. { //已加载,并且不在回收缓存里
  283. return true;
  284. }
  285. }
  286. return false;
  287. }
  288. void OnUnloadAsset(string addressableName)
  289. {
  290. if (!TryGetBundleInfo(addressableName, out string bundleName, out string[] dependencies))
  291. { //找不到bundle信息
  292. return;
  293. }
  294. Repository.ReleaseBundle(bundleName);
  295. if (dependencies != null)
  296. {
  297. foreach (var dependency in dependencies)
  298. {
  299. Repository.ReleaseBundle(dependency);
  300. }
  301. }
  302. }
  303. /// <summary>
  304. /// 卸载资源
  305. /// 该方法只会将Asset回收进Repository缓存
  306. /// </summary>
  307. /// <param name="addressableName"></param>
  308. /// <param name="source"></param>
  309. public void Unload(string addressableName, object source)
  310. {
  311. if (source is Object obj)
  312. {
  313. var instanceId = obj.GetInstanceID();
  314. if (string.IsNullOrEmpty(Repository.GetAssetNameByHash(instanceId)))
  315. {
  316. AssetsLog.Warn($"{instanceId} is unregistered. Name:{addressableName}");
  317. }
  318. Repository.PushUnusedAsset(obj);
  319. }
  320. }
  321. /// <summary>
  322. /// 卸载卸载所有没有使用的资源
  323. /// </summary>
  324. public void UnloadUnusedAssets()
  325. {
  326. Repository.UnloadUnusedAssets(IsReferencing, OnUnloadAsset);
  327. }
  328. protected override void OnDispose()
  329. {
  330. Repository.Dispose();
  331. (_bundleManifest as System.IDisposable)?.Dispose();
  332. (_referenceManifest as System.IDisposable)?.Dispose();
  333. (_sceneInfosManifest as System.IDisposable)?.Dispose();
  334. _bundleManifest = null;
  335. _referenceManifest = null;
  336. _sceneInfosManifest = null;
  337. }
  338. }
  339. }