feat(ui): share indicator detail panels
Port the authored Link Status, Vitae, and Mini Game detail roots and register every indicator page with retail's one-active gmPanelUI owner. Helpful/Harmful and the new pages now replace Inventory, Character, or Magic at one canonical window position while preserving the DAT restore-previous flag. Correct the retail ping wire to its payload-free request/response, publish measured RTT, and port Vitae recovery XP from the live modifier and player properties. Keep transport packet-loss averaging and mini-game gameplay explicitly tracked under AP-110. Release build and all 5,814 tests pass with five intentional skips. Connected visual gate pending. Co-authored-by: OpenAI Codex <codex@openai.com>
This commit is contained in:
parent
52c529be86
commit
a96767ba6d
28 changed files with 6539 additions and 32 deletions
|
|
@ -61,6 +61,12 @@ back to inert generic DAT elements.
|
|||
`gmUIElement_EffectsIndicator`. The retained controller consequently had no
|
||||
live bindings for session packet age, Vitae, or the player load ratio and did
|
||||
not dispatch Character Information or the shared logout confirmation path.
|
||||
The strip and its actions are now ported. Link Status (panel 8), both effect
|
||||
pages (4/5), Vitae (15), and the authored Mini Game shell (9) are registered as
|
||||
children of the same retained main-panel owner as Inventory/Character/Magic,
|
||||
so switching pages preserves one canonical position. Link ping RTT and Vitae
|
||||
recovery XP are live; transport packet-loss averaging and Mini Game gameplay
|
||||
remain the explicitly narrowed AP-110 residual.
|
||||
|
||||
**Files:** `src/AcDream.App/UI/Layout/IndicatorBarController.cs`;
|
||||
`src/AcDream.App/UI/Layout/DatWidgetFactory.cs`;
|
||||
|
|
@ -74,6 +80,8 @@ quality follows the 5/20/40-second thresholds and bad-link flash cadence;
|
|||
helpful, harmful, Vitae, and burden react to live state; the burden icon opens
|
||||
Character Information; effects open their matching panels; crossed swords use
|
||||
the shared confirmation dialog and close gracefully only after acceptance.
|
||||
Every non-ghosted detail icon opens its authored page in the shared main-panel
|
||||
position; closing a restore-previous page returns to the deferred ordinary page.
|
||||
|
||||
---
|
||||
|
||||
|
|
|
|||
|
|
@ -207,7 +207,7 @@ AP-94..AP-112 for the confirmed retail-UI completion gaps.
|
|||
| ~~AP-107~~ | **RETIRED 2026-07-11 (Wave 3.3 / #197)** — typed `OfferPrimaryClick` returns `NotActive`, `ConsumedSuccess`, or `ConsumedRejected`; every retained item surface plus radar/world offers active target mode before local selection/open/use fallback. Rejections are consumed and cannot drift selection. | `src/AcDream.App/UI/ItemInteractionController.cs`; inventory/paperdoll/toolbar/radar/world call sites | — | — | `UIElement_ItemList::HandleTargetedUseLeftClick @ 0x004E24D0` |
|
||||
| AP-108 | Paperdoll/AutoWield still omit full `AutoWieldIsLegal`/dual-wield rules, double-click examine/drag from the doll, body-part selection lighting, and retail's synchronous `" - cannot unwield the %s"` failure suffix (the current send seam reports rejection asynchronously). **Primary replacement retired from this row 2026-07-14:** inventory activation and paperdoll drops share the confirmed blocker transaction, preserve explicit slot intent, relocate an already-worn item to an explicitly selected compatible slot, and emit retail's successful move-to-backpack status. **Aetheria retired 2026-07-13.** | `src/AcDream.App/UI/Layout/PaperdollController.cs`; `src/AcDream.App/UI/AutoWieldController.cs` | Basic equip slots, Aetheria, and live doll work; primary weapon, incompatible shield, and mismatched ammo blockers sequence through server-confirmed dequip→wield in both peace and war | Remaining illegal/off-hand cases, asynchronous dequip rejection wording, doll examine/drag, and selection lighting still differ functionally | `CPlayerSystem::AutoWield @ 0x00560A60`; `ACCWeenieObject::BlocksUseOfShield @ 0x0055D3E0`; `gmPaperDollUI @ 0x004A3590..0x004A5F90` |
|
||||
| AP-109 | Character Titles page is inert and live displayed-title/luminance state is absent | `src/AcDream.App/UI/Layout/CharacterStatController.cs`; `CharacterSheetProvider.cs` | Attributes/skills core output is user-accepted | Titles cannot be selected/displayed and level-200 luminance fields are missing | `gmCharacterTitleUI @ 0x0049A610`; `gmStatManagementUI::UpdateExperience @ 0x004F0A70` |
|
||||
| AP-110 | Remaining retained gameplay panels and world HUD are absent: advanced-combat powerbar, residual social/examine/floating chat, quests/map/vitae/options/smartbox, vendor/trade/salvage/tinkering, and D.6 nameplates/floaters | D.5/D.6 roadmap; retained layout registration set | Basic combat plus M3 spellbook/component/effects/favorite-spell surfaces now cover the active melee/missile/magic loops; later waves land each remaining surface against authoritative state | Large portions of retail gameplay still have no production UI outside the current combat/magic/inventory/character loops | Named `gm*UI::PostInit` methods and LayoutDesc catalog |
|
||||
| AP-110 | Remaining retained gameplay panels and world HUD are absent: advanced-combat powerbar, residual social/examine/floating chat, quests/map/options/smartbox, vendor/trade/salvage/tinkering, mini-game gameplay, Link Status NAK/retransmission packet-loss averaging, and D.6 nameplates/floaters | `src/AcDream.App/UI/RetailUiRuntime.cs`; `src/AcDream.Core.Net/LinkStatusSnapshot.cs`; D.5/D.6 roadmap | Basic combat plus M3 spellbook/component/effects/favorite-spell/Link/Vitae surfaces now cover the active melee/missile/magic loops; the Link page has exact ping RTT but reports the current transport's zero default until its missing reliability statistics land | Large portions of retail gameplay still have no production UI; real packet loss is displayed as 0.00% instead of retail's moving average | Named `gm*UI::PostInit` methods; `CLinkStatusAverages::GetAveragePacketLoss @ 0x00546610`; LayoutDesc catalog |
|
||||
| ~~AP-111~~ | **RETIRED 2026-07-11 (M2 held-object parenting)** — equipped hand items are no longer omitted from the render world. CreateObject now preserves Placement/Parent/position timestamp bootstrap; live `0xF749` ParentEvent is parsed with retail sequence freshness; a focused render controller resolves `Setup.HoldingLocations`, applies the child's placement frame, and recomposes the separate child entity after every parent animation tick. Pickup retains the weenie's visual metadata for a later wield. | `src/AcDream.Core.Net/Messages/{CreateObject,ParentEvent}.cs`; `src/AcDream.Core/Meshing/EquippedChildAttachment.cs`; `src/AcDream.App/Rendering/EquippedChildRenderController.cs` | — | — | `ClientCombatSystem::GetDefaultCombatMode @ 0x0056B310`; `SmartBox::HandleParentEvent @ 0x004535D0`; `CPhysicsObj::set_parent @ 0x00515A90`; `CPhysicsObj::UpdateChild @ 0x00512D50` |
|
||||
| AP-112 | The basic combat bar ports visibility, height selection, desired-power slider, exact 1.0/0.8-second charge, ready-stance gating, request/release, `MaybeStopCompletely`, server-response queueing, and auto-repeat, but still omits `StartAttackRequest`'s `FinishJump` call and exact trained-Recklessness visibility semantics (IA-20 keeps the dark range as the accepted baseline) | `src/AcDream.App/Combat/CombatAttackController.cs`; `src/AcDream.App/UI/Layout/CombatUiController.cs` | The shared player movement owner now performs retail's server-control-gated full stop and movement report before an attack build; the remaining seams require the jump owner and a distinct Recklessness treatment | Starting an attack while charging a jump may not finish that jump exactly when retail does; trained/untrained Recklessness presentation is identical | `ClientCombatSystem::StartAttackRequest @ 0x0056C040`; `CommandInterpreter::MaybeStopCompletely @ 0x006B3B90`; `gmCombatUI::ListenToElementMessage @ 0x004CC430` |
|
||||
| AP-113 | Invalid lifestone-command arguments display the local text `Usage: /lifestone`; retail definitely emits a local usage/error line but Binary Ninja misidentifies the referenced wide-string address, so its exact wording is not yet recovered | `src/AcDream.UI.Abstractions/Panels/Chat/ChatCommandRouter.cs`; `RetailClientCommandCatalog.cs` | The behavior boundary is exact (handled locally, no chat and no game action); only a low-impact diagnostic sentence differs | `/ls now` can show different wording/color from retail while still refusing the invalid request correctly | `ClientCommunicationSystem::DoLifestone @ 0x0056FC70` |
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
# acdream — strategic roadmap
|
||||
|
||||
**Status:** Living document. Updated 2026-07-17. **M3 active; automated implementation complete, visual gates pending.** M2's connected demo loop is complete. M3 now has the retail cast-intent/component/target lifecycle, exact live enchantment wire state, scoped Magic input, retained spell bar, spellbook, component book, positive/negative effects panels, the complete authored seven-control gameplay indicator strip, and shared `gmPanelUI` switching over the Step 9 projectile/PhysicsScript/particle/portal foundation. The remaining M3 work is the connected single-client magic-UI/casting gate and final two-client portal-out/materialization observer gate.
|
||||
**Status:** Living document. Updated 2026-07-17. **M3 active; automated implementation complete, visual gates pending.** M2's connected demo loop is complete. M3 now has the retail cast-intent/component/target lifecycle, exact live enchantment wire state, scoped Magic input, retained spell bar, spellbook, component book, positive/negative effects panels, the complete authored seven-control gameplay indicator strip and its Link/Vitae detail pages, and shared `gmPanelUI` switching over the Step 9 projectile/PhysicsScript/particle/portal foundation. The remaining M3 work is the connected single-client magic-UI/casting gate and final two-client portal-out/materialization observer gate.
|
||||
**Purpose:** One source of truth for where the project is and where it's going. Every observed defect or missing feature has a named phase that owns it; when something looks wrong in-game, look here to find the phase that'll address it. Implementation details live in per-phase specs under `docs/superpowers/specs/`, not in this file.
|
||||
|
||||
---
|
||||
|
|
@ -22,7 +22,9 @@ active enchantment, then recall through the DAT-driven portal presentation.
|
|||
equipped caster endowment, scoped retail keys, spellbook/component book,
|
||||
positive/negative active-enchantment panels, the seven-control link/effect/
|
||||
Vitae/burden/mini-game/session indicator strip, and the retail
|
||||
one-active-main-panel lifecycle. Connected-gate
|
||||
one-active-main-panel lifecycle. Link Status, Helpful/Harmful, Vitae, and
|
||||
the inactive Mini Game shell now occupy that same canonical main-panel
|
||||
position; Link RTT and Vitae recovery XP are live. Connected-gate
|
||||
correction now also pins type-12 spellbook tabs, retail zero text margins,
|
||||
and `PassToChildren` Closed/Open chrome through real-DAT fixtures.
|
||||
3. **Pending user visual gate:** connected projectile/self-buff casts plus the
|
||||
|
|
|
|||
|
|
@ -714,6 +714,11 @@ the burden/effect/logout actions use the shared panel/dialog owners. Main-panel
|
|||
visibility now flows through retail's one-active `gmPanelUI` owner. M3 remains
|
||||
active only for the connected single-client magic
|
||||
UI/casting visual gate and the final two-client portal observer gate.
|
||||
The 2026-07-17 indicator follow-up also mounts the authored Link Status, Vitae,
|
||||
and Mini Game detail roots as children of that same main-panel owner. Helpful,
|
||||
Harmful, Link, and Vitae therefore replace Inventory/Character/Magic in one
|
||||
canonical window position. Link uses retail's payload-free ping/RTT cadence;
|
||||
Vitae uses PropertyInt 129/139 and the retail XP-pool threshold formula.
|
||||
The first connected gate exposed and corrected two retained-import defects:
|
||||
spellbook tabs are authored stateful text controls (not buttons), and retail
|
||||
text starts with zero margins. Real-DAT fixtures now pin spellbook binding,
|
||||
|
|
|
|||
|
|
@ -25,6 +25,17 @@ Named retail functions:
|
|||
- `gmUIElement_BurdenIndicator::Update @ 0x004E6CE0`
|
||||
- `LinkStatusHolder::GetConnectionStatus @ 0x00411380`
|
||||
- `LinkStatusHolder::OnHeartbeat @ 0x004113D0`
|
||||
- `gmPanelUI::SetupChildren @ 0x004BC9E0`
|
||||
- `gmPanelUI::RecvNotice_SetPanelVisibility @ 0x004BC6F0`
|
||||
- `gmLinkStatusUI::PostInit @ 0x004AADB0`
|
||||
- `gmLinkStatusUI::Update @ 0x004AAEA0`
|
||||
- `gmLinkStatusUI::ListenToElementMessage @ 0x004AB0B0`
|
||||
- `gmLinkStatusUI::ListenToGlobalMessage @ 0x004AB110`
|
||||
- `gmLinkStatusUI::RecvNotice_Ping @ 0x004AB150`
|
||||
- `gmVitaeUI::PostInit @ 0x004A7240`
|
||||
- `gmVitaeUI::Update @ 0x004A7400`
|
||||
- `VitaeSystem::VitaeCPPoolThreshold @ 0x005C8FD0`
|
||||
- `CM_Character::Event_RequestPing @ 0x006A19A0`
|
||||
- `gmEffectsUI::SpellEffectMatchesUIType @ 0x004B76C0`
|
||||
- `gmGamePlayUI::RecvNotice_EndCharacterSession @ 0x004EBEA0`
|
||||
|
||||
|
|
@ -40,6 +51,11 @@ The installed retail LayoutDesc establishes the fixed child order and art:
|
|||
| 105 | `0x100000F3` | `0x10000004` | mini-game |
|
||||
| 125 | `0x100000FA` | ordinary button | end character session |
|
||||
|
||||
`gmPanelUI::SetupChildren` reads enum property `0x10000029` from each
|
||||
registered child. The installed main-panel LayoutDesc resolves the indicator
|
||||
detail pages to Link Status `8`, Mini Game `9`, and Vitae `15` (Helpful and
|
||||
Harmful remain `4` and `5`). They are not independent floating-window ids.
|
||||
|
||||
## Pseudocode
|
||||
|
||||
### Link indicator
|
||||
|
|
@ -82,6 +98,46 @@ acdream records the last successfully decoded server datagram in
|
|||
keeps socket/session facts out of the UI while preserving retail's thresholds
|
||||
and cadence.
|
||||
|
||||
### Link Status detail page
|
||||
|
||||
```text
|
||||
On shown:
|
||||
register for time notices
|
||||
pleaseRequestPing = true
|
||||
Update()
|
||||
|
||||
On hidden:
|
||||
unregister time notices
|
||||
pleaseRequestPing = false
|
||||
|
||||
On time notice while visible:
|
||||
if now >= nextUpdate:
|
||||
nextUpdate = now + 5 seconds
|
||||
Update()
|
||||
|
||||
Update:
|
||||
replace text with localized connection explanation + 5/20-second legend
|
||||
append 10-second packet-loss percentage with two decimal places
|
||||
append ping in milliseconds, or "????" before a response
|
||||
if pleaseRequestPing or now - lastPingRequest >= 120 seconds:
|
||||
lastPingRequest = now
|
||||
Event_RequestPing()
|
||||
pleaseRequestPing = false
|
||||
|
||||
Event_RequestPing:
|
||||
send F7B1, game-action sequence, opcode 0x01E9
|
||||
// no payload
|
||||
|
||||
On empty 0x01EA PingResponse:
|
||||
pingRoundTrip = monotonicNow - lastPingRequest
|
||||
```
|
||||
|
||||
The network session owns the send timestamp and response sample. The retained
|
||||
page owns only retail's display and refresh cadence. acdream's transport does
|
||||
not yet expose the retail NAK/retransmission moving averages, so packet-loss
|
||||
averaging remains the explicit AP-110 residual rather than being guessed from
|
||||
ordinary packet sequence gaps.
|
||||
|
||||
### Helpful and harmful effects
|
||||
|
||||
```text
|
||||
|
|
@ -109,6 +165,25 @@ On PlayerDesc or VitaeChanged:
|
|||
SetState(Ghosted = 13)
|
||||
```
|
||||
|
||||
The detail page uses the same modifier:
|
||||
|
||||
```text
|
||||
lostPercent = 100 - int(vitae * 100)
|
||||
if lostPercent <= 0:
|
||||
show localized full-strength sentence
|
||||
else:
|
||||
vitaePool = player PropertyInt 129
|
||||
deathLevel = player PropertyInt 139, falling back to Level (25)
|
||||
threshold = int(((deathLevel ^ 2.5 * 2.5) + 20)
|
||||
* vitae ^ 5 + 0.5)
|
||||
remaining = threshold - vitaePool
|
||||
show localized lost-percent sentence and remaining-XP sentence
|
||||
```
|
||||
|
||||
The x87 powers omitted from the named pseudo-C output for
|
||||
`VitaeCPPoolThreshold` were cross-checked against the official ACE
|
||||
`Player_Xp.cs` port. The property ids and rounding expression agree.
|
||||
|
||||
### Burden / character information
|
||||
|
||||
```text
|
||||
|
|
@ -136,6 +211,28 @@ The authored ghosted state is rendered now. The notices remain owned by the
|
|||
still-unported mini-game subsystem (existing divergence AP-110), so this task
|
||||
does not manufacture a game-active state from unrelated packets.
|
||||
|
||||
The authored `gmMiniGameUI` root `0x1000016A` is mounted and registered as
|
||||
main panel `9`, including its close behavior. It remains unreachable while the
|
||||
indicator is Ghosted; board state and game actions remain with the unported
|
||||
mini-game subsystem.
|
||||
|
||||
### Shared main-panel ownership
|
||||
|
||||
```text
|
||||
For every toolbar or indicator detail page:
|
||||
register page with gmPanelUI panel id
|
||||
when shown:
|
||||
hide the current child
|
||||
move the requested child to the shared main-panel placement
|
||||
show only the requested child
|
||||
when a page with bool property 0x10000049 closes:
|
||||
restore the deferred ordinary child
|
||||
```
|
||||
|
||||
Helpful/Harmful, Link Status, Vitae, and the Mini Game shell therefore share
|
||||
the same retained host position as Inventory, Character, and Magic. They do
|
||||
not remember independent positions.
|
||||
|
||||
### End character session
|
||||
|
||||
```text
|
||||
|
|
@ -159,8 +256,8 @@ CharacterLogOff and transport Disconnect packets.
|
|||
`EncumbranceSystem::Load @ 0x004FCC40`.
|
||||
- The existing enchantment parser preserves the separate Mult, Add, Vitae, and
|
||||
Cooldown registry buckets used by the retail indicator queries.
|
||||
- ACE/reference source is not present in this worktree. No server behavior is
|
||||
inferred for the strip: state is derived only from packets already parsed by
|
||||
the client, and the named retail client remains the behavior oracle.
|
||||
- Full Link Status, Vitae, and mini-game panels remain tracked by AP-110. This
|
||||
port does not replace them with an ad-hoc panel.
|
||||
- Official ACE was cross-checked for the empty PingResponse and the vitae-pool
|
||||
threshold expression; the named retail client remains the behavior oracle.
|
||||
- The Link Status and Vitae pages now use their authored DAT roots and localized
|
||||
strings. AP-110 retains only packet-loss averaging and mini-game gameplay for
|
||||
this slice; neither is replaced with an ad-hoc approximation.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue