Files
mtgodot-poc/audit/contracts/ui.equipment-tooltip.md
T
shenandshen c93894313a fix: 装备属性面板避让逻辑 + 多项功能更新
- item_tooltip_view.gd: 新增 avoid_rect 属性,tooltip 与装备窗口重叠时自动推到左侧
- inventory_ui.gd: 悬停装备时传入窗口矩形作为避让区域
- 包含其他累积的功能开发和测试文件
2026-09-21 16:38:59 -07:00

7.0 KiB
Raw Blame History

ui.equipment-tooltip

Scope

比较查看装备、装备属性计算、普通提示框与查看装备窗口的创建/销毁、定位、内容和重复打开行为。

Reference call chain

  • UserInterface/PythonNetworkStreamPhaseGameItem.cpp
  • UserInterface/PythonItem.cpp
  • UserInterface/PythonItemModule.cpp
  • UserInterface/PythonNetworkStreamPhaseGame.cpp
  • UserInterface/PythonTextTail.cpp

说明:40250 ClientVS22/source 树中没有 Python UI 脚本;迁移目录中的脚本只能作为历史/资产线索,不能替代 C++ 参考实现。

Current call chain

  • project/ui/view_equipment_ui.gd
  • project/ui/item_tooltip.gd
  • project/ui/item_tooltip_view.gd
  • project/ui/ui_manager.gd
  • project/ui/inventory_ui.gd
  • project/ui/shop_ui.gd
  • project/ui/equip_model.gd
  • project/ui/player_view.gd
  • project/view_equipment_ui_test.gd
  • project/item_tooltip_test.gd

Initial finding

当前已经针对“两个属性面板”和查看装备窗口增加了实现与测试,但尚未完成 40250 的窗口生命周期、属性来源、槽位顺序、装备/时装分层和关闭清理的 1:1 证明。重点检查重复创建、普通 tooltip 与查看装备窗口同时存在、远程角色更新和切换目标。

Audit findings (2026-09-20)

ViewEquipmentUI 本身已经使用 UiManager 提供的单例 ItemTooltipView,测试也确认查看装备窗口的尺寸、11 个槽位和共享属性面板通过。但全局提示框路径仍存在明确的重复面板风险:

  • project/ui/inventory_ui.gd_fill_cell 中给每个格子写入 Godot 原生 cell.tooltip_text,同时在 mouse_entered 中显示共享 ItemTooltipView
  • project/ui/shop_ui.gd 在商店格子中同样写入 slot.tooltip_text,并在悬停时显示共享 ItemTooltipView
  • 40250 的 uiToolTip.py 是自绘/自管理的 ItemToolTip 窗口语义;当前端同时保留原生 tooltip 和自定义 tooltip,因此“查看装备窗口自身只有一个面板”的测试不能证明背包、商店和装备查看的全局单面板约束。

这解释了为什么局部查看装备测试可以通过,但实际切换到背包或商店仍可能出现两个属性面板。另一个未决点是 ViewEquipmentUI 的固定位置与 40250 窗口定位/屏幕边界处理尚未完成对照。当前仅记录差异,本轮不把它误标为已修复。

Baseline tests

view_equipment_ui_test.gd 当前通过,确认已覆盖的 40250 对话框尺寸、11 个装备槽、共享属性面板和单实例约束正常;属性数据来源及完整窗口生命周期仍未完成对照。

Equivalence matrix

项目 状态 备注
Preconditions UNASSESSED 目标有效性、物品存在和查看权限
Branch structure UNASSESSED 普通物品、装备、时装、空槽和未知物品
Algorithms/formulas UNASSESSED 属性和附加属性展示来源
State transition order UNASSESSED request → data → panel → tooltip → cleanup
Constants/units UNASSESSED 槽位、尺寸、偏移和格式化规则
Timing/event sources UNASSESSED 网络查看结果和鼠标悬停更新
Resource/data sources UNASSESSED item_proto、itemdesc、UI .sub 和 locale
Protocol side effects UNASSESSED 查看装备请求/响应及重复请求
Interruption/failure/cleanup UNASSESSED 关闭、切换目标、重复打开和节点回收

