Custom Commands
Build real commands with tab completion, arguments, cooldowns and limits, in a few lines of YAML.
Every top-level key in any file inside plugins/Lightning/commands/ becomes a command. They're registered as real Brigadier commands, the same system vanilla uses, so players get proper tab completion, and wrong input is underlined in red before they even press enter.
Your first command
discord:
description: Get the Discord link
aliases: [dc]
actions:
- "<spark:prefix> Join us at discord.gg/example"That's a complete command. Restart your server once and /discord (or /dc) is ready. Everything below is optional.
Options
| Option | What it does |
|---|---|
enabled | false turns the command off without deleting it |
description | Shown in /help |
aliases | Other names for the command |
permission | Who can use it. Players without it won't see it in tab completion either |
sender | player, console or any (the default) |
cooldown | Time between uses, like 30s, 5m or 12h |
limit | How many times it can be used, see Cooldowns and limits |
usage | Replaces the usage line Lightning builds for you |
arguments | What the command takes |
messages | This command's own cooldown, limit, usage, players or console message |
subcommands | Commands inside this one |
actions | What it does, top to bottom |
Arguments
A list, in the order players type them:
arguments:
- name: target
type: player
- name: amount
type: number
min: 1
max: 64
default: 1| Field | What it does |
|---|---|
name | What it's called. Use it as {name} in actions |
type | One of the types below, word if you leave it out |
default | Used when the player leaves it out, which makes it optional |
optional | true makes it optional without a default. It's empty when left out |
min, max | For number and decimal. The player's game refuses anything outside |
options | For choice, the allowed values |
| Type | Takes |
|---|---|
player | An online player, with names suggested |
number | A whole number |
decimal | Any number |
boolean | true or false |
word | One word |
text | Everything left on the line, so it has to come last |
world | A loaded world, with names suggested |
choice | One of options, which are suggested |
There's a short way to write arguments too, with the name and the type on one line:
arguments:
- target: player
- reason: text
- mode: [easy, normal, hard]A list as the type makes it a choice. Use the full form when you need min, max or default.
Optional arguments go last
Put optional arguments after the required ones. If something's out of order or misspelled, the console tells you exactly which argument of which command.
Subcommands
kit:
description: Grab a kit
sender: player
subcommands:
starter:
limit: 1
actions: [...]
daily:
cooldown: 24h
actions: [...]/kit on its own shows Usage: /kit <starter|daily>. Subcommands follow their parent's sender unless they set their own, and can use every other option, including their own subcommands.
Cooldowns and limits
cooldown: 12h# once, ever
limit: 1# three times a day
limit:
amount: 3
reset: daycooldown is the wait between two uses. limit caps how many uses fit in a window: reset can be never, hour, day, week, month, or a time like 6h. Both are tracked per player and per subcommand, and they survive restarts.
Skipping the wait
lightning.bypass skips cooldowns and limits. Nobody has it by default, ops included, so give it out on purpose.
Actions
actions:
- "<spark:prefix> Welcome back, {player}!<sound:entity.player.levelup>"
- console: "give {player} diamond"
- wait: 2s
- "<actionbar:'<gold>+1 diamond'>"| Action | What it does |
|---|---|
"text" | A message to whoever ran the command. Sparks, bolts, faces, <center> and placeholders all work |
message: "text" | The same, written out |
console: "command" | Runs a command as the console |
player: "command" | Runs a command as the player |
broadcast: "text" | A message to everyone. Each reader sees their own placeholders and sparks |
broadcast with permission: | Only players with that permission |
wait: 2s | Pauses, then carries on |
if: with then: and else: | Runs one or the other |
chance: 10% with then: and else: | The same, by chance |
pick: with a list | Runs one of the options at random. Each option can be a line or a whole list of actions |
stop: true | Ends the command right there |
{player} is whoever ran the command, {world} and {uuid} are theirs too, and every argument is {its name}. then and else take one line or a list, and can hold more ifs.
Checks
- if: "%vault_eco_balance% >= 1000 and has vip.perks"
then: "<gold>Welcome back, big spender."
else: "<gray>Welcome back."| Form | Meaning |
|---|---|
a >= b, <=, >, < | Number comparisons |
a == b, a != b | Numbers compare as numbers, anything else as text, ignoring case |
has some.permission | The player has it |
not ... | The opposite |
and, or | Combine checks |
Messages per command
Any command can swap the general messages from config.yml for its own:
kit:
subcommands:
starter:
limit: 1
messages:
limit: "<spark:prefix> You already grabbed your starter kit."Available: cooldown (with <time>), limit, usage (with <usage>), players and console.
Safe by default
Whatever a player types into an argument is treated as plain data, never as instructions:
- No tags. A
/reportreason of<red>spamshows the tag as text. It never turns red. - No placeholders. A player typing
%player_ip%sees exactly that, nothing gets filled in. - No selectors.
@is removed before arguments go into aconsoleorplayercommand, so/give {target}can never become@a. - No double filling. A player typing
{target}gets exactly that, it's never filled in a second time. - Real players only.
playerarguments only accept players who are online.
Reloading
Changing what a command says or does applies with /lightning reload.
New commands need a restart
A brand new command, or changed arguments, need a full restart. Players only receive the command list when they join. If the name is already taken by another plugin, the console says so, and the command still works as /lightning:name.
A few to copy
report:
description: Report a player to staff
sender: player
cooldown: 1m
arguments:
- name: target
type: player
- name: reason
type: text
actions:
- "<spark:prefix> Thanks, staff will look into it."
- broadcast: "<spark:alert>Report</spark> {player} reported {target}: {reason}"
permission: server.staffComing soon
More argument types are on the way: items, amounts like 10k, and durations like 1h.
Last updated on