Files
bl/docs/fight-group-implementation-checklist-2026-04-04.md
xinian 78a68148ce
Some checks failed
ci/woodpecker/push/my-first-workflow Pipeline failed
chore: update fight logic and effect implementations
2026-04-05 02:25:44 +08:00

401 lines
14 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 战斗系统对齐 `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 11v1 旧流程
- Case 22v2 双方四动作
- 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. 组队 effect501/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. 保持旧协议兼容旧入口不报错但按上述兜底规则执行