refactor : 代码重构

This commit is contained in:
何冠峰
2026-03-26 21:02:11 +08:00
parent 8b35472991
commit d47b9e9d56
304 changed files with 4305 additions and 2618 deletions

View File

@@ -53,6 +53,8 @@
| `LogOff` | `logOff` | ~~LogOut~~ |
| `Email` | `email` | ~~EMail~~ |
> ✔️ 在 Unity 项目中,`ID` 保持全大写以与 Unity API 风格一致(如 `GetInstanceID()`、`PropertyToID()`),项目内应保持风格统一。
### 1.5 区分大小写
- 不要假定所有语言都区分大小写

View File

@@ -14,12 +14,12 @@
```csharp
// ✔️
$"File cache entry not found: '{bundleGUID}'."
$"File cache entry not found: '{bundleGuid}'."
$"Invalid clear method: '{options.ClearMethod}'."
$"Could not find file '{filePath}'."
// ❌
$"File cache entry not found: {bundleGUID}."
$"File cache entry not found: {bundleGuid}."
```
### 1.2 数值变量不加引号
@@ -95,6 +95,17 @@ throw new Exception("catalog file data is null or empty");
"Bundle handle null."
```
> **例外**`not found` 等 .NET 生态中广泛使用的惯用短语,允许省略 `was`,以保持简洁和一致性。
```csharp
// ✔️ 惯用短语,省略 was
"File cache entry not found: '{bundleGuid}'."
"Asset not found: '{assetPath}'."
// ❌ 冗余
"File cache entry was not found: '{bundleGuid}'."
```
### 2.3 不要以冠词或变量开头
消息以关键实体词开头,不要以 `The` / `A` / `An` 或变量开头,便于日志搜索和排序。
@@ -103,11 +114,11 @@ throw new Exception("catalog file data is null or empty");
```csharp
// ✔️
$"Cache entry already exists: '{bundleGUID}'."
$"Cache entry already exists: '{bundleGuid}'."
$"Log file '{name}' is full."
// ❌
$"The cache entry already exists: '{bundleGUID}'."
$"The cache entry already exists: '{bundleGuid}'."
$"'{name}' log file is full."
```
@@ -174,7 +185,7 @@ $"Exception in {this.GetType().Name}.InternalStart: {ex}."
```csharp
// ✔️ 统一格式
$"File cache entry not found: '{bundleGUID}'." // 所有缓存未命中统一使用此句式
$"File cache entry not found: '{bundleGuid}'." // 所有缓存未命中统一使用此句式
$"Exception in {GetType().Name}.{MethodName}: {ex}." // 所有异常日志统一使用此句式
// ❌ 同一语义不同表达
@@ -199,7 +210,7 @@ $"Exception in {GetType().Name}.{MethodName}: {ex}." // 所有异常日志统一
| # | 规则 | 正确示例 | 错误示例 |
|---|------|---------|---------|
| 1 | 字符串变量值加单引号 | `'{bundleGUID}'` | `{bundleGUID}` |
| 1 | 字符串变量值加单引号 | `'{bundleGuid}'` | `{bundleGuid}` |
| 2 | 数值变量不加引号 | `{count}` | `'{count}'` |
| 3 | 类型名作主语不加引号 | `TypeName is not ...` | `'TypeName' is not ...` |
| 4 | 异常对象不加引号 | `{ex.Message}` | `'{ex.Message}'` |

View File

@@ -21,7 +21,6 @@ C# 使用 XML 文档注释为代码提供结构化文档。编译器从 `///`
| `<summary>` | 简要描述类型或成员的功能 | 所有公共类型和成员 |
| `<param>` | 描述方法参数 | 方法、构造函数 |
| `<returns>` | 描述方法返回值 | 有返回值的方法 |
| `<exception>` | 说明可能抛出的异常 | 可能抛出异常的方法 |
| `<remarks>` | 补充说明,提供额外细节 | 需要详细解释的成员 |
| `<value>` | 描述属性所代表的值 | 属性 |
@@ -41,7 +40,6 @@ C# 使用 XML 文档注释为代码提供结构化文档。编译器从 `///`
| `<para>` | 在 `<remarks>` 等标签内分段 |
| `<list>` | 创建列表或表格 |
| `<code>` | 多行代码示例 |
| `<c>` | 行内代码片段 |
| `<example>` | 包含使用示例 |
### 2.4 泛型与继承标签
@@ -71,13 +69,15 @@ C# 使用 XML 文档注释为代码提供结构化文档。编译器从 `///`
|----------|---------|---------|
| 类 / 结构 | `<summary>` | `<remarks>``<typeparam>` |
| 接口 | `<summary>` | `<remarks>` |
| 方法 | `<summary>``<param>``<returns>` | `<exception>``<remarks>``<example>` |
| 构造函数 | `<summary>``<param>` | `<exception>` |
| 属性 | `<summary>` | `<value>``<exception>` |
| 方法 | `<summary>``<param>``<returns>` | `<remarks>``<example>` |
| 构造函数 | `<summary>``<param>` | |
| 属性 | `<summary>` | `<value>` |
| 事件 | `<summary>` | `<remarks>` |
| 枚举类型 | `<summary>` | — |
| 枚举值 | `<summary>` | — |
| 委托 | `<summary>``<param>``<returns>` | — |
| 接口实现成员 | `<inheritdoc/>` | — |
| override 方法 | **不添加**注释 | — |
---
@@ -89,17 +89,46 @@ C# 使用 XML 文档注释为代码提供结构化文档。编译器从 `///`
✔️ 以**第三人称动词**开头。
✔️ 完整语句末尾**建议**使用句号,短语式描述可省略
✔️ 句号规则:注释内容含逗号、分号等分句标点时,末尾**加**句号;纯短语**不加**句号
```csharp
// ✔️ 含逗号 → 加句号
/// <param name="timeout">超时时间0 表示不限制。</param>
/// <returns>下载结果,包含状态码和错误信息。</returns>
// ✔️ 纯短语 → 不加句号
/// <param name="url">资源包的完整下载地址</param>
/// <returns>初始化操作句柄</returns>
```
❌ **禁止**重复方法名或参数类型中已表达的信息。
❌ **禁止**在注释中重复方法命名后缀已表达的语义。常见后缀包括:
| 命名后缀 | 已表达的语义 | 注释中禁止使用 |
|----------|------------|--------------|
| `Async` | 异步执行 | "异步" |
| `Internal` | 内部实现 | "内部" |
❌ **禁止**以"这个方法"、"该类"等冗余前缀开头。
### 4.2 常见动词约定
### 4.2 常见开头约定
#### 属性 —— 描述值本身,不加动词前缀
属性的 `{ get; }` / `{ get; set; }` 访问器已表达读写语义summary 应直接描述**值的含义**,避免用"获取"、"获取或设置"等动词前缀重复已知信息。
| 属性类型 | 推荐写法 | 反例 |
|----------|---------|------|
| 只读属性 | 名词短语,如 "错误信息" | ~~"获取错误信息"~~ |
| 可读写属性 | 名词短语,如 "当前下载进度" | ~~"获取或设置当前下载进度"~~ |
| 返回 bool 的属性 | "是否……",如 "是否为只读缓存" | ~~"判断是否为只读缓存"~~ |
#### 方法 —— 以动词开头
| 成员类型 | 推荐开头动词 |
|----------|-------------|
| 返回 bool 的方法 / 属性 | "检查是否"、"判断是否" |
| 返回 bool 的方法 | "检查是否"、"判断是否" |
| 获取类方法 | "获取"、"查询" |
| 设置类方法 | "设置"、"更新" |
| 创建类方法 | "创建"、"构建"、"生成" |
@@ -112,8 +141,6 @@ C# 使用 XML 文档注释为代码提供结构化文档。编译器从 `///`
✔️ 说明有效范围和边界值(如为 `null` 时的行为、取值范围)。
✔️ 完整语句末尾**建议**使用句号,短语式描述可省略。
❌ **禁止**仅重复参数名或类型名,如"url 参数"。
### 4.4 `<returns>` 书写规范
@@ -122,13 +149,25 @@ C# 使用 XML 文档注释为代码提供结构化文档。编译器从 `///`
✔️ 说明**特殊返回值**的含义(如返回 `null` 表示未找到)。
### 4.5 `<exception>` 书写规范
### 4.5 `<remarks>` 书写规范
✔️ 指定异常的**具体类型**`cref` 属性)
✔️ 多行内容**必须**用 `<para>` 包裹每段,否则 IDE 会将多行合并显示为一行
✔️ 说明异常的**触发条件**。
```csharp
// ✔️ 好:每段用 <para> 包裹
/// <remarks>
/// <para>下载并加载 Unity AssetBundle 资源包</para>
/// <para>支持 Unity 内置缓存机制和 CRC 校验</para>
/// </remarks>
✔️ 使用 `<paramref>` 引用相关参数。
// ❌ 差多行纯文本IDE 显示时会合并为一行
/// <remarks>
/// 下载并加载 Unity AssetBundle 资源包
/// 支持 Unity 内置缓存机制和 CRC 校验
/// </remarks>
```
✔️ 单行内容可直接书写,无需 `<para>`
---
@@ -141,8 +180,8 @@ C# 使用 XML 文档注释为代码提供结构化文档。编译器从 `///`
/// 资源包下载请求,负责管理单个资源包的下载生命周期。
/// </summary>
/// <remarks>
/// <para>支持断点续传和失败重试</para>
/// <para>通过 <see cref="DownloadRetryController"/> 控制重试策略</para>
/// <para>支持断点续传和失败重试</para>
/// <para>通过 <see cref="DownloadRetryController"/> 控制重试策略</para>
/// </remarks>
public class BundleDownloadRequest
{
@@ -153,16 +192,12 @@ public class BundleDownloadRequest
```csharp
/// <summary>
/// 从指定 URL 异步下载资源包并保存到本地磁盘
/// 从指定 URL 下载资源包并保存到本地磁盘
/// </summary>
/// <param name="url">资源包的完整下载地址</param>
/// <param name="savePath">本地保存的目标路径</param>
/// <param name="url">资源包的完整下载地址</param>
/// <param name="savePath">本地保存的目标路径</param>
/// <param name="timeout">超时时间0 表示不限制。</param>
/// <returns>下载结果,包含状态码和错误信息。</returns>
/// <exception cref="ArgumentNullException">
/// 当 <paramref name="url"/> 或 <paramref name="savePath"/> 为 <c>null</c> 时抛出。
/// </exception>
/// <exception cref="TimeoutException">当下载超过指定时间时抛出。</exception>
public async Task<DownloadResult> DownloadAsync(string url, string savePath, int timeout = 30)
{
}
@@ -172,7 +207,7 @@ public async Task<DownloadResult> DownloadAsync(string url, string savePath, int
```csharp
/// <summary>
/// 获取当前下载进度
/// 当前下载进度
/// </summary>
/// <value>取值范围 0.0 ~ 1.0,其中 1.0 表示下载完成。</value>
public float Progress { get; private set; }
@@ -182,7 +217,7 @@ public float Progress { get; private set; }
```csharp
/// <summary>
/// 下载任务的运行状态
/// 下载任务的运行状态
/// </summary>
public enum DownloadStatus
{
@@ -192,17 +227,17 @@ public enum DownloadStatus
Pending,
/// <summary>
/// 正在下载中
/// 正在下载中
/// </summary>
Downloading,
/// <summary>
/// 下载已完成
/// 下载已完成
/// </summary>
Completed,
/// <summary>
/// 下载失败
/// 下载失败
/// </summary>
Failed
}
@@ -224,17 +259,17 @@ public class ObjectPool<T> where T : IDisposable
```csharp
/// <summary>
/// 定义下载请求的标准行为
/// 定义下载请求的标准行为
/// </summary>
public interface IDownloadRequest
{
/// <summary>
/// 获取请求的远程 URL
/// 请求的远程 URL
/// </summary>
string URL { get; }
/// <summary>
/// 取消当前下载请求
/// 取消当前下载请求
/// </summary>
void Abort();
}
@@ -242,6 +277,10 @@ public interface IDownloadRequest
### 5.7 使用 `<inheritdoc/>`
#### 接口实现 —— 使用 `<inheritdoc/>`
实现接口成员时,使用 `<inheritdoc/>` 继承接口中定义的文档:
```csharp
public class MyDownloadRequest : IDownloadRequest
{
@@ -255,14 +294,35 @@ public class MyDownloadRequest : IDownloadRequest
}
```
#### 基类继承override —— 不添加任何注释
重写基类方法时,**不需要**添加任何 XML 文档注释(包括 `<inheritdoc/>`)。方法签名中的 `override` 关键字已明确表达继承关系IDE 会自动展示基类文档。
```csharp
// ✔️ 好override 方法不添加注释
protected override void InternalStart()
{
}
protected override void InternalUpdate()
{
}
// ❌ 差:多余的 inheritdoc
/// <inheritdoc/>
protected override void InternalStart()
{
}
```
### 5.8 使用 `<example>` 和 `<code>`
```csharp
/// <summary>
/// 根据资源路径异步加载资源对象
/// 根据资源路径加载资源对象
/// </summary>
/// <param name="assetPath">资源路径</param>
/// <returns>资源操作句柄,加载失败时资源对象为 <c>null</c>。</returns>
/// <param name="assetPath">资源路径</param>
/// <returns>资源操作句柄,加载失败时资源对象为 null。</returns>
/// <example>
/// 加载一个预制体:
/// <code>
@@ -291,10 +351,10 @@ public void Download(string url, string savePath) { }
// ✔️ 好:说明行为和目的
/// <summary>
/// 从远程服务器下载资源包并保存到本地磁盘
/// 从远程服务器下载资源包并保存到本地磁盘
/// </summary>
/// <param name="url">资源包的完整下载地址</param>
/// <param name="savePath">本地保存的目标路径</param>
/// <param name="url">资源包的完整下载地址</param>
/// <param name="savePath">本地保存的目标路径</param>
public void Download(string url, string savePath) { }
```
@@ -302,20 +362,36 @@ public void Download(string url, string savePath) { }
```csharp
// ❌ 差:仅重复参数名
/// <param name="name">名称</param>
/// <param name="name">名称</param>
// ✔️ 好:说明含义和约束
/// <param name="name">资源包的唯一标识名称,不可为 <c>null</c> 或空字符串。</param>
/// <param name="name">资源包的唯一标识名称</param>
```
### 6.3 缺少边界说明
### 6.3 重复命名后缀
```csharp
// ❌ 差:方法名 Async 后缀已表达异步语义
/// <summary>
/// 异步加载资源对象
/// </summary>
public AssetHandle LoadAssetAsync(string location) { }
// ✔️ 好:描述功能意图,不重复后缀语义
/// <summary>
/// 加载资源对象
/// </summary>
public AssetHandle LoadAssetAsync(string location) { }
```
### 6.4 缺少边界说明
```csharp
// ❌ 差:未说明返回 null 的情况
/// <returns>资源对象</returns>
/// <returns>资源对象</returns>
// ✔️ 好:说明特殊返回值
/// <returns>加载到的资源对象,如果资源不存在则返回 <c>null</c>。</returns>
/// <returns>加载到的资源对象</returns>
```
---
@@ -350,4 +426,78 @@ if (count > maxCount)
// 环形缓冲区写满后从头覆盖,避免无限增长
if (count > maxCount)
count = 0;
```
```
---
## 八、术语翻译映射表
> 为保持注释用语统一,以下列出项目中常用英文类型/概念与其中文翻译的对应关系。
> 撰写或审核注释时,请以此表为准。
### 8.1 核心领域类型
| 英文类型 / 概念 | 中文翻译 | 备注 |
|-----------------|---------|------|
| `PackageBundle` | 资源包描述 | 清单中的静态元数据(`Package*` = 描述) |
| `PackageAsset` | 资源描述 | 清单中的静态元数据(`Package*` = 描述) |
| `AssetInfo` | 资源信息 | 运行时上下文(`*Info` = 信息) |
| `BundleInfo` | 资源包信息 | 运行时上下文(`*Info` = 信息) |
| `ResourcePackage` | 资源包裹 | 顶层包裹容器 |
| `PackageManifest` | 包裹清单 / 资源清单 | — |
| `AssetBundle` | AssetBundle | Unity 引擎类型,保留英文 |
| `RawBundle` | 原生资源包 | 非 AssetBundle 的原始文件 |
### 8.2 文件系统与缓存
| 英文类型 / 概念 | 中文翻译 | 备注 |
|-----------------|---------|------|
| `IFileSystem` | 文件系统 | — |
| `IBundleCache` | 缓存系统 | — |
| `ICacheEntry` | 缓存条目 | — |
| `BundleGuid` | 资源包 GUID / Bundle 唯一标识 | — |
| `ICacheEvictionPolicy` | 淘汰策略 | — |
| `EvictionResult` | 淘汰结果 | — |
### 8.3 下载与网络
| 英文类型 / 概念 | 中文翻译 | 备注 |
|-----------------|---------|------|
| `IDownloadRequest` | 下载请求 | — |
| `IDownloadBackend` | 下载后台 | — |
| `IRemoteService` | 远端资源服务 | — |
| `IDownloadRetryPolicy` | 下载重试策略 | — |
| `IDownloadUrlPolicy` | URL 选择策略 | — |
### 8.4 加密与解密
| 英文类型 / 概念 | 中文翻译 | 备注 |
|-----------------|---------|------|
| `IBundleEncryptor` | 资源包加密器 | — |
| `IBundleDecryptor` | 资源包解密器 | 基接口,需实现派生接口 |
| `IManifestEncryptor` | 资源清单加密器 | — |
| `IManifestDecryptor` | 资源清单解密器 | — |
| `BundleEncryptArgs` | 加密操作的输入参数 | — |
| `BundleDecryptArgs` | 解密操作的输入参数 | — |
### 8.5 资源加载与句柄
| 英文类型 / 概念 | 中文翻译 | 备注 |
|-----------------|---------|------|
| `IBundleHandle` | 资源包句柄 | — |
| `AssetHandle` | 资源句柄 | — |
| `RawFileHandle` | 原生文件句柄 | — |
| `SubAssetsHandle` | 子资源句柄 | — |
### 8.6 通用术语
| 英文术语 | 中文翻译 | 备注 |
|---------|---------|------|
| Package | 包裹 | 项目级容器 |
| Bundle | 资源包 | 构建产物单元 |
| Asset | 资源 | 单个资源文件 |
| Manifest | 清单 | — |
| Handle | 句柄 | — |
| Operation | 操作 / 异步操作 | — |
| Scheduler | 调度器 | — |
| Provider | 提供者 | — |

View File

@@ -0,0 +1,200 @@
# 逻辑检测
> **总则**:检查运行时代码的关键逻辑路径,确保宏分支、异步操作生命周期、参数完整性和资源释放均无遗漏。
## 1. 宏包裹代码逻辑
检查所有 `#if` / `#elif` / `#else` / `#endif` 包裹的代码:
- 每个分支的变量赋值路径是否完整(不存在未赋值分支)
- `#else` 兜底分支是否覆盖所有未列出的平台
- 各分支之间的语义是否一致(同一变量在不同分支中的类型和用途是否相同)
- 分支中引用的 API 是否与对应宏版本匹配(如 `UNITY_2020_3_OR_NEWER` 对应的 API
## 2. 子异步操作检查
**定义**:通过 `AddChildOperation()` 添加的操作为子异步操作。
### 2.1 同步等待传播
如果类实现了 `InternalWaitForCompletion()` 方法,所有子异步操作必须在该方法中主动调用 `WaitForCompletion()`
```
❌ 父操作实现了 InternalWaitForCompletion但未对子操作调用 WaitForCompletion
✅ 父操作在 InternalWaitForCompletion 中对每个子操作调用 WaitForCompletion()
```
### 2.2 更新驱动
所有子异步操作必须在父操作的 `InternalUpdate()` 中主动调用 `UpdateOperation()`,确保子操作能被正常驱动。
```
❌ 子操作被 AddChildOperation 添加后,未在 InternalUpdate 中调用 UpdateOperation
✅ 每个子操作在 InternalUpdate 中被调用 UpdateOperation()
```
## 3. 异步操作参数完整性
检查所有 Operation 的 Options 在 `new` 的位置是否完整填充了所有成员字段。
- 找到 Options 结构体的所有字段定义
- 找到所有 `new XxxOptions(...)` 的调用点
- 逐一比对构造参数是否覆盖了所有必填字段
- 可选参数(有默认值)可以跳过
```
❌ new DownloadFileRequestOptions(url, savePath, timeout) // 遗漏了 watchdogTimeout
✅ new DownloadFileRequestOptions(url, savePath, timeout, watchdogTimeout)
```
## 4. 整数溢出与取模安全
检查所有对 `int` 计数器执行 `%`(取模)运算的位置,确保不会因溢出产生负索引。
- 只增不减的 `int` 计数器(如失败计数、轮转索引),溢出 `int.MaxValue` 后变为负数
- 负数 `%` 正数在 C# 中结果为负数,用作数组/列表索引会触发 `ArgumentOutOfRangeException`
- 使用 `& 0x7FFFFFFF` 清除符号位,保证结果始终为非负整数(.NET 中处理哈希取模的惯用手法)
```
❌ int index = _counter % list.Count; // _counter 溢出后 index 为负
✅ int index = (_counter & 0x7FFFFFFF) % list.Count; // 始终非负
```
## 5. 下载请求资源释放
### 5.1 IDownloadRequest 释放
检查所有持有 `IDownloadRequest`(及其子接口)实例的 Operation是否在 `InternalDispose()` 中调用了 `Dispose()` 释放资源。
```
❌ Operation 持有 IDownloadFileRequest 但未在 InternalDispose 中释放
✅ protected override void InternalDispose() { _request?.Dispose(); }
```
### 5.2 下载数据完整性验证
检查文件数据下载完成后,是否有容错或数据完整性验证:
- 是否校验文件大小(下载字节数与预期是否一致)
- 是否校验文件哈希CRC / MD5 / SHA 等)
- 如果无校验,是否有其他容错机制(如重试、回退)
- 无任何验证且无容错机制的,标记为需要关注
## 6. 计时方式一致性
检查所有需要"测量经过时间"的逻辑,确保计时方式不会因帧率波动或 App 后台恢复而失真。
- 使用 `Time.unscaledDeltaTime` 累加计时的方式,在 App 从后台恢复时会产生巨大 spike一帧跨越几十秒导致等待逻辑在单帧内被直接跳过
- 同一系统内应保持计时方式统一,避免一处用绝对时间戳、另一处用帧增量
- 推荐使用 `TimeUtility.RealtimeSinceStartup` 记录起止时间戳做差值判断
```
❌ _elapsed += Time.unscaledDeltaTime; return _elapsed >= delay; // 后台恢复时 spike 跳过等待
✅ return TimeUtility.RealtimeSinceStartup - _startTime >= delay; // 绝对时间戳,不受 spike 影响
```
## 7. 子类回调不得覆写基类已确定的状态
检查所有基类定义的"成功/失败回调"(如 `OnRequestSucceeded``OnRequestFailed`),子类在重写时不应直接修改基类已确定的 `Status`
- 基类在调用回调前已设置 `Status = Succeeded`,若子类在回调中将其改为 `Failed`,后续基类逻辑可能与实际状态不一致
- 回调应仅负责提取结果或设置错误信息,状态转换应由基类统一控制
- 推荐将回调签名改为返回 `bool`(或通过 out 参数传递错误),基类根据返回值决定最终状态
```
❌ protected override void OnRequestSucceeded()
{
if (result == null) Status = Failed; // 子类直接覆写基类已确定的 Succeeded 状态
}
✅ protected override bool OnRequestSucceeded()
{
if (result == null) { Error = "..."; return false; } // 返回 false由基类设置 Failed
return true;
}
```
## 8. 结构体不可变性检测
> 依据:[类型设计准则](2.类型设计准则.md) — "❌ **禁止**定义可变值类型" / "✔️ 声明不可变值类型时使用 `readonly struct` 修饰符"
检查所有 `struct` 定义,**必须**声明为 `readonly struct`。存在可变 struct 即为违规。
检测要点:
- `struct` 声明缺少 `readonly` 修饰符
- 属性使用 `{ get; set; }` 而非 `{ get; }`
- 公共字段未声明为 `readonly`
- 缺少构造函数(依赖默认值逐字段赋值的模式)
```
❌ struct MutableConfig
{
public int Timeout { get; set; } // 可变属性
public string Name { get; set; }
}
✅ readonly struct ImmutableConfig
{
public int Timeout { get; } // 只读属性
public string Name { get; }
public ImmutableConfig(int timeout, string name)
{
Timeout = timeout;
Name = name;
}
}
```
**禁止可变 struct 的原因**
- 值类型按值复制,可变成员修改作用于副本而非原值,极易产生静默 bug
- `readonly` 字段持有可变 struct 时,编译器每次访问都会产生防御性复制,造成不必要的性能开销
- `readonly struct` 从根源上杜绝以上两类问题
## 9. 文件系统禁止重写 GetHashCode
检查所有 `IFileSystem` 实现类,确认未重写 `GetHashCode()``Equals()`
`BundleInfo.GetCombineKey()` 依赖 `RuntimeHelpers.GetHashCode(_fileSystem)` 获取基于引用标识的哈希值,用于下载器合并时的去重判断。如果文件系统实现类重写了 `GetHashCode()`,虽然 `RuntimeHelpers.GetHashCode` 本身不受影响,但会暗示该类型有自定义相等性语义,可能导致其他使用 `GetHashCode()` 的位置产生非预期的碰撞。
检测要点:
- `IFileSystem` 实现类中存在 `override int GetHashCode()` 声明
- `IFileSystem` 实现类中存在 `override bool Equals(object)` 声明
```
❌ class SandboxFileSystem : IFileSystem
{
public override int GetHashCode() => PackageName.GetHashCode(); // 破坏引用标识语义
}
✅ class SandboxFileSystem : IFileSystem
{
// 不重写 GetHashCode保持 object 默认的引用标识行为
}
```
## 10. 不可变结构体命名参数检测
检测所有 `readonly struct` 构造函数调用中**位置参数 > 3 个**的位置,确认是否使用命名参数提高可读性。
`readonly struct` 只能通过构造函数一次性传入所有字段,参数数量通常较多,且参数顺序是唯一区分手段。同类型参数相邻时,顺序错误不会产生编译错误,容易引入静默 bug。
重点检查以下场景:
- 构造函数参数 > 3 个
- 多个同类型参数相邻(如连续多个 `bool``int`、接口类型)
- 参数名与属性名高度对应,使用命名参数可消除歧义
```
❌ new Configuration(60, true, level, decryptor, backend, retryPolicy, urlPolicy);
✅ new Configuration(
watchdogTimeout: 60,
disableUnityWebCache: true,
downloadVerifyLevel: level,
assetBundleDecryptor: decryptor,
downloadBackend: backend,
downloadRetryPolicy: retryPolicy,
downloadUrlPolicy: urlPolicy);
```

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 200087470392cf24ebdd0efac8e44210
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.IO;
using System.Collections;
using System.Collections.Generic;
@@ -146,7 +146,7 @@ namespace YooAsset.Editor
string message = BuildLogger.GetErrorMessage(ErrorCode.BuildPipelineIsNullOrEmpty, "Build pipeline is null or empty !");
throw new Exception(message);
}
if (BuildBundleType == (int)EBundleType.Unknown)
if (BuildBundleType == (int)EBundleType.None)
{
string message = BuildLogger.GetErrorMessage(ErrorCode.BuildBundleTypeIsUnknown, $"Build bundle type is unknown {BuildBundleType} !");
throw new Exception(message);

View File

@@ -54,8 +54,8 @@ namespace YooAsset.Editor
{
foreach (var packageBundle in manifest.BundleList)
{
string sourcePath = $"{packageOutputDirectory}/{packageBundle.FileName}";
string destPath = $"{buildinRootDirectory}/{packageBundle.FileName}";
string sourcePath = $"{packageOutputDirectory}/{packageBundle.GetFileName()}";
string destPath = $"{buildinRootDirectory}/{packageBundle.GetFileName()}";
EditorTools.CopyFile(sourcePath, destPath, true);
}
}
@@ -68,8 +68,8 @@ namespace YooAsset.Editor
{
if (packageBundle.HasAnyTag(tags) == false)
continue;
string sourcePath = $"{packageOutputDirectory}/{packageBundle.FileName}";
string destPath = $"{buildinRootDirectory}/{packageBundle.FileName}";
string sourcePath = $"{packageOutputDirectory}/{packageBundle.GetFileName()}";
string destPath = $"{buildinRootDirectory}/{packageBundle.GetFileName()}";
EditorTools.CopyFile(sourcePath, destPath, true);
}
}

