Skip to main content

Command

Use Command to register, remove, inspect, list, and execute commands from chat (/command) and debug console (command).

Prerequisites​

  • Command runtime module must be enabled on server/client runtime for Command.* to be available.

Error Handling Pattern​

  • Success: err == nil
  • Failure: err contains an error code string

Scope Model​

  • Client runtime supports local command registration/execution and optional server forwarding.
  • Server runtime is authoritative for privileged command execution.

Node Relationship​

  • Command is control-plane orchestration, not a node graph API.
  • Command handlers may call Node.*, Chat.*, Resource.*, etc. based on ACL.
  • For deterministic simulation changes, handlers should invoke server-authoritative NodeSim paths only.

Function List​

FunctionDescriptionScope
Command.AddRegister a command handler and optional help/security metadata.S
Command.RemoveRemove a registered command by name.S
Command.GetGet metadata for one command.S
Command.ListList visible commands for a source type.S
Command.ExecuteParse and execute a command line.S

Event List​

EventDescriptionScope
Built-in eventsNone in Command v1.S
command:executedRecommended custom event for successful execution.S
command:failedRecommended custom event for handler/runtime failures.S
command:deniedRecommended custom event for ACL/context denial.S

Functions​

Command.Add​

S Shared (Client & Server)

local err = Command.Add(name, handler, options)

Parameters:

  • name (string): canonical command name (for example ban, tp, help).
  • handler (function): callback invoked when command executes.
  • options (table, optional): optional fields listed below.
  • description (string): short help text.
  • usage (string): usage string shown in help.
  • aliases (table<string>): shorthand names.
  • restricted (boolean): deny by default unless ACL explicitly allows.

Returns:

  • err (nil or string)

Handler signature:

function handler(execution, args, raw)
-- execution.name
-- execution.source
-- execution.role
-- execution.playerId -- connection/session id
-- execution.accountId -- authenticated account id (if logged in)
-- execution.clientId -- client installation id (if provided)
-- args: parsed array
-- raw: original command line
end

Command.Remove​

S Shared (Client & Server)

local err = Command.Remove(name)

Parameters:

  • name (string)

Returns:

  • err (nil or string)

Command.Get​

S Shared (Client & Server)

local commandInfo, err = Command.Get(name)

Parameters:

  • name (string)

Returns:

  • commandInfo (table or nil)
  • err (nil or string)

Command.List​

S Shared (Client & Server)

local commands, err = Command.List(options)

Parameters:

  • options (table, optional): optional fields listed below.
  • sourceType (chat | debug | system)

Returns:

  • commands (table or nil)
  • err (nil or string)

Command.Execute​

S Shared (Client & Server)

local result, err = Command.Execute(input, options)

Parameters:

  • input (string): raw command line.
  • options (table, optional): optional fields listed below.
  • sourceType (chat | debug | system)
  • source (table): source metadata (for example playerId, clientId, accountId, role).

Returns:

  • result (table or nil)
  • err (nil or string)

result shape:

  • name (string): resolved command name.
  • sourceType (chat | debug | system): effective source type.
  • args (table): parsed argument array.
  • handled (boolean): true when a handler was executed.
  • status (ok | denied | not_found | error): execution outcome.
  • errorCode (string or nil): populated when status is not ok.
  • durationMs (number): execution time in milliseconds.

Source Types​

chat:

  • user enters /command arg1 arg2
  • leading / indicates command mode

debug:

  • user enters command arg1 arg2

system:

  • internal/operator invocation path only (not direct player input)

Security rule:

  • never map direct player input (Input, chat text, UI button clicks) to sourceType=\"system\".

Built-in auth command routing:

  • Server runtime includes built-in login, register, logout, start, stop, and restart command handlers.
  • login/register are denied with ERR_ALREADY_LOGGED_IN when already authenticated.
  • start / stop / restart are registered as restricted commands, so ACL must allow them (default admin / system via cmd.*).
  • Client debug console keeps a small local command set (help, clear, debugscript, reconnect, etc.) and forwards unmatched command names to the connected server command runtime as debug-source requests.
  • Feedback for debug-source server commands is routed back into the debug console, so usage/errors like Usage: start <resourceName> appear there instead of only in chat.
  • reconnect is a built-in client-local command in the debug console. It disconnects and reconnects to the last server target known by the client.
  • /reconnect is intercepted client-side in chat before normal slash-command forwarding. It performs the same client-local reconnect instead of invoking a server command.
  • Reconnect still goes through the normal server handshake and auth abuse controls. Spamming it can trigger server lockouts such as auth_failed:rate_limited_ip_lockout or auth_failed:rate_limited_player_lockout.

