feat(ui): preserve exact retail shortcut records
Carry signed index, object id, and raw spell word losslessly through PlayerDescription, session storage, drag mutation, and AddShortcut wire serialization while keeping gmToolbarUI object-only. Retire AP-103 and record the live ACE relog persistence gate. Co-Authored-By: Codex <codex@openai.com>
This commit is contained in:
parent
e65119f0c6
commit
b5b230c860
21 changed files with 271 additions and 181 deletions
|
|
@ -128,19 +128,26 @@ Client-side restore: `gmToolbarUI::UpdateFromPlayerDesc` (decomp 198838) → `Fl
|
|||
|
||||
Opcode values triple-confirmed: decomp `Event_AddShortCut` packs `*(uint32_t*)var_c = 0x19c` (decomp 679733) and `Event_RemoveShortCut` packs `0x19d` (decomp 680332); ACE `GameActionType.cs:77-78` (`AddShortCut=0x019C, RemoveShortCut=0x019D`); holtburger `opcodes.rs:371-374` (commented, same values).
|
||||
|
||||
**Wire field order — `ShortCutData` payload (16 bytes), CONFIRMED across 3 refs:**
|
||||
**Correction (2026-07-11) — packed `ShortCutData` is 12 bytes, while the C++
|
||||
object is 16 bytes only because it includes a vtable pointer.** Retail's header,
|
||||
constructor, `ShortCutManager::AddShortCut`, and vtable-routed packer establish
|
||||
three native 32-bit fields:
|
||||
```
|
||||
Index : u32 (slot 0..17)
|
||||
Index : i32 (slot 0..17 when valid)
|
||||
ObjectId : u32 (item guid; 0 for spell)
|
||||
SpellId : u16 (LayeredSpell.id; 0 for item)
|
||||
Layer : u16 (LayeredSpell.layer; 0 for item)
|
||||
SpellId : u32 (raw retail spell word; 0 for toolbar-created items)
|
||||
```
|
||||
- Chorizite `ShortCutData.generated.cs:41-46` (`Index`, `ObjectId`, then `LayeredSpellId.Read` = u16 id + u16 layer).
|
||||
- ACE `Shortcut.cs:33-42` `ReadShortcut` (`Index`, `ObjectId`, `ReadLayeredSpell`).
|
||||
- holtburger `shortcuts.rs:13-34` (`index u32`, `object_id Guid`, `spell_id u16`, `layer u16`).
|
||||
- Retail `ShortCutData` in `acclient.h:36484`, constructor `0x005D55E0`,
|
||||
manager copy `0x005D5790`, and 12-byte packer `0x005CABB0` are authoritative.
|
||||
- Chorizite, ACE, and holtburger split the final four bytes into a layered-spell
|
||||
`u16/u16` view. That view is wire-compatible but is not retail's field model;
|
||||
acdream preserves the complete raw `uint` losslessly.
|
||||
RemoveShortCut payload = just `Index:u32` (Chorizite `Character_RemoveShortCut.generated.cs:33`; ACE `GameActionRemoveShortcut.cs:9`; decomp packs `*(uint32_t*)eax_3 = arg1` at 680335).
|
||||
|
||||
**⚠ acdream builder field-naming bug to fix at port time (not a wire bug).** `InventoryActions.BuildAddShortcut(seq, slotIndex, objectType, targetId)` (`InventoryActions.cs:99-110`) writes 24 bytes = 8-byte envelope (`0xF7B1` + seq) + `slotIndex`(u32) + `objectType`(u32) + `targetId`(u32). The **byte layout is correct for item shortcuts** (slot, then guid, then a final dword that for items is `0` = SpellId|Layer), but the parameter names are wrong/misleading: the 2nd field is `Index`, the 3rd is `ObjectId`, and the 4th dword is `SpellId(u16)|Layer(u16)` — there is no separate "objectType". A faithful builder should take `(seq, uint index, uint objectGuid, ushort spellId, ushort layer)` and pack the spell as two u16s. For the toolbar's item-only use, callers must pass `objectGuid` as the 3rd arg and `0` as the 4th. LIKELY a latent bug if anyone wired a "objectType" semantic; flag in the divergence register when the toolbar lands. (CONFIRMED file contents; the "bug" judgment is mine.)
|
||||
**Resolved 2026-07-11:** `AcDream.Core.Items.ShortcutEntry` now owns the exact
|
||||
signed-index/object-id/raw-spell-word value. Parser, store, toolbar mutation, and
|
||||
`InventoryActions.BuildAddShortcut` all carry that value without a layered-spell
|
||||
reinterpretation. The production toolbar still renders only nonzero object ids.
|
||||
|
||||
**ACE's reorder note (important UX contract):** *"When a shortcut is added on top of an existing item, the client automatically sends the RemoveShortcut command for that existing item first, then will add the new item, and re-add the existing item to the appropriate place."* (`Player_Character.cs:254`). This is exactly the `HandleDropRelease` sequence in §5. CONFIRMED.
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue