Files
mtgodot-poc/audit/contracts/world.npc-drop-actor-spawn.md
T
shenleiandClaude Opus 5 a989b8f19b chore: delete 106 unreachable *_system.gd and their parity tests
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>
2026-09-22 17:51:52 +09:00

13 KiB
Raw Blame History

world.npc_drop_actor_spawn

Scope

审计 40250 Windows 客户端的 NPC、怪物、石头、建筑/墙体、玩家实体、地面掉落、所有权、私人商店招牌和实体清理链。判断标准是实体是否按相同的包字段、VID 生命周期、分类、可见性、模型/动作资源、名字尾标、掉落所有权和删除时序进入客户端;服务端掉落概率、散落规则或本地活动规则不能因为在当前端有脚本就当作 40250 客户端等价实现。

Reference call chain

  • UserInterface/PythonNetworkStreamPhaseGameActor.cpp
    • RecvCharacterAppendPacket / RecvCharacterAdditionalInfo / RecvCharacterUpdatePacket 解包 race、character type、parts、affect、位置、速度、名字、公会、等级、mount 等字段;不可见 race 不创建实例;角色新增最终进入 CNetworkActorManager / CInstanceBase,非零 mount vnum 由角色实例处理。
    • RecvCharacterDeletePacket 通过 actor manager 删除 VID,并同步通知私人商店消失。
    • RecvOwnerShipPacket 把 owner VID 与 victim VID 写入网络 actor manager。
  • UserInterface/NetworkActorManager.cpp / UserInterface/PythonCharacterManager.cpp / UserInterface/InstanceBase.cpp
    • actor manager 负责 add/update/move/delete、VID 查找和实例状态;character manager 负责碰撞、拾取、排序、距离可见性和渲染列表;CInstanceBase 按 race/type 选择模型、动作、名字和状态。
    • 40250 的可见性由 CHAR_STAGE_VIEW_BOUNDAFFECT_SHOW_ALWAYS 和 wall 判定共同决定;离开范围时走 delete/blend-out,数据与渲染实例不是同一层。
  • UserInterface/PythonNetworkStreamPhaseGameItem.cpp / UserInterface/PythonItem.cpp / UserInterface/PythonTextTail.cpp / Packet.h
    • RecvItemGroundAddPacket 将全局坐标转本地坐标后调用 CPythonItem::CreateItem(vid, vnum, x, y, z);未知 item data 不创建地面物体。
    • RecvItemOwnership 调用 SetOwnership(vid, name),更新独立 owner 尾标;RecvItemGroundDelPacket 删除地面实例并删除对应 item text tail。
    • CreateItemCItemData::GetDropModelThing() 建立掉落模型,注册 item text tailGetCloseMoney / GetCloseItem、模型拾取和网络 CG_ITEM_PICKUP 负责交互,服务器回包才完成真正拾取。
  • UserInterface/PythonNetworkStreamPhaseGame.cpp
    • RecvShopSignPacket 对空 sign 触发 BINARY_PrivateShop_Disappear,非空 sign 触发 BINARY_PrivateShop_Appear(vid, sign);该包不是普通实体 spawn,必须依赖已存在角色 VID。

Current call chain

  • extension/src/net/classic/classic_parser.cpp 已将 character add/additional/update/delete、GC_OWNERSHIPGC_ITEM_GROUND_ADD/DEL/OWNERSHIPGC_SHOP_SIGN 分别写入 EntityStore/ground storeM2Client::poll 将实体和地面变化转为 Godot signal。
  • extension/src/net/entity_store.cpp/.h 以 VID 保存实体,spawn 是整行替换;地面掉落独立保存 vid/vnum/pos/owner,shop sign 是已存在实体的可变字段;未知 VID 的 shop sign/owner 不凭空创建实体。
  • project/net_world.gd 在数据层保存全部实体,在场景层按主角距离、AFFECT_SHOW_ALWAYS 和 wall race 创建/淡出节点;_on_spawn 写入分类、名字、parts、affect、速度、mount 和 shop sign_on_info 刷新可变字段;project/ui/mob_view.gd 负责 NPC/怪物模型、动作、受击和名字补点。
  • project/ui/ground_items.gd 监听 ground add/del,按 item proto 解析名字/颜色,加载 item bag/money 模型或 fallback BoxMesh,创建名字与 owner 尾标、稀有掉落光柱,按距离和 500ms 节流发送拾取;服务端 ground del 负责最终消失。
  • project/entity_rules.gdproject/metin_spawn_event_system.gdproject/mob_drop_scatter.gd 等本地 helper 还承担木门/建筑分类、石头活动、掉落散落和所有权保护等自定义规则;这些不等于 40250 Windows 客户端本身的 authority。

