These files were loaded only by their own test_*_parity.gd and never by the runtime (transitively checked, incl. client_phase_integration_system). Removes 76 manifest implementation/evidence references across 18 contracts; contract docs get a note that conclusions based on them are void. Live systems kept: chest, consumable, item_attr, metin_socket, whisper_chat. Full headless suite: no new failures (7 failing + 5 headless-hanging render tests are identical before the deletion). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
127 lines
17 KiB
Markdown
127 lines
17 KiB
Markdown
# item.refine_socket_costume
|
||
|
||
## Scope
|
||
|
||
审计强化窗口、强化请求与回包、普通/魔石/首饰镶嵌、属性添加与洗炼、时装栏位与外观更新,以及当前端额外的幻化/衣柜逻辑。判断标准不是本地字典能否算出相同结果,而是是否复现 40250 的物品原型校验、请求协议、服务器权威结果、`GC_ITEM_*` 状态更新、角色部件刷新、特效/资源和失败清理链。
|
||
|
||
## Reference call chain
|
||
|
||
- `UserInterface/PythonNetworkStreamPhaseGame.cpp` / `PythonNetworkStreamModule.cpp`
|
||
- `SendRefinePacket` 发送 `CG_REFINE(pos,type)`;40250 取消强化使用 `(255,255)`,写包后进入序列发送。
|
||
- `RecvRefineInformationPacket` 解析旧版 `GC_REFINE_INFORMATION(95)`;`RecvRefineInformationPacketNew` 解析新版 `GC_REFINE_INFORMATION_NEW(119)`,两者都把服务端给出的源物品、结果 vnum、费用、概率和材料交给 `OpenRefineDialog`。
|
||
- 强化信息由服务器提供,客户端不拥有强化成功率、结果 vnum、费用或材料公式。
|
||
- `UserInterface/Packet.h` / `GameLib/ItemData.cpp` / `PythonItemModule.cpp`
|
||
- 旧、新强化包的 wire layout 不同;`ITEM_USE` 子类型包括 `USE_TUNING`、`USE_CLEAN_SOCKET`、`USE_CHANGE_ATTRIBUTE`、`USE_ADD_ATTRIBUTE`、`USE_ADD_ATTRIBUTE2`、`USE_ADD_ACCESSORY_SOCKET`、`USE_PUT_INTO_ACCESSORY_SOCKET` 等。
|
||
- ItemData 提供 `GetSocket`、`GetSocketCount`、`GetRefine`、`GetRefinedVnum`、`GetValue`、flags/anti-flags、装备类型和外观资源;客户端用这些信息做 UI/目标校验,不替代服务端物品变更。
|
||
- `UserInterface/PythonPlayer.cpp` / `PythonPlayerModule.cpp` / `PythonNetworkStreamPhaseGameItem.cpp`
|
||
- `SetItemData` 对非零 vnum 先验证 ItemManager;`SetItemCount`、socket、attribute 按服务器回包写入本地物品,并刷新窗口。
|
||
- `CanRefine`、`CanAttachMetin` 等只依据 ItemManager 的真实 type/subtype/flag/socket 数据判断允许与否,然后由物品使用协议请求服务端执行。
|
||
- 物品更新顺序是服务器回包驱动的 count、socket、attribute 与窗口刷新,不是 UI 或脚本直接扣除材料。
|
||
- `UserInterface/InstanceBase.cpp` / `PythonNetworkStreamPhaseGameActor.cpp`
|
||
- 角色的 armor、weapon、hair 部件来自角色同步包;`SetArmor` 通过 ItemData 映射模型、specular 和强化特效,`SetHair`/weapon attachment 刷新实际角色模型。
|
||
- `__GetRefinedEffect` 按 ItemData 的 refine/socket/type/subtype 选择并挂接/清理强化特效。
|
||
- `Client/Eternexus/root/uirefine.py` / `uiinventory.py`
|
||
- 强化窗口只负责显示服务器给出的 refine table、材料库存和警告;确认/取消均发送网络请求。属性、清孔、首饰孔和物品使用入口同样依赖 `item_proto` 的 use type 与服务器 `GC_ITEM_*` 回包。
|
||
- 服务器权威位于 `Server/metin2/src/server/game/src/char_item.cpp`、`item.cpp`、`item_attribute.cpp` 及 `item_proto`。这些文件决定属性池、概率、socket/强化限制、消耗和最终 item data;客户端源码没有对应的独立权威算法。
|
||
|
||
## Current call chain
|
||
|
||
- `project/ui/refine_ui.gd` 已接收 `M2Client.refine_ask`,显示材料/概率/费用并调用 `M2Client.refine`;`extension/src/net/classic/classic_session.cpp` 已能构造 `CGRefine`,`EntityStore` 已有 `RefineCue`。
|
||
- `extension/src/net/m2_client.cpp::refine` 只允许 `0 <= pos < INVENTORY_MAX_NUM`,所以 `RefineUI.cancel_refine()` 发出的 40250 取消哨兵 `255,255` 在 native 层直接返回 false,未到达服务器。
|
||
- `extension/src/net/classic/classic_parser.cpp` 已分别解析旧版 `GCRefineInfoOld`(95,59 字节,无 type)和新版 `GCRefineInfo`(119,60 字节,有 type),并将两者送入 `EntityStore::mut_refine`;旧版 wire layout 本身已补齐,但旧版真实服务器回包和类型默认值仍缺端到端 fixture。
|
||
- `project/item_attr_system.gd`、`item_enchant_system.gd` 直接在传入 `Dictionary/Array` 上生成/重置普通和稀有属性并扣本地卷轴;没有调用 `M2Client::use_item_to_item`、等待 `GC_ITEM_UPDATE` 或从 ItemManager 读取真实 use subtype/attribute set。
|
||
- `project/jewelry_socket_system.gd` 直接用硬编码 vnum、首饰 vnum 前缀、成功率、寿命和 bonus tier 修改 sockets/gem_times;没有通过 40250 的 `ITEM_USE`/`USE_ADD_ACCESSORY_SOCKET`/`USE_PUT_INTO_ACCESSORY_SOCKET` 请求和服务器更新闭环。
|
||
- `project/costume_system.gd` 维护独立的 `equipped_costumes`,复制传入时装、默认本地 7 天计时并计算 bonus/model_id;未发现它接入 `M2Client`、EntityStore 的 equipment 回包或 `project/ui/equip_model.gd` 的角色部件更新。
|
||
- `project/costume_attr_transfer_system.gd` 和 `project/wardrobe_transmog_system.gd` 直接修改库存、金币、属性和 `transmog_*` 字段。现有 40250 客户端源码中没有与 `wardrobe_transmog_system.gd` 对应的幻化协议/角色字段,因此它是当前端自定义扩展,不应标记为 40250 已实现。
|
||
- `project/refine_effect_system.gd` 有本地强化光效规格和粒子测试,但尚未证明由权威装备回包触发,且当前模型/角色路径与 40250 的 `InstanceBase` 部件、ItemData 和 effect attach 链未形成端到端测试。
|
||
|
||
## Branch matrix
|
||
|
||
| 场景 | 40250 | 当前端 | 结论 |
|
||
|---|---|---|---|
|
||
| 打开强化窗口 | 服务器发送旧/新版 refine info;客户端按 packet layout 交给 UI | native parser 已分别接受 95/119 并生成 cue | PARTIAL:旧版真实回包与 UI 行为缺 fixture |
|
||
| 强化确认 | UI 发 `CG_REFINE(pos,type)`,结果和消耗由服务器回包决定 | 正常 pos/type 可发 `CGRefine` | PARTIAL:缺完整成功/失败后的 item/point/effect 顺序证明 |
|
||
| 强化取消/超距/ESC | 发送 `CG_REFINE(255,255)` | `RefineUI` 调用 `refine(255,255)`,native 范围校验先拒绝 | GAP |
|
||
| 强化数据来源 | `src_vnum/result_vnum/cost/prob/materials` 全部服务端提供 | `RefineCue` 能保存字段,窗口能显示 | MAPPED + tests:旧包与真实回包覆盖不足 |
|
||
| 普通/魔石/首饰镶嵌 | ItemManager use subtype/flag/socket 校验后发物品使用请求,服务器改 item data | 本地系统按字典直接改 socket/attrs | GAP |
|
||
| 属性添加/洗炼/第五属性 | 客户端显示 ItemData/回包,成功率和属性生成在服务器 `char_item.cpp/item_attribute.cpp` | 本地硬编码池/概率并直接写 attrs | GAP:算法复制不等于客户端协议实现 |
|
||
| 稀有属性 6/7 条 | 在当前 40250 客户端引用中未找到与当前 71151/71152 本地系统相同的完整客户端链 | `ItemEnchantSystem` 本地新增稀有池并直接扣卷轴 | CUSTOM/PARTIAL,不能宣称 40250 1:1 |
|
||
| 时装穿戴/卸下 | 角色同步包给 armor/weapon/hair 部件,ItemData/InstanceBase 刷新模型与强化效果 | `CostumeSystem` 只更新本地字典和信号;未接 actor/model 回包 | GAP |
|
||
| 时装属性/限时 | 服务器 item data/affect/point 回包决定状态 | 本地 `bonuses` 与 `remaining_time` 逐帧扣减 | PARTIAL:缺权威计时、point/affect 和过期回包 |
|
||
| 幻化/衣柜 | 40250 客户端源码未找到相同协议或 `transmog_*` 角色部件链 | 本地直接扣金币/卷轴/皮肤并改字段 | CUSTOM,不属于已验证的 40250 parity |
|
||
| 强化外观效果 | `InstanceBase::__GetRefinedEffect` 依 ItemData 的 refine/socket/type/subtype attach/clear effect | 本地 `RefineEffectSystem` 可计算规格并创建粒子 | PARTIAL:资源、部件更新和清理未闭环 |
|
||
|
||
## Implementation-equivalence matrix
|
||
|
||
| 项目 | 状态 | 证据/限制 |
|
||
|---|---|---|
|
||
| Preconditions | PARTIAL | refine 基础 pos 校验存在;取消哨兵被错误拒绝;属性/socket/costume helper 不统一使用 ItemManager 的 type/subtype/flag/anti-flag/equipment slot 校验 |
|
||
| Branch structure | PARTIAL | 强化 UI 分支和 native 请求存在;本地属性、镶嵌、时装操作绕过 `CG_ITEM_USE`/`GC_ITEM_UPDATE`,并增加了参考端不存在的幻化分支 |
|
||
| Algorithms/formulas | PARTIAL | 40250 的强化、属性、socket 结果由服务器权威计算;当前本地池/概率/寿命只通过孤立测试,不能证明与运行时服务端一致 |
|
||
| State transition order | GAP | 参考是请求→服务器判定→`GC_ITEM_*`/point/affect/actor update→刷新;当前多个 helper 是本地立即写入和发 signal |
|
||
| Constants/units | PARTIAL | refine packet header/字段和部分 vnum 已定位;socket 前缀、gem tier、时装 7 天、幻化 1000 万等硬编码未由当前 40250 运行时数据链证明 |
|
||
| Timing/event sources | PARTIAL | RefineCue/signal/UI 事件存在;旧包、取消包、真实 item update/actor update 顺序和过期竞态未覆盖 |
|
||
| Resource/data sources | PARTIAL | 当前可读部分 item proto/模型数据;属性池、socket 规则和 costume model_id 多来自脚本常量,未接 40250 ItemData/资源选择链 |
|
||
| Protocol side effects | PARTIAL | `CGRefine` 和基础 refine cue 存在;取消 sentinel、旧 refine header、item-use/socket/costume request、SendSequence/失败反馈未完整闭合 |
|
||
| Interruption/failure/cleanup | GAP | 本地操作成功前就能改变库存/金币/attrs/sockets;网络拒绝、重复回包、断线、换图、时装过期和 actor model 清理没有同一权威回滚路径 |
|
||
|
||
## Regression evidence
|
||
|
||
- `project/test_refine_parity.gd`:通过,覆盖窗口显示、材料颜色、确认/取消 UI 规则和超距行为;使用 fake client,未证明 native `255,255` 取消包真实发出,也未覆盖旧版 95 包。
|
||
- `project/test_refine_effect_parity.gd`:25/25 通过,覆盖本地强化等级和粒子规格;未覆盖 40250 `InstanceBase` 真实 ItemData 部件更新、attach/clear 和资源加载失败。
|
||
- `project/test_item_attr_parity.gd`:28/28 通过;`project/test_item_enchant_manager_parity.gd`:36/36 通过。两者都直接对 `Dictionary` 做本地生成/扣除,未启动服务器或消费 `GC_ITEM_UPDATE`。
|
||
- `project/test_jewelry_socket_parity.gd`:23/23 通过;覆盖本地打孔/镶嵌/寿命计算,但没有 40250 物品使用协议、ItemData socket count、服务器拒绝或回包。
|
||
- `project/test_costume_system_parity.gd`:23/23 通过;`project/test_costume_attr_transfer_parity.gd`:23/23 通过;`project/test_wardrobe_transmog_parity.gd`:22/22 通过。它们验证本地 helper 的字典和 signal 行为,不能证明角色模型、服务端库存/金币或 40250 客户端协议等价。
|
||
- native/refine 现有测试覆盖 `CGRefine`/cue 基础布局,但未覆盖 `GC_REFINE_INFORMATION(95)` 与 `(119)` 双版本解析、`255,255` 取消发送和 refine 后 item/point/affect/actor 更新顺序。
|
||
|
||
## Deep audit round 2026-09-21
|
||
|
||
### Fresh regression results
|
||
|
||
- `godot --headless --path project --script test_refine_parity.gd`:退出码 0;强化窗口/材料/确认/取消 UI 规则通过,但 fake client 不能证明 native 取消包真正发出。
|
||
- `godot --headless --path project --script test_refine_effect_parity.gd`:退出码 0,25/25 通过;只证明本地强化等级到粒子规格的映射。
|
||
- `godot --headless --path project --script test_item_attr_parity.gd`:退出码 0,28/28 通过;只证明本地属性字典算法。
|
||
- `godot --headless --path project --script test_item_enchant_manager_parity.gd`:退出码 0,36/36 通过;只证明本地普通/稀有属性管理器的直接修改路径。
|
||
- `godot --headless --path project --script test_jewelry_socket_parity.gd`:退出码 0,23/23 通过;只证明本地首饰打孔、镶嵌和寿命计算。
|
||
- `godot --headless --path project --script test_costume_system_parity.gd`、`test_costume_attr_transfer_parity.gd`、`test_wardrobe_transmog_parity.gd`:均退出码 0,分别 23/23、23/23、22/22 通过;验证的是本地时装/属性转移/幻化字典状态,不是服务器权威链路。
|
||
- `godot --headless --path project --script guild_refine_test.gd`:退出码 0,确认 UI 取消会调用 `client.refine(255,255)`。
|
||
- `./build/extension/net_classic_session_test`、`./build/extension/net_entity_test`:均退出码 0;native 基础 refine/DS refine 包和新版 cue 通过。源码复核确认 parser 已分别支持旧版 95(59 字节)与新版 119(60 字节)。
|
||
|
||
### Static parity findings
|
||
|
||
- 当前明确的协议缺陷仍是 `M2Client::refine` 要求 `0 <= pos < INVENTORY_MAX_NUM`;因此 `RefineUI.cancel_refine()` 发出的 40250 取消哨兵 `(255,255)` 在 native 层被拒绝,`ClassicSession::send_refine` 虽可编码该字节,但 UI 入口到不了它。
|
||
- 旧/新版 refine parser 已经分别存在,先前“旧版 95 包被统一结构丢弃”的判断已纠正;尚缺旧版实际字节 fixture、旧包 `type=0` 对 UI 分支的行为和成功/失败后的 item/point/actor 更新时序。
|
||
- 40250 的属性、socket、装备外观和时装穿戴依赖 ItemManager/ItemData + `CG_ITEM_USE`/`CG_ITEM_USE_TO_ITEM` + 服务器 `GC_ITEM_*`/affect/point/character parts;当前 `ItemAttrSystem`、`ItemEnchantSystem`、`JewelrySocketSystem`、`CostumeSystem` 仍能直接修改传入字典、金币、socket、attributes 或本地计时。
|
||
- 当前 `CostumeSystem` 的 bonus/model/7 天过期以及 `wardrobe_transmog_system.gd` 的金币/卷轴扣除都没有连接 EntityStore equipment/point/affect 回包;幻化分支在 40250 源码中没有对应协议,应继续标记为 CUSTOM,而不是 parity 已实现。
|
||
- `EquipModel` 存在由 equipment 状态刷新强化光效的路径,但本轮没有证明 refine 后 `GC_ITEM_UPDATE` 与 character part/模型资源更新按 40250 顺序触发,资源失败和清理也未闭合。
|
||
|
||
### Round conclusion
|
||
|
||
本轮仍为 `PARTIAL`:旧/新版 refine 解析已确认存在,强化/DS 基础包和局部 UI 测试通过;但取消 sentinel 是明确失败点,本地属性/镶嵌/时装/幻化旁路仍绕过服务器权威结果,真实 item/point/affect/actor 更新和失败清理尚未与 40250 统一。本轮未修改实现代码。
|
||
|
||
## Next audit round 2026-09-20T18:19Z
|
||
|
||
本轮对强化/镶嵌/时装链进行一次入口级复核,重点验证 UI 认为“已发出”的请求是否真的能穿过 native 层:
|
||
|
||
- `RefineUI.cancel_refine()` 按 40250 发送 `client.refine(255, 255)`,但 `M2Client::refine`(`extension/src/net/m2_client.cpp:2351-2356`)要求 `pos >= 0 && pos < INVENTORY_MAX_NUM`,因此取消请求在 native 入口直接返回 `false`;`ClassicSession::send_refine` 的字节编码能力无法弥补这个前置门。现有 `test_refine_parity.gd` 使用 fake client,不能捕获该失败。
|
||
- `RecvRefineInformationPacket`(95)和 `RecvRefineInformationPacketNew`(119)均已在 parser 中存在,本轮没有把此前的“旧包完全缺失”继续列为事实;但旧版真实字节 fixture、`type=0` 的 UI 分支和强化后 `GC_ITEM_UPDATE`/point/affect/actor 更新顺序仍没有证据。
|
||
- `ItemAttrSystem`、`ItemEnchantSystem`、`JewelrySocketSystem`、`CostumeSystem` 仍直接修改传入字典、属性、socket、金币或本地剩余时间;40250 客户端对应入口只做 ItemData 校验并发 `CG_ITEM_USE`/`CG_ITEM_USE_TO_ITEM`,结果由服务器回包驱动。局部脚本测试通过不能证明这两条链统一。
|
||
|
||
本轮没有修改实现代码。合同继续为 `PARTIAL`,其中取消 sentinel 是可直接复现的协议级差异,优先级高于继续增加本地属性公式测试。
|
||
|
||
## Status
|
||
|
||
`PARTIAL`。强化窗口已有可用的新版协议骨架和本地 UI 回归;属性、socket、时装和幻化的本地脚本测试通过,实际实现仍主要是本地字典状态机,尚未复现 40250 的 ItemManager→CG 请求→服务器权威结果→GC item/actor/model 更新完整链路。
|
||
|
||
## Implementation fix round 2026-09-21
|
||
|
||
- `mtnet::bounds::refine_request` 与 `M2Client::refine` 现在保留普通库存位置校验,同时按 40250 接受强化取消哨兵 `(255,255)`;`net_bounds_test` 覆盖普通位置、哨兵和非法混合值。
|
||
- `test_refine_parity.gd`/`guild_refine_test.gd` 仍证明 UI 会发出取消调用;native 回归现在证明该调用不会在入口被错误拦截。真实服务器回包、旧版 95 字节 fixture 和强化后权威 item/point/actor 顺序仍待补齐。
|
||
- `EntityStore` 的正 HP 点数更新会清除 `dead`,`M2Client` 会重置 `dead_seen`,保证复活后下一次死亡可以再次发出 `entity_dead`。
|
||
|
||
本合同继续为 `PARTIAL`:本轮只修复了可直接验证的协议边界和死亡状态边沿,没有把本地属性/镶嵌/时装旁路误标为 40250 等价实现。
|
||
|
||
### 2026-09-22 死代码删除
|
||
|
||
以下文件只被自身测试引用、运行时从不加载,已删除;本文中以它们为实现或证据的结论作废,相关行为需按 40250 源码单元重新移植:`costume_attr_transfer_system.gd`, `costume_system.gd`, `item_enchant_system.gd`, `jewelry_socket_system.gd`, `refine_effect_system.gd`, `test_costume_attr_transfer_parity.gd`, `test_costume_system_parity.gd`, `test_item_enchant_manager_parity.gd`, `test_jewelry_socket_parity.gd`, `test_refine_effect_parity.gd`, `test_wardrobe_transmog_parity.gd`, `wardrobe_transmog_system.gd`。
|