Skip to content

Registering Commands

Use register() to create dynamic Brigadier commands from Lua without touching Java code.

Warning: Commands can only be registered at script load time — you cannot add commands at runtime (e.g. inside event handlers or scheduled callbacks). All register() calls must be at the top level of your .lua files.

register(syntax, handler, permission?)
ParamTypeDescription
syntaxstringCommand syntax string
handlerfunctionCallback invoked when the command runs
permission?stringOptional permission node (see Permissions)
command <name:type> [name:type] [name:choice=a,b]
PartMeaning
cmd subLiteral path tokens
<name:type>Required argument
[name:type]Optional trailing argument
<name:choice=a,b>Choice argument with tab completions

Optional [<name:type>] is also supported, because i think both of them are pretty.

Optional arguments can only appear such that no required argument follows them. Literals may appear after optional arguments. Omitting any optional arg removes all later ones too.

TypeLua typeDescription
textstringGreedy: consumes the rest of the command line.
wordstringSingle word (abc or "abc abc")
playerplayerPlayer
targetplayerAlias for player
intnumberInteger
doublenumberDouble-precision float
floatnumberSingle-precision float
boolbooleanBoolean
block_postableVector
choice=a,bstringMulti-choice — runtime validation + tab completion

The handler receives ctx as the first argument, followed by each argument value as a positional parameter in syntax order.

--# nova syntax
register("warn <target:player> <reason:text>") \{ctx, target, reason ->
target:sendMessage("Warning: " .. reason)
}
PropertyTypeDescription
ctx.playerplayerPlayer who called the command

Pass a permission node as the third argument. Players won’t even see the command. If omitted, all players can use the command.

register("kick <target:player>", function(ctx, target)
target:kick("Kicked by operator")
end, "admin.kick")

These cannot be registered (for safety):

ignis, stop, reload, op, deop, ban, ban-ip, pardon, pardon-ip, save-all, save-on, save-off, whitelist

--# nova syntax
-- Simple command, no arguments, no permission
register("healme") \{ ctx ->
ctx.player:heal(20)
ctx.player:sendMessage("Healed!")
}
-- Player argument with permission
register("fly <target:player>") \{ ctx, target ->
target:setFlySpeed(0.1)
end, "myplugin.fly")
-- Optional argument
register("balance [<target:player>]", function(ctx, target)
local t = target or ctx.player
t:sendMessage("Balance: " .. (t.data.balance or 0))
end)
-- Choice argument
register("time set <phase:choice=day,night,noon,midnight>", function(ctx, phase)
local times = { day = 1000, night = 13000, noon = 6000, midnight = 18000 }
ctx.player.world.time = times[phase]
end)