Target Selector​

For moderation/gameplay commands that address players (/kick, /ban, /mute, etc.), use:

  • number -> playerId (session id)
  • string prefixed c_ -> clientId
  • string prefixed a_ -> accountId

Identifier Model​

Command execution metadata should distinguish session identity vs persistent identity:

  • playerId: connection/session id (changes per reconnect)
  • accountId: authenticated account id when logged in; nil for guests
  • clientId: installation/device client id when available

For persistence (bans, economy, progression), prefer accountId (fallback clientId), not session playerId.

Registration model:

  • client runtime registrations are local-only.
  • server runtime registrations are authoritative.
  • command routing source type (chat|debug|system) is validated at execution time, not registration time.
  • command permissions are validated by ACL, not by command definition roles.

Events​

Command does not expose built-in hook callbacks in v1.

Use custom events for observability and automation.

command:executed (Custom)​

Recommended payload:

  • name (string)
  • sourceType (chat | debug | system)
  • playerId (number or nil)
  • accountId (string or nil)
  • clientId (string or nil)
  • args (table)

Example:

TriggerEvent("command:executed", {
name = execution.name,
sourceType = execution.source,
playerId = execution.playerId,
accountId = execution.accountId,
clientId = execution.clientId,
args = args
})

command:failed (Custom)​

Recommended payload:

  • name (string)
  • error (string)
  • sourceType (chat | debug | system)

Example:

TriggerEvent("command:failed", {
name = execution.name,
error = tostring(handlerErr),
sourceType = execution.source
})

command:denied (Custom)​

Recommended payload:

  • name (string)
  • reason (string)
  • sourceType (chat | debug | system)

Example:

TriggerEvent("command:denied", {
name = "ban",
reason = "ERR_COMMAND_PERMISSION_DENIED",
sourceType = "chat"
})

ACL and Restricted Commands​

Command ACL policy file:

  • acl.json (same directory as server.json)

Restricted command behavior:

  • if restricted=true, execution is denied unless ACL has a matching allow.
  • use this for sensitive commands (for example ban, kick, spawn, storage/admin commands).

API simplification:

  • requiredRole is intentionally not part of Command.Add.
  • scope and allowIn are intentionally not part of Command.Add.
  • ACL + runtime source type enforce authorization and routing.

Role assignment model:

  • ACL is the permission policy source (recommended default roles: normal, admin, plus internal system).
  • Logged-in account role should come from server account storage (runtime/mtadm.db, SQLite).
  • Guests use a temporary session role (typically normal) until logout/disconnect.
  • ACL can pin specific principals to roles using roleMembers.

Example:

{
"DefaultRole": "player",
"RoleMembers": {
"admin": [
"a_done"
]
}
}

Scope Matrix​

CapabilityClientServer
Register local commandsYesYes
Execute local commandsYesYes
Execute privileged gameplay commandsNoYes
Slash command routing from chatYesYes
Debug command executionYesYes

Error Codes​

  • ERR_COMMAND_NOT_FOUND
  • ERR_COMMAND_ALREADY_EXISTS
  • ERR_COMMAND_INVALID_NAME
  • ERR_COMMAND_INVALID_HANDLER
  • ERR_COMMAND_PERMISSION_DENIED
  • ERR_COMMAND_INVALID_CONTEXT
  • ERR_COMMAND_PARSE
  • ERR_COMMAND_EXECUTION
  • ERR_NOT_CONNECTED

Quick Examples​

Register and execute a local command:

local err = Command.Add("ping", function(execution, args, raw)
print("pong from accountId=" .. tostring(execution.accountId) .. " clientId=" .. tostring(execution.clientId))
end, {
description = "Connectivity check",
usage = "/ping",
aliases = { "p" }
})

if err then
print("Command.Add failed: " .. err)
end

local result, runErr = Command.Execute("/ping", { sourceType = "chat" })
if runErr then
print("Command.Execute failed: " .. runErr)
elseif result then
print("Command status=" .. tostring(result.status) .. " handled=" .. tostring(result.handled))
end

Register a restricted command (ACL required):

local err2 = Command.Add("ban", function(execution, args)
-- server-authoritative handler
end, {
restricted = true,
description = "Ban a player",
usage = "/ban <target> <reason>"
})