Chat and commands
Chat lines and slash commands are the first interactive surface most game modes build. Both arrive as server events, and one global switch decides whether plain chat is relayed to other players automatically.
How a chat line travels
Section titled “How a chat line travels”When a player submits the chat input, the line takes this path:
- The client’s
chatSendevent fires synchronously. A handler returningfalseswallows the line before it leaves the machine (Chat.send(text)bypasses this event). - The line reaches the server. If it starts with
/, the server raisesplayerCommandwith the command name and whitespace-split arguments. Otherwise it raisesplayerChat. - If the default relay is enabled (it is by default), a plain chat line is forwarded to every client, where it arrives through the client’s
chatMessageevent and the native chat overlay draws it.
Events.on("playerChat", (player, text) => { console.log(`${player.nickname}: ${text}`);});Disable the relay to take full control of chat distribution — team chat, proximity chat, or muting:
Chat.setDefaultRelay(false);With the relay off, nothing is forwarded until you do it yourself: forward the line to your chosen recipients with player.emit, and draw it client-side (with a web view, Render2D, or Hud.showMessage).
A command dispatcher
Section titled “A command dispatcher”playerCommand gives you (player, command, args) with the leading / stripped. A lookup table keeps the handler flat as the command set grows:
const COMMANDS = { veh(player, args) { const modelId = args.length ? Number(args[0]) : Math.floor(Math.random() * 52); if (!Number.isInteger(modelId) || modelId < 0 || modelId > 51) { return notify(player, "Usage: /veh [0-51]"); } const p = player.position; Vehicle.spawn(modelId, new Vector3(p.x + 3, p.y, p.z)); notify(player, `Spawned vehicle model ${modelId}.`); },
heal(player, args) { const amount = args.length ? Number(args[0]) : null; if (amount === null) player.restoreHealth(); else player.setHealth(amount); notify(player, "Health restored."); },
announce(player, args) { const text = args.join(" "); if (!text) return notify(player, "Usage: /announce <text>"); Events.emitAllClients("mygm:announce", { text, from: player.nickname }); },};
Events.on("playerCommand", (player, command, args) => { const handler = COMMANDS[command.toLowerCase()]; if (!handler) return notify(player, `Unknown command /${command}.`); handler(player, args);});notify() is the one-line HUD feedback helper from Server, client, and the UI — there is no server-side “send chat line” API, so command feedback goes to the player’s HUD (or your own chat UI) via an intent.
Console commands
Section titled “Console commands”Lines typed into the server console that are not a built-in server command are raised through consoleCommand — same shape, no player:
Events.on("consoleCommand", (command, args) => { if (command === "players") { World.players.forEach((p) => console.log(` ${p.nickname} (ping ${p.ping}ms)`)); }});Client-side chat control
Section titled “Client-side chat control”The client can drive the native chat UI directly — everything local, no server involvement:
| Call | Effect |
|---|---|
Chat.open() / Chat.close() / Chat.isOpen() |
Control the chat input box. |
Chat.setUIVisible(visible) |
Show or hide the chat overlay without touching the input. |
Chat.send(text) |
Submit a line programmatically, bypassing chatSend. |
Events.on("chatMessage", (m) => …) |
Observe incoming lines (m.author, m.text, m.color) — for a custom chat renderer. |
A custom chat interface is the combination: hide the native overlay with Chat.setUIVisible(false), render chatMessage events yourself, and submit through Chat.send.
