docs: hover-feedback completion round — #409/#411 bookkeeping, TS-85 narrowed
Records the round that shipped item-cell tooltips, the world-object hover tooltip, and the #411 cursor-swap fix: #409's write-up gains a "hover-feedback completion round" section covering all three items with live-verification notes; #411 is closed with the corrected decomp reading; register row TS-85 is narrowed to reflect the two newly-ported SetTooltip call sites (UIElement_UIItem::UpdateTooltip, UIElement_SmartBoxWrapper::RecvNotice_SmartBoxObjectFound) and the still-open ones (spellcasting endowment/cast-button/favorite/submenu, map notes, character-panel attribute/skill info). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
aed423174b
commit
708e35f610
2 changed files with 126 additions and 9 deletions
133
docs/ISSUES.md
133
docs/ISSUES.md
|
|
@ -26,13 +26,33 @@ What does NOT go here:
|
||||||
|
|
||||||
## #411 — Hover feedback over interactive UI elements: no cursor swap, and item cells have no rollover state
|
## #411 — Hover feedback over interactive UI elements: no cursor swap, and item cells have no rollover state
|
||||||
|
|
||||||
**Status:** OPEN (filed 2026-08-16 during the #409 live-failure investigation, at the
|
**Status:** CLOSED 2026-08-16 at the #409 hover-feedback completion round — the
|
||||||
lead's scope addition; user report: "the cursor should light up when I hover over an
|
user's answer to the open question below ("the POINTER changes, like it already
|
||||||
item in inventory. it does not")
|
does over world NPCs") is CONFIRMED by decomp, not merely a memory to trust:
|
||||||
|
`UIElement_SmartBoxWrapper::FindObject @0x004E5430` calls
|
||||||
|
`SmartBox::set_found_object(itemID)` UNCONDITIONALLY whenever the hovered UI
|
||||||
|
element casts to `UIElement_UIItem` — not gated on target mode, as the port plan
|
||||||
|
below (written before this finding) assumed it would need to be. Fixed with a
|
||||||
|
ONE-LINE widening of `CursorFeedbackController.Update(UiRoot)`'s existing
|
||||||
|
(too-narrow) item-hover special case; `ResolveGlobalKind` needed no changes,
|
||||||
|
since it already read the "found" flag unconditionally across every mode. See
|
||||||
|
docs/ISSUES.md #409's own "hover-feedback completion round" write-up (item 3)
|
||||||
|
for the full derivation and `CursorFeedbackControllerTests.
|
||||||
|
UpdateFromRoot_HoveringAnItemSlot_ShowsFoundCursor_In{OrdinaryPeaceMode,CombatMode}`
|
||||||
|
for the pin. The rollover-STATE half of this investigation (item 3 below,
|
||||||
|
`UiItemSlot` has no `HoverEnter`/`HoverLeave`) was NOT in scope for the pointer
|
||||||
|
question and remains unaddressed if the user separately wants the highlight —
|
||||||
|
file a fresh issue if so; this closure covers only the pointer-swap question the
|
||||||
|
lead's scope addition asked about.
|
||||||
|
|
||||||
**Severity:** LOW (cosmetic/affordance; no gameplay impact)
|
**Severity:** LOW (cosmetic/affordance; no gameplay impact)
|
||||||
**Depends on:** nothing — the hover dispatch it needs is already correct (see #409's
|
**Depends on:** nothing — the hover dispatch it needs is already correct (see #409's
|
||||||
live-failure round, which proved `UiRoot.UpdateHover` selects the right widget).
|
live-failure round, which proved `UiRoot.UpdateHover` selects the right widget).
|
||||||
|
|
||||||
|
**Original investigation (below), kept for its still-valid layer 1/2/3 breakdown —
|
||||||
|
only the "never fires over an inventory item" conclusion for layer 2 was
|
||||||
|
incomplete; see the closure note above for the corrected reading.**
|
||||||
|
|
||||||
**Retail mechanism, derived from `docs/research/named-retail/acclient_2013_pseudo_c.txt`.**
|
**Retail mechanism, derived from `docs/research/named-retail/acclient_2013_pseudo_c.txt`.**
|
||||||
There are THREE separate hover-feedback layers, and the DAT decides which one applies:
|
There are THREE separate hover-feedback layers, and the DAT decides which one applies:
|
||||||
|
|
||||||
|
|
@ -188,7 +208,7 @@ horizontal `HJustify` mapping while in this code, since it shares the
|
||||||
|
|
||||||
## #409 — Client-wide UI tooltip system is unshipped (GF-16, deferred out of Campaign CC gate round 1)
|
## #409 — Client-wide UI tooltip system is unshipped (GF-16, deferred out of Campaign CC gate round 1)
|
||||||
|
|
||||||
**Status:** CODE-COMPLETE 2026-08-16; review-fix round F1-F11 and the LIVE-FAILURE round both landed same day. The live-failure round's own fix is LIVE-VERIFIED (Options -> Character tab tooltip observed on a real connected client, screenshot evidence); the user's full connected gate is still owed.
|
**Status:** CODE-COMPLETE 2026-08-16; review-fix round F1-F11, the LIVE-FAILURE round, and the hover-feedback completion round (item-cell tooltips + world-object hover tooltip) all landed same day. The live-failure round's own fix is LIVE-VERIFIED (Options -> Character tab tooltip observed on a real connected client, screenshot evidence); the hover-feedback completion round's three items are automated-gate-verified (unit + live-DAT) but the user's connected gate for THOSE items specifically is still owed — see that round's own "Live-verify all three" note.
|
||||||
**Severity:** LOW-MEDIUM (cosmetic/discoverability — no gameplay impact, but retail shows a tooltip on hover for authored elements client-wide and acdream showed none before this fix)
|
**Severity:** LOW-MEDIUM (cosmetic/discoverability — no gameplay impact, but retail shows a tooltip on hover for authored elements client-wide and acdream showed none before this fix)
|
||||||
|
|
||||||
**2026-08-16 re-derivation + port.** Full re-derivation from
|
**2026-08-16 re-derivation + port.** Full re-derivation from
|
||||||
|
|
@ -353,16 +373,113 @@ the "Slots" button.
|
||||||
spin arrows — longer text, should WRAP rather than run off-screen; (7) the
|
spin arrows — longer text, should WRAP rather than run off-screen; (7) the
|
||||||
Heritage/Profession/Skills/Town/Summary tab buttons.
|
Heritage/Profession/Skills/Town/Summary tab buttons.
|
||||||
|
|
||||||
*Expected NOT to show anything yet (deferred, register TS-85):* hovering an
|
|
||||||
inventory ITEM icon. Retail shows the item name there
|
|
||||||
(`UIElement_UIItem::UpdateTooltip @0x004E1CB0`); acdream shows nothing.
|
|
||||||
|
|
||||||
Confirm also: the box sits offset down-right of the cursor (retail's +32px on
|
Confirm also: the box sits offset down-right of the cursor (retail's +32px on
|
||||||
both axes), never runs off the edge of the window even near a corner, and
|
both axes), never runs off the edge of the window even near a corner, and
|
||||||
disappears on its own after ~10 s if you hold still without moving away. No
|
disappears on its own after ~10 s if you hold still without moving away. No
|
||||||
click-to-dismiss is expected — only moving off the control, or a very long
|
click-to-dismiss is expected — only moving off the control, or a very long
|
||||||
hold, closes it.
|
hold, closes it.
|
||||||
|
|
||||||
|
**2026-08-16 hover-feedback completion round.** Closes the two items the
|
||||||
|
live-failure round explicitly deferred (item-cell tooltips, and the #411
|
||||||
|
pointer question), plus the world-object hover tooltip the user's gate notes
|
||||||
|
called out separately.
|
||||||
|
|
||||||
|
1. **Inventory/shortcut/paperdoll item-name tooltips — SHIPPED.**
|
||||||
|
`UIElement_UIItem::UpdateTooltip @0x004E1CB0` is called from
|
||||||
|
`UIItem_Update` (an item-DATA-CHANGE refresh, not a hover handler — the
|
||||||
|
trigger that actually SHOWS it is the generic `CheckTooltip` dwell timer,
|
||||||
|
same as any other tooltip-bearing element). Re-derived and closed the gap
|
||||||
|
the live-failure round left open ("acdream's `UiItemSlot` carries neither
|
||||||
|
the `P0x47` popup locator nor a name source"): live-DAT sweep of the
|
||||||
|
shared UIItem cell-template catalog (`ItemListCellTemplate.CatalogLayoutId`,
|
||||||
|
`0x21000037`) found ALL 47 UIItem-type (class `0x10000032`) prototypes —
|
||||||
|
inventory's cell, every toolbar slot, every paperdoll/armor slot skin —
|
||||||
|
resolve the IDENTICAL popup locator (`P0x47=0x10000395`/`P0x48=0x21000041`)
|
||||||
|
through catalog inheritance, with no literal text authored on any of them
|
||||||
|
(`TooltipLiveDatTests.UiItemCatalog_EveryPrototype_SharesTheSamePopupLocator`).
|
||||||
|
`UiItemSlot` now hardcodes that pair and exposes `GetTooltipText()` via a
|
||||||
|
new per-instance `TooltipTextResolve` delegate, wired at every physical-
|
||||||
|
item construction site — `InventoryController` (main-pack cell + grid
|
||||||
|
cells), `ExternalContainerController`, `PaperdollController` (closes the
|
||||||
|
`gmPaperDollUI::UpdateItemSlotTooltip @0x004A52EF` row too — same cell
|
||||||
|
class, same fix), `VendorUiController` (shop/buying/selling lists),
|
||||||
|
`SecureTradeUiController`, `ToolbarController`. Text is
|
||||||
|
`ClientObject.GetTooltipDisplayName()` (new Core method): `GetAppropriateName()`
|
||||||
|
prefixed with the stack count via `"{count} {name}"` when `StackSize > 1`,
|
||||||
|
matching `UpdateTooltip`'s exact `NAME_APPROPRIATE` + `"%d %s"` sprintf.
|
||||||
|
`UiCatalogSlot` (spell/component catalog cells — a DIFFERENT `UiItemSlot`
|
||||||
|
subclass) is unaffected; it already overrides `GetTooltipText()` with its
|
||||||
|
own `Label`.
|
||||||
|
|
||||||
|
2. **World-object hover tooltip (NPCs, players, signs, chests, portals) —
|
||||||
|
SHIPPED.** NOT the UI-element dwell-timer path — 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
|
||||||
|
`PlayerModule::ShowTooltips` character option (`CharacterOptionId.ShowTooltips`
|
||||||
|
— already modeled in `CharacterOptionTable`, default true), with text
|
||||||
|
`ACCWeenieObject::GetObjectName(id, NAME_APPROPRIATE, 0)` — the SAME name
|
||||||
|
call as item tooltips, but WITHOUT the item-cell's separate stack-count
|
||||||
|
prefix (a real, decomp-confirmed asymmetry: a ground pile of arrows shows
|
||||||
|
"Arrows", not "20 Arrows"). Ported as `RetailTooltipPresenter.
|
||||||
|
UpdateWorldHoverTooltip`, driven by the SAME world-hover pick
|
||||||
|
`CursorFeedbackController`'s own found-cursor already uses
|
||||||
|
(`WorldSelectionQuery.PickAtCursor`, `includeSelf: true`) and the SAME
|
||||||
|
`ClientObjectTable`-backed name resolver `SocialAllegiancePageController`'s
|
||||||
|
`ResolveWorldObjectName` already established as this codebase's pattern.
|
||||||
|
Queried only when no UI element is hovered (this port's reading of
|
||||||
|
`FindObject`'s `m_pElementLastOver` check, narrowed from retail's literal
|
||||||
|
"raycast even under non-item UI chrome" — see the class's own doc note).
|
||||||
|
**Own player is included** (`includeSelf: true`, the same precedent the
|
||||||
|
cursor feedback wiring already set) — no decomp evidence was found either
|
||||||
|
confirming or excluding self from the found-object pipeline, so this
|
||||||
|
follows the established local precedent rather than guessing fresh; flag
|
||||||
|
if that reads wrong in the live gate. **The exact popup skin is an
|
||||||
|
inference, not a measured value** — an exhaustive live-DAT sweep found
|
||||||
|
`UIElement_SmartBoxWrapper` (class `0x10000030`) has NO authored
|
||||||
|
`ElementDesc` anywhere installed (unlike every other tooltip trigger, it
|
||||||
|
is evidently constructed directly by `gmGamePlayUI`'s own mode setup, not
|
||||||
|
from a walkable LayoutDesc — `TooltipLiveDatTests.
|
||||||
|
SmartBoxWrapper_HasNoAuthoredElementDesc_AnywhereInstalled`), so its real
|
||||||
|
`P0x47`/`P0x48` cannot be read off the DAT the way the item catalog's can.
|
||||||
|
This port reuses the SAME pair every other game-code `SetTooltip` caller
|
||||||
|
in this family resolves to — the best-evidenced choice, called out in
|
||||||
|
register row TS-85 rather than silently assumed exact.
|
||||||
|
|
||||||
|
3. **#411 resolved: retail DOES swap the pointer over inventory items,
|
||||||
|
unconditionally — the earlier investigation's "never fires over an
|
||||||
|
inventory item" finding was INCOMPLETE, not wrong about what it checked.**
|
||||||
|
The original #411 scan (below) correctly found no PER-ELEMENT authored
|
||||||
|
cursor on item cells and correctly found `SmartBox::get_found_object_id()`
|
||||||
|
is written only by `UIElement_SmartBoxWrapper` — but it had not yet traced
|
||||||
|
`FindObject @0x004E5430` far enough: when the currently-hovered UI element
|
||||||
|
(`m_pElementLastOver`) casts to `UIElement_UIItem` (class `0x10000032`),
|
||||||
|
`FindObject` calls `SmartBox::set_found_object(itemID, 0xFFFFFFFF)`
|
||||||
|
directly and returns WITHOUT running the 3D raycast — UNCONDITIONALLY, not
|
||||||
|
gated on target mode. `ClientUISystem::UpdateCursorState @0x00564630`
|
||||||
|
computes its "found" flag ONCE at the top of the function
|
||||||
|
(`ebx = SmartBox::get_found_object_id() != 0`, `@0x00564642`) and every
|
||||||
|
later branch (default/melee-missile/magic/use/examine/use-target/busy)
|
||||||
|
reads that SAME flag — so hovering an occupied item cell shows the
|
||||||
|
cursor's "...Found" variant in EVERY mode, not only during an active
|
||||||
|
`UseTarget` selection. `CursorFeedbackController.Update(UiRoot)` already
|
||||||
|
had the item-hover special case wired (from an earlier round) but
|
||||||
|
incorrectly gated it to `TargetMode.UseTarget` only; that one-line gate is
|
||||||
|
now removed — `ResolveGlobalKind`'s existing found/not-found branching
|
||||||
|
needed no changes at all, since it already read the snapshot's
|
||||||
|
`HoverTargetGuid` unconditionally across every mode. Live-DAT-independent
|
||||||
|
(pure decomp + unit fixture), so no DAT sweep was needed for this part;
|
||||||
|
two new `CursorFeedbackControllerTests` pin the widened behavior in
|
||||||
|
ordinary peace mode and in combat mode.
|
||||||
|
|
||||||
|
**Live-verify all three on the connected client** (session-config launch,
|
||||||
|
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.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
**Original GF-16 filing (superseded by the re-derivation above; kept for
|
**Original GF-16 filing (superseded by the re-derivation above; kept for
|
||||||
|
|
|
||||||
File diff suppressed because one or more lines are too long
Loading…
Add table
Add a link
Reference in a new issue