3-7. 流程模块 - ProcedureModule
April 23, 2026 · View on GitHub
🔄 模块概述
流程模块是 TEngine 框架中的商业化启动流程管理系统,提供了完整的游戏启动、资源更新、热更新等流程控制。流程模块采用状态机模式,确保游戏启动流程的稳定性和可维护性。
✨ 核心优势
-
📋 完整的商业化流程
- 覆盖从启动到进入游戏的完整流程
- 支持资源更新、热更新等商业级功能
- 可自定义流程节点
-
🔄 状态机模式
- 清晰的流程状态管理
- 易于扩展和维护
- 支持流程跳转和回退
-
🚀 异步流程支持
- 基于 UniTask 的异步流程
- 不阻塞主线程
- 支持流程进度显示
📖 流程节点说明
TEngine 提供了以下标准流程节点:
1. ProcedureLaunch - 流程启动
游戏启动入口,初始化基础系统。
2. ProcedureSplash - 流程闪屏
显示游戏启动画面(Splash Screen)。
3. ProcedureInitPackage - 流程初始化 Package
初始化资源包系统(YooAsset)。
4. ProcedurePreload - 流程预加载
预加载必要的资源(如配置表、基础 UI 等)。
5. ProcedureInitResources - 流程初始化 Resources
初始化资源模块。
6. ProcedureUpdateVersion - 流程更新版本 Version
检查并更新资源包版本。
7. ProcedureUpdateManifest - 流程更新 Manifest 清单
更新资源清单文件。
8. ProcedureCreateDownloader - 流程创建下载器
创建资源下载器,用于下载更新资源。
9. ProcedureDownloadFile - 流程下载文件
下载需要更新的资源文件。
10. ProcedureDownloadOver - 流程下载文件结束
资源下载完成处理。
11. ProcedureClearCache - 流程清理缓存
清理不需要的缓存文件。
12. ProcedureLoadAssembly - 流程加载进入热更新程序集
加载热更新程序集(HybridCLR)。
13. ProcedureStartGame - 流程开始游戏
进入游戏主流程。
🔄 流程执行顺序
标准流程执行顺序(根据实际代码中的 ChangeState<T>() 调用链):
ProcedureLaunch
↓
ProcedureSplash
↓
ProcedureInitPackage
↓
ProcedureInitResources
↓ ← 根据运行模式分支:
├─ EditorSimulateMode / OfflinePlayMode → ProcedurePreload(直通)
└─ HostPlayMode → ProcedureCreateDownloader → ProcedureDownloadFile → ProcedureDownloadOver → ProcedureClearCache → ProcedurePreload
↓
ProcedurePreload
↓
ProcedureLoadAssembly
↓
ProcedureStartGame
注意:联机模式下,
ProcedureInitResources之后会进入版本更新和下载流程(ProcedureCreateDownloader → ProcedureDownloadFile → ProcedureDownloadOver → ProcedureClearCache),然后才进入 ProcedurePreload。编辑器模拟模式和单机模式则直接跳到 ProcedurePreload。
💡 自定义流程
创建自定义流程节点
using ProcedureOwner = TEngine.IFsm<TEngine.IProcedureModule>;
/// <summary>
/// 自定义流程节点。
/// </summary>
public class ProcedureCustom : ProcedureBase
{
public override bool UseNativeDialog => false;
protected override void OnEnter(ProcedureOwner procedureOwner)
{
base.OnEnter(procedureOwner);
// 流程进入逻辑
Log.Info("进入自定义流程");
// 执行异步操作,使用 UniTask 并 Forget 启动
DoSomethingAsync(procedureOwner).Forget();
}
protected override void OnUpdate(ProcedureOwner procedureOwner, float elapseSeconds, float realElapseSeconds)
{
base.OnUpdate(procedureOwner, elapseSeconds, realElapseSeconds);
// 流程更新逻辑
}
protected override void OnLeave(ProcedureOwner procedureOwner, bool isShutdown)
{
base.OnLeave(procedureOwner, isShutdown);
// 流程离开逻辑
Log.Info("离开自定义流程");
}
private async UniTaskVoid DoSomethingAsync(ProcedureOwner procedureOwner)
{
// 异步操作(禁止使用 Coroutine,必须使用 UniTask)
await UniTask.Delay(1000);
// 切换到下一个流程
ChangeState<ProcedureNext>(procedureOwner);
}
}
注册自定义流程
在流程模块初始化时注册自定义流程:
// 在 ProcedureModule 中注册
ProcedureBase[] procedures = {
new ProcedureLaunch(),
new ProcedureSplash(),
// ... 其他流程
new ProcedureCustom(), // 自定义流程
new ProcedureStartGame(),
};
🔧 API 参考
流程切换
// ProcedureOwner 别名:using ProcedureOwner = TEngine.IFsm<TEngine.IProcedureModule>;
/// <summary>
/// 切换到指定流程。
/// </summary>
/// <typeparam name="T">流程类型。</typeparam>
/// <param name="procedureOwner">流程状态机持有者。</param>
void ChangeState<T>(ProcedureOwner procedureOwner) where T : ProcedureBase;
流程生命周期
// ProcedureOwner 别名:using ProcedureOwner = TEngine.IFsm<TEngine.IProcedureModule>;
/// <summary>
/// 流程进入时调用。
/// </summary>
/// <param name="procedureOwner">流程状态机持有者。</param>
protected override void OnEnter(ProcedureOwner procedureOwner);
/// <summary>
/// 流程更新时调用。
/// </summary>
/// <param name="procedureOwner">流程状态机持有者。</param>
/// <param name="elapseSeconds">逻辑流逝时间。</param>
/// <param name="realElapseSeconds">真实流逝时间。</param>
protected override void OnUpdate(ProcedureOwner procedureOwner, float elapseSeconds, float realElapseSeconds);
/// <summary>
/// 流程离开时调用。
/// </summary>
/// <param name="procedureOwner">流程状态机持有者。</param>
/// <param name="isShutdown">是否是关闭状态机时触发。</param>
protected override void OnLeave(ProcedureOwner procedureOwner, bool isShutdown);
💡 最佳实践
1. 流程节点职责单一
每个流程节点应该只负责一个明确的任务:
// ✅ 推荐:职责单一
public class ProcedureUpdateVersion : ProcedureBase
{
// 只负责版本更新
}
// ❌ 不推荐:职责过多
public class ProcedureUpdateEverything : ProcedureBase
{
// 同时负责版本更新、资源更新、配置加载等
}
2. 使用异步操作
对于耗时操作,使用 UniTask 异步方式(禁止使用 async void 或 Coroutine):
// ✅ 推荐:在 OnEnter 中启动 UniTaskVoid 并 Forget
// using ProcedureOwner = TEngine.IFsm<TEngine.IProcedureModule>;
protected override void OnEnter(ProcedureOwner procedureOwner)
{
base.OnEnter(procedureOwner);
UpdateVersionAsync(procedureOwner).Forget();
}
private async UniTaskVoid UpdateVersionAsync(ProcedureOwner procedureOwner)
{
await DoUpdateAsync();
ChangeState<ProcedureNext>(procedureOwner);
}
// ❌ 禁止:async void 签名、Coroutine
// public override async void OnEnter(...) { ... }
// StartCoroutine(UpdateVersion());
3. 提供流程进度反馈
对于需要时间的流程,提供进度反馈:
// using ProcedureOwner = TEngine.IFsm<TEngine.IProcedureModule>;
protected override void OnEnter(ProcedureOwner procedureOwner)
{
base.OnEnter(procedureOwner);
DownloadWithProgressAsync(procedureOwner).Forget();
}
private async UniTaskVoid DownloadWithProgressAsync(ProcedureOwner procedureOwner)
{
var downloader = GameModule.Resource.CreateResourceDownloader();
// 显示进度
while (!downloader.IsDone)
{
float progress = downloader.Progress;
UpdateProgressUI(progress);
await UniTask.Yield();
}
ChangeState<ProcedureNext>(procedureOwner);
}