Files
mtgodot-poc/audit/contracts/world.mount-pet-polymorph.md
T
shenandshen c93894313a fix: 装备属性面板避让逻辑 + 多项功能更新
- item_tooltip_view.gd: 新增 avoid_rect 属性,tooltip 与装备窗口重叠时自动推到左侧
- inventory_ui.gd: 悬停装备时传入窗口矩形作为避让区域
- 包含其他累积的功能开发和测试文件
2026-09-21 16:38:59 -07:00

84 lines
10 KiB
Markdown
Raw 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.
# world.mount_pet_polymorph
## Scope
审计 40250 Windows 客户端的角色 `mount_vnum` 接收、`GC_MOUNT` 上下马状态、骑乘/步行 motion mode、旋转速度、骑乘攻击/技能限制、变身 affect/装备遮挡,以及当前端的马匹、宠物、变身和马上技能脚本。判断标准是客户端是否与 40250 的实体字段、动作模式、门控和回包顺序统一;服务端拥有马匹等级、宠物属性、变身持续和技能伤害 authority,当前端本地 helper 能独立推进规则不能作为 parity 证明。
## Reference call chain
- `UserInterface/PythonNetworkStreamPhaseGameActor.cpp`
- Character add/additional/update packet 携带 `dwMountVnum`,交给 `CInstanceBase`;角色创建时非零 mount vnum 会进入 `MountHorse`
- `UserInterface/PythonNetworkStreamPhaseGame.cpp` / `Packet.h`
- `RecvMountPacket` 读取 `vid/mount_vid/pos/x/y`,按角色存在性处理上下马;该版本的 `Ride/Unride/SetRidingVehicleIndex` 调用被注释,不能凭空扩大为客户端结算。
- `UserInterface/InstanceBase.cpp` / `InstanceBaseMotion.cpp`
- `MountHorse/DismountHorse` 更新 horse actor、动作模式和 rotation speed;持镐、钓竿、变身、婚纱、坐骑会影响 motion mode、`CanAttack``CanUseSkill` 和武器/发型遮挡。
- `CanAttackHorseLevel` 通过 horse actor 等级限制普通攻击;新的坐骑/马术技能可由 `PythonPlayer` 的 can-use 门控决定。
- `UserInterface/PythonPlayer.cpp` / `PythonPlayerSkill.cpp` / `InstanceBase.h`
- 客户端消费 `NEW_AFFECT_POLYMORPH`/`NEW_AFFECT_MOUNT` 等状态和 skill level,阻止不允许的动作;不在客户端本地计算宠物战力、掉落、马匹成长或服务端技能伤害。
- 40250 ClientVS22 全树搜索未找到独立宠物 follow/combat authority 实现;`ITEM_TYPE_POLYMORPH` 和 polymorph skill/affect 常量存在,但其客户端职责是展示/门控/动作。
## Current call chain
- native classic parser 已将角色 add/update、additional info 和 `GC_MOUNT``mount_vnum` 写入 `EntityStore``M2Client::poll` 发出 `mount_changed`,实体 getter 能提供该字段。
- `project/net_world.gd` 保存 `mount_vnum` metadata、根据 mount 选择旋转速度并更新实体字段;`project/net_play.gd` 根据 mount/poly/weapon 刷新 local motion mode、骑乘攻击等级门和技能上下文;`EquipModel` 只用 mount 状态处理武器双手规则。
- `project/horse_system.gd``horse_combat_system.gd``horse_level_growth_system.gd``mounted_combat_skill_system.gd``pet_companion_system.gd``classic_pet_system.gd``polymorph_system.gd``polymorph_marble_system.gd` 在本地维护召唤、骑乘、耐力、宠物跟随/增益、变身时限和技能伤害。
- 当前代码搜索未发现 `mount_vnum` 被用于创建/挂接实际坐骑模型或 saddle actor 的实现;大多数 live 网络路径只保留 metadata/motion mode,宠物和变身 helper 也没有对应的 native server affect/entity 回包闭环。
## Branch matrix
| 场景 | 40250 | 当前端 | 结论 |
|---|---|---|---|
| 角色创建带 mount | add packet 的 `dwMountVnum``MountHorse`→动作/挂点;服务器字段权威 | parser/store 保存 mountNetWorld 只写 metadata,未发现 mount actor/model attach | GAP:状态字段有,视觉实体链缺失 |
| `GC_MOUNT` 上马 | 读取包,角色存在时进入 Ride 分支(本版本 Ride 调用被注释),主角色 vehicle index 也被注释 | parser 更新实体 `mount_vnum`,发 `mount_changed`NetPlay 刷 motion mode | PARTIAL:字段/动作门有,需保持与该版本注释语义一致,不能自行增加本地 ride authority |
| `GC_MOUNT` 下马 | `mount_vid==0`,服务端位置字段交给 Unride(本版本调用被注释) | mount 字段置零并刷新 motion;没有验证 x/y 下马位置和模型清理 | PARTIAL |
| 骑乘旋转/移动 | MountHorse 使用约 300°/s rotation,步行约 1200°/shorse motion mode 参与根运动 | NetPlay/NetWorld 有 horse rotation speed 和 mounted modeNetWorld 对有 mount 的真模型不推送 motion speeds | PARTIAL:常量入口接近,但实际 horse motion/模型不存在,远端骑乘 root motion 不完整 |
| 普通攻击 | `CanAttack` 受 horse level、婚纱、持镐和 actor lock 限制;等级 1 坐骑不能攻击 | NetPlay 有 `_can_attack_horse_level` 和部分新坐骑 skill gate | PARTIAL:部分映射存在,真实 horse actor 等级、服务器拒绝、动作/包副作用未完整证明 |
| 技能/武器模式 | `CanUseSkill``SetMotionMode` 受变身、婚纱、持镐、坐骑、武器类型影响 | local motion mode/skill context 有 mount/poly 字段,但 poly 字段未由 native entity 回包提供 | PARTIAL/GAP |
| 变身 | `NEW_AFFECT_POLYMORPH`/shape/parts 影响模型、装备遮挡、技能/动作门;状态来自服务器 affect/character data | `polymorph_system.gd` 直接启动、加攻防、计时、死亡取消;EquipModel 明确 `_is_poly()` 恒 false | GAP:本地 helper 有规则,live 视觉和 native affect 闭环缺失 |
| 宠物 | 40250 ClientVS22 未发现独立宠物 follow/combat authority | `pet_companion_system.gd`/`classic_pet_system.gd` 本地召唤、跟随和属性加成 | GAPcustom feature/authority):不能标记为 40250 parity |
| 马匹成长/耐力/喂养/马上技能 | 服务端/脚本权威;客户端只消费字段和动作 | 本地 helper 直接计算成长、耐力、技能 CD、伤害、库存消耗 | GAPcustom authority |
## Implementation-equivalence matrix
| 项目 | 状态 | 证据/限制 |
|---|---|---|
| Preconditions | PARTIAL | native stage/VID/mount 字段、部分死亡/技能/新坐骑门存在;角色存在、horse actor、变身 affect 和 server rejection 的完整门控未闭合 |
| Branch structure | PARTIAL | add/update/mount parser、动作模式、攻击范围/等级入口存在;ride/unride 位置、实际 mount attach、poly entity field 和 pet 分支不等价 |
| Algorithms/formulas | PARTIAL | motion mode/旋转速度和部分 mount level 表有映射;马匹成长、耐力、宠物加成、变身加攻防、马上技能伤害是本地 custom 算法 |
| State transition order | PARTIAL | server actor data→EntityStore→mount_changed→motion mode 顺序大体存在;模型 attach/detach、poly affect→装备遮挡、断线/重连和死亡清理未闭合 |
| Constants/units | PARTIAL | `mount_vnum`、马等级表、300/1200°/s、技能/affect 常量有证据;本地宠物/成长/耐力/伤害常量没有 40250 client authority 依据 |
| Timing/event sources | PARTIAL | mount signal、motion refresh、死亡/技能上下文存在;实际 ride animation、poly affect duration、server updates、重复/乱序包未覆盖 |
| Resource/data sources | GAP | 当前搜索未找到 `mount_vnum`→horse model/saddle actor 挂接;真实 horse/poly motion 资源存在与否、路径和绑定关系没有端到端证明 |
| Protocol side effects | PARTIAL | actor/mount packet parser 和 getter 存在;没有客户端等价的宠物/马战本地结算,也缺 live 上下马/变身/拒绝/重连 packet sequence |
| Interruption/failure/cleanup | GAP | 下马、角色消失、地图切换、死亡、变身过期、宠物过期、断线重连和 mount/poly model 清理未完整回归;本地 helper 可绕开服务器 authority |
## Regression evidence
- `project/test_mount_horse_parity.gd`:24/24 通过,覆盖本地马匹命令/范围 helper;不证明 `GC_MOUNT` live actor/model attach。
- `project/test_horse_combat_parity.gd`32/32、`test_horse_level_growth_parity.gd`42/42、`test_mounted_combat_skill_parity.gd`:25/25 通过;这些测试验证本地骑乘战斗、成长、耐力和技能 helper,不能作为 40250 Windows client parity。
- `project/test_pet_companion_parity.gd`40/40、`test_classic_pet_parity.gd`:31/31 通过;验证本地宠物状态/序列化,40250 ClientVS22 未发现同等宠物 authority。
- `project/test_polymorph_parity.gd`25/25、`test_polymorph_marble_parity.gd`:32/32 通过;验证本地变身 helper,但未覆盖 native affect/entity、模型 shape、装备遮挡和 server lifetime。
- `project/netplay_test.gd``project/netbridge_test.gd``build/extension/net_entity_test``build/extension/net_classic_session_test`:覆盖部分 mount 字段、motion mode 和 parser 信号;未覆盖模型挂接、GC_MOUNT 位置、poly/pet live chain、骑乘根运动、拒绝、乱序和重连清理。
## Status
## Deep audit round 2026-09-21
### Fresh regression results
- `test_mount_horse_parity.gd` 24/24、`test_horse_combat_parity.gd` 32/32、`test_horse_level_growth_parity.gd` 42/42、`test_mounted_combat_skill_parity.gd` 25/25、`test_pet_companion_parity.gd` 40/40、`test_classic_pet_parity.gd` 31/31、`test_polymorph_parity.gd` 25/25、`test_polymorph_marble_parity.gd` 32/32 均通过。
- `equip_rules_test.gd``test_battle_arena_duel_parity.gd``player_move_test.gd``netplay_test.gd` 和 native entity/session 测试退出码 0;通用 `netbridge_test.gd` 仍有 3 项实体桥接失败和 5 个 ObjectDB 泄漏。
### Static parity conclusion
- `mount_vnum` 的 parser/store/signal、部分动作模式、旋转速度和攻击等级门存在;但没有找到 `mount_vnum` 到实际 horse/saddle model attach/detach 的生产链。
- `GC_MOUNT` 的位置、下马清理、重复/乱序、断线重连和角色死亡后的模型生命周期没有闭合;本版本参考代码中 Ride/Unride 调用被注释,不能用本地 helper 自行扩大 authority。
- 变身字段没有形成 native affect→shape→装备遮挡/动作资源的完整链,`EquipModel``_is_poly()` 仍是恒 false;宠物、马匹成长/耐力/马上技能/变身加攻防由本地脚本直接结算,而 40250 Windows 客户端没有对应本地 authority。
- 所有 helper 测试通过只证明当前端自定义规则内部一致,不证明与参考客户端实现统一。
### Status update
本轮仍为 `PARTIAL`;完成坐骑、宠物和变身方向的合同审计并登记,未修改实现。
`PARTIAL`。当前端已具备 `mount_vnum` 的网络存储、mount_changed 信号、部分动作模式/旋转速度/攻击门控,并有本地马匹、宠物和变身 helper;但没有发现实际坐骑模型挂接链,变身状态尚未进入 native entity,宠物与马战/成长/耐力/伤害脚本承担了 40250 客户端没有承担的本地 authority。基础测试全部通过仍不足以证明与 40250 Windows 客户端实现统一。本轮完成审计并记录,未修改实现。