From 20d2c517b211ae3ad6c18a60f7efe54c24167a2b Mon Sep 17 00:00:00 2001 From: hevinci Date: Thu, 21 Apr 2022 16:16:40 +0800 Subject: [PATCH] Optimized raw file load logic MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 优化原生文件加载逻辑,支持离线运行模式和编辑器运行模式。 --- .../Runtime/AssetSystem/AssetSystem.cs | 12 - .../Operations/RawFileOperation.cs | 328 +++++++++++++++--- .../Operations/InitializationOperation.cs | 7 +- .../Operations/UpdateManifestOperation.cs | 6 +- .../UpdateStaticVersionOperation.cs | 8 +- .../PlayMode/EditorPlayModeImpl.cs | 2 +- Assets/YooAsset/Runtime/YooAssets.cs | 35 +- 7 files changed, 320 insertions(+), 78 deletions(-) diff --git a/Assets/YooAsset/Runtime/AssetSystem/AssetSystem.cs b/Assets/YooAsset/Runtime/AssetSystem/AssetSystem.cs index f7b9782..dfde138 100644 --- a/Assets/YooAsset/Runtime/AssetSystem/AssetSystem.cs +++ b/Assets/YooAsset/Runtime/AssetSystem/AssetSystem.cs @@ -127,18 +127,6 @@ namespace YooAsset } - /// - /// 异步加载原生文件 - /// - public static RawFileOperation LoadRawFileAsync(string assetPath, string copyPath) - { - string bundleName = BundleServices.GetBundleName(assetPath); - BundleInfo bundleInfo = BundleServices.GetBundleInfo(bundleName); - RawFileOperation operation = new RawFileOperation(bundleInfo, copyPath); - OperationSystem.ProcessOperaiton(operation); - return operation; - } - /// /// 异步加载场景 /// diff --git a/Assets/YooAsset/Runtime/AssetSystem/Operations/RawFileOperation.cs b/Assets/YooAsset/Runtime/AssetSystem/Operations/RawFileOperation.cs index 0fea447..909be51 100644 --- a/Assets/YooAsset/Runtime/AssetSystem/Operations/RawFileOperation.cs +++ b/Assets/YooAsset/Runtime/AssetSystem/Operations/RawFileOperation.cs @@ -2,49 +2,159 @@ namespace YooAsset { - public class RawFileOperation : AsyncOperationBase + /// + /// 原生文件操作 + /// + public abstract class RawFileOperation : AsyncOperationBase { - private enum ESteps - { - None, - Prepare, - DownloadFromWeb, - CheckDownloadFromWeb, - DownloadFromApk, - CheckDownloadFromApk, - CheckAndCopyFile, - Done, - } - - private readonly BundleInfo _bundleInfo; - private ESteps _steps = ESteps.None; - private DownloaderBase _downloader; - private UnityWebFileRequester _fileRequester; + protected readonly BundleInfo _bundleInfo; /// /// 原生文件的拷贝路径 /// public string CopyPath { private set; get; } - /// - /// 原生文件的缓存路径 - /// - public string CachePath - { - get - { - if (_bundleInfo == null) - return string.Empty; - return _bundleInfo.GetCacheLoadPath(); - } - } - internal RawFileOperation(BundleInfo bundleInfo, string copyPath) { _bundleInfo = bundleInfo; CopyPath = copyPath; } + + /// + /// 原生文件的缓存路径 + /// + public abstract string GetCachePath(); + + /// + /// 获取原生文件的二进制数据 + /// + public byte[] GetFileData() + { + string filePath = GetCachePath(); + if (File.Exists(filePath) == false) + return null; + return File.ReadAllBytes(filePath); + } + + /// + /// 获取原生文件的文本数据 + /// + public string GetFileText() + { + string filePath = GetCachePath(); + if (File.Exists(filePath) == false) + return string.Empty; + return File.ReadAllText(filePath, System.Text.Encoding.UTF8); + } + } + + /// + /// 编辑器下模拟运行的原生文件操作 + /// + internal sealed class EditorPlayModeRawFileOperation : RawFileOperation + { + private enum ESteps + { + None, + Prepare, + CheckAndCopyFile, + Done, + } + + private ESteps _steps = ESteps.None; + + internal EditorPlayModeRawFileOperation(BundleInfo bundleInfo, string copyPath) : base(bundleInfo, copyPath) + { + } + internal override void Start() + { + _steps = ESteps.Prepare; + } + 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.CheckAndCopyFile; + return; // 模拟实现异步操作 + } + else + { + throw new System.NotImplementedException(_bundleInfo.LoadMode.ToString()); + } + } + + // 2. 检测并拷贝原生文件 + if (_steps == ESteps.CheckAndCopyFile) + { + // 如果不需要保存文件 + if (string.IsNullOrEmpty(CopyPath)) + { + _steps = ESteps.Done; + Status = EOperationStatus.Succeed; + return; + } + + // 如果原生文件已经存在,则将其删除 + if (File.Exists(CopyPath)) + { + 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(); + } + } + } + + /// + /// 原生文件的缓存路径 + /// + public override string GetCachePath() + { + if (_bundleInfo == null) + return string.Empty; + return _bundleInfo.BundleName; + } + } + + /// + /// 离线模式的原生文件操作 + /// + internal sealed class OfflinePlayModeRawFileOperation : RawFileOperation + { + private enum ESteps + { + None, + Prepare, + DownloadFromApk, + CheckDownloadFromApk, + CheckAndCopyFile, + Done, + } + + private ESteps _steps = ESteps.None; + private UnityWebFileRequester _fileRequester; + + public OfflinePlayModeRawFileOperation(BundleInfo bundleInfo, string copyPath) : base(bundleInfo, copyPath) + { + } internal override void Start() { _steps = ESteps.Prepare; @@ -62,10 +172,142 @@ namespace YooAsset _steps = ESteps.Done; Status = EOperationStatus.Failed; Error = $"Bundle info is invalid : {_bundleInfo.BundleName}"; + } + else if (_bundleInfo.LoadMode == BundleInfo.ELoadMode.LoadFromStreaming) + { + _steps = ESteps.DownloadFromApk; + } + else + { + throw new System.NotImplementedException(_bundleInfo.LoadMode.ToString()); + } + } + + // 2. 从APK拷贝文件 + if (_steps == ESteps.DownloadFromApk) + { + string downloadURL = PathHelper.ConvertToWWWPath(_bundleInfo.GetStreamingLoadPath()); + _fileRequester = new UnityWebFileRequester(); + _fileRequester.SendRequest(downloadURL, GetCachePath()); + _steps = ESteps.CheckDownloadFromApk; + } + + // 3. 检测APK拷贝文件结果 + if (_steps == ESteps.CheckDownloadFromApk) + { + if (_fileRequester.IsDone() == false) + return; + + if (_fileRequester.HasError()) + { + _steps = ESteps.Done; + Status = EOperationStatus.Failed; + Error = _fileRequester.GetError(); + } + else + { + _steps = ESteps.CheckAndCopyFile; + } + _fileRequester.Dispose(); + } + + // 4. 检测并拷贝原生文件 + if (_steps == ESteps.CheckAndCopyFile) + { + // 如果不需要保存文件 + if (string.IsNullOrEmpty(CopyPath)) + { + _steps = ESteps.Done; + Status = EOperationStatus.Succeed; return; } - if (_bundleInfo.LoadMode == BundleInfo.ELoadMode.LoadFromRemote) + // 如果原生文件已经存在,则验证其完整性 + 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(); + } + } + } + + /// + /// 原生文件的缓存路径 + /// + public override string GetCachePath() + { + if (_bundleInfo == null) + return string.Empty; + return _bundleInfo.GetCacheLoadPath(); + } + } + + /// + /// 网络模式的原生文件操作 + /// + internal sealed class HostPlayModeRawFileOperation : RawFileOperation + { + private enum ESteps + { + None, + Prepare, + DownloadFromWeb, + CheckDownloadFromWeb, + DownloadFromApk, + CheckDownloadFromApk, + CheckAndCopyFile, + Done, + } + + private ESteps _steps = ESteps.None; + private DownloaderBase _downloader; + private UnityWebFileRequester _fileRequester; + + internal HostPlayModeRawFileOperation(BundleInfo bundleInfo, string copyPath) : base(bundleInfo, copyPath) + { + } + internal override void Start() + { + _steps = ESteps.Prepare; + } + 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; } @@ -114,7 +356,7 @@ namespace YooAsset { string downloadURL = PathHelper.ConvertToWWWPath(_bundleInfo.GetStreamingLoadPath()); _fileRequester = new UnityWebFileRequester(); - _fileRequester.SendRequest(downloadURL, _bundleInfo.GetCacheLoadPath()); + _fileRequester.SendRequest(downloadURL, GetCachePath()); _steps = ESteps.CheckDownloadFromApk; } @@ -167,7 +409,7 @@ namespace YooAsset try { FileUtility.CreateFileDirectory(CopyPath); - File.Copy(_bundleInfo.GetCacheLoadPath(), CopyPath, true); + File.Copy(GetCachePath(), CopyPath, true); _steps = ESteps.Done; Status = EOperationStatus.Succeed; } @@ -181,25 +423,13 @@ namespace YooAsset } /// - /// 获取原生文件的二进制数据 + /// 原生文件的缓存路径 /// - public byte[] GetFileData() + public override string GetCachePath() { - string cachePath = _bundleInfo.GetCacheLoadPath(); - if (File.Exists(cachePath) == false) - return null; - return File.ReadAllBytes(cachePath); - } - - /// - /// 获取原生文件的文本数据 - /// - public string GetFileText() - { - string cachePath = _bundleInfo.GetCacheLoadPath(); - if (File.Exists(cachePath) == false) + if (_bundleInfo == null) return string.Empty; - return File.ReadAllText(cachePath, System.Text.Encoding.UTF8); + return _bundleInfo.GetCacheLoadPath(); } } } \ No newline at end of file diff --git a/Assets/YooAsset/Runtime/PatchSystem/Operations/InitializationOperation.cs b/Assets/YooAsset/Runtime/PatchSystem/Operations/InitializationOperation.cs index 788fe94..9c223dc 100644 --- a/Assets/YooAsset/Runtime/PatchSystem/Operations/InitializationOperation.cs +++ b/Assets/YooAsset/Runtime/PatchSystem/Operations/InitializationOperation.cs @@ -1,6 +1,5 @@ using System.Collections; using System.Collections.Generic; -using System.IO; using UnityEngine; namespace YooAsset @@ -15,7 +14,7 @@ namespace YooAsset /// /// 编辑器下模拟运行的初始化操作 /// - internal class EditorModeInitializationOperation : InitializationOperation + internal sealed class EditorPlayModeInitializationOperation : InitializationOperation { internal override void Start() { @@ -29,7 +28,7 @@ namespace YooAsset /// /// 离线模式的初始化操作 /// - internal class OfflinePlayModeInitializationOperation : InitializationOperation + internal sealed class OfflinePlayModeInitializationOperation : InitializationOperation { private enum ESteps { @@ -81,7 +80,7 @@ namespace YooAsset /// /// 网络模式的初始化操作 /// - internal class HostPlayModeInitializationOperation : InitializationOperation + internal sealed class HostPlayModeInitializationOperation : InitializationOperation { private enum ESteps { diff --git a/Assets/YooAsset/Runtime/PatchSystem/Operations/UpdateManifestOperation.cs b/Assets/YooAsset/Runtime/PatchSystem/Operations/UpdateManifestOperation.cs index 32a8127..43a2c4d 100644 --- a/Assets/YooAsset/Runtime/PatchSystem/Operations/UpdateManifestOperation.cs +++ b/Assets/YooAsset/Runtime/PatchSystem/Operations/UpdateManifestOperation.cs @@ -16,7 +16,7 @@ namespace YooAsset /// /// 编辑器下模拟运行的更新清单操作 /// - internal class EditorModeUpdateManifestOperation : UpdateManifestOperation + internal sealed class EditorPlayModeUpdateManifestOperation : UpdateManifestOperation { internal override void Start() { @@ -30,7 +30,7 @@ namespace YooAsset /// /// 离线模式的更新清单操作 /// - internal class OfflinePlayModeUpdateManifestOperation : UpdateManifestOperation + internal sealed class OfflinePlayModeUpdateManifestOperation : UpdateManifestOperation { internal override void Start() { @@ -44,7 +44,7 @@ namespace YooAsset /// /// 网络模式的更新清单操作 /// - internal class HostPlayModeUpdateManifestOperation : UpdateManifestOperation + internal sealed class HostPlayModeUpdateManifestOperation : UpdateManifestOperation { private enum ESteps { diff --git a/Assets/YooAsset/Runtime/PatchSystem/Operations/UpdateStaticVersionOperation.cs b/Assets/YooAsset/Runtime/PatchSystem/Operations/UpdateStaticVersionOperation.cs index cc114db..62a5b4c 100644 --- a/Assets/YooAsset/Runtime/PatchSystem/Operations/UpdateStaticVersionOperation.cs +++ b/Assets/YooAsset/Runtime/PatchSystem/Operations/UpdateStaticVersionOperation.cs @@ -1,7 +1,5 @@ using System.Collections; using System.Collections.Generic; -using System.IO; -using UnityEngine; namespace YooAsset { @@ -19,7 +17,7 @@ namespace YooAsset /// /// 编辑器下模拟运行的更新静态版本操作 /// - internal class EditorModeUpdateStaticVersionOperation : UpdateStaticVersionOperation + internal sealed class EditorPlayModeUpdateStaticVersionOperation : UpdateStaticVersionOperation { internal override void Start() { @@ -33,7 +31,7 @@ namespace YooAsset /// /// 离线模式的更新静态版本操作 /// - internal class OfflinePlayModeUpdateStaticVersionOperation : UpdateStaticVersionOperation + internal sealed class OfflinePlayModeUpdateStaticVersionOperation : UpdateStaticVersionOperation { internal override void Start() { @@ -47,7 +45,7 @@ namespace YooAsset /// /// 网络模式的更新静态版本操作 /// - internal class HostPlayModeUpdateStaticVersionOperation : UpdateStaticVersionOperation + internal sealed class HostPlayModeUpdateStaticVersionOperation : UpdateStaticVersionOperation { private enum ESteps { diff --git a/Assets/YooAsset/Runtime/PatchSystem/PlayMode/EditorPlayModeImpl.cs b/Assets/YooAsset/Runtime/PatchSystem/PlayMode/EditorPlayModeImpl.cs index 36c0cb0..f812784 100644 --- a/Assets/YooAsset/Runtime/PatchSystem/PlayMode/EditorPlayModeImpl.cs +++ b/Assets/YooAsset/Runtime/PatchSystem/PlayMode/EditorPlayModeImpl.cs @@ -11,7 +11,7 @@ namespace YooAsset /// public InitializationOperation InitializeAsync() { - var operation = new EditorModeInitializationOperation(); + var operation = new EditorPlayModeInitializationOperation(); OperationSystem.ProcessOperaiton(operation); return operation; } diff --git a/Assets/YooAsset/Runtime/YooAssets.cs b/Assets/YooAsset/Runtime/YooAssets.cs index ea18703..c063127 100644 --- a/Assets/YooAsset/Runtime/YooAssets.cs +++ b/Assets/YooAsset/Runtime/YooAssets.cs @@ -219,12 +219,11 @@ namespace YooAsset /// 向网络端请求静态资源版本号 /// /// 超时时间(默认值:60秒) - /// public static UpdateStaticVersionOperation UpdateStaticVersionAsync(int timeout = 60) { if (_playMode == EPlayMode.EditorPlayMode) { - var operation = new EditorModeUpdateStaticVersionOperation(); + var operation = new EditorPlayModeUpdateStaticVersionOperation(); OperationSystem.ProcessOperaiton(operation); return operation; } @@ -255,7 +254,7 @@ namespace YooAsset { if (_playMode == EPlayMode.EditorPlayMode) { - var operation = new EditorModeUpdateManifestOperation(); + var operation = new EditorPlayModeUpdateManifestOperation(); OperationSystem.ProcessOperaiton(operation); return operation; } @@ -369,7 +368,35 @@ namespace YooAsset public static RawFileOperation LoadRawFileAsync(string location, string copyPath = null) { string assetPath = _locationServices.ConvertLocationToAssetPath(_playMode, location); - return AssetSystem.LoadRawFileAsync(assetPath, copyPath); + if (_playMode == EPlayMode.EditorPlayMode) + { + BundleInfo bundleInfo = new BundleInfo(assetPath); + RawFileOperation operation = new EditorPlayModeRawFileOperation(bundleInfo, copyPath); + OperationSystem.ProcessOperaiton(operation); + return operation; + } + else if (_playMode == EPlayMode.OfflinePlayMode) + { + IBundleServices bundleServices = _offlinePlayModeImpl; + string bundleName = bundleServices.GetBundleName(assetPath); + BundleInfo bundleInfo = bundleServices.GetBundleInfo(bundleName); + RawFileOperation operation = new OfflinePlayModeRawFileOperation(bundleInfo, copyPath); + OperationSystem.ProcessOperaiton(operation); + return operation; + } + else if (_playMode == EPlayMode.HostPlayMode) + { + IBundleServices bundleServices = _hostPlayModeImpl; + string bundleName = bundleServices.GetBundleName(assetPath); + BundleInfo bundleInfo = bundleServices.GetBundleInfo(bundleName); + RawFileOperation operation = new HostPlayModeRawFileOperation(bundleInfo, copyPath); + OperationSystem.ProcessOperaiton(operation); + return operation; + } + else + { + throw new NotImplementedException(); + } }