157 lines
4.4 KiB
Markdown
157 lines
4.4 KiB
Markdown
# P0-2: GameFlow 需求详细文档
|
||
|
||
## 对齐说明
|
||
|
||
本文档以 `docs/requirements/p0-requirements-set.md` 为准。GameFlow 是全局生命周期所有者,负责创建 Feature scope、FeatureContext,并编排 Feature 的进入、切换和关闭。
|
||
|
||
## 目标
|
||
|
||
提供游戏启动、Feature 切换和关闭流程的编排器,保证生命周期顺序、失败清理、取消和非法状态防护。
|
||
|
||
## 状态机
|
||
|
||
```csharp
|
||
public enum GameFlowState
|
||
{
|
||
Idle,
|
||
Starting,
|
||
Running,
|
||
Switching,
|
||
NoActiveFeature,
|
||
ShuttingDown,
|
||
Disposed
|
||
}
|
||
```
|
||
|
||
状态转换:
|
||
|
||
```text
|
||
Idle -> Starting -> Running <-> Switching
|
||
\-> NoActiveFeature
|
||
Running -> ShuttingDown -> Disposed
|
||
NoActiveFeature -> Switching -> Running
|
||
NoActiveFeature -> ShuttingDown -> Disposed
|
||
```
|
||
|
||
非法状态调用抛 `InvalidOperationException`,错误必须包含当前状态和操作名。
|
||
|
||
## 接口
|
||
|
||
```csharp
|
||
public sealed class GameFlow
|
||
{
|
||
public GameFlowState State { get; }
|
||
|
||
public Task StartupAsync<TInitialFeature>(
|
||
Container root,
|
||
CancellationToken cancellationToken)
|
||
where TInitialFeature : IFeature;
|
||
|
||
public Task SwitchToAsync<TFeature>(
|
||
CancellationToken cancellationToken)
|
||
where TFeature : IFeature;
|
||
|
||
public Task ShutdownAsync(CancellationToken cancellationToken);
|
||
}
|
||
```
|
||
|
||
## 启动流程
|
||
|
||
```text
|
||
StartupAsync:
|
||
1. State = Starting
|
||
2. Resolve IConfigProvider
|
||
3. await config.LoadAllAsync(ct)
|
||
4. Resolve ISaveService
|
||
5. 加载或创建 P0 Sample 所需 Data
|
||
6. 注册 Data 到 root Container
|
||
7. 创建 TInitialFeature
|
||
8. 创建 Feature scope
|
||
9. 创建 FeatureContext
|
||
10. await feature.LoadAsync(context)
|
||
11. await feature.EnterAsync(context)
|
||
12. State = Running
|
||
```
|
||
|
||
失败规则:
|
||
|
||
- 配置加载失败:清理已创建对象,State 回到 Idle,抛异常。
|
||
- 存档加载失败:使用默认 Data,记录警告,继续启动。
|
||
- Feature Load/Enter 失败:调用 Dispose 清理,State 回到 Idle,抛异常。
|
||
|
||
## Feature 切换流程
|
||
|
||
```text
|
||
SwitchToAsync:
|
||
1. State = Switching
|
||
2. await current.ExitAsync(currentContext)
|
||
3. current.Dispose()
|
||
4. Dispose current FeatureContext / scope / resources
|
||
5. 创建新 Feature、scope、FeatureContext
|
||
6. await next.LoadAsync(nextContext)
|
||
7. await next.EnterAsync(nextContext)
|
||
8. State = Running
|
||
```
|
||
|
||
失败规则:
|
||
|
||
- 旧 Feature `ExitAsync` 失败:记录错误,继续 Dispose。
|
||
- 旧 Feature `Dispose` 失败:记录错误,继续创建新 Feature。
|
||
- 新 Feature `LoadAsync` 失败:清理新 Feature,State = NoActiveFeature,抛异常。
|
||
- 新 Feature `EnterAsync` 失败:调用新 Feature Dispose,State = NoActiveFeature,抛异常。
|
||
- 切换期间再次调用 `SwitchToAsync`:P0 抛 `InvalidOperationException`,不排队。
|
||
|
||
## 关闭流程
|
||
|
||
```text
|
||
ShutdownAsync:
|
||
1. State = ShuttingDown
|
||
2. best-effort 调用当前 Feature ExitAsync
|
||
3. best-effort 调用当前 Feature Dispose
|
||
4. best-effort 保存必要 Data
|
||
5. Dispose root Container
|
||
6. State = Disposed
|
||
```
|
||
|
||
规则:
|
||
|
||
- `ShutdownAsync` 一旦进入关闭流程,必须尽量执行到底。
|
||
- 保存失败记录错误,不阻塞退出。
|
||
- Feature 退出/释放失败记录错误,不阻塞退出。
|
||
- Container 释放失败记录错误,不阻塞退出。
|
||
|
||
## 暂不做
|
||
|
||
- Feature 栈。
|
||
- 并行 Feature。
|
||
- Feature 预加载。
|
||
- 可配置启动任务列表。
|
||
- 切换请求队列。
|
||
- Starting/Switching 中断式 Shutdown。
|
||
|
||
## 验收标准
|
||
|
||
| # | 标准 | 通过条件 |
|
||
|---|------|---------|
|
||
| 1 | 正常启动 | Startup 完成后 State == Running,初始 Feature 已 Load + Enter |
|
||
| 2 | 启动配置失败 | State 回到 Idle,异常向上传播 |
|
||
| 3 | 启动存档失败 | 使用默认 Data,记录警告,继续启动 |
|
||
| 4 | 正常切换 | 旧 Feature 已 Exit/Dispose,新 Feature 已 Load/Enter |
|
||
| 5 | 新 Feature Load 失败 | State == NoActiveFeature,已清理新 Feature |
|
||
| 6 | 新 Feature Enter 失败 | State == NoActiveFeature,已 Dispose 新 Feature |
|
||
| 7 | 关闭 best-effort | 保存或释放失败时仍进入 Disposed |
|
||
| 8 | 非法状态防护 | 非法调用抛异常并包含当前状态 |
|
||
| 9 | CancellationToken 传递 | FeatureContext 中可拿到同一个取消信号 |
|
||
|
||
## 依赖关系
|
||
|
||
```text
|
||
GameFlow
|
||
├── Container
|
||
├── IFeature
|
||
├── FeatureContext
|
||
├── IConfigProvider
|
||
├── ISaveService
|
||
└── IResourceService
|
||
```
|