diff --git a/Assets/YooAsset/Runtime/PatchSystem/Operations/DeserializeManifestOperation.cs b/Assets/YooAsset/Runtime/PatchSystem/Operations/DeserializeManifestOperation.cs new file mode 100644 index 0000000..6371d59 --- /dev/null +++ b/Assets/YooAsset/Runtime/PatchSystem/Operations/DeserializeManifestOperation.cs @@ -0,0 +1,162 @@ +using System.IO; +using System.Collections; +using System.Collections.Generic; + +namespace YooAsset +{ + internal class DeserializeManifestOperation : AsyncOperationBase + { + private enum ESteps + { + None, + DeserializeFileHeader, + PrepareAssetList, + DeserializeAssetList, + PrepareBundleList, + DeserializeBundleList, + Done, + } + + public PatchManifest Manifest { private set; get; } + private readonly BufferReader _buffer; + private ESteps _steps = ESteps.None; + private int _patchAssetCount; + private int _patchBundleCount; + private int _progressTotalValue; + + + public DeserializeManifestOperation(byte[] binaryData) + { + // 创建缓存器 + _buffer = new BufferReader(binaryData); + } + internal override void Start() + { + _steps = ESteps.DeserializeFileHeader; + } + internal override void Update() + { + if (_steps == ESteps.None || _steps == ESteps.Done) + return; + + try + { + if (_steps == ESteps.DeserializeFileHeader) + { + // 读取文件标记 + uint fileSign = _buffer.ReadUInt32(); + if (fileSign != YooAssetSettings.PatchManifestFileSign) + { + _steps = ESteps.Done; + Status = EOperationStatus.Failed; + Error = "Invalid manifest file format !"; + return; + } + + // 读取文件版本 + string fileVersion = _buffer.ReadUTF8(); + if (fileVersion != YooAssetSettings.PatchManifestFileVersion) + { + _steps = ESteps.Done; + Status = EOperationStatus.Failed; + Error = $"The manifest file version are not compatible : {fileVersion} != {YooAssetSettings.PatchManifestFileVersion}"; + return; + } + + // 读取文件头信息 + Manifest = new PatchManifest(); + Manifest.FileVersion = fileVersion; + Manifest.EnableAddressable = _buffer.ReadBool(); + Manifest.OutputNameStyle = _buffer.ReadInt32(); + Manifest.PackageName = _buffer.ReadUTF8(); + Manifest.PackageVersion = _buffer.ReadUTF8(); + + _steps = ESteps.PrepareAssetList; + } + + if (_steps == ESteps.PrepareAssetList) + { + _patchAssetCount = _buffer.ReadInt32(); + Manifest.AssetList = new List(_patchAssetCount); + Manifest.AssetDic = new Dictionary(_patchAssetCount); + _progressTotalValue = _patchAssetCount; + _steps = ESteps.DeserializeAssetList; + } + if (_steps == ESteps.DeserializeAssetList) + { + while (_patchAssetCount > 0) + { + var patchAsset = new PatchAsset(); + patchAsset.Address = _buffer.ReadUTF8(); + patchAsset.AssetPath = _buffer.ReadUTF8(); + patchAsset.AssetTags = _buffer.ReadUTF8Array(); + patchAsset.BundleID = _buffer.ReadInt32(); + patchAsset.DependIDs = _buffer.ReadInt32Array(); + Manifest.AssetList.Add(patchAsset); + + // 注意:我们不允许原始路径存在重名 + string assetPath = patchAsset.AssetPath; + if (Manifest.AssetDic.ContainsKey(assetPath)) + throw new System.Exception($"AssetPath have existed : {assetPath}"); + else + Manifest.AssetDic.Add(assetPath, patchAsset); + + _patchAssetCount--; + Progress = _patchAssetCount / _progressTotalValue; + if (OperationSystem.IsBusy) + break; + } + + if (_patchAssetCount <= 0) + { + _steps = ESteps.PrepareBundleList; + } + } + + if (_steps == ESteps.PrepareBundleList) + { + _patchBundleCount = _buffer.ReadInt32(); + Manifest.BundleList = new List(_patchBundleCount); + Manifest.BundleDic = new Dictionary(_patchBundleCount); + _progressTotalValue = _patchBundleCount; + _steps = ESteps.DeserializeBundleList; + } + if (_steps == ESteps.DeserializeBundleList) + { + while (_patchBundleCount > 0) + { + var patchBundle = new PatchBundle(); + patchBundle.BundleName = _buffer.ReadUTF8(); + patchBundle.FileHash = _buffer.ReadUTF8(); + patchBundle.FileCRC = _buffer.ReadUTF8(); + patchBundle.FileSize = _buffer.ReadInt64(); + patchBundle.IsRawFile = _buffer.ReadBool(); + patchBundle.LoadMethod = _buffer.ReadByte(); + patchBundle.Tags = _buffer.ReadUTF8Array(); + Manifest.BundleList.Add(patchBundle); + + patchBundle.ParseBundle(Manifest.PackageName, Manifest.OutputNameStyle); + Manifest.BundleDic.Add(patchBundle.BundleName, patchBundle); + + _patchBundleCount--; + Progress = _patchBundleCount / _progressTotalValue; + if (OperationSystem.IsBusy) + break; + } + + if (_patchBundleCount <= 0) + { + _steps = ESteps.Done; + Status = EOperationStatus.Succeed; + } + } + } + catch(System.Exception e) + { + _steps = ESteps.Done; + Status = EOperationStatus.Failed; + Error = e.Message; + } + } + } +} \ No newline at end of file diff --git a/Assets/YooAsset/Runtime/PatchSystem/Operations/DeserializeManifestOperation.cs.meta b/Assets/YooAsset/Runtime/PatchSystem/Operations/DeserializeManifestOperation.cs.meta new file mode 100644 index 0000000..7888210 --- /dev/null +++ b/Assets/YooAsset/Runtime/PatchSystem/Operations/DeserializeManifestOperation.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a800be1f31ec6364f8cdd0d8c7eef269 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/YooAsset/Runtime/PatchSystem/Operations/DownloadPackageOperation.cs b/Assets/YooAsset/Runtime/PatchSystem/Operations/DownloadPackageOperation.cs index 5cfe82b..ba9f49d 100644 --- a/Assets/YooAsset/Runtime/PatchSystem/Operations/DownloadPackageOperation.cs +++ b/Assets/YooAsset/Runtime/PatchSystem/Operations/DownloadPackageOperation.cs @@ -73,7 +73,8 @@ namespace YooAsset { None, LoadWebManifest, - CheckWebManifest, + CheckLoadWebManifest, + CheckDeserializeManifest, Done, } @@ -84,6 +85,7 @@ namespace YooAsset private readonly int _timeout; private ESteps _steps = ESteps.None; private UnityWebDataRequester _downloader; + private DeserializeManifestOperation _deserializer; private PatchManifest _remotePatchManifest; internal HostPlayModeDownloadPackageOperation(HostPlayModeImpl impl, string packageName, string packageVersion, int timeout) @@ -95,7 +97,7 @@ namespace YooAsset } internal override void Start() { - RequestCount++; + RequestCount++; _steps = ESteps.LoadWebManifest; } internal override void Update() @@ -110,10 +112,10 @@ namespace YooAsset YooLogger.Log($"Beginning to request patch manifest : {webURL}"); _downloader = new UnityWebDataRequester(); _downloader.SendRequest(webURL, _timeout); - _steps = ESteps.CheckWebManifest; + _steps = ESteps.CheckLoadWebManifest; } - if (_steps == ESteps.CheckWebManifest) + if (_steps == ESteps.CheckLoadWebManifest) { Progress = _downloader.Progress(); if (_downloader.IsDone() == false) @@ -129,21 +131,32 @@ namespace YooAsset else { // 解析补丁清单 - try + byte[] bytesData = _downloader.GetData(); + _deserializer = new DeserializeManifestOperation(bytesData); + OperationSystem.StartOperation(_deserializer); + _steps = ESteps.CheckDeserializeManifest; + } + _downloader.Dispose(); + } + + if (_steps == ESteps.CheckDeserializeManifest) + { + Progress = _deserializer.Progress; + if (_deserializer.IsDone) + { + if (_deserializer.Status == EOperationStatus.Succeed) { - byte[] bytesData = _downloader.GetData(); - _remotePatchManifest = PatchManifest.DeserializeFromBinary(bytesData); + _remotePatchManifest = _deserializer.Manifest; _steps = ESteps.Done; Status = EOperationStatus.Succeed; } - catch(System.Exception e) + else { _steps = ESteps.Done; Status = EOperationStatus.Failed; - Error = e.Message; + Error = _deserializer.Error; } } - _downloader.Dispose(); } } diff --git a/Assets/YooAsset/Runtime/PatchSystem/Operations/InitializationOperation.cs b/Assets/YooAsset/Runtime/PatchSystem/Operations/InitializationOperation.cs index 31c878e..e461712 100644 --- a/Assets/YooAsset/Runtime/PatchSystem/Operations/InitializationOperation.cs +++ b/Assets/YooAsset/Runtime/PatchSystem/Operations/InitializationOperation.cs @@ -24,12 +24,14 @@ namespace YooAsset private enum ESteps { None, - Load, + LoadManifestFileData, + CheckDeserializeManifest, Done, } private readonly EditorSimulateModeImpl _impl; private readonly string _simulatePatchManifestPath; + private DeserializeManifestOperation _deserializer; private ESteps _steps = ESteps.None; internal EditorSimulateModeInitializationOperation(EditorSimulateModeImpl impl, string simulatePatchManifestPath) @@ -39,11 +41,11 @@ namespace YooAsset } internal override void Start() { - _steps = ESteps.Load; + _steps = ESteps.LoadManifestFileData; } internal override void Update() { - if (_steps == ESteps.Load) + if (_steps == ESteps.LoadManifestFileData) { if (File.Exists(_simulatePatchManifestPath) == false) { @@ -53,21 +55,31 @@ namespace YooAsset return; } - try + YooLogger.Log($"Load simulation manifest file : {_simulatePatchManifestPath}"); + byte[] bytesData = FileUtility.ReadAllBytes(_simulatePatchManifestPath); + _deserializer = new DeserializeManifestOperation(bytesData); + OperationSystem.StartOperation(_deserializer); + _steps = ESteps.CheckDeserializeManifest; + } + + if (_steps == ESteps.CheckDeserializeManifest) + { + if (_deserializer.IsDone) { - YooLogger.Log($"Load simulation manifest file : {_simulatePatchManifestPath}"); - byte[] bytesData = FileUtility.ReadAllBytes(_simulatePatchManifestPath); - var manifest = PatchManifest.DeserializeFromBinary(bytesData); - InitializedPackageVersion = manifest.PackageVersion; - _impl.SetSimulatePatchManifest(manifest); - _steps = ESteps.Done; - Status = EOperationStatus.Succeed; - } - catch (System.Exception e) - { - _steps = ESteps.Done; - Status = EOperationStatus.Failed; - Error = e.Message; + if (_deserializer.Status == EOperationStatus.Succeed) + { + var manifest = _deserializer.Manifest; + InitializedPackageVersion = manifest.PackageVersion; + _impl.SetSimulatePatchManifest(manifest); + _steps = ESteps.Done; + Status = EOperationStatus.Succeed; + } + else + { + _steps = ESteps.Done; + Status = EOperationStatus.Failed; + Error = _deserializer.Error; + } } } } @@ -81,8 +93,8 @@ namespace YooAsset private enum ESteps { None, - QueryAppPackageVersion, - LoadAppManifest, + QueryBuildinPackageVersion, + LoadBuildinManifest, StartVerifyOperation, CheckVerifyOperation, Done, @@ -90,8 +102,8 @@ namespace YooAsset private readonly OfflinePlayModeImpl _impl; private readonly string _packageName; - private readonly AppPackageVersionQuerier _appPackageVersionQuerier; - private AppManifestLoader _appManifestLoader; + private readonly BuildinPackageVersionQuerier _buildinPackageVersionQuerier; + private BuildinManifestLoader _buildinManifestLoader; private CacheFilesVerifyOperation _verifyOperation; private ESteps _steps = ESteps.None; private float _verifyTime; @@ -100,24 +112,24 @@ namespace YooAsset { _impl = impl; _packageName = packageName; - _appPackageVersionQuerier = new AppPackageVersionQuerier(packageName); + _buildinPackageVersionQuerier = new BuildinPackageVersionQuerier(packageName); } internal override void Start() { - _steps = ESteps.QueryAppPackageVersion; + _steps = ESteps.QueryBuildinPackageVersion; } internal override void Update() { if (_steps == ESteps.None || _steps == ESteps.Done) return; - if (_steps == ESteps.QueryAppPackageVersion) + if (_steps == ESteps.QueryBuildinPackageVersion) { - _appPackageVersionQuerier.Update(); - if (_appPackageVersionQuerier.IsDone == false) + _buildinPackageVersionQuerier.Update(); + if (_buildinPackageVersionQuerier.IsDone == false) return; - string error = _appPackageVersionQuerier.Error; + string error = _buildinPackageVersionQuerier.Error; if (string.IsNullOrEmpty(error) == false) { _steps = ESteps.Done; @@ -126,24 +138,24 @@ namespace YooAsset } else { - _appManifestLoader = new AppManifestLoader(_packageName, _appPackageVersionQuerier.Version); - _steps = ESteps.LoadAppManifest; + _buildinManifestLoader = new BuildinManifestLoader(_packageName, _buildinPackageVersionQuerier.Version); + _steps = ESteps.LoadBuildinManifest; } } - if (_steps == ESteps.LoadAppManifest) + if (_steps == ESteps.LoadBuildinManifest) { - _appManifestLoader.Update(); - Progress = _appManifestLoader.Progress; - if (_appManifestLoader.IsDone == false) + _buildinManifestLoader.Update(); + Progress = _buildinManifestLoader.Progress; + if (_buildinManifestLoader.IsDone == false) return; - var manifest = _appManifestLoader.Manifest; + var manifest = _buildinManifestLoader.Manifest; if (manifest == null) { _steps = ESteps.Done; Status = EOperationStatus.Failed; - Error = _appManifestLoader.Error; + Error = _buildinManifestLoader.Error; } else { @@ -191,9 +203,9 @@ namespace YooAsset None, CheckAppFootPrint, TryLoadCacheManifest, - QueryAppPackageVersion, - CopyAppManifest, - LoadAppManifest, + QueryBuildinPackageVersion, + CopyBuildinManifest, + LoadBuildinManifest, StartVerifyOperation, CheckVerifyOperation, Done, @@ -201,9 +213,10 @@ namespace YooAsset private readonly HostPlayModeImpl _impl; private readonly string _packageName; - private readonly AppPackageVersionQuerier _appPackageVersionQuerier; - private AppManifestCopyer _appManifestCopyer; - private AppManifestLoader _appManifestLoader; + private readonly BuildinPackageVersionQuerier _buildinPackageVersionQuerier; + private BuildinManifestCopyer _buildinManifestCopyer; + private BuildinManifestLoader _buildinManifestLoader; + private CacheManifestLoader _cacheManifestLoader; private CacheFilesVerifyOperation _verifyOperation; private ESteps _steps = ESteps.None; private float _verifyTime; @@ -212,7 +225,7 @@ namespace YooAsset { _impl = impl; _packageName = packageName; - _appPackageVersionQuerier = new AppPackageVersionQuerier(packageName); + _buildinPackageVersionQuerier = new BuildinPackageVersionQuerier(packageName); } internal override void Start() { @@ -240,37 +253,34 @@ namespace YooAsset if (_steps == ESteps.TryLoadCacheManifest) { - if (PersistentHelper.CheckCacheManifestFileExists(_packageName)) + if (_cacheManifestLoader == null) + _cacheManifestLoader = new CacheManifestLoader(_packageName); + + _cacheManifestLoader.Update(); + if (_cacheManifestLoader.IsDone) { - try + var manifest = _cacheManifestLoader.Manifest; + if (manifest != null) { - var manifest = PersistentHelper.LoadCacheManifestFile(_packageName); InitializedPackageVersion = manifest.PackageVersion; _impl.SetLocalPatchManifest(manifest); _steps = ESteps.StartVerifyOperation; } - catch (System.Exception e) + else { - // 注意:如果加载沙盒内的清单报错,为了避免流程被卡住,我们主动把损坏的文件删除。 - YooLogger.Warning($"Failed to load cache manifest file : {e.Message}"); - PersistentHelper.DeleteCacheManifestFile(_packageName); - _steps = ESteps.QueryAppPackageVersion; + _steps = ESteps.QueryBuildinPackageVersion; } } - else - { - _steps = ESteps.QueryAppPackageVersion; - } } - if (_steps == ESteps.QueryAppPackageVersion) + if (_steps == ESteps.QueryBuildinPackageVersion) { - _appPackageVersionQuerier.Update(); - if (_appPackageVersionQuerier.IsDone == false) + _buildinPackageVersionQuerier.Update(); + if (_buildinPackageVersionQuerier.IsDone == false) return; // 注意:为了兼容MOD模式,初始化动态新增的包裹的时候,如果内置清单不存在也不需要报错! - string error = _appPackageVersionQuerier.Error; + string error = _buildinPackageVersionQuerier.Error; if (string.IsNullOrEmpty(error) == false) { _steps = ESteps.Done; @@ -279,20 +289,20 @@ namespace YooAsset } else { - _appManifestCopyer = new AppManifestCopyer(_packageName, _appPackageVersionQuerier.Version); - _appManifestLoader = new AppManifestLoader(_packageName, _appPackageVersionQuerier.Version); - _steps = ESteps.CopyAppManifest; + _buildinManifestCopyer = new BuildinManifestCopyer(_packageName, _buildinPackageVersionQuerier.Version); + _buildinManifestLoader = new BuildinManifestLoader(_packageName, _buildinPackageVersionQuerier.Version); + _steps = ESteps.CopyBuildinManifest; } } - if (_steps == ESteps.CopyAppManifest) + if (_steps == ESteps.CopyBuildinManifest) { - _appManifestCopyer.Update(); - Progress = _appManifestCopyer.Progress; - if (_appManifestCopyer.IsDone == false) + _buildinManifestCopyer.Update(); + Progress = _buildinManifestCopyer.Progress; + if (_buildinManifestCopyer.IsDone == false) return; - string error = _appManifestCopyer.Error; + string error = _buildinManifestCopyer.Error; if (string.IsNullOrEmpty(error) == false) { _steps = ESteps.Done; @@ -301,23 +311,23 @@ namespace YooAsset } else { - _steps = ESteps.LoadAppManifest; + _steps = ESteps.LoadBuildinManifest; } } - if (_steps == ESteps.LoadAppManifest) + if (_steps == ESteps.LoadBuildinManifest) { - _appManifestLoader.Update(); - Progress = _appManifestLoader.Progress; - if (_appManifestLoader.IsDone == false) + _buildinManifestLoader.Update(); + Progress = _buildinManifestLoader.Progress; + if (_buildinManifestLoader.IsDone == false) return; - var manifest = _appManifestLoader.Manifest; + var manifest = _buildinManifestLoader.Manifest; if (manifest == null) { _steps = ESteps.Done; Status = EOperationStatus.Failed; - Error = _appManifestLoader.Error; + Error = _buildinManifestLoader.Error; } else { @@ -409,7 +419,7 @@ namespace YooAsset /// /// 内置补丁清单版本查询器 /// - internal class AppPackageVersionQuerier + internal class BuildinPackageVersionQuerier { private enum ESteps { @@ -444,7 +454,7 @@ namespace YooAsset } - public AppPackageVersionQuerier(string buildinPackageName) + public BuildinPackageVersionQuerier(string buildinPackageName) { _buildinPackageName = buildinPackageName; } @@ -491,25 +501,32 @@ namespace YooAsset /// /// 内置补丁清单加载器 /// - internal class AppManifestLoader + internal class BuildinManifestLoader { private enum ESteps { - LoadAppManifest, - CheckAppManifest, + LoadBuildinManifest, + CheckLoadBuildinManifest, + CheckDeserializeManifest, Done, } private readonly string _buildinPackageName; private readonly string _buildinPackageVersion; - private ESteps _steps = ESteps.LoadAppManifest; + private ESteps _steps = ESteps.LoadBuildinManifest; private UnityWebDataRequester _downloader; + private DeserializeManifestOperation _deserializer; /// /// 加载结果 /// public PatchManifest Manifest { private set; get; } + /// + /// 加载进度 + /// + public float Progress { private set; get; } + /// /// 错误日志 /// @@ -526,21 +543,8 @@ namespace YooAsset } } - /// - /// 加载进度 - /// - public float Progress - { - get - { - if (_downloader == null) - return 0; - return _downloader.Progress(); - } - } - - public AppManifestLoader(string buildinPackageName, string buildinPackageVersion) + public BuildinManifestLoader(string buildinPackageName, string buildinPackageVersion) { _buildinPackageName = buildinPackageName; _buildinPackageVersion = buildinPackageVersion; @@ -554,17 +558,17 @@ namespace YooAsset if (IsDone) return; - if (_steps == ESteps.LoadAppManifest) + if (_steps == ESteps.LoadBuildinManifest) { string fileName = YooAssetSettingsData.GetPatchManifestBinaryFileName(_buildinPackageName, _buildinPackageVersion); string filePath = PathHelper.MakeStreamingLoadPath(fileName); string url = PathHelper.ConvertToWWWPath(filePath); _downloader = new UnityWebDataRequester(); _downloader.SendRequest(url); - _steps = ESteps.CheckAppManifest; + _steps = ESteps.CheckLoadBuildinManifest; } - if (_steps == ESteps.CheckAppManifest) + if (_steps == ESteps.CheckLoadBuildinManifest) { if (_downloader.IsDone() == false) return; @@ -572,41 +576,53 @@ namespace YooAsset if (_downloader.HasError()) { Error = _downloader.GetError(); + _steps = ESteps.Done; } else { // 解析APP里的补丁清单 - try - { - byte[] bytesData = _downloader.GetData(); - Manifest = PatchManifest.DeserializeFromBinary(bytesData); - } - catch (System.Exception e) - { - Error = e.Message; - } + byte[] bytesData = _downloader.GetData(); + _deserializer = new DeserializeManifestOperation(bytesData); + OperationSystem.StartOperation(_deserializer); + _steps = ESteps.CheckDeserializeManifest; } - _steps = ESteps.Done; _downloader.Dispose(); } + + if (_steps == ESteps.CheckDeserializeManifest) + { + Progress = _deserializer.Progress; + if (_deserializer.IsDone) + { + if (_deserializer.Status == EOperationStatus.Succeed) + { + Manifest = _deserializer.Manifest; + } + else + { + Error = _deserializer.Error; + } + _steps = ESteps.Done; + } + } } } /// /// 内置补丁清单复制器 /// - internal class AppManifestCopyer + internal class BuildinManifestCopyer { private enum ESteps { - CopyAppManifest, - CheckAppManifest, + CopyBuildinManifest, + CheckCopyBuildinManifest, Done, } private readonly string _buildinPackageName; private readonly string _buildinPackageVersion; - private ESteps _steps = ESteps.CopyAppManifest; + private ESteps _steps = ESteps.CopyBuildinManifest; private UnityWebFileRequester _downloader; /// @@ -639,7 +655,7 @@ namespace YooAsset } - public AppManifestCopyer(string buildinPackageName, string buildinPackageVersion) + public BuildinManifestCopyer(string buildinPackageName, string buildinPackageVersion) { _buildinPackageName = buildinPackageName; _buildinPackageVersion = buildinPackageVersion; @@ -653,7 +669,7 @@ namespace YooAsset if (IsDone) return; - if (_steps == ESteps.CopyAppManifest) + if (_steps == ESteps.CopyBuildinManifest) { string savePath = PersistentHelper.GetCacheManifestFilePath(_buildinPackageName); string fileName = YooAssetSettingsData.GetPatchManifestBinaryFileName(_buildinPackageName, _buildinPackageVersion); @@ -661,10 +677,10 @@ namespace YooAsset string url = PathHelper.ConvertToWWWPath(filePath); _downloader = new UnityWebFileRequester(); _downloader.SendRequest(url, savePath); - _steps = ESteps.CheckAppManifest; + _steps = ESteps.CheckCopyBuildinManifest; } - if (_steps == ESteps.CheckAppManifest) + if (_steps == ESteps.CheckCopyBuildinManifest) { if (_downloader.IsDone() == false) return; @@ -678,4 +694,104 @@ namespace YooAsset } } } + + /// + /// 沙盒补丁清单加载器 + /// + internal class CacheManifestLoader + { + private enum ESteps + { + LoadCacheManifestFile, + CheckDeserializeManifest, + Done, + } + + private readonly string _packageName; + private ESteps _steps = ESteps.LoadCacheManifestFile; + private DeserializeManifestOperation _deserializer; + private string _manifestFilePath; + + /// + /// 加载结果 + /// + public PatchManifest Manifest { private set; get; } + + /// + /// 加载进度 + /// + public float Progress { private set; get; } + + /// + /// 错误日志 + /// + public string Error { private set; get; } + + /// + /// 是否已经完成 + /// + public bool IsDone + { + get + { + return _steps == ESteps.Done; + } + } + + + public CacheManifestLoader(string packageName) + { + _packageName = packageName; + } + + /// + /// 更新流程 + /// + public void Update() + { + if (IsDone) + return; + + if (_steps == ESteps.LoadCacheManifestFile) + { + _manifestFilePath = PersistentHelper.GetCacheManifestFilePath(_packageName); + if (File.Exists(_manifestFilePath) == false) + { + _steps = ESteps.Done; + Error = $"Manifest file not found : {_manifestFilePath}"; + return; + } + + byte[] bytesData = File.ReadAllBytes(_manifestFilePath); + _deserializer = new DeserializeManifestOperation(bytesData); + OperationSystem.StartOperation(_deserializer); + _steps = ESteps.CheckDeserializeManifest; + } + + if (_steps == ESteps.CheckDeserializeManifest) + { + Progress = _deserializer.Progress; + if (_deserializer.IsDone) + { + if (_deserializer.Status == EOperationStatus.Succeed) + { + Manifest = _deserializer.Manifest; + } + else + { + Error = _deserializer.Error; + + // 注意:如果加载沙盒内的清单报错,为了避免流程被卡住,我们主动把损坏的文件删除。 + if (File.Exists(_manifestFilePath)) + { + YooLogger.Warning($"Failed to load cache manifest file : {Error}"); + YooLogger.Warning($"Invalid cache manifest file have been removed : {_manifestFilePath}"); + File.Delete(_manifestFilePath); + } + } + _steps = ESteps.Done; + } + } + } + } } \ No newline at end of file diff --git a/Assets/YooAsset/Runtime/PatchSystem/Operations/UpdatePackageManifestOperation.cs b/Assets/YooAsset/Runtime/PatchSystem/Operations/UpdatePackageManifestOperation.cs index 48bb7c1..bf30b4f 100644 --- a/Assets/YooAsset/Runtime/PatchSystem/Operations/UpdatePackageManifestOperation.cs +++ b/Assets/YooAsset/Runtime/PatchSystem/Operations/UpdatePackageManifestOperation.cs @@ -54,11 +54,11 @@ namespace YooAsset { None, TryLoadCacheHash, - LoadWebHash, - CheckWebHash, - LoadCacheManifest, - LoadWebManifest, - CheckWebManifest, + DownloadWebHash, + CheckDownloadWebHash, + DownloadWebManifest, + CheckDownloadWebManifest, + CheckDeserializeWebManifest, StartVerifyOperation, CheckVerifyOperation, Done, @@ -71,6 +71,7 @@ namespace YooAsset private readonly int _timeout; private UnityWebDataRequester _downloader1; private UnityWebDataRequester _downloader2; + private DeserializeManifestOperation _deserializer; private CacheFilesVerifyOperation _verifyOperation; private string _cacheManifestHash; @@ -100,25 +101,25 @@ namespace YooAsset if (File.Exists(filePath)) { _cacheManifestHash = HashUtility.FileMD5(filePath); - _steps = ESteps.LoadWebHash; + _steps = ESteps.DownloadWebHash; } else { - _steps = ESteps.LoadWebManifest; + _steps = ESteps.DownloadWebManifest; } } - if (_steps == ESteps.LoadWebHash) + if (_steps == ESteps.DownloadWebHash) { string fileName = YooAssetSettingsData.GetPatchManifestHashFileName(_packageName, _packageVersion); string webURL = GetPatchManifestRequestURL(fileName); YooLogger.Log($"Beginning to request patch manifest hash : {webURL}"); _downloader1 = new UnityWebDataRequester(); _downloader1.SendRequest(webURL, _timeout); - _steps = ESteps.CheckWebHash; + _steps = ESteps.CheckDownloadWebHash; } - if (_steps == ESteps.CheckWebHash) + if (_steps == ESteps.CheckDownloadWebHash) { if (_downloader1.IsDone() == false) return; @@ -135,45 +136,29 @@ namespace YooAsset if (_cacheManifestHash == webManifestHash) { YooLogger.Log($"Not found new package : {_packageName}"); - _steps = ESteps.LoadCacheManifest; + _steps = ESteps.Done; + Status = EOperationStatus.Succeed; } else { YooLogger.Log($"Package {_packageName} is change : {_cacheManifestHash} -> {webManifestHash}"); - _steps = ESteps.LoadWebManifest; + _steps = ESteps.DownloadWebManifest; } } _downloader1.Dispose(); } - if (_steps == ESteps.LoadCacheManifest) - { - try - { - var manifest = PersistentHelper.LoadCacheManifestFile(_packageName); - _impl.SetLocalPatchManifest(manifest); - _steps = ESteps.StartVerifyOperation; - } - catch (System.Exception e) - { - // 注意:如果加载沙盒内的清单报错,为了避免流程被卡住,我们主动把损坏的文件删除。 - YooLogger.Warning($"Failed to load cache manifest file : {e.Message}"); - PersistentHelper.DeleteCacheManifestFile(_packageName); - _steps = ESteps.LoadWebManifest; - } - } - - if (_steps == ESteps.LoadWebManifest) + if (_steps == ESteps.DownloadWebManifest) { string fileName = YooAssetSettingsData.GetPatchManifestBinaryFileName(_packageName, _packageVersion); string webURL = GetPatchManifestRequestURL(fileName); YooLogger.Log($"Beginning to request patch manifest : {webURL}"); _downloader2 = new UnityWebDataRequester(); _downloader2.SendRequest(webURL, _timeout); - _steps = ESteps.CheckWebManifest; + _steps = ESteps.CheckDownloadWebManifest; } - if (_steps == ESteps.CheckWebManifest) + if (_steps == ESteps.CheckDownloadWebManifest) { if (_downloader2.IsDone() == false) return; @@ -186,22 +171,37 @@ namespace YooAsset } else { - try + // 保存文件到沙盒内 + byte[] bytesData = _downloader2.GetData(); + string savePath = PersistentHelper.GetCacheManifestFilePath(_packageName); + FileUtility.CreateFile(savePath, bytesData); + + // 解析二进制数据 + _deserializer = new DeserializeManifestOperation(bytesData); + OperationSystem.StartOperation(_deserializer); + _steps = ESteps.CheckDeserializeWebManifest; + } + _downloader2.Dispose(); + } + + if (_steps == ESteps.CheckDeserializeWebManifest) + { + Progress = _deserializer.Progress; + if (_deserializer.IsDone) + { + if (_deserializer.Status == EOperationStatus.Succeed) { - byte[] bytesData = _downloader2.GetData(); - var manifest = PersistentHelper.SaveCacheManifestFile(_packageName, bytesData); - _impl.SetLocalPatchManifest(manifest); + _impl.SetLocalPatchManifest(_deserializer.Manifest); FoundNewManifest = true; _steps = ESteps.StartVerifyOperation; } - catch (Exception e) + else { - _steps = ESteps.Done; Status = EOperationStatus.Failed; - Error = e.Message; + Error = _deserializer.Error; + _steps = ESteps.Done; } } - _downloader2.Dispose(); } if (_steps == ESteps.StartVerifyOperation) diff --git a/Assets/YooAsset/Runtime/PatchSystem/PatchManifest.cs b/Assets/YooAsset/Runtime/PatchSystem/PatchManifest.cs index 1ed8d57..1e30739 100644 --- a/Assets/YooAsset/Runtime/PatchSystem/PatchManifest.cs +++ b/Assets/YooAsset/Runtime/PatchSystem/PatchManifest.cs @@ -267,149 +267,6 @@ namespace YooAsset } - /// - /// 序列化(JSON文件) - /// - public static void SerializeToJson(string savePath, PatchManifest manifest) - { - string json = JsonUtility.ToJson(manifest, true); - FileUtility.CreateFile(savePath, json); - } - - /// - /// 序列化(二进制文件) - /// - public static void SerializeToBinary(string savePath, PatchManifest patchManifest) - { - using (FileStream fs = new FileStream(savePath, FileMode.Create)) - { - // 创建缓存器 - BufferWriter buffer = new BufferWriter(YooAssetSettings.PatchManifestFileMaxSize); - - // 写入文件标记 - buffer.WriteUInt32(YooAssetSettings.PatchManifestFileSign); - - // 写入文件版本 - buffer.WriteUTF8(patchManifest.FileVersion); - - // 写入文件头信息 - buffer.WriteBool(patchManifest.EnableAddressable); - buffer.WriteInt32(patchManifest.OutputNameStyle); - buffer.WriteUTF8(patchManifest.PackageName); - buffer.WriteUTF8(patchManifest.PackageVersion); - - // 写入资源列表 - buffer.WriteInt32(patchManifest.AssetList.Count); - for (int i = 0; i < patchManifest.AssetList.Count; i++) - { - var patchAsset = patchManifest.AssetList[i]; - buffer.WriteUTF8(patchAsset.Address); - buffer.WriteUTF8(patchAsset.AssetPath); - buffer.WriteUTF8Array(patchAsset.AssetTags); - buffer.WriteInt32(patchAsset.BundleID); - buffer.WriteInt32Array(patchAsset.DependIDs); - } - - // 写入资源包列表 - buffer.WriteInt32(patchManifest.BundleList.Count); - for (int i = 0; i < patchManifest.BundleList.Count; i++) - { - var patchBundle = patchManifest.BundleList[i]; - buffer.WriteUTF8(patchBundle.BundleName); - buffer.WriteUTF8(patchBundle.FileHash); - buffer.WriteUTF8(patchBundle.FileCRC); - buffer.WriteInt64(patchBundle.FileSize); - buffer.WriteBool(patchBundle.IsRawFile); - buffer.WriteByte(patchBundle.LoadMethod); - buffer.WriteUTF8Array(patchBundle.Tags); - } - - // 写入文件流 - buffer.WriteToStream(fs); - fs.Flush(); - } - } - - /// - /// 反序列化(二进制文件) - /// - public static PatchManifest DeserializeFromBinary(byte[] binaryData) - { - // 创建缓存器 - BufferReader buffer = new BufferReader(binaryData); - - // 读取文件标记 - uint fileSign = buffer.ReadUInt32(); - if (fileSign != YooAssetSettings.PatchManifestFileSign) - throw new Exception("Invalid manifest file !"); - - PatchManifest manifest = new PatchManifest(); - { - // 读取文件版本 - manifest.FileVersion = buffer.ReadUTF8(); - if (manifest.FileVersion != YooAssetSettings.PatchManifestFileVersion) - throw new Exception($"The manifest file version are not compatible : {manifest.FileVersion} != {YooAssetSettings.PatchManifestFileVersion}"); - - // 读取文件头信息 - manifest.EnableAddressable = buffer.ReadBool(); - manifest.OutputNameStyle = buffer.ReadInt32(); - manifest.PackageName = buffer.ReadUTF8(); - manifest.PackageVersion = buffer.ReadUTF8(); - - // 读取资源列表 - int patchAssetCount = buffer.ReadInt32(); - manifest.AssetList = new List(patchAssetCount); - for (int i = 0; i < patchAssetCount; i++) - { - var patchAsset = new PatchAsset(); - patchAsset.Address = buffer.ReadUTF8(); - patchAsset.AssetPath = buffer.ReadUTF8(); - patchAsset.AssetTags = buffer.ReadUTF8Array(); - patchAsset.BundleID = buffer.ReadInt32(); - patchAsset.DependIDs = buffer.ReadInt32Array(); - manifest.AssetList.Add(patchAsset); - } - - // 读取资源包列表 - int patchBundleCount = buffer.ReadInt32(); - manifest.BundleList = new List(patchBundleCount); - for (int i = 0; i < patchBundleCount; i++) - { - var patchBundle = new PatchBundle(); - patchBundle.BundleName = buffer.ReadUTF8(); - patchBundle.FileHash = buffer.ReadUTF8(); - patchBundle.FileCRC = buffer.ReadUTF8(); - patchBundle.FileSize = buffer.ReadInt64(); - patchBundle.IsRawFile = buffer.ReadBool(); - patchBundle.LoadMethod = buffer.ReadByte(); - patchBundle.Tags = buffer.ReadUTF8Array(); - manifest.BundleList.Add(patchBundle); - } - } - - // BundleDic - manifest.BundleDic = new Dictionary(manifest.BundleList.Count); - foreach (var patchBundle in manifest.BundleList) - { - patchBundle.ParseBundle(manifest.PackageName, manifest.OutputNameStyle); - manifest.BundleDic.Add(patchBundle.BundleName, patchBundle); - } - - // AssetDic - manifest.AssetDic = new Dictionary(manifest.AssetList.Count); - foreach (var patchAsset in manifest.AssetList) - { - // 注意:我们不允许原始路径存在重名 - string assetPath = patchAsset.AssetPath; - if (manifest.AssetDic.ContainsKey(assetPath)) - throw new Exception($"AssetPath have existed : {assetPath}"); - else - manifest.AssetDic.Add(assetPath, patchAsset); - } - - return manifest; - } - /// /// 生成Bundle文件的正式名称 /// diff --git a/Assets/YooAsset/Runtime/PatchSystem/PatchManifestTools.cs b/Assets/YooAsset/Runtime/PatchSystem/PatchManifestTools.cs new file mode 100644 index 0000000..45fbd51 --- /dev/null +++ b/Assets/YooAsset/Runtime/PatchSystem/PatchManifestTools.cs @@ -0,0 +1,155 @@ +using System; +using System.IO; +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +namespace YooAsset +{ + internal static class PatchManifestTools + { + /// + /// 序列化(JSON文件) + /// + public static void SerializeToJson(string savePath, PatchManifest manifest) + { + string json = JsonUtility.ToJson(manifest, true); + FileUtility.CreateFile(savePath, json); + } + + /// + /// 序列化(二进制文件) + /// + public static void SerializeToBinary(string savePath, PatchManifest patchManifest) + { + using (FileStream fs = new FileStream(savePath, FileMode.Create)) + { + // 创建缓存器 + BufferWriter buffer = new BufferWriter(YooAssetSettings.PatchManifestFileMaxSize); + + // 写入文件标记 + buffer.WriteUInt32(YooAssetSettings.PatchManifestFileSign); + + // 写入文件版本 + buffer.WriteUTF8(patchManifest.FileVersion); + + // 写入文件头信息 + buffer.WriteBool(patchManifest.EnableAddressable); + buffer.WriteInt32(patchManifest.OutputNameStyle); + buffer.WriteUTF8(patchManifest.PackageName); + buffer.WriteUTF8(patchManifest.PackageVersion); + + // 写入资源列表 + buffer.WriteInt32(patchManifest.AssetList.Count); + for (int i = 0; i < patchManifest.AssetList.Count; i++) + { + var patchAsset = patchManifest.AssetList[i]; + buffer.WriteUTF8(patchAsset.Address); + buffer.WriteUTF8(patchAsset.AssetPath); + buffer.WriteUTF8Array(patchAsset.AssetTags); + buffer.WriteInt32(patchAsset.BundleID); + buffer.WriteInt32Array(patchAsset.DependIDs); + } + + // 写入资源包列表 + buffer.WriteInt32(patchManifest.BundleList.Count); + for (int i = 0; i < patchManifest.BundleList.Count; i++) + { + var patchBundle = patchManifest.BundleList[i]; + buffer.WriteUTF8(patchBundle.BundleName); + buffer.WriteUTF8(patchBundle.FileHash); + buffer.WriteUTF8(patchBundle.FileCRC); + buffer.WriteInt64(patchBundle.FileSize); + buffer.WriteBool(patchBundle.IsRawFile); + buffer.WriteByte(patchBundle.LoadMethod); + buffer.WriteUTF8Array(patchBundle.Tags); + } + + // 写入文件流 + buffer.WriteToStream(fs); + fs.Flush(); + } + } + + /// + /// 反序列化(二进制文件) + /// + public static PatchManifest DeserializeFromBinary(byte[] binaryData) + { + // 创建缓存器 + BufferReader buffer = new BufferReader(binaryData); + + // 读取文件标记 + uint fileSign = buffer.ReadUInt32(); + if (fileSign != YooAssetSettings.PatchManifestFileSign) + throw new Exception("Invalid manifest file !"); + + // 读取文件版本 + string fileVersion = buffer.ReadUTF8(); + if (fileVersion != YooAssetSettings.PatchManifestFileVersion) + throw new Exception($"The manifest file version are not compatible : {fileVersion} != {YooAssetSettings.PatchManifestFileVersion}"); + + PatchManifest manifest = new PatchManifest(); + { + // 读取文件头信息 + manifest.FileVersion = fileVersion; + manifest.EnableAddressable = buffer.ReadBool(); + manifest.OutputNameStyle = buffer.ReadInt32(); + manifest.PackageName = buffer.ReadUTF8(); + manifest.PackageVersion = buffer.ReadUTF8(); + + // 读取资源列表 + int patchAssetCount = buffer.ReadInt32(); + manifest.AssetList = new List(patchAssetCount); + for (int i = 0; i < patchAssetCount; i++) + { + var patchAsset = new PatchAsset(); + patchAsset.Address = buffer.ReadUTF8(); + patchAsset.AssetPath = buffer.ReadUTF8(); + patchAsset.AssetTags = buffer.ReadUTF8Array(); + patchAsset.BundleID = buffer.ReadInt32(); + patchAsset.DependIDs = buffer.ReadInt32Array(); + manifest.AssetList.Add(patchAsset); + } + + // 读取资源包列表 + int patchBundleCount = buffer.ReadInt32(); + manifest.BundleList = new List(patchBundleCount); + for (int i = 0; i < patchBundleCount; i++) + { + var patchBundle = new PatchBundle(); + patchBundle.BundleName = buffer.ReadUTF8(); + patchBundle.FileHash = buffer.ReadUTF8(); + patchBundle.FileCRC = buffer.ReadUTF8(); + patchBundle.FileSize = buffer.ReadInt64(); + patchBundle.IsRawFile = buffer.ReadBool(); + patchBundle.LoadMethod = buffer.ReadByte(); + patchBundle.Tags = buffer.ReadUTF8Array(); + manifest.BundleList.Add(patchBundle); + } + } + + // BundleDic + manifest.BundleDic = new Dictionary(manifest.BundleList.Count); + foreach (var patchBundle in manifest.BundleList) + { + patchBundle.ParseBundle(manifest.PackageName, manifest.OutputNameStyle); + manifest.BundleDic.Add(patchBundle.BundleName, patchBundle); + } + + // AssetDic + manifest.AssetDic = new Dictionary(manifest.AssetList.Count); + foreach (var patchAsset in manifest.AssetList) + { + // 注意:我们不允许原始路径存在重名 + string assetPath = patchAsset.AssetPath; + if (manifest.AssetDic.ContainsKey(assetPath)) + throw new Exception($"AssetPath have existed : {assetPath}"); + else + manifest.AssetDic.Add(assetPath, patchAsset); + } + + return manifest; + } + } +} \ No newline at end of file diff --git a/Assets/YooAsset/Runtime/PatchSystem/PatchManifestTools.cs.meta b/Assets/YooAsset/Runtime/PatchSystem/PatchManifestTools.cs.meta new file mode 100644 index 0000000..d50f4f4 --- /dev/null +++ b/Assets/YooAsset/Runtime/PatchSystem/PatchManifestTools.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1014f7c3c05ebab4d8023b27f97a2119 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/YooAsset/Runtime/Utility/YooHelper.cs b/Assets/YooAsset/Runtime/Utility/YooHelper.cs index 030f037..11dd2ff 100644 --- a/Assets/YooAsset/Runtime/Utility/YooHelper.cs +++ b/Assets/YooAsset/Runtime/Utility/YooHelper.cs @@ -134,7 +134,6 @@ namespace YooAsset return PathHelper.MakePersistentLoadPath(AppFootPrintFileName); } - #region 沙盒内清单相关 /// /// 获取沙盒内清单文件的路径 /// @@ -143,56 +142,5 @@ namespace YooAsset string fileName = YooAssetSettingsData.GetPatchManifestFileNameWithoutVersion(packageName); return PathHelper.MakePersistentLoadPath($"{ManifestFolderName}/{fileName}"); } - - /// - /// 加载沙盒内清单文件 - /// - public static PatchManifest LoadCacheManifestFile(string packageName) - { - YooLogger.Log($"Load sandbox patch manifest file : {packageName}"); - string filePath = GetCacheManifestFilePath(packageName); - byte[] bytesData = File.ReadAllBytes(filePath); - return PatchManifest.DeserializeFromBinary(bytesData); - } - - /// - /// 存储沙盒内清单文件 - /// - public static PatchManifest SaveCacheManifestFile(string packageName, byte[] fileBytesData) - { - YooLogger.Log($"Save sandbox patch manifest file : {packageName}"); - var manifest = PatchManifest.DeserializeFromBinary(fileBytesData); - string savePath = GetCacheManifestFilePath(packageName); - FileUtility.CreateFile(savePath, fileBytesData); - 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)) - { - YooLogger.Warning($"Invalid cache manifest file have been removed : {filePath}"); - File.Delete(filePath); - return true; - } - else - { - return false; - } - } - #endregion } } \ No newline at end of file