feat(ui): port retail jump power bar
Import gmFloatyPowerBarUI LayoutDesc 0x21000072, teach the meter factory its stateful single-image shape, and project the movement-owned retail jump charge through a focused retained controller. Preserve authored resize constraints and state-managed visibility, with named-decomp pseudocode plus controller, movement, and production-DAT conformance coverage. Co-Authored-By: Codex <codex@openai.com>
This commit is contained in:
parent
27619b2328
commit
db03b4bda8
18 changed files with 3045 additions and 10 deletions
|
|
@ -46,6 +46,36 @@ Copy this block when adding a new issue:
|
|||
|
||||
---
|
||||
|
||||
## #209 — Retail jump power bar missing
|
||||
|
||||
**Status:** IN-PROGRESS — implementation complete 2026-07-13, pending live visual gate
|
||||
**Severity:** MEDIUM
|
||||
**Component:** retained UI / movement
|
||||
|
||||
**Description:** Holding the jump key charged the movement system correctly,
|
||||
but the separate retail floating power bar did not appear or show jump power.
|
||||
|
||||
**Root cause:** The production retained runtime had not mounted
|
||||
`gmFloatyPowerBarUI` LayoutDesc `0x21000072`. The generic meter importer also
|
||||
mistook its stateful fill child plus hidden Recklessness child for a vitals-style
|
||||
three-slice meter, leaving all slice ids empty.
|
||||
|
||||
**Resolution:** The importer now recognizes the stateful single-image meter
|
||||
shape: the authored direct image is the empty track and the selected numeric
|
||||
child state supplies the fill. `JumpPowerbarController` selects JumpMode, reads
|
||||
the movement controller's existing retail-timed charge snapshot, shows the
|
||||
state-managed window on charge begin, fills left-to-right, and resets/hides it
|
||||
on release. Geometry and resize limits come from the authored DAT layout.
|
||||
|
||||
**Research:** `docs/research/2026-07-13-retail-jump-powerbar-pseudocode.md`
|
||||
|
||||
**Acceptance:** In the connected Release client, hold Jump: the 610×25 retail
|
||||
bar appears and fills smoothly from its left edge to its right edge in about
|
||||
one second. Keep holding at full, then release: the bar resets and disappears as
|
||||
the jump starts. Repeat after moving/resizing the bar and after relogging.
|
||||
|
||||
---
|
||||
|
||||
## #208 — Combat bar appears after logging in peacefully
|
||||
|
||||
**Status:** IN-PROGRESS — fix shipped 2026-07-12, pending live gate
|
||||
|
|
|
|||
|
|
@ -506,7 +506,7 @@ behavior. Estimated 17–26 days focused work, 3–5 weeks calendar.
|
|||
- **Roadmap correction (2026-07-10):** the completion order is now the architecture-first campaign in `docs/superpowers/plans/2026-07-10-retail-ui-fidelity-completion.md`. Retail `gmToolbarUI` is object-only: preserve `ShortCutData.index_`, `objectID_`, and `spellID_`, but do not invent spell glyphs on this bar. `PlayerModule::favorite_spells_[8]` feeds separate spell bars.
|
||||
- **✓ D.5.3 — Toolbar selected-object display (issue #141) SHIPPED.** Exact health/player/pet/Free-PK policy, selected-item mana (`0x100001A2`), stack entry (`0x100001A3`), stack slider (`0x100001A4`), formatted count/name, shared split quantity, click-to-use, peace/war, health/name, and paperdoll self/upper-item selection all passed live by 2026-07-11. Exact raw `ShortCutData` preservation is already shipped in Wave 4.2; the eight `favorite_spells_` lists belong to the separate spellbook/spell-bar phase.
|
||||
- **☐ D.5.5+ — Core panels.** Inventory (`gmInventoryUI`/`gmBackpackUI`), equipment/paperdoll (`gmPaperDollUI`/`gm3DItemsUI` + the `UiViewport` 3D doll), vendor, trade, spellbook. Research drop done (`docs/research/2026-06-16-*`). Depends on **D.5.4** (data model) + the item-slot/list/icon spine (D.5.1/D.5.2) + the **window manager** (Plan 2: open/close/z-order/persist + faithful grip/dragbar drag-resize) + the drag-drop spine wired (`UiRoot` has the chain; the per-cell accept/drop hooks are still stubs in `UiField`). Also deferred from D.5.1: drag/reorder + the `AddShortcut`/`RemoveShortcut` mutate wire.
|
||||
- **D.6 — HUD.** **Radar/compass IMPLEMENTED 2026-07-10; live-world visual gate pending.** It is the retained retail `gmRadarUI` (`LayoutDesc 0x21000074`): a 120×140 circular radar (`0x06004CC1`) with N/E/S/W token sprites orbiting the face, a fixed bright-green player marker, and the coordinate footer (`0x06004CC0`). Projection is `radarPixelRadius / radarRange` with 75 m outdoor / 25 m indoor ranges — there is no 1.18 factor or scrolling compass strip. It lives in `AcDream.App/UI` beside the other imported retail panels. Remaining D.6: target name plate, damage floaters, and other world-space HUD elements through the raw `TextRenderer` path. See slice 06 §A.2, `docs/research/2026-07-10-retail-radar-pseudocode.md`, and the named `gmRadarUI` decomp.
|
||||
- **D.6 — HUD.** **Radar/compass IMPLEMENTED 2026-07-10; jump power bar IMPLEMENTED 2026-07-13; live-world visual gates pending.** The radar is retained retail `gmRadarUI` (`LayoutDesc 0x21000074`): a 120×140 circular face (`0x06004CC1`) with orbiting N/E/S/W tokens, a fixed bright-green player marker, and coordinate footer (`0x06004CC0`). Projection is `radarPixelRadius / radarRange` with 75 m outdoor / 25 m indoor ranges — no 1.18 factor or scrolling strip. The separate `gmFloatyPowerBarUI` (`LayoutDesc 0x21000072`) now appears only while jump is pending and clips the authored JumpMode fill left-to-right from the movement controller's shared 0–1 charge. Both live in `AcDream.App/UI` behind focused controllers; `GameWindow` supplies state delegates only. Remaining D.6: target name plate, damage floaters, and other world-space HUD elements through the raw `TextRenderer` path. See slice 06 §A.2, `docs/research/2026-07-10-retail-radar-pseudocode.md`, `docs/research/2026-07-13-retail-jump-powerbar-pseudocode.md`, and the named `gmRadarUI`/`gmPowerbarUI` decomp.
|
||||
- **✓ SHIPPED — D.7 — Cursor manager (user-confirmed 2026-07-11).** All reachable `ClientUISystem::UpdateCursorState @ 0x00564630` branches resolve through production DAT EnumIDMap table 6, with event-ordered global-default versus captured/hovered `MediaDescCursor` layering from `UIElementManager::CheckCursor @ 0x0045ABF0`. OS fallback remains only AP-72 and emits a visible diagnostic. The live gate covered world/object, combat, targeted-use, text, move/resize, and drag contexts; combat-indicator mouse clicks and the quick key share the same toggle command.
|
||||
- ~~**D.8 — Sound.**~~ **Superseded — shipped as Phase E.2** (`SoundTable`/`Sound` dat decode, OpenAL 16-voice engine, per-entity 3D positional audio via `AudioHookSink`). Entry kept here for history; see the shipped table.
|
||||
|
||||
|
|
|
|||
|
|
@ -566,11 +566,13 @@ Open the inventory panel — retail-skinned with the right font, icons, and
|
|||
- **C.3** — Palette range tuning (skin/hair/eye colors match retail).
|
||||
- **C.4** — Double-sided translucent polys.
|
||||
- **D.2b** — Custom retail-look UI backend. **In progress:** vitals + chat + toolbar + inventory (window manager, B-Grid, B-Controller, B-Wire, drag-drop, container-switching) + paperdoll (equip slots, 3-D doll UiViewport, Slots toggle) + **Character window** (Attributes tab, visually confirmed 2026-06-26) + **UI Studio** (standalone panel previewer + 26-window retail dump + interactive click-routing + headless screenshot) + **importer dat-fidelity** (Fix A/B/C: justification, FontColor, per-element FontDid resolver [studio-only; #157 tracks live-game path]) are shipped. Current campaign: shared retained-widget/window architecture, then selected-object mana/stack completion. **Retail correction:** the main toolbar is object-only; the eight favorite-spell lists drive separate spell bars. Execution plan: `docs/superpowers/plans/2026-07-10-retail-ui-fidelity-completion.md`.
|
||||
- **D.3–D.7** — AcFont + dat sprites + core panels reskinned + HUD orbs +
|
||||
cursor manager. **D.6 radar/compass shipped 2026-07-10; D.7 complete retail
|
||||
- **D.3–D.7** — AcFont + dat sprites + core panels reskinned + HUD +
|
||||
cursor manager. **D.6 radar/compass shipped 2026-07-10 and the separate retail
|
||||
jump power bar was implemented 2026-07-13; D.7 complete retail
|
||||
cursor catalog/precedence shipped and user-confirmed 2026-07-11.** The radar uses the retained
|
||||
UI architecture using the retail DAT layout and recovered runtime behavior;
|
||||
live-game visual confirmation remains the user gate.
|
||||
the jump bar uses the same retained composition with movement-owned charge timing.
|
||||
Live-game visual confirmation remains the user gate.
|
||||
- **L.1f** — NPC/monster + item-use animation coverage.
|
||||
|
||||
**Freeze on landing:**
|
||||
|
|
|
|||
135
docs/research/2026-07-13-retail-jump-powerbar-pseudocode.md
Normal file
135
docs/research/2026-07-13-retail-jump-powerbar-pseudocode.md
Normal file
|
|
@ -0,0 +1,135 @@
|
|||
# Retail jump power bar — pseudocode and port map
|
||||
|
||||
Date: 2026-07-13
|
||||
|
||||
Binary: Sept. 2013 EoR `acclient.exe` v11.4186
|
||||
|
||||
Scope: the floating `gmPowerbarUI` presentation used while the player charges a jump
|
||||
|
||||
## Named retail sources
|
||||
|
||||
- `gmPowerbarUI::PostInit @ 0x004DA4E0`
|
||||
- `gmPowerbarUI::RecvNotice_SetPowerbarLevel @ 0x004DA550`
|
||||
- `gmPowerbarUI::RecvNotice_FinishPowerbar @ 0x004DA580`
|
||||
- `gmPowerbarUI::RecvNotice_BeginPowerbar @ 0x004DA730`
|
||||
- `gmFloatyPowerBarUI::PostInit @ 0x004D0F00`
|
||||
- `gmFloatyPowerBarUI::UpdateFromPlayerModule @ 0x004D1200`
|
||||
- `gmFloatyPowerBarUI::ResizeTo @ 0x004D1460`
|
||||
- `gmFloatyPowerBarUI::MoveTo @ 0x004D15D0`
|
||||
- `gmFloatyPowerBarUI::SetVisible @ 0x004D17D0`
|
||||
- `ClientCombatSystem::FinishJump @ 0x0056A9B0`
|
||||
- `ClientCombatSystem::StartPowerBarBuild @ 0x0056ADB0`
|
||||
- `ClientCombatSystem::GetPowerBarLevel @ 0x0056ADE0`
|
||||
- `ClientCombatSystem::CommenceJump @ 0x0056AF90`
|
||||
- `ClientCombatSystem::DoJump @ 0x0056B110`
|
||||
|
||||
The symbols and addresses above are present in
|
||||
`docs/research/named-retail/symbols.json`; the bodies are in
|
||||
`docs/research/named-retail/acclient_2013_pseudo_c.txt`.
|
||||
|
||||
## Authored DAT layout
|
||||
|
||||
Portal DAT `LayoutDesc 0x21000072` is a `gmFloatyPowerBarUI` window:
|
||||
|
||||
| Element | ID | Geometry | Media/state |
|
||||
|---|---:|---:|---|
|
||||
| Root | `0x10000612` | 610×25 px | custom type `0x10000053` |
|
||||
| Meter | `0x10000034` | x=5, y=5, 600×15 px | empty track `0x06004D0B` |
|
||||
| Fill field | `0x00000002` | 600×15 px | JumpMode `0x10000042` → `0x06001354`; MeleeMode `0x10000043` and MissileMode `0x10000044` → `0x06001200`; DDDMode `0x10000045` → `0x0600195B` |
|
||||
| Recklessness field | `0x100005EE` | x=60, 480×15 px | `0x0600715E`; hidden by `PostInit` |
|
||||
|
||||
The meter's fill is clipped horizontally. A level of 0.0 shows no fill; 0.5
|
||||
shows the left 300 px; 1.0 shows the full 600 px. It does not stretch from the
|
||||
center or from the right.
|
||||
|
||||
## Retail lifecycle pseudocode
|
||||
|
||||
```text
|
||||
CommenceJump():
|
||||
if jump_pending:
|
||||
return
|
||||
error = motion_interpreter.charge_jump()
|
||||
if error != success:
|
||||
report the matching jump error
|
||||
return
|
||||
cancel repeat attack if active
|
||||
latest_powerbar_level = 0
|
||||
jump_pending = true
|
||||
powerbar_mode = JUMP
|
||||
notify BeginPowerbar(JUMP)
|
||||
StartPowerBarBuild()
|
||||
|
||||
StartPowerBarBuild():
|
||||
build_in_progress = true
|
||||
build_start_time = current_time
|
||||
notify SetPowerbarLevel(powerbar_mode, 0)
|
||||
latest_powerbar_level = 0
|
||||
|
||||
GetPowerBarLevel():
|
||||
if not build_in_progress:
|
||||
return 0
|
||||
duration = 0.8 seconds in dual-wield style, otherwise 1.0 second
|
||||
return clamp((current_time - build_start_time) / duration, 0, 1)
|
||||
|
||||
gmPowerbarUI.BeginPowerbar(JUMP):
|
||||
set root state to JumpMode (0x10000042)
|
||||
current_mode = JUMP
|
||||
set meter 0x10000034 level to 0
|
||||
show window
|
||||
|
||||
gmPowerbarUI.SetPowerbarLevel(mode, level):
|
||||
if mode == current_mode:
|
||||
set meter 0x10000034 level to level
|
||||
|
||||
DoJump(on release):
|
||||
extent = max(GetPowerBarLevel(), MIN_JUMP_EXTENT)
|
||||
FinishJump()
|
||||
motion_interpreter.jump(extent)
|
||||
send JumpPack(extent, velocity, position/update sequences)
|
||||
|
||||
FinishJump():
|
||||
if jump_pending:
|
||||
stop build and clear its time
|
||||
notify FinishPowerbar(JUMP)
|
||||
powerbar_mode = UNDEFINED
|
||||
clear standing_longjump
|
||||
jump_pending = false
|
||||
|
||||
gmPowerbarUI.FinishPowerbar(JUMP):
|
||||
if JUMP == current_mode:
|
||||
current_mode = UNDEFINED
|
||||
set meter level to 0
|
||||
hide window
|
||||
```
|
||||
|
||||
`gmPowerbarUI::PostInit` also hides the recklessness field. The floaty subclass
|
||||
restores and persists its position, size, lock chrome, and visibility through
|
||||
the normal retail window preferences.
|
||||
|
||||
## Reference cross-checks
|
||||
|
||||
- ACE `ACE.Server/Network/Structure/JumpPack.cs` documents `Extent` as jump
|
||||
power 0–1. `ACE.Server/WorldObjects/Player.cs::HandleActionJump` clamps the
|
||||
received extent to that same interval before applying jump stamina/height.
|
||||
- holtburger `crates/holtburger-core/src/client/commands.rs` carries the chosen
|
||||
extent unchanged into the `JumpData` action. Its vendored ACViewer movement
|
||||
implementation likewise stores jump extent as the power input to the jump
|
||||
calculation.
|
||||
|
||||
These references corroborate the data range and its handoff. The named retail
|
||||
decomp remains authoritative for charge timing, notices, visibility, and UI
|
||||
state selection.
|
||||
|
||||
## acdream port map
|
||||
|
||||
- `PlayerMovementController` already owns the exact shared retail charge clock
|
||||
and release transition. Expose it as a read-only `(IsCharging, Power)`
|
||||
snapshot; do not add a UI timer.
|
||||
- Teach `UiMeter`/`DatWidgetFactory` the DAT's stateful single-image meter shape:
|
||||
meter direct media is the track, child state media is the selected fill.
|
||||
- `JumpPowerbarController` selects JumpMode, binds fill to the movement snapshot,
|
||||
and performs the begin/show and finish/reset/hide transitions.
|
||||
- `RetailUiRuntime` imports and mounts `0x21000072` as a state-managed retained
|
||||
window. `GameWindow` only supplies the movement snapshot delegate.
|
||||
|
||||
This port introduces no intentional retail divergence.
|
||||
Loading…
Add table
Add a link
Reference in a new issue