Unify the toolbar shortcut manager with Runtime inventory state, route retail-ordered shortcut and spellbook command effects through the canonical owners, and make retained controllers borrow those exact instances. Remove the item-interaction transaction fallback and add graphical/no-window parity plus failure-safe terminal ownership-ledger coverage. Co-authored-by: Codex <codex@openai.com>
4.1 KiB
Slice J4.5 — retail local gameplay-command ordering
Scope
This note fixes the command/local-state ordering used while J4.5 removes the
last graphical-only shortcut and spellbook mirrors. It does not add a new
gameplay algorithm. It preserves the existing packet builders and moves the
retail PlayerModule mutation onto the one Runtime-owned state object.
Oracle:
docs/research/named-retail/acclient_2013_pseudo_c.txtdocs/research/named-retail/acclient.h
The existing wire ports remain:
AcDream.Core.Net.Messages.ClientCommandRequestsAcDream.Core.Net.WorldSessionAcDream.App.Net.LiveSessionCommandRouter
Retail pseudocode
Toolbar shortcut add
Retail anchors:
gmToolbarUI::AddShortcut @ 0x004BD9A0PlayerModule::AddShortCut @ 0x005D29A0ShortCutManager::AddShortCut @ 0x005D5790
if slot is valid and the toolbar accepts the item:
create ShortCutData(slot, objectId, spellId)
send Event_AddShortCut(data)
playerModule.AddShortCut(data)
ShortCutManager.AddShortCut(data):
if data.index is outside [0, 18):
return false
if the slot already owns a record:
replace all three record fields in place
else:
allocate and install one record
return true
Toolbar shortcut remove
Retail anchors:
gmToolbarUI::RemoveShortcut @ 0x004BD450PlayerModule::RemoveShortCut @ 0x005D29E0ShortCutManager::RemoveShortCut @ 0x005D5690
find the slot containing the selected shortcut
flush the visible slot
if this is a persisted removal:
send Event_RemoveShortCut(slot)
playerModule.RemoveShortCut(slot)
ShortCutManager.RemoveShortCut(slot):
if slot is outside [0, 18):
return
destroy the record if present
set the slot to empty
Favorite spell add/remove
Retail anchors:
- spell-menu handler at
0x004C64C0 PlayerModule::AddSpellFavorite @ 0x005D43E0PlayerModule::RemoveSpellFavorite @ 0x005D4910
add:
if tab is in [0, 8):
insert spellId at position in that tab
send Event_AddSpellFavorite(spellId, position, tab)
remove:
if tab is in [0, 8):
remove spellId from that tab
send Event_RemoveSpellFavorite(spellId, tab)
Unlike toolbar shortcuts, favorite-spell state changes locally before the outbound event.
Spellbook filter
Retail anchors:
gmSpellbookUI::UpdateFilter @ 0x0048B5E0
derive the changed school/level bit
derive the next filter bitfield from the button state
if next differs from current:
playerModule.SetSpellbookFilter(next)
send Event_SpellbookFilterEvent(next)
rebuild the visible spell list
scroll to row zero
Desired component level
Retail anchors:
gmSpellComponentUI::ListenToElementMessage @ 0x0048A420PlayerModule::SetDesiredCompLevel @ 0x005D4940
parse the edited amount
if amount is in [0, 5000]:
send Event_SetDesiredComponentLevel(componentId, amount)
playerModule.SetDesiredCompLevel(componentId, amount)
else:
restore the current value in the editor
PlayerModule.SetDesiredCompLevel(componentId, amount):
if amount is outside [0, 5000]:
return false
lazily create the desired-component table
replace an existing value or add a new value
return true
Retail retains an explicit zero-valued entry. J4.5 preserves that distinction; only the clear-list command destroys the complete desired-component table.
Clear desired components
Retail anchors:
- chat-command handler at
0x0056FE4A PlayerModule::ClearDesiredCompList @ 0x005D2A00
send Event_SetDesiredComponentLevel(INVALID_DID, -1)
destroy the complete desired-component table
set the table pointer to null
publish the spell-component UI update notice
J4.5 integration consequence
The graphical toolbar, retained spell UI, plugins, and future no-window host
must all mutate the same Runtime-owned ShortcutStore and Spellbook.
Graphical controllers may initiate the operation, but they may not retain or
reconstruct another mutable slot/favorite/component collection. Commands stay
synchronous; no additional frame or background queue is introduced.