diff --git a/Assets/YooAsset/Runtime/DownloadSystem/DownloadSystemDefine.cs b/Assets/YooAsset/Runtime/DownloadSystem/DownloadSystemDefine.cs index 1fe19898..e693d1bc 100644 --- a/Assets/YooAsset/Runtime/DownloadSystem/DownloadSystemDefine.cs +++ b/Assets/YooAsset/Runtime/DownloadSystem/DownloadSystemDefine.cs @@ -2,100 +2,6 @@ using System.Collections.Generic; namespace YooAsset { - /// - /// 下载器结束 - /// - public struct DownloaderFinishData - { - /// - /// 所属包裹名称 - /// - public string PackageName; - - /// - /// 是否成功 - /// - public bool Succeed; - } - - /// - /// 下载器相关的更新数据 - /// - public struct DownloadUpdateData - { - /// - /// 所属包裹名称 - /// - public string PackageName; - - /// - /// 下载进度 (0-1f) - /// - public float Progress; - - /// - /// 下载文件总数 - /// - public int TotalDownloadCount; - - /// - /// 当前完成的下载文件数量 - /// - public int CurrentDownloadCount; - - /// - /// 下载数据总大小(单位:字节) - /// - public long TotalDownloadBytes; - - /// - /// 当前完成的下载数据大小(单位:字节) - /// - public long CurrentDownloadBytes; - } - - /// - /// 下载器相关的错误数据 - /// - public struct DownloadErrorData - { - /// - /// 所属包裹名称 - /// - public string PackageName; - - /// - /// 下载失败的文件名称 - /// - public string FileName; - - /// - /// 错误信息 - /// - public string ErrorInfo; - } - - /// - /// 下载器相关的文件数据 - /// - public struct DownloadFileData - { - /// - /// 所属包裹名称 - /// - public string PackageName; - - /// - /// 下载的文件名称 - /// - public string FileName; - - /// - /// 下载的文件大小 - /// - public long FileSize; - } - /// /// 导入文件的信息 /// diff --git a/Assets/YooAsset/Runtime/DownloadSystem/README.md b/Assets/YooAsset/Runtime/DownloadSystem/README.md index 1f857d95..6800ab0a 100644 --- a/Assets/YooAsset/Runtime/DownloadSystem/README.md +++ b/Assets/YooAsset/Runtime/DownloadSystem/README.md @@ -41,20 +41,20 @@ DownloadSystem 的职责是提供“可替换后端 + 统一请求接口 + 轮 ``` ┌─────────────────────────────────────────────────────────┐ -│ 上层调用者 │ -│ (FileSystem / ResourceManager) │ +│ 上层调用者 │ +│ (FileSystem / ResourceManager) │ └─────────────────────────┬───────────────────────────────┘ │ ┌─────────────────────────▼───────────────────────────────┐ -│ IDownloadBackend │ +│ IDownloadBackend │ │ (后端接口) │ -│ 定义网络库合约,工厂模式创建请求 │ +│ 定义网络库合约,工厂模式创建请求 │ └─────────────────────────┬───────────────────────────────┘ │ ┌─────────────────────────▼───────────────────────────────┐ -│ IDownloadRequest │ +│ IDownloadRequest │ │ (请求接口) │ -│ 轮询式生命周期管理,状态机驱动 │ +│ 轮询式生命周期管理,状态机驱动 │ └─────────────────────────┬───────────────────────────────┘ │ ┌─────────────────────────▼───────────────────────────────┐ @@ -244,16 +244,6 @@ public struct DownloadSimulateRequestArgs } ``` -### 回调数据结构体 - -| 结构体 | 用途 | 关键字段 | -|--------|------|----------| -| `DownloaderFinishData` | 下载完成回调 | `PackageName`, `Succeed` | -| `DownloadUpdateData` | 进度更新回调 | `Progress`, `TotalDownloadBytes`, `CurrentDownloadBytes` | -| `DownloadErrorData` | 下载错误回调 | `FileName`, `ErrorInfo` | -| `DownloadFileData` | 文件完成回调 | `FileName`, `FileSize` | -| `ImportFileInfo` | 导入文件元数据 | `FilePath`, `BundleName`, `BundleGUID` | - --- ## 核心类说明 diff --git a/Assets/YooAsset/Runtime/OperationSystem/README.md b/Assets/YooAsset/Runtime/OperationSystem/README.md index 60b1f76a..dece1f34 100644 --- a/Assets/YooAsset/Runtime/OperationSystem/README.md +++ b/Assets/YooAsset/Runtime/OperationSystem/README.md @@ -32,23 +32,23 @@ OperationSystem 是 YooAsset 资源管理系统的**异步操作调度核心** ``` ┌─────────────────────────────────────────────────────────┐ -│ 上层调用者 │ +│ 上层调用者 │ │ (ResourceManager / FileSystem / 业务层) │ └─────────────────────────┬───────────────────────────────┘ │ StartOperation() ┌─────────────────────────▼───────────────────────────────┐ -│ OperationSystem │ +│ OperationSystem │ │ (调度器) │ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ -│ │ 优先级队列 │ │ 时间切片 │ │ 回调通知 │ │ +│ │ 优先级队列 │ │ 时间切片 │ │ 回调通知 │ │ │ └─────────────┘ └─────────────┘ └─────────────┘ │ └─────────────────────────┬───────────────────────────────┘ │ UpdateOperation() ┌─────────────────────────▼───────────────────────────────┐ -│ AsyncOperationBase │ +│ AsyncOperationBase │ │ (操作基类) │ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ -│ │ 状态机 │ │ 子任务管理 │ │ 异步模式 │ │ +│ │ 状态机 │ │ 子任务管理 │ │ 异步模式 │ │ │ └─────────────┘ └─────────────┘ └─────────────┘ │ └─────────────────────────────────────────────────────────┘ ``` diff --git a/Assets/YooAsset/Runtime/ResourcePackage/Operation/DownloaderOperation.cs b/Assets/YooAsset/Runtime/ResourcePackage/Operation/DownloaderOperation.cs index de063aad..fa39a055 100644 --- a/Assets/YooAsset/Runtime/ResourcePackage/Operation/DownloaderOperation.cs +++ b/Assets/YooAsset/Runtime/ResourcePackage/Operation/DownloaderOperation.cs @@ -3,13 +3,115 @@ using System.Collections.Generic; namespace YooAsset { + #region 下载器相关类型定义 + /// + /// 下载器结束 + /// + public struct DownloaderFinishData + { + /// + /// 所属包裹名称 + /// + public string PackageName; + + /// + /// 是否成功 + /// + public bool Succeed; + } + + /// + /// 下载器相关的更新数据 + /// + public struct DownloadUpdateData + { + /// + /// 所属包裹名称 + /// + public string PackageName; + + /// + /// 下载进度 (0-1f) + /// + public float Progress; + + /// + /// 下载文件总数 + /// + public int TotalDownloadCount; + + /// + /// 当前完成的下载文件数量 + /// + public int CurrentDownloadCount; + + /// + /// 下载数据总大小(单位:字节) + /// + public long TotalDownloadBytes; + + /// + /// 当前完成的下载数据大小(单位:字节) + /// + public long CurrentDownloadBytes; + } + + /// + /// 下载器相关的错误数据 + /// + public struct DownloadErrorData + { + /// + /// 所属包裹名称 + /// + public string PackageName; + + /// + /// 下载失败的文件名称 + /// + public string FileName; + + /// + /// 错误信息 + /// + public string ErrorInfo; + } + + /// + /// 下载器相关的文件数据 + /// + public struct DownloadFileData + { + /// + /// 所属包裹名称 + /// + public string PackageName; + + /// + /// 资源包名称 + /// + public string BundleName; + + /// + /// 文件名称 + /// + public string FileName; + + /// + /// 文件大小 + /// + public long FileSize; + } + #endregion + public abstract class DownloaderOperation : AsyncOperationBase { private enum ESteps { None, Check, - Loading, + Downloading, + Finish, Done, } @@ -127,15 +229,37 @@ namespace YooAsset { _steps = ESteps.Done; Status = EOperationStatus.Failed; - Error = "Download list is null."; + Error = "Download bundle list is null."; + + if (DownloadFinishCallback != null) + { + var data = new DownloaderFinishData(); + data.PackageName = _packageName; + data.Succeed = false; + DownloadFinishCallback.Invoke(data); + } + } + else if (_bundleInfoList.Count == 0) + { + _steps = ESteps.Done; + Status = EOperationStatus.Succeed; + Progress = 1f; + + if (DownloadFinishCallback != null) + { + var data = new DownloaderFinishData(); + data.PackageName = _packageName; + data.Succeed = true; + DownloadFinishCallback.Invoke(data); + } } else { - _steps = ESteps.Loading; + _steps = ESteps.Downloading; } } - if (_steps == ESteps.Loading) + if (_steps == ESteps.Downloading) { // 检测下载器结果 _removeList.Clear(); @@ -172,7 +296,10 @@ namespace YooAsset { _lastDownloadBytes = downloadBytes; _lastDownloadCount = _cachedDownloadCount; - Progress = (float)_lastDownloadBytes / TotalDownloadBytes; + if (TotalDownloadBytes == 0) + Progress = (float)_lastDownloadCount / TotalDownloadCount; + else + Progress = (float)_lastDownloadBytes / TotalDownloadBytes; if (DownloadUpdateCallback != null) { @@ -209,54 +336,60 @@ namespace YooAsset { var data = new DownloadFileData(); data.PackageName = _packageName; - data.FileName = bundleInfo.Bundle.BundleName; + data.BundleName = bundleInfo.Bundle.BundleName; + data.FileName = bundleInfo.Bundle.FileName; data.FileSize = bundleInfo.Bundle.FileSize; DownloadFileBeginCallback.Invoke(data); } } } - // 下载结算 + // 下载结束 if (_downloaders.Count == 0) { - if (_failedList.Count > 0) + _steps = ESteps.Finish; + } + } + + if (_steps == ESteps.Finish) + { + if (_failedList.Count > 0) + { + var failedDownloader = _failedList[0]; + string bundleName = failedDownloader.Bundle.BundleName; + _steps = ESteps.Done; + Status = EOperationStatus.Failed; + Error = $"Failed to download file : {bundleName}"; + + if (DownloadErrorCallback != null) { - var failedDownloader = _failedList[0]; - string bundleName = failedDownloader.Bundle.BundleName; - _steps = ESteps.Done; - Status = EOperationStatus.Failed; - Error = $"Failed to download file : {bundleName}"; - - if (DownloadErrorCallback != null) - { - var data = new DownloadErrorData(); - data.PackageName = _packageName; - data.FileName = bundleName; - data.ErrorInfo = failedDownloader.Error; - DownloadErrorCallback.Invoke(data); - } - - if (DownloadFinishCallback != null) - { - var data = new DownloaderFinishData(); - data.PackageName = _packageName; - data.Succeed = false; - DownloadFinishCallback.Invoke(data); - } + var data = new DownloadErrorData(); + data.PackageName = _packageName; + data.FileName = bundleName; + data.ErrorInfo = failedDownloader.Error; + DownloadErrorCallback.Invoke(data); } - else - { - // 结算成功 - _steps = ESteps.Done; - Status = EOperationStatus.Succeed; - if (DownloadFinishCallback != null) - { - var data = new DownloaderFinishData(); - data.PackageName = _packageName; - data.Succeed = true; - DownloadFinishCallback.Invoke(data); - } + if (DownloadFinishCallback != null) + { + var data = new DownloaderFinishData(); + data.PackageName = _packageName; + data.Succeed = false; + DownloadFinishCallback.Invoke(data); + } + } + else + { + // 结算成功 + _steps = ESteps.Done; + Status = EOperationStatus.Succeed; + + if (DownloadFinishCallback != null) + { + var data = new DownloaderFinishData(); + data.PackageName = _packageName; + data.Succeed = true; + DownloadFinishCallback.Invoke(data); } } } diff --git a/Assets/YooAsset/Runtime/ResourcePackage/Operation/Internal/DeserializeManifestOperation.cs b/Assets/YooAsset/Runtime/ResourcePackage/Operation/Internal/DeserializeManifestOperation.cs index 87afcfcc..e7b1a455 100644 --- a/Assets/YooAsset/Runtime/ResourcePackage/Operation/Internal/DeserializeManifestOperation.cs +++ b/Assets/YooAsset/Runtime/ResourcePackage/Operation/Internal/DeserializeManifestOperation.cs @@ -91,7 +91,7 @@ namespace YooAsset { _steps = ESteps.Done; Status = EOperationStatus.Failed; - Error = $"The manifest file version are not compatible : {fileVersion} != {ManifestDefine.FileVersion}"; + Error = $"The manifest version is lower than the minimum compatible version : {fileVer} < {ver2025_8_28}"; return; } @@ -158,7 +158,7 @@ namespace YooAsset FillAssetCollection(Manifest, packageAsset, replaceAssetPath); _packageAssetCount--; - Progress = 1f - _packageAssetCount / _progressTotalValue; + Progress = 1f - (_packageAssetCount / (float)_progressTotalValue); if (IsBusy) break; } @@ -192,7 +192,7 @@ namespace YooAsset FillBundleCollection(Manifest, packageBundle); _packageBundleCount--; - Progress = 1f - _packageBundleCount / _progressTotalValue; + Progress = 1f - (_packageBundleCount / (float)_progressTotalValue); if (IsBusy) break; } diff --git a/Assets/YooAsset/Runtime/ResourcePackage/PlayMode/PlayModeImpl.cs b/Assets/YooAsset/Runtime/ResourcePackage/PlayMode/PlayModeImpl.cs index b15f0b51..c14c8f0e 100644 --- a/Assets/YooAsset/Runtime/ResourcePackage/PlayMode/PlayModeImpl.cs +++ b/Assets/YooAsset/Runtime/ResourcePackage/PlayMode/PlayModeImpl.cs @@ -298,7 +298,8 @@ namespace YooAsset return new List(); // 获取资源对象的资源包和所有依赖资源包 - List checkList = new List(); + HashSet checkSet = new HashSet(); + List checkList = new List(assetInfos.Length); foreach (var assetInfo in assetInfos) { if (assetInfo.IsInvalid) @@ -309,15 +310,21 @@ namespace YooAsset // 注意:如果清单里未找到资源包会抛出异常! PackageBundle mainBundle = manifest.GetMainPackageBundle(assetInfo.Asset); - if (checkList.Contains(mainBundle) == false) + if (checkSet.Contains(mainBundle.BundleGUID) == false) + { + checkSet.Add(mainBundle.BundleGUID); checkList.Add(mainBundle); + } // 注意:如果清单里未找到资源包会抛出异常! List mainDependBundles = manifest.GetAssetAllDependencies(assetInfo.Asset); foreach (var dependBundle in mainDependBundles) { - if (checkList.Contains(dependBundle) == false) + if (checkSet.Contains(dependBundle.BundleGUID) == false) + { + checkSet.Add(dependBundle.BundleGUID); checkList.Add(dependBundle); + } } // 下载主资源包内所有资源对象依赖的资源包 @@ -326,14 +333,20 @@ namespace YooAsset foreach (var otherMainAsset in mainBundle.IncludeMainAssets) { var otherMainBundle = manifest.GetMainPackageBundle(otherMainAsset.BundleID); - if (checkList.Contains(otherMainBundle) == false) + if (checkSet.Contains(otherMainBundle.BundleGUID) == false) + { + checkSet.Add(otherMainBundle.BundleGUID); checkList.Add(otherMainBundle); + } List otherDependBundles = manifest.GetAssetAllDependencies(otherMainAsset); foreach (var dependBundle in otherDependBundles) { - if (checkList.Contains(dependBundle) == false) + if (checkSet.Contains(dependBundle.BundleGUID) == false) + { + checkSet.Add(dependBundle.BundleGUID); checkList.Add(dependBundle); + } } } } diff --git a/Assets/YooAsset/Runtime/ResourcePackage/README.md b/Assets/YooAsset/Runtime/ResourcePackage/README.md index 3cc7b297..b40987a6 100644 --- a/Assets/YooAsset/Runtime/ResourcePackage/README.md +++ b/Assets/YooAsset/Runtime/ResourcePackage/README.md @@ -372,6 +372,8 @@ public class PackageBundle 清单序列化工具类。 +> 注意:`DeserializeFromJson` 仅用于编辑器/调试用途,不保证运行时可用;运行时请优先使用二进制清单 `DeserializeFromBinary`。 + ```csharp // 验证清单数据完整性 static bool VerifyManifestData(byte[] fileData, string hashValue); @@ -381,6 +383,7 @@ static string SerializeToJson(PackageManifest manifest); static byte[] SerializeToBinary(PackageManifest manifest); // 反序列化 +// 注意:JSON 反序列化仅用于编辑器/调试用途,运行时请优先使用二进制清单。 static PackageManifest DeserializeFromJson(string jsonContent); static PackageManifest DeserializeFromBinary(byte[] binaryData); diff --git a/Assets/YooAsset/Runtime/ResourcePackage/ResourcePackage.cs b/Assets/YooAsset/Runtime/ResourcePackage/ResourcePackage.cs index e48a6dbd..d9f0af1f 100644 --- a/Assets/YooAsset/Runtime/ResourcePackage/ResourcePackage.cs +++ b/Assets/YooAsset/Runtime/ResourcePackage/ResourcePackage.cs @@ -1163,7 +1163,6 @@ namespace YooAsset #endregion #region 调试方法 - [Conditional("DEBUG")] private void DebugCheckInitialize(bool checkActiveManifest = true) { if (_initializeStatus == EOperationStatus.None)