AssetBundleFileLoader.cs 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225
  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 : AssetBundleLoaderBase
  9. {
  10. private enum ESteps
  11. {
  12. None = 0,
  13. Download,
  14. CheckDownload,
  15. LoadFile,
  16. CheckFile,
  17. Done,
  18. }
  19. //从服务器下载重试次数
  20. private const int RetryCnt = 2;
  21. private ESteps _steps = ESteps.None;
  22. private string _fileLoadPath;
  23. private bool _isWaitForAsyncComplete = false;
  24. private bool _isShowWaitForAsyncError = false;
  25. private DownloaderBase _downloader;
  26. private AssetBundleCreateRequest _cacheRequest;
  27. public AssetBundleFileLoader(BundleInfo bundleInfo) : base(bundleInfo)
  28. {
  29. }
  30. /// <summary>
  31. /// 轮询更新
  32. /// </summary>
  33. public override void Update()
  34. {
  35. if (_steps == ESteps.Done)
  36. return;
  37. if (_steps == ESteps.None)
  38. {
  39. if (MainBundleInfo.IsInvalid)
  40. {
  41. _steps = ESteps.Done;
  42. Status = EStatus.Failed;
  43. LastError = $"The bundle info is invalid : {MainBundleInfo.BundleName}";
  44. YooLogger.Error(LastError);
  45. return;
  46. }
  47. if (MainBundleInfo.LoadMode == BundleInfo.ELoadMode.LoadFromRemote)
  48. {
  49. _steps = ESteps.Download;
  50. _fileLoadPath = MainBundleInfo.GetCacheLoadPath();
  51. }
  52. else if (MainBundleInfo.LoadMode == BundleInfo.ELoadMode.LoadFromStreaming)
  53. {
  54. _steps = ESteps.LoadFile;
  55. _fileLoadPath = MainBundleInfo.GetStreamingLoadPath();
  56. }
  57. else if (MainBundleInfo.LoadMode == BundleInfo.ELoadMode.LoadFromCache)
  58. {
  59. _steps = ESteps.LoadFile;
  60. _fileLoadPath = MainBundleInfo.GetCacheLoadPath();
  61. }
  62. else
  63. {
  64. throw new System.NotImplementedException(MainBundleInfo.LoadMode.ToString());
  65. }
  66. }
  67. // 1. 从服务器下载
  68. if (_steps == ESteps.Download)
  69. {
  70. int failedTryAgain = RetryCnt;
  71. _downloader = DownloadSystem.BeginDownload(MainBundleInfo, failedTryAgain);
  72. _steps = ESteps.CheckDownload;
  73. }
  74. // 2. 检测服务器下载结果
  75. if (_steps == ESteps.CheckDownload)
  76. {
  77. if (_downloader.IsDone() == false)
  78. return;
  79. if (_downloader.HasError())
  80. {
  81. _steps = ESteps.Done;
  82. Status = EStatus.Failed;
  83. LastError = _downloader.GetLastError();
  84. }
  85. else
  86. {
  87. _steps = ESteps.LoadFile;
  88. }
  89. }
  90. // 3. 加载AssetBundle
  91. if (_steps == ESteps.LoadFile)
  92. {
  93. #if UNITY_EDITOR
  94. // 注意:Unity2017.4编辑器模式下,如果AssetBundle文件不存在会导致编辑器崩溃,这里做了预判。
  95. if (System.IO.File.Exists(_fileLoadPath) == false)
  96. {
  97. _steps = ESteps.Done;
  98. Status = EStatus.Failed;
  99. LastError = $"Not found assetBundle file : {_fileLoadPath}";
  100. YooLogger.Error(LastError);
  101. return;
  102. }
  103. #endif
  104. // Load assetBundle file
  105. if (MainBundleInfo.IsEncrypted)
  106. {
  107. if (AssetSystem.DecryptionServices == null)
  108. throw new Exception($"{nameof(AssetBundleFileLoader)} need {nameof(IDecryptionServices)} : {MainBundleInfo.BundleName}");
  109. DecryptionFileInfo fileInfo = new DecryptionFileInfo();
  110. fileInfo.BundleName = MainBundleInfo.BundleName;
  111. fileInfo.BundleHash = MainBundleInfo.Hash;
  112. fileInfo.BundleCRC = MainBundleInfo.CRC;
  113. ulong offset = AssetSystem.DecryptionServices.GetFileOffset(fileInfo);
  114. if (_isWaitForAsyncComplete)
  115. CacheBundle = AssetBundle.LoadFromFile(_fileLoadPath, 0, offset);
  116. else
  117. _cacheRequest = AssetBundle.LoadFromFileAsync(_fileLoadPath, 0, offset);
  118. }
  119. else
  120. {
  121. if (_isWaitForAsyncComplete)
  122. CacheBundle = AssetBundle.LoadFromFile(_fileLoadPath);
  123. else
  124. _cacheRequest = AssetBundle.LoadFromFileAsync(_fileLoadPath);
  125. }
  126. _steps = ESteps.CheckFile;
  127. }
  128. // 4. 检测AssetBundle加载结果
  129. if (_steps == ESteps.CheckFile)
  130. {
  131. if (_cacheRequest != null)
  132. {
  133. if (_isWaitForAsyncComplete)
  134. {
  135. // 强制挂起主线程(注意:该操作会很耗时)
  136. YooLogger.Warning("Suspend the main thread to load unity bundle.");
  137. CacheBundle = _cacheRequest.assetBundle;
  138. }
  139. else
  140. {
  141. if (_cacheRequest.isDone == false)
  142. return;
  143. CacheBundle = _cacheRequest.assetBundle;
  144. }
  145. }
  146. // Check error
  147. if (CacheBundle == null)
  148. {
  149. _steps = ESteps.Done;
  150. Status = EStatus.Failed;
  151. LastError = $"Failed to load assetBundle : {MainBundleInfo.BundleName}";
  152. YooLogger.Error(LastError);
  153. // 注意:当缓存文件的校验等级为Low的时候,并不能保证缓存文件的完整性。
  154. // 在AssetBundle文件加载失败的情况下,我们需要重新验证文件的完整性!
  155. if (MainBundleInfo.LoadMode == BundleInfo.ELoadMode.LoadFromCache)
  156. {
  157. string cacheLoadPath = MainBundleInfo.GetCacheLoadPath();
  158. if (DownloadSystem.CheckContentIntegrity(EVerifyLevel.High, cacheLoadPath, MainBundleInfo.SizeBytes, MainBundleInfo.CRC) == false)
  159. {
  160. if (File.Exists(cacheLoadPath))
  161. {
  162. YooLogger.Error($"Delete the invalid cache file : {cacheLoadPath}");
  163. File.Delete(cacheLoadPath);
  164. }
  165. }
  166. }
  167. }
  168. else
  169. {
  170. _steps = ESteps.Done;
  171. Status = EStatus.Succeed;
  172. }
  173. }
  174. }
  175. /// <summary>
  176. /// 主线程等待异步操作完毕
  177. /// </summary>
  178. public override void WaitForAsyncComplete()
  179. {
  180. _isWaitForAsyncComplete = true;
  181. int frame = 1000;
  182. while (true)
  183. {
  184. // 保险机制
  185. // 注意:如果需要从WEB端下载资源,可能会触发保险机制!
  186. frame--;
  187. if (frame == 0)
  188. {
  189. if (_isShowWaitForAsyncError == false)
  190. {
  191. _isShowWaitForAsyncError = true;
  192. YooLogger.Error($"WaitForAsyncComplete failed ! Try load bundle : {MainBundleInfo.BundleName} from remote with sync load method !");
  193. }
  194. break;
  195. }
  196. // 驱动流程
  197. Update();
  198. // 完成后退出
  199. if (IsDone())
  200. break;
  201. }
  202. }
  203. }
  204. }