fix(ui): morning gate — world tooltips ride retail's mouse-idle dwell, not the found edge

User finding 1 (side-by-side vs retail): our world-object tooltips popped
the instant the found object changed; retail's "lag". The night round's
derivation from RecvNotice_SmartBoxObjectFound @0x004E5AD0 misread the
notice as edge-MOUNTING: its immediate StartTooltipAtMouse @0x004E5DFB is
inside `if (s_pInstance->m_dragElement != 0)` (@0x004E5D8E) — and
m_dragElement is a real, distinct PDB field in acclient.h's
UIElementManager (separate from the m_pTooltipElement family), so the
immediate mount is DRAG-AND-DROP ONLY. The ordinary hover path merely
STAGES the name (SetTooltip @0x004E5D74 + the |=0x20 TooltipOn bit) and
the display rides the SAME UIElementManager::CheckTooltip @0x0045B6E0
mouse-idle dwell as UI tooltips: 250 ms (m_tooltipDelay @0x0045f75d)
since m_lastMouseMoveTime (stamped on EVERY move, MouseMoveHandler
@0x0045e736). Found swaps under an IDLE mouse replace the popup the same
frame (SetTooltip's own text-change teardown @0x004617FF -> ResetTooltip
@0x0045C360 tail-calling CheckTooltip); the 10 s duration expiry
(@0x0045b78a) requires a fresh mouse move before re-arming
(SwitchMouseOver(null) @0x0045b7b2 clears m_pElementLastEntered).

Port: UiRoot gains the unconditional last-mouse-move stamp
(m_lastMouseMoveTime 1:1 — the existing _hoverStartedMs stamps are
deliberately conditional) exposed as MouseIdleMs/NowMs;
RetailTooltipPresenter.UpdateWorldHoverTooltip now stages text at the
notice edge (ShowTooltips gate + name resolve read there, @0x004E5D21/
@0x004E5D3B, empty-name SetTooltip skip @0x004E5D48 included) and mounts
via the CheckTooltip dwell block (no-capture gate @0x0045b715,
m_tooltipEnable via MouseHover @0x0046254C — which the drag-immediate
branch faithfully bypasses). Session reset also forgets the staged text.

Tests: the world-hover fixture section rewritten to the corrected model —
found edge stages but never mounts before the dwell; a continuously
moving mouse never mounts until it rests; idle found-swap replaces
same-frame without stacking; duration auto-hide needs a move + fresh
dwell to remount; drag-in-progress mounts immediately. 38/38 pass.

Register TS-85 and ISSUES item 2 corrected honestly: the "edge-fired
(no dwell)" conclusion is superseded by the user's retail evidence and
the m_dragElement branch read.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Erik 2026-08-17 08:49:11 +02:00
parent e316e190cb
commit 9d9280a069
5 changed files with 444 additions and 108 deletions

View file

@ -630,11 +630,28 @@ called out separately.
own `Label`.
2. **World-object hover tooltip (NPCs, players, signs, chests, portals) —
SHIPPED.** NOT the UI-element dwell-timer path — retail's mechanism is
SHIPPED; TIMING CORRECTED at the 2026-08-17 morning gate round.** Retail's
mechanism is
`UIElement_SmartBoxWrapper::RecvNotice_SmartBoxObjectFound @0x004E5AD0`,
fed every frame by `FindObject @0x004E5430`/`Global_Loop @0x004E5620`
using the current mouse position regardless of input focus. It fires
IMMEDIATELY (no dwell wait) on the found-object id CHANGING, gated by the
using the current mouse position regardless of input focus. **The
original "fires IMMEDIATELY (no dwell wait)" reading here was a misread
— the user's side-by-side retail comparison (retail world tooltips "lag";
ours popped instantly) sent the derivation back, and the notice's
immediate `StartTooltipAtMouse @0x004E5DFB` turned out to sit inside
`if (UIElementManager::s_pInstance->m_dragElement != 0)` (`@0x004E5D8E`
— a real, distinct PDB field, drag-and-drop only). The ordinary hover
path STAGES the name (`SetTooltip @0x004E5D74` + the `|= 0x20` TooltipOn
bit) and the display rides the SAME `UIElementManager::CheckTooltip
@0x0045B6E0` mouse-idle dwell as UI-element tooltips: 250 ms
(`m_tooltipDelay @0x0045f75d`) since the last mouse move
(`m_lastMouseMoveTime`, stamped on EVERY move `@0x0045e736`), so a
continuously moving mouse shows nothing and the popup appears only once
the cursor rests. Found-object changes under an IDLE mouse swap the
popup the same frame (`SetTooltip`'s text-change teardown `@0x004617FF`
`ResetTooltip @0x0045C360` tail-calls `CheckTooltip`); the 10 s
duration expiry requires a fresh mouse move before re-arming
(`SwitchMouseOver(null) @0x0045b7b2`).** Gated by the
`PlayerModule::ShowTooltips` character option (`CharacterOptionId.ShowTooltips`
— already modeled in `CharacterOptionTable`, default true), with text
`ACCWeenieObject::GetObjectName(id, NAME_APPROPRIATE, 0)` — the SAME name
@ -695,8 +712,9 @@ called out separately.
graceful close per the usual rules): hover an inventory item — a name
tooltip should appear (with a count prefix for a stack) AND the mouse
pointer should swap to its "found" variant; hover an NPC/creature — a name
tooltip should appear immediately (no perceptible delay) if "Show Tooltips"
is on; hover a sign/chest/portal similarly.
tooltip should appear after the 250 ms idle dwell (mouse must REST;
sweeping continuously shows nothing — corrected 2026-08-17) if "Show
Tooltips" is on; hover a sign/chest/portal similarly.
**2026-08-16/17 overnight hover/UI round, Batch A bug 1 — CLOSED same round:
world tooltips never cleared, stacking dozens of popups.** The world-object

File diff suppressed because one or more lines are too long