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

14 KiB
Raw Permalink Blame History

战斗系统对齐 flash/group 组队战斗实施清单(执行版)

日期2026-04-04
适用仓库:E:\newcode\sun
参考客户端仓库:E:\newcode\flash


1. 结论与范围

1.1 结论

  • sun 当前战斗系统具备多战位骨架(ActorIndex/TargetIndexOur/Opp []*input.Input),但未完成组队战斗全链路。
  • flashgroup 分支当前 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 不再包含 GroupFightDLLcore/group/* 组队代码;需参考 4c07fa07 的内容。

2.2 sun 战斗现状

  • 已有多战位骨架:
    • logic/service/fight/input.goOur/Opp []*input.Input
    • logic/service/fight/action/BattleAction.goActorIndex/TargetIndex
    • logic/service/fight/new_options.goWithFightPlayersOnSide/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
    • 最少字段:
      • phasestart/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+posactorIndex/targetIndex 转换规则写入注释

验收:

  • 旧 cmd2405/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
  • 统一“队友”查询工具函数

    • 建议在 inputfight 层提供:
      • 获取同阵营存活战位
      • 获取队友列表(排除自己)
      • 群体目标选择上限
  • 扫描组队敏感 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 testgo 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-messageseer2-server 都采用统一 team/user/pet 层级结构,position 作为战位核心字段。
    • 本仓库已具备 actorIndex/targetIndexUseSkillAt/ChangePetAt/UseItemAt 能力,协议统一后只需补齐映射和广播。
  • 实施建议:
    • 先完成“旧入口 -> 统一入站结构”映射。
    • 再完成“统一出站结构 + phase 广播”。
    • 最后做前端切换与旧包退场(或长期双通道兼容)。

AtkType 目标语义补充2026-04-05

来源:flashSkillXMLInfo.getGpFtSkillType(skillID),读取 movesMap/moveStoneMapAtkType

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.goMove 需包含 AtkType 字段解析。
  2. 动作目标不再依赖“默认 Opp 绑定”effect 上下文必须使用“本次动作的实际目标”。
  3. 需支持区分 selfally(例如同为 AtkType=1 时,不能混用同一默认目标)。
  4. 保持旧协议兼容:旧入口不报错,但按上述兜底规则执行。