# 战斗系统对齐 `flash/group` 组队战斗实施清单(执行版) 日期:2026-04-04 适用仓库:`E:\newcode\sun` 参考客户端仓库:`E:\newcode\flash` --- ## 1. 结论与范围 ### 1.1 结论 - `sun` 当前战斗系统具备多战位骨架(`ActorIndex/TargetIndex`、`Our/Opp []*input.Input`),但未完成组队战斗全链路。 - `flash` 的 `group` 分支当前 HEAD 已回滚组队重构;组队实现主要存在于历史提交 `4c07fa07`。 - 因此本次不是“直接搬代码”,而是“按协议与行为对齐实现”。 ### 1.2 本清单目标 - 在不破坏现有 `1v1` 的前提下,落地组队战斗可运行版本(MVP)。 - 对齐 `flash`/社区实现中的关键行为(开战、出招、切宠、道具、结算、战斗结束)。 - 协议层采用“一个统一结构体 + phase 字段”方案,单打/双打共用同一序列化模型。 - 保留旧 `24xx/25xx` 流程入口,通过服务端适配映射到统一结构体。 ### 1.3 非目标 - 不要求一次性 100% 复刻客户端所有 UI/演出细节。 - 不要求一次性改完全部 effect;先保证核心流程可跑,再分批清理。 --- ## 2. 基线事实(实施前必须统一认知) ### 2.1 `flash` 仓库事实 - `group` 分支相对 `main` 的提交: - `4c07fa07 refactor(group-fight)`(引入组队) - `a410bfca Revert "refactor(group-fight)"`(回滚组队) - `e2382a4f`(地图重构) - `bd84f206`(.gitignore) - 所以 `group` HEAD 不再包含 `GroupFightDLL`、`core/group/*` 组队代码;需参考 `4c07fa07` 的内容。 ### 2.2 `sun` 战斗现状 - 已有多战位骨架: - `logic/service/fight/input.go`:`Our/Opp []*input.Input` - `logic/service/fight/action/BattleAction.go`:`ActorIndex/TargetIndex` - `logic/service/fight/new_options.go`:`WithFightPlayersOnSide/WithFightInputs` - 仍有关键缺口: - 控制器入站仍是单战位参数(如 `2405/2406/2407` 只传技能/道具/catchTime) - 回合主链仍以双动作兼容流程为中心 - 组队相关特性存在 TODO(例如 `501/502/503`) ### 2.3 外部实现参考(本次新增) - `arcadia-star/seer2-fight-ui` - 双打核心模型不是独立命令集,而是统一帧模型 + `uiStyle + side + position`。 - `uiStyle` 支持 `2v2/2v1`,战位通过 `position(main/sub)` 区分。 - `arcadia-star/seer2-next-message/src/entity/fight.rs` - 采用统一战斗实体结构:`team/user/pet` + `side/position`。 - 行为包拆分为 `Load/Hurt/Change/Escape/...`,但底层字段模型统一。 - `ukuq/seer2-server/src/seer2/fight` - `ArenaResourceLoadCMD -> TeamInfo -> FightUserInfo -> FighterInfo` 为层级化统一结构。 - `FighterInfo` 直接包含 `position/hp/maxHp/anger/skills`,适合直接映射为本项目统一结构体。 --- ## 3. 协议对齐清单(按优先级) > 说明:本清单改为“统一协议结构体”路线,不再强制先实现 `75xx` 独立命令族。 > 推荐做法:保留旧入口命令,服务端内部统一转为 `FightActionEnvelope/FightStateEnvelope`。 ### 3.1 P0 必做(MVP 必须) - [ ] 统一入站动作结构 `FightActionEnvelope` - 最少字段:`actionType/actorIndex/targetIndex/skillId/itemId/catchTime/escape/chat` - 兼容映射: - `2405 -> actionType=skill` - `2406 -> actionType=item` - `2407 -> actionType=change` - `2410 -> actionType=escape` - [ ] 统一出站状态结构 `FightStateEnvelope` - 最少字段: - `phase`(`start/skill_hurt/change/over/load/chat`) - `left[]/right[]`(元素为统一 `FighterState`) - `meta`(回合号、天气、胜负、结束原因) - [ ] 统一战位子结构 `FighterState` - 每项至少包含:`side/position(userSlot)/userId/petId(catchTime)/hp/maxHp/level/anger/status/prop/skills` ### 3.2 P1 强烈建议(提升一致性) - [ ] 完善 `phase=skill_hurt` - 至少带:施法方快照、受击方快照、技能、暴击、伤害、HP 变更 - [ ] 完善 `phase=change` - 至少带:切宠发起位、切入目标位、新精灵状态 - [ ] 完善 `phase=over` - 至少带:结束原因、胜方、收益主体 - [ ] 完善 `phase=load/chat` - 组队加载进度、战斗内聊天统一走同一 envelope ### 3.3 P2 视时间补齐 - [ ] `phase=sprite_die/sprite_notice/win_close` - [ ] `phase=skill_wait/skill_wait_notice` - [ ] `phase=overtime/timeout_exit/relation_notice` --- ## 4. 代码改造任务清单(可直接分工) ## 4.1 协议与结构层(Owner A) - [ ] 新增统一协议结构文件 - 建议新建:`logic/service/fight/cmd_unified.go` - 要求:统一定义 `FightActionEnvelope` 和映射辅助结构 - [ ] 新增统一出站结构 - 建议新建:`logic/service/fight/info/unified_info.go` - 要求:定义 `FightStateEnvelope/FighterState`,支持单打与双打 - [ ] 统一战位字段命名规范 - `actorIndex`:我方执行位 - `targetIndex`:敌方目标位 - `side+pos` 与 `actorIndex/targetIndex` 转换规则写入注释 验收: - [ ] 旧 cmd(`2405/2406/2407/2410`)可无损映射到统一入站结构。 - [ ] 统一出站结构在 `start/skill_hurt/change/over` phase 均可序列化。 --- ## 4.2 控制器与路由层(Owner B) - [ ] 新增统一动作入口(可单文件) - 建议新建:`logic/controller/fight_unified.go` - 用途:将旧包和未来扩展包统一落到 `FightActionEnvelope` - [ ] 兼容旧协议入口 - `2405/2406/2407` 保持可用(默认 `actorIndex=0,targetIndex=0`) - 组队场景由 `actorIndex/targetIndex` 与战斗上下文决定,不再依赖独立 `75xx` - [ ] 增加战前校验 - 成员是否在同一组队房间 - 战斗状态互斥 - 战位可操作权限 验收: - [ ] 任意技能动作都能转化为 `UseSkillAt(...)`(含 `actorIndex/targetIndex`)。 - [ ] 非法战位命令被拒绝,不影响其他战位。 --- ## 4.3 战斗核心层(Owner C) - [ ] 固化“多动作一回合”模型 - `collectPlayerActions`:按预期战位数收集,不是按两人收集 - `resolveRound`:每回合一次统一排序与执行 - [ ] 降低对“双动作 enterturn”的耦合 - 当前 `enterturn(first, second)` 作为兼容层保留 - 新逻辑要确保: - 回合开始钩子只执行一次/回合 - 回合结束钩子只执行一次/回合 - 不因 pair 分片导致重复触发 - [ ] 完善动作-战位映射 - `GetInputByAction` 在组队模式下严格按 `playerID + actorIndex/targetIndex` 定位 - 超时补默认动作按战位补齐 - [ ] 完善死亡换宠/主动换宠 - 按 actorIndex 粒度处理 - 切宠广播必须携带 actor 位信息 验收: - [ ] 2v2 场景一回合四动作都参与排序,不丢动作。 - [ ] 同玩家多战位动作不会互相覆盖。 - [ ] 任一战位死亡只影响对应战位换宠链路。 --- ## 4.4 组队战报与广播层(Owner D) - [ ] 统一战报快照结构 - 至少包含: - 施法方:`userId/actorIndex/skillId/crit/dmg/hpAfter/status/prop` - 受击方:`userId/actorIndex/hpAfter/status/prop` - [ ] 完成关键广播 - 开战广播 - 技能结果广播 - 切宠成功广播 - 战斗结束广播 - [ ] 保留旧包兼容(必要时双发) - 单打/双打统一走同一结构体 - 如前端未升级,可按需保留旧 `2503/2505/2506` 过渡映射 验收: - [ ] 观战端/队友端收到的战位与 HP 同步一致。 - [ ] 切宠后不会出现“错位显示”。 --- ## 4.5 Effect 与规则层(Owner E) - [ ] 先补明确组队依赖效果 - `logic/service/fight/boss/NewSeIdx_501.go` - `logic/service/fight/boss/NewSeIdx_502.go` - `logic/service/fight/boss/NewSeIdx_503.go` - [ ] 统一“队友”查询工具函数 - 建议在 `input` 或 `fight` 层提供: - 获取同阵营存活战位 - 获取队友列表(排除自己) - 群体目标选择上限 - [ ] 扫描组队敏感 effect - 特别关注含“组队对战时无效”描述项(如 effect 457) - 明确:是直接禁用,还是按组队模式替代逻辑 验收: - [ ] `501/502/503` 在 2v2 场景行为符合设计。 - [ ] 组队模式下不再出现空指针或越界。 --- ## 4.6 测试与回归(Owner F) - [ ] 单测补齐 - `logic/service/fight/action_test.go`:继续扩充多战位覆盖 - 新增建议: - `logic/service/fight/loop_multi_test.go` - `logic/service/fight/fight_group_test.go` - [ ] 集成回归用例(最少) - Case 1:1v1 旧流程 - Case 2:2v2 双方四动作 - Case 3:同一玩家两战位各自出招 - Case 4:中途切宠 + 被动死亡切宠 - Case 5:超时默认动作补齐 - Case 6:逃跑/掉线结束 - [ ] 构建与测试命令 - `cd logic && go test ./service/fight/...` - `cd logic && go test ./controller/...` - `cd logic && go build ./...` --- ## 5. 文件级任务地图(便于派工) - 协议/结构: - `logic/service/fight/cmd.go` - `logic/service/fight/cmd_unified.go`(新增) - `logic/service/fight/info/info.go` - `logic/service/fight/info/unified_info.go`(新增) - 控制器: - `logic/controller/fight_base.go` - `logic/controller/fight_pvp_withplayer.go` - `logic/controller/fight_unified.go`(新增) - 核心流程: - `logic/service/fight/new.go` - `logic/service/fight/new_options.go` - `logic/service/fight/input.go` - `logic/service/fight/action.go` - `logic/service/fight/loop.go` - `logic/service/fight/fightc.go` - Effect: - `logic/service/fight/boss/NewSeIdx_501.go` - `logic/service/fight/boss/NewSeIdx_502.go` - `logic/service/fight/boss/NewSeIdx_503.go` - 其他含组队语义的 effect 文件 - 测试: - `logic/service/fight/action_test.go` - `logic/service/fight/*_test.go`(新增) --- ## 6. 里程碑与交付标准 ### M1(协议可通) - [ ] 统一结构体可完成 `start/skill_hurt/change/over` 四类下发 - [ ] 旧命令入口均可映射到 `FightC` indexed 接口 ### M2(核心可跑) - [ ] 2v2 全回合可稳定执行 - [ ] 切宠/道具/超时可用 ### M3(规则可用) - [ ] 501/502/503 完成 - [ ] 主要组队战报可用 ### M4(回归上线) - [ ] 1v1 不回归 - [ ] `go test` 与 `go build` 通过 - [ ] 文档补充已完成项与遗留项 --- ## 7. 风险清单与缓解 - 风险:旧逻辑大量默认 `CurPet[0]`,多人战位容易错位。 缓解:引入统一 `CurrentPetByActor`/`TargetByIndex` 访问函数,禁止新代码直接写死 `[0]`。 - 风险:`enterturn` 兼容层导致钩子重复触发。 缓解:把“回合开始/结束”从 pair 执行中抽离,确保每回合只触发一次。 - 风险:协议切换导致旧客户端不可用。 缓解:服务端保持旧入口不变,先做“旧包 -> 统一结构”映射;前端按版本切流。 - 风险:effect 批量改动引发回归。 缓解:先做组队关键 effect,其他 effect 分批迁移并每批回归。 --- ## 8. 实施顺序建议(最小阻塞) 1. 协议结构与控制器入口 2. 动作收集与回合统一执行 3. 切宠/道具/超时按战位修正 4. 关键广播与战报 5. 组队 effect(501/502/503) 6. 全量测试与回归 --- ## 9. 交接要求(给执行同学) - 每完成一个里程碑,在 `docs/` 新增一段“完成项/未完成项/阻塞项”。 - 如改动协议字段,必须附抓包样例或字段注释,不允许只改代码不补说明。 - 如发现与本清单冲突的历史逻辑,以“兼容线上行为优先”,并在文档记录偏差原因。 --- ## 10. 可实现性结论(统一协议结构体) - 结论:可实现,且风险可控。 - 依据: - `seer2-fight-ui` 的双打模型本质是统一数据结构 + `uiStyle/side/position`,不是强依赖独立命令族。 - `seer2-next-message` 与 `seer2-server` 都采用统一 `team/user/pet` 层级结构,`position` 作为战位核心字段。 - 本仓库已具备 `actorIndex/targetIndex` 与 `UseSkillAt/ChangePetAt/UseItemAt` 能力,协议统一后只需补齐映射和广播。 - 实施建议: - 先完成“旧入口 -> 统一入站结构”映射。 - 再完成“统一出站结构 + phase 广播”。 - 最后做前端切换与旧包退场(或长期双通道兼容)。 --- ## AtkType 目标语义补充(2026-04-05) 来源:`flash` 端 `SkillXMLInfo.getGpFtSkillType(skillID)`,读取 `movesMap/moveStoneMap` 的 `AtkType`。 GBTL 规则(已确认): 1. `AtkNum`:本技能同时攻击数量,默认 `1`(不能为 `0`) 2. `AtkType`:目标范围 - `0`:所有人 - `1`:仅己方 - `2`:仅对方 - `3`:仅自己 - 默认:`2` 前端目标选择行为(`SkillMouseController.attack(skillID, attackType)`): 1. `attackType=0` -> `allPetWinList`(全体可选) 2. `attackType=1` -> `membPetWinList`(己方可选,含自己与队友) 3. `attackType=2` -> `oppPetWinList`(敌方可选) 4. `attackType=3` -> `[playerMode.petWin]`(仅自己) 后端目标关系判定(组队/多战位必须遵循): 1. 若协议传 `actor + target(side,pos)`: - `target.side != actor.side` => 对方目标 - `target.side == actor.side && target.pos == actor.pos` => 自身目标 - `target.side == actor.side && target.pos != actor.pos` => 队友目标 2. 若协议未显式传目标(旧 `2405`): - 用 `AtkType` 兜底: - `AtkType=3` => 强制自身 - `AtkType=1` => 默认自身(无显式队友位时) - 其他 => 维持旧行为(默认对方 `0` 位) 实施要求(与现有清单并行): 1. `common/data/xmlres/skill.go` 的 `Move` 需包含 `AtkType` 字段解析。 2. 动作目标不再依赖“默认 Opp 绑定”;effect 上下文必须使用“本次动作的实际目标”。 3. 需支持区分 `self` 与 `ally`(例如同为 `AtkType=1` 时,不能混用同一默认目标)。 4. 保持旧协议兼容:旧入口不报错,但按上述兜底规则执行。