首页 / 大项目模块 / 传送 / 重构 · 流程命令化

TeleportController 重构 · 第二次:流程命令化与 V2 拆分

本次挂在 CL856231(pending,2026-10-12):把传送编排从「大段回调 + 代次标志」改为「分阶段命令(Command)」驱动,并把 4371 行的 V2 表现单体拆成流程、组装器、命令与协作类。变更共 40 个文件:24 增、15 改、1 删。

2026-10-12 CL856231(pending) 40 文件(24 增 · 15 改 · 1 删) V2 单体 4371 → 1647 行 PIE 功能回归待测
本文只记录第二次重构 第一次重构(2026-09-07 · 结构拆分)把 TeleportController 从 3526 行收敛到 467 行、拆出六个子职责,见 TeleportController 重构 · 第一次:结构拆分。两页相互独立,可分开阅读。

1. 背景与目标

第一次拆分解决了「控制器太大」,但每条表现路径内部的阶段推进仍写成连续回调:成功、让位、失败、致命四种收口散落在各处,阶段之间缺少统一边界;V2 表现层 TeleportV2Flow.ts 单体达 4371 行,改一处要通读全文件。第二次重构做两件事:把阶段推进收敛为命令(单阶段只回答「成了没有」),把 V2 单体按职责拆开(流程持状态、组装器给计划、命令做阶段、协作类管资源与绑定)。

2. 文件变更总览

目录新增改动内容
Module/Teleport/Cmd/10—命令基类 TeleportCommandBase、上下文 TeleportCmdContext 与轮次令牌 TeleportRoundToken,以及 Init / Casting / EntryCover / Streaming / Landing / Finalize 六个阶段命令与 SeqV1、Simplified 两套组装文件
Module/Teleport/V2/11—新 TeleportV2Flow(流程躯干)、TeleportFlowAssembler(阶段计划)、TeleportV2CmdContext、常量与阶段资源/等待,以及 AvatarBinder / Seq3Binder / CameraAnchor / EntryCover / FogControl 等协作类
Module/Teleport/V2/Cmd/3—V2 三个阶段命令:TeleportLoadTransitionCmd / TeleportSequenceCmd / TeleportDownCmd
Module/Teleport/—9门面 TeleportController 接入命令线与 V2 分流;TeleportTransitionFlow、TeleportSameSceneFlow、TeleportSequenceFlow、TeleportSeq3Binder、TeleportPresentation、TeleportGroundProbe、TeleportDefine、TeleportEntityBufferController 配合调整
技能 / World / SceneLoading—6上升/下降技能 LevelSkillLogicLightTeleportUp/Down(2);GameModeModel(1,仅注释);场景加载命令 SceneLoadingWaitTeleportCmdFinishedCmd / SceneWaitWpStreamingCmd / SceneLoadingCommandHelper(3)
Module/Teleport/——删除 旧单体 TeleportV2Flow.ts(4371 行)

关键行数变化(本次实测):

文件行数说明
TeleportV2Flow.ts(旧,已删)4371V2 表现单体,本次删除
V2/TeleportV2Flow.ts(新)1647V2 流程躯干:状态与编排留在流程,具体工作下沉到协作类与命令
TeleportTransitionFlow.ts985默认线编排:持有阶段组装与 CommandExecutor,不再内联各阶段实现
TeleportController.ts718门面新增 V2 分流入口(UseTeleportV2Flow),较第一次重构后的 467 行上升
TeleportSameSceneFlow.ts921同场景流送与安全等待段
Cmd/TeleportSeqV1Cmd.ts334SeqV1 完整链的阶段命令与组装器
Cmd/TeleportSimplifiedCmd.ts201简化段 Down / Load / Seamless 三段命令与组装器

3. 命令层:四出口与轮次身份

阶段命令统一继承 TeleportCommandBase<T>,只固定两件事:阶段名(日志前缀 传送-阶段[名])与四个收口出口——Complete(成功继续)、Skip(主动让位)、Abort(失败还原)、FatalError(致命终止)。四者都先判 Executing 才结算,避免迟到回执重复收口。

Skip 走的是 Bail,是「结束本条链」而不是「跳过本步」 传送故意把「本轮让位 / 被打断」定义为结束当前阶段链,后续交给编排层,而不是让后面的阶段继续跑。这与场景加载里「条件不满足就 Succeed() 跳过继续」是两种语义。

命令之间通过 TeleportCmdContext 共享本轮状态(传送类型、参数、是否主控),并携带 TeleportRoundToken 做轮次身份隔离:每轮新建、取消后永不复用;异步等待抓到令牌后,回执到达时用 IsRoundValid 自检,不成立就 Skip 让位。命令只依赖受限接口 ITeleportStageFlow,不反向依赖流程实现——这也是它能在两套流程里复用的原因。

