# RPG 运行时战斗后处理后端迁移落地方案(2026-04-28) ## 目标 本方案承接 `docs/audits/engineering/RPG_FRONTEND_SCRIPT_BACKEND_MIGRATION_AUDIT_2026-04-28.md` 的 4.5 项,专门收口三类仍由前端补真相的逻辑: 1. 战斗胜利 / 切磋完成后的正式 `GameState` 清理。 2. 玩家死亡后的复活场景、血蓝恢复与首场景 act 状态。 3. 战斗结束后章节 act 推进与 `currentStory.deferredOptions` 编排。 ## 边界 后端负责: 1. 根据 battle resolver 的 `outcome` 决定 `victory`、`spar_complete`、`defeat`、`escaped` 的最终状态。 2. 写回 `inBattle`、`currentEncounter`、`sceneHostileNpcs`、`currentNpcBattleOutcome`、`playerHp`、`playerMana`、`storyEngineMemory.currentSceneActState`。 3. 为死亡复活构造回到首场景的快照,并恢复 `playerHp = playerMaxHp`、`playerMana = playerMaxMana`。 4. 为胜利 / 切磋完成构造只含 `story_continue_adventure` 的当前 story,并把真实后续 options 放入 `deferredOptions`。 5. 在最后一幕或无需等待继续按钮时直接返回场景旅行 / 常规 fallback options。 前端只负责: 1. 播放 `presentation.battle` 对应动画。 2. 使用 `response.snapshot.gameState` 与 `response.snapshot.currentStory` 渲染。 3. 不再调用 `buildPostBattleVictoryState`、`buildPostBattleVictoryStory`、`buildRevivedFirstSceneState`、`buildDeathStory` 作为服务端动作后的正式状态。 ## 后端落点 1. `server-rs/crates/module-runtime-story-compat/src/post_battle.rs` - 增加纯 JSON helper,迁移战斗后状态、复活和 scene act 推进。 2. `server-rs/crates/api-server/src/runtime_story/compat.rs` - 在 `resolve_battle_action` 之后、生成 AI fallback 之前统一调用 post-battle finalizer。 3. `server-rs/crates/api-server/src/runtime_story/compat/presentation.rs` - 复用现有 option / current story 构造函数。 4. `packages/shared/src/contracts/rpgRuntimeStoryState.ts` - battle outcome 增加 `defeat`,避免前端类型层把失败误判成非战斗终局。 ## 落地补充 1. 后端 post-battle finalizer 在 `resolve_battle_action` 之后、LLM fallback 之前执行,终局战斗不再生成额外 AI 文本。 2. 胜利 / 切磋完成会清理战斗态并推进当前场景 act;非最后一幕只展示 `story_continue_adventure`,真实后续动作写入 `deferredOptions`。 3. 败北复活会先写回首场景、回满血蓝、重置首场景 act,再基于复活后的场景重新生成 `deferredOptions`,避免沿用战斗前旧场景选项。 4. story engine 投影额外接收 battle outcome;只有 `victory / spar_complete` 会记录胜利信号,`defeat` 不会被“战斗态从 true 变 false”误判成胜利。 5. 前端 `runServerRuntimeChoiceAction` 的服务端路径不再调用 `postBattleFlow` 构造正式状态;死亡动画仍可短暂播放,但最终 `GameState/currentStory` 只采用后端 hydrated snapshot。 ## 本轮收口记录 1. `choiceActions.ts` 删除 `shouldResolveCombatChoiceLocally(...)`,`battle_* / inventory_use` 不再因战斗可见态回落到本地 continuation。 2. `storyChoiceContinuation.ts` 对 `battle_* / inventory_use` 以及被分类为 `battle / escape` 的动作加硬保护,误入时不会裁决掉落、复活、任务推进或战后 story。 3. `storyChoiceRuntime.ts` 删除本地敌对 NPC 战斗奖励 helper,前端不再调用 `rollHostileNpcLoot(...)` 与 `addInventoryItems(...)` 生成正式战利品。 4. 删除 `postBattleFlow.ts` 与其测试,前端不再保留死亡复活、胜利后 story、deferred options、章节推进的正式构造函数。 5. `choiceActions.test.ts` 覆盖 `battle_use_skill`、stale `battle_attack_basic`、`inventory_use` 全部进入后端 resolver;`storyChoiceRuntime.test.ts` 继续覆盖服务端胜利 / 失败 snapshot 被直接采用。 ## 验收 1. Rust 单测覆盖: - 服务端 battle victory 返回后,`currentEncounter = null`、`inBattle = false`、`currentStory.options = [story_continue_adventure]`、`deferredOptions` 存在。 - 服务端 battle defeat 返回后,玩家复活到首场景,`playerHp/playerMana` 回满,`currentStory` 为死亡复活故事。 2. 前端单测覆盖: - `runServerRuntimeChoiceAction` 对 `victory` 和 `defeat` 都直接采用服务端 snapshot/story,不再本地构造 post battle / revive 状态。 3. 搜索确认 `src/hooks/rpg-runtime-story` 不再出现 `shouldResolveCombatChoiceLocally`、`buildPostBattleVictory*`、`buildRevivedFirstSceneState`、`buildDeathStory`、`buildHostileNpcBattleReward`。 4. Rust 单测覆盖: - story engine 对 `defeat` outcome 不写入 `win_battle` 信号和敌压 mutation。