refactor : 重构资源包裹模块

This commit is contained in:
何冠峰
2026-01-13 19:11:49 +08:00
parent b3d024743c
commit c8c74b8c20
8 changed files with 210 additions and 166 deletions

View File

@@ -2,100 +2,6 @@ using System.Collections.Generic;
namespace YooAsset namespace YooAsset
{ {
/// <summary>
/// 下载器结束
/// </summary>
public struct DownloaderFinishData
{
/// <summary>
/// 所属包裹名称
/// </summary>
public string PackageName;
/// <summary>
/// 是否成功
/// </summary>
public bool Succeed;
}
/// <summary>
/// 下载器相关的更新数据
/// </summary>
public struct DownloadUpdateData
{
/// <summary>
/// 所属包裹名称
/// </summary>
public string PackageName;
/// <summary>
/// 下载进度 (0-1f)
/// </summary>
public float Progress;
/// <summary>
/// 下载文件总数
/// </summary>
public int TotalDownloadCount;
/// <summary>
/// 当前完成的下载文件数量
/// </summary>
public int CurrentDownloadCount;
/// <summary>
/// 下载数据总大小(单位:字节)
/// </summary>
public long TotalDownloadBytes;
/// <summary>
/// 当前完成的下载数据大小(单位:字节)
/// </summary>
public long CurrentDownloadBytes;
}
/// <summary>
/// 下载器相关的错误数据
/// </summary>
public struct DownloadErrorData
{
/// <summary>
/// 所属包裹名称
/// </summary>
public string PackageName;
/// <summary>
/// 下载失败的文件名称
/// </summary>
public string FileName;
/// <summary>
/// 错误信息
/// </summary>
public string ErrorInfo;
}
/// <summary>
/// 下载器相关的文件数据
/// </summary>
public struct DownloadFileData
{
/// <summary>
/// 所属包裹名称
/// </summary>
public string PackageName;
/// <summary>
/// 下载的文件名称
/// </summary>
public string FileName;
/// <summary>
/// 下载的文件大小
/// </summary>
public long FileSize;
}
/// <summary> /// <summary>
/// 导入文件的信息 /// 导入文件的信息
/// </summary> /// </summary>

View File

@@ -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` |
--- ---
## 核心类说明 ## 核心类说明

View File

@@ -32,23 +32,23 @@ OperationSystem 是 YooAsset 资源管理系统的**异步操作调度核心**
``` ```
┌─────────────────────────────────────────────────────────┐ ┌─────────────────────────────────────────────────────────┐
│ 上层调用者 │ │ 上层调用者
│ (ResourceManager / FileSystem / 业务层) │ │ (ResourceManager / FileSystem / 业务层) │
└─────────────────────────┬───────────────────────────────┘ └─────────────────────────┬───────────────────────────────┘
│ StartOperation() │ StartOperation()
┌─────────────────────────▼───────────────────────────────┐ ┌─────────────────────────▼───────────────────────────────┐
│ OperationSystem │ OperationSystem │
│ (调度器) │ │ (调度器) │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ 优先级队列 │ │ 时间切片 │ │ 回调通知 │ │ │ │ 优先级队列 │ │ 时间切片 │ │ 回调通知 │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │ │ └─────────────┘ └─────────────┘ └─────────────┘ │
└─────────────────────────┬───────────────────────────────┘ └─────────────────────────┬───────────────────────────────┘
│ UpdateOperation() │ UpdateOperation()
┌─────────────────────────▼───────────────────────────────┐ ┌─────────────────────────▼───────────────────────────────┐
│ AsyncOperationBase │ AsyncOperationBase │
│ (操作基类) │ │ (操作基类) │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ 状态机 │ │ 子任务管理 │ │ 异步模式 │ │ │ │ 状态机 │ │ 子任务管理 │ │ 异步模式 │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │ │ └─────────────┘ └─────────────┘ └─────────────┘ │
└─────────────────────────────────────────────────────────┘ └─────────────────────────────────────────────────────────┘
``` ```

View File

@@ -3,13 +3,115 @@ using System.Collections.Generic;
namespace YooAsset namespace YooAsset
{ {
#region
/// <summary>
/// 下载器结束
/// </summary>
public struct DownloaderFinishData
{
/// <summary>
/// 所属包裹名称
/// </summary>
public string PackageName;
/// <summary>
/// 是否成功
/// </summary>
public bool Succeed;
}
/// <summary>
/// 下载器相关的更新数据
/// </summary>
public struct DownloadUpdateData
{
/// <summary>
/// 所属包裹名称
/// </summary>
public string PackageName;
/// <summary>
/// 下载进度 (0-1f)
/// </summary>
public float Progress;
/// <summary>
/// 下载文件总数
/// </summary>
public int TotalDownloadCount;
/// <summary>
/// 当前完成的下载文件数量
/// </summary>
public int CurrentDownloadCount;
/// <summary>
/// 下载数据总大小(单位:字节)
/// </summary>
public long TotalDownloadBytes;
/// <summary>
/// 当前完成的下载数据大小(单位:字节)
/// </summary>
public long CurrentDownloadBytes;
}
/// <summary>
/// 下载器相关的错误数据
/// </summary>
public struct DownloadErrorData
{
/// <summary>
/// 所属包裹名称
/// </summary>
public string PackageName;
/// <summary>
/// 下载失败的文件名称
/// </summary>
public string FileName;
/// <summary>
/// 错误信息
/// </summary>
public string ErrorInfo;
}
/// <summary>
/// 下载器相关的文件数据
/// </summary>
public struct DownloadFileData
{
/// <summary>
/// 所属包裹名称
/// </summary>
public string PackageName;
/// <summary>
/// 资源包名称
/// </summary>
public string BundleName;
/// <summary>
/// 文件名称
/// </summary>
public string FileName;
/// <summary>
/// 文件大小
/// </summary>
public long FileSize;
}
#endregion
public abstract class DownloaderOperation : AsyncOperationBase public abstract class DownloaderOperation : AsyncOperationBase
{ {
private enum ESteps private enum ESteps
{ {
None, None,
Check, Check,
Loading, Downloading,
Finish,
Done, Done,
} }
@@ -127,15 +229,37 @@ namespace YooAsset
{ {
_steps = ESteps.Done; _steps = ESteps.Done;
Status = EOperationStatus.Failed; 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 else
{ {
_steps = ESteps.Loading; _steps = ESteps.Downloading;
} }
} }
if (_steps == ESteps.Loading) if (_steps == ESteps.Downloading)
{ {
// 检测下载器结果 // 检测下载器结果
_removeList.Clear(); _removeList.Clear();
@@ -172,7 +296,10 @@ namespace YooAsset
{ {
_lastDownloadBytes = downloadBytes; _lastDownloadBytes = downloadBytes;
_lastDownloadCount = _cachedDownloadCount; _lastDownloadCount = _cachedDownloadCount;
Progress = (float)_lastDownloadBytes / TotalDownloadBytes; if (TotalDownloadBytes == 0)
Progress = (float)_lastDownloadCount / TotalDownloadCount;
else
Progress = (float)_lastDownloadBytes / TotalDownloadBytes;
if (DownloadUpdateCallback != null) if (DownloadUpdateCallback != null)
{ {
@@ -209,54 +336,60 @@ namespace YooAsset
{ {
var data = new DownloadFileData(); var data = new DownloadFileData();
data.PackageName = _packageName; data.PackageName = _packageName;
data.FileName = bundleInfo.Bundle.BundleName; data.BundleName = bundleInfo.Bundle.BundleName;
data.FileName = bundleInfo.Bundle.FileName;
data.FileSize = bundleInfo.Bundle.FileSize; data.FileSize = bundleInfo.Bundle.FileSize;
DownloadFileBeginCallback.Invoke(data); DownloadFileBeginCallback.Invoke(data);
} }
} }
} }
// 下载结 // 下载结
if (_downloaders.Count == 0) 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]; var data = new DownloadErrorData();
string bundleName = failedDownloader.Bundle.BundleName; data.PackageName = _packageName;
_steps = ESteps.Done; data.FileName = bundleName;
Status = EOperationStatus.Failed; data.ErrorInfo = failedDownloader.Error;
Error = $"Failed to download file : {bundleName}"; DownloadErrorCallback.Invoke(data);
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);
}
} }
else
{
// 结算成功
_steps = ESteps.Done;
Status = EOperationStatus.Succeed;
if (DownloadFinishCallback != null) if (DownloadFinishCallback != null)
{ {
var data = new DownloaderFinishData(); var data = new DownloaderFinishData();
data.PackageName = _packageName; data.PackageName = _packageName;
data.Succeed = true; data.Succeed = false;
DownloadFinishCallback.Invoke(data); 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);
} }
} }
} }

View File

@@ -91,7 +91,7 @@ namespace YooAsset
{ {
_steps = ESteps.Done; _steps = ESteps.Done;
Status = EOperationStatus.Failed; 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; return;
} }
@@ -158,7 +158,7 @@ namespace YooAsset
FillAssetCollection(Manifest, packageAsset, replaceAssetPath); FillAssetCollection(Manifest, packageAsset, replaceAssetPath);
_packageAssetCount--; _packageAssetCount--;
Progress = 1f - _packageAssetCount / _progressTotalValue; Progress = 1f - (_packageAssetCount / (float)_progressTotalValue);
if (IsBusy) if (IsBusy)
break; break;
} }
@@ -192,7 +192,7 @@ namespace YooAsset
FillBundleCollection(Manifest, packageBundle); FillBundleCollection(Manifest, packageBundle);
_packageBundleCount--; _packageBundleCount--;
Progress = 1f - _packageBundleCount / _progressTotalValue; Progress = 1f - (_packageBundleCount / (float)_progressTotalValue);
if (IsBusy) if (IsBusy)
break; break;
} }

View File

@@ -298,7 +298,8 @@ namespace YooAsset
return new List<BundleInfo>(); return new List<BundleInfo>();
// 获取资源对象的资源包和所有依赖资源包 // 获取资源对象的资源包和所有依赖资源包
List<PackageBundle> checkList = new List<PackageBundle>(); HashSet<string> checkSet = new HashSet<string>();
List<PackageBundle> checkList = new List<PackageBundle>(assetInfos.Length);
foreach (var assetInfo in assetInfos) foreach (var assetInfo in assetInfos)
{ {
if (assetInfo.IsInvalid) if (assetInfo.IsInvalid)
@@ -309,15 +310,21 @@ namespace YooAsset
// 注意:如果清单里未找到资源包会抛出异常! // 注意:如果清单里未找到资源包会抛出异常!
PackageBundle mainBundle = manifest.GetMainPackageBundle(assetInfo.Asset); PackageBundle mainBundle = manifest.GetMainPackageBundle(assetInfo.Asset);
if (checkList.Contains(mainBundle) == false) if (checkSet.Contains(mainBundle.BundleGUID) == false)
{
checkSet.Add(mainBundle.BundleGUID);
checkList.Add(mainBundle); checkList.Add(mainBundle);
}
// 注意:如果清单里未找到资源包会抛出异常! // 注意:如果清单里未找到资源包会抛出异常!
List<PackageBundle> mainDependBundles = manifest.GetAssetAllDependencies(assetInfo.Asset); List<PackageBundle> mainDependBundles = manifest.GetAssetAllDependencies(assetInfo.Asset);
foreach (var dependBundle in mainDependBundles) foreach (var dependBundle in mainDependBundles)
{ {
if (checkList.Contains(dependBundle) == false) if (checkSet.Contains(dependBundle.BundleGUID) == false)
{
checkSet.Add(dependBundle.BundleGUID);
checkList.Add(dependBundle); checkList.Add(dependBundle);
}
} }
// 下载主资源包内所有资源对象依赖的资源包 // 下载主资源包内所有资源对象依赖的资源包
@@ -326,14 +333,20 @@ namespace YooAsset
foreach (var otherMainAsset in mainBundle.IncludeMainAssets) foreach (var otherMainAsset in mainBundle.IncludeMainAssets)
{ {
var otherMainBundle = manifest.GetMainPackageBundle(otherMainAsset.BundleID); var otherMainBundle = manifest.GetMainPackageBundle(otherMainAsset.BundleID);
if (checkList.Contains(otherMainBundle) == false) if (checkSet.Contains(otherMainBundle.BundleGUID) == false)
{
checkSet.Add(otherMainBundle.BundleGUID);
checkList.Add(otherMainBundle); checkList.Add(otherMainBundle);
}
List<PackageBundle> otherDependBundles = manifest.GetAssetAllDependencies(otherMainAsset); List<PackageBundle> otherDependBundles = manifest.GetAssetAllDependencies(otherMainAsset);
foreach (var dependBundle in otherDependBundles) foreach (var dependBundle in otherDependBundles)
{ {
if (checkList.Contains(dependBundle) == false) if (checkSet.Contains(dependBundle.BundleGUID) == false)
{
checkSet.Add(dependBundle.BundleGUID);
checkList.Add(dependBundle); checkList.Add(dependBundle);
}
} }
} }
} }

View File

@@ -372,6 +372,8 @@ public class PackageBundle
清单序列化工具类。 清单序列化工具类。
> 注意:`DeserializeFromJson` 仅用于编辑器/调试用途,不保证运行时可用;运行时请优先使用二进制清单 `DeserializeFromBinary`。
```csharp ```csharp
// 验证清单数据完整性 // 验证清单数据完整性
static bool VerifyManifestData(byte[] fileData, string hashValue); static bool VerifyManifestData(byte[] fileData, string hashValue);
@@ -381,6 +383,7 @@ static string SerializeToJson(PackageManifest manifest);
static byte[] SerializeToBinary(PackageManifest manifest); static byte[] SerializeToBinary(PackageManifest manifest);
// 反序列化 // 反序列化
// 注意JSON 反序列化仅用于编辑器/调试用途,运行时请优先使用二进制清单。
static PackageManifest DeserializeFromJson(string jsonContent); static PackageManifest DeserializeFromJson(string jsonContent);
static PackageManifest DeserializeFromBinary(byte[] binaryData); static PackageManifest DeserializeFromBinary(byte[] binaryData);

View File

@@ -1163,7 +1163,6 @@ namespace YooAsset
#endregion #endregion
#region #region
[Conditional("DEBUG")]
private void DebugCheckInitialize(bool checkActiveManifest = true) private void DebugCheckInitialize(bool checkActiveManifest = true)
{ {
if (_initializeStatus == EOperationStatus.None) if (_initializeStatus == EOperationStatus.None)