AssetBundleFileLoader.cs 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294
  1. using System;
  2. using System.IO;
  3. using System.Collections;
  4. using System.Collections.Generic;
  5. using UnityEngine;
  6. namespace YooAsset
  7. {
  8. internal sealed class AssetBundleFileLoader : BundleLoaderBase
  9. {
  10. private enum ESteps
  11. {
  12. None = 0,
  13. Download,
  14. CheckDownload,
  15. Unpack,
  16. CheckUnpack,
  17. LoadBundleFile,
  18. LoadDeliveryFile,
  19. CheckLoadFile,
  20. Done,
  21. }
  22. private ESteps _steps = ESteps.None;
  23. private bool _isWaitForAsyncComplete = false;
  24. private bool _isShowWaitForAsyncError = false;
  25. private DownloaderBase _unpacker;
  26. private DownloaderBase _downloader;
  27. private AssetBundleCreateRequest _createRequest;
  28. private Stream _managedStream;
  29. public AssetBundleFileLoader(ResourceManager impl, BundleInfo bundleInfo) : base(impl, bundleInfo)
  30. {
  31. }
  32. /// <summary>
  33. /// 轮询更新
  34. /// </summary>
  35. public override void Update()
  36. {
  37. if (_steps == ESteps.Done)
  38. return;
  39. if (_steps == ESteps.None)
  40. {
  41. if (MainBundleInfo.LoadMode == BundleInfo.ELoadMode.LoadFromRemote)
  42. {
  43. _steps = ESteps.Download;
  44. FileLoadPath = MainBundleInfo.CachedDataFilePath;
  45. }
  46. else if (MainBundleInfo.LoadMode == BundleInfo.ELoadMode.LoadFromStreaming)
  47. {
  48. #if UNITY_ANDROID
  49. if (MainBundleInfo.Bundle.Encrypted)
  50. {
  51. _steps = ESteps.Unpack;
  52. FileLoadPath = MainBundleInfo.CachedDataFilePath;
  53. }
  54. else
  55. {
  56. _steps = ESteps.LoadBundleFile;
  57. FileLoadPath = MainBundleInfo.BuildinFilePath;
  58. }
  59. #else
  60. _steps = ESteps.LoadBundleFile;
  61. FileLoadPath = MainBundleInfo.BuildinFilePath;
  62. #endif
  63. }
  64. else if (MainBundleInfo.LoadMode == BundleInfo.ELoadMode.LoadFromCache)
  65. {
  66. _steps = ESteps.LoadBundleFile;
  67. FileLoadPath = MainBundleInfo.CachedDataFilePath;
  68. }
  69. else if (MainBundleInfo.LoadMode == BundleInfo.ELoadMode.LoadFromDelivery)
  70. {
  71. _steps = ESteps.LoadDeliveryFile;
  72. FileLoadPath = MainBundleInfo.DeliveryFilePath;
  73. }
  74. else
  75. {
  76. throw new System.NotImplementedException(MainBundleInfo.LoadMode.ToString());
  77. }
  78. }
  79. // 1. 从服务器下载
  80. if (_steps == ESteps.Download)
  81. {
  82. _downloader = MainBundleInfo.CreateDownloader(int.MaxValue);
  83. _downloader.SendRequest();
  84. _steps = ESteps.CheckDownload;
  85. }
  86. // 2. 检测服务器下载结果
  87. if (_steps == ESteps.CheckDownload)
  88. {
  89. DownloadProgress = _downloader.DownloadProgress;
  90. DownloadedBytes = _downloader.DownloadedBytes;
  91. if (_downloader.IsDone() == false)
  92. return;
  93. if (_downloader.HasError())
  94. {
  95. _steps = ESteps.Done;
  96. Status = EStatus.Failed;
  97. LastError = _downloader.GetLastError();
  98. }
  99. else
  100. {
  101. _steps = ESteps.LoadBundleFile;
  102. return; //下载完毕等待一帧再去加载!
  103. }
  104. }
  105. // 3. 内置文件解压
  106. if (_steps == ESteps.Unpack)
  107. {
  108. int failedTryAgain = 1;
  109. _unpacker = MainBundleInfo.CreateUnpacker(failedTryAgain);
  110. _unpacker.SendRequest();
  111. _steps = ESteps.CheckUnpack;
  112. }
  113. // 4.检测内置文件解压结果
  114. if (_steps == ESteps.CheckUnpack)
  115. {
  116. DownloadProgress = _unpacker.DownloadProgress;
  117. DownloadedBytes = _unpacker.DownloadedBytes;
  118. if (_unpacker.IsDone() == false)
  119. return;
  120. if (_unpacker.HasError())
  121. {
  122. _steps = ESteps.Done;
  123. Status = EStatus.Failed;
  124. LastError = _unpacker.GetLastError();
  125. }
  126. else
  127. {
  128. _steps = ESteps.LoadBundleFile;
  129. }
  130. }
  131. // 5. 加载AssetBundle
  132. if (_steps == ESteps.LoadBundleFile)
  133. {
  134. #if UNITY_EDITOR
  135. // 注意:Unity2017.4编辑器模式下,如果AssetBundle文件不存在会导致编辑器崩溃,这里做了预判。
  136. if (System.IO.File.Exists(FileLoadPath) == false)
  137. {
  138. _steps = ESteps.Done;
  139. Status = EStatus.Failed;
  140. LastError = $"Not found assetBundle file : {FileLoadPath}";
  141. YooLogger.Error(LastError);
  142. return;
  143. }
  144. #endif
  145. // 设置下载进度
  146. DownloadProgress = 1f;
  147. DownloadedBytes = (ulong)MainBundleInfo.Bundle.FileSize;
  148. // 加载AssetBundle资源对象
  149. // 注意:解密服务类可能会返回空的对象。
  150. if (_isWaitForAsyncComplete)
  151. CacheBundle = MainBundleInfo.LoadAssetBundle(FileLoadPath, out _managedStream);
  152. else
  153. _createRequest = MainBundleInfo.LoadAssetBundleAsync(FileLoadPath, out _managedStream);
  154. _steps = ESteps.CheckLoadFile;
  155. }
  156. // 6. 加载AssetBundle
  157. if (_steps == ESteps.LoadDeliveryFile)
  158. {
  159. // 设置下载进度
  160. DownloadProgress = 1f;
  161. DownloadedBytes = (ulong)MainBundleInfo.Bundle.FileSize;
  162. // Load assetBundle file
  163. if (_isWaitForAsyncComplete)
  164. CacheBundle = MainBundleInfo.LoadDeliveryAssetBundle(FileLoadPath);
  165. else
  166. _createRequest = MainBundleInfo.LoadDeliveryAssetBundleAsync(FileLoadPath);
  167. _steps = ESteps.CheckLoadFile;
  168. }
  169. // 7. 检测AssetBundle加载结果
  170. if (_steps == ESteps.CheckLoadFile)
  171. {
  172. if (_createRequest != null)
  173. {
  174. if (_isWaitForAsyncComplete || IsForceDestroyComplete)
  175. {
  176. // 强制挂起主线程(注意:该操作会很耗时)
  177. YooLogger.Warning("Suspend the main thread to load unity bundle.");
  178. CacheBundle = _createRequest.assetBundle;
  179. }
  180. else
  181. {
  182. if (_createRequest.isDone == false)
  183. return;
  184. CacheBundle = _createRequest.assetBundle;
  185. }
  186. }
  187. // Check error
  188. if (CacheBundle == null)
  189. {
  190. _steps = ESteps.Done;
  191. Status = EStatus.Failed;
  192. LastError = $"Failed to load assetBundle : {MainBundleInfo.Bundle.BundleName}";
  193. YooLogger.Error(LastError);
  194. // 注意:当缓存文件的校验等级为Low的时候,并不能保证缓存文件的完整性。
  195. // 在AssetBundle文件加载失败的情况下,我们需要重新验证文件的完整性!
  196. if (MainBundleInfo.LoadMode == BundleInfo.ELoadMode.LoadFromCache)
  197. {
  198. var result = MainBundleInfo.VerifySelf();
  199. if (result != EVerifyResult.Succeed)
  200. {
  201. YooLogger.Error($"Found possibly corrupt file ! {MainBundleInfo.Bundle.CacheGUID} Verify result : {result}");
  202. MainBundleInfo.CacheDiscard();
  203. }
  204. }
  205. }
  206. else
  207. {
  208. _steps = ESteps.Done;
  209. Status = EStatus.Succeed;
  210. }
  211. }
  212. }
  213. /// <summary>
  214. /// 销毁
  215. /// </summary>
  216. public override void Destroy()
  217. {
  218. base.Destroy();
  219. if (_managedStream != null)
  220. {
  221. _managedStream.Close();
  222. _managedStream.Dispose();
  223. _managedStream = null;
  224. }
  225. }
  226. /// <summary>
  227. /// 主线程等待异步操作完毕
  228. /// </summary>
  229. public override void WaitForAsyncComplete()
  230. {
  231. _isWaitForAsyncComplete = true;
  232. int frame = 1000;
  233. while (true)
  234. {
  235. // 文件解压
  236. if (_unpacker != null)
  237. {
  238. if (_unpacker.IsDone() == false)
  239. {
  240. _unpacker.WaitForAsyncComplete = true;
  241. _unpacker.Update();
  242. continue;
  243. }
  244. }
  245. // 保险机制
  246. // 注意:如果需要从WEB端下载资源,可能会触发保险机制!
  247. frame--;
  248. if (frame == 0)
  249. {
  250. if (_isShowWaitForAsyncError == false)
  251. {
  252. _isShowWaitForAsyncError = true;
  253. YooLogger.Error($"{nameof(WaitForAsyncComplete)} failed ! Try load bundle : {MainBundleInfo.Bundle.BundleName} from remote with sync load method !");
  254. }
  255. break;
  256. }
  257. // 驱动流程
  258. Update();
  259. // 完成后退出
  260. if (IsDone())
  261. break;
  262. }
  263. }
  264. }
  265. }