View File

@@ -35,7 +35,7 @@ namespace YooAsset.Editor
manifest.EnableAddressable = buildMapContext.Command.EnableAddressable;
manifest.SupportExtensionless = buildMapContext.Command.SupportExtensionless;
manifest.LocationToLower = buildMapContext.Command.LocationToLower;
manifest.IncludeAssetGUID = buildMapContext.Command.IncludeAssetGUID;
manifest.IncludeAssetGuid = buildMapContext.Command.IncludeAssetGUID;
manifest.ReplaceAssetPathWithAddress = replaceAssetPathWithAddress;
manifest.OutputNameStyle = (int)buildParameters.FileNameStyle;
manifest.BuildBundleType = buildParameters.BuildBundleType;
@@ -152,7 +152,7 @@ namespace YooAsset.Editor
PackageAsset packageAsset = new PackageAsset();
packageAsset.Address = buildMapContext.Command.EnableAddressable ? assetInfo.Address : string.Empty;
packageAsset.AssetPath = assetInfo.AssetInfo.AssetPath;
packageAsset.AssetGUID = buildMapContext.Command.IncludeAssetGUID ? assetInfo.AssetInfo.AssetGUID : string.Empty;
packageAsset.AssetGuid = buildMapContext.Command.IncludeAssetGUID ? assetInfo.AssetInfo.AssetGUID : string.Empty;
packageAsset.AssetTags = assetInfo.AssetTags.ToArray();
packageAsset.EditorUserData = assetInfo;
result.Add(packageAsset);

View File