Branch matrix

场景 40250 当前端 结论
角色/NPC/怪物新增 add packet→actor manager→CInstanceBase→模型/尾标;不可见 race 跳过 parser/store→entity_spawnedNetWorld,可延迟 placeholder 后升级真模型 PARTIAL:字段链存在,但不可见 race、未知 race、真资源缺失时的失败分支未完整证明
character additional/update 按包刷新 parts、名字、公会、affect、速度、状态和 shop 相关数据 _on_info/_apply_field_updates 按顺序刷新部分字段 PARTIAL:顺序入口有,角色类型、异常字段、重复/乱序包和实际 model attachment 缺 live 证据
VID 重用 删除旧实例后重新 addactor manager 查找不应残留旧状态 EntityStore whole-row spawnNetWorld 销毁并重建节点 PARTIAL:设计上接近,但旧节点延迟释放与同 VID 新 spawn 的边界没有完整回归
远端删除/淡出 actor manager 删除;尾标、商店和交互引用同步清理 entity_despawned_fade_and_free,数据层/场景层分离 PARTIAL:删除链存在,blend-out 期间重复 spawn、目标/尾标/交互引用的完整时序仍需验证
距离可见性 CHAR_STAGE_VIEW_BOUND、always-show、wall 分支控制实例和渲染列表 _update_visibility 每帧以 20000cm/20010cm、affect bit、wall race 建/淡出 PARTIAL:基础分支已映射;距离常量、真实 actor manager 淡出和复杂 wall/always-show 组合仍未完全证明
建筑/墙体/门 由 race 与 InstanceBase/碰撞数据决定,墙体不因距离错误消失 entity_rules/cursor shape 识别 door/buildingwall race 强制可见 PARTIAL:分类与 cursor 入口有;模型、碰撞、阻挡和真实 wall 生命周期未统一证明
地面掉落新增 坐标转换→CItemData drop model→item text tail;未知 vnum 不创建 ground store→ground_itemsitem bag/money 或 BoxMesh fallback→Label3D PARTIAL:协议、坐标、名字尾标和 fallback 有;真实 drop model/effect/sound/未知 vnum 失败语义不等价
地面掉落所有权 RecvItemOwnership 更新独立 owner text tail;服务器仍是拾取 authority owner 写入 ground row/owner_tag,并在本地 pickup 前做名字判断 PARTIAL:回包链存在;本地 owner precheck 是额外 optimistic gateparty/anti-flag/native action gate 未完整接入
地面掉落删除/拾取 GC_ITEM_GROUND_DEL 同步删除模型和尾标;拾取成功依赖服务器包序 ground del signal 删除节点,pickup 只发送请求 PARTIAL:删除基础链有;CG_ITEM_PICKUP→GC_DEL→ITEM_GET/ITEM_SET/UPDATE 的 live 成功、失败、乱序和回滚未证明
私人商店招牌 GC_SHOP_SIGN 空/非空走 disappear/appear,依赖已有角色 VID shop_sign 进入实体 info_refresh_shop_sign 创建/释放 Label3D PARTIAL:空/非空状态可映射;BINARY 私人商店 UI、重复/未知 VID、重连清理和视觉资源不等价
怪物死亡与掉落 死亡/删除/地面掉落由服务端包和 actor/item manager 驱动 mob_view 死亡表现,活动 helper 可生成本地掉落 GAPcustom authority):本地散落/活动掉落不能作为 40250 client paritylive server death→drop 时序仍缺证据

Implementation-equivalence matrix

项目 状态 证据/限制
Preconditions PARTIAL stage、VID、实体/ground store 和部分分类存在;未知 race/vnum、主 VID、模型工厂未就绪和 owner/anti-flag 门控未完整证明
Branch structure PARTIAL actor add/info/update/delete、ground add/del/owner、shop sign 主要分支存在;visibility、不可见 race、未知数据和 server rejection 分支不等价
Algorithms/formulas PARTIAL 坐标转换、20000cm 可见范围、owner 标签和拾取距离有实现;CItemData 模型选择、碰撞/拾取几何、drop effect 和参考资源算法未统一
State transition order PARTIAL parser→store→signal→view 顺序明确;延迟模型升级、淡出、同 VID 重用、ground del 与 owner/sign 乱序的可观察顺序未闭合
Constants/units PARTIAL CHAR_STAGE_VIEW_BOUND、+10 cull、ground height/pickup 距离、packet fields 有证据;Godot world unit 与 40250 pixel/cm、文本像素度量、模型锚点仍是近似
Timing/event sources PARTIAL poll、ground signal、500ms pickup throttle、visibility interval 有;真实 frame cull、blend-out、drop animation/effect/sound、server packet delay 未覆盖
Resource/data sources PARTIAL mob/NPC 资源扫描和部分真模型测试通过,但有 4 个 fallbackground 使用通用 bag/BoxMesh,未证明所有 CItemData drop model、特效、音效和牌匾资源
Protocol side effects PARTIAL classic parser/session 与 ground/ownership/shop sign 基础路径存在;完整拾取回包、商店 UI、不可见实体过滤和未知 packet 语义缺 live 证据
Interruption/failure/cleanup PARTIAL net_world_vis_test.gd 的基本可见性/重显/删除回归已通过;地图切换基础清理已有,但实体淡出、地面掉落、尾标、商店、同 VID 重用、断线/重连和模型 fallback 的组合清理未完整证明

