Files
aibis-dream/Docs/GameManagerRefactorPlan.md
T

7.9 KiB
Raw Blame History

GameManager 收敛式重构说明

状态:已按修订方案实现

更新日期:2026-07-17

1. 最终职责边界

组件 职责
GameManager 唯一会话命令入口;编排开始、章节跳转、读档、暂停、返回主界面和退出应用
GameSession GameManager 持有的纯状态对象;保存状态、校验迁移并计算能力
TalkSceneGraphIndex 从首章图派生运行时章节列表和恢复名称索引
SceneLoader 串行执行 Addressables 场景加载、卸载和场景级资源清理
SceneReadiness 在当前加载 Scene 内收集 ISceneDialogueGate 并等待就绪
SaveRestoreOrchestrator 存档预检和 Snapshot 内部恢复阶段
ChapterController 章节解锁数据及章节面板投影
ApplicationBootstrapper 应用设置、SnapshotRegistry、本地化及主界面启动流程
DisplaySettingsController 窗口模式和分辨率应用,并发送显示变化通知

没有引入 NarrativeFlowController、人工维护的 TalkSceneCatalog 或独立全局 Session 服务。TalkSceneSOSceneExit、章节资产和 Chapter Graph Editor 数据结构保持不变。

2. GameSession

GameSessionPhase

MainMenu
Starting
Transitioning
Restoring
Playing
ReturningToMenu

只读状态:

  • Phase
  • CurrentTalkScene
  • IsPaused
  • IsDialogueActive
  • IsActive
  • IsBusy
  • CanPause
  • CanResume
  • CanAdvanceDialogue

外部通过 GameManager.Session 读取;GameManager 内部直接使用 _session。所有写入方法均为 internalGameSession 不执行协程、不操作 UI、不加载场景,也不发送全局事件。

合法迁移:

MainMenu → Starting / Restoring
Playing → Transitioning / Restoring / ReturningToMenu
Starting / Transitioning → Playing / ReturningToMenu
Restoring → Playing / MainMenu / ReturningToMenu
ReturningToMenu → MainMenu

3. 生命周期事件

GameLoopEnum 已删除,统一使用:

public enum GameLifecycleEvent
{
    ApplicationReady,
    SessionStarted,
    SessionReady,
    SessionPaused,
    SessionResumed,
    SessionEnding,
    SessionEnded,
    SessionFailed
}

显示设置通知使用 SettingChangeEvent.DisplayChanged

事件顺序固定为:GameManager 执行命令 → GameSession 完成状态迁移 → GameManager 发送生命周期通知。监听方不能反向修改 Session。

DialogController.DialogueActivityChanged(bool) 是 GameManager 更新对话活动状态的直接 C# 事件;原有对话表现事件继续供其他系统使用。

4. GameManager API

public bool TryStartNewGame();
public bool TryStartChapter(TalkSceneSO chapter);
public bool TryRestoreSlot(int slotIndex, Action<RestoreResult> completed = null);
public bool TryPause();
public bool TryResume();
public bool TryReturnToMainMenu();
public void QuitApplication();
public IReadOnlyList<TalkSceneSO> RuntimeChapters { get; }

开始、转场和恢复共用一个活动命令锁,重复请求直接返回 false。返回主界面请求可以在活动命令期间排队;当前不可中断的 Addressables 或 Provider 单步结束后,流程会在阶段边界停止,并进入唯一的返回主界面协程。

Yarn 场景命令通过以下内部可等待入口执行;章节交接是例外,由源 Runner 同步提交后交给 GameManager 独立执行:

internal bool TryAdvanceChapterFromYarn(string exitName);
internal IEnumerator LoadSceneFromYarn(string sceneName);
internal IEnumerator UnloadSceneFromYarn();

NextYarn 是同步交接命令:它只向 GameManager 提交章节跳转并立即返回,不等待转场,也不在自身命令回调中停止 DialogueRunner。NextYarn 必须是当前分支最后一条可执行命令;GameManager 只等待源节点自然结束,超时视为内容错误并终止转场,不兼容后续选项、jump 或其他命令。load_scene / unload_scene 不替换 YarnProject,因此继续由 Yarn 等待完成。

