Files
FlowScope/docs/requirements/p0-gameflow.md
2026-05-15 15:38:40 +08:00

157 lines
4.4 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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` 失败:清理新 FeatureState = NoActiveFeature抛异常。
- 新 Feature `EnterAsync` 失败:调用新 Feature DisposeState = 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
```