- item_tooltip_view.gd: 新增 avoid_rect 属性,tooltip 与装备窗口重叠时自动推到左侧 - inventory_ui.gd: 悬停装备时传入窗口矩形作为避让区域 - 包含其他累积的功能开发和测试文件
12 KiB
12 KiB
item.drop_pickup
Scope
审计地面掉落物从 GC_ITEM_GROUND_ADD、所有权更新、模型/特效/名条创建,到鼠标点选、走近、500ms 拾取节流、权限拒绝、CG_ITEM_PICKUP、GC_ITEM_GROUND_DEL 和拾取后物品回包的完整链路。
Reference call chain
PythonNetworkStreamPhaseGameItem.cppRecvItemGroundAddPacket读取坐标、VID、vnum,转换全局/本地坐标后调用CPythonItem::CreateItem。RecvItemOwnership调用CPythonItem::SetOwnership;RecvItemGroundDelPacket调用CPythonItem::DeleteItem。
PythonItem.cpp/ItemData.cpp/ItemManager.cppCreateItem先通过CItemManager::GetItemDataPointer验证 vnum,使用CItemData::GetDropModelThing创建实际掉落模型,按地形高度/法线处理位置,并挂接 drop effect、掉落声音和掉落动画状态;名条使用 item data 名称。SetOwnership只更新已有 VID 的 ground instance 和名条;未知 VID 不创建对象。DeleteItem同时删除模型实例和CPythonTextTail名条;DeleteAllItems用于清理整张地图。
PythonPlayer.cpp/PythonPlayerInputMouse.cppSendClickItemPacket在观战模式直接拒绝,500ms 节流;读取地面物品 owner、vnum 和 ItemManager anti-flag,非本人且不满足组队/可掉落可赠送条件时触发OnCannotPickItem,否则发送SendItemPickUpPacket。__OnPressItem清理旧预约和自动攻击;距离足够时发送 WAIT 状态和拾取请求,否则建立MODE_CLICK_ITEM预约并持续走近。__ProcessClickItem到达约 20 像素内时发送 WAIT、SendClickItemPacket、停止并清理预约;物品消失则清理预约。
PythonTextTail.cpp/CPythonItem::__Pick- 鼠标拾取先测试实际掉落模型的相交,再回退到文本尾标拾取;owner 名条独立显示并参加尾标排布。
Current call chain
extension/src/net/classic/classic_parser.cpp/EntityStore- 解析
GC_ITEM_GROUND_ADD、GC_ITEM_GROUND_DEL、GC_ITEM_OWNERSHIP,写入GroundItem{vid,vnum,x,y,z,owner}并通过M2Client信号同步。 - 当前 parser/store 不查询 ItemManager 以拒绝未知 vnum;未知掉落仍可进入当前状态。
- 解析
project/ui/ground_items.gd_on_added生成通用item_bag.gr2或 BoxMesh,占位模型;按 MapCoord 和地形采样设置位置,创建名字/owner Label3D、稀有光柱和名条防重叠。_on_removed/clear_for_map_change删除 Godot 节点;_process旋转占位网格、按距离改名字颜色并重新排布尾标。try_pickup/try_pickup_vid有 3m 步行、5m 骑马、最近优先、500ms 节流和 owner 名字拦截;然后直接调用client.pickup_item(vid)。pick_at用投影后的模型点、名字标签和 owner 标签的 64px 最近点选择,不是参考端的实际模型相交 + TextTail Pick。
project/net_play.gd/player_controller.gdpick_ground_item在约 20m?(代码使用CLICK_ITEM_PICKUP_CM换算)内立即发 WAIT 并尝试拾取,否则建立走近预约;有观战拦截和自动攻击清理。
extension/src/net/m2_client.cpp/classic_session.cpppickup_item只检查is_in_game、正 VID 和 u32 范围,再发送CG_ITEM_PICKUP;没有参考端的 observer、item proto、owner/party、anti-flag 或 action gate。ground_item_added/ground_item_removed/item_picked_up信号存在,但未证明GC_ITEM_GROUND_DEL后 inventory item set/update 的严格反馈顺序。
Branch matrix
| 场景 | 40250 | 当前端 | 结论 |
|---|---|---|---|
| 掉落创建 | ItemManager 验证 vnum,按 item proto 的 drop model、地形/法线、drop effect、声音和动画创建 | parser/store 建立记录;UI 通用 bag/BoxMesh,无实际 item drop model、effect、sound、drop animation | GAP |
| 坐标/地形 | 全局坐标转换后按 Background height/normal 设置模型位置 | MapCoord 转换并 sample_height + 0.1,没有法线、模型包围盒和掉落动画落点 |
PARTIAL |
| 所有权更新 | 只更新已存在 VID;owner 进入独立 TextTail owner 实例 | mut_ground_owner 更新并重新发 ground added;UI 重建/更新 owner tag |
MAPPED + tests |
| 名称与颜色 | 名称取 CItemData::GetName,颜色/尾标来自 item data 和 TextTail |
名称优先 proto/item_list;grade/color 有适配,但 _process 近距离颜色会覆盖原品阶色 |
PARTIAL |
| 名条点击 | 实际模型 Intersect,再 TextTail Pick |
64px 投影点近邻,可能选中不可见/非相交对象或错误标签 | PARTIAL |
| 近距离拾取 | 距离约 20 像素内发送 WAIT+pickup;远距离建立 MODE_CLICK_ITEM 走近 | pick_ground_item 有走近预约和 WAIT;GroundItems 又有 3m/5m 阈值,两个距离层未统一证明 |
PARTIAL |
| 最近拾取/按键 | GetCloseItem/预留动作按参考距离和对象选择 |
最近优先、3m/5m 和 500ms 已有本地测试 | MAPPED + tests |
| 所有权拒绝 | owner 不同且非 party/anti-flag 允许时本地拒绝并回调 | 只比较 owner 字符串与本地名字;没有 ItemManager anti-flag 和 party member 分支 | PARTIAL |
| 观战/行动门 | IsObserverMode 和主角行动状态阻止拾取 |
NetPlay 有 observer;native pickup_item 未有统一行动门 |
PARTIAL |
| 拾取协议 | SendItemPickUpPacket 写包并 SendSequence |
ClassicSession 构造 VID 包,但没有序列/副作用等价保证 | PARTIAL |
| 拾取成功/失败清理 | server GC ground del 删除模型和名条;后续 item get/set/update 刷新背包 | ground del 删除 Node,item event/物品信号存在;失败、超时、重复回包和预约清理缺少包级测试 | PARTIAL |
| 换图/断线 | DeleteAllItems 和阶段清理释放全部 ground instance/text tail |
clear_for_map_change queue_free;延迟释放/generation/断线顺序未完全证明 |
PARTIAL |
Implementation-equivalence matrix
| 项目 | 状态 | 证据/限制 |
|---|---|---|
| Preconditions | PARTIAL | stage/VID、距离、owner 名和 observer 有部分检查;ItemManager vnum/anti-flag/party/action gate 缺失 |
| Branch structure | PARTIAL | add/owner/del、最近拾取、走近预约和移动端入口存在;实际模型拾取、权限分支和 drop animation 分支不等价 |
| Algorithms/formulas | PARTIAL | 坐标转换、距离、500ms、尾标布局已覆盖;模型包围盒/法线/近似拾取和颜色更新不同 |
| State transition order | PARTIAL | reference 是 add→model/text tail→ownership→pickup→server del→inventory feedback;当前 signal→Node 与延迟 queue_free/双距离层顺序未端到端证明 |
| Constants/units | PARTIAL | 3m/5m/500ms 有测试;参考 20 像素、真实 item model 尺寸和服务端 cm/m 换算还需统一 fixture |
| Timing/event sources | PARTIAL | 当前依赖 Godot _process、signals、预约;参考由网络收包、输入状态机、Item/Actor/TextTail 事件驱动 |
| Resource/data sources | GAP | 当前 ground model 使用通用 item bag/BoxMesh,没有使用 CItemData::GetDropModelThing、drop effect、drop sound、法线等资源链 |
| Protocol side effects | PARTIAL | add/del/ownership/pickup packet 基础结构已解析;SendSequence、OnCannotPickItem 全分支和拾取后回包顺序未闭合 |
| Interruption/failure/cleanup | PARTIAL | map change 清理有实现;server 拒绝、重复 ownership、延迟删除、断线和旧 VID generation 尚未完整覆盖 |
Regression evidence
project/test_ground_pickup_parity.gd:拾取距离、骑马距离、最近优先、500ms、owner 名拦截、稀有光柱和基础名条通过。project/mob_death_drop_test.gd:掉落坐标/地形高度、Yang 名称、拾取调用和死亡清理通过。project/p2b_test.gd:掉落节点、proto 名称、多条名条去重、owner 独立名条和颜色通过,但退出仍有 2 个 ObjectDB 泄漏。project/text_tail_arrange_test.gd:尾标 AABB 和 owner 排布通过。extension/tests/net_entity_test.cpp、extension/tests/net_classic_session_test.cpp:ground add/del/owner 与经典物品包基础布局通过。- 未覆盖:未知 vnum、真实 drop model/effect/sound、模型相交拾取、party + anti-flag 权限矩阵、observer/native action gate、CG_ITEM_PICKUP 后 GC_DEL→ITEM_GET/ITEM_SET 顺序、失败/重复/断线/换图竞态。
Deep audit round 2026-09-20
Fresh regression results
godot --headless --path project --script test_ground_pickup_parity.gd:退出码 0;距离、骑马距离、最近优先、500ms、owner 拦截和基础名条通过。godot --headless --path project --script mob_death_drop_test.gd:退出码 0;死亡脱离、地面坐标/高度、Yang 命名和拾取调用通过。godot --headless --path project --script p2b_test.gd:退出码 0;地面掉落、名称、名条去重、owner 名条和颜色通过,但退出仍有 2 个 ObjectDB 实例泄漏。godot --headless --path project --script text_tail_arrange_test.gd:退出码 0;尾标 AABB 与 owner 排布通过。godot --headless --path project --script test_drop_and_cursor_parity.gd:退出码 0;MapCoord heading、cursor 注册、占位模型创建和点选通过。./build/extension/net_entity_test与./build/extension/net_classic_session_test:均退出码 0;只证明 ground add/del/owner 和 pickup 包的基础 native 处理。
Static parity findings
- 40250
CPythonItem::CreateItem先用ItemManager校验 vnum,再加载GetDropModelThing,创建 drop effect、drop sound、drop animation,并按地形法线调整实例;当前 parser/store 接受未知 vnum,GroundItems使用通用item_bag.gr2或 BoxMesh,未接 item-specific model/effect/sound/animation。 - 40250 的
SetOwnership只更新已存在 VID,DeleteItem同时回收 ground instance 与 TextTail;当前 owner 更新通过ground_item_added信号重建/更新 Godot 节点,仍没有未知 vnum/未知 VID 的严格资源语义和 generation 保护。 - 40250 鼠标拾取优先测试真实掉落模型相交,再回退到 TextTail;当前
pick_at只比较模型/名条/owner 标签的屏幕投影点距离 64px,可能选中不可见或非实际相交对象。 - 40250
SendClickItemPacket有 observer、owner、party/anti-flag 和 action gate;当前GroundItems只比较 owner 字符串,M2Client::pickup_item只检查游戏阶段、VID 和整数范围,缺少 ItemManager anti-flag、party 分支、native action gate 与 SendSequence 等价语义。 - 当前
NetPlay的 20m 走近/等待路径与GroundItems的 3m/5m 拾取路径同时存在;它们都能发CG_ITEM_PICKUP,但距离、预约清理、拒绝和重复/延迟回包尚未由同一状态机统一证明。 - 现有
ground_item_removed和item_picked_up信号存在,但没有包级 fixture 证明CG_ITEM_PICKUP → GC_ITEM_GROUND_DEL → GC_ITEM_GET/SET/UPDATE的成功、失败、重复、断线和换图时序。
Round conclusion
本轮仍为 PARTIAL:基础 ground add/del/owner/pickup 协议和局部 UI 回归通过,但真实掉落资源链、模型相交点选、权限矩阵、native action gate 与拾取后的权威回包链仍未与 40250 统一;本轮未修改实现代码。
Status
PARTIAL。当前端已具备掉落状态、坐标、owner 名条、最近拾取和基础协议骨架,但通用占位模型替代了 40250 的 item proto drop model/effect/sound/animation,拾取权限和模型点选分支也不完整;现有本地回归不能标记为完整 1:1,本轮未修改实现代码。