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:
Erik 2026-07-11 09:17:33 +02:00
parent e65119f0c6
commit b5b230c860
21 changed files with 271 additions and 181 deletions

View file

@ -1,4 +1,5 @@
using System.Buffers.Binary;
using AcDream.Core.Items;
namespace AcDream.Core.Net.Messages;
@ -98,20 +99,20 @@ public static class InventoryActions
return body;
}
/// <summary>Pin an item/spell to a quickbar slot. ShortCutData = Index(u32), ObjectId(u32),
/// SpellId(u16), Layer(u16) — CONFIRMED across ACE/Chorizite/holtburger (action-bar deep-dive
/// §131-145). For an ITEM: objectGuid = item guid, spellId = layer = 0.</summary>
public static byte[] BuildAddShortcut(
uint seq, uint index, uint objectGuid, ushort spellId, ushort layer)
/// <summary>
/// Pack retail <c>ShortCutData</c> for AddShortcut: signed index, object id,
/// and raw 32-bit spell word. Retail uses the same three-u32 packer as
/// <c>InventoryPlacement::Pack @ 0x005CABB0</c> through the shortcut vtable.
/// </summary>
public static byte[] BuildAddShortcut(uint seq, ShortcutEntry entry)
{
byte[] body = new byte[24];
BinaryPrimitives.WriteUInt32LittleEndian(body, GameActionEnvelope);
BinaryPrimitives.WriteUInt32LittleEndian(body.AsSpan(4), seq);
BinaryPrimitives.WriteUInt32LittleEndian(body.AsSpan(8), AddShortcutOpcode);
BinaryPrimitives.WriteUInt32LittleEndian(body.AsSpan(12), index);
BinaryPrimitives.WriteUInt32LittleEndian(body.AsSpan(16), objectGuid);
BinaryPrimitives.WriteUInt16LittleEndian(body.AsSpan(20), spellId);
BinaryPrimitives.WriteUInt16LittleEndian(body.AsSpan(22), layer);
BinaryPrimitives.WriteInt32LittleEndian(body.AsSpan(12), entry.Index);
BinaryPrimitives.WriteUInt32LittleEndian(body.AsSpan(16), entry.ObjectId);
BinaryPrimitives.WriteUInt32LittleEndian(body.AsSpan(20), entry.SpellId);
return body;
}