@@ -102,7 +102,7 @@ namespace YooAsset.Editor
{
ReportBundleInfo reportBundleInfo = new ReportBundleInfo();
reportBundleInfo.BundleName = packageBundle.BundleName;
reportBundleInfo.FileName = packageBundle.FileName;
reportBundleInfo.FileName = packageBundle.GetFileName();
reportBundleInfo.FileHash = packageBundle.FileHash;
reportBundleInfo.FileCRC = packageBundle.FileCrc;
reportBundleInfo.FileSize = packageBundle.FileSize;

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Linq;
using System.IO;
using System.Collections;
@@ -24,15 +24,14 @@ namespace YooAsset.Editor
string pipelineOutputDirectory = buildParametersContext.GetPipelineOutputDirectory();
foreach (var bundleInfo in buildMapContext.Collection)
{
BundleEncryptArgs args = new BundleEncryptArgs();
args.BundleName = bundleInfo.BundleName;
args.FilePath = $"{pipelineOutputDirectory}/{bundleInfo.BundleName}";
string filePath = $"{pipelineOutputDirectory}/{bundleInfo.BundleName}";
var args = new BundleEncryptArgs(bundleInfo.BundleName, filePath);
var encryptResult = encryptionServices.Encrypt(args);
if (encryptResult.Encrypted)
if (encryptResult.IsEncrypted)
{
string filePath = $"{pipelineOutputDirectory}/{bundleInfo.BundleName}.encrypt";
string encryptedFilePath = $"{pipelineOutputDirectory}/{bundleInfo.BundleName}.encrypt";
FileUtility.WriteAllBytes(filePath, encryptResult.EncryptedFileData);
bundleInfo.EncryptedFilePath = filePath;
bundleInfo.EncryptedFilePath = encryptedFilePath;
bundleInfo.Encrypted = true;
BuildLogger.Log($"Bundle file encryption complete: {filePath}");
}

View File

@@ -1,4 +1,4 @@
#if UNITY_2019_4_OR_NEWER
#if UNITY_2019_4_OR_NEWER
using System;
using System.Collections.Generic;
using UnityEditor;
@@ -255,7 +255,7 @@ namespace YooAsset.Editor
{
// 发送采集数据的命令
DiagnosticCommand command = new DiagnosticCommand();
command.CommandType = (int)EDiagnosticCommandType.AutoSampling;
command.CommandType = EDiagnosticCommandType.AutoSampling;
command.Parameter = evt.newValue ? "open" : "close";
byte[] data = DiagnosticCommand.Serialize(command);
EditorConnection.instance.Send(DiagnosticSystemConsts.EditorToPlayerMessageId, data);
@@ -266,7 +266,7 @@ namespace YooAsset.Editor
{
// 发送采集数据的命令
DiagnosticCommand command = new DiagnosticCommand();
command.CommandType = (int)EDiagnosticCommandType.SampleOnce;
command.CommandType = EDiagnosticCommandType.SampleOnce;
command.Parameter = string.Empty;
byte[] data = DiagnosticCommand.Serialize(command);
EditorConnection.instance.Send(DiagnosticSystemConsts.EditorToPlayerMessageId, data);

View File

@@ -379,7 +379,9 @@ namespace YooAsset.Editor
var sourceDatas = new List<ITableData>(providerInfo.Dependencies.Count);
foreach (var bundleName in providerInfo.Dependencies)
{
var dependBundleInfo = packageData.GetBundleInfo(bundleName);
if (packageData.TryGetBundleInfo(bundleName, out var dependBundleInfo) == false)
continue;
var rowData = new DependTableData();
rowData.BundleInfo = dependBundleInfo;
rowData.AddStringValueCell("DependBundles", dependBundleInfo.BundleName);

View File

@@ -468,7 +468,9 @@ namespace YooAsset.Editor
var sourceDatas = new List<ITableData>(1000);
foreach (string referenceBundleName in selectBundleInfo.Referencers)
{
var bundleInfo = packageData.GetBundleInfo(referenceBundleName);
if (packageData.TryGetBundleInfo(referenceBundleName, out var bundleInfo) == false)
continue;
var rowData = new ReferenceTableData();
rowData.BundleInfo = bundleInfo;
rowData.AddStringValueCell("BundleName", bundleInfo.BundleName);

View File

@@ -33,10 +33,10 @@ namespace YooAsset
internal bool IsWaitForCompletion { get; private set; }
/// <summary>
/// 判断当前帧时间切片是否已用完
/// 当前帧时间切片是否已用完
/// </summary>
/// <remarks>
/// 同步等待时始终返回 false以确保操作能持续执行直到完成
/// 同步等待时始终返回 false以确保操作能持续执行直到完成
/// </remarks>
protected bool IsBusy
{
@@ -73,7 +73,7 @@ namespace YooAsset
public float Progress { get; protected set; }
/// <summary>
/// 判断异步操作是否已结束
/// 异步操作是否已结束
/// </summary>
public bool IsDone
{
@@ -103,7 +103,7 @@ namespace YooAsset
/// 异步操作的完成事件
/// </summary>
/// <remarks>
/// 若注册时操作已完成,回调将立即执行
/// 若注册时操作已完成,回调将立即执行
/// </remarks>
public event Action<AsyncOperationBase> Completed
{
@@ -119,7 +119,7 @@ namespace YooAsset
}
catch (Exception ex)
{
YooLogger.Error($"Exception in completion callback: {ex}.");
YooLogger.LogError($"Exception in completion callback: {ex}.");
}
}
else
@@ -178,7 +178,7 @@ namespace YooAsset
{
_error = $"Operation '{GetType().Name}' did not complete during synchronous wait.";
_status = EOperationStatus.Failed;
YooLogger.Error(_error);
YooLogger.LogError(_error);
}
// 注意强制收尾确保Task能完成
@@ -209,7 +209,7 @@ namespace YooAsset
// 内部逻辑抛出异常一律视为该异步任务失败。
_error = ex.ToString();
_status = EOperationStatus.Failed;
YooLogger.Error($"Exception in {GetType().Name}.InternalStart: {ex}.");
YooLogger.LogError($"Exception in {GetType().Name}.InternalStart: {ex}.");
}
// 注意:同步完成的操作立即收尾
@@ -243,7 +243,7 @@ namespace YooAsset
// 内部逻辑抛出异常一律视为该异步任务失败。
_error = ex.ToString();
_status = EOperationStatus.Failed;
YooLogger.Error($"Exception in {GetType().Name}.InternalUpdate: {ex}.");
YooLogger.LogError($"Exception in {GetType().Name}.InternalUpdate: {ex}.");
}
}
@@ -271,7 +271,7 @@ namespace YooAsset
InternalAbort();
_error = "Operation was aborted.";
_status = EOperationStatus.Failed;
YooLogger.Warning($"Async operation '{GetType().Name}' has been aborted.");
YooLogger.LogWarning($"Async operation '{GetType().Name}' has been aborted.");
}
// 注意强制收尾确保Task能完成
@@ -316,7 +316,7 @@ namespace YooAsset
/// 内部同步等待方法(子类可选实现)
/// </summary>
/// <remarks>
/// 默认抛出异常,子类应重写以支持同步等待
/// 默认抛出异常,子类应重写以支持同步等待
/// </remarks>
protected virtual void InternalWaitForCompletion()
{
@@ -327,7 +327,6 @@ namespace YooAsset
/// <summary>
/// 将操作标记为成功完成
/// </summary>
/// <exception cref="InvalidOperationException">操作已处于终结状态时抛出</exception>
protected void SetResult()
{
if (IsDone)
@@ -340,7 +339,6 @@ namespace YooAsset
/// 将操作标记为失败
/// </summary>
/// <param name="error">错误描述</param>
/// <exception cref="InvalidOperationException">操作已处于终结状态时抛出</exception>
protected void SetError(string error)
{
if (IsDone)
@@ -350,6 +348,22 @@ namespace YooAsset
_status = EOperationStatus.Failed;
}
/// <summary>
/// 计算多阶段操作的整体进度
/// </summary>
/// <param name="stageIndex">当前阶段索引从0开始</param>
/// <param name="stageCount">阶段总数</param>
/// <param name="remaining">当前阶段剩余工作量</param>
/// <param name="total">当前阶段总工作量</param>
/// <returns>返回归一化的整体进度值0-1</returns>
protected float CalculateMultiStageProgress(int stageIndex, int stageCount, int remaining, int total)
{
if (total <= 0)
return (stageIndex + 1f) / stageCount;
float stageProgress = 1f - remaining / (float)total;
return (stageIndex + stageProgress) / stageCount;
}
/// <summary>
/// 添加子任务
/// </summary>
@@ -391,7 +405,7 @@ namespace YooAsset
throw new YooInternalException("Child operation is null.");
if (_children.Contains(child) == false)
throw new YooInternalException($"Child operation '{child.GetType().Name}' was not found.");
throw new YooInternalException($"Child operation '{child.GetType().Name}' not found.");
#endif
_children.Remove(child);
@@ -411,7 +425,7 @@ namespace YooAsset
/// <summary>
/// 批量执行一定次数的更新逻辑
/// </summary>
/// <param name="count">最大执行次数默认1000次</param>
/// <param name="count">最大执行次数默认1000次</param>
/// <remarks>
/// 用于需要快速完成但又不想完全阻塞主线程的场景
/// </remarks>
@@ -438,7 +452,7 @@ namespace YooAsset
/// </summary>
/// <param name="sleepMilliseconds">每次循环后的休眠时长(毫秒)</param>
/// <remarks>
/// 该方法会阻塞调用线程,每次更新之间会短暂休眠以避免占满 CPU
/// 该方法会阻塞调用线程,每次更新之间会短暂休眠以避免占满 CPU
/// </remarks>
protected void ExecuteUntilComplete(int sleepMilliseconds = 1)
{
@@ -475,7 +489,7 @@ namespace YooAsset
}
catch (Exception ex)
{
YooLogger.Error($"Exception in {GetType().Name}.InternalDispose: {ex}.");
YooLogger.LogError($"Exception in {GetType().Name}.InternalDispose: {ex}.");
}
InvokeCompletedCallbacks();
@@ -495,7 +509,7 @@ namespace YooAsset
}
catch (Exception ex)
{
YooLogger.Error($"Exception in completion callback: {ex}.");
YooLogger.LogError($"Exception in completion callback: {ex}.");
}
_completedCallback = null;
}
@@ -510,7 +524,7 @@ namespace YooAsset
}
catch (Exception ex)
{
YooLogger.Error($"Exception in completion callback: {ex}.");
YooLogger.LogError($"Exception in completion callback: {ex}.");
}
}
_completedCallbackList = null;

View File

@@ -47,7 +47,7 @@ namespace YooAsset
/// <summary>
/// 创建异步操作调度器实例
/// </summary>
/// <param name="packageName">所属包裹的名称</param>
/// <param name="packageName">所属包裹的名称</param>
/// <param name="creationOrder">创建顺序,用于同优先级时的稳定排序。</param>
public AsyncOperationScheduler(string packageName, int creationOrder)
{
@@ -60,7 +60,7 @@ namespace YooAsset
/// </summary>
/// <param name="operation">要启动的异步操作</param>
/// <remarks>
/// 操作立即启动,下一次 Update 时合并到执行队列
/// 操作立即启动,下一次 Update 时合并到执行队列
/// </remarks>
public void StartOperation(AsyncOperationBase operation)
{
@@ -146,7 +146,7 @@ namespace YooAsset
/// <summary>
/// 获取调试信息
/// </summary>
/// <returns>包含所有运行中和待处理操作的诊断信息列表</returns>
/// <returns>包含所有运行中和待处理操作的诊断信息列表</returns>
public List<DiagnosticOperationInfo> GetDiagnosticInfos()
{
int totalCount = _runningOperations.Count + _pendingOperations.Count;

View File

@@ -6,7 +6,7 @@ using System.Diagnostics;
namespace YooAsset
{
/// <summary>
/// 异步操作系统,负责管理所有包裹的调度器
/// 异步操作系统,负责管理所有包裹的调度器
/// </summary>
internal static class AsyncOperationSystem
{
@@ -40,7 +40,7 @@ namespace YooAsset
/// </summary>
/// <value>最小值为 <see cref="MinTimeSlice"/> 毫秒,低于此值将被自动钳制。</value>
/// <remarks>
/// 设置过小会导致每帧可执行的操作极少,影响整体加载速度
/// 设置过小会导致每帧可执行的操作极少,影响整体加载速度
/// </remarks>
public static long MaxTimeSlice
{
@@ -53,7 +53,7 @@ namespace YooAsset
if (value < MinTimeSlice)
{
_maxTimeSlice = MinTimeSlice;
YooLogger.Warning($"MaxTimeSlice must be at least {MinTimeSlice} ms, clamped to {MinTimeSlice}.");
YooLogger.LogWarning($"MaxTimeSlice must be at least {MinTimeSlice} ms, clamped to {MinTimeSlice}.");
}
else
{
@@ -63,7 +63,7 @@ namespace YooAsset
}
/// <summary>
/// 判断当前帧的时间切片预算是否已用完
/// 当前帧的时间切片预算是否已用完
/// </summary>
public static bool IsBusy
{
@@ -88,7 +88,7 @@ namespace YooAsset
{
if (_isInitialized)
{
YooLogger.Warning("Operation system is already initialized.");
YooLogger.LogWarning("Operation system is already initialized.");
return;
}
@@ -232,7 +232,7 @@ namespace YooAsset
/// 设置指定包裹调度器的优先级
/// </summary>
/// <param name="packageName">包裹名称</param>
/// <param name="priority">优先级,值越大越优</param>
/// <param name="priority">优先级,值越大越优</param>
public static void SetSchedulerPriority(string packageName, uint priority)
{
DebugCheckInitialized(packageName);
@@ -245,7 +245,7 @@ namespace YooAsset
/// 获取指定包裹调度器的优先级
/// </summary>
/// <param name="packageName">包裹名称</param>
/// <returns>调度器的当前优先级</returns>
/// <returns>调度器的当前优先级</returns>
public static uint GetSchedulerPriority(string packageName)
{
DebugCheckInitialized(packageName);
@@ -272,8 +272,8 @@ namespace YooAsset
/// <summary>
/// 获取指定包裹中所有操作的诊断信息
/// </summary>
/// <param name="packageName">包裹名称</param>
/// <returns>该包裹下所有操作的诊断信息列表</returns>
/// <param name="packageName">包裹名称</param>
/// <returns>该包裹下所有操作的诊断信息列表</returns>
internal static List<DiagnosticOperationInfo> GetDiagnosticInfos(string packageName)
{
DebugCheckInitialized(packageName);

View File

@@ -27,7 +27,7 @@ namespace YooAsset
/// 获取操作结果
/// </summary>
/// <remarks>
/// 业务失败不视为异常,此处不抛出异常
/// 业务失败不视为异常,此处不抛出异常
/// </remarks>
public void GetResult()
{
@@ -45,4 +45,4 @@ namespace YooAsset
_operation.Completed += (op) => continuation();
}
}
}
}

View File

@@ -7,56 +7,51 @@ namespace YooAsset
/// </summary>
internal readonly struct EvictionResult
{
private readonly bool _initialized;
/// <summary>
/// 错误信息
/// </summary>
public readonly string Error;
public string Error { get; }
/// <summary>
/// 需要清理的资源标识符集合
/// </summary>
public readonly List<string> BundleGUIDs;
public IReadOnlyList<string> BundleGuids { get; }
/// <summary>
/// 是否成功
/// 是否执行成功
/// </summary>
public bool Succeeded
{
get { return Error == null; }
get { return _initialized && Error == null; }
}
/// <summary>
/// 创建失败结果
/// </summary>
public EvictionResult(string error)
private EvictionResult(string error, IReadOnlyList<string> bundleGuids)
{
_initialized = true;
Error = error;
BundleGUIDs = null;
BundleGuids = bundleGuids;
}
/// <summary>
/// 创建成功结果
/// 创建表示执行成功的淘汰结果
/// </summary>
public EvictionResult(List<string> bundleGUIDs)
/// <param name="bundleGuids">需要清理的资源包标识符列表</param>
/// <returns>携带待清理列表的成功结果</returns>
public static EvictionResult CreateSuccess(IReadOnlyList<string> bundleGuids)
{
Error = null;
BundleGUIDs = bundleGUIDs;
return new EvictionResult(null, bundleGuids);
}
/// <summary>
/// 创建成功结果
/// 创建表示执行失败的淘汰结果
/// </summary>
public static EvictionResult Success(List<string> bundleGUIDs)
/// <param name="error">描述失败原因的错误信息</param>
/// <returns>携带错误信息的失败结果</returns>
public static EvictionResult CreateFailure(string error)
{
return new EvictionResult(bundleGUIDs);
}
/// <summary>
/// 创建失败结果
/// </summary>
public static EvictionResult Failure(string error)
{
return new EvictionResult(error);
return new EvictionResult(error, null);
}
}
}

View File

@@ -18,7 +18,7 @@ namespace YooAsset
string RootPath { get; }
/// <summary>
/// 只读属性
/// 是否为只读缓存
/// </summary>
bool IsReadOnly { get; }
@@ -34,33 +34,44 @@ namespace YooAsset
/// <summary>
/// 初始化文件缓存系统
/// 初始化缓存系统
/// </summary>
/// <returns>初始化异步操作对象</returns>
BCInitializeOperation InitializeAsync();
/// <summary>
/// 写入缓存文件
/// 将资源包数据写入缓存
/// </summary>
/// <param name="options">写入操作的配置参数</param>
/// <returns>写入缓存异步操作对象</returns>
BCWriteCacheOperation WriteCacheAsync(BCWriteCacheOptions options);
/// <summary>
/// 清理缓存文件
/// 清理符合淘汰策略的缓存文件
/// </summary>
/// <param name="options">清理操作的配置参数</param>
/// <returns>清理缓存异步操作对象</returns>
BCClearCacheOperation ClearCacheAsync(BCClearCacheOptions options);
/// <summary>
/// 验证缓存文件
/// 验证缓存文件的完整性
/// </summary>
/// <param name="options">验证操作的配置参数</param>
/// <returns>验证缓存异步操作对象</returns>
BCVerifyCacheOperation VerifyCacheAsync(BCVerifyCacheOptions options);
/// <summary>
/// 加载资源包
/// 加载指定资源包
/// </summary>
/// <param name="options">加载操作的配置参数</param>
/// <returns>加载资源包异步操作对象</returns>
BCLoadBundleOperation LoadBundleAsync(BCLoadBundleOptions options);
/// <summary>
/// 是否已缓存指定 Bundle
/// 检查指定资源包是否已存在于缓存中
/// </summary>
bool IsCached(string bundleGUID);
/// <param name="bundleGuid">资源包的唯一标识符</param>
/// <returns>如果缓存中存在该资源包则返回 true否则返回 false。</returns>
bool IsCached(string bundleGuid);
}
}

View File

@@ -7,8 +7,8 @@ namespace YooAsset
internal interface ICacheEntry
{
/// <summary>
/// Bundle唯一标识
/// Bundle 唯一标识
/// </summary>
string BundleGUID { get; }
string BundleGuid { get; }
}
}

View File

@@ -8,8 +8,11 @@ namespace YooAsset
internal interface ICacheEvictionPolicy
{
/// <summary>
/// 根据策略从缓存条目中选出需要清理的 BundleGUID 列表
/// 选出需要清理的 BundleGuid 列表
/// </summary>
/// <param name="cacheEntries">当前全部缓存条目的只读集合</param>
/// <param name="options">缓存清理的配置参数</param>
/// <returns>包含待清理 BundleGuid 列表的执行结果,失败时携带错误信息。</returns>
EvictionResult SelectEvictionTargets(IReadOnlyCollection<ICacheEntry> cacheEntries, BCClearCacheOptions options);
}
}

View File

@@ -11,14 +11,22 @@ namespace YooAsset
/// <summary>
/// 清理缓存完成操作
/// </summary>
internal class BCClearCacheCompleteOperation : BCClearCacheOperation
internal sealed class BCClearCacheCompleteOperation : BCClearCacheOperation
{
private readonly string _error;
/// <summary>
/// 创建清理缓存完成操作实例
/// </summary>
public BCClearCacheCompleteOperation()
{
_error = null;
}
/// <summary>
/// 创建清理缓存完成操作实例
/// </summary>
/// <param name="error">错误信息</param>
public BCClearCacheCompleteOperation(string error)
{
_error = error;

View File

@@ -4,21 +4,28 @@ namespace YooAsset
/// <summary>
/// 清理缓存操作选项
/// </summary>
internal struct BCClearCacheOptions
internal readonly struct BCClearCacheOptions
{
/// <summary>
/// 清理方式
/// </summary>
public string ClearMethod { get; set; }
public string ClearMethod { get; }
/// <summary>
/// 附加参数
/// </summary>
public object ClearParameter { get; set; }
public object ClearParameter { get; }
/// <summary>
/// 资源清单
/// </summary>
public PackageManifest Manifest { get; set; }
public PackageManifest Manifest { get; }
public BCClearCacheOptions(string clearMethod, object clearParameter, PackageManifest manifest)
{
ClearMethod = clearMethod;
ClearParameter = clearParameter;
Manifest = manifest;
}
}
}

View File

@@ -6,6 +6,9 @@ namespace YooAsset
/// </summary>
internal abstract class BCLoadBundleOperation : AsyncOperationBase
{
/// <summary>
/// 资源包加载的内部结果
/// </summary>
protected readonly struct LoadResult
{
/// <summary>
@@ -14,22 +17,32 @@ namespace YooAsset
public readonly string Error;
/// <summary>
/// 是否成功
/// 加载是否成功
/// </summary>
public bool Succeeded
{
get { return Error == null; }
}
public LoadResult(string error)
private LoadResult(string error)
{
Error = error;
}
/// <summary>
/// 创建表示加载成功的默认结果
/// </summary>
/// <returns>不携带错误信息的成功结果</returns>
public static LoadResult Default()
{
return new LoadResult(null);
}
/// <summary>
/// 创建表示加载失败的结果
/// </summary>
/// <param name="error">错误信息</param>
/// <returns>携带错误信息的失败结果</returns>
public static LoadResult Failure(string error)
{
return new LoadResult(error);
@@ -49,6 +62,10 @@ namespace YooAsset
{
private readonly string _error;
/// <summary>
/// 创建加载资源包错误操作实例
/// </summary>
/// <param name="error">错误信息</param>
internal BCLoadBundleErrorOperation(string error)
{
_error = error;

View File

@@ -7,10 +7,14 @@ namespace YooAsset
internal readonly struct BCLoadBundleOptions
{
/// <summary>
/// 资源包
/// 要加载的资源包
/// </summary>
public readonly PackageBundle Bundle;
public PackageBundle Bundle { get; }
/// <summary>
/// 创建加载资源包操作选项实例
/// </summary>
/// <param name="bundle">要加载的资源包描述</param>
public BCLoadBundleOptions(PackageBundle bundle)
{
Bundle = bundle;

View File

@@ -11,14 +11,23 @@ namespace YooAsset
/// <summary>
/// 验证缓存完成操作
/// </summary>
internal class BCVerifyCacheCompleteOperation : BCVerifyCacheOperation
internal sealed class BCVerifyCacheCompleteOperation : BCVerifyCacheOperation
{
private readonly string _error;
/// <summary>
/// 创建验证缓存完成操作实例
/// </summary>
public BCVerifyCacheCompleteOperation()
{
_error = null;
}
/// <summary>
/// 创建验证缓存完成操作实例
/// </summary>
/// <param name="error">错误信息</param>
public BCVerifyCacheCompleteOperation(string error)
{
_error = error;

View File

@@ -4,16 +4,22 @@ namespace YooAsset
/// <summary>
/// 验证缓存操作选项
/// </summary>
internal struct BCVerifyCacheOptions
internal readonly struct BCVerifyCacheOptions
{
/// <summary>
/// 要验证的资源包
/// </summary>
public PackageBundle Bundle { get; set; }
public PackageBundle Bundle { get; }
/// <summary>
/// 失败后直接移除缓存条目
/// </summary>
public bool DeleteCacheEntryOnFailure { get; set; }
public bool DeleteCacheEntryOnFailure { get; }
public BCVerifyCacheOptions(PackageBundle bundle, bool deleteCacheEntryOnFailure)
{
Bundle = bundle;
DeleteCacheEntryOnFailure = deleteCacheEntryOnFailure;
}
}
}

View File

@@ -11,14 +11,22 @@ namespace YooAsset
/// <summary>
/// 写入缓存完成操作
/// </summary>
internal class BCWriteCacheCompleteOperation : BCWriteCacheOperation
internal sealed class BCWriteCacheCompleteOperation : BCWriteCacheOperation
{
private readonly string _error;
/// <summary>
/// 创建写入缓存完成操作实例
/// </summary>
public BCWriteCacheCompleteOperation()
{
_error = null;
}
/// <summary>
/// 创建写入缓存完成操作实例
/// </summary>
/// <param name="error">错误信息</param>
public BCWriteCacheCompleteOperation(string error)
{
_error = error;

View File

@@ -4,21 +4,28 @@ namespace YooAsset
/// <summary>
/// 写入缓存操作选项
/// </summary>
internal struct BCWriteCacheOptions
internal readonly struct BCWriteCacheOptions
{
/// <summary>
/// 要缓存的资源包
/// </summary>
public PackageBundle Bundle { get; set; }
public PackageBundle Bundle { get; }
/// <summary>
/// 要缓存的文件路径
/// </summary>
public string FilePath { get; set; }
public string FilePath { get; }
/// <summary>
/// 要缓存的文件数据(可选)
/// </summary>
public byte[] FileData { get; set; }
public byte[] FileData { get; }
public BCWriteCacheOptions(PackageBundle bundle, string filePath, byte[] fileData = null)
{
Bundle = bundle;
FilePath = filePath;
FileData = fileData;
}
}
}

View File

@@ -28,6 +28,10 @@ namespace YooAsset
/// </summary>
public BuiltinCatalog Catalog;
/// <summary>
/// 创建加载内置资源目录操作实例
/// </summary>
/// <param name="options">加载内置资源目录的配置选项</param>
internal LoadBuiltinCatalogOperation(LoadBuiltinCatalogOptions options)
{
_options = options;
@@ -69,7 +73,10 @@ namespace YooAsset
if (_downloadBytesRequest == null)
{
string url = DownloadUrlHelper.ToLocalFileUrl(_options.FilePath);
var args = new DownloadDataRequestArgs(url, 60, 0);
var args = new DownloadDataRequestArgs(
url: url,
timeout: 60,
watchdogTimeout: 0);
_downloadBytesRequest = _options.DownloadBackend.CreateBytesRequest(args);
_downloadBytesRequest.SendRequest();
}

View File

@@ -4,21 +4,28 @@ namespace YooAsset
/// <summary>
/// 加载内置资源目录操作选项
/// </summary>
internal struct LoadBuiltinCatalogOptions
internal readonly struct LoadBuiltinCatalogOptions
{
/// <summary>
/// 包裹名称
/// </summary>
public string PackageName { get; set; }
public string PackageName { get; }
/// <summary>
/// 文件路径
/// </summary>
public string FilePath { get; set; }
public string FilePath { get; }
/// <summary>
/// 下载后台
/// </summary>
public IDownloadBackend DownloadBackend { get; set; }
public IDownloadBackend DownloadBackend { get; }
public LoadBuiltinCatalogOptions(string packageName, string filePath, IDownloadBackend downloadBackend)
{
PackageName = packageName;
FilePath = filePath;
DownloadBackend = downloadBackend;
}
}
}

View File

@@ -6,7 +6,7 @@ namespace YooAsset
/// <summary>
/// 从本地文件加载 AssetBundle 操作
/// </summary>
internal class LoadLocalAssetBundleOperation : BCLoadBundleOperation
internal sealed class LoadLocalAssetBundleOperation : BCLoadBundleOperation
{
private enum ESteps
{
@@ -27,6 +27,10 @@ namespace YooAsset
/// </summary>
public bool UnityEngineLoadFailed { get; private set; } = false;
/// <summary>
/// 创建本地 AssetBundle 加载操作实例
/// </summary>
/// <param name="options">从本地加载 AssetBundle 的配置选项</param>
public LoadLocalAssetBundleOperation(LoadLocalAssetBundleOptions options)
{
_options = options;
@@ -95,7 +99,7 @@ namespace YooAsset
if (IsWaitForCompletion)
{
// 强制挂起主线程(注意:该操作会很耗时)
YooLogger.Warning("Suspending the main thread to load Unity bundle.");
YooLogger.LogWarning("Suspending the main thread to load Unity bundle.");
_assetBundle = _createRequest.assetBundle;
}
else
@@ -135,10 +139,11 @@ namespace YooAsset
}
private LoadResult LoadFromFileWithOffset(IBundleOffsetDecryptor decryptor)
{
var args = new BundleDecryptArgs();
args.Bundle = _options.Bundle;
args.FilePath = _options.FilePath;
ulong offset = (ulong)decryptor.GetFileOffset(args);
var args = new BundleDecryptArgs(_options.Bundle, null, _options.FilePath);
long rawOffset = decryptor.GetFileOffset(args);
if (rawOffset < 0)
return LoadResult.Failure($"{_options.CacheName} decryptor returned negative offset: {rawOffset}.");
ulong offset = (ulong)rawOffset;
if (IsWaitForCompletion)
_assetBundle = AssetBundle.LoadFromFile(_options.FilePath, 0, offset);
@@ -149,9 +154,7 @@ namespace YooAsset
}
private LoadResult LoadFromMemory(IBundleMemoryDecryptor decryptor)
{
var args = new BundleDecryptArgs();
args.Bundle = _options.Bundle;
args.FilePath = _options.FilePath;
var args = new BundleDecryptArgs(_options.Bundle, null, _options.FilePath);
var binaryData = decryptor.GetDecryptedData(args);
if (binaryData == null)
return LoadResult.Failure($"{_options.CacheName} decryptor returned null data.");
@@ -165,9 +168,7 @@ namespace YooAsset
}
private LoadResult LoadFromStream(IBundleStreamDecryptor decryptor)
{
var args = new BundleDecryptArgs();
args.Bundle = _options.Bundle;
args.FilePath = _options.FilePath;
var args = new BundleDecryptArgs(_options.Bundle, null, _options.FilePath);
uint bufferSize = (uint)decryptor.GetBufferSize(args);
_loadStream = decryptor.CreateDecryptionStream(args);
if (_loadStream == null)

View File

@@ -4,27 +4,35 @@ namespace YooAsset
/// <summary>
/// 加载 AssetBundle 的上下文信息
/// </summary>
internal struct LoadLocalAssetBundleOptions
internal readonly struct LoadLocalAssetBundleOptions
{
/// <summary>
/// 文件缓存名称
/// </summary>
public string CacheName { get; set; }
public string CacheName { get; }
/// <summary>
/// 资源包信息
/// 资源包描述
/// </summary>
public PackageBundle Bundle { get; set; }
public PackageBundle Bundle { get; }
/// <summary>
/// 文件加载路径
/// </summary>
public string FilePath { get; set; }
public string FilePath { get; }
/// <summary>
/// AssetBundle 解密器
/// </summary>
public IBundleDecryptor AssetBundleDecryptor { get; set; }
public IBundleDecryptor AssetBundleDecryptor { get; }
public LoadLocalAssetBundleOptions(string cacheName, PackageBundle bundle, string filePath, IBundleDecryptor assetBundleDecryptor)
{
CacheName = cacheName;
Bundle = bundle;
FilePath = filePath;
AssetBundleDecryptor = assetBundleDecryptor;
}
}
}

View File

@@ -6,7 +6,7 @@ namespace YooAsset
/// <summary>
/// 从本地加载 RawBundle 操作
/// </summary>
internal class LoadLocalRawBundleOperation : BCLoadBundleOperation
internal sealed class LoadLocalRawBundleOperation : BCLoadBundleOperation
{
private enum ESteps
{
@@ -16,10 +16,14 @@ namespace YooAsset
Done,
}
protected readonly LoadLocalRawBundleOptions _options;
private readonly LoadLocalRawBundleOptions _options;
private RawBundle _rawBundle;
private ESteps _steps = ESteps.None;
/// <summary>
/// 创建本地 RawBundle 加载操作实例
/// </summary>
/// <param name="options">从本地加载 RawBundle 的配置选项</param>
public LoadLocalRawBundleOperation(LoadLocalRawBundleOptions options)
{
_options = options;
@@ -44,7 +48,13 @@ namespace YooAsset
return;
}
LoadFromFile();
LoadResult result = LoadFromFile();
if (result.Succeeded == false)
{
_steps = ESteps.Done;
SetError(result.Error);
return;
}
}
else
{
@@ -99,16 +109,22 @@ namespace YooAsset
ExecuteBatch();
}
private void LoadFromFile()
private LoadResult LoadFromFile()
{
byte[] data = File.ReadAllBytes(_options.FilePath);
_rawBundle = new RawBundle(data);
try
{
byte[] data = File.ReadAllBytes(_options.FilePath);
_rawBundle = new RawBundle(data);
return LoadResult.Default();
}
catch (Exception ex)
{
return LoadResult.Failure($"Failed to read raw bundle file: {ex.Message}.");
}
}
private LoadResult LoadFromMemory(IBundleMemoryDecryptor decryptor)
{
var args = new BundleDecryptArgs();
args.Bundle = _options.Bundle;
args.FilePath = _options.FilePath;
var args = new BundleDecryptArgs(_options.Bundle, null, _options.FilePath);
var binaryData = decryptor.GetDecryptedData(args);
if (binaryData == null)
return LoadResult.Failure($"{_options.CacheName} decryptor returned null data.");

View File

@@ -4,26 +4,34 @@ namespace YooAsset
/// <summary>
/// 加载 RawBundle 的上下文信息
/// </summary>
internal struct LoadLocalRawBundleOptions
internal readonly struct LoadLocalRawBundleOptions
{
/// <summary>
/// 文件缓存名称
/// </summary>
public string CacheName { get; set; }
public string CacheName { get; }
/// <summary>
/// 资源包信息
/// 资源包描述
/// </summary>
public PackageBundle Bundle { get; set; }
public PackageBundle Bundle { get; }
/// <summary>
/// 文件加载路径
/// </summary>
public string FilePath { get; set; }
public string FilePath { get; }
/// <summary>
/// RawBundle 解密器
/// </summary>
public IBundleDecryptor RawBundleDecryptor { get; set; }
public IBundleDecryptor RawBundleDecryptor { get; }
public LoadLocalRawBundleOptions(string cacheName, PackageBundle bundle, string filePath, IBundleDecryptor rawBundleDecryptor)
{
CacheName = cacheName;
Bundle = bundle;
FilePath = filePath;
RawBundleDecryptor = rawBundleDecryptor;
}
}
}

View File

@@ -12,7 +12,7 @@ namespace YooAsset
/// <summary>
/// 从网络加载未加密 AssetBundle 操作
/// </summary>
internal class LoadWebNormalAssetBundleOperation : LoadWebAssetBundleOperation
internal sealed class LoadWebNormalAssetBundleOperation : LoadWebAssetBundleOperation
{
private enum ESteps
{
@@ -28,6 +28,10 @@ namespace YooAsset
private IDownloadAssetBundleRequest _downloadAssetBundleRequest;
private ESteps _steps = ESteps.None;
/// <summary>
/// 创建网络未加密 AssetBundle 加载操作实例
/// </summary>
/// <param name="options">从网络加载 AssetBundle 的配置选项</param>
public LoadWebNormalAssetBundleOperation(LoadWebAssetBundleOptions options)
{
_options = options;
@@ -47,7 +51,13 @@ namespace YooAsset
if (_steps == ESteps.BundleRequest)
{
string url = GetRequestUrl();
var args = new DownloadAssetBundleRequestArgs(url, 0, _options.WatchdogTimeout, _options.DisableUnityWebCache, _options.Bundle.FileHash, _options.Bundle.UnityCrc);
var args = new DownloadAssetBundleRequestArgs(
url: url,
timeout: 0,
watchdogTimeout: _options.WatchdogTimeout,
disableUnityWebCache: _options.DisableUnityWebCache,
fileHash: _options.Bundle.FileHash,
unityCrc: _options.Bundle.UnityCrc);
_downloadAssetBundleRequest = _options.DownloadBackend.CreateAssetBundleRequest(args);
_downloadAssetBundleRequest.SendRequest();
_steps = ESteps.CheckRequest;
@@ -66,7 +76,7 @@ namespace YooAsset
if (assetBundle == null)
{
_steps = ESteps.Done;
SetError($"Fatal error: downloaded asset bundle is null.");
SetError("Downloaded asset bundle is null.");
}
else
{
@@ -128,7 +138,7 @@ namespace YooAsset
/// <summary>
/// 从网络加载加密的 AssetBundle 操作
/// </summary>
internal class LoadWebEncryptedAssetBundleOperation : LoadWebAssetBundleOperation
internal sealed class LoadWebEncryptedAssetBundleOperation : LoadWebAssetBundleOperation
{
private enum ESteps
{
@@ -149,6 +159,10 @@ namespace YooAsset
private AssetBundleCreateRequest _createRequest;
private ESteps _steps = ESteps.None;
/// <summary>
/// 创建网络加密 AssetBundle 加载操作实例
/// </summary>
/// <param name="options">从网络加载 AssetBundle 的配置选项</param>
public LoadWebEncryptedAssetBundleOperation(LoadWebAssetBundleOptions options)
{
_options = options;
@@ -179,7 +193,10 @@ namespace YooAsset
{
_decryptor = decryptor as IBundleMemoryDecryptor;
string url = GetRequestUrl();
var args = new DownloadDataRequestArgs(url, 0, _options.WatchdogTimeout);
var args = new DownloadDataRequestArgs(
url: url,
timeout: 0,
watchdogTimeout: _options.WatchdogTimeout);
_downloadBytesRequest = _options.DownloadBackend.CreateBytesRequest(args);
_downloadBytesRequest.SendRequest();
_steps = ESteps.CheckRequest;
@@ -231,7 +248,7 @@ namespace YooAsset
else if (_options.DownloadVerifyLevel == EFileVerifyLevel.High)
verifyResult = FileVerifyHelper.VerifyFile(_downloadBytesRequest.Result, _options.Bundle.FileSize, _options.Bundle.FileCrc);
else
throw new System.NotImplementedException(_options.DownloadVerifyLevel.ToString());
throw new YooInternalException($"Unexpected verify level: {_options.DownloadVerifyLevel}.");
if (verifyResult == EFileVerifyResult.Succeed)
{
@@ -240,7 +257,7 @@ namespace YooAsset
else
{
string error = $"[WebBundleVerify] Verify failed. Url: '{_downloadBytesRequest.Url}' Level: {_options.DownloadVerifyLevel} Result: {verifyResult}.";
YooLogger.Warning(error);
YooLogger.LogWarning(error);
if (IsWaitForCompletion == false && _downloadRetryController.HasRetriesRemaining())
{
@@ -314,9 +331,7 @@ namespace YooAsset
private LoadResult LoadFromMemory(IBundleMemoryDecryptor decryptor, byte[] fileData)
{
var args = new BundleDecryptArgs();
args.Bundle = _options.Bundle;
args.FileData = fileData;
var args = new BundleDecryptArgs(_options.Bundle, fileData, null);
var binaryData = decryptor.GetDecryptedData(args);
if (binaryData == null)
return LoadResult.Failure($"{_options.CacheName} decryptor returned null data.");

View File

@@ -5,56 +5,70 @@ namespace YooAsset
/// <summary>
/// 加载 AssetBundle 的上下文信息
/// </summary>
internal struct LoadWebAssetBundleOptions
internal readonly struct LoadWebAssetBundleOptions
{
/// <summary>
/// 文件缓存名称
/// </summary>
public string CacheName { get; set; }
public string CacheName { get; }
/// <summary>
/// 资源包信息
/// 资源包描述
/// </summary>
public PackageBundle Bundle { get; set; }
public PackageBundle Bundle { get; }
/// <summary>
/// 候选下载地址列表
/// </summary>
public IReadOnlyList<string> CandidateUrls { get; set; }
public IReadOnlyList<string> CandidateUrls { get; }
/// <summary>
/// AssetBundle 解密器
/// </summary>
public IBundleDecryptor AssetBundleDecryptor { get; set; }
public IBundleDecryptor AssetBundleDecryptor { get; }
/// <summary>
/// 下载后台接口
/// </summary>
public IDownloadBackend DownloadBackend { get; set; }
public IDownloadBackend DownloadBackend { get; }
/// <summary>
/// 下载数据校验级别
/// </summary>
public EFileVerifyLevel DownloadVerifyLevel { get; set; }
public EFileVerifyLevel DownloadVerifyLevel { get; }
/// <summary>
/// 看门狗超时时间
/// </summary>
public int WatchdogTimeout { get; set; }
public int WatchdogTimeout { get; }
/// <summary>
/// 禁用Unity的网络缓存
/// </summary>
public bool DisableUnityWebCache { get; set; }
public bool DisableUnityWebCache { get; }
/// <summary>
/// 下载重试判定策略
/// </summary>
public IDownloadRetryPolicy DownloadRetryPolicy { get; set; }
public IDownloadRetryPolicy DownloadRetryPolicy { get; }
/// <summary>
/// URL 选择策略
/// </summary>
public IDownloadUrlPolicy DownloadUrlPolicy { get; set; }
public IDownloadUrlPolicy DownloadUrlPolicy { get; }
public LoadWebAssetBundleOptions(string cacheName, PackageBundle bundle, IReadOnlyList<string> candidateUrls, IBundleDecryptor assetBundleDecryptor, IDownloadBackend downloadBackend, EFileVerifyLevel downloadVerifyLevel, int watchdogTimeout, bool disableUnityWebCache, IDownloadRetryPolicy downloadRetryPolicy, IDownloadUrlPolicy downloadUrlPolicy)
{
CacheName = cacheName;
Bundle = bundle;
CandidateUrls = candidateUrls;
AssetBundleDecryptor = assetBundleDecryptor;
DownloadBackend = downloadBackend;
DownloadVerifyLevel = downloadVerifyLevel;
WatchdogTimeout = watchdogTimeout;
DisableUnityWebCache = disableUnityWebCache;
DownloadRetryPolicy = downloadRetryPolicy;
DownloadUrlPolicy = downloadUrlPolicy;
}
}
}

View File

@@ -10,12 +10,12 @@ namespace YooAsset
/// <inheritdoc />
public EvictionResult SelectEvictionTargets(IReadOnlyCollection<ICacheEntry> cacheEntries, BCClearCacheOptions options)
{
var bundleGUIDs = new List<string>(cacheEntries.Count);
var bundleGuids = new List<string>(cacheEntries.Count);
foreach (var entry in cacheEntries)
{
bundleGUIDs.Add(entry.BundleGUID);
bundleGuids.Add(entry.BundleGuid);
}
return EvictionResult.Success(bundleGUIDs);
return EvictionResult.CreateSuccess(bundleGuids);
}
}
}

View File

@@ -14,9 +14,9 @@ namespace YooAsset
public EvictionResult SelectEvictionTargets(IReadOnlyCollection<ICacheEntry> cacheEntries, BCClearCacheOptions options)
{
if (options.Manifest == null)
return EvictionResult.Failure("Active package manifest not found.");
return EvictionResult.CreateFailure("Active package manifest not found.");
if (options.ClearParameter == null)
return EvictionResult.Failure("Clear param is null.");
return EvictionResult.CreateFailure("Clear param is null.");
string[] locations;
if (options.ClearParameter is string str)
@@ -26,19 +26,19 @@ namespace YooAsset
else if (options.ClearParameter is string[] array)
locations = array;
else
return EvictionResult.Failure($"Invalid clear param: {options.ClearParameter.GetType().FullName}");
return EvictionResult.CreateFailure($"Invalid clear param: {options.ClearParameter.GetType().FullName}");
var bundleGUIDs = new List<string>(locations.Length);
var bundleGuids = new List<string>(locations.Length);
foreach (var location in locations)
{
string assetPath = options.Manifest.TryMappingToAssetPath(location);
if (options.Manifest.TryGetPackageAsset(assetPath, out PackageAsset packageAsset))
{
PackageBundle bundle = options.Manifest.GetMainPackageBundle(packageAsset.BundleID);
bundleGUIDs.Add(bundle.BundleGuid);
bundleGuids.Add(bundle.BundleGuid);
}
}
return EvictionResult.Success(bundleGUIDs);
return EvictionResult.CreateSuccess(bundleGuids);
}
}
}

View File

@@ -14,9 +14,9 @@ namespace YooAsset
public EvictionResult SelectEvictionTargets(IReadOnlyCollection<ICacheEntry> cacheEntries, BCClearCacheOptions options)
{
if (options.Manifest == null)
return EvictionResult.Failure("Active package manifest not found.");
return EvictionResult.CreateFailure("Active package manifest not found.");
if (options.ClearParameter == null)
return EvictionResult.Failure("Clear param is null.");
return EvictionResult.CreateFailure("Clear param is null.");
string[] tags;
if (options.ClearParameter is string str)
@@ -26,18 +26,18 @@ namespace YooAsset
else if (options.ClearParameter is string[] array)
tags = array;
else
return EvictionResult.Failure($"Invalid clear param: {options.ClearParameter.GetType().FullName}");
return EvictionResult.CreateFailure($"Invalid clear param: {options.ClearParameter.GetType().FullName}");
var bundleGUIDs = new List<string>(cacheEntries.Count);
var bundleGuids = new List<string>(cacheEntries.Count);
foreach (var entry in cacheEntries)
{
if (options.Manifest.TryGetPackageBundleByBundleGUID(entry.BundleGUID, out PackageBundle bundle))
if (options.Manifest.TryGetPackageBundleByBundleGuid(entry.BundleGuid, out PackageBundle bundle))
{
if (bundle.HasAnyTag(tags))
bundleGUIDs.Add(bundle.BundleGuid);
bundleGuids.Add(bundle.BundleGuid);
}
}
return EvictionResult.Success(bundleGUIDs);
return EvictionResult.CreateSuccess(bundleGuids);
}
}
}

View File

@@ -11,17 +11,17 @@ namespace YooAsset
public EvictionResult SelectEvictionTargets(IReadOnlyCollection<ICacheEntry> cacheEntries, BCClearCacheOptions options)
{
if (options.Manifest == null)
return EvictionResult.Failure("Active package manifest not found.");
return EvictionResult.CreateFailure("Active package manifest not found.");
var bundleGUIDs = new List<string>(cacheEntries.Count);
var bundleGuids = new List<string>(cacheEntries.Count);
foreach (var entry in cacheEntries)
{
if (options.Manifest.ContainsBundle(entry.BundleGUID) == false)
if (options.Manifest.ContainsBundle(entry.BundleGuid) == false)
{
bundleGUIDs.Add(entry.BundleGUID);
bundleGuids.Add(entry.BundleGuid);
}
}
return EvictionResult.Success(bundleGUIDs);
return EvictionResult.CreateSuccess(bundleGuids);
}
}
}

View File

@@ -4,29 +4,36 @@ using System.Collections.Generic;
namespace YooAsset
{
/// <summary>
/// 内置文件缓存系统,用于管理 StreamingAssets 中的资源包
/// 内置文件缓存系统,用于管理 StreamingAssets 中的资源包
/// </summary>
internal class BuiltinBundleCache : IBundleCache
{
/// <summary>
/// 内置文件缓存配置
/// </summary>
internal struct Configuration
internal readonly struct Configuration
{
/// <summary>
/// AssetBundle 解密器
/// </summary>
public IBundleDecryptor AssetBundleDecryptor { get; set; }
public IBundleDecryptor AssetBundleDecryptor { get; }
/// <summary>
/// RawBundle 解密器
/// </summary>
public IBundleDecryptor RawBundleDecryptor { get; set; }
public IBundleDecryptor RawBundleDecryptor { get; }
/// <summary>
/// 下载后台
/// </summary>
public IDownloadBackend DownloadBackend { get; set; }
public IDownloadBackend DownloadBackend { get; }
public Configuration(IBundleDecryptor assetBundleDecryptor, IBundleDecryptor rawBundleDecryptor, IDownloadBackend downloadBackend)
{
AssetBundleDecryptor = assetBundleDecryptor;
RawBundleDecryptor = rawBundleDecryptor;
DownloadBackend = downloadBackend;
}
}
private readonly Dictionary<string, BuiltinBundleCacheEntry> _cacheEntries = new Dictionary<string, BuiltinBundleCacheEntry>(10000);
@@ -48,7 +55,7 @@ namespace YooAsset
public string RootPath { get; }
/// <summary>
/// 只读属性
/// 是否为只读缓存
/// </summary>
public bool IsReadOnly { get; }
@@ -88,62 +95,64 @@ namespace YooAsset
{
}
/// <inheritdoc />
public virtual BCInitializeOperation InitializeAsync()
public BCInitializeOperation InitializeAsync()
{
var operation = new BBCInitializeOperation(this);
return operation;
}
/// <inheritdoc />
public virtual BCWriteCacheOperation WriteCacheAsync(BCWriteCacheOptions options)
public BCWriteCacheOperation WriteCacheAsync(BCWriteCacheOptions options)
{
var operation = new BCWriteCacheCompleteOperation($"{nameof(BuiltinBundleCache)} is readonly.");
return operation;
}
/// <inheritdoc />
public virtual BCClearCacheOperation ClearCacheAsync(BCClearCacheOptions options)
public BCClearCacheOperation ClearCacheAsync(BCClearCacheOptions options)
{
var operation = new BCClearCacheCompleteOperation();
return operation;
}
/// <inheritdoc />
public virtual BCVerifyCacheOperation VerifyCacheAsync(BCVerifyCacheOptions options)
public BCVerifyCacheOperation VerifyCacheAsync(BCVerifyCacheOptions options)
{
var operation = new BCVerifyCacheCompleteOperation();
return operation;
}
/// <inheritdoc />
public virtual BCLoadBundleOperation LoadBundleAsync(BCLoadBundleOptions options)
public BCLoadBundleOperation LoadBundleAsync(BCLoadBundleOptions options)
{
if (options.Bundle.BundleType == (int)EBundleType.AssetBundle)
if (options.Bundle.GetBundleType() == (int)EBundleType.AssetBundle)
{
var operation = new BBCLoadAssetBundleOperation(this, options.Bundle);
return operation;
}
else if (options.Bundle.BundleType == (int)EBundleType.RawBundle)
else if (options.Bundle.GetBundleType() == (int)EBundleType.RawBundle)
{
var operation = new BBCLoadRawBundleOperation(this, options.Bundle);
return operation;
}
else
{
string error = $"{nameof(BuiltinBundleCache)} does not support bundle type: {options.Bundle.BundleType}.";
string error = $"{nameof(BuiltinBundleCache)} does not support bundle type: {options.Bundle.GetBundleType()}.";
var operation = new BCLoadBundleErrorOperation(error);
return operation;
}
}
/// <inheritdoc />
public virtual bool IsCached(string bundleGUID)
public bool IsCached(string bundleGuid)
{
return _cacheEntries.ContainsKey(bundleGUID);
return _cacheEntries.ContainsKey(bundleGuid);
}
#region
/// <summary>
/// 获取指定缓存条目
/// </summary>
internal BuiltinBundleCacheEntry GetEntry(string bundleGUID)
/// <param name="bundleGuid">资源包 GUID</param>
/// <returns>对应的内置缓存条目</returns>
internal BuiltinBundleCacheEntry GetEntry(string bundleGuid)
{
if (_cacheEntries.TryGetValue(bundleGUID, out BuiltinBundleCacheEntry entry))
if (_cacheEntries.TryGetValue(bundleGuid, out BuiltinBundleCacheEntry entry))
return entry;
else
return null;
@@ -152,21 +161,24 @@ namespace YooAsset
/// <summary>
/// 添加指定缓存条目
/// </summary>
internal void AddEntry(string bundleGUID, BuiltinBundleCacheEntry cacheEntry)
/// <param name="bundleGuid">资源包 GUID</param>
/// <param name="cacheEntry">内置缓存条目</param>
internal void AddEntry(string bundleGuid, BuiltinBundleCacheEntry cacheEntry)
{
if (_cacheEntries.ContainsKey(bundleGUID))
throw new YooInternalException($"Cache entry already exists: '{bundleGUID}'.");
if (_cacheEntries.ContainsKey(bundleGuid))
throw new YooInternalException($"Cache entry already exists: '{bundleGuid}'.");
_cacheEntries.Add(bundleGUID, cacheEntry);
_cacheEntries.Add(bundleGuid, cacheEntry);
}
/// <summary>
/// 获取Catalog文件加载路径
/// </summary>
/// <returns>完整加载路径</returns>
internal string GetCatalogBinaryFileLoadPath()
{
return PathUtility.Combine(RootPath, BuiltinCatalogConsts.BinaryFileName);
}
#endregion
}
}
}

View File

@@ -9,7 +9,7 @@ namespace YooAsset
/// <summary>
/// 资源包唯一标识
/// </summary>
public string BundleGUID { get; private set; }
public string BundleGuid { get; private set; }
/// <summary>
/// 资源包文件路径
@@ -17,13 +17,13 @@ namespace YooAsset
public string FilePath { get; private set; }
/// <summary>
/// 创建内置文件缓存条目
/// 创建内置文件缓存条目实例
/// </summary>
/// <param name="bundleGUID">资源包唯一标识</param>
/// <param name="bundleGuid">资源包唯一标识</param>
/// <param name="filePath">资源包文件路径</param>
public BuiltinBundleCacheEntry(string bundleGUID, string filePath)
public BuiltinBundleCacheEntry(string bundleGuid, string filePath)
{
BundleGUID = bundleGUID;
BundleGuid = bundleGuid;
FilePath = filePath;
}
}

View File

@@ -1,5 +1,4 @@
using System;
using System.IO;
using System.Collections.Generic;
namespace YooAsset
@@ -19,7 +18,7 @@ namespace YooAsset
/// <summary>
/// 资源包唯一标识
/// </summary>
public string BundleGUID;
public string BundleGuid;
/// <summary>
/// 资源包文件名

View File

@@ -4,7 +4,7 @@ namespace YooAsset
/// <summary>
/// 内置资源目录常量定义
/// </summary>
internal class BuiltinCatalogConsts
internal static class BuiltinCatalogConsts
{
/// <summary>
/// 文件极限大小100MB

View File

@@ -13,8 +13,12 @@ namespace YooAsset
#if UNITY_EDITOR
/// <summary>
/// 生成包裹的内置资源目录文件
/// 说明:根据指定目录下的文件生成清单文件
/// 说明:根据指定目录下的文件生成清单文件
/// </summary>
/// <param name="decryptor">资源清单解密器</param>
/// <param name="packageName">包裹名称</param>
/// <param name="packageDirectory">包裹在目录路径</param>
/// <returns>是否创建文件成功</returns>
public static bool CreateFile(IManifestDecryptor decryptor, string packageName, string packageDirectory)
{
// 获取资源清单版本
@@ -51,7 +55,7 @@ namespace YooAsset
{
foreach (var packageBundle in packageManifest.BundleList)
{
fileMapping.Add(packageBundle.FileName, packageBundle.BundleGuid);
fileMapping.Add(packageBundle.GetFileName(), packageBundle.BundleGuid);
}
}
@@ -92,10 +96,10 @@ namespace YooAsset
continue;
string fileName = fileInfo.Name;
if (fileMapping.TryGetValue(fileName, out string bundleGUID))
if (fileMapping.TryGetValue(fileName, out string bundleGuid))
{
var fileEntry = new BuiltinCatalog.CatalogEntry();
fileEntry.BundleGUID = bundleGUID;
fileEntry.BundleGuid = bundleGuid;
fileEntry.FileName = fileName;
buildinCatalog.Entries.Add(fileEntry);
}
@@ -125,6 +129,10 @@ namespace YooAsset
/// <summary>
/// 生成空的包裹内置资源目录文件
/// </summary>
/// <param name="packageName">包裹名称</param>
/// <param name="packageVersion">包裹版本</param>
/// <param name="outputPath">输出目录路径</param>
/// <returns>是否创建文件成功</returns>
public static bool CreateEmptyFile(string packageName, string packageVersion, string outputPath)
{
// 创建内置清单实例
@@ -153,6 +161,8 @@ namespace YooAsset
/// <summary>
/// 序列化为 JSON 文件
/// </summary>
/// <param name="savePath">文件的保存路径</param>
/// <param name="catalog">要序列化的内置目录</param>
public static void SerializeToJson(string savePath, BuiltinCatalog catalog)
{
string json = JsonUtility.ToJson(catalog, true);
@@ -162,6 +172,8 @@ namespace YooAsset
/// <summary>
/// 序列化为二进制文件
/// </summary>
/// <param name="savePath">文件的保存路径</param>
/// <param name="catalog">要序列化的内置目录</param>
public static void SerializeToBinary(string savePath, BuiltinCatalog catalog)
{
using (FileStream fs = new FileStream(savePath, FileMode.Create))
@@ -184,7 +196,7 @@ namespace YooAsset
for (int i = 0; i < catalog.Entries.Count; i++)
{
var fileWrapper = catalog.Entries[i];
buffer.WriteString(fileWrapper.BundleGUID);
buffer.WriteString(fileWrapper.BundleGuid);
buffer.WriteString(fileWrapper.FileName);
}
@@ -198,6 +210,8 @@ namespace YooAsset
/// <summary>
/// 从 JSON 反序列化
/// </summary>
/// <param name="jsonContent">文本内容</param>
/// <returns>反序列化得到的内置目录对象</returns>
public static BuiltinCatalog DeserializeFromJson(string jsonContent)
{
return JsonUtility.FromJson<BuiltinCatalog>(jsonContent);
@@ -206,6 +220,8 @@ namespace YooAsset
/// <summary>
/// 从二进制数据反序列化
/// </summary>
/// <param name="binaryData">二进制数据</param>
/// <returns>反序列化得到的内置目录对象</returns>
public static BuiltinCatalog DeserializeFromBinary(byte[] binaryData)
{
if (binaryData == null || binaryData.Length == 0)
@@ -217,12 +233,12 @@ namespace YooAsset
// 读取文件标记
uint fileMagic = buffer.ReadUInt32();
if (fileMagic != BuiltinCatalogConsts.FileMagic)
throw new Exception("Invalid catalog file.");
throw new Exception("Catalog file is invalid.");
// 读取文件版本
int fileVersion = buffer.ReadInt32();
if (fileVersion != BuiltinCatalogConsts.FileVersion)
throw new Exception($"The catalog file version is not compatible: {fileVersion} != {BuiltinCatalogConsts.FileVersion}.");
throw new Exception($"Catalog file version is not compatible: {fileVersion} != {BuiltinCatalogConsts.FileVersion}.");
BuiltinCatalog catalog = new BuiltinCatalog();
{
@@ -237,7 +253,7 @@ namespace YooAsset
for (int i = 0; i < fileCount; i++)
{
var fileEntry = new BuiltinCatalog.CatalogEntry();
fileEntry.BundleGUID = buffer.ReadString();
fileEntry.BundleGuid = buffer.ReadString();
fileEntry.FileName = buffer.ReadString();
catalog.Entries.Add(fileEntry);
}
@@ -246,4 +262,4 @@ namespace YooAsset
return catalog;
}
}
}
}

View File

@@ -4,7 +4,7 @@ namespace YooAsset
/// <summary>
/// 内置文件缓存初始化操作
/// </summary>
internal class BBCInitializeOperation : BCInitializeOperation
internal sealed class BBCInitializeOperation : BCInitializeOperation
{
private enum ESteps
{
@@ -18,6 +18,10 @@ namespace YooAsset
private LoadBuiltinCatalogOperation _loadBuiltinCatalogOp;
private ESteps _steps = ESteps.None;
/// <summary>
/// 创建内置缓存初始化操作实例
/// </summary>
/// <param name="fileCache">内置文件缓存系统</param>
public BBCInitializeOperation(BuiltinBundleCache fileCache)
{
_fileCache = fileCache;
@@ -35,10 +39,10 @@ namespace YooAsset
{
if (_loadBuiltinCatalogOp == null)
{
var options = new LoadBuiltinCatalogOptions();
options.PackageName = _fileCache.PackageName;
options.FilePath = _fileCache.GetCatalogBinaryFileLoadPath();
options.DownloadBackend = _fileCache.Config.DownloadBackend;
var options = new LoadBuiltinCatalogOptions(
packageName: _fileCache.PackageName,
filePath: _fileCache.GetCatalogBinaryFileLoadPath(),
downloadBackend: _fileCache.Config.DownloadBackend);
_loadBuiltinCatalogOp = new LoadBuiltinCatalogOperation(options);
_loadBuiltinCatalogOp.StartOperation();
AddChildOperation(_loadBuiltinCatalogOp);
@@ -65,8 +69,8 @@ namespace YooAsset
foreach (var fileEntry in catalog.Entries)
{
string filePath = PathUtility.Combine(_fileCache.RootPath, fileEntry.FileName);
var cacheEntry = new BuiltinBundleCacheEntry(fileEntry.BundleGUID, filePath);
_fileCache.AddEntry(fileEntry.BundleGUID, cacheEntry);
var cacheEntry = new BuiltinBundleCacheEntry(fileEntry.BundleGuid, filePath);
_fileCache.AddEntry(fileEntry.BundleGuid, cacheEntry);
}
_steps = ESteps.Done;

View File

@@ -4,7 +4,7 @@ namespace YooAsset
/// <summary>
/// 内置文件缓存加载 AssetBundle 操作
/// </summary>
internal class BBCLoadAssetBundleOperation : BCLoadBundleOperation
internal sealed class BBCLoadAssetBundleOperation : BCLoadBundleOperation
{
private enum ESteps
{
@@ -20,6 +20,11 @@ namespace YooAsset
private BuiltinBundleCacheEntry _cacheEntry;
private ESteps _steps = ESteps.None;
/// <summary>
/// 创建内置 AssetBundle 加载操作实例
/// </summary>
/// <param name="fileCache">内置文件缓存系统</param>
/// <param name="bundle">资源包描述</param>
public BBCLoadAssetBundleOperation(BuiltinBundleCache fileCache, PackageBundle bundle)
{
_fileCache = fileCache;
@@ -52,11 +57,11 @@ namespace YooAsset
{
if (_loadLocalAssetBundleOp == null)
{
var options = new LoadLocalAssetBundleOptions();
options.CacheName = _fileCache.GetType().Name;
options.Bundle = _bundle;
options.FilePath = _cacheEntry.FilePath;
options.AssetBundleDecryptor = _fileCache.Config.AssetBundleDecryptor;
var options = new LoadLocalAssetBundleOptions(
cacheName: _fileCache.GetType().Name,
bundle: _bundle,
filePath: _cacheEntry.FilePath,
assetBundleDecryptor: _fileCache.Config.AssetBundleDecryptor);
_loadLocalAssetBundleOp = new LoadLocalAssetBundleOperation(options);
_loadLocalAssetBundleOp.StartOperation();
AddChildOperation(_loadLocalAssetBundleOp);
@@ -94,7 +99,7 @@ namespace YooAsset
/// <summary>
/// 内置文件缓存加载 RawBundle 操作
/// </summary>
internal class BBCLoadRawBundleOperation : BCLoadBundleOperation
internal sealed class BBCLoadRawBundleOperation : BCLoadBundleOperation
{
private enum ESteps
{
@@ -142,11 +147,11 @@ namespace YooAsset
{
if(_loadLocalRawBundleOp == null)
{
var options = new LoadLocalRawBundleOptions();
options.CacheName = _fileCache.GetType().Name;
options.Bundle = _bundle;
options.FilePath = _cacheEntry.FilePath;
options.RawBundleDecryptor = _fileCache.Config.RawBundleDecryptor;
var options = new LoadLocalRawBundleOptions(
cacheName: _fileCache.GetType().Name,
bundle: _bundle,
filePath: _cacheEntry.FilePath,
rawBundleDecryptor: _fileCache.Config.RawBundleDecryptor);
_loadLocalRawBundleOp = new LoadLocalRawBundleOperation(options);
_loadLocalRawBundleOp.StartOperation();
AddChildOperation(_loadLocalRawBundleOp);

View File

@@ -4,34 +4,42 @@ using System.Collections.Generic;
namespace YooAsset
{
/// <summary>
/// 编辑器文件缓存系统,用于编辑器模式下的资源模拟加载
/// 编辑器文件缓存系统,用于编辑器模式下的资源模拟加载
/// </summary>
internal class EditorBundleCache : IBundleCache
{
/// <summary>
/// 编辑器文件缓存配置
/// </summary>
internal struct Configuration
internal readonly struct Configuration
{
/// <summary>
/// 虚拟下载模式,模拟资源下载流程
/// 虚拟下载模式,模拟资源下载流程
/// </summary>
public bool VirtualDownloadMode { get; set; }
public bool VirtualDownloadMode { get; }
/// <summary>
/// 虚拟WebGL模式
/// </summary>
public bool VirtualWebGLMode { get; set; }
public bool VirtualWebGLMode { get; }
/// <summary>
/// 异步模拟最小帧数
/// </summary>
public int AsyncSimulateMinFrame { get; set; }
public int AsyncSimulateMinFrame { get; }
/// <summary>
/// 异步模拟最大帧数
/// </summary>
public int AsyncSimulateMaxFrame { get; set; }
public int AsyncSimulateMaxFrame { get; }
public Configuration(bool virtualDownloadMode, bool virtualWebGLMode, int asyncSimulateMinFrame, int asyncSimulateMaxFrame)
{
VirtualDownloadMode = virtualDownloadMode;
VirtualWebGLMode = virtualWebGLMode;
AsyncSimulateMinFrame = asyncSimulateMinFrame;
AsyncSimulateMaxFrame = asyncSimulateMaxFrame;
}
}
private readonly Dictionary<string, EditorBundleCacheEntry> _cacheEntries = new Dictionary<string, EditorBundleCacheEntry>(10000);
@@ -53,7 +61,7 @@ namespace YooAsset
public string RootPath { get; }
/// <summary>
/// 只读属性
/// 是否为只读缓存
/// </summary>
public bool IsReadOnly { get; }
@@ -71,7 +79,7 @@ namespace YooAsset
/// <summary>
/// 已占用空间
/// </summary>
/// <remarks>按缓存索引累计</remarks>
/// <remarks>编辑器缓存为虚拟缓存,不占用磁盘空间。</remarks>
public long SpaceOccupied { get; private set; }
#endregion
@@ -93,19 +101,19 @@ namespace YooAsset
{
}
/// <inheritdoc />
public virtual BCInitializeOperation InitializeAsync()
public BCInitializeOperation InitializeAsync()
{
var operation = new EBCInitializeOperation(this);
return operation;
}
/// <inheritdoc />
public virtual BCWriteCacheOperation WriteCacheAsync(BCWriteCacheOptions options)
public BCWriteCacheOperation WriteCacheAsync(BCWriteCacheOptions options)
{
var operation = new EBCWriteCacheOperation(this, options);
return operation;
}
/// <inheritdoc />
public virtual BCClearCacheOperation ClearCacheAsync(BCClearCacheOptions options)
public BCClearCacheOperation ClearCacheAsync(BCClearCacheOptions options)
{
ICacheEvictionPolicy policy = CreateEvictionPolicy(options);
if (policy == null)
@@ -117,7 +125,9 @@ namespace YooAsset
/// <summary>
/// 根据 ClearMethod 创建对应的淘汰策略实例
/// </summary>
protected virtual ICacheEvictionPolicy CreateEvictionPolicy(BCClearCacheOptions options)
/// <param name="options">清理缓存选项</param>
/// <returns>淘汰策略实例</returns>
protected ICacheEvictionPolicy CreateEvictionPolicy(BCClearCacheOptions options)
{
if (options.ClearMethod == ClearCacheMethods.ClearAllBundleFiles)
return new EvictionAllPolicy();
@@ -134,31 +144,31 @@ namespace YooAsset
return null;
}
/// <inheritdoc />
public virtual BCVerifyCacheOperation VerifyCacheAsync(BCVerifyCacheOptions options)
public BCVerifyCacheOperation VerifyCacheAsync(BCVerifyCacheOptions options)
{
var operation = new BCVerifyCacheCompleteOperation();
return operation;
}
/// <inheritdoc />
public virtual BCLoadBundleOperation LoadBundleAsync(BCLoadBundleOptions options)
public BCLoadBundleOperation LoadBundleAsync(BCLoadBundleOptions options)
{
if (options.Bundle.BundleType == (int)EBundleType.VirtualBundle)
if (options.Bundle.GetBundleType() == (int)EBundleType.VirtualBundle)
{
var operation = new EBCLoadBundleOperation(this, options.Bundle);
return operation;
}
else
{
string error = $"{nameof(EditorBundleCache)} does not support bundle type: {options.Bundle.BundleType}.";
string error = $"{nameof(EditorBundleCache)} does not support bundle type: {options.Bundle.GetBundleType()}.";
var operation = new BCLoadBundleErrorOperation(error);
return operation;
}
}
/// <inheritdoc />
public virtual bool IsCached(string bundleGUID)
public bool IsCached(string bundleGuid)
{
if (Config.VirtualDownloadMode)
return _cacheEntries.ContainsKey(bundleGUID);
return _cacheEntries.ContainsKey(bundleGuid);
else
return true;
}
@@ -167,6 +177,7 @@ namespace YooAsset
/// <summary>
/// 获取所有缓存条目
/// </summary>
/// <returns>当前字典中全部缓存条目的只读集合</returns>
internal IReadOnlyCollection<EditorBundleCacheEntry> GetAllEntries()
{
return _cacheEntries.Values;
@@ -175,24 +186,27 @@ namespace YooAsset
/// <summary>
/// 添加指定缓存条目
/// </summary>
internal void AddEntry(string bundleGUID, EditorBundleCacheEntry cacheEntry)
/// <param name="bundleGuid">资源包 GUID</param>
/// <param name="cacheEntry">编辑器缓存条目</param>
internal void AddEntry(string bundleGuid, EditorBundleCacheEntry cacheEntry)
{
if (_cacheEntries.ContainsKey(bundleGUID))
throw new YooInternalException($"Cache entry already exists: '{bundleGUID}'.");
if (_cacheEntries.ContainsKey(bundleGuid))
throw new YooInternalException($"Cache entry already exists: '{bundleGuid}'.");
_cacheEntries.Add(bundleGUID, cacheEntry);
_cacheEntries.Add(bundleGuid, cacheEntry);
}
/// <summary>
/// 删除指定缓存条目
/// </summary>
internal void RemoveEntry(string bundleGUID)
/// <param name="bundleGuid">资源包 GUID</param>
internal void RemoveEntry(string bundleGuid)
{
if (_cacheEntries.TryGetValue(bundleGUID, out EditorBundleCacheEntry entry))
if (_cacheEntries.TryGetValue(bundleGuid, out EditorBundleCacheEntry entry))
{
_cacheEntries.Remove(bundleGUID);
_cacheEntries.Remove(bundleGuid);
}
}
#endregion
}
}
}

View File

@@ -9,7 +9,7 @@ namespace YooAsset
/// <summary>
/// 资源包唯一标识
/// </summary>
public string BundleGUID { get; private set; }
public string BundleGuid { get; private set; }
/// <summary>
/// 资源包文件路径
@@ -17,13 +17,13 @@ namespace YooAsset
public string FilePath { get; private set; }
/// <summary>
/// 创建编辑器文件缓存条目
/// 创建编辑器文件缓存条目实例
/// </summary>
/// <param name="bundleGUID">资源包唯一标识</param>
/// <param name="bundleGuid">资源包唯一标识</param>
/// <param name="filePath">资源包文件路径</param>
public EditorBundleCacheEntry(string bundleGUID, string filePath)
public EditorBundleCacheEntry(string bundleGuid, string filePath)
{
BundleGUID = bundleGUID;
BundleGuid = bundleGuid;
FilePath = filePath;
}
}

View File

@@ -18,9 +18,15 @@ namespace YooAsset
private readonly EditorBundleCache _fileCache;
private readonly BCClearCacheOptions _options;
private readonly ICacheEvictionPolicy _policy;
private List<string> _bundleGUIDs;
private IReadOnlyList<string> _bundleGuids;
private ESteps _steps = ESteps.None;
/// <summary>
/// 创建编辑器清理缓存操作实例
/// </summary>
/// <param name="fileCache">编辑器文件缓存系统</param>
/// <param name="options">清理缓存选项</param>
/// <param name="policy">缓存逐出策略</param>
internal EBCClearCacheOperation(EditorBundleCache fileCache, BCClearCacheOptions options, ICacheEvictionPolicy policy)
{
_fileCache = fileCache;
@@ -48,15 +54,15 @@ namespace YooAsset
return;
}
_bundleGUIDs = clearResult.BundleGUIDs;
_bundleGuids = clearResult.BundleGuids;
_steps = ESteps.ClearCacheFiles;
}
if (_steps == ESteps.ClearCacheFiles)
{
foreach (var bundleGUID in _bundleGUIDs)
foreach (var bundleGuid in _bundleGuids)
{
_fileCache.RemoveEntry(bundleGUID);
_fileCache.RemoveEntry(bundleGuid);
}
_steps = ESteps.Done;

View File

@@ -4,7 +4,7 @@ namespace YooAsset
/// <summary>
/// 编辑器文件缓存初始化操作
/// </summary>
internal class EBCInitializeOperation : BCInitializeOperation
internal sealed class EBCInitializeOperation : BCInitializeOperation
{
private readonly EditorBundleCache _fileCache;

View File

@@ -4,7 +4,7 @@ namespace YooAsset
/// <summary>
/// 编辑器文件缓存加载资源包操作
/// </summary>
internal class EBCLoadBundleOperation : BCLoadBundleOperation
internal sealed class EBCLoadBundleOperation : BCLoadBundleOperation
{
private enum ESteps
{

View File

@@ -4,7 +4,7 @@ namespace YooAsset
/// <summary>
/// 编辑器文件缓存写入操作
/// </summary>
internal class EBCWriteCacheOperation : BCWriteCacheOperation
internal sealed class EBCWriteCacheOperation : BCWriteCacheOperation
{
private enum ESteps
{
@@ -18,9 +18,14 @@ namespace YooAsset
private readonly BCWriteCacheOptions _options;
private ESteps _steps = ESteps.None;
public EBCWriteCacheOperation(EditorBundleCache cache, BCWriteCacheOptions options)
/// <summary>
/// 创建编辑器写入缓存操作实例
/// </summary>
/// <param name="fileCache">编辑器文件缓存系统</param>
/// <param name="options">写入缓存选项</param>
public EBCWriteCacheOperation(EditorBundleCache fileCache, BCWriteCacheOptions options)
{
_fileCache = cache;
_fileCache = fileCache;
_options = options;
}
protected override void InternalStart()
@@ -37,7 +42,7 @@ namespace YooAsset
if (_fileCache.IsCached(_options.Bundle.BundleGuid))
{
_steps = ESteps.Done;
SetError("The bundle is already cached.");
SetError("Bundle is already cached.");
}
else
{

View File

@@ -13,9 +13,9 @@ namespace YooAsset
/// </summary>
/// <param name="filePath">文件路径</param>
/// <param name="fileSize">期望的文件大小</param>
/// <param name="fileCRC">期望的文件CRC值</param>
/// <param name="fileCrc">期望的文件CRC值</param>
/// <returns>校验结果</returns>
public static EFileVerifyResult VerifyFile(string filePath, long fileSize, uint fileCRC)
public static EFileVerifyResult VerifyFile(string filePath, long fileSize, uint fileCrc)
{
try
{
@@ -23,6 +23,7 @@ namespace YooAsset
return EFileVerifyResult.DataFileNotExisted;
// 可选条件:验证文件大小
// fileSize == 0 表示调用方不要求大小校验(哨兵值)
if (fileSize > 0)
{
long size = FileUtility.GetFileSize(filePath);
@@ -33,10 +34,11 @@ namespace YooAsset
}
// 可选条件验证文件CRC
if (fileCRC > 0)
// fileCRC == 0 表示调用方不要求 CRC 校验(哨兵值)
if (fileCrc > 0)
{
uint crc = HashUtility.ComputeFileCrc32AsUInt(filePath);
if (crc == fileCRC)
if (crc == fileCrc)
return EFileVerifyResult.Succeed;
else
return EFileVerifyResult.DataFileCrcError;
@@ -48,7 +50,7 @@ namespace YooAsset
}
catch (Exception ex)
{
YooLogger.Error($"File verification exception: {ex.Message}.");
YooLogger.LogError($"File verification exception: {ex.Message}.");
return EFileVerifyResult.Exception;
}
}
@@ -58,9 +60,9 @@ namespace YooAsset
/// </summary>
/// <param name="fileData">文件数据</param>
/// <param name="fileSize">期望的文件大小</param>
/// <param name="fileCRC">期望的文件CRC值</param>
/// <param name="fileCrc">期望的文件CRC值</param>
/// <returns>校验结果</returns>
public static EFileVerifyResult VerifyFile(byte[] fileData, long fileSize, uint fileCRC)
public static EFileVerifyResult VerifyFile(byte[] fileData, long fileSize, uint fileCrc)
{
try
{
@@ -68,6 +70,7 @@ namespace YooAsset
return EFileVerifyResult.DataFileInvalid;
// 可选条件:验证文件大小
// fileSize == 0 表示调用方不要求大小校验(哨兵值)
if (fileSize > 0)
{
long size = fileData.Length;
@@ -78,10 +81,11 @@ namespace YooAsset
}
// 可选条件验证文件CRC
if (fileCRC > 0)
// fileCRC == 0 表示调用方不要求 CRC 校验(哨兵值)
if (fileCrc > 0)
{
uint crc = HashUtility.ComputeCrc32AsUInt(fileData);
if (crc == fileCRC)
if (crc == fileCrc)
return EFileVerifyResult.Succeed;
else
return EFileVerifyResult.DataFileCrcError;
@@ -93,7 +97,7 @@ namespace YooAsset
}
catch (Exception ex)
{
YooLogger.Error($"File verification exception: {ex.Message}.");
YooLogger.LogError($"File verification exception: {ex.Message}.");
return EFileVerifyResult.Exception;
}
}

View File

@@ -5,7 +5,7 @@ namespace YooAsset
/// <summary>
/// 清理缓存文件操作
/// </summary>
internal class ClearCacheFilesOperation : AsyncOperationBase
internal sealed class ClearCacheFilesOperation : AsyncOperationBase
{
private enum ESteps
{
@@ -16,14 +16,19 @@ namespace YooAsset
}
private readonly SandboxBundleCache _fileCache;
private readonly List<string> _bundleGUIDs;
private readonly List<string> _bundleGuids;
private int _fileTotalCount;
private ESteps _steps = ESteps.None;
public ClearCacheFilesOperation(SandboxBundleCache fileCache, List<string> bundleGUIDs)
/// <summary>
/// 创建清理缓存文件操作实例
/// </summary>
/// <param name="fileCache">沙盒文件缓存系统</param>
/// <param name="bundleGuids">要清理的资源包 GUID 列表</param>
public ClearCacheFilesOperation(SandboxBundleCache fileCache, List<string> bundleGuids)
{
_fileCache = fileCache;
_bundleGUIDs = bundleGUIDs;
_bundleGuids = bundleGuids;
}
protected override void InternalStart()
{
@@ -36,24 +41,24 @@ namespace YooAsset
if (_steps == ESteps.CheckParam)
{
if (_bundleGUIDs == null || _bundleGUIDs.Count == 0)
if (_bundleGuids == null || _bundleGuids.Count == 0)
{
_steps = ESteps.Done;
SetResult();
return;
}
_fileTotalCount = _bundleGUIDs.Count;
_fileTotalCount = _bundleGuids.Count;
_steps = ESteps.ClearCache;
}
if (_steps == ESteps.ClearCache)
{
for (int i = _bundleGUIDs.Count - 1; i >= 0; i--)
for (int i = _bundleGuids.Count - 1; i >= 0; i--)
{
string bundleGUID = _bundleGUIDs[i];
_fileCache.RemoveEntry(bundleGUID);
_bundleGUIDs.RemoveAt(i);
string bundleGuid = _bundleGuids[i];
_fileCache.RemoveEntry(bundleGuid);
_bundleGuids.RemoveAt(i);
if (IsBusy)
break;
}
@@ -61,9 +66,9 @@ namespace YooAsset
if (_fileTotalCount == 0)
Progress = 1.0f;
else
Progress = 1.0f - ((float)_bundleGUIDs.Count / _fileTotalCount);
Progress = 1.0f - ((float)_bundleGuids.Count / _fileTotalCount);
if (_bundleGUIDs.Count == 0)
if (_bundleGuids.Count == 0)
{
_steps = ESteps.Done;
SetResult();

View File

@@ -6,7 +6,7 @@ using System.Collections.Generic;
namespace YooAsset
{
/// <summary>
/// 搜索缓存文件操作,扫描缓存目录中的文件
/// 搜索缓存文件操作,扫描缓存目录中的文件
/// </summary>
internal sealed class SearchCacheFilesOperation : AsyncOperationBase
{
@@ -28,7 +28,10 @@ namespace YooAsset
/// </summary>
public readonly List<SearchFileInfo> Result = new List<SearchFileInfo>(5000);
/// <summary>
/// 创建搜索缓存文件操作实例
/// </summary>
/// <param name="fileCache">沙盒文件缓存系统</param>
internal SearchCacheFilesOperation(SandboxBundleCache fileCache)
{
_fileCache = fileCache;
@@ -69,7 +72,15 @@ namespace YooAsset
_steps = ESteps.Done;
SetResult();
double costTime = TimeUtility.RealtimeSinceStartup - _verifyStartTime;
YooLogger.Log($"Search cache files elapsed time {costTime:f1} seconds");
YooLogger.Log($"Cache file search completed in {costTime:f1} seconds.");
}
}
protected override void InternalDispose()
{
if (_filesEnumerator != null)
{
_filesEnumerator.Dispose();
_filesEnumerator = null;
}
}
@@ -86,15 +97,15 @@ namespace YooAsset
var childDirectories = Directory.EnumerateDirectories(rootFolder);
foreach (var childDirectory in childDirectories)
{
string bundleGUID = Path.GetFileName(childDirectory);
if (_fileCache.IsCached(bundleGUID))
string bundleGuid = Path.GetFileName(childDirectory);
if (_fileCache.IsCached(bundleGuid))
continue;
// 创建验证元素类
string fileRootPath = childDirectory;
string dataFilePath = PathUtility.Combine(fileRootPath, SandboxBundleCacheConsts.BundleDataFileName);
string infoFilePath = PathUtility.Combine(fileRootPath, SandboxBundleCacheConsts.BundleInfoFileName);
var element = new SearchFileInfo(bundleGUID, fileRootPath, dataFilePath, infoFilePath);
var element = new SearchFileInfo(bundleGuid, fileRootPath, dataFilePath, infoFilePath);
Result.Add(element);
}
@@ -105,4 +116,4 @@ namespace YooAsset
return isFindItem;
}
}
}
}

View File

@@ -1,5 +1,4 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Threading;
@@ -7,7 +6,7 @@ using System.Threading;
namespace YooAsset
{
/// <summary>
/// 缓存文件验证(线程版),验证缓存目录中的文件
/// 缓存文件验证(线程版),验证缓存目录中的文件
/// </summary>
internal sealed class VerifyCacheFilesOperation : AsyncOperationBase
{
@@ -31,7 +30,13 @@ namespace YooAsset
private int _failedCount;
private ESteps _steps = ESteps.None;
/// <summary>
/// 创建缓存文件验证操作实例
/// </summary>
/// <param name="fileCache">沙盒文件缓存系统</param>
/// <param name="verifyLevel">文件校验等级</param>
/// <param name="fileVerifyMaxConcurrency">文件校验最大并发数</param>
/// <param name="elements">待验证的搜索文件信息列表</param>
internal VerifyCacheFilesOperation(SandboxBundleCache fileCache, EFileVerifyLevel verifyLevel, int fileVerifyMaxConcurrency, List<SearchFileInfo> elements)
{
_fileCache = fileCache;
@@ -56,7 +61,7 @@ namespace YooAsset
if (_maxConcurrentVerifyCount < 1)
_maxConcurrentVerifyCount = 1;
YooLogger.Log($"Verify max concurrency: {_maxConcurrentVerifyCount}");
YooLogger.Log($"Maximum verify concurrency is {_maxConcurrentVerifyCount}.");
_activeVerifyList = new List<SearchFileInfo>(_maxConcurrentVerifyCount);
_verifyStartTime = TimeUtility.RealtimeSinceStartup;
_verifyTotalCount = _pendingVerifyList.Count;
@@ -76,13 +81,13 @@ namespace YooAsset
if (resultCode == (int)EFileVerifyResult.Succeed)
{
_successCount++;
var cacheEntry = new SandboxBundleCacheEntry(verifyElement.BundleGUID, verifyElement.InfoFilePath, verifyElement.DataFilePath);
_fileCache.AddEntry(verifyElement.BundleGUID, cacheEntry);
var cacheEntry = new SandboxBundleCacheEntry(verifyElement.BundleGuid, verifyElement.InfoFilePath, verifyElement.DataFilePath);
_fileCache.AddEntry(verifyElement.BundleGuid, cacheEntry);
}
else
{
_failedCount++;
YooLogger.Warning($"File verification failed (code: {verifyElement.VerifyResultCode}). Deleting files: '{verifyElement.FolderPath}'.");
YooLogger.LogWarning($"File verification failed (code: {resultCode}). Deleting files: '{verifyElement.FolderPath}'.");
verifyElement.DeleteCacheFolder();
}
}
@@ -94,7 +99,7 @@ namespace YooAsset
_steps = ESteps.Done;
SetResult();
double costTime = TimeUtility.RealtimeSinceStartup - _verifyStartTime;
YooLogger.Log($"Verify cache files elapsed time {costTime:f1} seconds");
YooLogger.Log($"Cache file verification completed in {costTime:f1} seconds.");
}
for (int i = _pendingVerifyList.Count - 1; i >= 0; i--)
@@ -163,13 +168,13 @@ namespace YooAsset
else if (verifyLevel == EFileVerifyLevel.High)
return FileVerifyHelper.VerifyFile(element.DataFilePath, dataFileSize, dataFileCRC);
else
throw new System.NotImplementedException(verifyLevel.ToString());
throw new YooInternalException($"Unexpected verify level: {verifyLevel}.");
}
catch (Exception ex)
{
YooLogger.Error($"File verification exception: {ex.Message}.");
YooLogger.LogError($"File verification exception: {ex.Message}.");
return EFileVerifyResult.Exception;
}
}
}
}
}

View File

@@ -24,7 +24,10 @@ namespace YooAsset
/// </summary>
public EFileVerifyResult VerifyResult { private set; get; }
/// <summary>
/// 创建下载文件验证(线程版)实例
/// </summary>
/// <param name="element">临时文件信息</param>
internal VerifyTempFileOperation(TempFileInfo element)
{
_element = element;
@@ -75,7 +78,7 @@ namespace YooAsset
private void VerifyFileInThread(object obj)
{
TempFileInfo element = (TempFileInfo)obj;
int resultCode = (int)FileVerifyHelper.VerifyFile(element.FilePath, element.FileSize, element.FileCRC);
int resultCode = (int)FileVerifyHelper.VerifyFile(element.FilePath, element.FileSize, element.FileCrc);
element.VerifyResultCode = resultCode; //注意: 一次命令赋值
}
}

View File

@@ -1,3 +1,4 @@
using System.Collections.Generic;
namespace YooAsset
{
@@ -20,6 +21,12 @@ namespace YooAsset
private ClearCacheFilesOperation _clearCacheFilesOp;
private ESteps _steps = ESteps.None;
/// <summary>
/// 创建沙盒清理缓存操作实例
/// </summary>
/// <param name="fileCache">沙盒文件缓存系统</param>
/// <param name="options">清理缓存选项</param>
/// <param name="policy">缓存淘汰策略</param>
internal SBCClearCacheOperation(SandboxBundleCache fileCache, BCClearCacheOptions options, ICacheEvictionPolicy policy)
{
_fileCache = fileCache;
@@ -48,7 +55,7 @@ namespace YooAsset
return;
}
_clearCacheFilesOp = new ClearCacheFilesOperation(_fileCache, clearResult.BundleGUIDs);
_clearCacheFilesOp = new ClearCacheFilesOperation(_fileCache, new List<string>(clearResult.BundleGuids));
_clearCacheFilesOp.StartOperation();
AddChildOperation(_clearCacheFilesOp);
_steps = ESteps.ClearCacheFiles;

View File

@@ -4,7 +4,7 @@ namespace YooAsset
/// <summary>
/// 沙盒文件缓存初始化操作
/// </summary>
internal class SBCInitializeOperation : BCInitializeOperation
internal sealed class SBCInitializeOperation : BCInitializeOperation
{
private enum ESteps
{
@@ -19,6 +19,10 @@ namespace YooAsset
private VerifyCacheFilesOperation _verifyCacheFilesOp;
private ESteps _steps = ESteps.None;
/// <summary>
/// 创建沙盒缓存初始化操作实例
/// </summary>
/// <param name="fileCache">沙盒文件缓存系统</param>
public SBCInitializeOperation(SandboxBundleCache fileCache)
{
_fileCache = fileCache;

View File

@@ -7,7 +7,7 @@ namespace YooAsset
/// <summary>
/// 沙盒文件缓存加载 AssetBundle 操作
/// </summary>
internal class SBCLoadAssetBundleOperation : BCLoadBundleOperation
internal sealed class SBCLoadAssetBundleOperation : BCLoadBundleOperation
{
private enum ESteps
{
@@ -26,10 +26,15 @@ namespace YooAsset
private SandboxBundleCacheEntry _cacheEntry;
private ESteps _steps = ESteps.None;
public SBCLoadAssetBundleOperation(SandboxBundleCache fileCache, PackageBundle bundle)
/// <summary>
/// 创建沙盒 AssetBundle 加载操作实例
/// </summary>
/// <param name="fileCache">沙盒文件缓存系统</param>
/// <param name="packageBundle">资源包描述</param>
public SBCLoadAssetBundleOperation(SandboxBundleCache fileCache, PackageBundle packageBundle)
{
_fileCache = fileCache;
_bundle = bundle;
_bundle = packageBundle;
}
protected override void InternalStart()
{
@@ -58,11 +63,11 @@ namespace YooAsset
{
if (_loadLocalAssetBundleOp == null)
{
var options = new LoadLocalAssetBundleOptions();
options.CacheName = _fileCache.GetType().Name;
options.Bundle = _bundle;
options.FilePath = _cacheEntry.DataFilePath;
options.AssetBundleDecryptor = _fileCache.Config.AssetBundleDecryptor;
var options = new LoadLocalAssetBundleOptions(
cacheName: _fileCache.GetType().Name,
bundle: _bundle,
filePath: _cacheEntry.DataFilePath,
assetBundleDecryptor: _fileCache.Config.AssetBundleDecryptor);
_loadLocalAssetBundleOp = new LoadLocalAssetBundleOperation(options);
_loadLocalAssetBundleOp.StartOperation();
AddChildOperation(_loadLocalAssetBundleOp);
@@ -105,9 +110,7 @@ namespace YooAsset
// 说明在AssetBundle文件加载失败的情况下我们需要重新验证文件的完整性
if (_verifyCacheOp == null)
{
var options = new BCVerifyCacheOptions();
options.Bundle = _bundle;
options.DeleteCacheEntryOnFailure = true;
var options = new BCVerifyCacheOptions(_bundle, true);
_verifyCacheOp = _fileCache.VerifyCacheAsync(options);
_verifyCacheOp.StartOperation();
AddChildOperation(_verifyCacheOp);
@@ -178,23 +181,39 @@ namespace YooAsset
private AssetBundle FallbackLoadAssetBundle()
{
byte[] fileData = FileUtility.ReadAllBytes(_cacheEntry.DataFilePath);
return AssetBundle.LoadFromMemory(fileData);
try
{
byte[] fileData = FileUtility.ReadAllBytes(_cacheEntry.DataFilePath);
return AssetBundle.LoadFromMemory(fileData);
}
catch (Exception ex)
{
YooLogger.LogWarning($"Fallback load failed: {ex.Message}.");
return null;
}
}
private AssetBundle FallbackLoadEncryptedAssetBundle(IBundleMemoryDecryptor decryptor)
{
var args = new BundleDecryptArgs();
args.Bundle = _bundle;
args.FilePath = _cacheEntry.DataFilePath;
var fileData = decryptor.GetDecryptedData(args);
return AssetBundle.LoadFromMemory(fileData);
try
{
var args = new BundleDecryptArgs(_bundle, null, _cacheEntry.DataFilePath);
var fileData = decryptor.GetDecryptedData(args);
if (fileData == null)
return null;
return AssetBundle.LoadFromMemory(fileData);
}
catch (Exception ex)
{
YooLogger.LogWarning($"Fallback encrypted load failed: {ex.Message}.");
return null;
}
}
}
/// <summary>
/// 沙盒文件缓存加载 RawBundle 操作
/// </summary>
internal class SBCLoadRawBundleOperation : BCLoadBundleOperation
internal sealed class SBCLoadRawBundleOperation : BCLoadBundleOperation
{
private enum ESteps
{
@@ -211,6 +230,11 @@ namespace YooAsset
private ESteps _steps = ESteps.None;
/// <summary>
/// 创建沙盒 RawBundle 加载操作实例
/// </summary>
/// <param name="fileCache">沙盒文件缓存系统</param>
/// <param name="bundle">资源包描述</param>
public SBCLoadRawBundleOperation(SandboxBundleCache fileCache, PackageBundle bundle)
{
_fileCache = fileCache;
@@ -243,11 +267,11 @@ namespace YooAsset
{
if (_loadLocalRawBundleOp == null)
{
var options = new LoadLocalRawBundleOptions();
options.CacheName = _fileCache.GetType().Name;
options.Bundle = _bundle;
options.FilePath = _cacheEntry.DataFilePath;
options.RawBundleDecryptor = _fileCache.Config.RawBundleDecryptor;
var options = new LoadLocalRawBundleOptions(
cacheName: _fileCache.GetType().Name,
bundle: _bundle,
filePath: _cacheEntry.DataFilePath,
rawBundleDecryptor: _fileCache.Config.RawBundleDecryptor);
_loadLocalRawBundleOp = new LoadLocalRawBundleOperation(options);
_loadLocalRawBundleOp.StartOperation();
AddChildOperation(_loadLocalRawBundleOp);
@@ -283,7 +307,7 @@ namespace YooAsset
}
#if TUANJIE_1_7_OR_NEWER
internal class SBCLoadInstantBundleOperation : BCLoadBundleOperation
internal sealed class SBCLoadInstantBundleOperation : BCLoadBundleOperation
{
private enum ESteps
{
@@ -295,11 +319,11 @@ namespace YooAsset
protected override void InternalStart()
{
throw new NotImplementedException();
throw new NotImplementedException($"{nameof(SBCLoadInstantBundleOperation)} is not implemented.");
}
protected override void InternalUpdate()
{
throw new NotImplementedException();
throw new NotImplementedException($"{nameof(SBCLoadInstantBundleOperation)} is not implemented.");
}
}
#endif

View File

@@ -4,7 +4,7 @@ namespace YooAsset
/// <summary>
/// 沙盒文件缓存验证操作
/// </summary>
internal class SBCVerifyCacheOperation : BCVerifyCacheOperation
internal sealed class SBCVerifyCacheOperation : BCVerifyCacheOperation
{
private enum ESteps
{
@@ -19,9 +19,14 @@ namespace YooAsset
private VerifyTempFileOperation _verifyTempFileOp;
private ESteps _steps = ESteps.None;
public SBCVerifyCacheOperation(SandboxBundleCache cache, BCVerifyCacheOptions options)
/// <summary>
/// 创建沙盒验证缓存操作实例
/// </summary>
/// <param name="fileCache">沙盒文件缓存系统</param>
/// <param name="options">验证缓存选项</param>
public SBCVerifyCacheOperation(SandboxBundleCache fileCache, BCVerifyCacheOptions options)
{
_fileCache = cache;
_fileCache = fileCache;
_options = options;
}
protected override void InternalStart()
@@ -38,7 +43,7 @@ namespace YooAsset
if (_fileCache.IsCached(_options.Bundle.BundleGuid) == false)
{
_steps = ESteps.Done;
SetError("Cached bundle not found.");
SetError($"File cache entry not found: '{_options.Bundle.BundleGuid}'.");
}
else
{
@@ -51,6 +56,13 @@ namespace YooAsset
if (_verifyTempFileOp == null)
{
var entry = _fileCache.GetEntry(_options.Bundle.BundleGuid);
if (entry == null)
{
_steps = ESteps.Done;
SetError($"File cache entry not found: '{_options.Bundle.BundleGuid}'.");
return;
}
var element = new TempFileInfo(entry.DataFilePath, _options.Bundle.FileCrc, _options.Bundle.FileSize);
_verifyTempFileOp = new VerifyTempFileOperation(element);
_verifyTempFileOp.StartOperation();
@@ -76,7 +88,7 @@ namespace YooAsset
if (_options.DeleteCacheEntryOnFailure)
{
YooLogger.Error($"Found corrupted bundle file. Removing cache entry: '{_options.Bundle.BundleGuid}'.");
YooLogger.LogError($"Found corrupted bundle file. Removing cache entry: '{_options.Bundle.BundleGuid}'.");
_fileCache.RemoveEntry(_options.Bundle.BundleGuid);
}
}

View File

@@ -6,7 +6,7 @@ namespace YooAsset
/// <summary>
/// 沙盒文件缓存写入操作
/// </summary>
internal class SBCWriteCacheOperation : BCWriteCacheOperation
internal sealed class SBCWriteCacheOperation : BCWriteCacheOperation
{
private enum ESteps
{
@@ -22,6 +22,11 @@ namespace YooAsset
private VerifyTempFileOperation _verifyTempFileOp;
private ESteps _steps = ESteps.None;
/// <summary>
/// 创建沙盒写入缓存操作实例
/// </summary>
/// <param name="fileCache">沙盒文件缓存系统</param>
/// <param name="options">写入缓存选项</param>
public SBCWriteCacheOperation(SandboxBundleCache fileCache, BCWriteCacheOptions options)
{
_fileCache = fileCache;
@@ -41,7 +46,7 @@ namespace YooAsset
if (_fileCache.IsCached(_options.Bundle.BundleGuid))
{
_steps = ESteps.Done;
SetError("The bundle is already cached.");
SetError("Bundle is already cached.");
}
else
{
@@ -120,8 +125,8 @@ namespace YooAsset
catch (Exception ex)
{
_steps = ESteps.Done;
SetError($"Failed to write cache file. Error: {ex.Message}.");
YooLogger.Error(Error);
SetError($"Failed to write cache file: {ex.Message}.");
YooLogger.LogError(Error);
// 回滚:清理临时文件,正式文件不受影响
DeleteFileSafely(dataTempPath);
@@ -150,7 +155,7 @@ namespace YooAsset
}
catch (Exception ex)
{
YooLogger.Warning($"Failed to delete file '{filePath}'. Error: {ex.Message}.");
YooLogger.LogWarning($"Failed to delete file '{filePath}': {ex.Message}.");
}
}
}

View File

@@ -4,39 +4,49 @@ using System.Collections.Generic;
namespace YooAsset
{
/// <summary>
/// 沙盒文件缓存系统,用于管理下载到本地的资源包缓存
/// 沙盒文件缓存系统,用于管理下载到本地的资源包缓存
/// </summary>
internal class SandboxBundleCache : IBundleCache
{
/// <summary>
/// 沙盒文件缓存配置
/// </summary>
internal struct Configuration
internal readonly struct Configuration
{
/// <summary>
/// 文件校验最大并发数
/// </summary>
public int FileVerifyMaxConcurrency { get; set; }
public int FileVerifyMaxConcurrency { get; }
/// <summary>
/// 文件校验级别
/// </summary>
public EFileVerifyLevel FileVerifyLevel { get; set; }
public EFileVerifyLevel FileVerifyLevel { get; }
/// <summary>
/// AssetBundle 解密器
/// </summary>
public IBundleDecryptor AssetBundleDecryptor { get; set; }
public IBundleDecryptor AssetBundleDecryptor { get; }
/// <summary>
/// RawBundle 解密器
/// </summary>
public IBundleDecryptor RawBundleDecryptor { get; set; }
public IBundleDecryptor RawBundleDecryptor { get; }
/// <summary>
/// AssetBundle 备用解密器
/// </summary>
public IBundleMemoryDecryptor AssetBundleFallbackDecryptor { get; set; }
public IBundleMemoryDecryptor AssetBundleFallbackDecryptor { get; }
public Configuration(int fileVerifyMaxConcurrency, EFileVerifyLevel fileVerifyLevel,
IBundleDecryptor assetBundleDecryptor, IBundleDecryptor rawBundleDecryptor, IBundleMemoryDecryptor assetBundleFallbackDecryptor)
{
FileVerifyMaxConcurrency = fileVerifyMaxConcurrency;
FileVerifyLevel = fileVerifyLevel;
AssetBundleDecryptor = assetBundleDecryptor;
RawBundleDecryptor = rawBundleDecryptor;
AssetBundleFallbackDecryptor = assetBundleFallbackDecryptor;
}
}
private const int HashFolderNameLength = 2;
@@ -61,7 +71,7 @@ namespace YooAsset
public string RootPath { get; }
/// <summary>
/// 只读属性
/// 是否为只读缓存
/// </summary>
public bool IsReadOnly { get; }
@@ -101,19 +111,19 @@ namespace YooAsset
{
}
/// <inheritdoc />
public virtual BCInitializeOperation InitializeAsync()
public BCInitializeOperation InitializeAsync()
{
var operation = new SBCInitializeOperation(this);
return operation;
}
/// <inheritdoc />
public virtual BCWriteCacheOperation WriteCacheAsync(BCWriteCacheOptions options)
public BCWriteCacheOperation WriteCacheAsync(BCWriteCacheOptions options)
{
var operation = new SBCWriteCacheOperation(this, options);
return operation;
}
/// <inheritdoc />
public virtual BCClearCacheOperation ClearCacheAsync(BCClearCacheOptions options)
public BCClearCacheOperation ClearCacheAsync(BCClearCacheOptions options)
{
ICacheEvictionPolicy policy = CreateEvictionPolicy(options);
if (policy == null)
@@ -125,7 +135,9 @@ namespace YooAsset
/// <summary>
/// 根据 ClearMethod 创建对应的淘汰策略实例
/// </summary>
protected virtual ICacheEvictionPolicy CreateEvictionPolicy(BCClearCacheOptions options)
/// <param name="options">清理缓存选项</param>
/// <returns>与清理方式匹配的淘汰策略实例</returns>
protected ICacheEvictionPolicy CreateEvictionPolicy(BCClearCacheOptions options)
{
if (options.ClearMethod == ClearCacheMethods.ClearAllBundleFiles)
return new EvictionAllPolicy();
@@ -142,41 +154,43 @@ namespace YooAsset
return null;
}
/// <inheritdoc />
public virtual BCVerifyCacheOperation VerifyCacheAsync(BCVerifyCacheOptions options)
public BCVerifyCacheOperation VerifyCacheAsync(BCVerifyCacheOptions options)
{
var operation = new SBCVerifyCacheOperation(this, options);
return operation;
}
/// <inheritdoc />
public virtual BCLoadBundleOperation LoadBundleAsync(BCLoadBundleOptions options)
public BCLoadBundleOperation LoadBundleAsync(BCLoadBundleOptions options)
{
if (options.Bundle.BundleType == (int)EBundleType.AssetBundle)
if (options.Bundle.GetBundleType() == (int)EBundleType.AssetBundle)
{
var operation = new SBCLoadAssetBundleOperation(this, options.Bundle);
return operation;
}
else if (options.Bundle.BundleType == (int)EBundleType.RawBundle)
else if (options.Bundle.GetBundleType() == (int)EBundleType.RawBundle)
{
var operation = new SBCLoadRawBundleOperation(this, options.Bundle);
return operation;
}
else
{
string error = $"{nameof(SandboxBundleCache)} does not support bundle type: {options.Bundle.BundleType}.";
string error = $"{nameof(SandboxBundleCache)} does not support bundle type: {options.Bundle.GetBundleType()}.";
var operation = new BCLoadBundleErrorOperation(error);
return operation;
}
}
/// <inheritdoc />
public virtual bool IsCached(string bundleGUID)
public bool IsCached(string bundleGuid)
{
return _cacheEntries.ContainsKey(bundleGUID);
return _cacheEntries.ContainsKey(bundleGuid);
}
#region
/// <summary>
/// 获取 Bundle 数据文件路径
/// </summary>
/// <param name="bundle">资源包描述</param>
/// <returns>数据文件的完整路径</returns>
internal string GetDataFilePath(PackageBundle bundle)
{
if (_dataFilePathMapping.TryGetValue(bundle.BundleGuid, out string filePath) == false)
@@ -191,6 +205,8 @@ namespace YooAsset
/// <summary>
/// 获取 Bundle 信息文件路径
/// </summary>
/// <param name="bundle">资源包描述</param>
/// <returns>信息文件的完整路径</returns>
internal string GetInfoFilePath(PackageBundle bundle)
{
if (_infoFilePathMapping.TryGetValue(bundle.BundleGuid, out string filePath) == false)
@@ -205,6 +221,8 @@ namespace YooAsset
/// <summary>
/// 获取 Bundle 数据临时文件路径
/// </summary>
/// <param name="bundle">资源包描述</param>
/// <returns>数据临时文件的完整路径</returns>
internal string GetDataTempFilePath(PackageBundle bundle)
{
string folderName = GetHashFolderName(bundle.FileHash);
@@ -214,6 +232,8 @@ namespace YooAsset
/// <summary>
/// 获取 Bundle 信息临时文件路径
/// </summary>
/// <param name="bundle">资源包描述</param>
/// <returns>信息临时文件的完整路径</returns>
internal string GetInfoTempFilePath(PackageBundle bundle)
{
string folderName = GetHashFolderName(bundle.FileHash);
@@ -223,9 +243,11 @@ namespace YooAsset
/// <summary>
/// 获取指定缓存条目
/// </summary>
internal SandboxBundleCacheEntry GetEntry(string bundleGUID)
/// <param name="bundleGuid">资源包 GUID</param>
/// <returns>对应的沙盒缓存条目</returns>
internal SandboxBundleCacheEntry GetEntry(string bundleGuid)
{
if (_cacheEntries.TryGetValue(bundleGUID, out SandboxBundleCacheEntry entry))
if (_cacheEntries.TryGetValue(bundleGuid, out SandboxBundleCacheEntry entry))
return entry;
else
return null;
@@ -234,6 +256,7 @@ namespace YooAsset
/// <summary>
/// 获取所有缓存条目
/// </summary>
/// <returns>当前字典中全部沙盒缓存条目的只读集合</returns>
internal IReadOnlyCollection<SandboxBundleCacheEntry> GetAllEntries()
{
return _cacheEntries.Values;
@@ -242,26 +265,31 @@ namespace YooAsset
/// <summary>
/// 添加指定缓存条目
/// </summary>
internal void AddEntry(string bundleGUID, SandboxBundleCacheEntry cacheEntry)
/// <param name="bundleGuid">资源包 GUID</param>
/// <param name="cacheEntry">沙盒缓存条目</param>
internal void AddEntry(string bundleGuid, SandboxBundleCacheEntry cacheEntry)
{
if (_cacheEntries.ContainsKey(bundleGUID))
throw new YooInternalException($"Cache entry already exists: '{bundleGUID}'.");
if (_cacheEntries.ContainsKey(bundleGuid))
throw new YooInternalException($"Cache entry already exists: '{bundleGuid}'.");
_cacheEntries.Add(bundleGUID, cacheEntry);
_cacheEntries.Add(bundleGuid, cacheEntry);
SpaceOccupied += cacheEntry.GetFileSize();
}
/// <summary>
/// 删除指定缓存条目
/// </summary>
internal void RemoveEntry(string bundleGUID)
/// <param name="bundleGuid">资源包 GUID</param>
internal void RemoveEntry(string bundleGuid)
{
if (_cacheEntries.TryGetValue(bundleGUID, out SandboxBundleCacheEntry entry))
if (_cacheEntries.TryGetValue(bundleGuid, out SandboxBundleCacheEntry entry))
{
_cacheEntries.Remove(bundleGUID);
_dataFilePathMapping.Remove(bundleGUID);
_infoFilePathMapping.Remove(bundleGUID);
_cacheEntries.Remove(bundleGuid);
_dataFilePathMapping.Remove(bundleGuid);
_infoFilePathMapping.Remove(bundleGuid);
SpaceOccupied -= entry.GetFileSize();
if (SpaceOccupied < 0)
SpaceOccupied = 0;
entry.Delete();
}
}
@@ -277,4 +305,4 @@ namespace YooAsset
}
#endregion
}
}
}

View File

@@ -4,7 +4,7 @@ namespace YooAsset
/// <summary>
/// 沙盒文件缓存常量定义
/// </summary>
internal class SandboxBundleCacheConsts
internal static class SandboxBundleCacheConsts
{
/// <summary>
/// 数据文件名称

View File

@@ -13,7 +13,7 @@ namespace YooAsset
/// <summary>
/// 资源包唯一标识
/// </summary>
public string BundleGUID { get; private set; }
public string BundleGuid { get; private set; }
/// <summary>
/// 信息文件路径
@@ -27,14 +27,14 @@ namespace YooAsset
/// <summary>
/// 创建沙盒文件缓存条目
/// 创建沙盒文件缓存条目实例
/// </summary>
/// <param name="bundleGUID">资源包唯一标识</param>
/// <param name="bundleGuid">资源包唯一标识</param>
/// <param name="infoFilePath">信息文件路径</param>
/// <param name="dataFilePath">数据文件路径</param>
public SandboxBundleCacheEntry(string bundleGUID, string infoFilePath, string dataFilePath)
public SandboxBundleCacheEntry(string bundleGuid, string infoFilePath, string dataFilePath)
{
BundleGUID = bundleGUID;
BundleGuid = bundleGuid;
InfoFilePath = infoFilePath;
DataFilePath = dataFilePath;
}
@@ -61,7 +61,7 @@ namespace YooAsset
}
catch (Exception ex)
{
YooLogger.Error($"Failed to delete sandbox file. Error: {ex.Message}.");
YooLogger.LogError($"Failed to delete sandbox file: {ex.Message}.");
return false;
}
}

View File

@@ -3,14 +3,14 @@ using System.IO;
namespace YooAsset
{
/// <summary>
/// 搜索的文件信息,用于缓存文件校验流程
/// 搜索的文件信息,用于缓存文件校验流程
/// </summary>
internal class SearchFileInfo
{
/// <summary>
/// 资源包唯一标识
/// </summary>
public string BundleGUID { get; private set; }
public string BundleGuid { get; private set; }
/// <summary>
/// 缓存文件夹路径
@@ -33,15 +33,15 @@ namespace YooAsset
public volatile int VerifyResultCode = 0;
/// <summary>
/// 创建验证文件信息
/// 创建验证文件信息实例
/// </summary>
/// <param name="bundleGUID">资源包唯一标识</param>
/// <param name="bundleGuid">资源包唯一标识</param>
/// <param name="folderPath">缓存文件夹路径</param>
/// <param name="dataFilePath">数据文件路径</param>
/// <param name="infoFilePath">信息文件路径</param>
public SearchFileInfo(string bundleGUID, string folderPath, string dataFilePath, string infoFilePath)
public SearchFileInfo(string bundleGuid, string folderPath, string dataFilePath, string infoFilePath)
{
BundleGUID = bundleGUID;
BundleGuid = bundleGuid;
FolderPath = folderPath;
DataFilePath = dataFilePath;
InfoFilePath = infoFilePath;
@@ -58,8 +58,8 @@ namespace YooAsset
}
catch (System.Exception ex)
{
YooLogger.Warning($"Failed to delete cache bundle folder: {ex}.");
YooLogger.LogWarning($"Failed to delete cache bundle folder: {ex}.");
}
}
}
}
}

View File

@@ -2,41 +2,41 @@
namespace YooAsset
{
/// <summary>
/// 临时的文件信息,用于存储待验证的下载文件
/// 临时的文件信息,用于存储待验证的下载文件
/// </summary>
internal class TempFileInfo
{
/// <summary>
/// 临时文件路径
/// </summary>
public string FilePath { private set; get; }
public string FilePath { get; private set; }
/// <summary>
/// 文件CRC校验值
/// </summary>
public uint FileCRC { private set; get; }
public uint FileCrc { get; private set; }
/// <summary>
/// 文件大小(字节)
/// </summary>
public long FileSize { private set; get; }
public long FileSize { get; private set; }
/// <summary>
/// 验证结果码(原子操作对象,用于线程安全)
/// 验证结果码(原子操作对象,用于线程安全)
/// </summary>
public volatile int VerifyResultCode = 0;
/// <summary>
/// 创建临时文件信息
/// 创建临时文件信息实例
/// </summary>
/// <param name="filePath">临时文件路径</param>
/// <param name="fileCRC">文件CRC校验值</param>
/// <param name="fileCrc">文件CRC校验值</param>
/// <param name="fileSize">文件大小(字节)</param>
public TempFileInfo(string filePath, uint fileCRC, long fileSize)
public TempFileInfo(string filePath, uint fileCrc, long fileSize)
{
FilePath = filePath;
FileCRC = fileCRC;
FileCrc = fileCrc;
FileSize = fileSize;
}
}
}
}

View File

@@ -4,13 +4,17 @@ namespace YooAsset
/// <summary>
/// Web远端文件缓存初始化操作
/// </summary>
internal class WRBCInitializeOperation : BCInitializeOperation
internal sealed class WRBCInitializeOperation : BCInitializeOperation
{
private readonly WebRemoteBundleCache _fileCache;
public WRBCInitializeOperation(WebRemoteBundleCache cache)
/// <summary>
/// 创建 Web 远端缓存初始化操作实例
/// </summary>
/// <param name="fileCache">Web 远端文件缓存系统</param>
public WRBCInitializeOperation(WebRemoteBundleCache fileCache)
{
_fileCache = cache;
_fileCache = fileCache;
}
protected override void InternalStart()
{

View File

@@ -4,7 +4,7 @@ namespace YooAsset
/// <summary>
/// Web远端文件缓存加载 AssetBundle 操作
/// </summary>
internal class WRBCLoadAssetBundleOperation : BCLoadBundleOperation
internal sealed class WRBCLoadAssetBundleOperation : BCLoadBundleOperation
{
private enum ESteps
{
@@ -20,6 +20,11 @@ namespace YooAsset
private WebRemoteBundleCacheEntry _cacheEntry;
private ESteps _steps = ESteps.None;
/// <summary>
/// 创建 Web 远端 AssetBundle 加载操作实例
/// </summary>
/// <param name="fileCache">Web 远端文件缓存系统</param>
/// <param name="options">加载资源包操作选项</param>
public WRBCLoadAssetBundleOperation(WebRemoteBundleCache fileCache, BCLoadBundleOptions options)
{
_fileCache = fileCache;
@@ -52,17 +57,17 @@ namespace YooAsset
{
if (_loadWebAssetBundleOp == null)
{
var options = new LoadWebAssetBundleOptions();
options.CacheName = _fileCache.GetType().Name;
options.Bundle = _options.Bundle;
options.CandidateUrls = _cacheEntry.URLs;
options.AssetBundleDecryptor = _fileCache.Config.AssetBundleDecryptor;
options.DownloadBackend = _fileCache.Config.DownloadBackend;
options.DownloadVerifyLevel = _fileCache.Config.DownloadVerifyLevel;
options.WatchdogTimeout = _fileCache.Config.WatchdogTimeout;
options.DisableUnityWebCache = _fileCache.Config.DisableUnityWebCache;
options.DownloadRetryPolicy = _fileCache.Config.DownloadRetryPolicy;
options.DownloadUrlPolicy = _fileCache.Config.DownloadUrlPolicy;
var options = new LoadWebAssetBundleOptions(
cacheName: _fileCache.GetType().Name,
bundle: _options.Bundle,
candidateUrls: _cacheEntry.URLs,
assetBundleDecryptor: _fileCache.Config.AssetBundleDecryptor,
downloadBackend: _fileCache.Config.DownloadBackend,
downloadVerifyLevel: _fileCache.Config.DownloadVerifyLevel,
watchdogTimeout: _fileCache.Config.WatchdogTimeout,
disableUnityWebCache: _fileCache.Config.DisableUnityWebCache,
downloadRetryPolicy: _fileCache.Config.DownloadRetryPolicy,
downloadUrlPolicy: _fileCache.Config.DownloadUrlPolicy);
if (_options.Bundle.IsEncrypted)
_loadWebAssetBundleOp = new LoadWebEncryptedAssetBundleOperation(options);
@@ -99,7 +104,7 @@ namespace YooAsset
{
_steps = ESteps.Done;
SetError($"{nameof(WebRemoteBundleCache)} does not support synchronous asset bundle loading.");
YooLogger.Error(Error);
YooLogger.LogError(Error);
}
}
}

View File

@@ -4,54 +4,68 @@ using System.Collections.Generic;
namespace YooAsset
{
/// <summary>
/// Web远端文件缓存系统用于从远程服务器加载资源
/// Web远端文件缓存系统用于从远程服务器加载资源
/// </summary>
internal class WebRemoteBundleCache : IBundleCache
{
/// <summary>
/// Web远端文件缓存配置
/// </summary>
internal struct Configuration
internal readonly struct Configuration
{
/// <summary>
/// 看门狗超时时间
/// </summary>
public int WatchdogTimeout { get; set; }
public int WatchdogTimeout { get; }
/// <summary>
/// 禁用Unity的网络缓存
/// </summary>
public bool DisableUnityWebCache { get; set; }
public bool DisableUnityWebCache { get; }
/// <summary>
/// 下载数据校验级别
/// </summary>
public EFileVerifyLevel DownloadVerifyLevel { get; set; }
public EFileVerifyLevel DownloadVerifyLevel { get; }
/// <summary>
/// AssetBundle 解密器
/// </summary>
public IBundleDecryptor AssetBundleDecryptor { get; set; }
public IBundleDecryptor AssetBundleDecryptor { get; }
/// <summary>
/// 远程服务接口
/// </summary>
public IRemoteService RemoteService { get; set; }
public IRemoteService RemoteService { get; }
/// <summary>
/// 下载后台接口
/// </summary>
public IDownloadBackend DownloadBackend { get; set; }
public IDownloadBackend DownloadBackend { get; }
/// <summary>
/// 下载重试判定策略
/// </summary>
public IDownloadRetryPolicy DownloadRetryPolicy { get; set; }
public IDownloadRetryPolicy DownloadRetryPolicy { get; }
/// <summary>
/// URL 选择策略
/// </summary>
public IDownloadUrlPolicy DownloadUrlPolicy { get; set; }
public IDownloadUrlPolicy DownloadUrlPolicy { get; }
public Configuration(int watchdogTimeout, bool disableUnityWebCache,
EFileVerifyLevel downloadVerifyLevel, IBundleDecryptor assetBundleDecryptor, IRemoteService remoteService,
IDownloadBackend downloadBackend, IDownloadRetryPolicy downloadRetryPolicy, IDownloadUrlPolicy downloadUrlPolicy)
{
WatchdogTimeout = watchdogTimeout;
DisableUnityWebCache = disableUnityWebCache;
DownloadVerifyLevel = downloadVerifyLevel;
AssetBundleDecryptor = assetBundleDecryptor;
RemoteService = remoteService;
DownloadBackend = downloadBackend;
DownloadRetryPolicy = downloadRetryPolicy;
DownloadUrlPolicy = downloadUrlPolicy;
}
}
private readonly Dictionary<string, WebRemoteBundleCacheEntry> _cacheEntries = new Dictionary<string, WebRemoteBundleCacheEntry>(10000);
@@ -73,7 +87,7 @@ namespace YooAsset
public string RootPath { get; }
/// <summary>
/// 只读属性
/// 是否为只读缓存
/// </summary>
public bool IsReadOnly { get; }
@@ -113,46 +127,46 @@ namespace YooAsset
{
}
/// <inheritdoc />
public virtual BCInitializeOperation InitializeAsync()
public BCInitializeOperation InitializeAsync()
{
var operation = new WRBCInitializeOperation(this);
return operation;
}
/// <inheritdoc />
public virtual BCWriteCacheOperation WriteCacheAsync(BCWriteCacheOptions options)
public BCWriteCacheOperation WriteCacheAsync(BCWriteCacheOptions options)
{
var operation = new BCWriteCacheCompleteOperation($"{nameof(WebRemoteBundleCache)} is readonly.");
return operation;
}
/// <inheritdoc />
public virtual BCClearCacheOperation ClearCacheAsync(BCClearCacheOptions options)
public BCClearCacheOperation ClearCacheAsync(BCClearCacheOptions options)
{
var operation = new BCClearCacheCompleteOperation();
return operation;
}
/// <inheritdoc />
public virtual BCVerifyCacheOperation VerifyCacheAsync(BCVerifyCacheOptions options)
public BCVerifyCacheOperation VerifyCacheAsync(BCVerifyCacheOptions options)
{
var operation = new BCVerifyCacheCompleteOperation();
return operation;
}
/// <inheritdoc />
public virtual BCLoadBundleOperation LoadBundleAsync(BCLoadBundleOptions options)
public BCLoadBundleOperation LoadBundleAsync(BCLoadBundleOptions options)
{
if (options.Bundle.BundleType == (int)EBundleType.AssetBundle)
if (options.Bundle.GetBundleType() == (int)EBundleType.AssetBundle)
{
var operation = new WRBCLoadAssetBundleOperation(this, options);
return operation;
}
else
{
string error = $"{nameof(WebRemoteBundleCache)} does not support bundle type: {options.Bundle.BundleType}.";
string error = $"{nameof(WebRemoteBundleCache)} does not support bundle type: {options.Bundle.GetBundleType()}.";
var operation = new BCLoadBundleErrorOperation(error);
return operation;
}
}
/// <inheritdoc />
public virtual bool IsCached(string bundleGUID)
public bool IsCached(string bundleGuid)
{
return true;
}
@@ -161,6 +175,8 @@ namespace YooAsset
/// <summary>
/// 获取或创建指定资源包的缓存条目
/// </summary>
/// <param name="bundle">资源包描述</param>
/// <returns>已存在则返回对应条目;否则创建并登记后返回新条目。</returns>
internal WebRemoteBundleCacheEntry GetEntry(PackageBundle bundle)
{
if (_cacheEntries.TryGetValue(bundle.BundleGuid, out WebRemoteBundleCacheEntry entry))
@@ -169,7 +185,7 @@ namespace YooAsset
}
else
{
var urls = Config.RemoteService.GetRemoteUrls(bundle.FileName);
var urls = Config.RemoteService.GetRemoteUrls(bundle.GetFileName());
var newEntry = new WebRemoteBundleCacheEntry(bundle.BundleGuid, urls);
_cacheEntries.Add(bundle.BundleGuid, newEntry);
return newEntry;
@@ -177,4 +193,4 @@ namespace YooAsset
}
#endregion
}
}
}

View File

@@ -10,7 +10,7 @@ namespace YooAsset
/// <summary>
/// 资源包唯一标识
/// </summary>
public string BundleGUID { get; private set; }
public string BundleGuid { get; private set; }
/// <summary>
/// 候选下载地址列表
@@ -18,13 +18,13 @@ namespace YooAsset
public IReadOnlyList<string> URLs { get; private set; }
/// <summary>
/// 创建Web远端文件缓存条目
/// 创建 Web 远端文件缓存条目实例
/// </summary>
/// <param name="bundleGUID">资源包唯一标识</param>
/// <param name="bundleGuid">资源包唯一标识</param>
/// <param name="urls">候选下载地址列表</param>
public WebRemoteBundleCacheEntry(string bundleGUID, IReadOnlyList<string> urls)
public WebRemoteBundleCacheEntry(string bundleGuid, IReadOnlyList<string> urls)
{
BundleGUID = bundleGUID;
BundleGuid = bundleGuid;
URLs = urls;
}
}

View File

@@ -4,7 +4,7 @@ namespace YooAsset
/// <summary>
/// Web服务器文件缓存初始化操作
/// </summary>
internal class WSBCInitializeOperation : BCInitializeOperation
internal sealed class WSBCInitializeOperation : BCInitializeOperation
{
private enum ESteps
{
@@ -18,9 +18,13 @@ namespace YooAsset
private LoadBuiltinCatalogOperation _loadBuiltinCatalogOp;
private ESteps _steps = ESteps.None;
public WSBCInitializeOperation(WebServerBundleCache cache)
/// <summary>
/// 创建 Web 服务器缓存初始化操作实例
/// </summary>
/// <param name="fileCache">Web 服务器文件缓存系统</param>
public WSBCInitializeOperation(WebServerBundleCache fileCache)
{
_fileCache = cache;
_fileCache = fileCache;
}
protected override void InternalStart()
{
@@ -35,10 +39,10 @@ namespace YooAsset
{
if (_loadBuiltinCatalogOp == null)
{
var options = new LoadBuiltinCatalogOptions();
options.PackageName = _fileCache.PackageName;
options.FilePath = _fileCache.GetCatalogBinaryFileLoadPath();
options.DownloadBackend = _fileCache.Config.DownloadBackend;
var options = new LoadBuiltinCatalogOptions(
packageName: _fileCache.PackageName,
filePath: _fileCache.GetCatalogBinaryFileLoadPath(),
downloadBackend: _fileCache.Config.DownloadBackend);
_loadBuiltinCatalogOp = new LoadBuiltinCatalogOperation(options);
_loadBuiltinCatalogOp.StartOperation();
AddChildOperation(_loadBuiltinCatalogOp);
@@ -65,8 +69,8 @@ namespace YooAsset
foreach (var fileEntry in catalog.Entries)
{
string filePath = PathUtility.Combine(_fileCache.RootPath, fileEntry.FileName);
var cacheEntry = new WebServerBundleCacheEntry(fileEntry.BundleGUID, filePath);
_fileCache.AddEntry(fileEntry.BundleGUID, cacheEntry);
var cacheEntry = new WebServerBundleCacheEntry(fileEntry.BundleGuid, filePath);
_fileCache.AddEntry(fileEntry.BundleGuid, cacheEntry);
}
_steps = ESteps.Done;

View File

@@ -4,7 +4,7 @@ namespace YooAsset
/// <summary>
/// Web服务器文件缓存加载 AssetBundle 操作
/// </summary>
internal class WSBCLoadAssetBundleOperation : BCLoadBundleOperation
internal sealed class WSBCLoadAssetBundleOperation : BCLoadBundleOperation
{
private enum ESteps
{
@@ -20,6 +20,11 @@ namespace YooAsset
private WebServerBundleCacheEntry _cacheEntry;
private ESteps _steps = ESteps.None;
/// <summary>
/// 创建 Web 服务器 AssetBundle 加载操作实例
/// </summary>
/// <param name="fileCache">Web 服务器文件缓存系统</param>
/// <param name="options">加载资源包操作选项</param>
public WSBCLoadAssetBundleOperation(WebServerBundleCache fileCache, BCLoadBundleOptions options)
{
_fileCache = fileCache;
@@ -53,17 +58,17 @@ namespace YooAsset
if (_loadWebAssetBundleOp == null)
{
string url = DownloadUrlHelper.ToLocalFileUrl(_cacheEntry.FilePath);
var options = new LoadWebAssetBundleOptions();
options.CacheName = _fileCache.GetType().Name;
options.Bundle = _options.Bundle;
options.CandidateUrls = new[] { url };
options.AssetBundleDecryptor = _fileCache.Config.AssetBundleDecryptor;
options.DownloadBackend = _fileCache.Config.DownloadBackend;
options.DownloadVerifyLevel = _fileCache.Config.DownloadVerifyLevel;
options.WatchdogTimeout = _fileCache.Config.WatchdogTimeout;
options.DisableUnityWebCache = _fileCache.Config.DisableUnityWebCache;
options.DownloadRetryPolicy = _fileCache.Config.DownloadRetryPolicy;
options.DownloadUrlPolicy = _fileCache.Config.DownloadUrlPolicy;
var options = new LoadWebAssetBundleOptions(
cacheName: _fileCache.GetType().Name,
bundle: _options.Bundle,
candidateUrls: new[] { url },
assetBundleDecryptor: _fileCache.Config.AssetBundleDecryptor,
downloadBackend: _fileCache.Config.DownloadBackend,
downloadVerifyLevel: _fileCache.Config.DownloadVerifyLevel,
watchdogTimeout: _fileCache.Config.WatchdogTimeout,
disableUnityWebCache: _fileCache.Config.DisableUnityWebCache,
downloadRetryPolicy: _fileCache.Config.DownloadRetryPolicy,
downloadUrlPolicy: _fileCache.Config.DownloadUrlPolicy);
if (_options.Bundle.IsEncrypted)
_loadWebAssetBundleOp = new LoadWebEncryptedAssetBundleOperation(options);
@@ -100,7 +105,7 @@ namespace YooAsset
{
_steps = ESteps.Done;
SetError($"{nameof(WebServerBundleCache)} does not support synchronous asset bundle loading.");
YooLogger.Error(Error);
YooLogger.LogError(Error);
}
}
}

View File

@@ -4,49 +4,62 @@ using System.Collections.Generic;
namespace YooAsset
{
/// <summary>
/// Web服务器文件缓存系统用于WebGL平台从服务器加载资源
/// Web服务器文件缓存系统用于WebGL平台从服务器加载资源
/// </summary>
internal class WebServerBundleCache : IBundleCache
{
/// <summary>
/// Web服务器文件缓存配置
/// </summary>
internal struct Configuration
internal readonly struct Configuration
{
/// <summary>
/// 看门狗超时时间
/// </summary>
public int WatchdogTimeout { get; set; }
public int WatchdogTimeout { get; }
/// <summary>
/// 禁用Unity的网络缓存
/// </summary>
public bool DisableUnityWebCache { get; set; }
public bool DisableUnityWebCache { get; }
/// <summary>
/// 下载数据校验级别
/// </summary>
public EFileVerifyLevel DownloadVerifyLevel { get; set; }
public EFileVerifyLevel DownloadVerifyLevel { get; }
/// <summary>
/// AssetBundle 解密器
/// </summary>
public IBundleDecryptor AssetBundleDecryptor { get; set; }
public IBundleDecryptor AssetBundleDecryptor { get; }
/// <summary>
/// 下载后台
/// </summary>
public IDownloadBackend DownloadBackend { get; set; }
public IDownloadBackend DownloadBackend { get; }
/// <summary>
/// 下载重试判定策略
/// </summary>
public IDownloadRetryPolicy DownloadRetryPolicy { get; set; }
public IDownloadRetryPolicy DownloadRetryPolicy { get; }
/// <summary>
/// URL 选择策略
/// </summary>
public IDownloadUrlPolicy DownloadUrlPolicy { get; set; }
public IDownloadUrlPolicy DownloadUrlPolicy { get; }
public Configuration(int watchdogTimeout, bool disableUnityWebCache,
EFileVerifyLevel downloadVerifyLevel, IBundleDecryptor assetBundleDecryptor,
IDownloadBackend downloadBackend, IDownloadRetryPolicy downloadRetryPolicy, IDownloadUrlPolicy downloadUrlPolicy)
{
WatchdogTimeout = watchdogTimeout;
DisableUnityWebCache = disableUnityWebCache;
DownloadVerifyLevel = downloadVerifyLevel;
AssetBundleDecryptor = assetBundleDecryptor;
DownloadBackend = downloadBackend;
DownloadRetryPolicy = downloadRetryPolicy;
DownloadUrlPolicy = downloadUrlPolicy;
}
}
private readonly Dictionary<string, WebServerBundleCacheEntry> _cacheEntries = new Dictionary<string, WebServerBundleCacheEntry>(10000);
@@ -68,7 +81,7 @@ namespace YooAsset
public string RootPath { get; }
/// <summary>
/// 只读属性
/// 是否为只读缓存
/// </summary>
public bool IsReadOnly { get; }
@@ -108,57 +121,59 @@ namespace YooAsset
{
}
/// <inheritdoc />
public virtual BCInitializeOperation InitializeAsync()
public BCInitializeOperation InitializeAsync()
{
var operation = new WSBCInitializeOperation(this);
return operation;
}
/// <inheritdoc />
public virtual BCWriteCacheOperation WriteCacheAsync(BCWriteCacheOptions options)
public BCWriteCacheOperation WriteCacheAsync(BCWriteCacheOptions options)
{
var operation = new BCWriteCacheCompleteOperation($"{nameof(WebServerBundleCache)} is readonly.");
return operation;
}
/// <inheritdoc />
public virtual BCClearCacheOperation ClearCacheAsync(BCClearCacheOptions options)
public BCClearCacheOperation ClearCacheAsync(BCClearCacheOptions options)
{
var operation = new BCClearCacheCompleteOperation();
return operation;
}
/// <inheritdoc />
public virtual BCVerifyCacheOperation VerifyCacheAsync(BCVerifyCacheOptions options)
public BCVerifyCacheOperation VerifyCacheAsync(BCVerifyCacheOptions options)
{
var operation = new BCVerifyCacheCompleteOperation();
return operation;
}
/// <inheritdoc />
public virtual BCLoadBundleOperation LoadBundleAsync(BCLoadBundleOptions options)
public BCLoadBundleOperation LoadBundleAsync(BCLoadBundleOptions options)
{
if (options.Bundle.BundleType == (int)EBundleType.AssetBundle)
if (options.Bundle.GetBundleType() == (int)EBundleType.AssetBundle)
{
var operation = new WSBCLoadAssetBundleOperation(this, options);
return operation;
}
else
{
string error = $"{nameof(WebServerBundleCache)} does not support bundle type: {options.Bundle.BundleType}.";
string error = $"{nameof(WebServerBundleCache)} does not support bundle type: {options.Bundle.GetBundleType()}.";
var operation = new BCLoadBundleErrorOperation(error);
return operation;
}
}
/// <inheritdoc />
public virtual bool IsCached(string bundleGUID)
public bool IsCached(string bundleGuid)
{
return _cacheEntries.ContainsKey(bundleGUID);
return _cacheEntries.ContainsKey(bundleGuid);
}
#region
/// <summary>
/// 获取指定缓存条目
/// </summary>
internal WebServerBundleCacheEntry GetEntry(string bundleGUID)
/// <param name="bundleGuid">资源包 GUID</param>
/// <returns>对应的 Web 服务器缓存条目</returns>
internal WebServerBundleCacheEntry GetEntry(string bundleGuid)
{
if (_cacheEntries.TryGetValue(bundleGUID, out WebServerBundleCacheEntry entry))
if (_cacheEntries.TryGetValue(bundleGuid, out WebServerBundleCacheEntry entry))
return entry;
else
return null;
@@ -167,21 +182,24 @@ namespace YooAsset
/// <summary>
/// 添加指定缓存条目
/// </summary>
internal void AddEntry(string bundleGUID, WebServerBundleCacheEntry cacheEntry)
/// <param name="bundleGuid">资源包 GUID</param>
/// <param name="cacheEntry">Web 服务器缓存条目</param>
internal void AddEntry(string bundleGuid, WebServerBundleCacheEntry cacheEntry)
{
if (_cacheEntries.ContainsKey(bundleGUID))
throw new YooInternalException($"Cache entry already exists: '{bundleGUID}'.");
if (_cacheEntries.ContainsKey(bundleGuid))
throw new YooInternalException($"Cache entry already exists: '{bundleGuid}'.");
_cacheEntries.Add(bundleGUID, cacheEntry);
_cacheEntries.Add(bundleGuid, cacheEntry);
}
/// <summary>
/// 获取Catalog文件加载路径
/// </summary>
/// <returns>文件的完整加载路径</returns>
internal string GetCatalogBinaryFileLoadPath()
{
return PathUtility.Combine(RootPath, BuiltinCatalogConsts.BinaryFileName);
}
#endregion
}
}
}

View File

@@ -9,7 +9,7 @@ namespace YooAsset
/// <summary>
/// 资源包唯一标识
/// </summary>
public string BundleGUID { get; private set; }
public string BundleGuid { get; private set; }
/// <summary>
/// 资源包文件路径
@@ -17,13 +17,13 @@ namespace YooAsset
public string FilePath { get; private set; }
/// <summary>
/// 创建Web服务器文件缓存条目
/// 创建 Web 服务器文件缓存条目实例
/// </summary>
/// <param name="bundleGUID">资源包唯一标识</param>
/// <param name="bundleGuid">资源包唯一标识</param>
/// <param name="filePath">资源包文件路径</param>
public WebServerBundleCacheEntry(string bundleGUID, string filePath)
public WebServerBundleCacheEntry(string bundleGuid, string filePath)
{
BundleGUID = bundleGUID;
BundleGuid = bundleGuid;
FilePath = filePath;
}
}

View File

@@ -2,14 +2,14 @@
namespace YooAsset
{
/// <summary>
/// 资源包类型枚举
/// 资源包类型
/// </summary>
public enum EBundleType
{
/// <summary>
/// 未类型
/// 未指定类型
/// </summary>
Unknown = 0,
None = 0,
/// <summary>
/// 虚拟资源包

View File

@@ -3,7 +3,7 @@ using UnityEngine.SceneManagement;
namespace YooAsset
{
/// <summary>
/// 资源包句柄接口,提供对已加载资源包的操作能力
/// 资源包句柄接口,提供对已加载资源包的操作能力
/// </summary>
internal interface IBundleHandle
{
@@ -18,33 +18,33 @@ namespace YooAsset
void UnloadBundle();
/// <summary>
/// 异步加载指定的主资源对象
/// 加载指定的主资源对象
/// </summary>
/// <param name="assetInfo">待加载资源的描述信息</param>
/// <returns>用于跟踪加载过程的异步操作对象</returns>
BHLoadAssetOperation LoadAssetAsync(AssetInfo assetInfo);
/// <summary>
/// 异步加载资源包内的全部资源对象
/// 加载资源包内的全部资源对象
/// </summary>
/// <param name="assetInfo">待加载资源的描述信息</param>
/// <returns>用于跟踪加载过程的异步操作对象</returns>
BHLoadAllAssetsOperation LoadAllAssetsAsync(AssetInfo assetInfo);
/// <summary>
/// 异步加载指定资源对应的全部子资源对象
/// 加载指定资源对应的全部子资源对象
/// </summary>
/// <param name="assetInfo">待加载资源的描述信息</param>
/// <returns>用于跟踪加载过程的异步操作对象</returns>
BHLoadSubAssetsOperation LoadSubAssetsAsync(AssetInfo assetInfo);
/// <summary>
/// 异步加载指定的场景资源
/// 加载指定的场景资源
/// </summary>
/// <param name="assetInfo">待加载场景的资源信息</param>
/// <param name="loadSceneParams">场景加载参数</param>
/// <param name="loadSceneParams">场景加载选项</param>
/// <param name="allowSceneActivation">是否允许场景在加载完成后立即激活</param>
/// <returns>用于跟踪场景加载过程的异步操作对象</returns>
BHLoadSceneOperation LoadSceneAsync(AssetInfo assetInfo, LoadSceneParameters loadSceneParams, bool allowSceneActivation);
}
}
}

View File

@@ -14,6 +14,14 @@ namespace YooAsset
/// <summary>
/// 允许场景在加载完成后进入激活阶段
/// </summary>
public abstract void AllowSceneActivation();
public void AllowSceneActivation()
{
InternalAllowSceneActivation();
}
/// <summary>
/// 执行场景激活的方法
/// </summary>
protected abstract void InternalAllowSceneActivation();
}
}

View File

@@ -7,7 +7,7 @@ namespace YooAsset
/// <summary>
/// AssetBundle资源包句柄
/// </summary>
internal class AssetBundleHandle : IBundleHandle
internal sealed class AssetBundleHandle : IBundleHandle
{
private readonly string _bundleFilePath;
private readonly PackageBundle _packageBundle;
@@ -22,6 +22,13 @@ namespace YooAsset
get { return _bundleFilePath; }
}
/// <summary>
/// 创建AssetBundle资源包句柄实例
/// </summary>
/// <param name="bundleFilePath">资源包文件的本地路径</param>
/// <param name="packageBundle">资源包描述</param>
/// <param name="assetBundle">已加载的 Unity AssetBundle 对象</param>
/// <param name="bundleStream">加载 AssetBundle 时使用的文件流</param>
public AssetBundleHandle(string bundleFilePath, PackageBundle packageBundle, AssetBundle assetBundle, Stream bundleStream)
{
_bundleFilePath = bundleFilePath;
@@ -42,7 +49,6 @@ namespace YooAsset
if (_bundleStream != null)
{
_bundleStream.Close();
_bundleStream.Dispose();
}
}

View File

@@ -3,11 +3,11 @@ using UnityEngine;
namespace YooAsset
{
/// <summary>
/// AssetBundle的加载所有资源操作
/// AssetBundle 中加载全部资源对象
/// </summary>
internal class ABHLoadAllAssetsOperation : BHLoadAllAssetsOperation
internal sealed class ABHLoadAllAssetsOperation : BHLoadAllAssetsOperation
{
protected enum ESteps
private enum ESteps
{
None,
CheckBundle,
@@ -22,6 +22,12 @@ namespace YooAsset
private AssetBundleRequest _request;
private ESteps _steps = ESteps.None;
/// <summary>
/// 创建实例
/// </summary>
/// <param name="packageBundle">资源包描述</param>
/// <param name="assetBundle">已加载的 Unity AssetBundle 对象</param>
/// <param name="assetInfo">待加载资源信息</param>
public ABHLoadAllAssetsOperation(PackageBundle packageBundle, AssetBundle assetBundle, AssetInfo assetInfo)
{
_packageBundle = packageBundle;
@@ -42,7 +48,7 @@ namespace YooAsset
if (_assetBundle == null)
{
_steps = ESteps.Done;
SetError($"The bundle {_packageBundle.BundleName} has been destroyed due to Unity engine bugs.");
SetError($"Bundle '{_packageBundle.BundleName}' has been destroyed due to Unity engine bugs.");
return;
}
@@ -77,7 +83,7 @@ namespace YooAsset
if (IsWaitForCompletion)
{
// 强制挂起主线程(注意:该操作会很耗时)
YooLogger.Warning("Blocking the main thread while loading Unity assets.");
YooLogger.LogWarning("Blocking the main thread while loading Unity assets.");
Result = _request.allAssets;
}
else
@@ -93,13 +99,13 @@ namespace YooAsset
{
string error;
if (_assetInfo.AssetType == null)
error = $"Failed to load all assets: {_assetInfo.AssetPath} AssetType: null AssetBundle: {_packageBundle.BundleName}";
error = $"Failed to load all assets: '{_assetInfo.AssetPath}' AssetType: null AssetBundle: '{_packageBundle.BundleName}'.";
else
error = $"Failed to load all assets: {_assetInfo.AssetPath} AssetType: {_assetInfo.AssetType} AssetBundle: {_packageBundle.BundleName}";
error = $"Failed to load all assets: '{_assetInfo.AssetPath}' AssetType: {_assetInfo.AssetType} AssetBundle: '{_packageBundle.BundleName}'.";
_steps = ESteps.Done;
SetError(error);
YooLogger.Error(error);
YooLogger.LogError(error);
}
else
{

View File

@@ -3,11 +3,11 @@ using UnityEngine;
namespace YooAsset
{
/// <summary>
/// AssetBundle加载单个资源操作
/// AssetBundle加载单个资源对象
/// </summary>
internal class ABHLoadAssetOperation : BHLoadAssetOperation
internal sealed class ABHLoadAssetOperation : BHLoadAssetOperation
{
protected enum ESteps
private enum ESteps
{
None,
CheckBundle,
@@ -22,6 +22,12 @@ namespace YooAsset
private AssetBundleRequest _request;
private ESteps _steps = ESteps.None;
/// <summary>
/// 创建实例
/// </summary>
/// <param name="packageBundle">资源包描述</param>
/// <param name="assetBundle">已加载的 Unity AssetBundle 对象</param>
/// <param name="assetInfo">待加载资源信息</param>
public ABHLoadAssetOperation(PackageBundle packageBundle, AssetBundle assetBundle, AssetInfo assetInfo)
{
_packageBundle = packageBundle;
@@ -42,7 +48,7 @@ namespace YooAsset
if (_assetBundle == null)
{
_steps = ESteps.Done;
SetError($"The bundle {_packageBundle.BundleName} has been destroyed due to Unity engine bugs.");
SetError($"Bundle '{_packageBundle.BundleName}' has been destroyed due to Unity engine bugs.");
return;
}
@@ -77,7 +83,7 @@ namespace YooAsset
if (IsWaitForCompletion)
{
// 强制挂起主线程(注意:该操作会很耗时)
YooLogger.Warning("Blocking the main thread while loading a Unity asset.");
YooLogger.LogWarning("Blocking the main thread while loading a Unity asset.");
Result = _request.asset;
}
else
@@ -93,13 +99,13 @@ namespace YooAsset
{
string error;
if (_assetInfo.AssetType == null)
error = $"Failed to load asset: {_assetInfo.AssetPath} AssetType: null AssetBundle: {_packageBundle.BundleName}";
error = $"Failed to load asset: '{_assetInfo.AssetPath}' AssetType: null AssetBundle: '{_packageBundle.BundleName}'.";
else
error = $"Failed to load asset: {_assetInfo.AssetPath} AssetType: {_assetInfo.AssetType} AssetBundle: {_packageBundle.BundleName}";
error = $"Failed to load asset: '{_assetInfo.AssetPath}' AssetType: {_assetInfo.AssetType} AssetBundle: '{_packageBundle.BundleName}'.";
_steps = ESteps.Done;
SetError(error);
YooLogger.Error(Error);
YooLogger.LogError(Error);
}
else
{

View File

@@ -4,11 +4,11 @@ using UnityEngine.SceneManagement;
namespace YooAsset
{
/// <summary>
/// AssetBundle的场景加载操作
/// AssetBundle 中加载场景资源
/// </summary>
internal class ABHLoadSceneOperation : BHLoadSceneOperation
internal sealed class ABHLoadSceneOperation : BHLoadSceneOperation
{
protected enum ESteps
private enum ESteps
{
None,
LoadScene,
@@ -22,6 +22,12 @@ namespace YooAsset
private AsyncOperation _asyncOperation;
private ESteps _steps = ESteps.None;
/// <summary>
/// 创建实例
/// </summary>
/// <param name="assetInfo">待加载场景信息</param>
/// <param name="loadSceneParams">控制场景加载的选项</param>
/// <param name="allowSceneActivation">是否允许场景在加载完成后立即激活</param>
public ABHLoadSceneOperation(AssetInfo assetInfo, LoadSceneParameters loadSceneParams, bool allowSceneActivation)
{
_assetInfo = assetInfo;
@@ -60,8 +66,8 @@ namespace YooAsset
else
{
_steps = ESteps.Done;
SetError($"Failed to load scene: {_assetInfo.AssetPath}");
YooLogger.Error(Error);
SetError($"Failed to load scene: '{_assetInfo.AssetPath}'.");
YooLogger.LogError(Error);
}
}
}
@@ -73,7 +79,7 @@ namespace YooAsset
if (IsWaitForCompletion)
{
// 注意:场景加载无法强制异步转同步
YooLogger.Error("The scene is already loading asynchronously.");
YooLogger.LogError("The scene is already loading asynchronously.");
}
else
{
@@ -98,8 +104,8 @@ namespace YooAsset
else
{
_steps = ESteps.Done;
SetError($"The loaded scene is invalid: {_assetInfo.AssetPath}");
YooLogger.Error(Error);
SetError($"Loaded scene is invalid: '{_assetInfo.AssetPath}'.");
YooLogger.LogError(Error);
}
}
}
@@ -108,7 +114,7 @@ namespace YooAsset
//注意:场景加载不支持异步转同步,为了支持同步加载方法需要实现该方法!
ExecuteOnce();
}
public override void AllowSceneActivation()
protected override void InternalAllowSceneActivation()
{
_allowSceneActivation = true;
}

View File

@@ -3,11 +3,11 @@ using UnityEngine;
namespace YooAsset
{
/// <summary>
/// AssetBundle的加载子资源操作
/// AssetBundle 中加载指定资源的全部子资源对象
/// </summary>
internal class ABHLoadSubAssetsOperation : BHLoadSubAssetsOperation
internal sealed class ABHLoadSubAssetsOperation : BHLoadSubAssetsOperation
{
protected enum ESteps
private enum ESteps
{
None,
CheckBundle,
@@ -22,6 +22,12 @@ namespace YooAsset
private AssetBundleRequest _request;
private ESteps _steps = ESteps.None;
/// <summary>
/// 创建实例
/// </summary>
/// <param name="packageBundle">资源包描述</param>
/// <param name="assetBundle">已加载的 Unity AssetBundle 对象</param>
/// <param name="assetInfo">待加载资源信息</param>
public ABHLoadSubAssetsOperation(PackageBundle packageBundle, AssetBundle assetBundle, AssetInfo assetInfo)
{
_packageBundle = packageBundle;
@@ -42,7 +48,7 @@ namespace YooAsset
if (_assetBundle == null)
{
_steps = ESteps.Done;
SetError($"The bundle {_packageBundle.BundleName} has been destroyed due to Unity engine bugs.");
SetError($"Bundle '{_packageBundle.BundleName}' has been destroyed due to Unity engine bugs.");
return;
}
@@ -77,7 +83,7 @@ namespace YooAsset
if (IsWaitForCompletion)
{
// 强制挂起主线程(注意:该操作会很耗时)
YooLogger.Warning("Blocking the main thread while loading Unity assets.");
YooLogger.LogWarning("Blocking the main thread while loading Unity assets.");
Result = _request.allAssets;
}
else
@@ -93,13 +99,13 @@ namespace YooAsset
{
string error;
if (_assetInfo.AssetType == null)
error = $"Failed to load sub-assets: {_assetInfo.AssetPath} AssetType: null AssetBundle: {_packageBundle.BundleName}";
error = $"Failed to load sub-assets: '{_assetInfo.AssetPath}' AssetType: null AssetBundle: '{_packageBundle.BundleName}'.";
else
error = $"Failed to load sub-assets: {_assetInfo.AssetPath} AssetType: {_assetInfo.AssetType} AssetBundle: {_packageBundle.BundleName}";
error = $"Failed to load sub-assets: '{_assetInfo.AssetPath}' AssetType: {_assetInfo.AssetType} AssetBundle: '{_packageBundle.BundleName}'.";
_steps = ESteps.Done;
SetError(error);
YooLogger.Error(error);
YooLogger.LogError(error);
}
else
{

View File

@@ -2,9 +2,9 @@
namespace YooAsset
{
/// <summary>
/// 原生资源包的加载所有资源操作(不支持)
/// 全部资源加载操作(原生资源包不支持)
/// </summary>
internal class RBHLoadAllAssetsOperation : BHLoadAllAssetsOperation
internal sealed class RBHLoadAllAssetsOperation : BHLoadAllAssetsOperation
{
protected override void InternalStart()
{

View File

@@ -2,11 +2,11 @@
namespace YooAsset
{
/// <summary>
/// 原生资源包加载单个资源操作
/// 原生资源包加载单个资源对象
/// </summary>
internal class RBHLoadAssetOperation : BHLoadAssetOperation
internal sealed class RBHLoadAssetOperation : BHLoadAssetOperation
{
protected enum ESteps
private enum ESteps
{
None,
LoadObject,
@@ -19,6 +19,12 @@ namespace YooAsset
private readonly AssetInfo _assetInfo;
private ESteps _steps = ESteps.None;
/// <summary>
/// 创建实例
/// </summary>
/// <param name="packageBundle">资源包描述</param>
/// <param name="rawBundle">已加载的原生资源包数据对象</param>
/// <param name="assetInfo">待加载资源信息</param>
public RBHLoadAssetOperation(PackageBundle packageBundle, RawBundle rawBundle, AssetInfo assetInfo)
{
_packageBundle = packageBundle;
@@ -45,8 +51,8 @@ namespace YooAsset
if (Result == null)
{
_steps = ESteps.Done;
SetError($"Failed to load raw file object: {_assetInfo.AssetPath}");
YooLogger.Error(Error);
SetError($"Failed to load raw file object: '{_assetInfo.AssetPath}'.");
YooLogger.LogError(Error);
}
else
{
@@ -55,5 +61,9 @@ namespace YooAsset
}
}
}
protected override void InternalWaitForCompletion()
{
ExecuteBatch();
}
}
}

View File

@@ -2,9 +2,9 @@
namespace YooAsset
{
/// <summary>
/// 原生资源包的场景加载操作(不支持)
/// 场景加载操作(原生资源包不支持)
/// </summary>
internal class RBHLoadSceneOperation : BHLoadSceneOperation
internal sealed class RBHLoadSceneOperation : BHLoadSceneOperation
{
protected override void InternalStart()
{
@@ -13,7 +13,7 @@ namespace YooAsset
protected override void InternalUpdate()
{
}
public override void AllowSceneActivation()
protected override void InternalAllowSceneActivation()
{
}
}

View File

@@ -2,9 +2,9 @@
namespace YooAsset
{
/// <summary>
/// 原生资源包的加载子资源操作(不支持)
/// 子资源加载操作(原生资源包不支持)
/// </summary>
internal class RBHLoadSubAssetsOperation : BHLoadSubAssetsOperation
internal sealed class RBHLoadSubAssetsOperation : BHLoadSubAssetsOperation
{
protected override void InternalStart()
{

View File

@@ -1,25 +1,37 @@
using System;
namespace YooAsset
{
/// <summary>
/// 封装原生文件字节数据的资源包对象
/// </summary>
public class RawBundle
internal class RawBundle
{
private byte[] _bytes;
private RawFileObject _cachedObject;
/// <summary>
/// 创建实例
/// </summary>
/// <param name="bytes">原生文件的字节数据</param>
public RawBundle(byte[] bytes)
{
if (bytes == null)
throw new ArgumentNullException(nameof(bytes));
_bytes = bytes;
}
/// <summary>
/// 根据当前字节数据创建可访问的原生文件对象
/// 创建基于当前字节数据的原生文件对象
/// </summary>
/// <returns>创建得到的原生文件对象</returns>
public RawFileObject CreateRawFileObject()
{
return RawFileObject.CreateFromBytes(_bytes);
if (_bytes == null)
throw new InvalidOperationException($"{nameof(RawBundle)} has been unloaded.");
if (_cachedObject == null)
_cachedObject = RawFileObject.CreateFromBytes(_bytes);
return _cachedObject;
}
/// <summary>
@@ -27,6 +39,12 @@ namespace YooAsset
/// </summary>
public void Unload()
{
if (_cachedObject != null)
{
_cachedObject.Release();
UnityEngine.Object.Destroy(_cachedObject);
_cachedObject = null;
}
_bytes = null;
}
}

View File

@@ -5,7 +5,7 @@ namespace YooAsset
/// <summary>
/// 原生资源包句柄
/// </summary>
internal class RawBundleHandle : IBundleHandle
internal sealed class RawBundleHandle : IBundleHandle
{
private readonly string _bundleFilePath;
private readonly PackageBundle _packageBundle;
@@ -19,6 +19,12 @@ namespace YooAsset
get { return _bundleFilePath; }
}
/// <summary>
/// 创建原生资源包句柄实例
/// </summary>
/// <param name="bundleFilePath">资源包文件的本地路径</param>
/// <param name="packageBundle">资源包描述</param>
/// <param name="rawBundle">已加载的原生资源包数据对象</param>
public RawBundleHandle(string bundleFilePath, PackageBundle packageBundle, RawBundle rawBundle)
{
_bundleFilePath = bundleFilePath;

View File

@@ -1,10 +1,11 @@
using System;
using System.Text;
using UnityEngine;
namespace YooAsset
{
/// <summary>
/// 用于访问原生文件字节数据及文本内容的对象
/// 原生文件对象
/// </summary>
public class RawFileObject : ScriptableObject
{
@@ -12,36 +13,69 @@ namespace YooAsset
private string _fileText;
/// <summary>
/// 原生文件的字节数据
/// 获取原生文件的字节数据
/// </summary>
public byte[] Bytes => _fileBytes;
/// <summary>
/// 以UTF-8编码解析得到的文本内容
/// </summary>
public string Text
/// <returns>原生文件字节数据的副本</returns>
public byte[] GetBytes()
{
get
{
if (_fileBytes == null || _fileBytes.Length == 0)
return null;
if (string.IsNullOrEmpty(_fileText))
_fileText = Encoding.UTF8.GetString(_fileBytes);
return _fileText;
}
if (_fileBytes == null)
return null;
var copy = new byte[_fileBytes.Length];
System.Buffer.BlockCopy(_fileBytes, 0, copy, 0, _fileBytes.Length);
return copy;
}
/// <summary>
/// 根据字节数据创建原生文件对象实例
/// 获取以 UTF-8 编码解析的文本内容
/// </summary>
/// <returns>解析后的文本字符串</returns>
public string GetText()
{
if (_fileBytes == null || _fileBytes.Length == 0)
return null;
if (string.IsNullOrEmpty(_fileText))
_fileText = Encoding.UTF8.GetString(_fileBytes);
return _fileText;
}
#if UNITY_2021_2_OR_NEWER
/// <summary>
/// 获取原生文件的只读字节数据
/// </summary>
/// <remarks>
/// 返回的数据直接引用内部数组,调用方不应在资源包卸载后继续使用。
/// </remarks>
/// <returns>原生文件的只读字节数据</returns>
public ReadOnlySpan<byte> GetBytesAsReadOnlySpan()
{
if (_fileBytes == null)
return ReadOnlySpan<byte>.Empty;
return new ReadOnlySpan<byte>(_fileBytes);
}
#endif
/// <summary>
/// 释放内部持有的字节数据和文本缓存
/// </summary>
internal void Release()
{
_fileBytes = null;
_fileText = null;
}
/// <summary>
/// 创建基于指定字节数据的原生文件对象实例
/// </summary>
/// <param name="bytes">原生文件的字节数据</param>
/// <returns>创建得到的原生文件对象</returns>
public static RawFileObject CreateFromBytes(byte[] bytes)
internal static RawFileObject CreateFromBytes(byte[] bytes)
{
if (bytes == null)
throw new ArgumentNullException(nameof(bytes));
var obj = CreateInstance<RawFileObject>();
obj._fileBytes = bytes;
return obj;
}
}
}
}

View File

@@ -3,11 +3,11 @@ using System.Collections.Generic;
namespace YooAsset
{
/// <summary>
/// 虚拟资源包的加载所有资源操作
/// 通过 AssetDatabase 加载全部资源对象(仅编辑器模式)
/// </summary>
internal class VBHLoadAllAssetsOperation : BHLoadAllAssetsOperation
internal sealed class VBHLoadAllAssetsOperation : BHLoadAllAssetsOperation
{
protected enum ESteps
private enum ESteps
{
None,
CheckBundle,
@@ -20,6 +20,11 @@ namespace YooAsset
private readonly AssetInfo _assetInfo;
private ESteps _steps = ESteps.None;
/// <summary>
/// 创建实例
/// </summary>
/// <param name="packageBundle">资源包描述</param>
/// <param name="assetInfo">待加载资源信息</param>
public VBHLoadAllAssetsOperation(PackageBundle packageBundle, AssetInfo assetInfo)
{
_packageBundle = packageBundle;
@@ -47,8 +52,8 @@ namespace YooAsset
if (string.IsNullOrEmpty(guid))
{
_steps = ESteps.Done;
SetError($"Asset not found: {_assetInfo.AssetPath}");
YooLogger.Error(Error);
SetError($"Asset not found: '{_assetInfo.AssetPath}'.");
YooLogger.LogError(Error);
return;
}
@@ -90,13 +95,13 @@ namespace YooAsset
{
string error;
if (_assetInfo.AssetType == null)
error = $"Failed to load all assets: {_assetInfo.AssetPath} AssetType: null";
error = $"Failed to load all assets: '{_assetInfo.AssetPath}' AssetType: null.";
else
error = $"Failed to load all assets: {_assetInfo.AssetPath} AssetType: {_assetInfo.AssetType}";
error = $"Failed to load all assets: '{_assetInfo.AssetPath}' AssetType: {_assetInfo.AssetType}.";
_steps = ESteps.Done;
SetError(error);
YooLogger.Error(error);
YooLogger.LogError(error);
}
else
{

View File

@@ -2,11 +2,11 @@
namespace YooAsset
{
/// <summary>
/// 虚拟资源包的加载单个资源操作
/// 通过 AssetDatabase 加载单个资源对象(仅编辑器模式)
/// </summary>
internal class VBHLoadAssetOperation : BHLoadAssetOperation
internal sealed class VBHLoadAssetOperation : BHLoadAssetOperation
{
protected enum ESteps
private enum ESteps
{
None,
CheckBundle,
@@ -19,6 +19,11 @@ namespace YooAsset
private readonly AssetInfo _assetInfo;
private ESteps _steps = ESteps.None;
/// <summary>
/// 创建实例
/// </summary>
/// <param name="packageBundle">资源包描述</param>
/// <param name="assetInfo">待加载资源信息</param>
public VBHLoadAssetOperation(PackageBundle packageBundle, AssetInfo assetInfo)
{
_packageBundle = packageBundle;
@@ -46,8 +51,8 @@ namespace YooAsset
if (string.IsNullOrEmpty(guid))
{
_steps = ESteps.Done;
SetError($"Asset not found: {_assetInfo.AssetPath}");
YooLogger.Error(Error);
SetError($"Asset not found: '{_assetInfo.AssetPath}'.");
YooLogger.LogError(Error);
return;
}
@@ -69,13 +74,13 @@ namespace YooAsset
{
string error;
if (_assetInfo.AssetType == null)
error = $"Failed to load asset object: {_assetInfo.AssetPath} AssetType: null";
error = $"Failed to load asset: '{_assetInfo.AssetPath}' AssetType: null.";
else
error = $"Failed to load asset object: {_assetInfo.AssetPath} AssetType: {_assetInfo.AssetType}";
error = $"Failed to load asset: '{_assetInfo.AssetPath}' AssetType: {_assetInfo.AssetType}.";
_steps = ESteps.Done;
SetError(error);
YooLogger.Error(error);
YooLogger.LogError(error);
}
else
{

View File

@@ -4,11 +4,11 @@ using UnityEngine.SceneManagement;
namespace YooAsset
{
/// <summary>
/// 虚拟资源包的场景加载操作
/// 通过 EditorSceneManager 加载场景资源(仅编辑器模式)
/// </summary>
internal class VBHLoadSceneOperation : BHLoadSceneOperation
internal sealed class VBHLoadSceneOperation : BHLoadSceneOperation
{
protected enum ESteps
private enum ESteps
{
None,
LoadScene,
@@ -17,15 +17,21 @@ namespace YooAsset
}
private readonly AssetInfo _assetInfo;
private readonly LoadSceneParameters _loadParams;
private readonly LoadSceneParameters _loadSceneParams;
private bool _allowSceneActivation;
private AsyncOperation _asyncOperation;
private ESteps _steps = ESteps.None;
public VBHLoadSceneOperation(AssetInfo assetInfo, LoadSceneParameters loadParams, bool allowSceneActivation)
/// <summary>
/// 创建实例
/// </summary>
/// <param name="assetInfo">待加载场景信息</param>
/// <param name="loadSceneParams">控制场景加载的选项</param>
/// <param name="allowSceneActivation">是否允许场景在加载完成后立即激活</param>
public VBHLoadSceneOperation(AssetInfo assetInfo, LoadSceneParameters loadSceneParams, bool allowSceneActivation)
{
_assetInfo = assetInfo;
_loadParams = loadParams;
_loadSceneParams = loadSceneParams;
_allowSceneActivation = allowSceneActivation;
}
protected override void InternalStart()
@@ -47,12 +53,12 @@ namespace YooAsset
{
if (IsWaitForCompletion)
{
Result = UnityEditor.SceneManagement.EditorSceneManager.LoadSceneInPlayMode(_assetInfo.AssetPath, _loadParams);
Result = UnityEditor.SceneManagement.EditorSceneManager.LoadSceneInPlayMode(_assetInfo.AssetPath, _loadSceneParams);
_steps = ESteps.CheckResult;
}
else
{
_asyncOperation = UnityEditor.SceneManagement.EditorSceneManager.LoadSceneAsyncInPlayMode(_assetInfo.AssetPath, _loadParams);
_asyncOperation = UnityEditor.SceneManagement.EditorSceneManager.LoadSceneAsyncInPlayMode(_assetInfo.AssetPath, _loadSceneParams);
if (_asyncOperation != null)
{
_asyncOperation.allowSceneActivation = _allowSceneActivation;
@@ -63,9 +69,8 @@ namespace YooAsset
else
{
_steps = ESteps.Done;
SetError($"Failed to load scene: {_assetInfo.AssetPath}");
YooLogger.Error(Error);
return;
SetError($"Failed to load scene: '{_assetInfo.AssetPath}'.");
YooLogger.LogError(Error);
}
}
}
@@ -77,7 +82,7 @@ namespace YooAsset
if (IsWaitForCompletion)
{
// 注意:场景加载无法强制异步转同步
YooLogger.Error("The scene is already loading asynchronously.");
YooLogger.LogError("The scene is already loading asynchronously.");
}
else
{
@@ -102,8 +107,8 @@ namespace YooAsset
else
{
_steps = ESteps.Done;
SetError($"The loaded scene is invalid: {_assetInfo.AssetPath}");
YooLogger.Error(Error);
SetError($"Loaded scene is invalid: '{_assetInfo.AssetPath}'.");
YooLogger.LogError(Error);
}
}
#endif
@@ -113,7 +118,7 @@ namespace YooAsset
//注意:场景加载不支持异步转同步,为了支持同步加载方法需要实现该方法!
ExecuteOnce();
}
public override void AllowSceneActivation()
protected override void InternalAllowSceneActivation()
{
_allowSceneActivation = true;
}

View File

@@ -3,11 +3,11 @@ using System.Collections.Generic;
namespace YooAsset
{
/// <summary>
/// 虚拟资源包的加载子资源操作
/// 通过 AssetDatabase 加载指定资源的全部子资源对象(仅编辑器模式)
/// </summary>
internal class VBHLoadSubAssetsOperation : BHLoadSubAssetsOperation
internal sealed class VBHLoadSubAssetsOperation : BHLoadSubAssetsOperation
{
protected enum ESteps
private enum ESteps
{
None,
CheckBundle,
@@ -20,6 +20,11 @@ namespace YooAsset
private readonly AssetInfo _assetInfo;
private ESteps _steps = ESteps.None;
/// <summary>
/// 创建实例
/// </summary>
/// <param name="packageBundle">资源包描述</param>
/// <param name="assetInfo">待加载资源信息</param>
public VBHLoadSubAssetsOperation(PackageBundle packageBundle, AssetInfo assetInfo)
{
_packageBundle = packageBundle;
@@ -47,8 +52,8 @@ namespace YooAsset
if (string.IsNullOrEmpty(guid))
{
_steps = ESteps.Done;
SetError($"Asset not found: {_assetInfo.AssetPath}");
YooLogger.Error(Error);
SetError($"Asset not found: '{_assetInfo.AssetPath}'.");
YooLogger.LogError(Error);
return;
}
@@ -81,13 +86,13 @@ namespace YooAsset
{
string error;
if (_assetInfo.AssetType == null)
error = $"Failed to load sub-assets: {_assetInfo.AssetPath} AssetType: null";
error = $"Failed to load sub-assets: '{_assetInfo.AssetPath}' AssetType: null.";
else
error = $"Failed to load sub-assets: {_assetInfo.AssetPath} AssetType: {_assetInfo.AssetType}";
error = $"Failed to load sub-assets: '{_assetInfo.AssetPath}' AssetType: {_assetInfo.AssetType}.";
_steps = ESteps.Done;
SetError(error);
YooLogger.Error(error);
YooLogger.LogError(error);
}
else
{

View File

@@ -5,7 +5,7 @@ namespace YooAsset
/// <summary>
/// 虚拟资源包句柄
/// </summary>
internal class VirtualBundleHandle : IBundleHandle
internal sealed class VirtualBundleHandle : IBundleHandle
{
private readonly string _bundleFilePath;
private readonly PackageBundle _packageBundle;
@@ -18,6 +18,11 @@ namespace YooAsset
get { return _bundleFilePath; }
}
/// <summary>
/// 创建虚拟资源包句柄实例
/// </summary>
/// <param name="bundleFilePath">资源包文件的本地路径</param>
/// <param name="packageBundle">资源包描述</param>
public VirtualBundleHandle(string bundleFilePath, PackageBundle packageBundle)
{
_bundleFilePath = bundleFilePath;
@@ -25,7 +30,7 @@ namespace YooAsset
}
/// <summary>
/// 虚拟资源包无需执行实际卸载操作
/// 释放虚拟资源包无需执行实际卸载操作
/// </summary>
public void UnloadBundle()
{

View File

@@ -8,7 +8,7 @@ namespace YooAsset
/// 诊断行为组件
/// </summary>
/// <remarks>
/// 负责接收 Editor 命令并发送诊断数据
/// 负责接收 Editor 命令并发送诊断数据
/// </remarks>
internal class DiagnosticBehaviour : MonoBehaviour
{
@@ -16,13 +16,13 @@ namespace YooAsset
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
private static void OnRuntimeInitialize()
{
_sampleOnce = false;
_autoSampling = false;
s_sampleOnce = false;
s_autoSampling = false;
}
#endif
private static bool _sampleOnce = false;
private static bool _autoSampling = false;
private static bool s_sampleOnce = false;
private static bool s_autoSampling = false;
private void Awake()
{
@@ -48,9 +48,9 @@ namespace YooAsset
}
private void LateUpdate()
{
if (_autoSampling || _sampleOnce)
if (s_autoSampling || s_sampleOnce)
{
_sampleOnce = false;
s_sampleOnce = false;
var debugReport = YooAssets.GetDiagnosticReport();
var data = DiagnosticReport.Serialize(debugReport);
@@ -65,22 +65,22 @@ namespace YooAsset
private static void HandleEditorMessage(MessageEventArgs args)
{
var command = DiagnosticCommand.Deserialize(args.data);
YooLogger.Log($"[{nameof(DiagnosticBehaviour)}] Handle command: Type={command.CommandType}, Param={command.Parameter}");
if (command.CommandType == (int)EDiagnosticCommandType.SampleOnce)
YooLogger.Log($"[{nameof(DiagnosticBehaviour)}] Received command: Type={command.CommandType}, Param='{command.Parameter}'.");
if (command.CommandType == EDiagnosticCommandType.SampleOnce)
{
_sampleOnce = true;
s_sampleOnce = true;
}
else if (command.CommandType == (int)EDiagnosticCommandType.AutoSampling)
else if (command.CommandType == EDiagnosticCommandType.AutoSampling)
{
if (command.Parameter == "open")
_autoSampling = true;
if (command.Parameter == DiagnosticSystemConsts.AutoSamplingOpen)
s_autoSampling = true;
else
_autoSampling = false;
s_autoSampling = false;
}
else
{
YooLogger.Warning($"Unknown diagnostic command type: {command.CommandType}.");
YooLogger.LogWarning($"Unknown diagnostic command type: {command.CommandType}.");
}
}
}
}
}

View File

@@ -8,7 +8,7 @@ namespace YooAsset
/// 诊断命令
/// </summary>
/// <remarks>
/// 用于 Editor 向 Player 发送诊断指令
/// 用于 Editor 向 Player 发送诊断指令
/// </remarks>
[Serializable]
internal class DiagnosticCommand
@@ -16,14 +16,13 @@ namespace YooAsset
/// <summary>
/// 命令类型
/// </summary>
public int CommandType;
public EDiagnosticCommandType CommandType;
/// <summary>
/// 命令附加参数
/// </summary>
public string Parameter;
/// <summary>
/// 序列化命令为字节数组
/// </summary>
@@ -44,4 +43,4 @@ namespace YooAsset
return JsonUtility.FromJson<DiagnosticCommand>(Encoding.UTF8.GetString(data));
}
}
}
}

View File

@@ -1,5 +1,4 @@
using System;
using System.Collections;
using System.Collections.Generic;
namespace YooAsset
@@ -8,7 +7,7 @@ namespace YooAsset
/// 描述资源包的运行时诊断信息
/// </summary>
[Serializable]
internal struct DiagnosticBundleInfo : IComparer<DiagnosticBundleInfo>, IComparable<DiagnosticBundleInfo>
internal class DiagnosticBundleInfo : IComparable<DiagnosticBundleInfo>
{
/// <summary>
/// 资源包名称
@@ -30,13 +29,10 @@ namespace YooAsset
/// </summary>
public List<string> Referencers;
/// <inheritdoc />
public int CompareTo(DiagnosticBundleInfo other)
{
return Compare(this, other);
}
public int Compare(DiagnosticBundleInfo a, DiagnosticBundleInfo b)
{
return string.CompareOrdinal(a.BundleName, b.BundleName);
return string.CompareOrdinal(BundleName, other.BundleName);
}
}
}

Some files were not shown because too many files have changed in this diff Show More