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>
17 KiB
item.refine_socket_costume
Scope
审计强化窗口、强化请求与回包、普通/魔石/首饰镶嵌、属性添加与洗炼、时装栏位与外观更新,以及当前端额外的幻化/衣柜逻辑。判断标准不是本地字典能否算出相同结果,而是是否复现 40250 的物品原型校验、请求协议、服务器权威结果、GC_ITEM_* 状态更新、角色部件刷新、特效/资源和失败清理链。
Reference call chain
UserInterface/PythonNetworkStreamPhaseGame.cpp/PythonNetworkStreamModule.cppSendRefinePacket发送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/目标校验,不替代服务端物品变更。
- 旧、新强化包的 wire layout 不同;
UserInterface/PythonPlayer.cpp/PythonPlayerModule.cpp/PythonNetworkStreamPhaseGameItem.cppSetItemData对非零 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 选择并挂接/清理强化特效。
- 角色的 armor、weapon、hair 部件来自角色同步包;
Client/Eternexus/root/uirefine.py/uiinventory.py- 强化窗口只负责显示服务器给出的 refine table、材料库存和警告;确认/取消均发送网络请求。属性、清孔、首饰孔和物品使用入口同样依赖
item_proto的 use type 与服务器GC_ITEM_*回包。
- 强化窗口只负责显示服务器给出的 refine table、材料库存和警告;确认/取消均发送网络请求。属性、清孔、首饰孔和物品使用入口同样依赖
- 服务器权威位于
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,未证明 native255,255取消包真实发出,也未覆盖旧版 95 包。project/test_refine_effect_parity.gd:25/25 通过,覆盖本地强化等级和粒子规格;未覆盖 40250InstanceBase真实 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。