14 KiB
战斗系统对齐 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)
- 所以
groupHEAD 不再包含GroupFightDLL、core/group/*组队代码;需参考4c07fa07的内容。
2.2 sun 战斗现状
- 已有多战位骨架:
logic/service/fight/input.go:Our/Opp []*input.Inputlogic/service/fight/action/BattleAction.go:ActorIndex/TargetIndexlogic/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/fightArenaResourceLoadCMD -> 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=skill2406 -> actionType=item2407 -> actionType=change2410 -> 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_closephase=skill_wait/skill_wait_noticephase=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/overphase 均可序列化。
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.gologic/service/fight/boss/NewSeIdx_502.gologic/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.gologic/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.gologic/service/fight/cmd_unified.go(新增)logic/service/fight/info/info.gologic/service/fight/info/unified_info.go(新增)
-
控制器:
logic/controller/fight_base.gologic/controller/fight_pvp_withplayer.gologic/controller/fight_unified.go(新增)
-
核心流程:
logic/service/fight/new.gologic/service/fight/new_options.gologic/service/fight/input.gologic/service/fight/action.gologic/service/fight/loop.gologic/service/fight/fightc.go
-
Effect:
logic/service/fight/boss/NewSeIdx_501.gologic/service/fight/boss/NewSeIdx_502.gologic/service/fight/boss/NewSeIdx_503.go- 其他含组队语义的 effect 文件
-
测试:
logic/service/fight/action_test.gologic/service/fight/*_test.go(新增)
6. 里程碑与交付标准
M1(协议可通)
- 统一结构体可完成
start/skill_hurt/change/over四类下发 - 旧命令入口均可映射到
FightCindexed 接口
M2(核心可跑)
- 2v2 全回合可稳定执行
- 切宠/道具/超时可用
M3(规则可用)
- 501/502/503 完成
- 主要组队战报可用
M4(回归上线)
- 1v1 不回归
go test与go build通过- 文档补充已完成项与遗留项
7. 风险清单与缓解
-
风险:旧逻辑大量默认
CurPet[0],多人战位容易错位。
缓解:引入统一CurrentPetByActor/TargetByIndex访问函数,禁止新代码直接写死[0]。 -
风险:
enterturn兼容层导致钩子重复触发。
缓解:把“回合开始/结束”从 pair 执行中抽离,确保每回合只触发一次。 -
风险:协议切换导致旧客户端不可用。
缓解:服务端保持旧入口不变,先做“旧包 -> 统一结构”映射;前端按版本切流。 -
风险:effect 批量改动引发回归。
缓解:先做组队关键 effect,其他 effect 分批迁移并每批回归。
8. 实施顺序建议(最小阻塞)
- 协议结构与控制器入口
- 动作收集与回合统一执行
- 切宠/道具/超时按战位修正
- 关键广播与战报
- 组队 effect(501/502/503)
- 全量测试与回归
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 规则(已确认):
AtkNum:本技能同时攻击数量,默认1(不能为0)AtkType:目标范围0:所有人1:仅己方2:仅对方3:仅自己- 默认:
2
前端目标选择行为(SkillMouseController.attack(skillID, attackType)):
attackType=0->allPetWinList(全体可选)attackType=1->membPetWinList(己方可选,含自己与队友)attackType=2->oppPetWinList(敌方可选)attackType=3->[playerMode.petWin](仅自己)
后端目标关系判定(组队/多战位必须遵循):
- 若协议传
actor + target(side,pos):target.side != actor.side=> 对方目标target.side == actor.side && target.pos == actor.pos=> 自身目标target.side == actor.side && target.pos != actor.pos=> 队友目标
- 若协议未显式传目标(旧
2405):- 用
AtkType兜底:AtkType=3=> 强制自身AtkType=1=> 默认自身(无显式队友位时)- 其他 => 维持旧行为(默认对方
0位)
- 用
实施要求(与现有清单并行):
common/data/xmlres/skill.go的Move需包含AtkType字段解析。- 动作目标不再依赖“默认 Opp 绑定”;effect 上下文必须使用“本次动作的实际目标”。
- 需支持区分
self与ally(例如同为AtkType=1时,不能混用同一默认目标)。 - 保持旧协议兼容:旧入口不报错,但按上述兜底规则执行。