旧 GameManager 状态字段、接口和命令 API 已删除,没有保留兼容转发层。

5. 章节索引

TalkSceneGraphIndexfirstTalkSo 开始,按 exits 顺序稳定深度优先遍历,并用 visited 集合处理环:

  • 可达节点进入 RuntimeChapters 和名称索引。
  • 同名不同资产会被标记为歧义,恢复预检失败。
  • ChapterController 直接投影 RuntimeChapters

这份索引完全从现有创作数据派生,不引入第二份章节目录。

6. 场景加载与 Readiness

SceneLoader 使用 AsyncOperationHandle<SceneInstance>,加载和卸载均返回结构化 SceneOperationResult

  • Busy、空 Key、Addressables 失败和无效 SceneInstance 均明确失败。
  • 仅成功后提交当前场景名、Scene 和句柄。
  • 卸载失败保留当前场景句柄与名称。
  • Loading UI 与 IsLoadingfinally 中复位。
  • DOTween、Fix 注册表和 ResourceSystem 场景级生命周期统一由 SceneLoader 清理。

SceneReadiness 在刚加载的 Scene 根对象内查找 Gate,使用 unscaled time,默认超时 15 秒。无 Gate 时等待稳定一帧后成功;Gate 销毁、取消或超时返回失败。普通章节加载在 SceneLoader 后等待;读档在 Provider 后、Anchor 前等待。

7. 恢复边界

PrepareRestore
→ 读槽位或文件
→ schema、场景、章节、YarnProject 和可选节点预检
→ 解析目标 TalkSceneSO
→ 不修改运行时

ExecutePreparedRestore
→ Yarn variables
→ Scene
→ Providers
→ SceneReadiness
→ Anchor
→ Postflight

说明:显式 <<save>> 可以生成无节点 anchor 的新格式快照。这类快照仍预检章节和 YarnProject,但跳过节点存在性校验,并在恢复时只加载 YarnProject、不重进节点。

GameManager 管理命令锁、Session Phase、遮罩、旧会话表现清理、成功提交和失败决策。Orchestrator 不再查找或设置 GameManager 的当前章节。

恢复成功后,GameManager 提交 RestoreResult.RestoredTalkScene、解锁章节、进入 Playing 并发送 SessionReady。预检失败恢复发起前的稳定 Phase;执行失败停止后续 Anchor 并排队安全返回主界面。已接受请求的回调只调用一次。

存档文件统一经过当前快照反序列化和 schema 预检,不保留旧 StorageSystem 格式的专用识别、恢复或转写分支。

8. 核心流程

新游戏 / 选章:

校验章节 → 获取命令锁 → Starting → SessionStarted → 遮黑
→ SceneLoader → SceneReadiness → 提交并解锁章节 → 启动 Yarn
→ Playing → SessionReady → 揭示画面

章节跳转:

解析出口 → Transitioning → 遮黑 → SceneLoader → SceneReadiness
→ 提交并解锁章节 → 启动 Yarn → Playing → SessionReady → 揭示画面

读档:

获取命令锁 → Restoring → PrepareRestore → SessionStarted → 遮黑
→ 清理旧会话表现 → ExecutePreparedRestore → 提交目标章节
→ Playing → SessionReady → 揭示画面

返回主界面:

ReturningToMenu → SessionEnding → 恢复 timeScale / 清除暂停 → 遮黑
→ 等待对话停止 → 卸载场景 → 清理表现和相机
→ 清除章节与对话状态 → MainMenu → SessionEnded → 揭示主界面

9. 验证基线

静态验收应确认:

  • 不存在 GameLoopEnumGameManager.state、旧 GameManager API 或 CleanSessionFirst
  • 输入只读取 CanAdvanceDialogue;暂停入口只读取 CanPause
  • 开始、转场、恢复和 Yarn 场景命令都经过 GameManager 互斥。
  • Snapshot 恢复不再通过 GameManager 查找或设置章节。
  • 章节面板和存档恢复都只使用从首章可达的正式章节。

运行时冒烟仍需覆盖新游戏、选章、每类新格式存档、Gate 成功/超时、活动命令期间返回主界面,以及退出后场景、对话、暂停、音频、相机和表现 UI 清理。