mirror of
https://github.com/tuyoogame/YooAsset.git
synced 2026-05-29 20:48:47 +00:00
refactor : 重构代码
This commit is contained in:
@@ -125,13 +125,13 @@ namespace YooAsset.Editor
|
|||||||
_providerTableView.AddColumn(column);
|
_providerTableView.AddColumn(column);
|
||||||
}
|
}
|
||||||
|
|
||||||
// BeginTime
|
// StartTime
|
||||||
{
|
{
|
||||||
var columnStyle = new ColumnStyle(100);
|
var columnStyle = new ColumnStyle(100);
|
||||||
columnStyle.Stretchable = false;
|
columnStyle.Stretchable = false;
|
||||||
columnStyle.Searchable = false;
|
columnStyle.Searchable = false;
|
||||||
columnStyle.Sortable = true;
|
columnStyle.Sortable = true;
|
||||||
var column = new TableColumn("BeginTime", "Begin Time", columnStyle);
|
var column = new TableColumn("StartTime", "Start Time", columnStyle);
|
||||||
column.MakeCell = () =>
|
column.MakeCell = () =>
|
||||||
{
|
{
|
||||||
var label = new Label();
|
var label = new Label();
|
||||||
@@ -314,7 +314,7 @@ namespace YooAsset.Editor
|
|||||||
rowData.AddAssetPathCell("PackageName", packageData.PackageName);
|
rowData.AddAssetPathCell("PackageName", packageData.PackageName);
|
||||||
rowData.AddStringValueCell("AssetPath", providerInfo.AssetPath);
|
rowData.AddStringValueCell("AssetPath", providerInfo.AssetPath);
|
||||||
rowData.AddStringValueCell("SpawnScene", providerInfo.OriginScene);
|
rowData.AddStringValueCell("SpawnScene", providerInfo.OriginScene);
|
||||||
rowData.AddStringValueCell("BeginTime", providerInfo.StartTime);
|
rowData.AddStringValueCell("StartTime", providerInfo.StartTime);
|
||||||
rowData.AddLongValueCell("LoadingTime", providerInfo.ElapsedMS);
|
rowData.AddLongValueCell("LoadingTime", providerInfo.ElapsedMS);
|
||||||
rowData.AddLongValueCell("RefCount", providerInfo.ReferenceCount);
|
rowData.AddLongValueCell("RefCount", providerInfo.ReferenceCount);
|
||||||
rowData.AddStringValueCell("Status", providerInfo.Status.ToString());
|
rowData.AddStringValueCell("Status", providerInfo.Status.ToString());
|
||||||
|
|||||||
@@ -208,13 +208,13 @@ namespace YooAsset.Editor
|
|||||||
_usingTableView.AddColumn(column);
|
_usingTableView.AddColumn(column);
|
||||||
}
|
}
|
||||||
|
|
||||||
// BeginTime
|
// StartTime
|
||||||
{
|
{
|
||||||
var columnStyle = new ColumnStyle(100);
|
var columnStyle = new ColumnStyle(100);
|
||||||
columnStyle.Stretchable = false;
|
columnStyle.Stretchable = false;
|
||||||
columnStyle.Searchable = false;
|
columnStyle.Searchable = false;
|
||||||
columnStyle.Sortable = true;
|
columnStyle.Sortable = true;
|
||||||
var column = new TableColumn("BeginTime", "Begin Time", columnStyle);
|
var column = new TableColumn("StartTime", "Start Time", columnStyle);
|
||||||
column.MakeCell = () =>
|
column.MakeCell = () =>
|
||||||
{
|
{
|
||||||
var label = new Label();
|
var label = new Label();
|
||||||
@@ -451,7 +451,7 @@ namespace YooAsset.Editor
|
|||||||
rowData.ProviderInfo = providerInfo;
|
rowData.ProviderInfo = providerInfo;
|
||||||
rowData.AddStringValueCell("UsingAssets", providerInfo.AssetPath);
|
rowData.AddStringValueCell("UsingAssets", providerInfo.AssetPath);
|
||||||
rowData.AddStringValueCell("SpawnScene", providerInfo.OriginScene);
|
rowData.AddStringValueCell("SpawnScene", providerInfo.OriginScene);
|
||||||
rowData.AddStringValueCell("BeginTime", providerInfo.StartTime);
|
rowData.AddStringValueCell("StartTime", providerInfo.StartTime);
|
||||||
rowData.AddLongValueCell("RefCount", providerInfo.ReferenceCount);
|
rowData.AddLongValueCell("RefCount", providerInfo.ReferenceCount);
|
||||||
rowData.AddStringValueCell("Status", providerInfo.Status);
|
rowData.AddStringValueCell("Status", providerInfo.Status);
|
||||||
sourceDatas.Add(rowData);
|
sourceDatas.Add(rowData);
|
||||||
|
|||||||
@@ -147,13 +147,13 @@ namespace YooAsset.Editor
|
|||||||
_operationTableView.AddColumn(column);
|
_operationTableView.AddColumn(column);
|
||||||
}
|
}
|
||||||
|
|
||||||
// BeginTime
|
// StartTime
|
||||||
{
|
{
|
||||||
var columnStyle = new ColumnStyle(100);
|
var columnStyle = new ColumnStyle(100);
|
||||||
columnStyle.Stretchable = false;
|
columnStyle.Stretchable = false;
|
||||||
columnStyle.Searchable = false;
|
columnStyle.Searchable = false;
|
||||||
columnStyle.Sortable = true;
|
columnStyle.Sortable = true;
|
||||||
var column = new TableColumn("BeginTime", "Begin Time", columnStyle);
|
var column = new TableColumn("StartTime", "Start Time", columnStyle);
|
||||||
column.MakeCell = () =>
|
column.MakeCell = () =>
|
||||||
{
|
{
|
||||||
var label = new Label();
|
var label = new Label();
|
||||||
@@ -168,14 +168,14 @@ namespace YooAsset.Editor
|
|||||||
_operationTableView.AddColumn(column);
|
_operationTableView.AddColumn(column);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ProcessTime
|
// ElapsedMS
|
||||||
{
|
{
|
||||||
var columnStyle = new ColumnStyle(130);
|
var columnStyle = new ColumnStyle(130);
|
||||||
columnStyle.Stretchable = false;
|
columnStyle.Stretchable = false;
|
||||||
columnStyle.Searchable = false;
|
columnStyle.Searchable = false;
|
||||||
columnStyle.Sortable = true;
|
columnStyle.Sortable = true;
|
||||||
columnStyle.Units = "ms";
|
columnStyle.Units = "ms";
|
||||||
var column = new TableColumn("ProcessTime", "Process Time", columnStyle);
|
var column = new TableColumn("ElapsedMS", "Elapsed MS", columnStyle);
|
||||||
column.MakeCell = () =>
|
column.MakeCell = () =>
|
||||||
{
|
{
|
||||||
var label = new Label();
|
var label = new Label();
|
||||||
@@ -259,19 +259,19 @@ namespace YooAsset.Editor
|
|||||||
_bottomToolbar.Add(button);
|
_bottomToolbar.Add(button);
|
||||||
}
|
}
|
||||||
|
|
||||||
// BeginTime
|
// StartTime
|
||||||
{
|
{
|
||||||
ToolbarButton button = new ToolbarButton();
|
ToolbarButton button = new ToolbarButton();
|
||||||
button.text = "BeginTime";
|
button.text = "StartTime";
|
||||||
button.style.flexGrow = 0;
|
button.style.flexGrow = 0;
|
||||||
button.style.width = 100;
|
button.style.width = 100;
|
||||||
_bottomToolbar.Add(button);
|
_bottomToolbar.Add(button);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ProcessTime
|
// ElapsedMS
|
||||||
{
|
{
|
||||||
ToolbarButton button = new ToolbarButton();
|
ToolbarButton button = new ToolbarButton();
|
||||||
button.text = "ProcessTime (ms)";
|
button.text = "ElapsedMS";
|
||||||
button.style.flexGrow = 0;
|
button.style.flexGrow = 0;
|
||||||
button.style.width = 130;
|
button.style.width = 130;
|
||||||
_bottomToolbar.Add(button);
|
_bottomToolbar.Add(button);
|
||||||
@@ -319,8 +319,8 @@ namespace YooAsset.Editor
|
|||||||
rowData.AddStringValueCell("OperationName", operationInfo.OperationName);
|
rowData.AddStringValueCell("OperationName", operationInfo.OperationName);
|
||||||
rowData.AddLongValueCell("Priority", operationInfo.Priority);
|
rowData.AddLongValueCell("Priority", operationInfo.Priority);
|
||||||
rowData.AddDoubleValueCell("Progress", operationInfo.Progress);
|
rowData.AddDoubleValueCell("Progress", operationInfo.Progress);
|
||||||
rowData.AddStringValueCell("BeginTime", operationInfo.StartTime);
|
rowData.AddStringValueCell("StartTime", operationInfo.StartTime);
|
||||||
rowData.AddLongValueCell("LoadingTime", operationInfo.ElapsedMS);
|
rowData.AddLongValueCell("ElapsedMS", operationInfo.ElapsedMS);
|
||||||
rowData.AddStringValueCell("Status", operationInfo.Status.ToString());
|
rowData.AddStringValueCell("Status", operationInfo.Status.ToString());
|
||||||
rowData.AddStringValueCell("Desc", operationInfo.OperationDesc);
|
rowData.AddStringValueCell("Desc", operationInfo.OperationDesc);
|
||||||
_sourceDatas.Add(rowData);
|
_sourceDatas.Add(rowData);
|
||||||
@@ -408,20 +408,20 @@ namespace YooAsset.Editor
|
|||||||
container.Add(label);
|
container.Add(label);
|
||||||
}
|
}
|
||||||
|
|
||||||
// BeginTime
|
// StartTime
|
||||||
{
|
{
|
||||||
var label = new Label();
|
var label = new Label();
|
||||||
label.name = "BeginTime";
|
label.name = "StartTime";
|
||||||
label.style.flexGrow = 0f;
|
label.style.flexGrow = 0f;
|
||||||
label.style.width = 100;
|
label.style.width = 100;
|
||||||
label.style.unityTextAlign = TextAnchor.MiddleLeft;
|
label.style.unityTextAlign = TextAnchor.MiddleLeft;
|
||||||
container.Add(label);
|
container.Add(label);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ProcessTime
|
// ElapsedMS
|
||||||
{
|
{
|
||||||
var label = new Label();
|
var label = new Label();
|
||||||
label.name = "ProcessTime";
|
label.name = "ElapsedMS";
|
||||||
label.style.flexGrow = 0f;
|
label.style.flexGrow = 0f;
|
||||||
label.style.width = 130;
|
label.style.width = 130;
|
||||||
label.style.unityTextAlign = TextAnchor.MiddleLeft;
|
label.style.unityTextAlign = TextAnchor.MiddleLeft;
|
||||||
@@ -464,15 +464,15 @@ namespace YooAsset.Editor
|
|||||||
label.text = operationInfo.Progress.ToString();
|
label.text = operationInfo.Progress.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
// BeginTime
|
// StartTime
|
||||||
{
|
{
|
||||||
var label = container.Q<Label>("BeginTime");
|
var label = container.Q<Label>("StartTime");
|
||||||
label.text = operationInfo.StartTime;
|
label.text = operationInfo.StartTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ProcessTime
|
// ElapsedMS
|
||||||
{
|
{
|
||||||
var label = container.Q<Label>("ProcessTime");
|
var label = container.Q<Label>("ElapsedMS");
|
||||||
label.text = operationInfo.ElapsedMS.ToString();
|
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
|
fileFormatVersion: 2
|
||||||
guid: 0ee8a6b68676976428b1886c273eaeb6
|
guid: 5fa2b66c20800124c8dd5cb77e854ce3
|
||||||
TextScriptImporter:
|
TextScriptImporter:
|
||||||
externalObjects: {}
|
externalObjects: {}
|
||||||
userData:
|
userData:
|
||||||
@@ -144,7 +144,7 @@ internal interface IDownloadRequest : IDisposable
|
|||||||
string URL { get; }
|
string URL { get; }
|
||||||
|
|
||||||
// 生命周期
|
// 生命周期
|
||||||
bool IsDone { get; } // 每次访问自动轮询
|
bool IsDone { get; } // 访问时自动调用 PollingRequest()
|
||||||
EDownloadRequestStatus Status { get; }
|
EDownloadRequestStatus Status { get; }
|
||||||
|
|
||||||
// 进度跟踪
|
// 进度跟踪
|
||||||
@@ -561,20 +561,25 @@ SimulateRequestFile (独立实现) ──► IDownloadFileRequest
|
|||||||
|
|
||||||
### DownloadSystemTools
|
### DownloadSystemTools
|
||||||
|
|
||||||
提供跨平台的工具函数:
|
提供跨平台的 URL 转换和判断功能:
|
||||||
|
|
||||||
| 方法 | 说明 |
|
| 方法 | 参数 | 返回值 | 说明 |
|
||||||
|------|------|
|
|------|------|--------|------|
|
||||||
| `ToLocalURL()` | 转换本地路径为文件协议 URL |
|
| `ToLocalURL(path)` | `string path` 本地文件路径 | 可用于 UnityWebRequest 的文件协议 URL | 转换本地路径为文件协议 URL(自动处理特殊字符) |
|
||||||
| `IsLocalFileURL()` | 判断是否本地文件 URL |
|
| `IsLocalFileURL(url)` | `string url` 要判断的 URL | `bool` 是否为本地文件 URL | 判断 URL 是否为 `file:` 或 `jar:file:` 协议 |
|
||||||
|
|
||||||
### DownloadFailureCounter
|
### DownloadFailureCounter
|
||||||
|
|
||||||
请求失败计数器,用于诊断统计:
|
网络请求失败计数器(诊断用):
|
||||||
|
|
||||||
- 线程安全:内部使用 `Dictionary` 且未加锁,约定只在主线程调用;如需多线程统计请在外层加锁或改造实现
|
- **线程安全**:内部使用 `Dictionary` 且未加锁,约定只在 Unity 主线程调用;如需在多线程/回调线程调用,请在外层加锁或改为并发容器实现
|
||||||
- Key 规则:`$"{packageName}_{eventName}"`
|
- **Key 格式**:`$"{packageName}_{eventName}"`
|
||||||
- 统计口径:**仅统计网络请求失败**(`IDownloadRequest.Status != Succeed` 时记录),不统计内容为空、校验失败、解析失败等业务层失败
|
- **统计口径**:**仅统计网络请求失败**(`IDownloadRequest.Status != Succeed` 时记录),不统计内容为空、校验失败、解析失败等业务层失败
|
||||||
|
|
||||||
|
| 方法 | 参数 | 返回值 | 说明 |
|
||||||
|
|------|------|--------|------|
|
||||||
|
| `RecordFailure(packageName, eventName)` | `string packageName` 资源包名称, `string eventName` 事件名称 | `void` | 记录一次失败 |
|
||||||
|
| `GetFailureCount(packageName, eventName)` | `string packageName` 资源包名称, `string eventName` 事件名称 | `int` 失败次数(未记录过返回 0) | 获取失败次数 |
|
||||||
|
|
||||||
```csharp
|
```csharp
|
||||||
// 记录失败
|
// 记录失败
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ namespace YooAsset
|
|||||||
|
|
||||||
if (_steps == ESteps.LoadAsset)
|
if (_steps == ESteps.LoadAsset)
|
||||||
{
|
{
|
||||||
if (IsWaitForAsyncComplete)
|
if (IsWaitingForAsyncComplete)
|
||||||
{
|
{
|
||||||
if (_assetInfo.AssetType == null)
|
if (_assetInfo.AssetType == null)
|
||||||
Result = _assetBundle.LoadAllAssets();
|
Result = _assetBundle.LoadAllAssets();
|
||||||
@@ -71,7 +71,7 @@ namespace YooAsset
|
|||||||
{
|
{
|
||||||
if (_request != null)
|
if (_request != null)
|
||||||
{
|
{
|
||||||
if (IsWaitForAsyncComplete)
|
if (IsWaitingForAsyncComplete)
|
||||||
{
|
{
|
||||||
// 强制挂起主线程(注意:该操作会很耗时)
|
// 强制挂起主线程(注意:该操作会很耗时)
|
||||||
YooLogger.Warning("Suspend the main thread to load unity asset.");
|
YooLogger.Warning("Suspend the main thread to load unity asset.");
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ namespace YooAsset
|
|||||||
|
|
||||||
if (_steps == ESteps.LoadAsset)
|
if (_steps == ESteps.LoadAsset)
|
||||||
{
|
{
|
||||||
if (IsWaitForAsyncComplete)
|
if (IsWaitingForAsyncComplete)
|
||||||
{
|
{
|
||||||
if (_assetInfo.AssetType == null)
|
if (_assetInfo.AssetType == null)
|
||||||
Result = _assetBundle.LoadAsset(_assetInfo.AssetPath);
|
Result = _assetBundle.LoadAsset(_assetInfo.AssetPath);
|
||||||
@@ -71,7 +71,7 @@ namespace YooAsset
|
|||||||
{
|
{
|
||||||
if (_request != null)
|
if (_request != null)
|
||||||
{
|
{
|
||||||
if (IsWaitForAsyncComplete)
|
if (IsWaitingForAsyncComplete)
|
||||||
{
|
{
|
||||||
// 强制挂起主线程(注意:该操作会很耗时)
|
// 强制挂起主线程(注意:该操作会很耗时)
|
||||||
YooLogger.Warning("Suspend the main thread to load unity asset.");
|
YooLogger.Warning("Suspend the main thread to load unity asset.");
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ namespace YooAsset
|
|||||||
|
|
||||||
if (_steps == ESteps.LoadScene)
|
if (_steps == ESteps.LoadScene)
|
||||||
{
|
{
|
||||||
if (IsWaitForAsyncComplete)
|
if (IsWaitingForAsyncComplete)
|
||||||
{
|
{
|
||||||
// 注意:场景同步加载方法不会立即加载场景,而是在下一帧加载。
|
// 注意:场景同步加载方法不会立即加载场景,而是在下一帧加载。
|
||||||
Result = SceneManager.LoadScene(_assetInfo.AssetPath, _loadParams);
|
Result = SceneManager.LoadScene(_assetInfo.AssetPath, _loadParams);
|
||||||
@@ -69,7 +69,7 @@ namespace YooAsset
|
|||||||
{
|
{
|
||||||
if (_asyncOperation != null)
|
if (_asyncOperation != null)
|
||||||
{
|
{
|
||||||
if (IsWaitForAsyncComplete)
|
if (IsWaitingForAsyncComplete)
|
||||||
{
|
{
|
||||||
//注意:场景加载无法强制异步转同步
|
//注意:场景加载无法强制异步转同步
|
||||||
YooLogger.Error("The scene is loading asyn.");
|
YooLogger.Error("The scene is loading asyn.");
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ namespace YooAsset
|
|||||||
|
|
||||||
if (_steps == ESteps.LoadAsset)
|
if (_steps == ESteps.LoadAsset)
|
||||||
{
|
{
|
||||||
if (IsWaitForAsyncComplete)
|
if (IsWaitingForAsyncComplete)
|
||||||
{
|
{
|
||||||
if (_assetInfo.AssetType == null)
|
if (_assetInfo.AssetType == null)
|
||||||
Result = _assetBundle.LoadAssetWithSubAssets(_assetInfo.AssetPath);
|
Result = _assetBundle.LoadAssetWithSubAssets(_assetInfo.AssetPath);
|
||||||
@@ -71,7 +71,7 @@ namespace YooAsset
|
|||||||
{
|
{
|
||||||
if (_request != null)
|
if (_request != null)
|
||||||
{
|
{
|
||||||
if (IsWaitForAsyncComplete)
|
if (IsWaitingForAsyncComplete)
|
||||||
{
|
{
|
||||||
// 强制挂起主线程(注意:该操作会很耗时)
|
// 强制挂起主线程(注意:该操作会很耗时)
|
||||||
YooLogger.Warning("Suspend the main thread to load unity asset.");
|
YooLogger.Warning("Suspend the main thread to load unity asset.");
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ namespace YooAsset
|
|||||||
|
|
||||||
if (_steps == ESteps.LoadScene)
|
if (_steps == ESteps.LoadScene)
|
||||||
{
|
{
|
||||||
if (IsWaitForAsyncComplete)
|
if (IsWaitingForAsyncComplete)
|
||||||
{
|
{
|
||||||
Result = UnityEditor.SceneManagement.EditorSceneManager.LoadSceneInPlayMode(_assetInfo.AssetPath, _loadParams);
|
Result = UnityEditor.SceneManagement.EditorSceneManager.LoadSceneInPlayMode(_assetInfo.AssetPath, _loadParams);
|
||||||
_steps = ESteps.CheckResult;
|
_steps = ESteps.CheckResult;
|
||||||
@@ -74,7 +74,7 @@ namespace YooAsset
|
|||||||
{
|
{
|
||||||
if (_asyncOperation != null)
|
if (_asyncOperation != null)
|
||||||
{
|
{
|
||||||
if (IsWaitForAsyncComplete)
|
if (IsWaitingForAsyncComplete)
|
||||||
{
|
{
|
||||||
// 注意:场景加载无法强制异步转同步
|
// 注意:场景加载无法强制异步转同步
|
||||||
YooLogger.Error("The scene is loading asyn.");
|
YooLogger.Error("The scene is loading asyn.");
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ namespace YooAsset
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IsWaitForAsyncComplete)
|
if (IsWaitingForAsyncComplete)
|
||||||
{
|
{
|
||||||
if (_bundle.Encrypted)
|
if (_bundle.Encrypted)
|
||||||
{
|
{
|
||||||
@@ -90,7 +90,7 @@ namespace YooAsset
|
|||||||
{
|
{
|
||||||
if (_createRequest != null)
|
if (_createRequest != null)
|
||||||
{
|
{
|
||||||
if (IsWaitForAsyncComplete)
|
if (IsWaitingForAsyncComplete)
|
||||||
{
|
{
|
||||||
// 强制挂起主线程(注意:该操作会很耗时)
|
// 强制挂起主线程(注意:该操作会很耗时)
|
||||||
YooLogger.Warning("Suspend the main thread to load unity bundle.");
|
YooLogger.Warning("Suspend the main thread to load unity bundle.");
|
||||||
@@ -253,7 +253,7 @@ namespace YooAsset
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IsWaitForAsyncComplete)
|
if (IsWaitingForAsyncComplete)
|
||||||
{
|
{
|
||||||
if (_bundle.Encrypted)
|
if (_bundle.Encrypted)
|
||||||
{
|
{
|
||||||
@@ -289,7 +289,7 @@ namespace YooAsset
|
|||||||
{
|
{
|
||||||
if (_createRequest != null)
|
if (_createRequest != null)
|
||||||
{
|
{
|
||||||
if (IsWaitForAsyncComplete)
|
if (IsWaitingForAsyncComplete)
|
||||||
{
|
{
|
||||||
// 强制挂起主线程(注意:该操作会很耗时)
|
// 强制挂起主线程(注意:该操作会很耗时)
|
||||||
YooLogger.Warning("Suspend the main thread to load unity bundle.");
|
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}";
|
return $"PackageVersion : {_packageVersion} PackageHash : {_packageHash}";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -85,7 +85,7 @@ namespace YooAsset
|
|||||||
AddChildOperation(_downloadFileOp);
|
AddChildOperation(_downloadFileOp);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IsWaitForAsyncComplete)
|
if (IsWaitingForAsyncComplete)
|
||||||
_downloadFileOp.WaitForAsyncComplete();
|
_downloadFileOp.WaitForAsyncComplete();
|
||||||
|
|
||||||
_downloadFileOp.UpdateOperation();
|
_downloadFileOp.UpdateOperation();
|
||||||
@@ -110,7 +110,7 @@ namespace YooAsset
|
|||||||
{
|
{
|
||||||
if (_downloadFileOp != null)
|
if (_downloadFileOp != null)
|
||||||
{
|
{
|
||||||
if (IsWaitForAsyncComplete)
|
if (IsWaitingForAsyncComplete)
|
||||||
_downloadFileOp.WaitForAsyncComplete();
|
_downloadFileOp.WaitForAsyncComplete();
|
||||||
|
|
||||||
_downloadFileOp.UpdateOperation();
|
_downloadFileOp.UpdateOperation();
|
||||||
@@ -137,7 +137,7 @@ namespace YooAsset
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IsWaitForAsyncComplete)
|
if (IsWaitingForAsyncComplete)
|
||||||
{
|
{
|
||||||
if (_bundle.Encrypted)
|
if (_bundle.Encrypted)
|
||||||
{
|
{
|
||||||
@@ -173,7 +173,7 @@ namespace YooAsset
|
|||||||
{
|
{
|
||||||
if (_createRequest != null)
|
if (_createRequest != null)
|
||||||
{
|
{
|
||||||
if (IsWaitForAsyncComplete)
|
if (IsWaitingForAsyncComplete)
|
||||||
{
|
{
|
||||||
// 强制挂起主线程(注意:该操作会很耗时)
|
// 强制挂起主线程(注意:该操作会很耗时)
|
||||||
YooLogger.Warning("Suspend the main thread to load unity bundle.");
|
YooLogger.Warning("Suspend the main thread to load unity bundle.");
|
||||||
@@ -354,7 +354,7 @@ namespace YooAsset
|
|||||||
AddChildOperation(_downloadFileOp);
|
AddChildOperation(_downloadFileOp);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IsWaitForAsyncComplete)
|
if (IsWaitingForAsyncComplete)
|
||||||
_downloadFileOp.WaitForAsyncComplete();
|
_downloadFileOp.WaitForAsyncComplete();
|
||||||
|
|
||||||
_downloadFileOp.UpdateOperation();
|
_downloadFileOp.UpdateOperation();
|
||||||
@@ -379,7 +379,7 @@ namespace YooAsset
|
|||||||
{
|
{
|
||||||
if (_downloadFileOp != null)
|
if (_downloadFileOp != null)
|
||||||
{
|
{
|
||||||
if (IsWaitForAsyncComplete)
|
if (IsWaitingForAsyncComplete)
|
||||||
_downloadFileOp.WaitForAsyncComplete();
|
_downloadFileOp.WaitForAsyncComplete();
|
||||||
|
|
||||||
_downloadFileOp.UpdateOperation();
|
_downloadFileOp.UpdateOperation();
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ namespace YooAsset
|
|||||||
// 检测下载结果
|
// 检测下载结果
|
||||||
if (_steps == ESteps.CheckRequest)
|
if (_steps == ESteps.CheckRequest)
|
||||||
{
|
{
|
||||||
if (IsWaitForAsyncComplete)
|
if (IsWaitingForAsyncComplete)
|
||||||
_downloadFileOp.WaitForAsyncComplete();
|
_downloadFileOp.WaitForAsyncComplete();
|
||||||
|
|
||||||
_downloadFileOp.UpdateOperation();
|
_downloadFileOp.UpdateOperation();
|
||||||
@@ -92,7 +92,7 @@ namespace YooAsset
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (IsWaitForAsyncComplete == false && _failedTryAgain > 0)
|
if (IsWaitingForAsyncComplete == false && _failedTryAgain > 0)
|
||||||
{
|
{
|
||||||
_steps = ESteps.TryAgain;
|
_steps = ESteps.TryAgain;
|
||||||
YooLogger.Warning($"Failed download : {_downloadFileOp.URL} Try again.");
|
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}";
|
return $"PackageVersion : {_packageVersion} PackageHash : {_packageHash}";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ namespace YooAsset
|
|||||||
{
|
{
|
||||||
URL = url;
|
URL = url;
|
||||||
}
|
}
|
||||||
internal override string InternalGetDesc()
|
internal override string InternalGetDescription()
|
||||||
{
|
{
|
||||||
return $"RefCount : {RefCount}";
|
return $"RefCount : {RefCount}";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -99,7 +99,7 @@ namespace YooAsset
|
|||||||
if (_steps == ESteps.CheckRequest)
|
if (_steps == ESteps.CheckRequest)
|
||||||
{
|
{
|
||||||
//TODO 更新下载后台,防止无限挂起
|
//TODO 更新下载后台,防止无限挂起
|
||||||
if (IsWaitForAsyncComplete)
|
if (IsWaitingForAsyncComplete)
|
||||||
_fileSystem.DownloadBackend.Update();
|
_fileSystem.DownloadBackend.Update();
|
||||||
|
|
||||||
DownloadProgress = _request.DownloadProgress;
|
DownloadProgress = _request.DownloadProgress;
|
||||||
@@ -135,7 +135,7 @@ namespace YooAsset
|
|||||||
AddChildOperation(_verifyOperation);
|
AddChildOperation(_verifyOperation);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IsWaitForAsyncComplete)
|
if (IsWaitingForAsyncComplete)
|
||||||
_verifyOperation.WaitForAsyncComplete();
|
_verifyOperation.WaitForAsyncComplete();
|
||||||
|
|
||||||
_verifyOperation.UpdateOperation();
|
_verifyOperation.UpdateOperation();
|
||||||
|
|||||||
@@ -98,7 +98,7 @@ namespace YooAsset
|
|||||||
AddChildOperation(_verifyOperation);
|
AddChildOperation(_verifyOperation);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IsWaitForAsyncComplete)
|
if (IsWaitingForAsyncComplete)
|
||||||
_verifyOperation.WaitForAsyncComplete();
|
_verifyOperation.WaitForAsyncComplete();
|
||||||
|
|
||||||
_verifyOperation.UpdateOperation();
|
_verifyOperation.UpdateOperation();
|
||||||
|
|||||||
@@ -113,7 +113,7 @@ namespace YooAsset
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
internal override string InternalGetDesc()
|
internal override string InternalGetDescription()
|
||||||
{
|
{
|
||||||
return $"{_fileSystem.GetType().FullName}";
|
return $"{_fileSystem.GetType().FullName}";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ namespace YooAsset
|
|||||||
AddChildOperation(_downloadFileOp);
|
AddChildOperation(_downloadFileOp);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IsWaitForAsyncComplete)
|
if (IsWaitingForAsyncComplete)
|
||||||
_downloadFileOp.WaitForAsyncComplete();
|
_downloadFileOp.WaitForAsyncComplete();
|
||||||
|
|
||||||
_downloadFileOp.UpdateOperation();
|
_downloadFileOp.UpdateOperation();
|
||||||
@@ -95,7 +95,7 @@ namespace YooAsset
|
|||||||
{
|
{
|
||||||
if (_downloadFileOp != null)
|
if (_downloadFileOp != null)
|
||||||
{
|
{
|
||||||
if (IsWaitForAsyncComplete)
|
if (IsWaitingForAsyncComplete)
|
||||||
_downloadFileOp.WaitForAsyncComplete();
|
_downloadFileOp.WaitForAsyncComplete();
|
||||||
|
|
||||||
_downloadFileOp.UpdateOperation();
|
_downloadFileOp.UpdateOperation();
|
||||||
@@ -110,7 +110,7 @@ namespace YooAsset
|
|||||||
|
|
||||||
if (_steps == ESteps.LoadAssetBundle)
|
if (_steps == ESteps.LoadAssetBundle)
|
||||||
{
|
{
|
||||||
if (IsWaitForAsyncComplete)
|
if (IsWaitingForAsyncComplete)
|
||||||
{
|
{
|
||||||
if (_fileSystem.VirtualWebGLMode)
|
if (_fileSystem.VirtualWebGLMode)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -91,7 +91,7 @@ namespace YooAsset
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (IsWaitForAsyncComplete == false && _failedTryAgain > 0)
|
if (IsWaitingForAsyncComplete == false && _failedTryAgain > 0)
|
||||||
{
|
{
|
||||||
_steps = ESteps.TryAgain;
|
_steps = ESteps.TryAgain;
|
||||||
YooLogger.Warning($"Failed download : {_downloadFileOp.URL} Try again.");
|
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}";
|
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}";
|
return $"PackageVersion : {_packageVersion} PackageHash : {_packageHash}";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -110,7 +110,7 @@ namespace YooAsset
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
internal override string InternalGetDesc()
|
internal override string InternalGetDescription()
|
||||||
{
|
{
|
||||||
return $"PackageVersion : {_packageVersion} PackageHash : {_packageHash}";
|
return $"PackageVersion : {_packageVersion} PackageHash : {_packageHash}";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,16 +6,20 @@ using System.Threading.Tasks;
|
|||||||
|
|
||||||
namespace YooAsset
|
namespace YooAsset
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 异步操作基类,所有异步操作的抽象基类
|
||||||
|
/// 支持协程(IEnumerator)、Task(async/await)、回调等多种异步编程模式
|
||||||
|
/// </summary>
|
||||||
public abstract class AsyncOperationBase : IEnumerator, IComparable<AsyncOperationBase>
|
public abstract class AsyncOperationBase : IEnumerator, IComparable<AsyncOperationBase>
|
||||||
{
|
{
|
||||||
private List<AsyncOperationBase> _childs;
|
private List<AsyncOperationBase> _children;
|
||||||
private Action<AsyncOperationBase> _callback;
|
private Action<AsyncOperationBase> _completedCallbacks;
|
||||||
private uint _priority;
|
private uint _priority;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 等待异步执行完成
|
/// 是否正处于同步等待状态
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal bool IsWaitForAsyncComplete { get; private set; }
|
internal bool IsWaitingForAsyncComplete { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 标记脏(用于调度器检测并重排)
|
/// 标记脏(用于调度器检测并重排)
|
||||||
@@ -23,25 +27,25 @@ namespace YooAsset
|
|||||||
internal bool IsDirty { get; set; }
|
internal bool IsDirty { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 是否已经完成
|
/// 任务是否已结束(已触发回调和Task完成)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal bool IsFinish { get; private set; }
|
internal bool IsFinished { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 异步系统是否繁忙
|
/// 当前帧时间切片是否已用完(同步等待时始终返回false)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal bool IsBusy
|
internal bool IsBusy
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
if (IsWaitForAsyncComplete)
|
if (IsWaitingForAsyncComplete)
|
||||||
return false;
|
return false;
|
||||||
return OperationSystem.IsBusy;
|
return OperationSystem.IsBusy;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 任务优先级
|
/// 任务优先级(值越大越优先执行)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public uint Priority
|
public uint Priority
|
||||||
{
|
{
|
||||||
@@ -74,7 +78,7 @@ namespace YooAsset
|
|||||||
public float Progress { get; protected set; }
|
public float Progress { get; protected set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 是否已经完成
|
/// 任务逻辑是否完成(Status为Succeed或Failed)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool IsDone
|
public bool IsDone
|
||||||
{
|
{
|
||||||
@@ -108,17 +112,17 @@ namespace YooAsset
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_callback += value;
|
_completedCallbacks += value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
remove
|
remove
|
||||||
{
|
{
|
||||||
_callback -= value;
|
_completedCallbacks -= value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 异步操作任务
|
/// 用于 async/await 的 Task 对象
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Task Task
|
public Task Task
|
||||||
{
|
{
|
||||||
@@ -134,16 +138,37 @@ namespace YooAsset
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 内部启动方法(子类必须实现)
|
||||||
|
/// </summary>
|
||||||
internal abstract void InternalStart();
|
internal abstract void InternalStart();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 内部更新方法(子类必须实现)
|
||||||
|
/// </summary>
|
||||||
internal abstract void InternalUpdate();
|
internal abstract void InternalUpdate();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 内部中止方法(子类可选实现)
|
||||||
|
/// </summary>
|
||||||
internal virtual void InternalAbort()
|
internal virtual void InternalAbort()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 内部同步等待方法(子类可选实现)
|
||||||
|
/// 默认抛出异常,如果异步操作需要支持,子类应重写以支持同步等待
|
||||||
|
/// </summary>
|
||||||
internal virtual void InternalWaitForAsyncComplete()
|
internal virtual void InternalWaitForAsyncComplete()
|
||||||
{
|
{
|
||||||
throw new YooInternalException($"InternalWaitForAsyncComplete() not implemented : {this.GetType().Name}");
|
throw new YooInternalException($"InternalWaitForAsyncComplete() not implemented : {this.GetType().Name}");
|
||||||
}
|
}
|
||||||
internal virtual string InternalGetDesc()
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取操作的描述信息(子类可选实现)
|
||||||
|
/// </summary>
|
||||||
|
internal virtual string InternalGetDescription()
|
||||||
{
|
{
|
||||||
return string.Empty;
|
return string.Empty;
|
||||||
}
|
}
|
||||||
@@ -153,8 +178,8 @@ namespace YooAsset
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
internal void AddChildOperation(AsyncOperationBase child)
|
internal void AddChildOperation(AsyncOperationBase child)
|
||||||
{
|
{
|
||||||
if (_childs == null)
|
if (_children == null)
|
||||||
_childs = new List<AsyncOperationBase>(10);
|
_children = new List<AsyncOperationBase>(10);
|
||||||
|
|
||||||
#if UNITY_EDITOR || DEBUG
|
#if UNITY_EDITOR || DEBUG
|
||||||
if (child == null)
|
if (child == null)
|
||||||
@@ -163,7 +188,7 @@ namespace YooAsset
|
|||||||
if (ReferenceEquals(child, this))
|
if (ReferenceEquals(child, this))
|
||||||
throw new YooInternalException("The child node cannot be itself.");
|
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.");
|
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}");
|
throw new YooInternalException($"AddChildOperation would create a cycle : {this.GetType().Name} -> {child.GetType().Name}");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
_childs.Add(child);
|
_children.Add(child);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -179,26 +204,26 @@ namespace YooAsset
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
internal void RemoveChildOperation(AsyncOperationBase child)
|
internal void RemoveChildOperation(AsyncOperationBase child)
|
||||||
{
|
{
|
||||||
if (_childs == null)
|
if (_children == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
#if UNITY_EDITOR || DEBUG
|
#if UNITY_EDITOR || DEBUG
|
||||||
if (child == null)
|
if (child == null)
|
||||||
throw new YooInternalException("The child node is 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.");
|
throw new YooInternalException($"The child node {child.GetType().Name} not exists.");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
_childs.Remove(child);
|
_children.Remove(child);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 获取异步操作说明
|
/// 获取异步操作说明
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal string GetOperationDesc()
|
internal string GetOperationDescription()
|
||||||
{
|
{
|
||||||
return InternalGetDesc();
|
return InternalGetDescription();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -252,7 +277,7 @@ namespace YooAsset
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IsDone && IsFinish == false)
|
if (IsDone && IsFinished == false)
|
||||||
{
|
{
|
||||||
FinishOperation();
|
FinishOperation();
|
||||||
}
|
}
|
||||||
@@ -263,9 +288,9 @@ namespace YooAsset
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
internal void AbortOperation()
|
internal void AbortOperation()
|
||||||
{
|
{
|
||||||
if (_childs != null)
|
if (_children != null)
|
||||||
{
|
{
|
||||||
foreach (var child in _childs)
|
foreach (var child in _children)
|
||||||
{
|
{
|
||||||
child.AbortOperation();
|
child.AbortOperation();
|
||||||
}
|
}
|
||||||
@@ -284,21 +309,21 @@ namespace YooAsset
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 强制结束异步任务
|
/// 完成异步任务(触发回调和Task完成)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private void FinishOperation()
|
private void FinishOperation()
|
||||||
{
|
{
|
||||||
if (IsFinish == false)
|
if (IsFinished == false)
|
||||||
{
|
{
|
||||||
IsFinish = true;
|
IsFinished = true;
|
||||||
Progress = 1f;
|
Progress = 1f;
|
||||||
|
|
||||||
// 结束记录
|
// 结束记录
|
||||||
DebugEndRecording();
|
DebugEndRecording();
|
||||||
|
|
||||||
if (_callback != null)
|
if (_completedCallbacks != null)
|
||||||
{
|
{
|
||||||
var invocationList = _callback.GetInvocationList();
|
var invocationList = _completedCallbacks.GetInvocationList();
|
||||||
foreach (var handler in invocationList)
|
foreach (var handler in invocationList)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@@ -312,7 +337,7 @@ namespace YooAsset
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_callback = null;
|
_completedCallbacks = null;
|
||||||
if (_taskCompletionSource != null)
|
if (_taskCompletionSource != null)
|
||||||
_taskCompletionSource.TrySetResult(null);
|
_taskCompletionSource.TrySetResult(null);
|
||||||
}
|
}
|
||||||
@@ -388,9 +413,9 @@ namespace YooAsset
|
|||||||
StartOperation();
|
StartOperation();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IsWaitForAsyncComplete == false)
|
if (IsWaitingForAsyncComplete == false)
|
||||||
{
|
{
|
||||||
IsWaitForAsyncComplete = true;
|
IsWaitingForAsyncComplete = true;
|
||||||
|
|
||||||
if (IsDone == false)
|
if (IsDone == false)
|
||||||
InternalWaitForAsyncComplete();
|
InternalWaitForAsyncComplete();
|
||||||
@@ -409,52 +434,58 @@ namespace YooAsset
|
|||||||
|
|
||||||
#region 调试信息
|
#region 调试信息
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 开始的时间
|
/// 任务开始的时间(格式:HH:MM:SS,仅DEBUG模式有效)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string BeginTime { get; protected set; }
|
public string StartTime { get; protected set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 处理耗时(单位:毫秒)
|
/// 处理耗时(单位:毫秒)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public long ProcessTime { get; protected set; }
|
public long ElapsedMS { get; protected set; }
|
||||||
|
|
||||||
// 加载耗时统计
|
/// <summary>
|
||||||
private Stopwatch _watch = null;
|
/// 任务耗时计时器
|
||||||
|
/// </summary>
|
||||||
|
private Stopwatch _stopwatch = null;
|
||||||
|
|
||||||
[Conditional("DEBUG")]
|
[Conditional("DEBUG")]
|
||||||
private void DebugBeginRecording()
|
private void DebugBeginRecording()
|
||||||
{
|
{
|
||||||
if (_watch == null)
|
if (_stopwatch == null)
|
||||||
{
|
{
|
||||||
BeginTime = SpawnTimeToString(TimeUtility.RealtimeSinceStartup);
|
StartTime = FormatElapsedTime(TimeUtility.RealtimeSinceStartup);
|
||||||
_watch = Stopwatch.StartNew();
|
_stopwatch = Stopwatch.StartNew();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[Conditional("DEBUG")]
|
[Conditional("DEBUG")]
|
||||||
private void DebugUpdateRecording()
|
private void DebugUpdateRecording()
|
||||||
{
|
{
|
||||||
if (_watch != null)
|
if (_stopwatch != null)
|
||||||
{
|
{
|
||||||
ProcessTime = _watch.ElapsedMilliseconds;
|
ElapsedMS = _stopwatch.ElapsedMilliseconds;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[Conditional("DEBUG")]
|
[Conditional("DEBUG")]
|
||||||
private void DebugEndRecording()
|
private void DebugEndRecording()
|
||||||
{
|
{
|
||||||
if (_watch != null)
|
if (_stopwatch != null)
|
||||||
{
|
{
|
||||||
ProcessTime = _watch.ElapsedMilliseconds;
|
ElapsedMS = _stopwatch.ElapsedMilliseconds;
|
||||||
_watch = null;
|
_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 h = System.Math.Floor(time / 3600);
|
||||||
double m = System.Math.Floor(spawnTime / 60 - h * 60);
|
double m = System.Math.Floor(time / 60 - h * 60);
|
||||||
double s = System.Math.Floor(spawnTime - m * 60 - h * 3600);
|
double s = System.Math.Floor(time - m * 60 - h * 3600);
|
||||||
return h.ToString("00") + ":" + m.ToString("00") + ":" + s.ToString("00");
|
return h.ToString("00") + ":" + m.ToString("00") + ":" + s.ToString("00");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -487,13 +518,13 @@ namespace YooAsset
|
|||||||
if (ReferenceEquals(node, this))
|
if (ReferenceEquals(node, this))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (node._childs == null)
|
if (node._children == null)
|
||||||
continue;
|
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();
|
var operationInfo = new DiagnosticOperationInfo();
|
||||||
operationInfo.OperationName = this.GetType().Name;
|
operationInfo.OperationName = this.GetType().Name;
|
||||||
operationInfo.OperationDesc = GetOperationDesc();
|
operationInfo.OperationDesc = GetOperationDescription();
|
||||||
operationInfo.Priority = Priority;
|
operationInfo.Priority = Priority;
|
||||||
operationInfo.Progress = Progress;
|
operationInfo.Progress = Progress;
|
||||||
operationInfo.StartTime = BeginTime;
|
operationInfo.StartTime = StartTime;
|
||||||
operationInfo.ElapsedMS = ProcessTime;
|
operationInfo.ElapsedMS = ElapsedMS;
|
||||||
operationInfo.Status = Status.ToString();
|
operationInfo.Status = Status.ToString();
|
||||||
|
|
||||||
if (_childs == null)
|
if (_children == null)
|
||||||
{
|
{
|
||||||
operationInfo.Children = new List<DiagnosticOperationInfo>();
|
operationInfo.Children = new List<DiagnosticOperationInfo>();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
operationInfo.Children = new List<DiagnosticOperationInfo>(_childs.Count);
|
operationInfo.Children = new List<DiagnosticOperationInfo>(_children.Count);
|
||||||
foreach (var child in _childs)
|
foreach (var child in _children)
|
||||||
{
|
{
|
||||||
var childInfo = child.GetDebugOperationInfo();
|
var childInfo = child.GetDebugOperationInfo();
|
||||||
operationInfo.Children.Add(childInfo);
|
operationInfo.Children.Add(childInfo);
|
||||||
@@ -541,6 +572,11 @@ namespace YooAsset
|
|||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region 异步编程相关
|
#region 异步编程相关
|
||||||
|
/// <summary>
|
||||||
|
/// 用于支持 async/await 的任务完成源
|
||||||
|
/// </summary>
|
||||||
|
private TaskCompletionSource<object> _taskCompletionSource;
|
||||||
|
|
||||||
bool IEnumerator.MoveNext()
|
bool IEnumerator.MoveNext()
|
||||||
{
|
{
|
||||||
return !IsDone;
|
return !IsDone;
|
||||||
@@ -549,8 +585,6 @@ namespace YooAsset
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
object IEnumerator.Current => null;
|
object IEnumerator.Current => null;
|
||||||
|
|
||||||
private TaskCompletionSource<object> _taskCompletionSource;
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,34 @@
|
|||||||
|
|
||||||
namespace YooAsset
|
namespace YooAsset
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 异步操作状态枚举
|
||||||
|
/// </summary>
|
||||||
public enum EOperationStatus
|
public enum EOperationStatus
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 未开始
|
||||||
|
/// </summary>
|
||||||
None,
|
None,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 处理中
|
||||||
|
/// </summary>
|
||||||
Processing,
|
Processing,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 已成功
|
||||||
|
/// </summary>
|
||||||
Succeed,
|
Succeed,
|
||||||
Failed
|
|
||||||
|
/// <summary>
|
||||||
|
/// 已失败
|
||||||
|
/// </summary>
|
||||||
|
Failed,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 已中止
|
||||||
|
/// </summary>
|
||||||
|
Aborted,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -9,7 +9,7 @@ namespace YooAsset
|
|||||||
internal class OperationScheduler : IComparable<OperationScheduler>
|
internal class OperationScheduler : IComparable<OperationScheduler>
|
||||||
{
|
{
|
||||||
private readonly List<AsyncOperationBase> _operations = new List<AsyncOperationBase>(100);
|
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;
|
private uint _priority;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -41,24 +41,25 @@ namespace YooAsset
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 创建顺序(用于同优先级稳定排序)
|
/// 创建顺序(用于同优先级稳定排序)
|
||||||
/// </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;
|
PackageName = packageName;
|
||||||
CreateIndex = createIndex;
|
CreationOrder = creationOrder;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 开始处理异步操作
|
/// 开始处理异步操作
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// 操作会先添加到临时队列,在下一次Update时才会开始执行
|
/// 操作会立即启动,但会先添加到待处理队列。
|
||||||
|
/// 在下一次Update时才会合并到执行队列并参与调度更新
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
public void StartOperation(AsyncOperationBase operation)
|
public void StartOperation(AsyncOperationBase operation)
|
||||||
{
|
{
|
||||||
_newList.Add(operation);
|
_pendingOperations.Add(operation);
|
||||||
operation.StartOperation();
|
operation.StartOperation();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -71,17 +72,17 @@ namespace YooAsset
|
|||||||
for (int i = _operations.Count - 1; i >= 0; i--)
|
for (int i = _operations.Count - 1; i >= 0; i--)
|
||||||
{
|
{
|
||||||
var operation = _operations[i];
|
var operation = _operations[i];
|
||||||
if (operation.IsFinish)
|
if (operation.IsFinished)
|
||||||
{
|
{
|
||||||
_operations.RemoveAt(i);
|
_operations.RemoveAt(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 添加新增的异步操作
|
// 添加新增的异步操作
|
||||||
if (_newList.Count > 0)
|
if (_pendingOperations.Count > 0)
|
||||||
{
|
{
|
||||||
_operations.AddRange(_newList);
|
_operations.AddRange(_pendingOperations);
|
||||||
_newList.Clear();
|
_pendingOperations.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
// 检测是否需要执行排序
|
// 检测是否需要执行排序
|
||||||
@@ -107,7 +108,7 @@ namespace YooAsset
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
var operation = _operations[i];
|
var operation = _operations[i];
|
||||||
if (operation.IsFinish)
|
if (operation.IsFinished)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
operation.UpdateOperation();
|
operation.UpdateOperation();
|
||||||
@@ -120,11 +121,11 @@ namespace YooAsset
|
|||||||
public void ClearAll()
|
public void ClearAll()
|
||||||
{
|
{
|
||||||
// 终止临时队列里的任务
|
// 终止临时队列里的任务
|
||||||
foreach (var operation in _newList)
|
foreach (var operation in _pendingOperations)
|
||||||
{
|
{
|
||||||
operation.AbortOperation();
|
operation.AbortOperation();
|
||||||
}
|
}
|
||||||
_newList.Clear();
|
_pendingOperations.Clear();
|
||||||
|
|
||||||
// 终止正在进行的任务
|
// 终止正在进行的任务
|
||||||
foreach (var operation in _operations)
|
foreach (var operation in _operations)
|
||||||
@@ -139,7 +140,7 @@ namespace YooAsset
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public List<DiagnosticOperationInfo> GetDebugOperationInfos()
|
public List<DiagnosticOperationInfo> GetDebugOperationInfos()
|
||||||
{
|
{
|
||||||
int totalCount = _operations.Count + _newList.Count;
|
int totalCount = _operations.Count + _pendingOperations.Count;
|
||||||
List<DiagnosticOperationInfo> result = new List<DiagnosticOperationInfo>(totalCount);
|
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();
|
var operationInfo = operation.GetDebugOperationInfo();
|
||||||
result.Add(operationInfo);
|
result.Add(operationInfo);
|
||||||
@@ -167,7 +168,7 @@ namespace YooAsset
|
|||||||
if (result == 0)
|
if (result == 0)
|
||||||
{
|
{
|
||||||
// 优先级相同,按创建顺序
|
// 优先级相同,按创建顺序
|
||||||
result = this.CreateIndex.CompareTo(other.CreateIndex);
|
result = this.CreationOrder.CompareTo(other.CreationOrder);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,10 @@ using System.Diagnostics;
|
|||||||
|
|
||||||
namespace YooAsset
|
namespace YooAsset
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 异步操作系统(静态调度器)
|
||||||
|
/// 负责管理所有包裹的调度器,提供时间切片执行机制
|
||||||
|
/// </summary>
|
||||||
internal static class OperationSystem
|
internal static class OperationSystem
|
||||||
{
|
{
|
||||||
#if UNITY_EDITOR
|
#if UNITY_EDITOR
|
||||||
@@ -18,13 +22,13 @@ namespace YooAsset
|
|||||||
public const string GlobalSchedulerName = "YOOASSET_GLOBAL_SCHEDULER"; // 全局调度器名称
|
public const string GlobalSchedulerName = "YOOASSET_GLOBAL_SCHEDULER"; // 全局调度器名称
|
||||||
private const long MinTimeSlice = 10; // 最小时间片(毫秒)
|
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 readonly List<OperationScheduler> _schedulerList = new List<OperationScheduler>(100);
|
||||||
private static bool _isInitialized;
|
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 _frameTime;
|
||||||
private static long _maxTimeSlice = long.MaxValue;
|
private static long _maxTimeSlice = long.MaxValue;
|
||||||
|
|
||||||
@@ -58,14 +62,14 @@ namespace YooAsset
|
|||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
if (_watch == null)
|
if (_systemStopwatch == null)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (_maxTimeSlice == long.MaxValue)
|
if (_maxTimeSlice == long.MaxValue)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// 注意 : 单次调用开销约1微秒
|
// 注意 : 单次调用开销约1微秒
|
||||||
return _watch.ElapsedMilliseconds - _frameTime >= _maxTimeSlice;
|
return _systemStopwatch.ElapsedMilliseconds - _frameTime >= _maxTimeSlice;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -82,7 +86,7 @@ namespace YooAsset
|
|||||||
}
|
}
|
||||||
|
|
||||||
_isInitialized = true;
|
_isInitialized = true;
|
||||||
_watch = Stopwatch.StartNew();
|
_systemStopwatch = Stopwatch.StartNew();
|
||||||
|
|
||||||
// 创建全局调度器
|
// 创建全局调度器
|
||||||
CreatePackageScheduler(GlobalSchedulerName, uint.MaxValue);
|
CreatePackageScheduler(GlobalSchedulerName, uint.MaxValue);
|
||||||
@@ -112,7 +116,7 @@ namespace YooAsset
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 更新帧时间
|
// 更新帧时间
|
||||||
_frameTime = _watch.ElapsedMilliseconds;
|
_frameTime = _systemStopwatch.ElapsedMilliseconds;
|
||||||
|
|
||||||
// 更新调度器
|
// 更新调度器
|
||||||
for (int i = 0; i < _schedulerList.Count; i++)
|
for (int i = 0; i < _schedulerList.Count; i++)
|
||||||
@@ -136,11 +140,11 @@ namespace YooAsset
|
|||||||
{
|
{
|
||||||
scheduler.ClearAll();
|
scheduler.ClearAll();
|
||||||
}
|
}
|
||||||
_schedulerDic.Clear();
|
_schedulerDict.Clear();
|
||||||
_schedulerList.Clear();
|
_schedulerList.Clear();
|
||||||
_createIndex = 0;
|
_nextCreationIndex = 0;
|
||||||
|
|
||||||
_watch = null;
|
_systemStopwatch = null;
|
||||||
_frameTime = 0;
|
_frameTime = 0;
|
||||||
_maxTimeSlice = long.MaxValue;
|
_maxTimeSlice = long.MaxValue;
|
||||||
}
|
}
|
||||||
@@ -152,13 +156,13 @@ namespace YooAsset
|
|||||||
{
|
{
|
||||||
DebugEnsureInitialized(packageName);
|
DebugEnsureInitialized(packageName);
|
||||||
|
|
||||||
if (_schedulerDic.ContainsKey(packageName))
|
if (_schedulerDict.ContainsKey(packageName))
|
||||||
{
|
{
|
||||||
throw new YooInternalException($"Package scheduler already exists: {packageName}");
|
throw new YooInternalException($"Package scheduler already exists: {packageName}");
|
||||||
}
|
}
|
||||||
|
|
||||||
var scheduler = new OperationScheduler(packageName, _createIndex++);
|
var scheduler = new OperationScheduler(packageName, _nextCreationIndex++);
|
||||||
_schedulerDic.Add(packageName, scheduler);
|
_schedulerDict.Add(packageName, scheduler);
|
||||||
_schedulerList.Add(scheduler);
|
_schedulerList.Add(scheduler);
|
||||||
scheduler.Priority = priority;
|
scheduler.Priority = priority;
|
||||||
return scheduler;
|
return scheduler;
|
||||||
@@ -177,10 +181,10 @@ namespace YooAsset
|
|||||||
throw new YooInternalException("Cannot destroy the global package scheduler.");
|
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();
|
scheduler.ClearAll();
|
||||||
_schedulerDic.Remove(packageName);
|
_schedulerDict.Remove(packageName);
|
||||||
_schedulerList.Remove(scheduler);
|
_schedulerList.Remove(scheduler);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -188,7 +192,7 @@ namespace YooAsset
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 销毁包裹的所有任务
|
/// 销毁包裹的所有任务
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static void ClearPackageOperation(string packageName)
|
public static void ClearPackageOperations(string packageName)
|
||||||
{
|
{
|
||||||
DebugEnsureInitialized(packageName);
|
DebugEnsureInitialized(packageName);
|
||||||
|
|
||||||
@@ -234,7 +238,7 @@ namespace YooAsset
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private static OperationScheduler GetScheduler(string packageName)
|
private static OperationScheduler GetScheduler(string packageName)
|
||||||
{
|
{
|
||||||
if (_schedulerDic.TryGetValue(packageName, out var scheduler))
|
if (_schedulerDict.TryGetValue(packageName, out var scheduler))
|
||||||
{
|
{
|
||||||
return 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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IsWaitForAsyncComplete)
|
if (IsWaitingForAsyncComplete)
|
||||||
_handle.WaitForAsyncComplete();
|
_handle.WaitForAsyncComplete();
|
||||||
|
|
||||||
if (_handle.IsDone == false)
|
if (_handle.IsDone == false)
|
||||||
@@ -95,7 +95,7 @@ namespace YooAsset
|
|||||||
_instantiateAsync = InstantiateAsyncInternal(_handle.AssetObject, _options);
|
_instantiateAsync = InstantiateAsyncInternal(_handle.AssetObject, _options);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IsWaitForAsyncComplete)
|
if (IsWaitingForAsyncComplete)
|
||||||
_instantiateAsync.WaitForCompletion();
|
_instantiateAsync.WaitForCompletion();
|
||||||
|
|
||||||
if (_instantiateAsync.isDone == false)
|
if (_instantiateAsync.isDone == false)
|
||||||
@@ -132,7 +132,7 @@ namespace YooAsset
|
|||||||
{
|
{
|
||||||
RunBatchExecution();
|
RunBatchExecution();
|
||||||
}
|
}
|
||||||
internal override string InternalGetDesc()
|
internal override string InternalGetDescription()
|
||||||
{
|
{
|
||||||
var assetInfo = _handle.GetAssetInfo();
|
var assetInfo = _handle.GetAssetInfo();
|
||||||
return $"AssetPath : {assetInfo.AssetPath}";
|
return $"AssetPath : {assetInfo.AssetPath}";
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ namespace YooAsset
|
|||||||
|
|
||||||
if (_steps == ESteps.CheckConcurrency)
|
if (_steps == ESteps.CheckConcurrency)
|
||||||
{
|
{
|
||||||
if (IsWaitForAsyncComplete)
|
if (IsWaitingForAsyncComplete)
|
||||||
{
|
{
|
||||||
_steps = ESteps.LoadBundleFile;
|
_steps = ESteps.LoadBundleFile;
|
||||||
}
|
}
|
||||||
@@ -90,7 +90,7 @@ namespace YooAsset
|
|||||||
AddChildOperation(_loadBundleOp);
|
AddChildOperation(_loadBundleOp);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IsWaitForAsyncComplete)
|
if (IsWaitingForAsyncComplete)
|
||||||
_loadBundleOp.WaitForAsyncComplete();
|
_loadBundleOp.WaitForAsyncComplete();
|
||||||
|
|
||||||
_loadBundleOp.UpdateOperation();
|
_loadBundleOp.UpdateOperation();
|
||||||
@@ -129,7 +129,7 @@ namespace YooAsset
|
|||||||
{
|
{
|
||||||
RunBatchExecution();
|
RunBatchExecution();
|
||||||
}
|
}
|
||||||
internal override string InternalGetDesc()
|
internal override string InternalGetDescription()
|
||||||
{
|
{
|
||||||
return $"BundleName : {LoadBundleInfo.Bundle.BundleName}";
|
return $"BundleName : {LoadBundleInfo.Bundle.BundleName}";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -110,7 +110,7 @@ namespace YooAsset
|
|||||||
Status = EOperationStatus.Succeed;
|
Status = EOperationStatus.Succeed;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
internal override string InternalGetDesc()
|
internal override string InternalGetDescription()
|
||||||
{
|
{
|
||||||
return $"SceneName : {_provider.SceneName}";
|
return $"SceneName : {_provider.SceneName}";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ namespace YooAsset
|
|||||||
{
|
{
|
||||||
RunBatchExecution();
|
RunBatchExecution();
|
||||||
}
|
}
|
||||||
internal override string InternalGetDesc()
|
internal override string InternalGetDescription()
|
||||||
{
|
{
|
||||||
return $"LoopCount : {_options.LoopCount}";
|
return $"LoopCount : {_options.LoopCount}";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ namespace YooAsset
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IsWaitForAsyncComplete)
|
if (IsWaitingForAsyncComplete)
|
||||||
_loadAllAssetsOp.WaitForAsyncComplete();
|
_loadAllAssetsOp.WaitForAsyncComplete();
|
||||||
|
|
||||||
_loadAllAssetsOp.UpdateOperation();
|
_loadAllAssetsOp.UpdateOperation();
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ namespace YooAsset
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IsWaitForAsyncComplete)
|
if (IsWaitingForAsyncComplete)
|
||||||
_loadAssetOp.WaitForAsyncComplete();
|
_loadAssetOp.WaitForAsyncComplete();
|
||||||
|
|
||||||
_loadAssetOp.UpdateOperation();
|
_loadAssetOp.UpdateOperation();
|
||||||
|
|||||||
@@ -137,7 +137,7 @@ namespace YooAsset
|
|||||||
|
|
||||||
if (_steps == ESteps.WaitBundleLoader)
|
if (_steps == ESteps.WaitBundleLoader)
|
||||||
{
|
{
|
||||||
if (IsWaitForAsyncComplete)
|
if (IsWaitingForAsyncComplete)
|
||||||
{
|
{
|
||||||
foreach (var bundleLoader in _bundleLoaders)
|
foreach (var bundleLoader in _bundleLoaders)
|
||||||
{
|
{
|
||||||
@@ -185,7 +185,7 @@ namespace YooAsset
|
|||||||
{
|
{
|
||||||
RunBatchExecution();
|
RunBatchExecution();
|
||||||
}
|
}
|
||||||
internal override string InternalGetDesc()
|
internal override string InternalGetDescription()
|
||||||
{
|
{
|
||||||
return $"AssetPath : {MainAssetInfo.AssetPath}";
|
return $"AssetPath : {MainAssetInfo.AssetPath}";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ namespace YooAsset
|
|||||||
AddChildOperation(_loadSceneOp);
|
AddChildOperation(_loadSceneOp);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IsWaitForAsyncComplete)
|
if (IsWaitingForAsyncComplete)
|
||||||
_loadSceneOp.WaitForAsyncComplete();
|
_loadSceneOp.WaitForAsyncComplete();
|
||||||
|
|
||||||
// 注意:场景加载中途可以取消挂起
|
// 注意:场景加载中途可以取消挂起
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ namespace YooAsset
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IsWaitForAsyncComplete)
|
if (IsWaitingForAsyncComplete)
|
||||||
_loadSubAssetsOp.WaitForAsyncComplete();
|
_loadSubAssetsOp.WaitForAsyncComplete();
|
||||||
|
|
||||||
_loadSubAssetsOp.UpdateOperation();
|
_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();
|
DiagnosticProviderInfo providerInfo = new DiagnosticProviderInfo();
|
||||||
providerInfo.AssetPath = provider.MainAssetInfo.AssetPath;
|
providerInfo.AssetPath = provider.MainAssetInfo.AssetPath;
|
||||||
providerInfo.OriginScene = provider.OriginScene;
|
providerInfo.OriginScene = provider.OriginScene;
|
||||||
providerInfo.StartTime = provider.BeginTime;
|
providerInfo.StartTime = provider.StartTime;
|
||||||
providerInfo.ElapsedMS = provider.ProcessTime;
|
providerInfo.ElapsedMS = provider.ElapsedMS;
|
||||||
providerInfo.ReferenceCount = provider.RefCount;
|
providerInfo.ReferenceCount = provider.RefCount;
|
||||||
providerInfo.Status = provider.Status.ToString();
|
providerInfo.Status = provider.Status.ToString();
|
||||||
providerInfo.DependentBundles = provider.GetDebugDependBundles();
|
providerInfo.DependentBundles = provider.GetDebugDependBundles();
|
||||||
|
|||||||
@@ -98,7 +98,7 @@ namespace YooAsset
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
internal override string InternalGetDesc()
|
internal override string InternalGetDescription()
|
||||||
{
|
{
|
||||||
return $"ClearMode : {_options.ClearMode}";
|
return $"ClearMode : {_options.ClearMode}";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -92,13 +92,13 @@ namespace YooAsset
|
|||||||
|
|
||||||
// 最后清理该包裹的异步任务
|
// 最后清理该包裹的异步任务
|
||||||
// 注意:对于有线程操作的异步任务,需要保证线程安全释放。
|
// 注意:对于有线程操作的异步任务,需要保证线程安全释放。
|
||||||
OperationSystem.ClearPackageOperation(_resourcePackage.PackageName);
|
OperationSystem.ClearPackageOperations(_resourcePackage.PackageName);
|
||||||
|
|
||||||
_steps = ESteps.Done;
|
_steps = ESteps.Done;
|
||||||
Status = EOperationStatus.Succeed;
|
Status = EOperationStatus.Succeed;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
internal override string InternalGetDesc()
|
internal override string InternalGetDescription()
|
||||||
{
|
{
|
||||||
return $"PackageVersion : {_resourcePackage.GetPackageVersion()}";
|
return $"PackageVersion : {_resourcePackage.GetPackageVersion()}";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -181,7 +181,7 @@ namespace YooAsset
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
internal override string InternalGetDesc()
|
internal override string InternalGetDescription()
|
||||||
{
|
{
|
||||||
return $"PlayMode : {_playMode}";
|
return $"PlayMode : {_playMode}";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ namespace YooAsset
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
internal override string InternalGetDesc()
|
internal override string InternalGetDescription()
|
||||||
{
|
{
|
||||||
return $"PackageVersion : {_options.PackageVersion}";
|
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(loadFrame, Time.frameCount);
|
||||||
};
|
};
|
||||||
Assert.AreEqual(true, assetHandle.Provider.IsFinish);
|
Assert.AreEqual(true, assetHandle.Provider.IsFinished);
|
||||||
Assert.AreEqual(EOperationStatus.Succeed, assetHandle.Status);
|
Assert.AreEqual(EOperationStatus.Succeed, assetHandle.Status);
|
||||||
|
|
||||||
var audioClip = assetHandle.AssetObject as AudioClip;
|
var audioClip = assetHandle.AssetObject as AudioClip;
|
||||||
|
|||||||
Reference in New Issue
Block a user