private List <BundleInfo> GetDownloadListByAll() { List <PatchBundle> downloadList = new List <PatchBundle>(1000); foreach (var patchBundle in LocalPatchManifest.BundleList) { // 忽略缓存文件 if (DownloadSystem.ContainsVerifyFile(patchBundle.Hash)) { continue; } // 忽略APP资源 // 注意:如果是APP资源并且哈希值相同,则不需要下载 if (AppPatchManifest.Bundles.TryGetValue(patchBundle.BundleName, out PatchBundle appPatchBundle)) { if (appPatchBundle.IsBuildin && appPatchBundle.Hash == patchBundle.Hash) { continue; } } downloadList.Add(patchBundle); } return(ConvertToDownloadList(downloadList)); }
private List <BundleInfo> GetDownloadListByPaths(AssetInfo[] assetInfos) { // 获取资源对象的资源包和所有依赖资源包 List <PatchBundle> checkList = new List <PatchBundle>(); foreach (var assetInfo in assetInfos) { if (assetInfo.IsInvalid) { YooLogger.Warning(assetInfo.Error); continue; } string mainBundleName = LocalPatchManifest.GetBundleName(assetInfo.AssetPath); if (LocalPatchManifest.Bundles.TryGetValue(mainBundleName, out PatchBundle mainBundle)) { if (checkList.Contains(mainBundle) == false) { checkList.Add(mainBundle); } } string[] dependBundleNames = LocalPatchManifest.GetAllDependencies(assetInfo.AssetPath); foreach (var dependBundleName in dependBundleNames) { if (LocalPatchManifest.Bundles.TryGetValue(dependBundleName, out PatchBundle dependBundle)) { if (checkList.Contains(dependBundle) == false) { checkList.Add(dependBundle); } } } } List <PatchBundle> downloadList = new List <PatchBundle>(1000); foreach (var patchBundle in checkList) { // 忽略缓存文件 if (DownloadSystem.ContainsVerifyFile(patchBundle.Hash)) { continue; } // 忽略APP资源 // 注意:如果是APP资源并且哈希值相同,则不需要下载 if (AppPatchManifest.Bundles.TryGetValue(patchBundle.BundleName, out PatchBundle appPatchBundle)) { if (appPatchBundle.IsBuildin && appPatchBundle.Hash == patchBundle.Hash) { continue; } } downloadList.Add(patchBundle); } return(ConvertToDownloadList(downloadList)); }
private void VerifyInThread(object infoObj) { ThreadInfo info = (ThreadInfo)infoObj; info.Result = DownloadSystem.CheckContentIntegrity(info.FilePath, info.Bundle.SizeBytes, info.Bundle.CRC); _syncContext.Post(VerifyCallback, info); }
private BundleInfo CreateBundleInfo(string bundleName) { if (LocalPatchManifest.Bundles.TryGetValue(bundleName, out PatchBundle patchBundle)) { // 查询沙盒资源 if (DownloadSystem.ContainsVerifyFile(patchBundle.Hash)) { BundleInfo bundleInfo = new BundleInfo(patchBundle, BundleInfo.ELoadMode.LoadFromCache); return(bundleInfo); } // 查询APP资源 if (AppPatchManifest.Bundles.TryGetValue(bundleName, out PatchBundle appPatchBundle)) { if (appPatchBundle.IsBuildin && appPatchBundle.Hash == patchBundle.Hash) { BundleInfo bundleInfo = new BundleInfo(appPatchBundle, BundleInfo.ELoadMode.LoadFromStreaming); return(bundleInfo); } } // 从服务端下载 return(ConvertToDownloadInfo(patchBundle)); } else { throw new Exception("Should never get here !"); } }
internal static void InternalUpdate() { // 更新异步操作系统 OperationSystem.Update(); // 更新下载管理系统 DownloadSystem.Update(); // 更新资源系统 AssetSystem.Update(); }
private void VerifyCallback(object obj) { ThreadInfo info = (ThreadInfo)obj; if (info.Result) { _verifySuccessCount++; DownloadSystem.CacheVerifyFile(info.Bundle.Hash, info.Bundle.BundleName); } else { _verifyFailCount++; YooLogger.Warning($"Failed to verify file : {info.FilePath}"); if (File.Exists(info.FilePath)) { File.Delete(info.FilePath); } } _verifyingList.Remove(info.Bundle); }
private List <BundleInfo> GetDownloadListByTags(string[] tags) { List <PatchBundle> downloadList = new List <PatchBundle>(1000); foreach (var patchBundle in LocalPatchManifest.BundleList) { // 忽略缓存文件 if (DownloadSystem.ContainsVerifyFile(patchBundle.Hash)) { continue; } // 忽略APP资源 // 注意:如果是APP资源并且哈希值相同,则不需要下载 if (AppPatchManifest.Bundles.TryGetValue(patchBundle.BundleName, out PatchBundle appPatchBundle)) { if (appPatchBundle.IsBuildin && appPatchBundle.Hash == patchBundle.Hash) { continue; } } // 如果是纯内置资源,则统一下载 // 注意:可能是新增的或者变化的内置资源 // 注意:可能是由热更资源转换的内置资源 if (patchBundle.IsPureBuildin()) { downloadList.Add(patchBundle); } else { // 查询DLC资源 if (patchBundle.HasTag(tags)) { downloadList.Add(patchBundle); } } } return(ConvertToDownloadList(downloadList)); }
/// <summary> /// 获取下载列表 /// </summary> private List <BundleInfo> GetDownloadList() { List <PatchBundle> downloadList = new List <PatchBundle>(1000); foreach (var patchBundle in _remotePatchManifest.BundleList) { // 忽略缓存文件 if (DownloadSystem.ContainsVerifyFile(patchBundle.Hash)) { continue; } // 忽略APP资源 // 注意:如果是APP资源并且哈希值相同,则不需要下载 if (_impl.AppPatchManifest.Bundles.TryGetValue(patchBundle.BundleName, out PatchBundle appPatchBundle)) { if (appPatchBundle.IsBuildin && appPatchBundle.Hash == patchBundle.Hash) { continue; } } // 注意:通过比对文件大小做快速的文件校验! // 注意:在初始化的时候会去做最终校验! string filePath = SandboxHelper.MakeCacheFilePath(patchBundle.Hash); if (File.Exists(filePath)) { long fileSize = FileUtility.GetFileSize(filePath); if (fileSize == patchBundle.SizeBytes) { continue; } } downloadList.Add(patchBundle); } return(_impl.ConvertToDownloadList(downloadList)); }
private void InitVerifyingCache() { // 遍历所有文件然后验证并缓存合法文件 foreach (var patchBundle in _impl.LocalPatchManifest.BundleList) { // 忽略缓存文件 if (DownloadSystem.ContainsVerifyFile(patchBundle.Hash)) { continue; } // 忽略APP资源 // 注意:如果是APP资源并且哈希值相同,则不需要下载 if (_impl.AppPatchManifest.Bundles.TryGetValue(patchBundle.BundleName, out PatchBundle appPatchBundle)) { if (appPatchBundle.IsBuildin && appPatchBundle.Hash == patchBundle.Hash) { continue; } } // 查看文件是否存在 string filePath = SandboxHelper.MakeCacheFilePath(patchBundle.Hash); if (File.Exists(filePath) == false) { continue; } _waitingList.Add(patchBundle); } // 设置同时验证的最大数 ThreadPool.GetMaxThreads(out int workerThreads, out int ioThreads); YooLogger.Log($"Work threads : {workerThreads}, IO threads : {ioThreads}"); _verifyMaxNum = Math.Min(workerThreads, ioThreads); _verifyTotalCount = _waitingList.Count; }
/// <summary> /// 异步初始化 /// </summary> public static InitializationOperation InitializeAsync(InitializeParameters parameters) { if (parameters == null) { throw new Exception($"YooAsset create parameters is null."); } if (parameters.LocationServices == null) { throw new Exception($"{nameof(IBundleServices)} is null."); } else { _locationServices = parameters.LocationServices; } #if !UNITY_EDITOR if (parameters is EditorSimulateModeParameters) { throw new Exception($"Editor simulate mode only support unity editor."); } #endif // 创建驱动器 if (_isInitialize == false) { _isInitialize = true; UnityEngine.GameObject driverGo = new UnityEngine.GameObject("[YooAsset]"); driverGo.AddComponent <YooAssetDriver>(); UnityEngine.Object.DontDestroyOnLoad(driverGo); } else { throw new Exception("YooAsset is initialized yet."); } // 检测参数范围 if (parameters.AssetLoadingMaxNumber < 1) { parameters.AssetLoadingMaxNumber = 1; YooLogger.Warning($"{nameof(parameters.AssetLoadingMaxNumber)} minimum value is 1"); } if (parameters.OperationSystemMaxTimeSlice < 30) { parameters.OperationSystemMaxTimeSlice = 30; YooLogger.Warning($"{nameof(parameters.OperationSystemMaxTimeSlice)} minimum value is 30 milliseconds"); } // 鉴定运行模式 if (parameters is EditorSimulateModeParameters) { _playMode = EPlayMode.EditorSimulateMode; } else if (parameters is OfflinePlayModeParameters) { _playMode = EPlayMode.OfflinePlayMode; } else if (parameters is HostPlayModeParameters) { _playMode = EPlayMode.HostPlayMode; } else { throw new NotImplementedException(); } // 初始化异步操作系统 OperationSystem.Initialize(parameters.OperationSystemMaxTimeSlice); // 初始化下载系统 if (_playMode == EPlayMode.HostPlayMode) { #if UNITY_WEBGL throw new Exception($"{EPlayMode.HostPlayMode} not supports WebGL platform !"); #else var hostPlayModeParameters = parameters as HostPlayModeParameters; DownloadSystem.Initialize(hostPlayModeParameters.BreakpointResumeFileSize); #endif } // 初始化资源系统 InitializationOperation initializeOperation; if (_playMode == EPlayMode.EditorSimulateMode) { _editorSimulateModeImpl = new EditorSimulateModeImpl(); _bundleServices = _editorSimulateModeImpl; AssetSystem.Initialize(true, parameters.AssetLoadingMaxNumber, parameters.DecryptionServices, _bundleServices); var editorSimulateModeParameters = parameters as EditorSimulateModeParameters; initializeOperation = _editorSimulateModeImpl.InitializeAsync( editorSimulateModeParameters.LocationToLower, editorSimulateModeParameters.SimulatePatchManifestPath); } else if (_playMode == EPlayMode.OfflinePlayMode) { _offlinePlayModeImpl = new OfflinePlayModeImpl(); _bundleServices = _offlinePlayModeImpl; AssetSystem.Initialize(false, parameters.AssetLoadingMaxNumber, parameters.DecryptionServices, _bundleServices); initializeOperation = _offlinePlayModeImpl.InitializeAsync(parameters.LocationToLower); } else if (_playMode == EPlayMode.HostPlayMode) { _hostPlayModeImpl = new HostPlayModeImpl(); _bundleServices = _hostPlayModeImpl; AssetSystem.Initialize(false, parameters.AssetLoadingMaxNumber, parameters.DecryptionServices, _bundleServices); var hostPlayModeParameters = parameters as HostPlayModeParameters; initializeOperation = _hostPlayModeImpl.InitializeAsync( hostPlayModeParameters.LocationToLower, hostPlayModeParameters.ClearCacheWhenDirty, hostPlayModeParameters.DefaultHostServer, hostPlayModeParameters.FallbackHostServer); } else { throw new NotImplementedException(); } // 监听初始化结果 initializeOperation.Completed += InitializeOperation_Completed; return(initializeOperation); }
void OnApplicationQuit() { DownloadSystem.DestroyAll(); }
internal override void Update() { if (_steps == ESteps.None || _steps == ESteps.Done) { return; } if (_steps == ESteps.Check) { if (_downloadList == null) { _steps = ESteps.Done; Status = EOperationStatus.Failed; Error = "Download list is null."; } else { _steps = ESteps.Loading; } } if (_steps == ESteps.Loading) { // 检测下载器结果 _removeList.Clear(); long downloadBytes = CurrentDownloadBytes; foreach (var downloader in _downloaders) { downloadBytes += (long)downloader.DownloadedBytes; if (downloader.IsDone() == false) { continue; } BundleInfo bundleInfo = downloader.GetBundleInfo(); // 检测是否下载失败 if (downloader.HasError()) { _removeList.Add(downloader); _loadFailedList.Add(bundleInfo); continue; } // 下载成功 _removeList.Add(downloader); CurrentDownloadCount++; CurrentDownloadBytes += bundleInfo.SizeBytes; } // 移除已经完成的下载器(无论成功或失败) foreach (var loader in _removeList) { _downloaders.Remove(loader); } // 如果下载进度发生变化 if (_lastDownloadBytes != downloadBytes || _lastDownloadCount != CurrentDownloadCount) { _lastDownloadBytes = downloadBytes; _lastDownloadCount = CurrentDownloadCount; Progress = (float)_lastDownloadBytes / TotalDownloadBytes; OnDownloadProgressCallback?.Invoke(TotalDownloadCount, _lastDownloadCount, TotalDownloadBytes, _lastDownloadBytes); } // 动态创建新的下载器到最大数量限制 // 注意:如果期间有下载失败的文件,暂停动态创建下载器 if (_downloadList.Count > 0 && _loadFailedList.Count == 0) { if (_isPause) { return; } if (_downloaders.Count < _downloadingMaxNumber) { int index = _downloadList.Count - 1; var operation = DownloadSystem.BeginDownload(_downloadList[index], _failedTryAgain); _downloaders.Add(operation); _downloadList.RemoveAt(index); } } // 下载结算 if (_downloaders.Count == 0) { if (_loadFailedList.Count > 0) { string fileName = _loadFailedList[0].BundleName; Error = $"Failed to download file : {fileName}"; _steps = ESteps.Done; Status = EOperationStatus.Failed; OnDownloadFileFailedCallback?.Invoke(fileName); OnDownloadOverCallback?.Invoke(false); } else { // 结算成功 _steps = ESteps.Done; Status = EOperationStatus.Succeed; OnDownloadOverCallback?.Invoke(true); } } } }
internal override void Update() { if (_steps == ESteps.None || _steps == ESteps.Done) { return; } // 1. 准备工作 if (_steps == ESteps.Prepare) { if (_bundleInfo.LoadMode == BundleInfo.ELoadMode.None) { _steps = ESteps.Done; Status = EOperationStatus.Failed; Error = $"Bundle info is invalid : {_bundleInfo.BundleName}"; } else if (_bundleInfo.LoadMode == BundleInfo.ELoadMode.LoadFromRemote) { _steps = ESteps.DownloadFromWeb; } else if (_bundleInfo.LoadMode == BundleInfo.ELoadMode.LoadFromStreaming) { _steps = ESteps.DownloadFromApk; } else if (_bundleInfo.LoadMode == BundleInfo.ELoadMode.LoadFromCache) { _steps = ESteps.CheckAndCopyFile; } else { throw new System.NotImplementedException(_bundleInfo.LoadMode.ToString()); } } // 2. 从服务器下载 if (_steps == ESteps.DownloadFromWeb) { int failedTryAgain = int.MaxValue; _downloader = DownloadSystem.BeginDownload(_bundleInfo, failedTryAgain); _steps = ESteps.CheckDownloadFromWeb; } // 3. 检测服务器下载结果 if (_steps == ESteps.CheckDownloadFromWeb) { Progress = _downloader.DownloadProgress; if (_downloader.IsDone() == false) { return; } if (_downloader.HasError()) { _steps = ESteps.Done; Status = EOperationStatus.Failed; Error = _downloader.GetLastError(); } else { _steps = ESteps.CheckAndCopyFile; } } // 4. 从APK拷贝文件 if (_steps == ESteps.DownloadFromApk) { string downloadURL = PathHelper.ConvertToWWWPath(_bundleInfo.GetStreamingLoadPath()); _fileRequester = new UnityWebFileRequester(); _fileRequester.SendRequest(downloadURL, GetCachePath()); _steps = ESteps.CheckDownloadFromApk; } // 5. 检测APK拷贝文件结果 if (_steps == ESteps.CheckDownloadFromApk) { Progress = _fileRequester.Progress(); if (_fileRequester.IsDone() == false) { return; } if (_fileRequester.HasError()) { _steps = ESteps.Done; Status = EOperationStatus.Failed; Error = _fileRequester.GetError(); } else { _steps = ESteps.CheckAndCopyFile; } _fileRequester.Dispose(); } // 6. 检测并拷贝原生文件 if (_steps == ESteps.CheckAndCopyFile) { // 如果不需要保存文件 if (string.IsNullOrEmpty(CopyPath)) { _steps = ESteps.Done; Status = EOperationStatus.Succeed; return; } // 如果原生文件已经存在,则验证其完整性 if (File.Exists(CopyPath)) { bool result = DownloadSystem.CheckContentIntegrity(CopyPath, _bundleInfo.SizeBytes, _bundleInfo.CRC); if (result) { _steps = ESteps.Done; Status = EOperationStatus.Succeed; return; } else { File.Delete(CopyPath); } } try { FileUtility.CreateFileDirectory(CopyPath); File.Copy(GetCachePath(), CopyPath, true); _steps = ESteps.Done; Status = EOperationStatus.Succeed; } catch (System.Exception e) { _steps = ESteps.Done; Status = EOperationStatus.Failed; Error = e.ToString(); } } }
private void ThreadRun() { long fileTotalSize = _fileSize; FileStream fileStream = null; HttpWebResponse webResponse = null; Stream responseStream = null; try { // 创建文件流 fileStream = new FileStream(_savePath, FileMode.OpenOrCreate, FileAccess.Write); long fileLength = fileStream.Length; // 创建HTTP下载请求 HttpWebRequest webRequest = WebRequest.Create(_url) as HttpWebRequest; webRequest.Timeout = _timeout * 1000; webRequest.ProtocolVersion = HttpVersion.Version10; if (fileLength > 0) { // 注意:设置远端请求文件的起始位置 webRequest.AddRange(fileLength); // 注意:设置本地文件流的起始位置 fileStream.Seek(fileLength, SeekOrigin.Begin); } // 读取下载数据并保存到文件 webResponse = webRequest.GetResponse() as HttpWebResponse; responseStream = webResponse.GetResponseStream(); byte[] buffer = new byte[BufferSize]; while (_running) { int length = responseStream.Read(buffer, 0, buffer.Length); if (length <= 0) { break; } fileStream.Write(buffer, 0, length); // 计算下载进度 // 注意:原子操作保证数据安全 fileLength += length; float progress = fileLength / fileTotalSize; DownloadProgress = progress; DownloadedBytes = (ulong)fileLength; } } catch (Exception e) { Error = e.Message; } finally { if (responseStream != null) { responseStream.Close(); responseStream.Dispose(); } if (webResponse != null) { webResponse.Close(); webResponse.Dispose(); } if (fileStream != null) { fileStream.Flush(); fileStream.Close(); } // 验证下载文件完整性 if (DownloadedBytes == (ulong)_fileSize) { bool verfiyResult = DownloadSystem.CheckContentIntegrity(_savePath, _fileSize, _fileCRC); if (verfiyResult == false) { Error = $"Verify download content failed : {_fileHash}"; if (File.Exists(_savePath)) { File.Delete(_savePath); } } } else { Error = $"Download content is incomplete : {_fileHash}"; } IsDone = true; } }
public override void Update() { if (_steps == ESteps.None) { return; } if (IsDone()) { return; } if (_steps == ESteps.CreateDownload) { // 重置变量 _downloadProgress = 0f; _downloadedBytes = 0; _tryAgainTimer = 0f; _requestURL = GetRequestURL(); _threadDownloader = new ThreadDownloader(); _threadDownloader.Run(_requestURL, _bundleInfo.GetCacheLoadPath(), _bundleInfo.Hash, _bundleInfo.CRC, _bundleInfo.SizeBytes, _timeout); _steps = ESteps.CheckDownload; } if (_steps == ESteps.CheckDownload) { _downloadProgress = _threadDownloader.DownloadProgress; _downloadedBytes = _threadDownloader.DownloadedBytes; if (_threadDownloader.IsDone == false) { return; } if (_threadDownloader.HasError()) { _lastError = _threadDownloader.Error; // 失败后重新尝试 if (_failedTryAgain > 0) { ReportWarning(); _steps = ESteps.TryAgain; } else { ReportError(); _steps = ESteps.Failed; } } else { DownloadSystem.CacheVerifyFile(_bundleInfo.Hash, _bundleInfo.BundleName); _steps = ESteps.Succeed; } } // 重新尝试下载 if (_steps == ESteps.TryAgain) { _tryAgainTimer += UnityEngine.Time.unscaledDeltaTime; if (_tryAgainTimer > 1f) { _failedTryAgain--; _steps = ESteps.CreateDownload; YooLogger.Warning($"Try again download : {_requestURL}"); } } }
public override void Update() { if (_steps == ESteps.None) { return; } if (IsDone()) { return; } // 创建下载器 if (_steps == ESteps.CreateDownload) { // 重置变量 _downloadProgress = 0f; _downloadedBytes = 0; _isAbort = false; _latestDownloadBytes = 0; _latestDownloadRealtime = Time.realtimeSinceStartup; _tryAgainTimer = 0f; _requestURL = GetRequestURL(); _webRequest = new UnityWebRequest(_requestURL, UnityWebRequest.kHttpVerbGET); DownloadHandlerFile handler = new DownloadHandlerFile(_bundleInfo.GetCacheLoadPath()); handler.removeFileOnAbort = true; _webRequest.downloadHandler = handler; _webRequest.disposeDownloadHandlerOnDispose = true; _operationHandle = _webRequest.SendWebRequest(); _steps = ESteps.CheckDownload; } // 检测下载结果 if (_steps == ESteps.CheckDownload) { _downloadProgress = _webRequest.downloadProgress; _downloadedBytes = _webRequest.downloadedBytes; if (_operationHandle.isDone == false) { CheckTimeout(); return; } // 检查网络错误 bool hasError = false; #if UNITY_2020_3_OR_NEWER if (_webRequest.result != UnityWebRequest.Result.Success) { hasError = true; _lastError = _webRequest.error; } #else if (_webRequest.isNetworkError || _webRequest.isHttpError) { hasError = true; _lastError = _webRequest.error; } #endif // 检查文件完整性 if (hasError == false) { // 注意:如果文件验证失败需要删除文件 if (DownloadSystem.CheckContentIntegrity(_bundleInfo) == false) { hasError = true; _lastError = $"Verification failed"; } } if (hasError == false) { _steps = ESteps.Succeed; DownloadSystem.CacheVerifyFile(_bundleInfo.Hash, _bundleInfo.BundleName); } else { string cacheFilePath = _bundleInfo.GetCacheLoadPath(); if (File.Exists(cacheFilePath)) { File.Delete(cacheFilePath); } // 失败后重新尝试 if (_failedTryAgain > 0) { ReportWarning(); _steps = ESteps.TryAgain; } else { ReportError(); _steps = ESteps.Failed; } } // 释放下载器 DisposeWebRequest(); } // 重新尝试下载 if (_steps == ESteps.TryAgain) { _tryAgainTimer += Time.unscaledDeltaTime; if (_tryAgainTimer > 1f) { _failedTryAgain--; _steps = ESteps.CreateDownload; YooLogger.Warning($"Try again download : {_requestURL}"); } } }
/// <summary> /// 轮询更新 /// </summary> public override void Update() { if (_steps == ESteps.Done) { return; } if (_steps == ESteps.None) { if (MainBundleInfo.IsInvalid) { _steps = ESteps.Done; Status = EStatus.Failed; LastError = $"The bundle info is invalid : {MainBundleInfo.BundleName}"; YooLogger.Error(LastError); return; } if (MainBundleInfo.LoadMode == BundleInfo.ELoadMode.LoadFromRemote) { _steps = ESteps.Download; _fileLoadPath = MainBundleInfo.GetCacheLoadPath(); } else if (MainBundleInfo.LoadMode == BundleInfo.ELoadMode.LoadFromStreaming) { _steps = ESteps.LoadFile; _fileLoadPath = MainBundleInfo.GetStreamingLoadPath(); } else if (MainBundleInfo.LoadMode == BundleInfo.ELoadMode.LoadFromCache) { _steps = ESteps.LoadFile; _fileLoadPath = MainBundleInfo.GetCacheLoadPath(); } else { throw new System.NotImplementedException(MainBundleInfo.LoadMode.ToString()); } } // 1. 从服务器下载 if (_steps == ESteps.Download) { int failedTryAgain = int.MaxValue; _downloader = DownloadSystem.BeginDownload(MainBundleInfo, failedTryAgain); _steps = ESteps.CheckDownload; } // 2. 检测服务器下载结果 if (_steps == ESteps.CheckDownload) { if (_downloader.IsDone() == false) { return; } if (_downloader.HasError()) { _steps = ESteps.Done; Status = EStatus.Failed; LastError = _downloader.GetLastError(); } else { _steps = ESteps.LoadFile; } } // 3. 加载AssetBundle if (_steps == ESteps.LoadFile) { #if UNITY_EDITOR // 注意:Unity2017.4编辑器模式下,如果AssetBundle文件不存在会导致编辑器崩溃,这里做了预判。 if (System.IO.File.Exists(_fileLoadPath) == false) { _steps = ESteps.Done; Status = EStatus.Failed; LastError = $"Not found assetBundle file : {_fileLoadPath}"; YooLogger.Error(LastError); return; } #endif // Load assetBundle file if (MainBundleInfo.IsEncrypted) { if (AssetSystem.DecryptionServices == null) { throw new Exception($"{nameof(AssetBundleFileLoader)} need {nameof(IDecryptionServices)} : {MainBundleInfo.BundleName}"); } ulong offset = AssetSystem.DecryptionServices.GetFileOffset(); if (_isWaitForAsyncComplete) { CacheBundle = AssetBundle.LoadFromFile(_fileLoadPath, 0, offset); } else { _cacheRequest = AssetBundle.LoadFromFileAsync(_fileLoadPath, 0, offset); } } else { if (_isWaitForAsyncComplete) { CacheBundle = AssetBundle.LoadFromFile(_fileLoadPath); } else { _cacheRequest = AssetBundle.LoadFromFileAsync(_fileLoadPath); } } _steps = ESteps.CheckFile; } // 4. 检测AssetBundle加载结果 if (_steps == ESteps.CheckFile) { if (_cacheRequest != null) { if (_isWaitForAsyncComplete) { // 强制挂起主线程(注意:该操作会很耗时) YooLogger.Warning("Suspend the main thread to load unity bundle."); CacheBundle = _cacheRequest.assetBundle; } else { if (_cacheRequest.isDone == false) { return; } CacheBundle = _cacheRequest.assetBundle; } } // Check error if (CacheBundle == null) { _steps = ESteps.Done; Status = EStatus.Failed; LastError = $"Failed to load assetBundle : {MainBundleInfo.BundleName}"; YooLogger.Error(LastError); } else { _steps = ESteps.Done; Status = EStatus.Succeed; } } }