AssetBundleWebLoader.cs 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  1. using System;
  2. using System.IO;
  3. using System.Collections;
  4. using System.Collections.Generic;
  5. using UnityEngine;
  6. using UnityEngine.Networking;
  7. namespace YooAsset
  8. {
  9. /// <summary>
  10. /// WebGL平台加载器
  11. /// </summary>
  12. internal sealed class AssetBundleWebLoader : BundleLoaderBase
  13. {
  14. private enum ESteps
  15. {
  16. None = 0,
  17. Download,
  18. CheckDownload,
  19. LoadCacheFile,
  20. CheckLoadCacheFile,
  21. LoadWebFile,
  22. CheckLoadWebFile,
  23. TryLoadWebFile,
  24. Done,
  25. }
  26. private ESteps _steps = ESteps.None;
  27. private float _tryTimer = 0;
  28. private DownloaderBase _downloader;
  29. private UnityWebRequest _webRequest;
  30. private AssetBundleCreateRequest _createRequest;
  31. public AssetBundleWebLoader(AssetSystemImpl impl, BundleInfo bundleInfo) : base(impl, bundleInfo)
  32. {
  33. }
  34. /// <summary>
  35. /// 轮询更新
  36. /// </summary>
  37. public override void Update()
  38. {
  39. if (_steps == ESteps.Done)
  40. return;
  41. if (_steps == ESteps.None)
  42. {
  43. if (MainBundleInfo.LoadMode == BundleInfo.ELoadMode.LoadFromRemote)
  44. {
  45. _steps = ESteps.Download;
  46. FileLoadPath = MainBundleInfo.Bundle.CachedDataFilePath;
  47. }
  48. else if (MainBundleInfo.LoadMode == BundleInfo.ELoadMode.LoadFromStreaming)
  49. {
  50. _steps = ESteps.LoadWebFile;
  51. FileLoadPath = MainBundleInfo.Bundle.StreamingFilePath;
  52. }
  53. else if (MainBundleInfo.LoadMode == BundleInfo.ELoadMode.LoadFromCache)
  54. {
  55. _steps = ESteps.LoadCacheFile;
  56. FileLoadPath = MainBundleInfo.Bundle.CachedDataFilePath;
  57. }
  58. else
  59. {
  60. throw new System.NotImplementedException(MainBundleInfo.LoadMode.ToString());
  61. }
  62. }
  63. // 1. 从服务器下载
  64. if (_steps == ESteps.Download)
  65. {
  66. int failedTryAgain = Impl.DownloadFailedTryAgain;
  67. _downloader = DownloadSystem.BeginDownload(MainBundleInfo, failedTryAgain);
  68. _steps = ESteps.CheckDownload;
  69. }
  70. // 2. 检测服务器下载结果
  71. if (_steps == ESteps.CheckDownload)
  72. {
  73. DownloadProgress = _downloader.DownloadProgress;
  74. DownloadedBytes = _downloader.DownloadedBytes;
  75. if (_downloader.IsDone() == false)
  76. return;
  77. if (_downloader.HasError())
  78. {
  79. _steps = ESteps.Done;
  80. Status = EStatus.Failed;
  81. LastError = _downloader.GetLastError();
  82. }
  83. else
  84. {
  85. _steps = ESteps.LoadCacheFile;
  86. return; //下载完毕等待一帧再去加载!
  87. }
  88. }
  89. // 3. 从本地缓存里加载AssetBundle
  90. if (_steps == ESteps.LoadCacheFile)
  91. {
  92. #if UNITY_EDITOR
  93. // 注意:Unity2017.4编辑器模式下,如果AssetBundle文件不存在会导致编辑器崩溃,这里做了预判。
  94. if (System.IO.File.Exists(FileLoadPath) == false)
  95. {
  96. _steps = ESteps.Done;
  97. Status = EStatus.Failed;
  98. LastError = $"Not found assetBundle file : {FileLoadPath}";
  99. YooLogger.Error(LastError);
  100. return;
  101. }
  102. #endif
  103. // 设置下载进度
  104. DownloadProgress = 1f;
  105. DownloadedBytes = (ulong)MainBundleInfo.Bundle.FileSize;
  106. // Load assetBundle file
  107. var loadMethod = (EBundleLoadMethod)MainBundleInfo.Bundle.LoadMethod;
  108. if (loadMethod == EBundleLoadMethod.Normal)
  109. {
  110. _createRequest = AssetBundle.LoadFromFileAsync(FileLoadPath);
  111. }
  112. else
  113. {
  114. _steps = ESteps.Done;
  115. Status = EStatus.Failed;
  116. LastError = $"WebGL not support encrypted bundle file : {MainBundleInfo.Bundle.BundleName}";
  117. YooLogger.Error(LastError);
  118. return;
  119. }
  120. _steps = ESteps.CheckLoadCacheFile;
  121. }
  122. // 4. 检测AssetBundle加载结果
  123. if (_steps == ESteps.CheckLoadCacheFile)
  124. {
  125. if (_createRequest.isDone == false)
  126. return;
  127. CacheBundle = _createRequest.assetBundle;
  128. if (CacheBundle == null)
  129. {
  130. _steps = ESteps.Done;
  131. Status = EStatus.Failed;
  132. LastError = $"Failed to load AssetBundle file : {MainBundleInfo.Bundle.BundleName}";
  133. YooLogger.Error(LastError);
  134. // 注意:当缓存文件的校验等级为Low的时候,并不能保证缓存文件的完整性。
  135. // 在AssetBundle文件加载失败的情况下,我们需要重新验证文件的完整性!
  136. if (MainBundleInfo.LoadMode == BundleInfo.ELoadMode.LoadFromCache)
  137. {
  138. var result = CacheSystem.VerifyingRecordFile(MainBundleInfo.Bundle.PackageName, MainBundleInfo.Bundle.CacheGUID);
  139. if (result != EVerifyResult.Succeed)
  140. {
  141. YooLogger.Error($"Found possibly corrupt file ! {MainBundleInfo.Bundle.CacheGUID}");
  142. CacheSystem.DiscardFile(MainBundleInfo.Bundle.PackageName, MainBundleInfo.Bundle.CacheGUID);
  143. }
  144. }
  145. }
  146. else
  147. {
  148. _steps = ESteps.Done;
  149. Status = EStatus.Succeed;
  150. }
  151. }
  152. // 5. 从WEB网站获取AssetBundle文件
  153. if (_steps == ESteps.LoadWebFile)
  154. {
  155. if (CacheSystem.DisableUnityCacheOnWebGL)
  156. {
  157. _webRequest = UnityWebRequestAssetBundle.GetAssetBundle(FileLoadPath);
  158. }
  159. else
  160. {
  161. var hash = Hash128.Parse(MainBundleInfo.Bundle.FileHash);
  162. _webRequest = UnityWebRequestAssetBundle.GetAssetBundle(FileLoadPath, hash);
  163. }
  164. DownloadSystem.SetUnityWebRequest(_webRequest);
  165. _webRequest.SendWebRequest();
  166. _steps = ESteps.CheckLoadWebFile;
  167. }
  168. // 6. 检测AssetBundle加载结果
  169. if (_steps == ESteps.CheckLoadWebFile)
  170. {
  171. DownloadProgress = _webRequest.downloadProgress;
  172. DownloadedBytes = _webRequest.downloadedBytes;
  173. if (_webRequest.isDone == false)
  174. return;
  175. #if UNITY_2020_1_OR_NEWER
  176. if (_webRequest.result != UnityWebRequest.Result.Success)
  177. #else
  178. if (_webRequest.isNetworkError || _webRequest.isHttpError)
  179. #endif
  180. {
  181. YooLogger.Warning($"Failed to get asset bundle from web : {FileLoadPath} Error : {_webRequest.error}");
  182. _steps = ESteps.TryLoadWebFile;
  183. _tryTimer = 0;
  184. }
  185. else
  186. {
  187. CacheBundle = DownloadHandlerAssetBundle.GetContent(_webRequest);
  188. if (CacheBundle == null)
  189. {
  190. _steps = ESteps.Done;
  191. Status = EStatus.Failed;
  192. LastError = $"AssetBundle file is invalid : {MainBundleInfo.Bundle.BundleName}";
  193. YooLogger.Error(LastError);
  194. }
  195. else
  196. {
  197. _steps = ESteps.Done;
  198. Status = EStatus.Succeed;
  199. }
  200. }
  201. }
  202. // 7. 如果获取失败,重新尝试
  203. if (_steps == ESteps.TryLoadWebFile)
  204. {
  205. _tryTimer += Time.unscaledDeltaTime;
  206. if (_tryTimer > 1f)
  207. {
  208. _webRequest.Dispose();
  209. _webRequest = null;
  210. _steps = ESteps.LoadWebFile;
  211. }
  212. }
  213. }
  214. /// <summary>
  215. /// 主线程等待异步操作完毕
  216. /// </summary>
  217. public override void WaitForAsyncComplete()
  218. {
  219. if (IsDone() == false)
  220. {
  221. Status = EStatus.Failed;
  222. LastError = $"{nameof(WaitForAsyncComplete)} failed ! WebGL platform not support sync load method !";
  223. YooLogger.Error(LastError);
  224. }
  225. }
  226. }
  227. }