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:
Erik 2026-07-13 10:22:03 +02:00
parent 27619b2328
commit db03b4bda8
18 changed files with 3045 additions and 10 deletions

View 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 01. `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.