From cd79f0e43402f2e243f87175e34a175aff3b6544 Mon Sep 17 00:00:00 2001 From: hevinci Date: Mon, 31 Oct 2022 16:45:21 +0800 Subject: [PATCH] Update runtime code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit AssetsPackage.WeaklyUpdateManifestAsync(string packageVersion)移除了packageVersion参数。 优化了HostPlayMode的初始化逻辑,优先读取沙盒内的清单,如果不存在则读取内置清单。 --- .../Operations/RawFileOperation.cs | 4 +- Assets/YooAsset/Runtime/AssetsPackage.cs | 15 +- .../ClearUnusedCacheFilesOperation.cs | 2 +- .../Operations/InitializationOperation.cs | 148 +++++++----- .../Operations/UpdateManifestOperation.cs | 220 ++++++++++-------- .../Operations/UpdatePackageOperation.cs | 26 +-- .../Runtime/PatchSystem/PatchBundle.cs | 2 +- .../Runtime/PatchSystem/PatchManifest.cs | 19 ++ .../PlayMode/EditorSimulateModeImpl.cs | 2 +- .../PatchSystem/PlayMode/HostPlayModeImpl.cs | 31 ++- .../PlayMode/OfflinePlayModeImpl.cs | 2 +- .../Runtime/Settings/YooAssetSettingsData.cs | 8 + Assets/YooAsset/Runtime/Utility/YooHelper.cs | 85 ++++--- Assets/YooAsset/Runtime/YooAssets.cs | 2 +- 14 files changed, 341 insertions(+), 225 deletions(-) diff --git a/Assets/YooAsset/Runtime/AssetSystem/Operations/RawFileOperation.cs b/Assets/YooAsset/Runtime/AssetSystem/Operations/RawFileOperation.cs index 3adfe02..2d6895c 100644 --- a/Assets/YooAsset/Runtime/AssetSystem/Operations/RawFileOperation.cs +++ b/Assets/YooAsset/Runtime/AssetSystem/Operations/RawFileOperation.cs @@ -219,7 +219,7 @@ namespace YooAsset if (_steps == ESteps.DownloadBuildinFile) { int failedTryAgain = int.MaxValue; - var bundleInfo = PatchHelper.ConvertToUnpackInfo(_bundleInfo.Bundle); + var bundleInfo = HostPlayModeImpl.ConvertToUnpackInfo(_bundleInfo.Bundle); _downloader = DownloadSystem.BeginDownload(bundleInfo, failedTryAgain); _steps = ESteps.CheckDownload; } @@ -367,7 +367,7 @@ namespace YooAsset if (_steps == ESteps.DownloadBuildinFile) { int failedTryAgain = int.MaxValue; - var bundleInfo = PatchHelper.ConvertToUnpackInfo(_bundleInfo.Bundle); + var bundleInfo = HostPlayModeImpl.ConvertToUnpackInfo(_bundleInfo.Bundle); _downloader = DownloadSystem.BeginDownload(bundleInfo, failedTryAgain); _steps = ESteps.CheckDownload; } diff --git a/Assets/YooAsset/Runtime/AssetsPackage.cs b/Assets/YooAsset/Runtime/AssetsPackage.cs index cca573a..d8a0a82 100644 --- a/Assets/YooAsset/Runtime/AssetsPackage.cs +++ b/Assets/YooAsset/Runtime/AssetsPackage.cs @@ -182,7 +182,7 @@ namespace YooAsset } /// - /// 向网络端请求静态资源版本 + /// 向网络端请求最新的资源版本 /// /// 超时时间(默认值:60秒) public UpdateStaticVersionOperation UpdateStaticVersionAsync(int timeout = 60) @@ -242,11 +242,10 @@ namespace YooAsset } /// - /// 弱联网情况下加载补丁清单 - /// 注意:当指定版本内容验证失败后会返回失败。 + /// 弱联网情况下加载本地的补丁清单 + /// 注意:当清单里的内容验证失败后会返回失败。 /// - /// 指定的包裹版本 - public UpdateManifestOperation WeaklyUpdateManifestAsync(string packageVersion) + public UpdateManifestOperation WeaklyUpdateManifestAsync() { DebugCheckInitialize(); if (_playMode == EPlayMode.EditorSimulateMode) @@ -263,7 +262,7 @@ namespace YooAsset } else if (_playMode == EPlayMode.HostPlayMode) { - return _hostPlayModeImpl.WeaklyUpdatePatchManifestAsync(PackageName, packageVersion); + return _hostPlayModeImpl.WeaklyUpdatePatchManifestAsync(PackageName); } else { @@ -945,9 +944,9 @@ namespace YooAsset private void DebugCheckInitialize() { if (_initializeStatus == EOperationStatus.None) - throw new Exception("YooAssets initialize not completed !"); + throw new Exception("Package initialize not completed !"); else if (_initializeStatus == EOperationStatus.Failed) - throw new Exception($"YooAssets initialize failed : {_initializeError}"); + throw new Exception($"Package initialize failed ! {_initializeError}"); } [Conditional("DEBUG")] diff --git a/Assets/YooAsset/Runtime/PatchSystem/Operations/ClearUnusedCacheFilesOperation.cs b/Assets/YooAsset/Runtime/PatchSystem/Operations/ClearUnusedCacheFilesOperation.cs index 95ff48e..2618162 100644 --- a/Assets/YooAsset/Runtime/PatchSystem/Operations/ClearUnusedCacheFilesOperation.cs +++ b/Assets/YooAsset/Runtime/PatchSystem/Operations/ClearUnusedCacheFilesOperation.cs @@ -84,7 +84,7 @@ namespace YooAsset /// private List GetUnusedCacheFilePaths() { - string cacheFolderPath = SandboxHelper.GetCacheFolderPath(); + string cacheFolderPath = PersistentHelper.GetCacheFolderPath(); if (Directory.Exists(cacheFolderPath) == false) return new List(); diff --git a/Assets/YooAsset/Runtime/PatchSystem/Operations/InitializationOperation.cs b/Assets/YooAsset/Runtime/PatchSystem/Operations/InitializationOperation.cs index a147ca6..9738523 100644 --- a/Assets/YooAsset/Runtime/PatchSystem/Operations/InitializationOperation.cs +++ b/Assets/YooAsset/Runtime/PatchSystem/Operations/InitializationOperation.cs @@ -25,7 +25,7 @@ namespace YooAsset } private readonly EditorSimulateModeImpl _impl; - private string _simulatePatchManifestPath; + private readonly string _simulatePatchManifestPath; private ESteps _steps = ESteps.None; internal EditorSimulateModeInitializationOperation(EditorSimulateModeImpl impl, string simulatePatchManifestPath) @@ -45,16 +45,25 @@ namespace YooAsset { _steps = ESteps.Done; Status = EOperationStatus.Failed; - Error = $"Manifest file not found : {_simulatePatchManifestPath}"; + Error = $"Not found simulation manifest file : {_simulatePatchManifestPath}"; return; } - YooLogger.Log($"Load manifest file : {_simulatePatchManifestPath}"); - string jsonContent = FileUtility.ReadFile(_simulatePatchManifestPath); - var simulatePatchManifest = PatchManifest.Deserialize(jsonContent); - _impl.SetSimulatePatchManifest(simulatePatchManifest); - _steps = ESteps.Done; - Status = EOperationStatus.Succeed; + try + { + YooLogger.Log($"Load simulation manifest file : {_simulatePatchManifestPath}"); + string jsonContent = FileUtility.ReadFile(_simulatePatchManifestPath); + var manifest = PatchManifest.Deserialize(jsonContent); + _impl.SetSimulatePatchManifest(manifest); + _steps = ESteps.Done; + Status = EOperationStatus.Succeed; + } + catch (System.Exception e) + { + _steps = ESteps.Done; + Status = EOperationStatus.Failed; + Error = e.Message; + } } } } @@ -67,7 +76,7 @@ namespace YooAsset private enum ESteps { None, - QueryPackageVersion, + QueryAppPackageVersion, LoadAppManifest, InitVerifyingCache, UpdateVerifyingCache, @@ -76,7 +85,7 @@ namespace YooAsset private readonly OfflinePlayModeImpl _impl; private readonly string _packageName; - private readonly CacheVerifier _patchCacheVerifier; + private readonly CacheVerifier _cacheVerifier; private readonly AppPackageVersionQuerier _appPackageVersionQuerier; private AppManifestLoader _appManifestLoader; private ESteps _steps = ESteps.None; @@ -89,21 +98,21 @@ namespace YooAsset _appPackageVersionQuerier = new AppPackageVersionQuerier(packageName); #if UNITY_WEBGL - _patchCacheVerifier = new CacheVerifierWithoutThread(); + _cacheVerifier = new CacheVerifierWithoutThread(); #else - _patchCacheVerifier = new CacheVerifierWithThread(); + _cacheVerifier = new CacheVerifierWithThread(); #endif } internal override void Start() { - _steps = ESteps.QueryPackageVersion; + _steps = ESteps.QueryAppPackageVersion; } internal override void Update() { if (_steps == ESteps.None || _steps == ESteps.Done) return; - if (_steps == ESteps.QueryPackageVersion) + if (_steps == ESteps.QueryAppPackageVersion) { _appPackageVersionQuerier.Update(); if (_appPackageVersionQuerier.IsDone == false) @@ -130,7 +139,8 @@ namespace YooAsset if (_appManifestLoader.IsDone == false) return; - if (_appManifestLoader.Manifest == null) + var manifest = _appManifestLoader.Manifest; + if (manifest == null) { _steps = ESteps.Done; Status = EOperationStatus.Failed; @@ -139,27 +149,27 @@ namespace YooAsset else { _steps = ESteps.InitVerifyingCache; - _impl.SetAppPatchManifest(_appManifestLoader.Manifest); + _impl.SetAppPatchManifest(manifest); } } if (_steps == ESteps.InitVerifyingCache) { var verifyInfos = _impl.GetVerifyInfoList(); - _patchCacheVerifier.InitVerifier(verifyInfos); + _cacheVerifier.InitVerifier(verifyInfos); _verifyTime = UnityEngine.Time.realtimeSinceStartup; _steps = ESteps.UpdateVerifyingCache; } if (_steps == ESteps.UpdateVerifyingCache) { - Progress = _patchCacheVerifier.GetVerifierProgress(); - if (_patchCacheVerifier.UpdateVerifier()) + Progress = _cacheVerifier.GetVerifierProgress(); + if (_cacheVerifier.UpdateVerifier()) { _steps = ESteps.Done; Status = EOperationStatus.Succeed; float costTime = UnityEngine.Time.realtimeSinceStartup - _verifyTime; - YooLogger.Log($"Verify result : Success {_patchCacheVerifier.VerifySuccessList.Count}, Fail {_patchCacheVerifier.VerifyFailList.Count}, Elapsed time {costTime} seconds"); + YooLogger.Log($"Verify result : Success {_cacheVerifier.VerifySuccessList.Count}, Fail {_cacheVerifier.VerifyFailList.Count}, Elapsed time {costTime} seconds"); } } } @@ -167,15 +177,17 @@ namespace YooAsset /// /// 联机运行模式的初始化操作 + /// 注意:优先从沙盒里加载清单,如果沙盒里不存在就尝试把内置清单拷贝到沙盒并加载该清单。 /// internal sealed class HostPlayModeInitializationOperation : InitializationOperation { private enum ESteps { None, - QueryPackageVersion, - LoadAppManifest, + TryLoadCacheManifest, + QueryAppPackageVersion, CopyAppManifest, + LoadAppManifest, InitVerifyingCache, UpdateVerifyingCache, Done, @@ -183,7 +195,7 @@ namespace YooAsset private readonly HostPlayModeImpl _impl; private readonly string _packageName; - private readonly CacheVerifier _patchCacheVerifier; + private readonly CacheVerifier _cacheVerifier; private readonly AppPackageVersionQuerier _appPackageVersionQuerier; private AppManifestCopyer _appManifestCopyer; private AppManifestLoader _appManifestLoader; @@ -197,21 +209,45 @@ namespace YooAsset _appPackageVersionQuerier = new AppPackageVersionQuerier(packageName); #if UNITY_WEBGL - _patchCacheVerifier = new CacheVerifierWithoutThread(); + _cacheVerifier = new CacheVerifierWithoutThread(); #else - _patchCacheVerifier = new CacheVerifierWithThread(); + _cacheVerifier = new CacheVerifierWithThread(); #endif } internal override void Start() { - _steps = ESteps.QueryPackageVersion; + _steps = ESteps.TryLoadCacheManifest; } internal override void Update() { if (_steps == ESteps.None || _steps == ESteps.Done) return; - if (_steps == ESteps.QueryPackageVersion) + if (_steps == ESteps.TryLoadCacheManifest) + { + if (PersistentHelper.CheckCacheManifestFileExists(_packageName)) + { + try + { + var manifest = PersistentHelper.LoadCacheManifestFile(_packageName); + _impl.SetLocalPatchManifest(manifest); + _steps = ESteps.InitVerifyingCache; + } + catch (System.Exception e) + { + // 注意:如果加载沙盒内的清单报错,为了避免流程被卡住,我们主动把损坏的文件删除。 + YooLogger.Warning($"Failed to load cache manifest file : {e.Message}"); + PersistentHelper.DeleteCacheManifestFile(_packageName); + _steps = ESteps.QueryAppPackageVersion; + } + } + else + { + _steps = ESteps.QueryAppPackageVersion; + } + } + + if (_steps == ESteps.QueryAppPackageVersion) { _appPackageVersionQuerier.Update(); if (_appPackageVersionQuerier.IsDone == false) @@ -223,6 +259,7 @@ namespace YooAsset { _steps = ESteps.Done; Status = EOperationStatus.Succeed; + YooLogger.Log($"Failed to load buildin package version file : {error}"); } else { @@ -240,7 +277,7 @@ namespace YooAsset return; string error = _appManifestCopyer.Error; - if(string.IsNullOrEmpty(error) == false) + if (string.IsNullOrEmpty(error) == false) { _steps = ESteps.Done; Status = EOperationStatus.Failed; @@ -259,7 +296,8 @@ namespace YooAsset if (_appManifestLoader.IsDone == false) return; - if (_appManifestLoader.Manifest == null) + var manifest = _appManifestLoader.Manifest; + if (manifest == null) { _steps = ESteps.Done; Status = EOperationStatus.Failed; @@ -267,35 +305,37 @@ namespace YooAsset } else { + _impl.SetLocalPatchManifest(manifest); _steps = ESteps.InitVerifyingCache; - _impl.SetLocalPatchManifest(_appManifestLoader.Manifest); } } if (_steps == ESteps.InitVerifyingCache) { var verifyInfos = _impl.GetVerifyInfoList(false); - _patchCacheVerifier.InitVerifier(verifyInfos); + _cacheVerifier.InitVerifier(verifyInfos); _verifyTime = UnityEngine.Time.realtimeSinceStartup; _steps = ESteps.UpdateVerifyingCache; } if (_steps == ESteps.UpdateVerifyingCache) { - Progress = _patchCacheVerifier.GetVerifierProgress(); - if (_patchCacheVerifier.UpdateVerifier()) + Progress = _cacheVerifier.GetVerifierProgress(); + if (_cacheVerifier.UpdateVerifier()) { _steps = ESteps.Done; Status = EOperationStatus.Succeed; float costTime = UnityEngine.Time.realtimeSinceStartup - _verifyTime; - YooLogger.Log($"Verify result : Success {_patchCacheVerifier.VerifySuccessList.Count}, Fail {_patchCacheVerifier.VerifyFailList.Count}, Elapsed time {costTime} seconds"); + YooLogger.Log($"Verify result : Success {_cacheVerifier.VerifySuccessList.Count}, Fail {_cacheVerifier.VerifyFailList.Count}, Elapsed time {costTime} seconds"); } } } } - // 内置补丁清单版本查询器 + /// + /// 内置补丁清单版本查询器 + /// internal class AppPackageVersionQuerier { private enum ESteps @@ -367,7 +407,7 @@ namespace YooAsset { Version = _downloader.GetText(); if (string.IsNullOrEmpty(Version)) - Error = $"Buildin package version is empty !"; + Error = $"Buildin package version file content is empty !"; } _steps = ESteps.Done; _downloader.Dispose(); @@ -375,7 +415,9 @@ namespace YooAsset } } - // 内置补丁清单加载器 + /// + /// 内置补丁清单加载器 + /// internal class AppManifestLoader { private enum ESteps @@ -461,7 +503,14 @@ namespace YooAsset else { // 解析APP里的补丁清单 - Manifest = PatchManifest.Deserialize(_downloader.GetText()); + try + { + Manifest = PatchManifest.Deserialize(_downloader.GetText()); + } + catch (System.Exception e) + { + Error = e.Message; + } } _steps = ESteps.Done; _downloader.Dispose(); @@ -469,7 +518,9 @@ namespace YooAsset } } - // 内置补丁清单复制器 + /// + /// 内置补丁清单复制器 + /// internal class AppManifestCopyer { private enum ESteps @@ -530,20 +581,13 @@ namespace YooAsset if (_steps == ESteps.CopyAppManifest) { + string savePath = PersistentHelper.GetCacheManifestFilePath(_buildinPackageName); string fileName = YooAssetSettingsData.GetPatchManifestFileName(_buildinPackageName, _buildinPackageVersion); - string destFilePath = PathHelper.MakePersistentLoadPath(fileName); - if (File.Exists(destFilePath)) - { - _steps = ESteps.Done; - } - else - { - string sourceFilePath = PathHelper.MakeStreamingLoadPath(fileName); - string url = PathHelper.ConvertToWWWPath(sourceFilePath); - _downloader = new UnityWebFileRequester(); - _downloader.SendRequest(url, destFilePath); - _steps = ESteps.CheckAppManifest; - } + string filePath = PathHelper.MakeStreamingLoadPath(fileName); + string url = PathHelper.ConvertToWWWPath(filePath); + _downloader = new UnityWebFileRequester(); + _downloader.SendRequest(url, savePath); + _steps = ESteps.CheckAppManifest; } if (_steps == ESteps.CheckAppManifest) diff --git a/Assets/YooAsset/Runtime/PatchSystem/Operations/UpdateManifestOperation.cs b/Assets/YooAsset/Runtime/PatchSystem/Operations/UpdateManifestOperation.cs index a01f042..e23a43d 100644 --- a/Assets/YooAsset/Runtime/PatchSystem/Operations/UpdateManifestOperation.cs +++ b/Assets/YooAsset/Runtime/PatchSystem/Operations/UpdateManifestOperation.cs @@ -13,7 +13,7 @@ namespace YooAsset /// /// 是否发现了新的补丁清单 /// - public bool FoundNewManifest { protected set; get; } + public bool FoundNewManifest { protected set; get; } = false; } /// @@ -46,14 +46,17 @@ namespace YooAsset /// /// 联机模式的更新清单操作 + /// 注意:优先比对沙盒清单哈希值,如果有变化就更新远端清单文件,并保存到本地。 /// internal sealed class HostPlayModeUpdateManifestOperation : UpdateManifestOperation { private enum ESteps { None, + TryLoadCacheHash, LoadWebHash, CheckWebHash, + LoadCacheManifest, LoadWebManifest, CheckWebManifest, InitVerifyingCache, @@ -65,10 +68,12 @@ namespace YooAsset private readonly HostPlayModeImpl _impl; private readonly string _packageName; private readonly string _packageVersion; + private readonly CacheVerifier _cacheVerifier; private readonly int _timeout; private UnityWebDataRequester _downloader1; private UnityWebDataRequester _downloader2; - private CacheVerifier _cacheVerifier; + + private string _cacheManifestHash; private ESteps _steps = ESteps.None; private float _verifyTime; @@ -88,13 +93,27 @@ namespace YooAsset internal override void Start() { RequestCount++; - _steps = ESteps.LoadWebHash; + _steps = ESteps.TryLoadCacheHash; } internal override void Update() { if (_steps == ESteps.None || _steps == ESteps.Done) return; + if (_steps == ESteps.TryLoadCacheHash) + { + string filePath = PersistentHelper.GetCacheManifestFilePath(_packageName); + if (File.Exists(filePath)) + { + _cacheManifestHash = HashUtility.FileMD5(filePath); + _steps = ESteps.LoadWebHash; + } + else + { + _steps = ESteps.LoadWebManifest; + } + } + if (_steps == ESteps.LoadWebHash) { string fileName = YooAssetSettingsData.GetPatchManifestHashFileName(_packageName, _packageVersion); @@ -110,7 +129,6 @@ namespace YooAsset if (_downloader1.IsDone() == false) return; - // Check error if (_downloader1.HasError()) { _steps = ESteps.Done; @@ -120,26 +138,37 @@ namespace YooAsset else { string webManifestHash = _downloader1.GetText(); - string cachedManifestHash = GetSandboxPatchManifestFileHash(_packageName, _packageVersion); - - // 如果补丁清单文件的哈希值相同 - if (cachedManifestHash == webManifestHash) + if (_cacheManifestHash == webManifestHash) { - YooLogger.Log($"Patch manifest file hash is not change : {webManifestHash}"); - LoadSandboxPatchManifest(_packageName, _packageVersion); - FoundNewManifest = false; - _steps = ESteps.InitVerifyingCache; + YooLogger.Log($"Not found new package : {_packageName}"); + _steps = ESteps.LoadCacheManifest; } else { - YooLogger.Log($"Patch manifest hash is change : {cachedManifestHash} -> {webManifestHash}"); - FoundNewManifest = true; + YooLogger.Log($"Package {_packageName} is change : {_cacheManifestHash} -> {webManifestHash}"); _steps = ESteps.LoadWebManifest; } } _downloader1.Dispose(); } + if (_steps == ESteps.LoadCacheManifest) + { + try + { + var manifest = PersistentHelper.LoadCacheManifestFile(_packageName); + _impl.SetLocalPatchManifest(manifest); + _steps = ESteps.InitVerifyingCache; + } + catch (System.Exception e) + { + // 注意:如果加载沙盒内的清单报错,为了避免流程被卡住,我们主动把损坏的文件删除。 + YooLogger.Warning($"Failed to load cache manifest file : {e.Message}"); + PersistentHelper.DeleteCacheManifestFile(_packageName); + _steps = ESteps.LoadWebManifest; + } + } + if (_steps == ESteps.LoadWebManifest) { string fileName = YooAssetSettingsData.GetPatchManifestFileName(_packageName, _packageVersion); @@ -155,7 +184,6 @@ namespace YooAsset if (_downloader2.IsDone() == false) return; - // Check error if (_downloader2.HasError()) { _steps = ESteps.Done; @@ -164,16 +192,19 @@ namespace YooAsset } else { - // 解析补丁清单 - if (ParseAndSaveRemotePatchManifest(_packageName, _packageVersion, _downloader2.GetText())) + try { + string content = _downloader2.GetText(); + var manifest = PersistentHelper.SaveCacheManifestFile(_packageName, content); + _impl.SetLocalPatchManifest(manifest); + FoundNewManifest = true; _steps = ESteps.InitVerifyingCache; } - else + catch (Exception e) { _steps = ESteps.Done; Status = EOperationStatus.Failed; - Error = $"URL : {_downloader2.URL} Error : remote patch manifest content is invalid"; + Error = e.Message; } } _downloader2.Dispose(); @@ -211,68 +242,20 @@ namespace YooAsset else return _impl.GetPatchDownloadMainURL(fileName); } - - /// - /// 解析并保存远端请求的补丁清单 - /// - private bool ParseAndSaveRemotePatchManifest(string packageName, string packageVersion, string content) - { - try - { - var remotePatchManifest = PatchManifest.Deserialize(content); - _impl.SetLocalPatchManifest(remotePatchManifest); - - YooLogger.Log("Save remote patch manifest file."); - string fileName = YooAssetSettingsData.GetPatchManifestFileName(packageName, packageVersion); - string savePath = PathHelper.MakePersistentLoadPath(fileName); - PatchManifest.Serialize(savePath, remotePatchManifest); - return true; - } - catch (Exception e) - { - YooLogger.Error(e.ToString()); - return false; - } - } - - /// - /// 加载沙盒内的补丁清单 - /// 注意:在加载本地补丁清单之前,已经验证过文件的哈希值 - /// - private void LoadSandboxPatchManifest(string packageName, string packageVersion) - { - YooLogger.Log("Load sandbox patch manifest file."); - string fileName = YooAssetSettingsData.GetPatchManifestFileName(packageName, packageVersion); - string filePath = PathHelper.MakePersistentLoadPath(fileName); - string jsonData = File.ReadAllText(filePath); - var sandboxPatchManifest = PatchManifest.Deserialize(jsonData); - _impl.SetLocalPatchManifest(sandboxPatchManifest); - } - - /// - /// 获取沙盒内补丁清单文件的哈希值 - /// 注意:如果沙盒内补丁清单文件不存在,返回空字符串 - /// - private string GetSandboxPatchManifestFileHash(string packageName, string packageVersion) - { - string fileName = YooAssetSettingsData.GetPatchManifestFileName(packageName, packageVersion); - string filePath = PathHelper.MakePersistentLoadPath(fileName); - if (File.Exists(filePath)) - return HashUtility.FileMD5(filePath); - else - return string.Empty; - } } /// /// 联机模式的更新清单操作(弱联网) + /// 注意:优先加载沙盒内的清单文件,如果不存在或加载失败,然后加载内置清单。 /// internal sealed class HostPlayModeWeaklyUpdateManifestOperation : UpdateManifestOperation { private enum ESteps { None, - LoadSandboxManifestHash, + TryLoadSandboxManifest, + QueryAppPackageVersion, + LoadAppManifest, InitVerifyingCache, UpdateVerifyingCache, Done, @@ -280,16 +263,17 @@ namespace YooAsset private readonly HostPlayModeImpl _impl; private readonly string _packageName; - private readonly string _packageVersion; + private readonly CacheVerifier _cacheVerifier; + private readonly AppPackageVersionQuerier _appPackageVersionQuerier; + private AppManifestLoader _appManifestLoader; private ESteps _steps = ESteps.None; - private CacheVerifier _cacheVerifier; private float _verifyTime; - internal HostPlayModeWeaklyUpdateManifestOperation(HostPlayModeImpl impl, string packageName, string packageVersion) + internal HostPlayModeWeaklyUpdateManifestOperation(HostPlayModeImpl impl, string packageName) { _impl = impl; _packageName = packageName; - _packageVersion = packageVersion; + _appPackageVersionQuerier = new AppPackageVersionQuerier(packageName); #if UNITY_WEBGL _cacheVerifier = new CacheVerifierWithoutThread(); @@ -299,17 +283,76 @@ namespace YooAsset } internal override void Start() { - _steps = ESteps.LoadSandboxManifestHash; + _steps = ESteps.TryLoadSandboxManifest; } internal override void Update() { if (_steps == ESteps.None || _steps == ESteps.Done) return; - if (_steps == ESteps.LoadSandboxManifestHash) + if (_steps == ESteps.TryLoadSandboxManifest) { - LoadSandboxPatchManifest(_packageName, _packageVersion); - _steps = ESteps.InitVerifyingCache; + if (PersistentHelper.CheckCacheManifestFileExists(_packageName) == false) + { + _steps = ESteps.QueryAppPackageVersion; + } + else + { + try + { + var manifest = PersistentHelper.LoadCacheManifestFile(_packageName); + _impl.SetLocalPatchManifest(manifest); + _steps = ESteps.InitVerifyingCache; + } + catch (System.Exception e) + { + // 注意:如果加载沙盒内的清单报错,为了避免流程被卡住,我们主动把损坏的文件删除。 + YooLogger.Warning($"Failed to load cache manifest file : {e.Message}"); + PersistentHelper.DeleteCacheManifestFile(_packageName); + _steps = ESteps.QueryAppPackageVersion; + } + } + } + + if (_steps == ESteps.QueryAppPackageVersion) + { + _appPackageVersionQuerier.Update(); + if (_appPackageVersionQuerier.IsDone == false) + return; + + string error = _appPackageVersionQuerier.Error; + if (string.IsNullOrEmpty(error) == false) + { + _steps = ESteps.Done; + Status = EOperationStatus.Failed; + Error = error; + } + else + { + _appManifestLoader = new AppManifestLoader(_packageName, _appPackageVersionQuerier.Version); + _steps = ESteps.LoadAppManifest; + } + } + + if (_steps == ESteps.LoadAppManifest) + { + _appManifestLoader.Update(); + Progress = _appManifestLoader.Progress; + if (_appManifestLoader.IsDone == false) + return; + + var manifest = _appManifestLoader.Manifest; + if (manifest == null) + { + _steps = ESteps.Done; + Status = EOperationStatus.Failed; + Error = _appManifestLoader.Error; + } + else + { + _steps = ESteps.InitVerifyingCache; + _impl.SetLocalPatchManifest(manifest); + } } if (_steps == ESteps.InitVerifyingCache) @@ -348,27 +391,10 @@ namespace YooAsset { _steps = ESteps.Done; Status = EOperationStatus.Failed; - Error = $"The package resource {_packageName}_{_packageVersion} content has verify failed file !"; + Error = $"The package resource {_packageName} content has verify failed file !"; } } } } - - /// - /// 加载沙盒内的补丁清单 - /// 注意:在加载本地补丁清单之前,未验证过文件的哈希值 - /// - private void LoadSandboxPatchManifest(string packageName, string packageVersion) - { - string fileName = YooAssetSettingsData.GetPatchManifestFileName(packageName, packageVersion); - string filePath = PathHelper.MakePersistentLoadPath(fileName); - if (File.Exists(filePath)) - { - YooLogger.Log("Load sandbox patch manifest file."); - string jsonData = File.ReadAllText(filePath); - var sandboxPatchManifest = PatchManifest.Deserialize(jsonData); - _impl.SetLocalPatchManifest(sandboxPatchManifest); - } - } } } \ No newline at end of file diff --git a/Assets/YooAsset/Runtime/PatchSystem/Operations/UpdatePackageOperation.cs b/Assets/YooAsset/Runtime/PatchSystem/Operations/UpdatePackageOperation.cs index e697f51..c40e5e4 100644 --- a/Assets/YooAsset/Runtime/PatchSystem/Operations/UpdatePackageOperation.cs +++ b/Assets/YooAsset/Runtime/PatchSystem/Operations/UpdatePackageOperation.cs @@ -128,17 +128,18 @@ namespace YooAsset } else { - // 解析补丁清单 - if (ParseRemotePatchManifest(_downloader.GetText())) + // 解析补丁清单 + try { + _remotePatchManifest = PatchManifest.Deserialize(_downloader.GetText()); _steps = ESteps.Done; Status = EOperationStatus.Succeed; } - else + catch(System.Exception e) { _steps = ESteps.Done; Status = EOperationStatus.Failed; - Error = $"URL : {_downloader.URL} Error : remote patch manifest content is invalid"; + Error = e.Message; } } _downloader.Dispose(); @@ -176,23 +177,6 @@ namespace YooAsset return _impl.GetPatchDownloadMainURL(fileName); } - /// - /// 解析远端请求的补丁清单 - /// - private bool ParseRemotePatchManifest(string content) - { - try - { - _remotePatchManifest = PatchManifest.Deserialize(content); - return true; - } - catch (Exception e) - { - YooLogger.Warning(e.ToString()); - return false; - } - } - /// /// 获取下载列表 /// diff --git a/Assets/YooAsset/Runtime/PatchSystem/PatchBundle.cs b/Assets/YooAsset/Runtime/PatchSystem/PatchBundle.cs index 4ea56d2..1b16bdb 100644 --- a/Assets/YooAsset/Runtime/PatchSystem/PatchBundle.cs +++ b/Assets/YooAsset/Runtime/PatchSystem/PatchBundle.cs @@ -64,7 +64,7 @@ namespace YooAsset if (string.IsNullOrEmpty(_cachedFilePath) == false) return _cachedFilePath; - string cacheRoot = SandboxHelper.GetCacheFolderPath(); + string cacheRoot = PersistentHelper.GetCacheFolderPath(); _cachedFilePath = $"{cacheRoot}/{FileName}"; return _cachedFilePath; } diff --git a/Assets/YooAsset/Runtime/PatchSystem/PatchManifest.cs b/Assets/YooAsset/Runtime/PatchSystem/PatchManifest.cs index 3cad644..e57d2c1 100644 --- a/Assets/YooAsset/Runtime/PatchSystem/PatchManifest.cs +++ b/Assets/YooAsset/Runtime/PatchSystem/PatchManifest.cs @@ -247,6 +247,23 @@ namespace YooAsset return false; } + /// + /// 获取资源信息列表 + /// + public AssetInfo[] GetAssetsInfoByTags(string[] tags) + { + List result = new List(100); + foreach (var patchAsset in AssetList) + { + if (patchAsset.HasTag(tags)) + { + AssetInfo assetInfo = new AssetInfo(patchAsset); + result.Add(assetInfo); + } + } + return result.ToArray(); + } + /// /// 序列化 @@ -263,6 +280,8 @@ namespace YooAsset public static PatchManifest Deserialize(string jsonData) { PatchManifest patchManifest = JsonUtility.FromJson(jsonData); + if (patchManifest == null) + throw new System.Exception($"{nameof(PatchManifest)} deserialize object is null !"); // 检测文件版本 if (patchManifest.FileVersion != YooAssetSettings.PatchManifestFileVersion) diff --git a/Assets/YooAsset/Runtime/PatchSystem/PlayMode/EditorSimulateModeImpl.cs b/Assets/YooAsset/Runtime/PatchSystem/PlayMode/EditorSimulateModeImpl.cs index 9f7ece5..4a95323 100644 --- a/Assets/YooAsset/Runtime/PatchSystem/PlayMode/EditorSimulateModeImpl.cs +++ b/Assets/YooAsset/Runtime/PatchSystem/PlayMode/EditorSimulateModeImpl.cs @@ -53,7 +53,7 @@ namespace YooAsset } AssetInfo[] IBundleServices.GetAssetInfos(string[] tags) { - return PatchHelper.GetAssetsInfoByTags(_simulatePatchManifest, tags); + return _simulatePatchManifest.GetAssetsInfoByTags(tags); } PatchAsset IBundleServices.TryGetPatchAsset(string assetPath) { diff --git a/Assets/YooAsset/Runtime/PatchSystem/PlayMode/HostPlayModeImpl.cs b/Assets/YooAsset/Runtime/PatchSystem/PlayMode/HostPlayModeImpl.cs index b262acc..259be1e 100644 --- a/Assets/YooAsset/Runtime/PatchSystem/PlayMode/HostPlayModeImpl.cs +++ b/Assets/YooAsset/Runtime/PatchSystem/PlayMode/HostPlayModeImpl.cs @@ -64,9 +64,9 @@ namespace YooAsset /// /// 异步更新补丁清单(弱联网) /// - public UpdateManifestOperation WeaklyUpdatePatchManifestAsync(string packageName, string packageVersion) + public UpdateManifestOperation WeaklyUpdatePatchManifestAsync(string packageName) { - var operation = new HostPlayModeWeaklyUpdateManifestOperation(this, packageName, packageVersion); + var operation = new HostPlayModeWeaklyUpdateManifestOperation(this, packageName); OperationSystem.StartOperation(operation); return operation; } @@ -229,7 +229,7 @@ namespace YooAsset } } - return PatchHelper.ConvertToUnpackList(downloadList); + return ConvertToUnpackList(downloadList); } /// @@ -256,7 +256,7 @@ namespace YooAsset } } - return PatchHelper.ConvertToUnpackList(downloadList); + return ConvertToUnpackList(downloadList); } // WEB相关 @@ -280,7 +280,7 @@ namespace YooAsset } return result; } - public BundleInfo ConvertToDownloadInfo(PatchBundle patchBundle) + private BundleInfo ConvertToDownloadInfo(PatchBundle patchBundle) { string remoteMainURL = GetPatchDownloadMainURL(patchBundle.FileName); string remoteFallbackURL = GetPatchDownloadFallbackURL(patchBundle.FileName); @@ -288,6 +288,25 @@ namespace YooAsset return bundleInfo; } + // 解压相关 + public List ConvertToUnpackList(List unpackList) + { + List result = new List(unpackList.Count); + foreach (var patchBundle in unpackList) + { + var bundleInfo = ConvertToUnpackInfo(patchBundle); + result.Add(bundleInfo); + } + return result; + } + public static BundleInfo ConvertToUnpackInfo(PatchBundle patchBundle) + { + // 注意:我们把流加载路径指定为远端下载地址 + string streamingPath = PathHelper.ConvertToWWWPath(patchBundle.StreamingFilePath); + BundleInfo bundleInfo = new BundleInfo(patchBundle, BundleInfo.ELoadMode.LoadFromStreaming, streamingPath, streamingPath); + return bundleInfo; + } + internal List GetVerifyInfoList(bool weaklyUpdateMode) { List result = new List(LocalPatchManifest.BundleList.Count); @@ -379,7 +398,7 @@ namespace YooAsset } AssetInfo[] IBundleServices.GetAssetInfos(string[] tags) { - return PatchHelper.GetAssetsInfoByTags(LocalPatchManifest, tags); + return LocalPatchManifest.GetAssetsInfoByTags(tags); } PatchAsset IBundleServices.TryGetPatchAsset(string assetPath) { diff --git a/Assets/YooAsset/Runtime/PatchSystem/PlayMode/OfflinePlayModeImpl.cs b/Assets/YooAsset/Runtime/PatchSystem/PlayMode/OfflinePlayModeImpl.cs index b2ab409..5e77346 100644 --- a/Assets/YooAsset/Runtime/PatchSystem/PlayMode/OfflinePlayModeImpl.cs +++ b/Assets/YooAsset/Runtime/PatchSystem/PlayMode/OfflinePlayModeImpl.cs @@ -104,7 +104,7 @@ namespace YooAsset } AssetInfo[] IBundleServices.GetAssetInfos(string[] tags) { - return PatchHelper.GetAssetsInfoByTags(_appPatchManifest, tags); + return _appPatchManifest.GetAssetsInfoByTags(tags); } PatchAsset IBundleServices.TryGetPatchAsset(string assetPath) { diff --git a/Assets/YooAsset/Runtime/Settings/YooAssetSettingsData.cs b/Assets/YooAsset/Runtime/Settings/YooAssetSettingsData.cs index 0eaf861..5414dee 100644 --- a/Assets/YooAsset/Runtime/Settings/YooAssetSettingsData.cs +++ b/Assets/YooAsset/Runtime/Settings/YooAssetSettingsData.cs @@ -40,6 +40,14 @@ namespace YooAsset return $"{YooAssetSettings.ReportFileName}_{packageName}_{packageVersion}.json"; } + /// + /// 获取补丁清单文件不带版本号的名称 + /// + public static string GetPatchManifestFileNameWithoutVersion(string packageName) + { + return $"{Setting.PatchManifestFileName}_{packageName}.bytes"; + } + /// /// 获取补丁清单文件完整名称 /// diff --git a/Assets/YooAsset/Runtime/Utility/YooHelper.cs b/Assets/YooAsset/Runtime/Utility/YooHelper.cs index 1c0a454..6a3ccda 100644 --- a/Assets/YooAsset/Runtime/Utility/YooHelper.cs +++ b/Assets/YooAsset/Runtime/Utility/YooHelper.cs @@ -76,9 +76,9 @@ namespace YooAsset } /// - /// 沙盒帮助类 + /// 持久化目录帮助类 /// - internal static class SandboxHelper + internal static class PersistentHelper { private const string CacheFolderName = "CacheFiles"; @@ -109,49 +109,66 @@ namespace YooAsset { return PathHelper.MakePersistentLoadPath(CacheFolderName); } - } - /// - /// 补丁包帮助类 - /// - internal static class PatchHelper - { + #region 沙盒内清单相关 /// - /// 获取资源信息列表 + /// 获取沙盒内清单文件的路径 /// - public static AssetInfo[] GetAssetsInfoByTags(PatchManifest patchManifest, string[] tags) + public static string GetCacheManifestFilePath(string packageName) { - List result = new List(100); - foreach (var patchAsset in patchManifest.AssetList) - { - if(patchAsset.HasTag(tags)) - { - AssetInfo assetInfo = new AssetInfo(patchAsset); - result.Add(assetInfo); - } - } - return result.ToArray(); + string fileName = YooAssetSettingsData.GetPatchManifestFileNameWithoutVersion(packageName); + return PathHelper.MakePersistentLoadPath(fileName); } /// - /// 资源解压相关 + /// 加载沙盒内清单文件 /// - public static List ConvertToUnpackList(List unpackList) + public static PatchManifest LoadCacheManifestFile(string packageName) { - List result = new List(unpackList.Count); - foreach (var patchBundle in unpackList) + YooLogger.Log($"Load sandbox patch manifest file : {packageName}"); + string filePath = GetCacheManifestFilePath(packageName); + string jsonData = File.ReadAllText(filePath); + return PatchManifest.Deserialize(jsonData); + } + + /// + /// 存储沙盒内清单文件 + /// + public static PatchManifest SaveCacheManifestFile(string packageName, string fileContent) + { + YooLogger.Log($"Save sandbox patch manifest file : {packageName}"); + var manifest = PatchManifest.Deserialize(fileContent); + string savePath = GetCacheManifestFilePath(packageName); + FileUtility.CreateFile(savePath, fileContent); + return manifest; + } + + /// + /// 检测沙盒内清单文件是否存在 + /// + public static bool CheckCacheManifestFileExists(string packageName) + { + string filePath = GetCacheManifestFilePath(packageName); + return File.Exists(filePath); + } + + /// + /// 删除沙盒内清单文件 + /// + public static bool DeleteCacheManifestFile(string packageName) + { + string filePath = GetCacheManifestFilePath(packageName); + if (File.Exists(filePath)) { - var bundleInfo = ConvertToUnpackInfo(patchBundle); - result.Add(bundleInfo); + YooLogger.Warning($"Invalid cache manifest file have been removed : {filePath}"); + File.Delete(filePath); + return true; + } + else + { + return false; } - return result; - } - public static BundleInfo ConvertToUnpackInfo(PatchBundle patchBundle) - { - // 注意:我们把流加载路径指定为远端下载地址 - string streamingPath = PathHelper.ConvertToWWWPath(patchBundle.StreamingFilePath); - BundleInfo bundleInfo = new BundleInfo(patchBundle, BundleInfo.ELoadMode.LoadFromStreaming, streamingPath, streamingPath); - return bundleInfo; } + #endregion } } \ No newline at end of file diff --git a/Assets/YooAsset/Runtime/YooAssets.cs b/Assets/YooAsset/Runtime/YooAssets.cs index 56f5d65..88bb81d 100644 --- a/Assets/YooAsset/Runtime/YooAssets.cs +++ b/Assets/YooAsset/Runtime/YooAssets.cs @@ -224,7 +224,7 @@ namespace YooAsset /// public static void ClearSandbox() { - SandboxHelper.DeleteSandbox(); + PersistentHelper.DeleteSandbox(); } #endregion