命令层的完整机制(四出口语义、上下文与令牌、InvalidateFlow 收口、异步「先监听再启动」)见 命令模式专栏 · 案例二 · 传送的 cmd,本文不重复。

4. 默认路径:SeqV1 完整链与 Simplified 简化段

默认线由 TeleportTransitionFlow 驱动,一个阶段一个 CommandExecutor:SeqV1 完整链用 SeqV1Executors: Set 记账,简化段用单个 SimplifiedExecutor。是否走 SeqV1 由 ShouldUseSeqV1Commands() 判定(非系统 Loading 且非淡入淡出传送)。各阶段组装命令如下:

线组装入口阶段 → 命令
SeqV1 完整链TeleportSeqV1Assembler.BuildCommands(stage)Up → Init / Casting / EntryCover;Load → LoadTransition / Streaming;Down → Sequence / Down / Landing / Finalize;ActiveUp → Casting / EntryCover
简化段TeleportSimplifiedAssembler.BuildCommands(stage, IsSceneLoading)Load → Cover(切图时仅此一条)/ Cover + Streaming;Down → Exit;Seamless → SeamlessStart

每个 executor 设 EnterSeqBackstopTimeoutMs(40 秒)作为兜底超时,正常结束时在 finally 里 RemoveExpireTime() 撤掉——是「显式设超时 + 用后移除」的正面用法,不依赖框架默认(框架默认超时只打日志、不结算)。取消整轮时 InvalidateFlow() 会作废旧令牌、换新令牌,并对挂起的流送等待与仍在跑的 executor 分别兑现与 CommandBail()。

SeqV1 完整链里仍保留一处「用户确认」等待 SeqV1 的 Init 阶段会 await ControllerHolder.QuestController.TeleportHookAsync() 等悬赏事件弹窗的用户选择。这处等待挂在阶段 40 秒兜底超时约束下(见第 7 节的 R1)。

5. V2 线:单体拆分

V2 表现(飞天遁地 / Seq 过场)是独立的第二条线,由 TeleportController 上的 UseTeleportV2Flow 开关接入(默认 false,即默认走上面的 SeqV1 / 简化线)。V2 线把旧单体拆开:

角色文件职责
流程V2/TeleportV2Flow.ts持本轮状态与编排入口:起播、加载、收尾、Tick、Seq3 剩余时长与相机转场
组装器V2/TeleportFlowAssembler.tsResolvePlan(type, isLocalPlayer) 由表现形式给出 Up / Load / Down 三段阶段计划;表现形式枚举 ETeleportPresentationForm:Seamless / BlackScreen / UiLoading / SeqV1 / SeqV2 / Simulated
上下文V2/TeleportV2CmdContext.tsV2 命令共享的本轮状态
命令V2/Cmd/Teleport{LoadTransition,Sequence,Down}Cmd.tsV2 的加载过渡、序列、下降三段阶段命令
协作类V2/TeleportV2{AvatarBinder,Seq3Binder,CameraAnchor,EntryCover,FogControl,StageResources,StageWait}.ts + TeleportV2FlowConstants.ts角色绑定、Seq3 绑定、相机锚点、入口遮挡、雾控、阶段资源与等待、常量
组装器目前是静态映射,运行期开关待接入 TeleportFlowAssembler.ResolvePlan 与 ResolveForm 的注释明确写着「按运行期开关做替换或插入……待后续步骤接入运行期开关」「占位映射,待后续步骤改为读运行期配置与开关」。也就是说当前表现形式的推导是固定映射,尚未接到运行期开关 / 配置。

V2 过场衔接的时序(Seq2 循环退出到 Seq3 起播的 7 个阶段与实测耗时)见 V2 表现 · Seq2 → Seq3 衔接问题。

6. 保留的不变量

7. 验证状态与已知遗留

检查项结果说明
变更清单40 文件CL856231(pending,2026-10-12):24 增 / 15 改 / 1 删
组装器运行期开关TODO表现形式推导暂为静态映射,运行期开关 / 配置接入待后续步骤
PIE(编辑器内运行)功能回归待测SeqV1 完整链、简化段、V2 主动传送与异常兜底路径均需回归

以下四项为代码审查阶段发现的遗留,不是本次重构本体的既定结论,均待修复 / 待确认:

编号范围问题状态
R1默认线(SeqV1)悬赏事件弹窗的用户确认(TeleportHookAsync)挂在阶段内,可能被 40 秒兜底超时取消待修
R2仅 V2TeleportV2CameraAnchor.EnsureHold 只置保持标记,缺少真实的 SwitchCamera(anchor, Level, reason)待修
R3仅 V2TeleportV2EntryCover.OpenBlack 的前置等待无轮次令牌校验待修
R4仅 V2TeleportV2FogControl 丢失 Console 高优先级写入回退,仅走 SetCVarInt32('ShowFlag.Fog')待确认

除以上四项外,默认(非 V2)路径未发现 P0 / P1 级问题。