Translate suicide response 0x004A as retail's successful self-kill notice. Port /framerate onto the authored SmartBox FPS element with live two-decimal FPS and DEG values, keep diagnostic window chrome independent, and synchronize command-driven settings without discarding panel drafts. Co-Authored-By: Codex <codex@openai.com>
13 KiB
Retail client command families
Date: 2026-07-13
Scope
This note extends the first lifestone vertical slice with the exact command families approved for porting. The named September 2013 retail client is the behavioral oracle; ACClientLib is used as an independent wire-name and payload cross-check.
Sources
ClientCommunicationSystem::DoMarketplace @ 0x0056FCE0ClientCommunicationSystem::DoLockUI @ 0x005703B0ClientCommunicationSystem::DoFrameRate @ 0x005707D0gmSmartBoxUI::UpdateFPSMeter @ 0x004D63A0gmSmartBoxUI::RecvNotice_SetFramerateDisplay @ 0x004D65E0gmSmartBoxUI::UseTime @ 0x004D6E30ClientCommunicationSystem::DoDie @ 0x00580050ClientCommunicationSystem::DieDialogCallback @ 0x0057BA70CM_Character::Event_Suicide @ 0x006A1B00ClientCommunicationSystem::DoPKArena @ 0x005788D0ClientCommunicationSystem::DoPKLArena @ 0x005789D0ClientCommunicationSystem::DoAge @ 0x0057C5A0ClientCommunicationSystem::DoBirth @ 0x0056E5F0CM_Character::Event_QueryAge @ 0x006A1620CM_Character::Event_QueryBirth @ 0x006A16F0CM_Character::Event_TeleToMarketplace @ 0x006A1C20CM_Character::Event_TeleToPKArena @ 0x006A1CB0CM_Character::Event_TeleToPKLArena @ 0x006A1D40CM_House::Event_TeleToHouse_Event @ 0x006AAFA0CM_House::Event_TeleToMansion_Event @ 0x006AB030CM_Character::DispatchUI_QueryAgeResponse @ 0x006A2E40ClientCommunicationSystem::Handle_Character__QueryAgeResponse @ 0x005711D0- retail command-table construction at
0x00581900..0x00585100
Independent protocol cross-check:
references/acclientlib/UtilityBelt.Common/MessageTypes.csreferences/acclientlib/UtilityBelt.Common/Enums/Enums.csreferences/acclientlib/UtilityBelt.Scripting/Enums/BusyAction.cs- ACE
Source/ACE.Server/Network/GameAction/Actions/handlers forSetAFKMode,ModifyCharacterSquelch,QueryAge,ConfirmationResponse,SetDesiredComponentLevel,AddFriend, and the teleport families - ACE
GameEventConfirmationRequest,GameEventFriendsListUpdate, andNetwork/Structure/SquelchDB/SquelchInfowriters
ACE's self age/birth handlers describe the trailing four zero bytes as an
empty aligned String16L; named retail describes the same self-command bytes
as object id zero. The wire bytes are identical for this path, and the named
retail interpretation remains authoritative.
Packet pseudocode
All actions use the normal 0xF7B1 game-action envelope and the next UI
sequence number.
send_parameterless_action(opcode):
packet = [0xF7B1, next_sequence(), opcode]
send packet to the weenie server
marketplace(): send_parameterless_action(0x028D)
pk_arena(): send_parameterless_action(0x0027)
pkl_arena(): send_parameterless_action(0x0026)
house_recall(): send_parameterless_action(0x0262)
mansion_recall(): send_parameterless_action(0x0278)
send_character_query(opcode, object_id):
packet = [0xF7B1, next_sequence(), opcode, object_id]
send packet to the weenie server
query_age(): send_character_query(0x01C2, selected_player_or_zero)
query_birth(): send_character_query(0x01C4, selected_player_or_zero)
For the ordinary self-command, selected_player_or_zero is zero. Retail's
privileged PSR path may use the currently selected player; acdream does not
claim that privileged mode.
Command pseudocode
marketplace(arguments):
if no arguments: send marketplace action
else: display local usage
pk_arena(arguments):
if arguments: display local usage
else if local player is not full PK: display retail failure 0x055F
else: send PK-arena action
pkl_arena(arguments):
if arguments: display local usage
else if local player is not PKLite: display retail failure 0x0560
else: send PKLite-arena action
Retail derives both eligibility checks from the local player's
PublicWeenieDesc bits (IsPK / IsPKLite), not from a guessed server
capability.
framerate(arguments):
if arguments: display local usage
else:
show_framerate = !show_framerate
notify gmSmartBoxUI
if enabled:
resolve UIElement_Text 0x10000047 from LayoutDesc 0x2100000F
show it and update it immediately
else:
hide it and clear the active FPS-display pointer
smartbox_use_time():
if the FPS-display pointer is active:
update the display with two-precision values:
"FPS: {Render.GetFramerate():F2}"
"DEG: {active_degrade_multiplier:F2}"
lockui(arguments):
if arguments: display local usage
else:
ui_locked = !ui_locked
broadcast the UI-lock state change
The two-line template is portal string-table entry 0x0DCFFF73 in table
0x23000001; its authored text fragments are FPS: and \nDEG: . The
display is the exact 128×36 SmartBox text element at (1,1), using font
0x4000001A. Retail registers only the exact command name /framerate;
/framrate is not an alias.
die(arguments):
if arguments: display local usage
else:
show the authored local confirmation dialog
if accepted: send parameterless game action 0x0279
suicide_response(weenie_error):
if code == 0x004A:
display "Ack! You killed yourself!"
0x004A is an informational success response, despite arriving through the
WeenieError message family. Retail's own error-string table contains that exact
text; exposing the numeric fallback makes a successful /die look like a
failure.
query_age_response(name, duration):
if name is empty: display "You have played for {duration}."
else: display "{name} has played for {duration}."
The age-response payload is two aligned CP-1252 String16L values: target
name (empty for self), then the already-formatted duration. Birth has no
dedicated response event in the retail registry; the server supplies its
result through the existing communication/system-text path.
Location and corpse pseudocode
Sources:
ClientCommunicationSystem::DoLoc @ 0x0057A250Position::ToString @ 0x005A9330ClientCommunicationSystem::DoCorpse @ 0x00578220LandDefs::CellidToCoordinateString @ 0x005A9CB0
loc(arguments):
if arguments: display local usage
else if player position has no cell: display "Not in valid cell!"
else:
position_text = format(
"0x%08X [%f %f %f] %f %f %f %f",
cell, x, y, z, quaternion_w, quaternion_x,
quaternion_y, quaternion_z)
display "Your location is: {position_text}"
corpse(arguments):
// Retail ignores arguments for this command.
last_outside = player quality PositionType.LastOutsideDeath (0x0E)
if absent:
display "We're sorry, but we have no record of your last outside corpse location."
else:
coordinates = cell_id_to_coordinate_string(last_outside.cell)
display "The last time you died outside, your corpse was located at ({coordinates})."
The corpse command reads the position already carried by PlayerDescription; it does not infer the corpse location from a nearby corpse object or the most recent death chat line.
Chat-local and UI-layout pseudocode
Sources:
ClientCommunicationSystem::DoClear @ 0x0056E600ClientCommunicationSystem::DoSaveUI @ 0x0056FFF0ClientCommunicationSystem::DoLoadUI @ 0x00570150ClientCommunicationSystem::DoSaveAutoUI @ 0x005702B0ClientCommunicationSystem::DoLoadAutoUI @ 0x00570330
clear(arguments):
source = current_chat_source
if first argument equals "all", ignoring case: source = all_sources
clear(source)
save_ui(arguments):
reject more than one argument with the retail usage message
name = first argument, or the empty/default profile
reject names longer than 16 characters
save every attached window's current placement and visibility to name
load_ui(arguments):
apply the same argument rules as save_ui
restore every attached window from name
save_auto_ui(arguments):
reject arguments
save every attached window under the current character and resolution
load_auto_ui(arguments):
reject arguments
restore every attached window for the current character and resolution
The original serializes UIElement_Position records. acdream stores the same
observable placement/visibility values in its typed layout store; the storage
format is deliberately modern and remains tracked as divergence IA-15.
Friends pseudocode
Sources:
ClientCommunicationSystem::DoFriends @ 0x0057BC00ClientCommunicationSystem::DoFriendsAdd @ 0x00578FB0ClientCommunicationSystem::DoFriendsRemove @ 0x00579080gmFriendsUI::Request_AddFriend @ 0x0048D240CM_Login::AddFriend @ 0x006A3020CM_Login::RemoveFriend @ 0x006A30A0CM_Login::ClearFriends @ 0x006A3110
friends(arguments):
no arguments: display all friends
"online": display only online friends
"add <name>": add_friend(name)
"remove <name>": remove_friend(name)
"old": request the legacy server friends listing
otherwise: display "Invalid friends command specified."
add_friend(name):
require a non-empty name
if local list already has 50 entries: display WeenieError 0x0561
else send opcode 0x0018 followed by String16L name
remove_friend(name):
require a non-empty name
if name equals "-all":
send opcode 0x0025 and clear the local list
else if a case-insensitive local match exists:
send opcode 0x0017 followed by the friend's object id
else display WeenieError 0x0563
The server's FriendsListUpdate event is authoritative. Full updates replace
the list; add/remove/login-state updates mutate it by object id. Display order
is the received retail list order.
Away, consent, and message-filter pseudocode
Sources:
ClientCommunicationSystem::DoAFK @ 0x0057B3F0ClientCommunicationSystem::DoConsent @ 0x0057DDA0ClientCommunicationSystem::ProcessSquelchArgs @ 0x00579C30ClientCommunicationSystem::DoSquelch @ 0x0057BF50ClientCommunicationSystem::DoUnSquelch @ 0x0057C070ClientCommunicationSystem::DoFilter @ 0x0057C860ClientCommunicationSystem::DoUnFilter @ 0x0057C880ClientCommunicationSystem::PerformGlobalSquelchMod @ 0x0057C2D0LogTextTypeEnumMapper::IsLegalChannel @ 0x006AFF40
afk(arguments):
no arguments or "on": send opcode 0x000F with true, unless already away
"off": send opcode 0x000F with false, unless already present
"msg <text>": trim/join text, enforce retail's 191-character limit,
send opcode 0x0010 with String16L text, and echo the new text
otherwise: display AFK usage
consent(arguments):
"on" / "off": toggle the local accept-loot-permits option and echo it
"who": send opcode 0x0217
"clear": send opcode 0x0216
"remove <name>": send opcode 0x0218 followed by String16L name
otherwise: display the retail invalid-command text
The option is CharacterOption bit 0x00080000; retail's default mask
0x50C4A54A leaves it clear.
parse_squelch(arguments):
default category = All
consume options before the target:
-reply uses the most recent teller
-account chooses account-wide storage
-<message type> chooses a legal LogTextType
remaining joined text is the target name
squelch / unsquelch:
with no arguments: display the authoritative local squelch database
account target: send opcode 0x0059, add/remove flag, String16L name
character target: send opcode 0x0058, add/remove flag, zero guid,
String16L name, category
filter / unfilter:
with no arguments: display global filters
require exactly a legal -<message type> option
send opcode 0x005B, add/remove flag, category
Legal retail filter types are Speech, Tell, Combat, Magic, Emote, Appraisal,
Spellcasting, Allegiance, Fellowship, Combat_Enemy, Combat_Self, Recall,
Craft, and Salvaging. The inbound SetSquelchDB packet replaces the local
database; command output reads that state rather than inventing client-only
state.
Emote and spell-component pseudocode
Sources:
ClientCommunicationSystem::DoEmote @ 0x00578AD0CM_Communication::Event_Emote @ 0x006A4120ClientCommunicationSystem::DoFillComponents @ 0x0056FD50gmVendorUI::FillComponentList @ 0x004C4540MagicEnumMapper::SpellComponentCategoryFromString @ 0x0056E290
emote(arguments):
text = join all arguments
if text is non-empty: send opcode 0x01DF followed by String16L text
emotes(arguments):
if arguments: display usage
else: display the retail standard-emote help list
fillcomps(arguments):
reject more than two arguments
if first argument is "clear":
send opcode 0x0224, component id 0, amount 0xFFFFFFFF
clear desired component levels and echo "Component list cleared."
return
parse optional component category and optional positive maximum price
if no vendor is open: display "You need an open vendor."
else for each desired component in the chosen category:
needed = desired level - currently held count
find the component in vendor stock and add min(needed, stock) to buy list
stop before exceeding the maximum price and report the limit
Accepted category spellings are Scarab(s), Herb(s), PowderedGem(s) or Powder(s), AlchemicalSubstance(s) or Potion(s), Talisman(s), Taper(s), and Pea(s). Component buying remains an operation on the vendor controller; the command parser does not duplicate vendor inventory or price logic.