mirror of
https://github.com/tuyoogame/YooAsset.git
synced 2026-05-25 18:20:15 +00:00
refactor : 重构代码
This commit is contained in:
@@ -125,13 +125,13 @@ namespace YooAsset.Editor
|
||||
_providerTableView.AddColumn(column);
|
||||
}
|
||||
|
||||
// BeginTime
|
||||
// StartTime
|
||||
{
|
||||
var columnStyle = new ColumnStyle(100);
|
||||
columnStyle.Stretchable = false;
|
||||
columnStyle.Searchable = false;
|
||||
columnStyle.Sortable = true;
|
||||
var column = new TableColumn("BeginTime", "Begin Time", columnStyle);
|
||||
var column = new TableColumn("StartTime", "Start Time", columnStyle);
|
||||
column.MakeCell = () =>
|
||||
{
|
||||
var label = new Label();
|
||||
@@ -314,7 +314,7 @@ namespace YooAsset.Editor
|
||||
rowData.AddAssetPathCell("PackageName", packageData.PackageName);
|
||||
rowData.AddStringValueCell("AssetPath", providerInfo.AssetPath);
|
||||
rowData.AddStringValueCell("SpawnScene", providerInfo.OriginScene);
|
||||
rowData.AddStringValueCell("BeginTime", providerInfo.StartTime);
|
||||
rowData.AddStringValueCell("StartTime", providerInfo.StartTime);
|
||||
rowData.AddLongValueCell("LoadingTime", providerInfo.ElapsedMS);
|
||||
rowData.AddLongValueCell("RefCount", providerInfo.ReferenceCount);
|
||||
rowData.AddStringValueCell("Status", providerInfo.Status.ToString());
|
||||
|
||||
@@ -208,13 +208,13 @@ namespace YooAsset.Editor
|
||||
_usingTableView.AddColumn(column);
|
||||
}
|
||||
|
||||
// BeginTime
|
||||
// StartTime
|
||||
{
|
||||
var columnStyle = new ColumnStyle(100);
|
||||
columnStyle.Stretchable = false;
|
||||
columnStyle.Searchable = false;
|
||||
columnStyle.Sortable = true;
|
||||
var column = new TableColumn("BeginTime", "Begin Time", columnStyle);
|
||||
var column = new TableColumn("StartTime", "Start Time", columnStyle);
|
||||
column.MakeCell = () =>
|
||||
{
|
||||
var label = new Label();
|
||||
@@ -451,7 +451,7 @@ namespace YooAsset.Editor
|
||||
rowData.ProviderInfo = providerInfo;
|
||||
rowData.AddStringValueCell("UsingAssets", providerInfo.AssetPath);
|
||||
rowData.AddStringValueCell("SpawnScene", providerInfo.OriginScene);
|
||||
rowData.AddStringValueCell("BeginTime", providerInfo.StartTime);
|
||||
rowData.AddStringValueCell("StartTime", providerInfo.StartTime);
|
||||
rowData.AddLongValueCell("RefCount", providerInfo.ReferenceCount);
|
||||
rowData.AddStringValueCell("Status", providerInfo.Status);
|
||||
sourceDatas.Add(rowData);
|
||||
|
||||
@@ -147,13 +147,13 @@ namespace YooAsset.Editor
|
||||
_operationTableView.AddColumn(column);
|
||||
}
|
||||
|
||||
// BeginTime
|
||||
// StartTime
|
||||
{
|
||||
var columnStyle = new ColumnStyle(100);
|
||||
columnStyle.Stretchable = false;
|
||||
columnStyle.Searchable = false;
|
||||
columnStyle.Sortable = true;
|
||||
var column = new TableColumn("BeginTime", "Begin Time", columnStyle);
|
||||
var column = new TableColumn("StartTime", "Start Time", columnStyle);
|
||||
column.MakeCell = () =>
|
||||
{
|
||||
var label = new Label();
|
||||
@@ -168,14 +168,14 @@ namespace YooAsset.Editor
|
||||
_operationTableView.AddColumn(column);
|
||||
}
|
||||
|
||||
// ProcessTime
|
||||
// ElapsedMS
|
||||
{
|
||||
var columnStyle = new ColumnStyle(130);
|
||||
columnStyle.Stretchable = false;
|
||||
columnStyle.Searchable = false;
|
||||
columnStyle.Sortable = true;
|
||||
columnStyle.Units = "ms";
|
||||
var column = new TableColumn("ProcessTime", "Process Time", columnStyle);
|
||||
var column = new TableColumn("ElapsedMS", "Elapsed MS", columnStyle);
|
||||
column.MakeCell = () =>
|
||||
{
|
||||
var label = new Label();
|
||||
@@ -259,19 +259,19 @@ namespace YooAsset.Editor
|
||||
_bottomToolbar.Add(button);
|
||||
}
|
||||
|
||||
// BeginTime
|
||||
// StartTime
|
||||
{
|
||||
ToolbarButton button = new ToolbarButton();
|
||||
button.text = "BeginTime";
|
||||
button.text = "StartTime";
|
||||
button.style.flexGrow = 0;
|
||||
button.style.width = 100;
|
||||
_bottomToolbar.Add(button);
|
||||
}
|
||||
|
||||
// ProcessTime
|
||||
// ElapsedMS
|
||||
{
|
||||
ToolbarButton button = new ToolbarButton();
|
||||
button.text = "ProcessTime (ms)";
|
||||
button.text = "ElapsedMS";
|
||||
button.style.flexGrow = 0;
|
||||
button.style.width = 130;
|
||||
_bottomToolbar.Add(button);
|
||||
@@ -319,8 +319,8 @@ namespace YooAsset.Editor
|
||||
rowData.AddStringValueCell("OperationName", operationInfo.OperationName);
|
||||
rowData.AddLongValueCell("Priority", operationInfo.Priority);
|
||||
rowData.AddDoubleValueCell("Progress", operationInfo.Progress);
|
||||
rowData.AddStringValueCell("BeginTime", operationInfo.StartTime);
|
||||
rowData.AddLongValueCell("LoadingTime", operationInfo.ElapsedMS);
|
||||
rowData.AddStringValueCell("StartTime", operationInfo.StartTime);
|
||||
rowData.AddLongValueCell("ElapsedMS", operationInfo.ElapsedMS);
|
||||
rowData.AddStringValueCell("Status", operationInfo.Status.ToString());
|
||||
rowData.AddStringValueCell("Desc", operationInfo.OperationDesc);
|
||||
_sourceDatas.Add(rowData);
|
||||
@@ -408,20 +408,20 @@ namespace YooAsset.Editor
|
||||
container.Add(label);
|
||||
}
|
||||
|
||||
// BeginTime
|
||||
// StartTime
|
||||
{
|
||||
var label = new Label();
|
||||
label.name = "BeginTime";
|
||||
label.name = "StartTime";
|
||||
label.style.flexGrow = 0f;
|
||||
label.style.width = 100;
|
||||
label.style.unityTextAlign = TextAnchor.MiddleLeft;
|
||||
container.Add(label);
|
||||
}
|
||||
|
||||
// ProcessTime
|
||||
// ElapsedMS
|
||||
{
|
||||
var label = new Label();
|
||||
label.name = "ProcessTime";
|
||||
label.name = "ElapsedMS";
|
||||
label.style.flexGrow = 0f;
|
||||
label.style.width = 130;
|
||||
label.style.unityTextAlign = TextAnchor.MiddleLeft;
|
||||
@@ -464,15 +464,15 @@ namespace YooAsset.Editor
|
||||
label.text = operationInfo.Progress.ToString();
|
||||
}
|
||||
|
||||
// BeginTime
|
||||
// StartTime
|
||||
{
|
||||
var label = container.Q<Label>("BeginTime");
|
||||
var label = container.Q<Label>("StartTime");
|
||||
label.text = operationInfo.StartTime;
|
||||
}
|
||||
|
||||
// ProcessTime
|
||||
// ElapsedMS
|
||||
{
|
||||
var label = container.Q<Label>("ProcessTime");
|
||||
var label = container.Q<Label>("ElapsedMS");
|
||||
label.text = operationInfo.ElapsedMS.ToString();
|
||||
}
|
||||
|
||||
|
||||
478
Assets/YooAsset/Runtime/DiagnosticSystem/README.md
Normal file
478
Assets/YooAsset/Runtime/DiagnosticSystem/README.md
Normal file
@@ -0,0 +1,478 @@
|
||||
# DiagnosticSystem 诊断模块
|
||||
|
||||
## 模块概述
|
||||
|
||||
DiagnosticSystem 是 YooAsset 资源管理系统的**运行时诊断模块**,负责收集和传输资源加载的实时状态信息。该模块支持 Editor 与运行时 Player 之间的双向通信,为 AssetBundleDebugger 窗口提供数据支持。
|
||||
|
||||
### 可见性说明
|
||||
|
||||
DiagnosticSystem 属于 YooAsset Runtime 的内部基础模块,目录内大多数类型为 `internal`(仅供 YooAsset Runtime 内部程序集使用)。业务层建议通过 `YooAssets.GetDebugReport()` 等上层接口获取诊断数据,避免直接依赖本模块的内部类型。
|
||||
|
||||
### 核心职责
|
||||
|
||||
- 资源加载状态采集
|
||||
- Provider/Bundle/Operation 诊断信息汇总
|
||||
- Editor 与 Player 的远程通信
|
||||
- 诊断数据的序列化与传输
|
||||
|
||||
---
|
||||
|
||||
## 边界与上层协作
|
||||
|
||||
DiagnosticSystem 的职责是提供"诊断数据采集 + 远程通信 + 序列化传输"的基础能力:
|
||||
|
||||
- **本模块不负责数据展示**:数据展示由 Editor 端的 AssetBundleDebugger 窗口实现。
|
||||
- **本模块不负责数据持久化**:诊断数据为实时采集,不进行本地存储。
|
||||
- **本模块不负责数据分析**:数据分析和统计由上层调试工具实现。
|
||||
|
||||
---
|
||||
|
||||
## 设计目标
|
||||
|
||||
| 目标 | 说明 |
|
||||
|------|------|
|
||||
| **实时性** | 支持单次采样和持续采样两种模式 |
|
||||
| **低侵入** | 仅在需要时采集数据,不影响正常运行性能 |
|
||||
| **跨平台** | 支持 Editor 模拟和真机远程调试 |
|
||||
| **可扩展性** | 诊断数据结构支持版本控制 |
|
||||
|
||||
---
|
||||
|
||||
## 架构概念
|
||||
|
||||
### 分层架构
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────┐
|
||||
│ AssetBundleDebugger (Editor) │
|
||||
│ (数据展示层) │
|
||||
└─────────────────────────┬───────────────────────────────┘
|
||||
│
|
||||
┌─────────────────────────▼───────────────────────────────┐
|
||||
│ MockEditorConnection (Editor) │
|
||||
│ EditorConnection (Runtime) │
|
||||
│ (通信层) │
|
||||
└─────────────────────────┬───────────────────────────────┘
|
||||
│ 双向消息
|
||||
┌─────────────────────────▼───────────────────────────────┐
|
||||
│ MockPlayerConnection (Editor) │
|
||||
│ PlayerConnection (Runtime) │
|
||||
│ (通信层) │
|
||||
└─────────────────────────┬───────────────────────────────┘
|
||||
│
|
||||
┌─────────────────────────▼───────────────────────────────┐
|
||||
│ RemoteDebugBehaviour │
|
||||
│ (运行时组件) │
|
||||
│ 接收命令、采集数据、发送报告 │
|
||||
└─────────────────────────┬───────────────────────────────┘
|
||||
│
|
||||
┌─────────────────────────▼───────────────────────────────┐
|
||||
│ DiagnosticReport │
|
||||
│ (数据模型) │
|
||||
│ DiagnosticPackageData / ProviderInfo / BundleInfo │
|
||||
└─────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### 核心组件
|
||||
|
||||
- **数据模型层**: 定义诊断数据的结构(DiagnosticReport、DiagnosticPackageData 等)
|
||||
- **通信层**: 处理 Editor 与 Player 之间的消息传递
|
||||
- **行为组件层**: 运行时 MonoBehaviour,负责采集和发送诊断数据
|
||||
|
||||
---
|
||||
|
||||
## 文件结构
|
||||
|
||||
```
|
||||
DiagnosticSystem/
|
||||
├── DiagnosticBundleInfo.cs # 资源包诊断信息
|
||||
├── DiagnosticOperationInfo.cs # 异步操作诊断信息
|
||||
├── DiagnosticPackageData.cs # 包裹诊断数据容器
|
||||
├── DiagnosticProviderInfo.cs # 资源加载诊断信息
|
||||
├── DiagnosticReport.cs # 诊断报告(顶层数据结构)
|
||||
│
|
||||
├── DiagnosticSystemDefine.cs # 诊断系统常量定义
|
||||
├── EDebugCommandType.cs # 调试命令类型枚举
|
||||
├── RemoteDebugCommand.cs # 远程调试命令
|
||||
│
|
||||
├── RemoteDebugBehaviour.cs # 运行时调试组件
|
||||
├── MockEditorConnection.cs # 模拟 Editor 连接(Editor 用)
|
||||
└── MockPlayerConnection.cs # 模拟 Player 连接(Editor 用)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 数据模型
|
||||
|
||||
### DiagnosticReport(诊断报告)
|
||||
|
||||
顶层数据结构,包含所有包裹的诊断数据。
|
||||
|
||||
```csharp
|
||||
[Serializable]
|
||||
internal class DiagnosticReport
|
||||
{
|
||||
/// <summary>
|
||||
/// 调试器版本
|
||||
/// </summary>
|
||||
public string DebuggerVersion;
|
||||
|
||||
/// <summary>
|
||||
/// 报告发生的游戏帧
|
||||
/// </summary>
|
||||
public int FrameCount;
|
||||
|
||||
/// <summary>
|
||||
/// 包裹数据列表
|
||||
/// </summary>
|
||||
public List<DiagnosticPackageData> PackageDataList;
|
||||
|
||||
// 序列化/反序列化方法
|
||||
public static byte[] Serialize(DiagnosticReport report);
|
||||
public static DiagnosticReport Deserialize(byte[] data);
|
||||
}
|
||||
```
|
||||
|
||||
### DiagnosticPackageData(包裹诊断数据)
|
||||
|
||||
单个包裹的诊断数据容器。
|
||||
|
||||
```csharp
|
||||
[Serializable]
|
||||
internal class DiagnosticPackageData
|
||||
{
|
||||
/// <summary>
|
||||
/// 包裹名称
|
||||
/// </summary>
|
||||
public string PackageName;
|
||||
|
||||
/// <summary>
|
||||
/// 资源加载的诊断信息列表
|
||||
/// </summary>
|
||||
public List<DiagnosticProviderInfo> ProviderInfos;
|
||||
|
||||
/// <summary>
|
||||
/// 资源包的诊断信息列表
|
||||
/// </summary>
|
||||
public List<DiagnosticBundleInfo> BundleInfos;
|
||||
|
||||
/// <summary>
|
||||
/// 异步操作的诊断信息列表
|
||||
/// </summary>
|
||||
public List<DiagnosticOperationInfo> OperationInfos;
|
||||
|
||||
// 快速查找方法
|
||||
public DiagnosticBundleInfo GetBundleInfo(string bundleName);
|
||||
}
|
||||
```
|
||||
|
||||
### DiagnosticProviderInfo(资源加载诊断信息)
|
||||
|
||||
描述单个资源加载操作的状态。
|
||||
|
||||
```csharp
|
||||
[Serializable]
|
||||
internal struct DiagnosticProviderInfo
|
||||
{
|
||||
public string AssetPath; // 资源对象路径
|
||||
public string OriginScene; // 资源加载时所在的场景
|
||||
public string StartTime; // 资源加载开始时间
|
||||
public long ElapsedMS; // 加载耗时(毫秒)
|
||||
public int ReferenceCount; // 引用计数
|
||||
public string Status; // 资源的加载状态
|
||||
public List<string> DependentBundles; // 依赖的资源包列表
|
||||
}
|
||||
```
|
||||
|
||||
### DiagnosticBundleInfo(资源包诊断信息)
|
||||
|
||||
描述单个 AssetBundle 的状态。
|
||||
|
||||
```csharp
|
||||
[Serializable]
|
||||
internal struct DiagnosticBundleInfo
|
||||
{
|
||||
public string BundleName; // 资源包名称
|
||||
public int ReferenceCount; // 引用计数
|
||||
public string Status; // 资源包的加载状态
|
||||
public List<string> ReferencedByBundles; // 该资源包被谁引用
|
||||
}
|
||||
```
|
||||
|
||||
### DiagnosticOperationInfo(异步操作诊断信息)
|
||||
|
||||
描述异步操作的执行状态。
|
||||
|
||||
```csharp
|
||||
[Serializable]
|
||||
internal struct DiagnosticOperationInfo
|
||||
{
|
||||
public string OperationName; // 异步操作的名称
|
||||
public string OperationDesc; // 异步操作的说明
|
||||
public uint Priority; // 异步操作的优先级
|
||||
public string StartTime; // 开始的时间
|
||||
public long ElapsedMS; // 处理耗时(毫秒)
|
||||
public float Progress; // 异步操作的执行进度
|
||||
public string Status; // 异步操作的执行状态
|
||||
public List<DiagnosticOperationInfo> Children; // 子任务列表
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 通信协议
|
||||
|
||||
### 命令类型
|
||||
|
||||
```csharp
|
||||
/// <summary>
|
||||
/// 远程调试命令类型
|
||||
/// </summary>
|
||||
internal enum EDebugCommandType
|
||||
{
|
||||
/// <summary>
|
||||
/// 采样一次
|
||||
/// </summary>
|
||||
SampleOnce = 0,
|
||||
|
||||
/// <summary>
|
||||
/// 持续采样
|
||||
/// </summary>
|
||||
AutoSampling = 1,
|
||||
}
|
||||
```
|
||||
|
||||
### RemoteDebugCommand(远程调试命令)
|
||||
|
||||
Editor 向 Player 发送的调试指令。
|
||||
|
||||
```csharp
|
||||
[Serializable]
|
||||
internal class RemoteDebugCommand
|
||||
{
|
||||
/// <summary>
|
||||
/// 命令类型
|
||||
/// </summary>
|
||||
public int CommandType;
|
||||
|
||||
/// <summary>
|
||||
/// 命令附加参数
|
||||
/// </summary>
|
||||
public string Parameter;
|
||||
|
||||
// 序列化/反序列化方法
|
||||
public static byte[] Serialize(RemoteDebugCommand command);
|
||||
public static RemoteDebugCommand Deserialize(byte[] data);
|
||||
}
|
||||
```
|
||||
|
||||
### 消息标识符
|
||||
|
||||
```csharp
|
||||
internal class DiagnosticSystemDefine
|
||||
{
|
||||
/// <summary>
|
||||
/// 调试器版本号
|
||||
/// </summary>
|
||||
public const string DebuggerVersion = "1.0";
|
||||
|
||||
/// <summary>
|
||||
/// Player 向 Editor 发送消息的标识符
|
||||
/// </summary>
|
||||
public static readonly Guid PlayerToEditorMessageId;
|
||||
|
||||
/// <summary>
|
||||
/// Editor 向 Player 发送消息的标识符
|
||||
/// </summary>
|
||||
public static readonly Guid EditorToPlayerMessageId;
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 核心类说明
|
||||
|
||||
### RemoteDebugBehaviour
|
||||
|
||||
运行时调试组件,负责接收 Editor 命令并发送诊断数据。
|
||||
|
||||
**职责:**
|
||||
- 监听 Editor 发送的调试命令
|
||||
- 根据命令采集诊断数据
|
||||
- 将诊断报告发送回 Editor
|
||||
|
||||
**采样模式:**
|
||||
- `SampleOnce`: 单次采样,采集一帧数据后停止
|
||||
- `AutoSampling`: 持续采样,每帧自动采集并发送数据
|
||||
|
||||
**生命周期:**
|
||||
|
||||
```
|
||||
Awake() ──► 初始化连接
|
||||
OnEnable() ──► 注册消息处理器
|
||||
LateUpdate()──► 检查采样标志,采集并发送数据
|
||||
OnDisable() ──► 注销消息处理器
|
||||
```
|
||||
|
||||
### MockEditorConnection / MockPlayerConnection
|
||||
|
||||
Editor 模式下的模拟连接,用于本地调试。
|
||||
|
||||
**特性:**
|
||||
- 在 Editor 中模拟 `EditorConnection` 和 `PlayerConnection` 的行为
|
||||
- 实现消息的本地传递,无需真机连接
|
||||
- 支持消息注册、注销和发送
|
||||
|
||||
```csharp
|
||||
// 注册消息处理器
|
||||
MockPlayerConnection.Instance.Register(messageId, callback);
|
||||
|
||||
// 发送消息
|
||||
MockPlayerConnection.Instance.Send(messageId, data);
|
||||
|
||||
// 注销消息处理器
|
||||
MockPlayerConnection.Instance.Unregister(messageId);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 通信流程
|
||||
|
||||
### Editor 模式(本地调试)
|
||||
|
||||
```
|
||||
┌───────────────────┐ ┌───────────────────┐
|
||||
│ Debugger Window │ │ RemoteDebugBehaviour│
|
||||
│ (Editor) │ │ (PlayMode) │
|
||||
└────────┬──────────┘ └────────┬──────────┘
|
||||
│ │
|
||||
│ 1. 发送采样命令 │
|
||||
│ ─────────────────────────────►
|
||||
│ MockEditorConnection.Send() │
|
||||
│ │
|
||||
│ │ 2. 接收命令
|
||||
│ │ HandleEditorMessage()
|
||||
│ │
|
||||
│ │ 3. 采集诊断数据
|
||||
│ │ YooAssets.GetDebugReport()
|
||||
│ │
|
||||
│ 4. 返回诊断报告 │
|
||||
│ ◄─────────────────────────────
|
||||
│ MockPlayerConnection.Send() │
|
||||
│ │
|
||||
│ 5. 解析并展示数据 │
|
||||
▼ ▼
|
||||
```
|
||||
|
||||
### 真机模式(远程调试)
|
||||
|
||||
```
|
||||
┌───────────────────┐ ┌───────────────────┐
|
||||
│ Debugger Window │ │ RemoteDebugBehaviour│
|
||||
│ (Editor) │ USB │ (Device) │
|
||||
└────────┬──────────┘ ════ └────────┬──────────┘
|
||||
│ │
|
||||
│ 1. 发送采样命令 │
|
||||
│ ─────────────────────────────►
|
||||
│ EditorConnection.Send() │
|
||||
│ │
|
||||
│ │ 2. 接收命令
|
||||
│ │ PlayerConnection.Register()
|
||||
│ │
|
||||
│ │ 3. 采集诊断数据
|
||||
│ │
|
||||
│ 4. 返回诊断报告 │
|
||||
│ ◄─────────────────────────────
|
||||
│ PlayerConnection.Send() │
|
||||
│ │
|
||||
│ 5. 解析并展示数据 │
|
||||
▼ ▼
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 设计模式
|
||||
|
||||
### 单例模式
|
||||
|
||||
`MockEditorConnection` 和 `MockPlayerConnection` 使用单例模式:
|
||||
|
||||
```csharp
|
||||
public static MockPlayerConnection Instance
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_instance == null)
|
||||
_instance = new MockPlayerConnection();
|
||||
return _instance;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 观察者模式
|
||||
|
||||
通过消息注册机制实现观察者模式:
|
||||
|
||||
```
|
||||
Register(messageId, callback) ──► 订阅消息
|
||||
Unregister(messageId) ──► 取消订阅
|
||||
HandleXxxMessage(messageId, data) ──► 通知订阅者
|
||||
```
|
||||
|
||||
### 命令模式
|
||||
|
||||
`RemoteDebugCommand` 封装调试指令:
|
||||
|
||||
```
|
||||
Editor Player
|
||||
│ │
|
||||
│ RemoteDebugCommand │
|
||||
│ ┌──────────────────┐ │
|
||||
│ │ CommandType: 0 │ │
|
||||
│ │ Parameter: "" │ ──────►│ 执行采样
|
||||
│ └──────────────────┘ │
|
||||
│ │
|
||||
│ RemoteDebugCommand │
|
||||
│ ┌──────────────────┐ │
|
||||
│ │ CommandType: 1 │ │
|
||||
│ │ Parameter: "open"│ ──────►│ 开启持续采样
|
||||
│ └──────────────────┘ │
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 类关系图
|
||||
|
||||
```
|
||||
DiagnosticReport (诊断报告)
|
||||
│
|
||||
└── List<DiagnosticPackageData> (包裹数据)
|
||||
│
|
||||
├── List<DiagnosticProviderInfo> (资源加载信息)
|
||||
├── List<DiagnosticBundleInfo> (资源包信息)
|
||||
└── List<DiagnosticOperationInfo> (异步操作信息)
|
||||
│
|
||||
└── List<DiagnosticOperationInfo> (子任务)
|
||||
|
||||
RemoteDebugBehaviour (运行时组件)
|
||||
│
|
||||
├── 接收 ──► RemoteDebugCommand
|
||||
│
|
||||
└── 发送 ──► DiagnosticReport
|
||||
|
||||
MockEditorConnection ◄────► MockPlayerConnection (Editor 模拟通信)
|
||||
EditorConnection ◄────► PlayerConnection (真机通信)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 注意事项
|
||||
|
||||
1. **采样性能**:持续采样模式会每帧采集数据,可能影响性能,建议仅在调试时使用
|
||||
2. **数据序列化**:使用 Unity 的 `JsonUtility` 进行序列化,受其限制(如不支持 Dictionary)
|
||||
3. **版本兼容**:`DebuggerVersion` 用于版本控制,Editor 和 Player 版本不匹配时可能无法正常工作
|
||||
4. **子任务深度**:`DiagnosticOperationInfo.Children` 存在序列化深度限制(10层)
|
||||
5. **Editor 模式**:在 Editor 模式下使用 Mock 连接进行本地通信,无需真机
|
||||
6. **真机调试**:真机调试需要通过 USB 连接,使用 Unity 的 `PlayerConnection` API
|
||||
7. **线程安全**:所有操作应在主线程进行
|
||||
8. **资源释放**:`MockEditorConnection` 和 `MockPlayerConnection` 在 Domain Reload 时会自动重置
|
||||
@@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0ee8a6b68676976428b1886c273eaeb6
|
||||
guid: 5fa2b66c20800124c8dd5cb77e854ce3
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
@@ -144,7 +144,7 @@ internal interface IDownloadRequest : IDisposable
|
||||
string URL { get; }
|
||||
|
||||
// 生命周期
|
||||
bool IsDone { get; } // 每次访问自动轮询
|
||||
bool IsDone { get; } // 访问时自动调用 PollingRequest()
|
||||
EDownloadRequestStatus Status { get; }
|
||||
|
||||
// 进度跟踪
|
||||
@@ -561,20 +561,25 @@ SimulateRequestFile (独立实现) ──► IDownloadFileRequest
|
||||
|
||||
### DownloadSystemTools
|
||||
|
||||
提供跨平台的工具函数:
|
||||
提供跨平台的 URL 转换和判断功能:
|
||||
|
||||
| 方法 | 说明 |
|
||||
|------|------|
|
||||
| `ToLocalURL()` | 转换本地路径为文件协议 URL |
|
||||
| `IsLocalFileURL()` | 判断是否本地文件 URL |
|
||||
| 方法 | 参数 | 返回值 | 说明 |
|
||||
|------|------|--------|------|
|
||||
| `ToLocalURL(path)` | `string path` 本地文件路径 | 可用于 UnityWebRequest 的文件协议 URL | 转换本地路径为文件协议 URL(自动处理特殊字符) |
|
||||
| `IsLocalFileURL(url)` | `string url` 要判断的 URL | `bool` 是否为本地文件 URL | 判断 URL 是否为 `file:` 或 `jar:file:` 协议 |
|
||||
|
||||
### DownloadFailureCounter
|
||||
|
||||
请求失败计数器,用于诊断统计:
|
||||
网络请求失败计数器(诊断用):
|
||||
|
||||
- 线程安全:内部使用 `Dictionary` 且未加锁,约定只在主线程调用;如需多线程统计请在外层加锁或改造实现
|
||||
- Key 规则:`$"{packageName}_{eventName}"`
|
||||
- 统计口径:**仅统计网络请求失败**(`IDownloadRequest.Status != Succeed` 时记录),不统计内容为空、校验失败、解析失败等业务层失败
|
||||
- **线程安全**:内部使用 `Dictionary` 且未加锁,约定只在 Unity 主线程调用;如需在多线程/回调线程调用,请在外层加锁或改为并发容器实现
|
||||
- **Key 格式**:`$"{packageName}_{eventName}"`
|
||||
- **统计口径**:**仅统计网络请求失败**(`IDownloadRequest.Status != Succeed` 时记录),不统计内容为空、校验失败、解析失败等业务层失败
|
||||
|
||||
| 方法 | 参数 | 返回值 | 说明 |
|
||||
|------|------|--------|------|
|
||||
| `RecordFailure(packageName, eventName)` | `string packageName` 资源包名称, `string eventName` 事件名称 | `void` | 记录一次失败 |
|
||||
| `GetFailureCount(packageName, eventName)` | `string packageName` 资源包名称, `string eventName` 事件名称 | `int` 失败次数(未记录过返回 0) | 获取失败次数 |
|
||||
|
||||
```csharp
|
||||
// 记录失败
|
||||
|
||||
@@ -49,7 +49,7 @@ namespace YooAsset
|
||||
|
||||
if (_steps == ESteps.LoadAsset)
|
||||
{
|
||||
if (IsWaitForAsyncComplete)
|
||||
if (IsWaitingForAsyncComplete)
|
||||
{
|
||||
if (_assetInfo.AssetType == null)
|
||||
Result = _assetBundle.LoadAllAssets();
|
||||
@@ -71,7 +71,7 @@ namespace YooAsset
|
||||
{
|
||||
if (_request != null)
|
||||
{
|
||||
if (IsWaitForAsyncComplete)
|
||||
if (IsWaitingForAsyncComplete)
|
||||
{
|
||||
// 强制挂起主线程(注意:该操作会很耗时)
|
||||
YooLogger.Warning("Suspend the main thread to load unity asset.");
|
||||
|
||||
@@ -49,7 +49,7 @@ namespace YooAsset
|
||||
|
||||
if (_steps == ESteps.LoadAsset)
|
||||
{
|
||||
if (IsWaitForAsyncComplete)
|
||||
if (IsWaitingForAsyncComplete)
|
||||
{
|
||||
if (_assetInfo.AssetType == null)
|
||||
Result = _assetBundle.LoadAsset(_assetInfo.AssetPath);
|
||||
@@ -71,7 +71,7 @@ namespace YooAsset
|
||||
{
|
||||
if (_request != null)
|
||||
{
|
||||
if (IsWaitForAsyncComplete)
|
||||
if (IsWaitingForAsyncComplete)
|
||||
{
|
||||
// 强制挂起主线程(注意:该操作会很耗时)
|
||||
YooLogger.Warning("Suspend the main thread to load unity asset.");
|
||||
|
||||
@@ -36,7 +36,7 @@ namespace YooAsset
|
||||
|
||||
if (_steps == ESteps.LoadScene)
|
||||
{
|
||||
if (IsWaitForAsyncComplete)
|
||||
if (IsWaitingForAsyncComplete)
|
||||
{
|
||||
// 注意:场景同步加载方法不会立即加载场景,而是在下一帧加载。
|
||||
Result = SceneManager.LoadScene(_assetInfo.AssetPath, _loadParams);
|
||||
@@ -69,7 +69,7 @@ namespace YooAsset
|
||||
{
|
||||
if (_asyncOperation != null)
|
||||
{
|
||||
if (IsWaitForAsyncComplete)
|
||||
if (IsWaitingForAsyncComplete)
|
||||
{
|
||||
//注意:场景加载无法强制异步转同步
|
||||
YooLogger.Error("The scene is loading asyn.");
|
||||
|
||||
@@ -49,7 +49,7 @@ namespace YooAsset
|
||||
|
||||
if (_steps == ESteps.LoadAsset)
|
||||
{
|
||||
if (IsWaitForAsyncComplete)
|
||||
if (IsWaitingForAsyncComplete)
|
||||
{
|
||||
if (_assetInfo.AssetType == null)
|
||||
Result = _assetBundle.LoadAssetWithSubAssets(_assetInfo.AssetPath);
|
||||
@@ -71,7 +71,7 @@ namespace YooAsset
|
||||
{
|
||||
if (_request != null)
|
||||
{
|
||||
if (IsWaitForAsyncComplete)
|
||||
if (IsWaitingForAsyncComplete)
|
||||
{
|
||||
// 强制挂起主线程(注意:该操作会很耗时)
|
||||
YooLogger.Warning("Suspend the main thread to load unity asset.");
|
||||
|
||||
@@ -43,7 +43,7 @@ namespace YooAsset
|
||||
|
||||
if (_steps == ESteps.LoadScene)
|
||||
{
|
||||
if (IsWaitForAsyncComplete)
|
||||
if (IsWaitingForAsyncComplete)
|
||||
{
|
||||
Result = UnityEditor.SceneManagement.EditorSceneManager.LoadSceneInPlayMode(_assetInfo.AssetPath, _loadParams);
|
||||
_steps = ESteps.CheckResult;
|
||||
@@ -74,7 +74,7 @@ namespace YooAsset
|
||||
{
|
||||
if (_asyncOperation != null)
|
||||
{
|
||||
if (IsWaitForAsyncComplete)
|
||||
if (IsWaitingForAsyncComplete)
|
||||
{
|
||||
// 注意:场景加载无法强制异步转同步
|
||||
YooLogger.Error("The scene is loading asyn.");
|
||||
|
||||
@@ -54,7 +54,7 @@ namespace YooAsset
|
||||
}
|
||||
}
|
||||
|
||||
if (IsWaitForAsyncComplete)
|
||||
if (IsWaitingForAsyncComplete)
|
||||
{
|
||||
if (_bundle.Encrypted)
|
||||
{
|
||||
@@ -90,7 +90,7 @@ namespace YooAsset
|
||||
{
|
||||
if (_createRequest != null)
|
||||
{
|
||||
if (IsWaitForAsyncComplete)
|
||||
if (IsWaitingForAsyncComplete)
|
||||
{
|
||||
// 强制挂起主线程(注意:该操作会很耗时)
|
||||
YooLogger.Warning("Suspend the main thread to load unity bundle.");
|
||||
@@ -253,7 +253,7 @@ namespace YooAsset
|
||||
}
|
||||
}
|
||||
|
||||
if (IsWaitForAsyncComplete)
|
||||
if (IsWaitingForAsyncComplete)
|
||||
{
|
||||
if (_bundle.Encrypted)
|
||||
{
|
||||
@@ -289,7 +289,7 @@ namespace YooAsset
|
||||
{
|
||||
if (_createRequest != null)
|
||||
{
|
||||
if (IsWaitForAsyncComplete)
|
||||
if (IsWaitingForAsyncComplete)
|
||||
{
|
||||
// 强制挂起主线程(注意:该操作会很耗时)
|
||||
YooLogger.Warning("Suspend the main thread to load unity bundle.");
|
||||
|
||||
@@ -126,7 +126,7 @@ namespace YooAsset
|
||||
}
|
||||
}
|
||||
}
|
||||
internal override string InternalGetDesc()
|
||||
internal override string InternalGetDescription()
|
||||
{
|
||||
return $"PackageVersion : {_packageVersion} PackageHash : {_packageHash}";
|
||||
}
|
||||
|
||||
@@ -85,7 +85,7 @@ namespace YooAsset
|
||||
AddChildOperation(_downloadFileOp);
|
||||
}
|
||||
|
||||
if (IsWaitForAsyncComplete)
|
||||
if (IsWaitingForAsyncComplete)
|
||||
_downloadFileOp.WaitForAsyncComplete();
|
||||
|
||||
_downloadFileOp.UpdateOperation();
|
||||
@@ -110,7 +110,7 @@ namespace YooAsset
|
||||
{
|
||||
if (_downloadFileOp != null)
|
||||
{
|
||||
if (IsWaitForAsyncComplete)
|
||||
if (IsWaitingForAsyncComplete)
|
||||
_downloadFileOp.WaitForAsyncComplete();
|
||||
|
||||
_downloadFileOp.UpdateOperation();
|
||||
@@ -137,7 +137,7 @@ namespace YooAsset
|
||||
}
|
||||
}
|
||||
|
||||
if (IsWaitForAsyncComplete)
|
||||
if (IsWaitingForAsyncComplete)
|
||||
{
|
||||
if (_bundle.Encrypted)
|
||||
{
|
||||
@@ -173,7 +173,7 @@ namespace YooAsset
|
||||
{
|
||||
if (_createRequest != null)
|
||||
{
|
||||
if (IsWaitForAsyncComplete)
|
||||
if (IsWaitingForAsyncComplete)
|
||||
{
|
||||
// 强制挂起主线程(注意:该操作会很耗时)
|
||||
YooLogger.Warning("Suspend the main thread to load unity bundle.");
|
||||
@@ -354,7 +354,7 @@ namespace YooAsset
|
||||
AddChildOperation(_downloadFileOp);
|
||||
}
|
||||
|
||||
if (IsWaitForAsyncComplete)
|
||||
if (IsWaitingForAsyncComplete)
|
||||
_downloadFileOp.WaitForAsyncComplete();
|
||||
|
||||
_downloadFileOp.UpdateOperation();
|
||||
@@ -379,7 +379,7 @@ namespace YooAsset
|
||||
{
|
||||
if (_downloadFileOp != null)
|
||||
{
|
||||
if (IsWaitForAsyncComplete)
|
||||
if (IsWaitingForAsyncComplete)
|
||||
_downloadFileOp.WaitForAsyncComplete();
|
||||
|
||||
_downloadFileOp.UpdateOperation();
|
||||
|
||||
@@ -75,7 +75,7 @@ namespace YooAsset
|
||||
// 检测下载结果
|
||||
if (_steps == ESteps.CheckRequest)
|
||||
{
|
||||
if (IsWaitForAsyncComplete)
|
||||
if (IsWaitingForAsyncComplete)
|
||||
_downloadFileOp.WaitForAsyncComplete();
|
||||
|
||||
_downloadFileOp.UpdateOperation();
|
||||
@@ -92,7 +92,7 @@ namespace YooAsset
|
||||
}
|
||||
else
|
||||
{
|
||||
if (IsWaitForAsyncComplete == false && _failedTryAgain > 0)
|
||||
if (IsWaitingForAsyncComplete == false && _failedTryAgain > 0)
|
||||
{
|
||||
_steps = ESteps.TryAgain;
|
||||
YooLogger.Warning($"Failed download : {_downloadFileOp.URL} Try again.");
|
||||
|
||||
@@ -99,7 +99,7 @@ namespace YooAsset
|
||||
}
|
||||
}
|
||||
}
|
||||
internal override string InternalGetDesc()
|
||||
internal override string InternalGetDescription()
|
||||
{
|
||||
return $"PackageVersion : {_packageVersion} PackageHash : {_packageHash}";
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ namespace YooAsset
|
||||
{
|
||||
URL = url;
|
||||
}
|
||||
internal override string InternalGetDesc()
|
||||
internal override string InternalGetDescription()
|
||||
{
|
||||
return $"RefCount : {RefCount}";
|
||||
}
|
||||
|
||||
@@ -99,7 +99,7 @@ namespace YooAsset
|
||||
if (_steps == ESteps.CheckRequest)
|
||||
{
|
||||
//TODO 更新下载后台,防止无限挂起
|
||||
if (IsWaitForAsyncComplete)
|
||||
if (IsWaitingForAsyncComplete)
|
||||
_fileSystem.DownloadBackend.Update();
|
||||
|
||||
DownloadProgress = _request.DownloadProgress;
|
||||
@@ -135,7 +135,7 @@ namespace YooAsset
|
||||
AddChildOperation(_verifyOperation);
|
||||
}
|
||||
|
||||
if (IsWaitForAsyncComplete)
|
||||
if (IsWaitingForAsyncComplete)
|
||||
_verifyOperation.WaitForAsyncComplete();
|
||||
|
||||
_verifyOperation.UpdateOperation();
|
||||
|
||||
@@ -98,7 +98,7 @@ namespace YooAsset
|
||||
AddChildOperation(_verifyOperation);
|
||||
}
|
||||
|
||||
if (IsWaitForAsyncComplete)
|
||||
if (IsWaitingForAsyncComplete)
|
||||
_verifyOperation.WaitForAsyncComplete();
|
||||
|
||||
_verifyOperation.UpdateOperation();
|
||||
|
||||
@@ -113,7 +113,7 @@ namespace YooAsset
|
||||
}
|
||||
}
|
||||
}
|
||||
internal override string InternalGetDesc()
|
||||
internal override string InternalGetDescription()
|
||||
{
|
||||
return $"{_fileSystem.GetType().FullName}";
|
||||
}
|
||||
|
||||
@@ -70,7 +70,7 @@ namespace YooAsset
|
||||
AddChildOperation(_downloadFileOp);
|
||||
}
|
||||
|
||||
if (IsWaitForAsyncComplete)
|
||||
if (IsWaitingForAsyncComplete)
|
||||
_downloadFileOp.WaitForAsyncComplete();
|
||||
|
||||
_downloadFileOp.UpdateOperation();
|
||||
@@ -95,7 +95,7 @@ namespace YooAsset
|
||||
{
|
||||
if (_downloadFileOp != null)
|
||||
{
|
||||
if (IsWaitForAsyncComplete)
|
||||
if (IsWaitingForAsyncComplete)
|
||||
_downloadFileOp.WaitForAsyncComplete();
|
||||
|
||||
_downloadFileOp.UpdateOperation();
|
||||
@@ -110,7 +110,7 @@ namespace YooAsset
|
||||
|
||||
if (_steps == ESteps.LoadAssetBundle)
|
||||
{
|
||||
if (IsWaitForAsyncComplete)
|
||||
if (IsWaitingForAsyncComplete)
|
||||
{
|
||||
if (_fileSystem.VirtualWebGLMode)
|
||||
{
|
||||
|
||||
@@ -91,7 +91,7 @@ namespace YooAsset
|
||||
}
|
||||
else
|
||||
{
|
||||
if (IsWaitForAsyncComplete == false && _failedTryAgain > 0)
|
||||
if (IsWaitingForAsyncComplete == false && _failedTryAgain > 0)
|
||||
{
|
||||
_steps = ESteps.TryAgain;
|
||||
YooLogger.Warning($"Failed download : {_downloadFileOp.URL} Try again.");
|
||||
|
||||
@@ -99,7 +99,7 @@ namespace YooAsset
|
||||
}
|
||||
}
|
||||
}
|
||||
internal override string InternalGetDesc()
|
||||
internal override string InternalGetDescription()
|
||||
{
|
||||
return $"PackageVersion : {_packageVersion} PackageHash : {_packageHash}";
|
||||
}
|
||||
|
||||
@@ -120,7 +120,7 @@ internal class LoadWebPackageManifestOperation : AsyncOperationBase
|
||||
}
|
||||
}
|
||||
}
|
||||
internal override string InternalGetDesc()
|
||||
internal override string InternalGetDescription()
|
||||
{
|
||||
return $"PackageVersion : {_packageVersion} PackageHash : {_packageHash}";
|
||||
}
|
||||
|
||||
@@ -110,7 +110,7 @@ namespace YooAsset
|
||||
}
|
||||
}
|
||||
}
|
||||
internal override string InternalGetDesc()
|
||||
internal override string InternalGetDescription()
|
||||
{
|
||||
return $"PackageVersion : {_packageVersion} PackageHash : {_packageHash}";
|
||||
}
|
||||
|
||||
@@ -6,16 +6,20 @@ using System.Threading.Tasks;
|
||||
|
||||
namespace YooAsset
|
||||
{
|
||||
/// <summary>
|
||||
/// 异步操作基类,所有异步操作的抽象基类
|
||||
/// 支持协程(IEnumerator)、Task(async/await)、回调等多种异步编程模式
|
||||
/// </summary>
|
||||
public abstract class AsyncOperationBase : IEnumerator, IComparable<AsyncOperationBase>
|
||||
{
|
||||
private List<AsyncOperationBase> _childs;
|
||||
private Action<AsyncOperationBase> _callback;
|
||||
private List<AsyncOperationBase> _children;
|
||||
private Action<AsyncOperationBase> _completedCallbacks;
|
||||
private uint _priority;
|
||||
|
||||
/// <summary>
|
||||
/// 等待异步执行完成
|
||||
/// 是否正处于同步等待状态
|
||||
/// </summary>
|
||||
internal bool IsWaitForAsyncComplete { get; private set; }
|
||||
internal bool IsWaitingForAsyncComplete { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 标记脏(用于调度器检测并重排)
|
||||
@@ -23,25 +27,25 @@ namespace YooAsset
|
||||
internal bool IsDirty { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否已经完成
|
||||
/// 任务是否已结束(已触发回调和Task完成)
|
||||
/// </summary>
|
||||
internal bool IsFinish { get; private set; }
|
||||
internal bool IsFinished { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 异步系统是否繁忙
|
||||
/// 当前帧时间切片是否已用完(同步等待时始终返回false)
|
||||
/// </summary>
|
||||
internal bool IsBusy
|
||||
{
|
||||
get
|
||||
{
|
||||
if (IsWaitForAsyncComplete)
|
||||
if (IsWaitingForAsyncComplete)
|
||||
return false;
|
||||
return OperationSystem.IsBusy;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 任务优先级
|
||||
/// 任务优先级(值越大越优先执行)
|
||||
/// </summary>
|
||||
public uint Priority
|
||||
{
|
||||
@@ -74,7 +78,7 @@ namespace YooAsset
|
||||
public float Progress { get; protected set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否已经完成
|
||||
/// 任务逻辑是否完成(Status为Succeed或Failed)
|
||||
/// </summary>
|
||||
public bool IsDone
|
||||
{
|
||||
@@ -108,17 +112,17 @@ namespace YooAsset
|
||||
}
|
||||
else
|
||||
{
|
||||
_callback += value;
|
||||
_completedCallbacks += value;
|
||||
}
|
||||
}
|
||||
remove
|
||||
{
|
||||
_callback -= value;
|
||||
_completedCallbacks -= value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 异步操作任务
|
||||
/// 用于 async/await 的 Task 对象
|
||||
/// </summary>
|
||||
public Task Task
|
||||
{
|
||||
@@ -134,16 +138,37 @@ namespace YooAsset
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 内部启动方法(子类必须实现)
|
||||
/// </summary>
|
||||
internal abstract void InternalStart();
|
||||
|
||||
/// <summary>
|
||||
/// 内部更新方法(子类必须实现)
|
||||
/// </summary>
|
||||
internal abstract void InternalUpdate();
|
||||
|
||||
/// <summary>
|
||||
/// 内部中止方法(子类可选实现)
|
||||
/// </summary>
|
||||
internal virtual void InternalAbort()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 内部同步等待方法(子类可选实现)
|
||||
/// 默认抛出异常,如果异步操作需要支持,子类应重写以支持同步等待
|
||||
/// </summary>
|
||||
internal virtual void InternalWaitForAsyncComplete()
|
||||
{
|
||||
throw new YooInternalException($"InternalWaitForAsyncComplete() not implemented : {this.GetType().Name}");
|
||||
}
|
||||
internal virtual string InternalGetDesc()
|
||||
|
||||
/// <summary>
|
||||
/// 获取操作的描述信息(子类可选实现)
|
||||
/// </summary>
|
||||
internal virtual string InternalGetDescription()
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
@@ -153,8 +178,8 @@ namespace YooAsset
|
||||
/// </summary>
|
||||
internal void AddChildOperation(AsyncOperationBase child)
|
||||
{
|
||||
if (_childs == null)
|
||||
_childs = new List<AsyncOperationBase>(10);
|
||||
if (_children == null)
|
||||
_children = new List<AsyncOperationBase>(10);
|
||||
|
||||
#if UNITY_EDITOR || DEBUG
|
||||
if (child == null)
|
||||
@@ -163,7 +188,7 @@ namespace YooAsset
|
||||
if (ReferenceEquals(child, this))
|
||||
throw new YooInternalException("The child node cannot be itself.");
|
||||
|
||||
if (_childs.Contains(child))
|
||||
if (_children.Contains(child))
|
||||
throw new YooInternalException($"The child node {child.GetType().Name} already exists.");
|
||||
|
||||
// 禁止形成环依赖
|
||||
@@ -171,7 +196,7 @@ namespace YooAsset
|
||||
throw new YooInternalException($"AddChildOperation would create a cycle : {this.GetType().Name} -> {child.GetType().Name}");
|
||||
#endif
|
||||
|
||||
_childs.Add(child);
|
||||
_children.Add(child);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -179,26 +204,26 @@ namespace YooAsset
|
||||
/// </summary>
|
||||
internal void RemoveChildOperation(AsyncOperationBase child)
|
||||
{
|
||||
if (_childs == null)
|
||||
if (_children == null)
|
||||
return;
|
||||
|
||||
#if UNITY_EDITOR || DEBUG
|
||||
if (child == null)
|
||||
throw new YooInternalException("The child node is null.");
|
||||
|
||||
if (_childs.Contains(child) == false)
|
||||
if (_children.Contains(child) == false)
|
||||
throw new YooInternalException($"The child node {child.GetType().Name} not exists.");
|
||||
#endif
|
||||
|
||||
_childs.Remove(child);
|
||||
_children.Remove(child);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取异步操作说明
|
||||
/// </summary>
|
||||
internal string GetOperationDesc()
|
||||
internal string GetOperationDescription()
|
||||
{
|
||||
return InternalGetDesc();
|
||||
return InternalGetDescription();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -252,7 +277,7 @@ namespace YooAsset
|
||||
}
|
||||
}
|
||||
|
||||
if (IsDone && IsFinish == false)
|
||||
if (IsDone && IsFinished == false)
|
||||
{
|
||||
FinishOperation();
|
||||
}
|
||||
@@ -263,9 +288,9 @@ namespace YooAsset
|
||||
/// </summary>
|
||||
internal void AbortOperation()
|
||||
{
|
||||
if (_childs != null)
|
||||
if (_children != null)
|
||||
{
|
||||
foreach (var child in _childs)
|
||||
foreach (var child in _children)
|
||||
{
|
||||
child.AbortOperation();
|
||||
}
|
||||
@@ -284,21 +309,21 @@ namespace YooAsset
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 强制结束异步任务
|
||||
/// 完成异步任务(触发回调和Task完成)
|
||||
/// </summary>
|
||||
private void FinishOperation()
|
||||
{
|
||||
if (IsFinish == false)
|
||||
if (IsFinished == false)
|
||||
{
|
||||
IsFinish = true;
|
||||
IsFinished = true;
|
||||
Progress = 1f;
|
||||
|
||||
// 结束记录
|
||||
DebugEndRecording();
|
||||
|
||||
if (_callback != null)
|
||||
if (_completedCallbacks != null)
|
||||
{
|
||||
var invocationList = _callback.GetInvocationList();
|
||||
var invocationList = _completedCallbacks.GetInvocationList();
|
||||
foreach (var handler in invocationList)
|
||||
{
|
||||
try
|
||||
@@ -312,7 +337,7 @@ namespace YooAsset
|
||||
}
|
||||
}
|
||||
|
||||
_callback = null;
|
||||
_completedCallbacks = null;
|
||||
if (_taskCompletionSource != null)
|
||||
_taskCompletionSource.TrySetResult(null);
|
||||
}
|
||||
@@ -388,9 +413,9 @@ namespace YooAsset
|
||||
StartOperation();
|
||||
}
|
||||
|
||||
if (IsWaitForAsyncComplete == false)
|
||||
if (IsWaitingForAsyncComplete == false)
|
||||
{
|
||||
IsWaitForAsyncComplete = true;
|
||||
IsWaitingForAsyncComplete = true;
|
||||
|
||||
if (IsDone == false)
|
||||
InternalWaitForAsyncComplete();
|
||||
@@ -409,52 +434,58 @@ namespace YooAsset
|
||||
|
||||
#region 调试信息
|
||||
/// <summary>
|
||||
/// 开始的时间
|
||||
/// 任务开始的时间(格式:HH:MM:SS,仅DEBUG模式有效)
|
||||
/// </summary>
|
||||
public string BeginTime { get; protected set; }
|
||||
public string StartTime { get; protected set; }
|
||||
|
||||
/// <summary>
|
||||
/// 处理耗时(单位:毫秒)
|
||||
/// </summary>
|
||||
public long ProcessTime { get; protected set; }
|
||||
public long ElapsedMS { get; protected set; }
|
||||
|
||||
// 加载耗时统计
|
||||
private Stopwatch _watch = null;
|
||||
/// <summary>
|
||||
/// 任务耗时计时器
|
||||
/// </summary>
|
||||
private Stopwatch _stopwatch = null;
|
||||
|
||||
[Conditional("DEBUG")]
|
||||
private void DebugBeginRecording()
|
||||
{
|
||||
if (_watch == null)
|
||||
if (_stopwatch == null)
|
||||
{
|
||||
BeginTime = SpawnTimeToString(TimeUtility.RealtimeSinceStartup);
|
||||
_watch = Stopwatch.StartNew();
|
||||
StartTime = FormatElapsedTime(TimeUtility.RealtimeSinceStartup);
|
||||
_stopwatch = Stopwatch.StartNew();
|
||||
}
|
||||
}
|
||||
|
||||
[Conditional("DEBUG")]
|
||||
private void DebugUpdateRecording()
|
||||
{
|
||||
if (_watch != null)
|
||||
if (_stopwatch != null)
|
||||
{
|
||||
ProcessTime = _watch.ElapsedMilliseconds;
|
||||
ElapsedMS = _stopwatch.ElapsedMilliseconds;
|
||||
}
|
||||
}
|
||||
|
||||
[Conditional("DEBUG")]
|
||||
private void DebugEndRecording()
|
||||
{
|
||||
if (_watch != null)
|
||||
if (_stopwatch != null)
|
||||
{
|
||||
ProcessTime = _watch.ElapsedMilliseconds;
|
||||
_watch = null;
|
||||
ElapsedMS = _stopwatch.ElapsedMilliseconds;
|
||||
_stopwatch = null;
|
||||
}
|
||||
}
|
||||
|
||||
private string SpawnTimeToString(double spawnTime)
|
||||
/// <summary>
|
||||
/// 将游戏运行时间格式化为 HH:MM:SS 格式
|
||||
/// </summary>
|
||||
/// <param name="time">运行时间(秒)</param>
|
||||
private string FormatElapsedTime(double time)
|
||||
{
|
||||
double h = System.Math.Floor(spawnTime / 3600);
|
||||
double m = System.Math.Floor(spawnTime / 60 - h * 60);
|
||||
double s = System.Math.Floor(spawnTime - m * 60 - h * 3600);
|
||||
double h = System.Math.Floor(time / 3600);
|
||||
double m = System.Math.Floor(time / 60 - h * 60);
|
||||
double s = System.Math.Floor(time - m * 60 - h * 3600);
|
||||
return h.ToString("00") + ":" + m.ToString("00") + ":" + s.ToString("00");
|
||||
}
|
||||
|
||||
@@ -487,13 +518,13 @@ namespace YooAsset
|
||||
if (ReferenceEquals(node, this))
|
||||
return true;
|
||||
|
||||
if (node._childs == null)
|
||||
if (node._children == null)
|
||||
continue;
|
||||
|
||||
// 将子节点加入栈
|
||||
for (int i = 0; i < node._childs.Count; i++)
|
||||
for (int i = 0; i < node._children.Count; i++)
|
||||
{
|
||||
stack.Push(node._childs[i]);
|
||||
stack.Push(node._children[i]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -508,21 +539,21 @@ namespace YooAsset
|
||||
{
|
||||
var operationInfo = new DiagnosticOperationInfo();
|
||||
operationInfo.OperationName = this.GetType().Name;
|
||||
operationInfo.OperationDesc = GetOperationDesc();
|
||||
operationInfo.OperationDesc = GetOperationDescription();
|
||||
operationInfo.Priority = Priority;
|
||||
operationInfo.Progress = Progress;
|
||||
operationInfo.StartTime = BeginTime;
|
||||
operationInfo.ElapsedMS = ProcessTime;
|
||||
operationInfo.StartTime = StartTime;
|
||||
operationInfo.ElapsedMS = ElapsedMS;
|
||||
operationInfo.Status = Status.ToString();
|
||||
|
||||
if (_childs == null)
|
||||
if (_children == null)
|
||||
{
|
||||
operationInfo.Children = new List<DiagnosticOperationInfo>();
|
||||
}
|
||||
else
|
||||
{
|
||||
operationInfo.Children = new List<DiagnosticOperationInfo>(_childs.Count);
|
||||
foreach (var child in _childs)
|
||||
operationInfo.Children = new List<DiagnosticOperationInfo>(_children.Count);
|
||||
foreach (var child in _children)
|
||||
{
|
||||
var childInfo = child.GetDebugOperationInfo();
|
||||
operationInfo.Children.Add(childInfo);
|
||||
@@ -541,6 +572,11 @@ namespace YooAsset
|
||||
#endregion
|
||||
|
||||
#region 异步编程相关
|
||||
/// <summary>
|
||||
/// 用于支持 async/await 的任务完成源
|
||||
/// </summary>
|
||||
private TaskCompletionSource<object> _taskCompletionSource;
|
||||
|
||||
bool IEnumerator.MoveNext()
|
||||
{
|
||||
return !IsDone;
|
||||
@@ -549,8 +585,6 @@ namespace YooAsset
|
||||
{
|
||||
}
|
||||
object IEnumerator.Current => null;
|
||||
|
||||
private TaskCompletionSource<object> _taskCompletionSource;
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,34 @@
|
||||
|
||||
namespace YooAsset
|
||||
{
|
||||
/// <summary>
|
||||
/// 异步操作状态枚举
|
||||
/// </summary>
|
||||
public enum EOperationStatus
|
||||
{
|
||||
/// <summary>
|
||||
/// 未开始
|
||||
/// </summary>
|
||||
None,
|
||||
|
||||
/// <summary>
|
||||
/// 处理中
|
||||
/// </summary>
|
||||
Processing,
|
||||
|
||||
/// <summary>
|
||||
/// 已成功
|
||||
/// </summary>
|
||||
Succeed,
|
||||
Failed
|
||||
|
||||
/// <summary>
|
||||
/// 已失败
|
||||
/// </summary>
|
||||
Failed,
|
||||
|
||||
/// <summary>
|
||||
/// 已中止
|
||||
/// </summary>
|
||||
Aborted,
|
||||
}
|
||||
}
|
||||
@@ -9,7 +9,7 @@ namespace YooAsset
|
||||
internal class OperationScheduler : IComparable<OperationScheduler>
|
||||
{
|
||||
private readonly List<AsyncOperationBase> _operations = new List<AsyncOperationBase>(100);
|
||||
private readonly List<AsyncOperationBase> _newList = new List<AsyncOperationBase>(100);
|
||||
private readonly List<AsyncOperationBase> _pendingOperations = new List<AsyncOperationBase>(100);
|
||||
private uint _priority;
|
||||
|
||||
/// <summary>
|
||||
@@ -41,24 +41,25 @@ namespace YooAsset
|
||||
/// <summary>
|
||||
/// 创建顺序(用于同优先级稳定排序)
|
||||
/// </summary>
|
||||
public int CreateIndex { get; private set; }
|
||||
public int CreationOrder { get; private set; }
|
||||
|
||||
|
||||
public OperationScheduler(string packageName, int createIndex)
|
||||
public OperationScheduler(string packageName, int creationOrder)
|
||||
{
|
||||
PackageName = packageName;
|
||||
CreateIndex = createIndex;
|
||||
CreationOrder = creationOrder;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 开始处理异步操作
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 操作会先添加到临时队列,在下一次Update时才会开始执行
|
||||
/// 操作会立即启动,但会先添加到待处理队列。
|
||||
/// 在下一次Update时才会合并到执行队列并参与调度更新
|
||||
/// </remarks>
|
||||
public void StartOperation(AsyncOperationBase operation)
|
||||
{
|
||||
_newList.Add(operation);
|
||||
_pendingOperations.Add(operation);
|
||||
operation.StartOperation();
|
||||
}
|
||||
|
||||
@@ -71,17 +72,17 @@ namespace YooAsset
|
||||
for (int i = _operations.Count - 1; i >= 0; i--)
|
||||
{
|
||||
var operation = _operations[i];
|
||||
if (operation.IsFinish)
|
||||
if (operation.IsFinished)
|
||||
{
|
||||
_operations.RemoveAt(i);
|
||||
}
|
||||
}
|
||||
|
||||
// 添加新增的异步操作
|
||||
if (_newList.Count > 0)
|
||||
if (_pendingOperations.Count > 0)
|
||||
{
|
||||
_operations.AddRange(_newList);
|
||||
_newList.Clear();
|
||||
_operations.AddRange(_pendingOperations);
|
||||
_pendingOperations.Clear();
|
||||
}
|
||||
|
||||
// 检测是否需要执行排序
|
||||
@@ -107,7 +108,7 @@ namespace YooAsset
|
||||
break;
|
||||
|
||||
var operation = _operations[i];
|
||||
if (operation.IsFinish)
|
||||
if (operation.IsFinished)
|
||||
continue;
|
||||
|
||||
operation.UpdateOperation();
|
||||
@@ -120,11 +121,11 @@ namespace YooAsset
|
||||
public void ClearAll()
|
||||
{
|
||||
// 终止临时队列里的任务
|
||||
foreach (var operation in _newList)
|
||||
foreach (var operation in _pendingOperations)
|
||||
{
|
||||
operation.AbortOperation();
|
||||
}
|
||||
_newList.Clear();
|
||||
_pendingOperations.Clear();
|
||||
|
||||
// 终止正在进行的任务
|
||||
foreach (var operation in _operations)
|
||||
@@ -139,7 +140,7 @@ namespace YooAsset
|
||||
/// </summary>
|
||||
public List<DiagnosticOperationInfo> GetDebugOperationInfos()
|
||||
{
|
||||
int totalCount = _operations.Count + _newList.Count;
|
||||
int totalCount = _operations.Count + _pendingOperations.Count;
|
||||
List<DiagnosticOperationInfo> result = new List<DiagnosticOperationInfo>(totalCount);
|
||||
|
||||
// 包含正在执行的任务
|
||||
@@ -150,7 +151,7 @@ namespace YooAsset
|
||||
}
|
||||
|
||||
// 包含待处理的新任务
|
||||
foreach (var operation in _newList)
|
||||
foreach (var operation in _pendingOperations)
|
||||
{
|
||||
var operationInfo = operation.GetDebugOperationInfo();
|
||||
result.Add(operationInfo);
|
||||
@@ -167,7 +168,7 @@ namespace YooAsset
|
||||
if (result == 0)
|
||||
{
|
||||
// 优先级相同,按创建顺序
|
||||
result = this.CreateIndex.CompareTo(other.CreateIndex);
|
||||
result = this.CreationOrder.CompareTo(other.CreationOrder);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -5,6 +5,10 @@ using System.Diagnostics;
|
||||
|
||||
namespace YooAsset
|
||||
{
|
||||
/// <summary>
|
||||
/// 异步操作系统(静态调度器)
|
||||
/// 负责管理所有包裹的调度器,提供时间切片执行机制
|
||||
/// </summary>
|
||||
internal static class OperationSystem
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
@@ -18,13 +22,13 @@ namespace YooAsset
|
||||
public const string GlobalSchedulerName = "YOOASSET_GLOBAL_SCHEDULER"; // 全局调度器名称
|
||||
private const long MinTimeSlice = 10; // 最小时间片(毫秒)
|
||||
|
||||
private static readonly Dictionary<string, OperationScheduler> _schedulerDic = new Dictionary<string, OperationScheduler>(100);
|
||||
private static readonly Dictionary<string, OperationScheduler> _schedulerDict = new Dictionary<string, OperationScheduler>(100);
|
||||
private static readonly List<OperationScheduler> _schedulerList = new List<OperationScheduler>(100);
|
||||
private static bool _isInitialized;
|
||||
private static int _createIndex;
|
||||
private static int _nextCreationIndex;
|
||||
|
||||
// 计时器相关
|
||||
private static Stopwatch _watch;
|
||||
private static Stopwatch _systemStopwatch;
|
||||
private static long _frameTime;
|
||||
private static long _maxTimeSlice = long.MaxValue;
|
||||
|
||||
@@ -58,14 +62,14 @@ namespace YooAsset
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_watch == null)
|
||||
if (_systemStopwatch == null)
|
||||
return false;
|
||||
|
||||
if (_maxTimeSlice == long.MaxValue)
|
||||
return false;
|
||||
|
||||
// 注意 : 单次调用开销约1微秒
|
||||
return _watch.ElapsedMilliseconds - _frameTime >= _maxTimeSlice;
|
||||
return _systemStopwatch.ElapsedMilliseconds - _frameTime >= _maxTimeSlice;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -82,7 +86,7 @@ namespace YooAsset
|
||||
}
|
||||
|
||||
_isInitialized = true;
|
||||
_watch = Stopwatch.StartNew();
|
||||
_systemStopwatch = Stopwatch.StartNew();
|
||||
|
||||
// 创建全局调度器
|
||||
CreatePackageScheduler(GlobalSchedulerName, uint.MaxValue);
|
||||
@@ -112,7 +116,7 @@ namespace YooAsset
|
||||
}
|
||||
|
||||
// 更新帧时间
|
||||
_frameTime = _watch.ElapsedMilliseconds;
|
||||
_frameTime = _systemStopwatch.ElapsedMilliseconds;
|
||||
|
||||
// 更新调度器
|
||||
for (int i = 0; i < _schedulerList.Count; i++)
|
||||
@@ -136,11 +140,11 @@ namespace YooAsset
|
||||
{
|
||||
scheduler.ClearAll();
|
||||
}
|
||||
_schedulerDic.Clear();
|
||||
_schedulerDict.Clear();
|
||||
_schedulerList.Clear();
|
||||
_createIndex = 0;
|
||||
_nextCreationIndex = 0;
|
||||
|
||||
_watch = null;
|
||||
_systemStopwatch = null;
|
||||
_frameTime = 0;
|
||||
_maxTimeSlice = long.MaxValue;
|
||||
}
|
||||
@@ -152,13 +156,13 @@ namespace YooAsset
|
||||
{
|
||||
DebugEnsureInitialized(packageName);
|
||||
|
||||
if (_schedulerDic.ContainsKey(packageName))
|
||||
if (_schedulerDict.ContainsKey(packageName))
|
||||
{
|
||||
throw new YooInternalException($"Package scheduler already exists: {packageName}");
|
||||
}
|
||||
|
||||
var scheduler = new OperationScheduler(packageName, _createIndex++);
|
||||
_schedulerDic.Add(packageName, scheduler);
|
||||
var scheduler = new OperationScheduler(packageName, _nextCreationIndex++);
|
||||
_schedulerDict.Add(packageName, scheduler);
|
||||
_schedulerList.Add(scheduler);
|
||||
scheduler.Priority = priority;
|
||||
return scheduler;
|
||||
@@ -177,10 +181,10 @@ namespace YooAsset
|
||||
throw new YooInternalException("Cannot destroy the global package scheduler.");
|
||||
}
|
||||
|
||||
if (_schedulerDic.TryGetValue(packageName, out var scheduler))
|
||||
if (_schedulerDict.TryGetValue(packageName, out var scheduler))
|
||||
{
|
||||
scheduler.ClearAll();
|
||||
_schedulerDic.Remove(packageName);
|
||||
_schedulerDict.Remove(packageName);
|
||||
_schedulerList.Remove(scheduler);
|
||||
}
|
||||
}
|
||||
@@ -188,7 +192,7 @@ namespace YooAsset
|
||||
/// <summary>
|
||||
/// 销毁包裹的所有任务
|
||||
/// </summary>
|
||||
public static void ClearPackageOperation(string packageName)
|
||||
public static void ClearPackageOperations(string packageName)
|
||||
{
|
||||
DebugEnsureInitialized(packageName);
|
||||
|
||||
@@ -234,7 +238,7 @@ namespace YooAsset
|
||||
/// </summary>
|
||||
private static OperationScheduler GetScheduler(string packageName)
|
||||
{
|
||||
if (_schedulerDic.TryGetValue(packageName, out var scheduler))
|
||||
if (_schedulerDict.TryGetValue(packageName, out var scheduler))
|
||||
{
|
||||
return scheduler;
|
||||
}
|
||||
|
||||
@@ -1,555 +0,0 @@
|
||||
# OperationSystem 异步操作系统
|
||||
|
||||
## 模块概述
|
||||
|
||||
OperationSystem 是 YooAsset 资源管理系统的**异步操作调度核心**,负责管理所有异步操作的生命周期、调度执行和状态追踪。该模块提供了统一的异步操作抽象,支持协程、async/await、回调等多种异步编程模式。
|
||||
|
||||
### 对外使用说明
|
||||
|
||||
- `AsyncOperationBase` / `EOperationStatus` 为对外公开类型,业务层可直接使用(协程/Task/Completed)。
|
||||
- `OperationSystem` / `OperationScheduler` 为内部调度实现,由 `YooAssets.Update()` 驱动,业务层一般无需直接调用。
|
||||
- 时间切片预算建议通过 `YooAssets.SetOperationSystemMaxTimeSlice(milliseconds)` 配置(内部会设置 `OperationSystem.MaxTimeSlice`)。
|
||||
|
||||
### 核心职责
|
||||
|
||||
- 异步操作的统一抽象和生命周期管理
|
||||
- 基于优先级的操作调度
|
||||
- 时间切片执行(防止主线程阻塞)
|
||||
- 多种异步编程模式支持
|
||||
- 操作状态追踪和调试信息收集
|
||||
|
||||
---
|
||||
|
||||
## 设计目标
|
||||
|
||||
| 目标 | 说明 |
|
||||
|------|------|
|
||||
| **统一抽象** | 所有异步操作继承同一基类,接口一致 |
|
||||
| **灵活调度** | 支持优先级排序、时间切片、帧预算控制 |
|
||||
| **多模式支持** | 协程(IEnumerator)、Task(async/await)、回调 |
|
||||
| **可调试性** | 完整的状态追踪、耗时统计、层级关系 |
|
||||
| **线程安全** | 所有调度逻辑在主线程执行 |
|
||||
|
||||
---
|
||||
|
||||
## 架构概念
|
||||
|
||||
### 系统架构
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────┐
|
||||
│ 上层调用者 │
|
||||
│ (ResourceManager / FileSystem / 业务层) │
|
||||
└─────────────────────────┬───────────────────────────────┘
|
||||
│ StartOperation()
|
||||
┌─────────────────────────▼───────────────────────────────┐
|
||||
│ OperationSystem │
|
||||
│ (调度器) │
|
||||
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
|
||||
│ │ 优先级队列 │ │ 时间切片 │ │ 回调通知 │ │
|
||||
│ └─────────────┘ └─────────────┘ └─────────────┘ │
|
||||
└─────────────────────────┬───────────────────────────────┘
|
||||
│ UpdateOperation()
|
||||
┌─────────────────────────▼───────────────────────────────┐
|
||||
│ AsyncOperationBase │
|
||||
│ (操作基类) │
|
||||
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
|
||||
│ │ 状态机 │ │ 子任务管理 │ │ 异步模式 │ │
|
||||
│ └─────────────┘ └─────────────┘ └─────────────┘ │
|
||||
└─────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### 核心组件
|
||||
|
||||
- **OperationSystem**: 静态调度器,管理所有操作的执行
|
||||
- **OperationScheduler**: 包裹级调度器,维护操作队列并负责更新调度
|
||||
- **AsyncOperationBase**: 异步操作基类,定义生命周期和状态
|
||||
- **EOperationStatus**: 操作状态枚举
|
||||
|
||||
---
|
||||
|
||||
## 文件结构
|
||||
|
||||
```
|
||||
OperationSystem/
|
||||
├── EOperationStatus.cs # 操作状态枚举
|
||||
├── AsyncOperationBase.cs # 异步操作基类
|
||||
├── OperationScheduler.cs # 包裹级调度器
|
||||
├── OperationSystem.cs # 异步操作调度器
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 枚举定义
|
||||
|
||||
### EOperationStatus(操作状态)
|
||||
|
||||
```csharp
|
||||
public enum EOperationStatus
|
||||
{
|
||||
None, // 未开始
|
||||
Processing, // 处理中
|
||||
Succeed, // 已成功
|
||||
Failed // 已失败
|
||||
}
|
||||
```
|
||||
|
||||
**状态转换:**
|
||||
|
||||
```
|
||||
StartOperation() InternalUpdate()
|
||||
None ─────────────────► Processing ─────────────────┬──► Succeed
|
||||
│
|
||||
└──► Failed
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 核心类说明
|
||||
|
||||
### AsyncOperationBase(异步操作基类)
|
||||
|
||||
所有异步操作的抽象基类,实现了 `IEnumerator` 和 `IComparable<AsyncOperationBase>` 接口。
|
||||
|
||||
#### 公共属性
|
||||
|
||||
| 属性 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| `Priority` | `uint` | 任务优先级(值越大越优先) |
|
||||
| `Status` | `EOperationStatus` | 当前状态 |
|
||||
| `Error` | `string` | 错误信息(失败时) |
|
||||
| `Progress` | `float` | 处理进度(0-1) |
|
||||
| `IsDone` | `bool` | 是否已完成(Succeed 或 Failed) |
|
||||
| `Task` | `Task` | 用于 async/await |
|
||||
| `BeginTime` | `string` | 开始时间(调试用) |
|
||||
| `ProcessTime` | `long` | 处理耗时毫秒(调试用) |
|
||||
|
||||
> 说明:`AsyncOperationBase` 本身不保存包裹名称;包裹名称由 `OperationSystem.StartOperation(packageName, operation)` 传入,并由 `OperationScheduler` 维护。
|
||||
|
||||
#### 内部协作:时间切片(`IsBusy`)
|
||||
|
||||
为配合异步系统的时间切片预算(可通过 `YooAssets.SetOperationSystemMaxTimeSlice` 配置),`AsyncOperationBase` 提供了内部属性 `IsBusy`(`internal`)用于任务在 `InternalUpdate()` 内主动让出本帧预算。
|
||||
|
||||
- 推荐用法:在 `InternalUpdate()` 内部(或内部子步骤)在执行重逻辑前判断 `IsBusy`,若繁忙则 `return`,把工作拆到下一帧继续执行。
|
||||
- 同步等待特殊处理:当调用了 `WaitForAsyncComplete()` 进入同步等待阶段时,`IsBusy` 会强制返回 `false`,避免因时间切片判断导致同步等待无法推进。
|
||||
- 注意:`WaitForAsyncComplete()` 会阻塞主线程,应谨慎使用;同步等待阶段不受时间切片保护,可能带来卡顿。
|
||||
|
||||
#### 公共事件
|
||||
|
||||
```csharp
|
||||
/// <summary>
|
||||
/// 完成事件(支持后注册立即触发)
|
||||
/// </summary>
|
||||
public event Action<AsyncOperationBase> Completed;
|
||||
```
|
||||
|
||||
#### 公共方法
|
||||
|
||||
```csharp
|
||||
/// <summary>
|
||||
/// 同步等待异步操作完成
|
||||
/// </summary>
|
||||
public void WaitForAsyncComplete();
|
||||
```
|
||||
|
||||
#### 内部抽象方法(子类实现)
|
||||
|
||||
| 方法 | 说明 |
|
||||
|------|------|
|
||||
| `InternalStart()` | 操作开始时调用 |
|
||||
| `InternalUpdate()` | 每帧更新时调用 |
|
||||
| `InternalAbort()` | 操作中止时调用(可选) |
|
||||
| `InternalWaitForAsyncComplete()` | 同步等待时调用(可选) |
|
||||
| `InternalGetDesc()` | 获取操作描述(可选) |
|
||||
|
||||
#### 子任务管理
|
||||
|
||||
```csharp
|
||||
// 添加/移除子任务(内部使用)
|
||||
internal void AddChildOperation(AsyncOperationBase child);
|
||||
internal void RemoveChildOperation(AsyncOperationBase child);
|
||||
```
|
||||
|
||||
**调用约束(重要):**
|
||||
- 仅允许在 Unity 主线程调用(与 `OperationSystem.Update()` 的调度线程一致)。
|
||||
- 不要在 `InternalUpdate()` 正在遍历/处理中途频繁增删子任务;推荐在任务启动阶段完成子任务挂接,或在确保无并发修改风险的安全点调整。
|
||||
- `AbortOperation()` 会递归中止子任务,子任务的生命周期由父任务统一管理;避免在 `Completed` 回调里再去修改子任务关系,防止时序混乱。
|
||||
|
||||
---
|
||||
|
||||
### OperationSystem(调度器)
|
||||
|
||||
静态类,负责异步操作的调度和管理。
|
||||
|
||||
#### 配置属性
|
||||
|
||||
```csharp
|
||||
/// <summary>
|
||||
/// 每帧最大执行时间(毫秒)
|
||||
/// 默认值:long.MaxValue(无限制)
|
||||
/// </summary>
|
||||
public static long MaxTimeSlice { set; get; }
|
||||
|
||||
/// <summary>
|
||||
/// 当前帧是否已超时
|
||||
/// </summary>
|
||||
public static bool IsBusy { get; }
|
||||
```
|
||||
|
||||
#### 核心方法
|
||||
|
||||
```csharp
|
||||
/// <summary>
|
||||
/// 初始化异步操作系统
|
||||
/// </summary>
|
||||
public static void Initialize();
|
||||
|
||||
/// <summary>
|
||||
/// 每帧更新(由 YooAssets 驱动)
|
||||
/// </summary>
|
||||
public static void Update();
|
||||
|
||||
/// <summary>
|
||||
/// 销毁所有操作
|
||||
/// </summary>
|
||||
public static void DestroyAll();
|
||||
|
||||
/// <summary>
|
||||
/// 清理指定包裹的所有操作
|
||||
/// </summary>
|
||||
public static void ClearPackageOperation(string packageName);
|
||||
|
||||
/// <summary>
|
||||
/// 启动异步操作
|
||||
/// </summary>
|
||||
public static void StartOperation(string packageName, AsyncOperationBase operation);
|
||||
|
||||
/// <summary>
|
||||
/// 设置调度器优先级
|
||||
/// </summary>
|
||||
public static void SetSchedulerPriority(string packageName, uint priority);
|
||||
|
||||
/// <summary>
|
||||
/// 获取调度器优先级
|
||||
/// </summary>
|
||||
public static uint GetSchedulerPriority(string packageName);
|
||||
```
|
||||
|
||||
#### 包裹调度说明
|
||||
|
||||
- `packageName` 不允许为空(`null` / `""`),否则会抛出异常。
|
||||
- 若在 YooAsset 内部需要使用全局调度器,请传入 `OperationSystem.GlobalSchedulerName`(`Initialize()` 时自动创建)。
|
||||
- `packageName` 为非全局调度器名称时,必须先通过 `YooAssets.CreatePackage(packageName)` 创建包裹(内部会注册对应 `OperationScheduler`),否则会抛出异常。
|
||||
|
||||
#### 回调监听
|
||||
|
||||
OperationSystem **当前未提供**全局任务开始/结束回调的注册接口。
|
||||
|
||||
如需监听任务结束(推荐),请直接订阅具体任务的 `Completed` 事件:
|
||||
|
||||
```csharp
|
||||
var operation = package.LoadAssetAsync<GameObject>(location);
|
||||
operation.Completed += op =>
|
||||
{
|
||||
// TODO : 根据 op.Status 判断成功/失败
|
||||
};
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 异步编程模式
|
||||
|
||||
### 1. 协程模式(IEnumerator)
|
||||
|
||||
```csharp
|
||||
IEnumerator LoadAsset()
|
||||
{
|
||||
var operation = package.LoadAssetAsync<GameObject>("Assets/Prefab.prefab");
|
||||
yield return operation;
|
||||
|
||||
if (operation.Status == EOperationStatus.Succeed)
|
||||
{
|
||||
GameObject prefab = operation.AssetObject as GameObject;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Task 模式(async/await)
|
||||
|
||||
```csharp
|
||||
async Task LoadAssetAsync()
|
||||
{
|
||||
var operation = package.LoadAssetAsync<GameObject>("Assets/Prefab.prefab");
|
||||
await operation.Task;
|
||||
|
||||
if (operation.Status == EOperationStatus.Succeed)
|
||||
{
|
||||
GameObject prefab = operation.AssetObject as GameObject;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3. 回调模式(Completed 事件)
|
||||
|
||||
```csharp
|
||||
void LoadAsset()
|
||||
{
|
||||
var operation = package.LoadAssetAsync<GameObject>("Assets/Prefab.prefab");
|
||||
operation.Completed += OnLoadCompleted;
|
||||
}
|
||||
|
||||
void OnLoadCompleted(AsyncOperationBase op)
|
||||
{
|
||||
var operation = op as AssetHandle;
|
||||
if (operation.Status == EOperationStatus.Succeed)
|
||||
{
|
||||
GameObject prefab = operation.AssetObject as GameObject;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 4. 同步等待模式
|
||||
|
||||
```csharp
|
||||
void LoadAssetSync()
|
||||
{
|
||||
var operation = package.LoadAssetAsync<GameObject>("Assets/Prefab.prefab");
|
||||
operation.WaitForAsyncComplete(); // 阻塞等待完成
|
||||
|
||||
if (operation.Status == EOperationStatus.Succeed)
|
||||
{
|
||||
GameObject prefab = operation.AssetObject as GameObject;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 调度机制
|
||||
|
||||
### 优先级调度
|
||||
|
||||
操作按 `Priority` 属性降序排列,优先级高的操作先执行。
|
||||
|
||||
#### 操作优先级
|
||||
|
||||
```csharp
|
||||
var operation = package.LoadAssetAsync<GameObject>(location);
|
||||
operation.Priority = 100; // 设置高优先级
|
||||
```
|
||||
|
||||
#### 包裹优先级
|
||||
|
||||
通过 `ResourcePackage.PackagePriority` 可以设置包裹的调度器优先级,值越大越优先更新。
|
||||
|
||||
```csharp
|
||||
// 创建包裹时指定优先级
|
||||
var package = YooAssets.CreatePackage("MyPackage", 100);
|
||||
|
||||
// 运行时动态调整优先级
|
||||
package.PackagePriority = 200;
|
||||
|
||||
// 获取当前优先级
|
||||
uint priority = package.PackagePriority;
|
||||
```
|
||||
|
||||
**使用场景:**
|
||||
- 多包裹场景下,可根据游戏状态动态调整包裹优先级
|
||||
- 例如:进入战斗时提高战斗资源包的优先级,退出战斗时恢复默认优先级
|
||||
|
||||
**排序规则:**
|
||||
- 新操作添加时:若新增队列存在非零优先级,则触发排序
|
||||
- 运行中修改 `Priority`:调度器会在每帧 `Update()` 的排序阶段检测 `IsDirty` 并触发重排;若在某个操作的 `InternalUpdate()` 内修改(本帧排序已完成),则新的优先级会延后一帧生效(可能与预期不符)
|
||||
- 若期望本帧生效:请尽量在任务入队前或本帧调度器 `Update()` 开始前设置 `Priority`,避免在 `InternalUpdate()` 内临时调整
|
||||
- 排序使用 `List.Sort()` 进行原地排序;频繁修改优先级会带来额外排序开销,建议按需使用
|
||||
|
||||
### 时间切片
|
||||
|
||||
通过 `MaxTimeSlice` 控制每帧最大执行时间,防止主线程阻塞。
|
||||
|
||||
```csharp
|
||||
// 设置每帧最多执行 8 毫秒
|
||||
YooAssets.SetOperationSystemMaxTimeSlice(16);
|
||||
```
|
||||
|
||||
**操作侧协作建议:**
|
||||
- 在操作的 `InternalUpdate()` 中使用 `IsBusy`(`AsyncOperationBase` 的内部属性)进行“自愿让出”,将重任务拆分到多帧执行。
|
||||
- 在同步等待(`WaitForAsyncComplete()`)阶段,`IsBusy` 会强制返回 `false`,以保证同步等待推进;此时需要自行评估卡顿风险。
|
||||
|
||||
**执行流程:**
|
||||
|
||||
```
|
||||
每帧 Update()
|
||||
│
|
||||
├── 记录帧开始时间 _frameTime
|
||||
│
|
||||
└── 遍历操作队列
|
||||
│
|
||||
├── 检查 IsBusy(是否超时)
|
||||
│ │
|
||||
│ └── 超时则中断本帧
|
||||
│
|
||||
└── 执行 operation.UpdateOperation()
|
||||
```
|
||||
|
||||
### 操作生命周期
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ 操作生命周期 │
|
||||
├─────────────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ 1. 创建操作 │
|
||||
│ └── Status = None │
|
||||
│ │
|
||||
│ 2. StartOperation() │
|
||||
│ ├── Status = Processing │
|
||||
│ ├── DebugBeginRecording() │
|
||||
│ ├── InternalStart() │
|
||||
│ └── 添加到 _newList │
|
||||
│ │
|
||||
│ 3. Update() - 每帧调度 │
|
||||
│ ├── 移除已完成操作 │
|
||||
│ ├── 合并 _newList 到 _operations │
|
||||
│ ├── 按优先级排序(如需要) │
|
||||
│ └── 遍历执行 UpdateOperation() │
|
||||
│ │
|
||||
│ 4. UpdateOperation() │
|
||||
│ ├── DebugUpdateRecording() │
|
||||
│ ├── InternalUpdate() │
|
||||
│ └── 检查 IsDone │
|
||||
│ │ │
|
||||
│ └── 完成时: │
|
||||
│ ├── IsFinish = true │
|
||||
│ ├── Progress = 1f │
|
||||
│ ├── DebugEndRecording() │
|
||||
│ ├── 触发 Completed 回调 │
|
||||
│ └── 设置 TaskCompletionSource │
|
||||
│ │
|
||||
│ 5. 下一帧移除完成的操作 │
|
||||
│ │
|
||||
└─────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 调试支持
|
||||
|
||||
### 调试信息结构
|
||||
|
||||
```csharp
|
||||
[Serializable]
|
||||
internal struct DebugOperationInfo
|
||||
{
|
||||
public string OperationName; // 任务名称
|
||||
public string OperationDesc; // 任务说明
|
||||
public uint Priority; // 优先级
|
||||
public float Progress; // 任务进度
|
||||
public string BeginTime; // 任务开始的时间
|
||||
public long ProcessTime; // 处理耗时(单位:毫秒)
|
||||
public string Status; // 任务状态
|
||||
public List<DebugOperationInfo> Childs; // 子任务列表(注意:JsonUtility 序列化深度限制)
|
||||
}
|
||||
```
|
||||
|
||||
> 说明:该结构体真实定义位于 `Runtime/DiagnosticSystem/DebugOperationInfo.cs`,这里仅展示关键字段以便理解。
|
||||
|
||||
### 获取调试信息
|
||||
|
||||
```csharp
|
||||
// 获取指定包裹的所有操作信息(内部调试接口)
|
||||
// packageName 不允许为空;全局调度器请使用 OperationSystem.GlobalSchedulerName(内部)
|
||||
// 非全局包裹需先 YooAssets.CreatePackage(packageName)
|
||||
var infos = OperationSystem.GetDebugOperationInfos(OperationSystem.GlobalSchedulerName);
|
||||
|
||||
foreach (var info in infos)
|
||||
{
|
||||
Debug.Log($"{info.OperationName}: {info.Status}, {info.ProcessTime}ms");
|
||||
}
|
||||
```
|
||||
|
||||
### 耗时统计
|
||||
|
||||
在 DEBUG 模式下自动统计操作耗时:
|
||||
|
||||
```csharp
|
||||
// 操作完成后可获取耗时
|
||||
Debug.Log($"开始时间: {operation.BeginTime}");
|
||||
Debug.Log($"处理耗时: {operation.ProcessTime}ms");
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 设计模式
|
||||
|
||||
### 模板方法模式
|
||||
|
||||
`AsyncOperationBase` 定义算法骨架,子类实现具体步骤:
|
||||
|
||||
```
|
||||
AsyncOperationBase
|
||||
│
|
||||
├── StartOperation() ──► InternalStart() [子类实现]
|
||||
├── UpdateOperation() ──► InternalUpdate() [子类实现]
|
||||
├── AbortOperation() ──► InternalAbort() [子类实现]
|
||||
└── WaitForAsyncComplete() ──► InternalWaitForAsyncComplete() [子类实现]
|
||||
```
|
||||
|
||||
### 状态机模式
|
||||
|
||||
操作状态由 `EOperationStatus` 管理:
|
||||
|
||||
```
|
||||
┌──────┐ StartOperation() ┌────────────┐ UpdateOperation() ┌─────────┐
|
||||
│ None │ ─────────────────► │ Processing │ ──────────────────► │ Succeed │
|
||||
└──────┘ └────────────┘ └─────────┘
|
||||
│
|
||||
│ UpdateOperation() / AbortOperation()
|
||||
▼
|
||||
┌──────────┐
|
||||
│ Failed │
|
||||
└──────────┘
|
||||
```
|
||||
|
||||
### 组合模式
|
||||
|
||||
通过内部子任务列表支持父子操作关系:
|
||||
|
||||
```
|
||||
ParentOperation
|
||||
├── ChildOperation1
|
||||
├── ChildOperation2
|
||||
└── ChildOperation3
|
||||
└── GrandChildOperation
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 类继承关系
|
||||
|
||||
```
|
||||
IEnumerator + IComparable<AsyncOperationBase>
|
||||
│
|
||||
▼
|
||||
AsyncOperationBase (抽象基类)
|
||||
│
|
||||
└── [YooAsset 内部操作]
|
||||
│
|
||||
├── InitializationOperation
|
||||
├── LoadAssetOperation
|
||||
├── LoadSceneOperation
|
||||
├── DownloadOperation
|
||||
└── ...
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 注意事项
|
||||
|
||||
1. **主线程执行**:所有操作的调度和更新都在 Unity 主线程执行
|
||||
2. **时间切片**:设置合理的 `MaxTimeSlice` 避免卡顿(建议 10-16ms;小于 10ms 会被钳制到 10ms)
|
||||
3. **同步等待**:`WaitForAsyncComplete()` 会阻塞主线程,谨慎使用
|
||||
4. **子任务中止**:父操作中止时会自动中止所有子操作
|
||||
5. **回调异常**:`Completed` 回调中的异常会被捕获并记录,不会中断系统
|
||||
6. **编辑器重置**:编辑器中使用 `RuntimeInitializeOnLoadMethod` 自动重置状态
|
||||
7. **循环保护**:在 `InternalWaitForAsyncComplete()` 中建议使用 `RunBatchExecution()`(默认 1000 次)限制单次推进次数,避免陷入无限循环或长时间占用主线程
|
||||
@@ -1,7 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2afe3d5ffb611b241919112b40d9c7d0
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -51,7 +51,7 @@ namespace YooAsset
|
||||
return;
|
||||
}
|
||||
|
||||
if (IsWaitForAsyncComplete)
|
||||
if (IsWaitingForAsyncComplete)
|
||||
_handle.WaitForAsyncComplete();
|
||||
|
||||
if (_handle.IsDone == false)
|
||||
@@ -95,7 +95,7 @@ namespace YooAsset
|
||||
_instantiateAsync = InstantiateAsyncInternal(_handle.AssetObject, _options);
|
||||
}
|
||||
|
||||
if (IsWaitForAsyncComplete)
|
||||
if (IsWaitingForAsyncComplete)
|
||||
_instantiateAsync.WaitForCompletion();
|
||||
|
||||
if (_instantiateAsync.isDone == false)
|
||||
@@ -132,7 +132,7 @@ namespace YooAsset
|
||||
{
|
||||
RunBatchExecution();
|
||||
}
|
||||
internal override string InternalGetDesc()
|
||||
internal override string InternalGetDescription()
|
||||
{
|
||||
var assetInfo = _handle.GetAssetInfo();
|
||||
return $"AssetPath : {assetInfo.AssetPath}";
|
||||
|
||||
@@ -67,7 +67,7 @@ namespace YooAsset
|
||||
|
||||
if (_steps == ESteps.CheckConcurrency)
|
||||
{
|
||||
if (IsWaitForAsyncComplete)
|
||||
if (IsWaitingForAsyncComplete)
|
||||
{
|
||||
_steps = ESteps.LoadBundleFile;
|
||||
}
|
||||
@@ -90,7 +90,7 @@ namespace YooAsset
|
||||
AddChildOperation(_loadBundleOp);
|
||||
}
|
||||
|
||||
if (IsWaitForAsyncComplete)
|
||||
if (IsWaitingForAsyncComplete)
|
||||
_loadBundleOp.WaitForAsyncComplete();
|
||||
|
||||
_loadBundleOp.UpdateOperation();
|
||||
@@ -129,7 +129,7 @@ namespace YooAsset
|
||||
{
|
||||
RunBatchExecution();
|
||||
}
|
||||
internal override string InternalGetDesc()
|
||||
internal override string InternalGetDescription()
|
||||
{
|
||||
return $"BundleName : {LoadBundleInfo.Bundle.BundleName}";
|
||||
}
|
||||
|
||||
@@ -110,7 +110,7 @@ namespace YooAsset
|
||||
Status = EOperationStatus.Succeed;
|
||||
}
|
||||
}
|
||||
internal override string InternalGetDesc()
|
||||
internal override string InternalGetDescription()
|
||||
{
|
||||
return $"SceneName : {_provider.SceneName}";
|
||||
}
|
||||
|
||||
@@ -54,7 +54,7 @@ namespace YooAsset
|
||||
{
|
||||
RunBatchExecution();
|
||||
}
|
||||
internal override string InternalGetDesc()
|
||||
internal override string InternalGetDescription()
|
||||
{
|
||||
return $"LoopCount : {_options.LoopCount}";
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ namespace YooAsset
|
||||
#endif
|
||||
}
|
||||
|
||||
if (IsWaitForAsyncComplete)
|
||||
if (IsWaitingForAsyncComplete)
|
||||
_loadAllAssetsOp.WaitForAsyncComplete();
|
||||
|
||||
_loadAllAssetsOp.UpdateOperation();
|
||||
|
||||
@@ -22,7 +22,7 @@ namespace YooAsset
|
||||
#endif
|
||||
}
|
||||
|
||||
if (IsWaitForAsyncComplete)
|
||||
if (IsWaitingForAsyncComplete)
|
||||
_loadAssetOp.WaitForAsyncComplete();
|
||||
|
||||
_loadAssetOp.UpdateOperation();
|
||||
|
||||
@@ -137,7 +137,7 @@ namespace YooAsset
|
||||
|
||||
if (_steps == ESteps.WaitBundleLoader)
|
||||
{
|
||||
if (IsWaitForAsyncComplete)
|
||||
if (IsWaitingForAsyncComplete)
|
||||
{
|
||||
foreach (var bundleLoader in _bundleLoaders)
|
||||
{
|
||||
@@ -185,7 +185,7 @@ namespace YooAsset
|
||||
{
|
||||
RunBatchExecution();
|
||||
}
|
||||
internal override string InternalGetDesc()
|
||||
internal override string InternalGetDescription()
|
||||
{
|
||||
return $"AssetPath : {MainAssetInfo.AssetPath}";
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ namespace YooAsset
|
||||
AddChildOperation(_loadSceneOp);
|
||||
}
|
||||
|
||||
if (IsWaitForAsyncComplete)
|
||||
if (IsWaitingForAsyncComplete)
|
||||
_loadSceneOp.WaitForAsyncComplete();
|
||||
|
||||
// 注意:场景加载中途可以取消挂起
|
||||
|
||||
@@ -22,7 +22,7 @@ namespace YooAsset
|
||||
#endif
|
||||
}
|
||||
|
||||
if (IsWaitForAsyncComplete)
|
||||
if (IsWaitingForAsyncComplete)
|
||||
_loadSubAssetsOp.WaitForAsyncComplete();
|
||||
|
||||
_loadSubAssetsOp.UpdateOperation();
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,7 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 23897062e5e2c98498f4bd00a407dda8
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -426,8 +426,8 @@ namespace YooAsset
|
||||
DiagnosticProviderInfo providerInfo = new DiagnosticProviderInfo();
|
||||
providerInfo.AssetPath = provider.MainAssetInfo.AssetPath;
|
||||
providerInfo.OriginScene = provider.OriginScene;
|
||||
providerInfo.StartTime = provider.BeginTime;
|
||||
providerInfo.ElapsedMS = provider.ProcessTime;
|
||||
providerInfo.StartTime = provider.StartTime;
|
||||
providerInfo.ElapsedMS = provider.ElapsedMS;
|
||||
providerInfo.ReferenceCount = provider.RefCount;
|
||||
providerInfo.Status = provider.Status.ToString();
|
||||
providerInfo.DependentBundles = provider.GetDebugDependBundles();
|
||||
|
||||
@@ -98,7 +98,7 @@ namespace YooAsset
|
||||
}
|
||||
}
|
||||
}
|
||||
internal override string InternalGetDesc()
|
||||
internal override string InternalGetDescription()
|
||||
{
|
||||
return $"ClearMode : {_options.ClearMode}";
|
||||
}
|
||||
|
||||
@@ -92,13 +92,13 @@ namespace YooAsset
|
||||
|
||||
// 最后清理该包裹的异步任务
|
||||
// 注意:对于有线程操作的异步任务,需要保证线程安全释放。
|
||||
OperationSystem.ClearPackageOperation(_resourcePackage.PackageName);
|
||||
OperationSystem.ClearPackageOperations(_resourcePackage.PackageName);
|
||||
|
||||
_steps = ESteps.Done;
|
||||
Status = EOperationStatus.Succeed;
|
||||
}
|
||||
}
|
||||
internal override string InternalGetDesc()
|
||||
internal override string InternalGetDescription()
|
||||
{
|
||||
return $"PackageVersion : {_resourcePackage.GetPackageVersion()}";
|
||||
}
|
||||
|
||||
@@ -181,7 +181,7 @@ namespace YooAsset
|
||||
}
|
||||
}
|
||||
}
|
||||
internal override string InternalGetDesc()
|
||||
internal override string InternalGetDescription()
|
||||
{
|
||||
return $"PlayMode : {_playMode}";
|
||||
}
|
||||
|
||||
@@ -87,7 +87,7 @@ namespace YooAsset
|
||||
}
|
||||
}
|
||||
}
|
||||
internal override string InternalGetDesc()
|
||||
internal override string InternalGetDescription()
|
||||
{
|
||||
return $"PackageVersion : {_options.PackageVersion}";
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -44,7 +44,7 @@ public class TestLoadAsset
|
||||
{
|
||||
Assert.AreEqual(loadFrame, Time.frameCount);
|
||||
};
|
||||
Assert.AreEqual(true, assetHandle.Provider.IsFinish);
|
||||
Assert.AreEqual(true, assetHandle.Provider.IsFinished);
|
||||
Assert.AreEqual(EOperationStatus.Succeed, assetHandle.Status);
|
||||
|
||||
var audioClip = assetHandle.AssetObject as AudioClip;
|
||||
|
||||
Reference in New Issue
Block a user