feat(D.5.3a): selected-object meter — Health bar + name on the action bar
Port of gmToolbarUI::HandleSelectionChanged (acclient_2013_pseudo_c.txt:198635). When the player selects a world object the action bar's bottom strip shows the object name + (for player/pet/attackable targets) a live Health meter; deselect clears it. Mana (#140) + stack slider deferred. - SelectedObjectController (new): clear-then-populate on selection change; sets name (UiText child, VitalsController pattern), overlay state (ObjectSelected / StackedItemSelected via UiDatElement.ActiveState), shows the health meter and sends QueryHealth for health targets. Subscribes via a delegate seam (no GameWindow coupling). - GameWindow: _selectedGuid field -> SelectedGuid property + SelectionChanged event (fires on actual change only); 3 write sites converted, reads untouched. All selection-write paths (LMB pick, Tab/Q, despawn-clear via Tick()) run on the render thread, so the event-driven UI mutation is single-threaded. - WorldSession.SendQueryHealth (0x01BF) — wraps SocialActions.BuildQueryHealth. - DatWidgetFactory.BuildMeter: handle the single-image toolbar meter shape (back-track on the element's own DirectState, fill on one Type-3 child). The sprites go in the TILE slot (DrawMode=Normal tiles to full bar geometry per UIElement_Meter::DrawChildren) — a left-cap assignment would gap/clamp a sub-140px sprite. Vitals 3-slice path unchanged. - ToolbarController.HiddenIds: A1 (health) now owned by SelectedObjectController; A2 (mana) + A4 (stack) stay hidden (deferred) so their dat back-tracks don't render as stray empty bars. Adversarial Opus review found + fixed: the mana-meter orphan (A2 left unhidden) and the meter tile-vs-cap render bug (C1). Divergence rows AP-46 (health gate approximation: IsLiveCreatureTarget vs IsPlayer||pet||attackable) + AP-47 (meter shown on select vs on UpdateHealth reply). Spec §5 corrected. Build + full test suite green (2,684 passed / 4 skipped). Health meter render fidelity (full-width fill + fraction mapping) pending the user's visual gate. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
e8562fc4e2
commit
6636e50c2a
11 changed files with 851 additions and 30 deletions
|
|
@ -144,6 +144,8 @@ accepted-divergence entries (#96, #49, #50).
|
|||
| AP-41 | Scrollbar thumb 3-slice cap fallback only: single-tile draw (`0x06004C63`) used only when `ThumbTopSprite`/`ThumbBotSprite` are unset; the chat controller passes all three cap ids so the 3-slice path is drawn in practice | `src/AcDream.App/UI/UiScrollbar.cs:35` | The fallback single-tile path is unreachable when caps are bound (chat controller always sets them); the 3-slice path is the active code path | Only if a future caller omits the cap ids will the fallback fire — no visual regression in the chat window | `UIElement_Scrollbar::UpdateLayout @0x4710d0`; cap sprites `0x06004C60` (top) + `0x06004C66` (bottom) from base layout `0x2100003E` |
|
||||
| AP-42 | `UiMenu` item model is flat (label + opaque payload, single-level popup); retail `UIElement_Menu::MakePopup @0x46d310` supports hierarchical nested submenus via recursive popup chain | `src/AcDream.App/UI/UiMenu.cs` | The chat talk-focus menu is single-level (14 rows, 2 columns, no submenu); hierarchy is latent and unreachable through the chat window — no behavioral difference in the current usage | A future menu with nested submenus would render flat (only the top-level items drawn, no drill-down) | `UIElement_Menu::MakePopup` @0x46d310 |
|
||||
| AP-45 | `PublicUpdatePropertyInt (0x02CE)` sequence byte parsed-past but not honored; last update wins (no freshness check against sequence number) | `src/AcDream.Core.Net/Messages/PublicUpdatePropertyInt.cs` | Loopback ACE rarely reorders; latest-wins matches `PrivateUpdateVital`/`UpdatePosition`'s existing non-sequence behavior. Sequence tracking added when needed alongside TS-26. | A reordered 0x02CE on a real network could apply a stale UiEffects value — item icon temporarily shows the wrong effect state, corrected on next update | `PublicUpdatePropertyInt` sequence byte (ACE GameMessagePublicUpdatePropertyInt) |
|
||||
| AP-46 | Health-meter gate approximation: retail shows the health meter for `IsPlayer() || pet_owner || ObjectIsAttackable()`; acdream uses `IsLiveCreatureTarget` (the `ItemType.Creature` flag) | `src/AcDream.App/UI/Layout/SelectedObjectController.cs` (`HandleSelectionChanged` analogue) | `IsLiveCreatureTarget` is already wired for Tab/Q combat-target gating and is the correct proxy for M1.5 scope (no pet system, no PK); the only practical gap is a friendly non-attackable NPC, which is rare in the ACE dev loop | A friendly (non-attackable) NPC shows a health meter where retail would show name+overlay only — false meter on non-combat NPCs | `gmToolbarUI::HandleSelectionChanged` acclient_2013_pseudo_c.txt:198754 |
|
||||
| AP-47 | Meter-visible timing: acdream shows the health meter immediately on select; retail shows it from `RecvNotice_UpdateObjectHealth` when the queried value arrives | `src/AcDream.App/UI/Layout/SelectedObjectController.cs` (`OnSelectionChanged`) | Avoids a one-round-trip blank-then-pop; the fill polls `GetHealthPercent` which returns 1.0 until the reply — visually indistinguishable for a full-HP target and self-corrects within one RTT for a damaged target | A freshly-selected off-screen-damaged target reads full for one server round-trip before the `QueryHealth` reply lands | `gmToolbarUI::HandleSelectionChanged` acclient_2013_pseudo_c.txt:198757 |
|
||||
|
||||
---
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue