# 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_BOUND`、`AFFECT_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。 - `CreateItem` 从 `CItemData::GetDropModelThing()` 建立掉落模型,注册 item text tail;`GetCloseMoney` / `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_OWNERSHIP`、`GC_ITEM_GROUND_ADD/DEL/OWNERSHIP` 和 `GC_SHOP_SIGN` 分别写入 `EntityStore`/ground store;`M2Client::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.gd`、`project/metin_spawn_event_system.gd`、`project/mob_drop_scatter.gd` 等本地 helper 还承担木门/建筑分类、石头活动、掉落散落和所有权保护等自定义规则;这些不等于 40250 Windows 客户端本身的 authority。 ## Branch matrix | 场景 | 40250 | 当前端 | 结论 | |---|---|---|---| | 角色/NPC/怪物新增 | add packet→actor manager→`CInstanceBase`→模型/尾标;不可见 race 跳过 | parser/store→`entity_spawned`→`NetWorld`,可延迟 placeholder 后升级真模型 | PARTIAL:字段链存在,但不可见 race、未知 race、真资源缺失时的失败分支未完整证明 | | character additional/update | 按包刷新 parts、名字、公会、affect、速度、状态和 shop 相关数据 | `_on_info`/`_apply_field_updates` 按顺序刷新部分字段 | PARTIAL:顺序入口有,角色类型、异常字段、重复/乱序包和实际 model attachment 缺 live 证据 | | VID 重用 | 删除旧实例后重新 add;actor manager 查找不应残留旧状态 | EntityStore whole-row spawn,NetWorld 销毁并重建节点 | 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/building,wall race 强制可见 | PARTIAL:分类与 cursor 入口有;模型、碰撞、阻挡和真实 wall 生命周期未统一证明 | | 地面掉落新增 | 坐标转换→CItemData drop model→item text tail;未知 vnum 不创建 | ground store→`ground_items`,item 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 gate,party/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 可生成本地掉落 | GAP(custom authority):本地散落/活动掉落不能作为 40250 client parity,live 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 个 fallback;ground 使用通用 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.gd`:24 个结果、0 failures、4 fallback;有 Godot ObjectDB leak warning,且仍需人工资源 sign-off,因此不能标记 PASS。 - `project/mob_view_test.gd`、`project/mob_winding_test.gd`、`project/net_world_push_test.gd`:通过;覆盖单体模型/绕序/受击推开,不能证明完整 actor manager 生命周期。 - `project/test_ground_pickup_parity.gd`、`project/mob_death_drop_test.gd`、`project/test_mob_drop_scatter_parity.gd`、`project/test_metin_spawn_event_parity.gd`:通过;主要覆盖当前端 helper、掉落散落和活动石头规则,不等于 40250 live drop/model/pickup parity。 - `build/extension/net_entity_test`、`build/extension/net_classic_session_test`、`build/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`。