mirror of
https://github.com/tuyoogame/YooAsset.git
synced 2026-05-22 00:11:41 +00:00
refactor : 代码重构
This commit is contained in:
@@ -53,6 +53,8 @@
|
||||
| `LogOff` | `logOff` | ~~LogOut~~ |
|
||||
| `Email` | `email` | ~~EMail~~ |
|
||||
|
||||
> ✔️ 在 Unity 项目中,`ID` 保持全大写以与 Unity API 风格一致(如 `GetInstanceID()`、`PropertyToID()`),项目内应保持风格统一。
|
||||
|
||||
### 1.5 区分大小写
|
||||
|
||||
- 不要假定所有语言都区分大小写
|
||||
|
||||
@@ -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}'` |
|
||||
|
||||
@@ -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 | 提供者 | — |
|
||||
200
Assets/YooAsset/Docs/逻辑检测.md
Normal file
200
Assets/YooAsset/Docs/逻辑检测.md
Normal 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);
|
||||
```
|
||||
7
Assets/YooAsset/Docs/逻辑检测.md.meta
Normal file
7
Assets/YooAsset/Docs/逻辑检测.md.meta
Normal file
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 200087470392cf24ebdd0efac8e44210
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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}");
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -27,7 +27,7 @@ namespace YooAsset
|
||||
/// 获取操作结果
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 业务失败不视为异常,此处不抛出异常
|
||||
/// 业务失败不视为异常,此处不抛出异常。
|
||||
/// </remarks>
|
||||
public void GetResult()
|
||||
{
|
||||
@@ -45,4 +45,4 @@ namespace YooAsset
|
||||
_operation.Completed += (op) => continuation();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,8 +7,8 @@ namespace YooAsset
|
||||
internal interface ICacheEntry
|
||||
{
|
||||
/// <summary>
|
||||
/// Bundle唯一标识
|
||||
/// Bundle 唯一标识
|
||||
/// </summary>
|
||||
string BundleGUID { get; }
|
||||
string BundleGuid { get; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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.");
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.");
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
/// 资源包文件名
|
||||
|
||||
@@ -4,7 +4,7 @@ namespace YooAsset
|
||||
/// <summary>
|
||||
/// 内置资源目录常量定义
|
||||
/// </summary>
|
||||
internal class BuiltinCatalogConsts
|
||||
internal static class BuiltinCatalogConsts
|
||||
{
|
||||
/// <summary>
|
||||
/// 文件极限大小(100MB)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -4,7 +4,7 @@ namespace YooAsset
|
||||
/// <summary>
|
||||
/// 编辑器文件缓存初始化操作
|
||||
/// </summary>
|
||||
internal class EBCInitializeOperation : BCInitializeOperation
|
||||
internal sealed class EBCInitializeOperation : BCInitializeOperation
|
||||
{
|
||||
private readonly EditorBundleCache _fileCache;
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ namespace YooAsset
|
||||
/// <summary>
|
||||
/// 编辑器文件缓存加载资源包操作
|
||||
/// </summary>
|
||||
internal class EBCLoadBundleOperation : BCLoadBundleOperation
|
||||
internal sealed class EBCLoadBundleOperation : BCLoadBundleOperation
|
||||
{
|
||||
private enum ESteps
|
||||
{
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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; //注意: 一次命令赋值
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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}.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ namespace YooAsset
|
||||
/// <summary>
|
||||
/// 沙盒文件缓存常量定义
|
||||
/// </summary>
|
||||
internal class SandboxBundleCacheConsts
|
||||
internal static class SandboxBundleCacheConsts
|
||||
{
|
||||
/// <summary>
|
||||
/// 数据文件名称
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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}.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,14 +2,14 @@
|
||||
namespace YooAsset
|
||||
{
|
||||
/// <summary>
|
||||
/// 资源包类型枚举
|
||||
/// 资源包的类型
|
||||
/// </summary>
|
||||
public enum EBundleType
|
||||
{
|
||||
/// <summary>
|
||||
/// 未知类型
|
||||
/// 未指定类型
|
||||
/// </summary>
|
||||
Unknown = 0,
|
||||
None = 0,
|
||||
|
||||
/// <summary>
|
||||
/// 虚拟资源包
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,6 +14,14 @@ namespace YooAsset
|
||||
/// <summary>
|
||||
/// 允许场景在加载完成后进入激活阶段
|
||||
/// </summary>
|
||||
public abstract void AllowSceneActivation();
|
||||
public void AllowSceneActivation()
|
||||
{
|
||||
InternalAllowSceneActivation();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 执行场景激活的方法
|
||||
/// </summary>
|
||||
protected abstract void InternalAllowSceneActivation();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
namespace YooAsset
|
||||
{
|
||||
/// <summary>
|
||||
/// 原生资源包的加载所有资源操作(不支持)
|
||||
/// 全部资源加载操作(原生资源包不支持)
|
||||
/// </summary>
|
||||
internal class RBHLoadAllAssetsOperation : BHLoadAllAssetsOperation
|
||||
internal sealed class RBHLoadAllAssetsOperation : BHLoadAllAssetsOperation
|
||||
{
|
||||
protected override void InternalStart()
|
||||
{
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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()
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
namespace YooAsset
|
||||
{
|
||||
/// <summary>
|
||||
/// 原生资源包的加载子资源操作(不支持)
|
||||
/// 子资源加载操作(原生资源包不支持)
|
||||
/// </summary>
|
||||
internal class RBHLoadSubAssetsOperation : BHLoadSubAssetsOperation
|
||||
internal sealed class RBHLoadSubAssetsOperation : BHLoadSubAssetsOperation
|
||||
{
|
||||
protected override void InternalStart()
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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()
|
||||
{
|
||||
|
||||
@@ -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}.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user