697 lines
19 KiB
Markdown
697 lines
19 KiB
Markdown
# FlowScope Game Core P0 需求集
|
||
|
||
## 文档目的
|
||
|
||
本文档定义 FlowScope Game Core 的 P0 范围。P0 的目标不是做一个覆盖所有未来项目的完整框架,而是交付一套能支撑真实休闲/超休闲 Unity 游戏最小纵向切片的 Core:
|
||
|
||
1. Unity 启动后进入 GameBootstrap。
|
||
2. 注册核心服务。
|
||
3. 加载 JSON 配置。
|
||
4. 加载或创建本地存档数据。
|
||
5. 进入初始 Feature。
|
||
6. 打开一个 MVVM Panel。
|
||
7. ViewModel/Data 通过 R3 驱动 UI 刷新。
|
||
8. 切换或关闭 Feature 时释放资源、订阅和作用域。
|
||
9. 退出时保存必要数据。
|
||
|
||
P0 允许包含部分开发体验能力,但这些能力必须服务于最小闭环,不能把 P0 扩张成完整包生态。
|
||
|
||
---
|
||
|
||
## P0 范围原则
|
||
|
||
1. 显式接口优先,业务模型不由 Core 暗猜。
|
||
2. Core 不包含具体玩法规则、具体 UI 文案、具体数值或业务 Data 类。
|
||
3. 默认实现只保留一条主路径,扩展实现通过接口或独立包接入。
|
||
4. 生命周期、资源、订阅、作用域必须有明确所有者。
|
||
5. 所有异步流程必须定义失败、取消和重复调用行为。
|
||
6. P0 文档中的每个模块都必须能通过单元测试或最小 Sample 验收。
|
||
|
||
---
|
||
|
||
## 统一架构决策
|
||
|
||
### 1. DI 自动注入进入 P0
|
||
|
||
P0 支持三种 DI 注册方式:
|
||
|
||
| 模式 | P0 定位 | 说明 |
|
||
|------|---------|------|
|
||
| 显式工厂注册 | 必须支持 | 最小稳定路径,所有项目都可用 |
|
||
| Attribute + Source Generator | P0 推荐路径 | 提供自动构造函数注入、RegisterAssembly、编译期检查 |
|
||
| Attribute + 运行时反射 | P0 可选降级路径 | 用于开发期、Generator 不可用场景、快速验证 |
|
||
|
||
约束:
|
||
|
||
- Container 的核心运行时只关心工厂函数,不直接依赖 Source Generator 或反射实现。
|
||
- Source Generator 和 Reflection 必须放在独立程序集或独立适配层中。
|
||
- 没有开启自动注入模式时,`RegisterType` / `RegisterAssembly` 必须给出明确错误,引导使用 `RegisterFactory`。
|
||
- 自动递归解析依赖链必须检测循环依赖,并输出完整依赖路径。
|
||
- Source Generator 的编译期检查作为 P0 推荐能力,但不能阻塞显式工厂模式使用。
|
||
|
||
### 2. UI 层级改为可配置
|
||
|
||
P0 不再强制固定 `Bottom / Middle / Top` 三层。UIManager 支持运行时注册层级:
|
||
|
||
```csharp
|
||
RegisterLayer(string name, Canvas canvas, int sortOrder, PanelStrategy strategy);
|
||
```
|
||
|
||
P0 仍需提供一个推荐默认预设,方便最小项目快速接入:
|
||
|
||
```text
|
||
background / hud / popup / dialog / system
|
||
```
|
||
|
||
项目可以只注册其中一部分,也可以自定义层级名。
|
||
|
||
### 3. UI 栈式面板进入 P0,但只做层内 LIFO
|
||
|
||
P0 支持同一层级内的栈式管理:
|
||
|
||
- 后打开的 Panel 位于同层级顶部。
|
||
- 默认只能关闭栈顶 Panel。
|
||
- `CloseLayer(layerName)` 关闭指定层。
|
||
- `CloseAll()` 关闭全部层级。
|
||
|
||
P0 暂不做完整导航路由、跨 Feature 页面恢复、URL/路由式导航、复杂返回策略。这些放到 P1/P2。
|
||
|
||
### 4. 配置系统 P0 只支持 JSON
|
||
|
||
P0 只交付 JSON 配置读取:
|
||
|
||
- `LoadAllAsync()`
|
||
- `Get<T>(int id)`
|
||
- `GetAll<T>()`
|
||
- 配置行实现 `IConfigRow`
|
||
|
||
CSV、Luban、ScriptableObject、远程配置、热重载、字段校验工具不进入 P0。后续通过 `IConfigSource` / `IConfigParser` 扩展包接入,而不是塞进核心实现。
|
||
|
||
### 5. 存档系统 P0 只保留本地轻量实现
|
||
|
||
P0 提供:
|
||
|
||
- `SaveAsync<T>(string key, T data)`
|
||
- `LoadAsync<T>(string key, T defaultValue)`
|
||
- `Delete(string key)`
|
||
|
||
默认实现二选一:
|
||
|
||
- `FileSaveStorage`
|
||
- `PlayerPrefsSaveStorage`
|
||
|
||
`Exists` 可作为轻量辅助进入 P0;`ListKeys`、云存档、加密、压缩、版本迁移、冲突解决不进入 P0。后续通过 `ISaveStorage` / `ISaveSerializer` 扩展。
|
||
|
||
### 6. 音频系统 P0 保留基础播放,不做完整音频框架
|
||
|
||
P0 提供:
|
||
|
||
- 播放/停止 BGM
|
||
- 播放 SFX
|
||
- 设置 BGM/SFX 音量
|
||
- 全局静音
|
||
- 简单 SFX AudioSource 池
|
||
- BGM 淡入淡出
|
||
|
||
`IAudioHandle` 可进入 P0,但只作为播放结果的轻量控制句柄:
|
||
|
||
- `Stop(float fadeOut = 0)`
|
||
- `IsPlaying`
|
||
|
||
单个音频暂停/恢复、单个音量、AudioMixer 路由、3D 音频、语音系统、动态音乐、音频配置表放到 P1/P2。
|
||
|
||
### 7. 资源系统 P0 支持引用计数,但只支持一个默认后端
|
||
|
||
P0 支持:
|
||
|
||
- `LoadAsync<T>(string key)`
|
||
- `IResourceHandle<T>`
|
||
- `IResourceGroup`
|
||
- 同 key 并发加载合并
|
||
- 引用计数
|
||
- Group 释放
|
||
|
||
P0 默认后端只支持 Addressables。
|
||
|
||
Resources / AssetBundle / YooAsset / 远程下载进度 / 资源分析工具不进入 P0。后续通过 `IResourceBackend` 插件化接入。
|
||
|
||
---
|
||
|
||
## 统一生命周期所有权
|
||
|
||
### GameFlow / AppFlow 负责
|
||
|
||
GameFlow 是全局生命周期编排者,负责:
|
||
|
||
- 创建 Feature 实例。
|
||
- 创建 Feature Scope。
|
||
- 创建 FeatureContext。
|
||
- 调用 Feature 生命周期。
|
||
- 在切换和关闭时保证释放顺序。
|
||
- 处理失败、取消和重复调用。
|
||
|
||
### Feature 负责
|
||
|
||
Feature 只负责自身业务行为:
|
||
|
||
- 在 `LoadAsync` 中加载自身资源、创建 ViewModel、准备运行时依赖。
|
||
- 在 `EnterAsync` 中打开 UI、订阅数据或事件流。
|
||
- 在 `ExitAsync` 中关闭 UI、取消业务订阅。
|
||
- 在 `Dispose` 中清空自身引用。
|
||
|
||
Feature 不直接创建根 scope。Feature 可以使用 GameFlow 提供的 feature scope 注册临时服务。
|
||
|
||
### FeatureContext
|
||
|
||
```csharp
|
||
public sealed class FeatureContext
|
||
{
|
||
public Container Scope { get; }
|
||
public IResourceGroup Resources { get; }
|
||
public CompositeDisposable Disposables { get; }
|
||
public CancellationToken CancellationToken { get; }
|
||
}
|
||
```
|
||
|
||
Feature 生命周期接口:
|
||
|
||
```csharp
|
||
public interface IFeature : IDisposable
|
||
{
|
||
Task LoadAsync(FeatureContext context);
|
||
Task EnterAsync(FeatureContext context);
|
||
Task ExitAsync(FeatureContext context);
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 统一异步策略
|
||
|
||
P0 接口统一使用 `Task` 和 `CancellationToken`。
|
||
|
||
规则:
|
||
|
||
- `StartupAsync`、`SwitchToAsync`、`ShutdownAsync` 必须接受 `CancellationToken`。
|
||
- Feature 生命周期通过 `FeatureContext.CancellationToken` 获取取消信号。
|
||
- 切换期间再次调用 `SwitchToAsync` 抛 `InvalidOperationException`,P0 不做排队。
|
||
- `ShutdownAsync` 在 `Starting` 或 `Switching` 中调用时,P0 抛 `InvalidOperationException`,P1 可考虑中断式关闭。
|
||
- `ShutdownAsync` 一旦进入关闭流程,必须 best-effort 执行到底。
|
||
|
||
失败处理:
|
||
|
||
| 场景 | P0 行为 |
|
||
|------|---------|
|
||
| Startup 配置加载失败 | 回到 Idle,抛异常 |
|
||
| Startup 存档加载失败 | 使用默认数据并记录警告 |
|
||
| 初始 Feature Load 失败 | 清理已创建资源,回到 Idle,抛异常 |
|
||
| Switch 旧 Feature Exit 失败 | 记录错误,继续 Dispose |
|
||
| Switch 旧 Feature Dispose 失败 | 记录错误,继续创建新 Feature |
|
||
| Switch 新 Feature Load 失败 | 清理新 Feature,进入 NoActiveFeature 状态,抛异常 |
|
||
| Switch 新 Feature Enter 失败 | 调用新 Feature Dispose,进入 NoActiveFeature 状态,抛异常 |
|
||
| Shutdown 保存失败 | 记录错误,不阻塞退出 |
|
||
| 取消发生 | 抛 `OperationCanceledException`,并清理已创建资源 |
|
||
|
||
---
|
||
|
||
## P0 模块需求
|
||
|
||
### P0-1 Container
|
||
|
||
目标:提供轻量 DI 容器,支持显式注册、自动注入、作用域和释放。
|
||
|
||
P0 必须支持:
|
||
|
||
- `RegisterInstance<T>(T instance)`
|
||
- `RegisterFactory<T>(Func<Container, T> factory)`
|
||
- `RegisterType<TInterface, TImplementation>()`
|
||
- `RegisterType<TImplementation>()`
|
||
- `RegisterAssembly()`
|
||
- `Resolve<T>()`
|
||
- `TryResolve<T>(out T value)`
|
||
- `CreateScope()`
|
||
- `Dispose()`
|
||
|
||
自动注入规则:
|
||
|
||
- 只允许一个 public 构造函数。
|
||
- 构造函数参数从 Container 递归解析。
|
||
- 循环依赖必须检测。
|
||
- Source Generator 模式提供编译期依赖检查。
|
||
- Reflection 模式提供运行时降级。
|
||
|
||
暂不做:
|
||
|
||
- `[Inject]` 属性/方法注入。
|
||
- 多生命周期模式。
|
||
- 开放泛型注册。
|
||
- 装饰器注册。
|
||
- 运行时动态切换 DI 模式。
|
||
|
||
验收:
|
||
|
||
- 显式工厂注册可解析。
|
||
- Source Generator 自动注入可解析。
|
||
- Reflection 自动注入可解析。
|
||
- 子 scope 可访问父 scope。
|
||
- 子 scope 覆盖父 scope 不污染父 scope。
|
||
- Dispose 按逆序释放本 scope 创建的 `IDisposable`。
|
||
- 循环依赖抛出包含依赖链的异常。
|
||
|
||
### P0-2 GameFlow
|
||
|
||
目标:编排游戏启动、Feature 切换和关闭。
|
||
|
||
状态:
|
||
|
||
```text
|
||
Idle -> Starting -> Running <-> Switching -> ShuttingDown -> Disposed
|
||
```
|
||
|
||
接口:
|
||
|
||
```csharp
|
||
Task StartupAsync<TInitialFeature>(Container root, CancellationToken ct);
|
||
Task SwitchToAsync<TFeature>(CancellationToken ct);
|
||
Task ShutdownAsync(CancellationToken ct);
|
||
```
|
||
|
||
职责:
|
||
|
||
- 启动时加载配置、加载存档、注册 Data、进入初始 Feature。
|
||
- 切换时按 `Exit -> Dispose -> CreateScope -> Load -> Enter` 执行。
|
||
- 关闭时按 `Exit -> Dispose -> Save -> DisposeRootContainer` 执行。
|
||
- 创建并传递 `FeatureContext`。
|
||
- 防止非法状态调用。
|
||
|
||
暂不做:
|
||
|
||
- Feature 栈。
|
||
- 并行 Feature。
|
||
- 可配置启动任务列表。
|
||
- Feature 预加载。
|
||
|
||
### P0-3 Feature
|
||
|
||
目标:定义业务特性的统一生命周期。
|
||
|
||
接口:
|
||
|
||
```csharp
|
||
public interface IFeature : IDisposable
|
||
{
|
||
Task LoadAsync(FeatureContext context);
|
||
Task EnterAsync(FeatureContext context);
|
||
Task ExitAsync(FeatureContext context);
|
||
}
|
||
```
|
||
|
||
规则:
|
||
|
||
- Feature 不依赖其他 Feature 的内部状态。
|
||
- 持久跨 Feature 状态放入 Data 类。
|
||
- 一次性过渡参数由目标 Feature 定义。
|
||
- 订阅必须进入 `FeatureContext.Disposables` 或 ViewModel 自己的 disposable 集合。
|
||
- 资源必须进入 `FeatureContext.Resources` 或由明确 handle 管理。
|
||
|
||
暂不做:
|
||
|
||
- Feature 间直接通信。
|
||
- Feature 热重载。
|
||
- Feature 过渡动画。
|
||
- 多 Feature 同时运行。
|
||
|
||
### P0-4 R3 + Data
|
||
|
||
目标:建立运行时数据和响应式绑定基础。
|
||
|
||
规则:
|
||
|
||
- 一个 Data 类对应一个业务域。
|
||
- Data 类是纯 C#,不依赖 Unity API。
|
||
- Data 类不引用 View / ViewModel。
|
||
- Data 类使用 `ReactiveProperty<T>` 和 `ReactiveCollection<T>` 表达可观察状态。
|
||
- ViewModel 负责业务表现逻辑,可以修改 Data。
|
||
- ViewModel 订阅必须释放。
|
||
|
||
P0 支持:
|
||
|
||
- `ReactiveProperty<T>` 序列化为 `.Value`。
|
||
- `ReactiveCollection<T>` 序列化为数组。
|
||
- 存档加载后恢复到 Data 实例。
|
||
|
||
暂不做:
|
||
|
||
- 自研响应式系统。
|
||
- UI 自动绑定。
|
||
- 全局 EventBus。
|
||
- Data Inspector 可视化。
|
||
|
||
### P0-5 ConfigProvider
|
||
|
||
目标:提供 JSON 配置读取。
|
||
|
||
接口:
|
||
|
||
```csharp
|
||
public interface IConfigProvider
|
||
{
|
||
Task LoadAllAsync(CancellationToken ct);
|
||
T Get<T>(int id) where T : class, IConfigRow;
|
||
IReadOnlyList<T> GetAll<T>() where T : class, IConfigRow;
|
||
}
|
||
|
||
public interface IConfigRow
|
||
{
|
||
int Id { get; }
|
||
}
|
||
```
|
||
|
||
规则:
|
||
|
||
- P0 默认 JSON。
|
||
- 查询不存在 ID 返回 null。
|
||
- 重复 ID 抛异常。
|
||
- 配置格式错误抛异常并包含文件名。
|
||
|
||
暂不做:
|
||
|
||
- CSV / Luban / ScriptableObject。
|
||
- 按模块加载和卸载。
|
||
- 热重载。
|
||
- 配置编辑器校验。
|
||
- 远程配置。
|
||
|
||
扩展方向:
|
||
|
||
- P1/P2 通过 `IConfigParser` 和 `IConfigSource` 插件化接入,不修改业务调用。
|
||
|
||
### P0-6 SaveService
|
||
|
||
目标:提供本地轻量存档。
|
||
|
||
接口:
|
||
|
||
```csharp
|
||
public interface ISaveService
|
||
{
|
||
Task SaveAsync<T>(string key, T data, CancellationToken ct);
|
||
Task<T> LoadAsync<T>(string key, T defaultValue, CancellationToken ct);
|
||
void Delete(string key);
|
||
bool Exists(string key);
|
||
}
|
||
```
|
||
|
||
默认实现:
|
||
|
||
- `FileSaveStorage` 或 `PlayerPrefsSaveStorage` 二选一。
|
||
- 默认序列化为 JSON。
|
||
|
||
规则:
|
||
|
||
- 不存在 key 返回 defaultValue。
|
||
- 反序列化失败返回 defaultValue 并记录警告。
|
||
- 写入失败抛异常。
|
||
- 删除不存在 key 静默忽略。
|
||
|
||
暂不做:
|
||
|
||
- `ListKeys`。
|
||
- 多存档槽管理。
|
||
- 云存档。
|
||
- 加密。
|
||
- 压缩。
|
||
- 版本迁移。
|
||
- 自动存档。
|
||
|
||
扩展方向:
|
||
|
||
- P1/P2 通过 `ISaveStorage` / `ISaveSerializer` 扩展。
|
||
|
||
### P0-7 ResourceService
|
||
|
||
目标:提供资源异步加载、引用计数和分组释放。
|
||
|
||
接口:
|
||
|
||
```csharp
|
||
public interface IResourceService
|
||
{
|
||
Task<IResourceHandle<T>> LoadAsync<T>(string key, CancellationToken ct) where T : class;
|
||
IResourceGroup CreateGroup();
|
||
}
|
||
|
||
public interface IResourceHandle<T> : IDisposable where T : class
|
||
{
|
||
string Key { get; }
|
||
T Asset { get; }
|
||
bool IsDisposed { get; }
|
||
}
|
||
|
||
public interface IResourceGroup : IDisposable
|
||
{
|
||
void Add<T>(IResourceHandle<T> handle) where T : class;
|
||
int Count { get; }
|
||
}
|
||
```
|
||
|
||
规则:
|
||
|
||
- 同 key 并发加载只触发一次底层加载。
|
||
- 每次加载返回独立 handle。
|
||
- 最后一个 handle Dispose 时释放底层资源。
|
||
- Group Dispose 释放组内所有 handle。
|
||
- 重复 Dispose 不抛异常。
|
||
- Dispose 后访问 Asset 返回 null 或抛明确异常,二选一需在实现前固定。
|
||
|
||
P0 默认:
|
||
|
||
- Addressables 后端。
|
||
|
||
暂不做:
|
||
|
||
- Resources 后端。
|
||
- AssetBundle 后端。
|
||
- YooAsset 后端。
|
||
- 下载进度。
|
||
- 资源预热。
|
||
- 资源分析工具。
|
||
|
||
扩展方向:
|
||
|
||
- P1/P2 通过 `IResourceBackend` 插件化接入其他资源系统。
|
||
|
||
### P0-8 UIManager
|
||
|
||
目标:提供 MVVM Panel 生命周期管理、可配置层级和层内栈。
|
||
|
||
接口:
|
||
|
||
```csharp
|
||
public sealed class UIManager
|
||
{
|
||
void RegisterLayer(string name, Canvas canvas, int sortOrder, PanelStrategy strategy);
|
||
Task<TPanel> OpenAsync<TPanel, TViewModel>(TViewModel vm, CancellationToken ct)
|
||
where TPanel : UIPanelBase<TViewModel>;
|
||
void Close<TPanel>();
|
||
void CloseLayer(string layerName);
|
||
void CloseAll();
|
||
bool IsOpen<TPanel>();
|
||
}
|
||
```
|
||
|
||
Panel Attribute:
|
||
|
||
```csharp
|
||
[AttributeUsage(AttributeTargets.Class)]
|
||
public sealed class UIPanelAttribute : Attribute
|
||
{
|
||
public string Layer { get; }
|
||
public string Path { get; }
|
||
public PanelStrategy? OverrideStrategy { get; }
|
||
|
||
public UIPanelAttribute(string layer);
|
||
public UIPanelAttribute(string layer, string path);
|
||
public UIPanelAttribute(string layer, PanelStrategy overrideStrategy);
|
||
public UIPanelAttribute(string layer, string path, PanelStrategy overrideStrategy);
|
||
}
|
||
```
|
||
|
||
Panel 基类:
|
||
|
||
```csharp
|
||
public abstract class UIPanelBase<TViewModel> : MonoBehaviour
|
||
{
|
||
protected TViewModel ViewModel { get; private set; }
|
||
protected CompositeDisposable Disposables { get; } = new();
|
||
|
||
public void Bind(TViewModel viewModel)
|
||
{
|
||
ViewModel = viewModel;
|
||
OnBind(viewModel);
|
||
}
|
||
|
||
public virtual void Unbind()
|
||
{
|
||
Disposables.Clear();
|
||
}
|
||
|
||
protected abstract void OnBind(TViewModel viewModel);
|
||
}
|
||
```
|
||
|
||
规则:
|
||
|
||
- Panel 必须声明 `UIPanelAttribute`。
|
||
- Attribute 未指定 path 时,按命名约定推导资源路径。
|
||
- C# Attribute 构造参数不支持 `Nullable<T>`,因此 `OverrideStrategy` 属性保持 nullable,但构造函数通过重载表达“未指定”和“指定覆盖策略”。
|
||
- 同层级采用 LIFO 栈。
|
||
- 关闭非栈顶 Panel 抛异常。
|
||
- Destroy 策略关闭时释放资源 handle。
|
||
- Cache 策略关闭时隐藏对象,复用时重新 Bind。
|
||
|
||
暂不做:
|
||
|
||
- 自动 UI 绑定。
|
||
- 导航路由系统。
|
||
- Panel 预加载。
|
||
- SafeArea。
|
||
- 多语言切换。
|
||
- 红点系统。
|
||
- 复杂转场动画。
|
||
|
||
### P0-9 AudioService
|
||
|
||
目标:提供基础音频播放能力。
|
||
|
||
接口:
|
||
|
||
```csharp
|
||
public interface IAudioService
|
||
{
|
||
IAudioHandle PlayBgm(string key, bool loop = true, float fadeIn = 0f);
|
||
IAudioHandle PlaySfx(string key);
|
||
void StopBgm(float fadeOut = 0f);
|
||
void SetBgmVolume(float volume);
|
||
void SetSfxVolume(float volume);
|
||
void SetMute(bool mute);
|
||
}
|
||
|
||
public interface IAudioHandle
|
||
{
|
||
void Stop(float fadeOut = 0f);
|
||
bool IsPlaying { get; }
|
||
}
|
||
```
|
||
|
||
规则:
|
||
|
||
- 同一时间只有一首 BGM。
|
||
- 播放新 BGM 自动停止旧 BGM。
|
||
- SFX 使用简单 AudioSource 池。
|
||
- 音量参数 clamp 到 `[0, 1]`。
|
||
- 资源通过 `IResourceService` 加载。
|
||
|
||
暂不做:
|
||
|
||
- 单个音频 Pause/Resume。
|
||
- 单个音频 Volume。
|
||
- AudioMixer 分组。
|
||
- 3D 音频。
|
||
- 动态音乐。
|
||
- 音频配置表。
|
||
|
||
---
|
||
|
||
## P0 最小 Sample 验收
|
||
|
||
P0 完成时必须提供一个最小 Sample:
|
||
|
||
```text
|
||
GameBootstrap
|
||
-> 创建根 Container
|
||
-> 注册 Container / Config / Save / Resource / UI / Audio
|
||
-> 注册 PlayerData
|
||
-> GameFlow.StartupAsync<MainMenuFeature>()
|
||
|
||
MainMenuFeature
|
||
-> LoadAsync: 加载 MainMenuPanel 资源,创建 MainMenuViewModel
|
||
-> EnterAsync: UIManager.OpenAsync<MainMenuPanel, MainMenuViewModel>()
|
||
-> 点击按钮修改 PlayerData.Gold
|
||
-> UI 文本响应刷新
|
||
-> ShutdownAsync 保存 PlayerData
|
||
```
|
||
|
||
验收标准:
|
||
|
||
- Sample 可在 Unity 中运行。
|
||
- 首次启动创建默认 PlayerData。
|
||
- 修改 Gold 后 UI 立即刷新。
|
||
- 退出后保存 PlayerData。
|
||
- 重新启动后恢复 PlayerData。
|
||
- Feature 退出后资源组释放。
|
||
- Feature 退出后订阅不再触发。
|
||
- 连续打开/关闭 Panel 不残留订阅。
|
||
|
||
---
|
||
|
||
## P0 测试矩阵
|
||
|
||
| 模块 | 必测内容 |
|
||
|------|----------|
|
||
| Container | 显式工厂、自动注入、scope 覆盖、Dispose、循环依赖 |
|
||
| GameFlow | 启动顺序、切换顺序、失败清理、非法状态调用、关闭 best-effort |
|
||
| Feature | Load/Enter/Exit/Dispose 顺序、资源和订阅释放 |
|
||
| Data/R3 | ReactiveProperty 同步、序列化/反序列化、订阅释放 |
|
||
| Config | JSON 解析、重复 Id、不存在 Id、格式错误 |
|
||
| Save | 保存/加载、默认值、删除、反序列化失败 |
|
||
| Resource | 同 key 并发、引用计数、Group 释放、加载失败 |
|
||
| UI | 层级注册、Open/Close、LIFO、Bind/Unbind、Cache/Destroy |
|
||
| Audio | BGM 播放/停止、SFX 池、音量 clamp、静音、资源加载失败 |
|
||
|
||
---
|
||
|
||
## P1/P2 扩展方向
|
||
|
||
后续能力优先做成可插拔扩展,而不是污染 P0 核心:
|
||
|
||
P1 生产化承接边界:P1 可以新增小接口、适配层和样例验收能力,但不得重写 P0 的核心生命周期、容器、UI 层内 LIFO、JSON 默认配置、本地存档和资源所有权语义。任何涉及 Addressables、配置来源、存档迁移、UI 导航或预加载的能力,都应先通过 P1 契约进入,再由独立实现或适配程序集承接。
|
||
|
||
| 能力 | 建议阶段 | 形式 |
|
||
|------|----------|------|
|
||
| CSV / Luban 配置 | P1/P2 | `IConfigParser` 插件 |
|
||
| 按模块配置加载 | P1 | `IConfigSource` 扩展 |
|
||
| 存档版本迁移 | P1/P2 | `ISaveMigration` 插件 |
|
||
| 云存档 | P2 | `ISaveStorage` 插件 |
|
||
| Resources / YooAsset / AssetBundle | P1/P2 | `IResourceBackend` 插件 |
|
||
| UI 路由 / 返回栈策略 | P1 | `IUIScreenNavigator` 扩展 |
|
||
| Panel 预加载 | P1 | UIManager 扩展服务 |
|
||
| AudioMixer / 3D 音频 | P1/P2 | `IAudioBackend` 或 AudioService 扩展 |
|
||
| 编辑器导入向导 | P2 | Editor 包 |
|
||
| 配置/资源检查工具 | P2 | Editor 工具包 |
|
||
|
||
---
|
||
|
||
## 需要同步修正的旧文档
|
||
|
||
以下旧文档需要按本文档重新收敛:
|
||
|
||
- `docs/game-core-requirement-tiers.md`
|
||
- `docs/requirements/p0-container.md`
|
||
- `docs/requirements/p0-gameflow.md`
|
||
- `docs/requirements/p0-feature.md`
|
||
- `docs/requirements/p0-configprovider.md`
|
||
- `docs/requirements/p0-saveservice.md`
|
||
- `docs/requirements/p0-resourceservice.md`
|
||
- `docs/requirements/p0-uimanager.md`
|
||
- `docs/requirements/p0-audioservice.md`
|
||
|
||
其中主文档必须更新的决策:
|
||
|
||
- DI 自动注入进入 P0。
|
||
- UI 层级从固定三层改为可配置层级。
|
||
- UI 层内 LIFO 栈进入 P0。
|
||
- JSON 是 P0 唯一默认配置格式。
|
||
- 资源 P0 只保留 Addressables 默认后端,其他后端插件化。
|
||
- 存档 P0 只保留本地轻量实现,云存档插件化。
|