Regression evidence

  • project/net_world_vis_test.gd:通过;覆盖主角进入范围后的远端节点创建、单次创建、离开范围裁剪和删除信号去重。仍不证明真实 actor manager 的 wall/always-show/模型失败组合。
  • project/entity_rules_test.gd:通过;验证实体分类/可攻击规则,但不证明 40250 的模型、碰撞和 visibility chain。
  • project/forest_mob_render_test.gd24 个结果、0 failures、4 fallback;有 Godot ObjectDB leak warning,且仍需人工资源 sign-off,因此不能标记 PASS。
  • project/mob_view_test.gdproject/mob_winding_test.gdproject/net_world_push_test.gd:通过;覆盖单体模型/绕序/受击推开,不能证明完整 actor manager 生命周期。
  • project/test_ground_pickup_parity.gdproject/mob_death_drop_test.gdproject/test_mob_drop_scatter_parity.gdproject/test_metin_spawn_event_parity.gd:通过;主要覆盖当前端 helper、掉落散落和活动石头规则,不等于 40250 live drop/model/pickup parity。
  • build/extension/net_entity_testbuild/extension/net_classic_session_testbuild/extension/net_classic_wire_test:覆盖部分实体、地面包和协议边界;未覆盖上述 visibility 失败、真实资源失败、完整拾取回包、商店牌匾和重连组合清理。

Active GameLib spawn/property review

  • GameLib/MonsterAreaInfo.cpp 保存刷怪区域 origin/size、左右上下边界、数量、随机初始位置、方向、group/leader/VID/name 和清理默认值;Property.cpp/PropertyLoader.cpp/PropertyManager.cpp 为地图 object/property 注册提供 CRC 和 token 数据。
  • 当前实体生成主要来自服务端 spawn packet 和 NetWorld,地图静态刷怪区域/property 并没有一条等价的客户端本地 MonsterAreaInfo 消费链;因此本轮只确认参考数据模型和清理边界,不能把网络实体测试当作静态刷怪 parity。

Active UserInterface NPC data review

  • PythonNonPlayer.h/PythonNonPlayerModule.cpp 以 MMPT mob table 为权威,提供 LoadNonPlayerData、vnum/name/type/event/color、VID event lookup 和按等级区间匹配的 mob list;PythonCharacterModule.cpp 再用 event type 决定角色 render/behavior。
  • 当前 Metin2Proto/EntityStore 能解析 mob proto 并生成网络实体,但 event type、mob color/name、等级筛选和 unknown vnum/缺记录失败分支没有完整接入 NetWorld/NPC view;本轮静态证据确认“能生成一个怪物”不等于 NPC data chain 一致。
  • 本轮完成 UserInterface NPC 数据入口静态核对,合同保持 PARTIAL

Deep audit round 2026-09-20

本轮复跑 project/net_world_vis_test.gd 时发现固定 100ms 可见性节流会让快速连续帧的结果不稳定;40250 CPythonCharacterManager::Update 每帧执行距离检查,因此已改为每帧调用 _update_visibility()。连续两次测试均 PASS。该结果只证明当前 Godot 可见性状态机的基础边沿,不足以把 40250 的 actor manager 淡出、wall 判定和真实资源失败分支标为等价。

Status

PARTIAL。当前端已经具备 40250 实体/掉落协议的主要 native parser、VID 数据层、NPC/怪物场景层、地面物体和 shop sign 状态入口;可见性基础回归和每帧更新边界已修复,但掉落模型/特效/音效、建筑碰撞、完整 actor/ground 生命周期和 live 拾取/商店回包证据仍不足。

2026-09-22 死代码删除

以下文件只被自身测试引用、运行时从不加载,已删除;本文中以它们为实现或证据的结论作废,相关行为需按 40250 源码单元重新移植:metin_spawn_event_system.gd, test_metin_spawn_event_parity.gd