# Retail client-command routing and lifestone recall Date: 2026-07-13 ## Scope This note records the retail path used for chat-bar commands and the first ported client command, `@lifestone` (`@lif`, `@ls`). It deliberately separates commands the retail client executes from ACE administrator commands that the server consumes as Talk text. ## Named-retail sources - `ChatInterface::ProcessCommand @ 0x004F5100` - `ClientCommunicationSystem::OnChatCommand @ 0x00581320` - `ClientCommunicationSystem::DoLifestone @ 0x0056FC70` - `ClientCommunicationSystem::HelpLifestone @ 0x00578500` - `CM_Character::Event_TeleToLifestone @ 0x006A1B90` - Command-table construction at `0x005838F7` through `0x00583A2B` - Alias data at `0x007E17E4` (`ls`), `0x007E17E8` (`lif`), and `0x007E17EC` (`lifestone`) Source file: `docs/research/named-retail/acclient_2013_pseudo_c.txt`. ## Cross-references - ACE consumes server/admin commands such as `@ci` from the Talk game action. That is a different path from retail client commands. - acdream already has the exact lifestone action builder in `AcDream.Core.Net.Messages.InteractRequests.BuildTeleToLifestone`. - holtburger's chat parser is useful for chat aliases, but the named retail command registry is authoritative for client-command ownership and aliases. ## Retail pseudocode ### Chat submission ```text ChatInterface.ProcessCommand(): text = read chat input communicationSystem.OnChatCommand(text, currentCommandSource) append text to input history ``` ```text ClientCommunicationSystem.OnChatCommand(text, source): allow plugin to inspect/replace the input remember the current source and trimmed command line if first character is '/': replace it with '@' return DoCommand() if first character is '@': return DoCommand() if first character denotes an emote shortcut: rewrite to '@emote ...' return DoCommand() otherwise: route as ordinary speech according to the current talk focus ``` ### Lifestone command registration ```text register "lifestone" -> DoLifestone, HelpLifestone register "lif" -> DoLifestone, HelpLifestone register "ls" -> DoLifestone, HelpLifestone ``` The registry uses case-insensitive command keys. ### Lifestone command execution ```text ClientCommunicationSystem.DoLifestone(argumentCount, arguments): if argumentCount == 0: CM_Character.Event_TeleToLifestone() else: add the command's usage/error text to the chat scroll return handled ``` ```text CM_Character.Event_TeleToLifestone(): sequence = Proto_UI.GetNextUICounter() packet = OrderHdr(gameActionEnvelope, sequence, payloadLength = 12) packet.action = 0x0063 sent = Proto_UI.SendToWeenie(packet) if not sent: Proto_UI.UICounterFailedSend(sequence) return sent ``` ## Port contract 1. Both `/` and `@` prefixes are accepted for retail client commands. 2. `lifestone`, `lif`, and `ls` match case-insensitively. 3. The command accepts no arguments. Invalid arguments display usage locally and send neither chat nor a game action. 4. A valid command publishes a typed client action. The App layer executes it through `WorldSession`; UI code never touches the network session. 5. Unknown command verbs remain server commands: `/foo` is canonicalized to `@foo` and sent through Talk so ACE remains authoritative for its command set. 6. The wire body is the existing 12-byte game-action envelope with opcode `0x0063`; no command text is sent for lifestone recall.