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:
errcontains 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​
Commandis 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
NodeSimpaths only.
Function List​
| Function | Description | Scope |
|---|---|---|
Command.Add | Register a command handler and optional help/security metadata. | S |
Command.Remove | Remove a registered command by name. | S |
Command.Get | Get metadata for one command. | S |
Command.List | List visible commands for a source type. | S |
Command.Execute | Parse and execute a command line. | S |
Event List​
| Event | Description | Scope |
|---|---|---|
Built-in events | None in Command v1. | S |
command:executed | Recommended custom event for successful execution. | S |
command:failed | Recommended custom event for handler/runtime failures. | S |
command:denied | Recommended 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 exampleban,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(nilor 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(nilor string)
Command.Get​
S Shared (Client & Server)
local commandInfo, err = Command.Get(name)
Parameters:
name(string)
Returns:
commandInfo(table ornil)err(nilor 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 ornil)err(nilor 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 exampleplayerId,clientId,accountId,role).
Returns:
result(table ornil)err(nilor string)
result shape:
name(string): resolved command name.sourceType(chat|debug|system): effective source type.args(table): parsed argument array.handled(boolean):truewhen a handler was executed.status(ok|denied|not_found|error): execution outcome.errorCode(string ornil): populated whenstatusis notok.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) tosourceType=\"system\".
Built-in auth command routing:
- Server runtime includes built-in
login,register,logout,start,stop, andrestartcommand handlers. login/registerare denied withERR_ALREADY_LOGGED_INwhen already authenticated.start/stop/restartare registered as restricted commands, so ACL must allow them (defaultadmin/systemviacmd.*).- 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. reconnectis a built-in client-local command in the debug console. It disconnects and reconnects to the last server target known by the client./reconnectis 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_lockoutorauth_failed:rate_limited_player_lockout.
Target Selector​
For moderation/gameplay commands that address players (/kick, /ban, /mute, etc.), use:
number->playerId(session id)stringprefixedc_->clientIdstringprefixeda_->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;nilfor guestsclientId: 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 ornil)accountId(string ornil)clientId(string ornil)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 asserver.json)
Restricted command behavior:
- if
restricted=true, execution is denied unless ACL has a matchingallow. - use this for sensitive commands (for example
ban,kick,spawn, storage/admin commands).
API simplification:
requiredRoleis intentionally not part ofCommand.Add.scopeandallowInare intentionally not part ofCommand.Add.- ACL + runtime source type enforce authorization and routing.
Role assignment model:
- ACL is the permission policy source (recommended default roles:
normal,admin, plus internalsystem). - 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​
| Capability | Client | Server |
|---|---|---|
| Register local commands | Yes | Yes |
| Execute local commands | Yes | Yes |
| Execute privileged gameplay commands | No | Yes |
| Slash command routing from chat | Yes | Yes |
| Debug command execution | Yes | Yes |
Error Codes​
ERR_COMMAND_NOT_FOUNDERR_COMMAND_ALREADY_EXISTSERR_COMMAND_INVALID_NAMEERR_COMMAND_INVALID_HANDLERERR_COMMAND_PERMISSION_DENIEDERR_COMMAND_INVALID_CONTEXTERR_COMMAND_PARSEERR_COMMAND_EXECUTIONERR_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>"
})