acdream/docs/research/2026-07-13-retail-jump-powerbar-pseudocode.md
Erik db03b4bda8 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>
2026-07-13 10:22:12 +02:00

4.9 KiB
Raw Blame History

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 0x100000420x06001354; MeleeMode 0x10000043 and MissileMode 0x100000440x06001200; DDDMode 0x100000450x0600195B
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

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.