Remaining

  • 对照 40250 的 uiToolTip.py/uiCharacter.py 及查看装备协议处理。
  • 证明背包、商店、交易、仓库、商城仓库、个人摊位和查看装备共用同一个 UiManager 实例,而不是只在各自 headless fixture 中各自创建 fallback。
  • 增加切换目标、快速打开关闭、空装备、远程更新和窗口边界定位测试。

Next audit round 2026-09-20T18:19Z

本轮继续沿 40250 的 PythonSlotWindow/uiToolTip.ItemToolTip 生命周期核对全局 tooltip,而不是只检查 ViewEquipmentUI

  • 40250 的装备查看窗口与背包/商店格都通过 ItemToolTip 的 ShowToolTip/HideToolTip 事件管理自绘窗口;当前 ViewEquipmentUI 确实通过 UiManager 复用单个 ItemTooltipView,局部测试中的“只有一个属性面板”成立。
  • 当前 InventoryUI::_fill_cellproject/ui/inventory_ui.gd:195-209)仍给格子写入 cell.tooltip_text,随后 _on_cell_mouse_entered:282-300)又显示共享 ItemTooltipViewShopUI::_fill_slotproject/ui/shop_ui.gd:420-426)同样同时设置 slot.tooltip_text 并连接 _show_slot_tooltip。鼠标悬停时存在 Godot 原生 tooltip 与自绘属性面板并存的路径,这正是“查看装备时出现两个面板”在背包/商店入口仍可能复现的结构性差异。
  • view_equipment_ui_test.gd 通过并且退出时仍报告 5 个 ObjectDB 泄漏;该测试只覆盖查看装备窗口自身,不覆盖背包/商店 tooltip 互斥,也不能作为完整生命周期清理证据。
  • ViewEquipmentUI 的固定 870,300 起始位置与 ItemTooltipView::update_position 的鼠标跟随/底部翻转策略仍不是同一定位算法;当前尚无屏幕边界和快速切换目标的回归测试。

结论:40250 语义的查看装备单例路径已经有局部实现,但全局 tooltip 互斥和窗口清理尚未闭合。本轮没有修改实现代码,合同保持 PARTIAL;下一步应由 UiManager 统一负责 item tooltip 的显示/隐藏,并清除物品格上的原生 tooltip_text,再补背包↔商店↔查看装备快速切换测试。

Implementation fix round 2026-09-21

  • InventoryUIShopUI 的物品格现在清空 Godot 原生 tooltip_text,属性内容保存在格子 metadata,并统一交给共享 ItemTooltipView;移动端详情读取同一份内容,不再产生第二个原生面板。
  • inventory_ui_test.gdview_equipment_ui_test.gdtest_npc_shop_flow.gd 已覆盖背包/装备/商店的单面板路径、属性/价格内容和刷新后的共享面板。

本合同继续为 PARTIAL:远程查看协议、窗口边界定位、快速切换和完整销毁生命周期仍需按 40250 继续审计。

Implementation fix round 2026-09-21 — all item windows use the custom tooltip owner

继续按 40250 PythonSlotWindow/ItemToolTip.ShowToolTip 的单实例语义收口物品入口:新增 ItemTooltipBridge,并将交易、仓库、商城仓库和个人摊位的物品行/物品格接入 UiManager.get_item_tooltip_view();没有 UiManager 的 headless fixture 使用同一 bridge 的 局部 fallback。所有这些 item control 现在清空 Godot 原生 tooltip_text,悬停进入/离开只 切换自绘 ItemTooltipView,关闭窗口时主动隐藏。

test_safebox_mall_parity.gd 新增原生重复面板和自绘悬停回归,40 项通过;同时回归 p8_test.gdtest_npc_shop_flow.gdprivate_shop_ui_test.gditem_tooltip_test.gd 均通过。真实运行时多窗口共享 UiManager、边界定位、快速切换和完整销毁顺序仍保持 PARTIAL