Configuring

Per-command rules

Every one of the 139 commands has its own block in its module's file, and every block takes the same fourteen options. Most commands use three of them.

commands:

  defaults:
    enabled: true
    warmup-seconds: 0
    cooldown-seconds: 0
    price: 0.0
    worlds: [ ]
    sound:
      key: ui.button.click
      volume: 0.5
      pitch: 1.2
    particle:
      name: ''
      count: 0
      spread: 0.4
      height: 1.8
      speed: 0.02

  home:
    warmup-seconds: 3
    cooldown-seconds: 30
    price: 50.0
    worlds: [ '!event' ]
    sound:
      key: entity.enderman.teleport
      volume: 0.7
      pitch: 1.2
    particle:
      name: PORTAL
      count: 45
      height: 2.0
      speed: 0.04

A command only writes down what it does differently. Everything it leaves out comes from defaults, which is why the shipped files are readable: most commands are three lines.

The options#

Option What it does
enabled false makes the command answer that it is switched off. The enabled at the top of the file does the same for every command in it.
warmup-seconds Stand still this long before the teleport happens. Only means anything for commands that teleport.
cooldown-seconds How long before the same player may use it again. Starts only once the command actually succeeded.
price What it costs. 0 is free. Charged only on success.
worlds Where it works. Empty is everywhere.
sound Played to whoever ran it.
particle Shown where it happened.
messages Lines this command says instead of the ones in the messages folder.
permission The node the command takes, in place of its own.
permission-message What somebody without that node is told.
requires What has to be true before it runs.
on-success Actions once it has worked.
on-fail Actions when it is refused.
log true writes every use into the staff log.

Warmups#

warmup-seconds: 3

The player stands still for three seconds and then arrives. Moving or taking damage cancels it, and nothing is charged for a cancelled teleport.

Two settings in modules/teleport.yml apply to every warmup in the plugin, whichever command started it:

teleport:
  cancel-on-move: true
  cancel-on-damage: true
  warmup-countdown: true

warmup-countdown shows the seconds left in the action bar.

chorus.teleport.instant skips every warmup.

Cooldowns#

cooldown-seconds: 30

Per player, per command. It starts when the command succeeds, not when it is typed, so a command that refused costs nothing. Cooldowns survive a disconnect: leaving and rejoining does not clear one.

chorus.bypass.cooldown ignores all of them.

Prices#

price: 50.0

Taken through whatever economy is in use, and only when the command actually goes through. A /home that was cancelled halfway through its warmup is free. A /sethome that was refused because the player was at their limit is free.

With no economy at all, every price is ignored rather than refusing the command.

chorus.bypass.price never pays.

For /sethome there is a second charge in modules/homes.yml:

homes:
  price-per-home: 0.0

Added to the price for every home the player already has, so the fifth home costs more than the first. Moving a home you already have is never surcharged.

Worlds#

One list does both jobs. A name on its own is the only place the command works; a name with ! in front is the one place it does not.

worlds: [ ]                        everywhere, which is the default
worlds: [ world, world_nether ]    only in those two
worlds: [ '!event' ]               everywhere except the event world
worlds: [ '!world_nether', '!world_the_end' ]   the overworld only

Names are compared without case. A refusal wins over an allowance for the same world, so a list that says both leaves the command off there.

chorus.bypass.worlds ignores the whole thing.

What it is for: no /home in the arena, no /tpa in the event world, no /back out of the nether — without a second plugin and without taking the command away from everybody.

Mind the quotes. YAML reads a bare ! at the start of a value as a type tag, so '!event' has to be quoted.

Sounds#

sound:
  key: entity.enderman.teleport
  volume: 0.7
  pitch: 1.2
Key Range
key A Minecraft sound name. Empty for silence.
volume 0 to 10. It doubles as how far away others hear it.
pitch 0.5 to 2. Higher is squeakier.

A name the client does not know simply plays nothing, so a typo can never break anything and a sound that only exists on newer versions is safe to use.

Ones that come up often:

ui.button.click                 a quiet tick, the default
entity.enderman.teleport        a teleport
entity.experience_orb.pickup    money, or a message arriving
entity.player.levelup           something was created
block.note_block.bass           a refusal
block.note_block.pling          a setting changed
block.lever.click               a toggle
entity.villager.trade           mail

Particles#

particle:
  name: PORTAL
  count: 45
  spread: 0.4
  height: 2.0
  speed: 0.02
Key What it does
name A Bukkit particle name. Empty for none.
count How many. 0 means none.
spread How far they scatter sideways, in blocks.
height How tall the burst is, in blocks.
speed How fast they drift. Keep it small.

Mojang renamed several of these over the years, so both the old and the new spelling are accepted and the right one is picked for whichever version you run.

Safe on every supported version:

PORTAL  REVERSE_PORTAL  FLAME  SOUL_FIRE_FLAME  CLOUD  END_ROD  DRAGON_BREATH
HEART  CRIT  ELECTRIC_SPARK  GLOW  NOTE  SNOWFLAKE  ASH

A teleport shows its particles twice: once where the player left from and once where they arrive.

Messages#

Lines this command says instead of the ones in the messages folder, by the same keys. A blank one silences that line for this command alone.

fly:
  messages:
    error.no-permission: '<red>Buy VIP to use /fly.'
    cooldown.wait: ''

Written either as a dotted key or as nested blocks; both reach the same line.

A messages block in defaults applies to every command in that file, and a command may add to it or rewrite one of its lines.

These are the server's own words, so they are the same in every language. A line that has to change per language belongs in messages/, not here — see Messages and translations.

Permissions#

commands:
  fly:
    permission: vip.fly
    permission-message: '<red>Flying is a VIP perk. <gray>/store'

permission replaces the node a command takes to be used at all. The nodes for the extras keep their own names: /fly <player> still needs chorus.utility.fly.others, and the bypass nodes are untouched.

permission: '' opens the command to everyone.

/commands follows it, so a player is shown the commands they may actually run under the new node.

permission-message is a shortcut for writing error.no-permission into the command's own messages block. When both are written, permission-message wins.

Only on a command. In defaults it would hand every command in the file the same node, which is never what anybody means, so it is ignored there and said so in the console.

Requirements#

What has to be true before the command runs at all. The same five types kits use:

commands:
  home:
    requires:
      - 'playtime: 3600'
      - condition: 'placeholder: %player_level% >= 10'
        deny: '<red>Come back at level 10.'
Type Passes when
permission: <node> The player has the node
placeholder: <comparison> The comparison holds. Anything PlaceholderAPI knows, with >=, <=, ==, !=, >, < or contains
money: <amount> Their balance is at least that
playtime: <seconds> They have played at least that long on this server
kit: <name> They have taken that kit at least once. Needs the kits module

They are checked in order and the first one that fails stops the command. A deny line is what that player is told; %player%, %command% and anything PlaceholderAPI knows work in it. Without one they get error.command-requirement from messages/core.yml, which ships as You cannot use /%command% yet.

Checked after the permission and the world, and before anything is charged, so a player who is turned away here has not paid for it.

The console always passes.

A command's own list replaces the one in defaults rather than adding to it, so a command can be exempted from a server-wide requirement by writing an empty list.

Actions#

Things to do once a command has worked, or when it has been refused. Written the same way as a kit's claim and fail actions:

commands:
  spawn:
    on-success:
      - 'title: <gold>Welcome back;<gray>to spawn'
      - 'sound: entity.player.levelup 1 1.4'
    on-fail:
      - 'actionbar: <red>Not now'
Action What it does
message: <text> Sends the player a line
broadcast: <text> Sends everyone a line
actionbar: <text> Shows the line above their hotbar
title: <title>;<subtitle> Shows a title. The subtitle is optional
sound: <key> [volume] [pitch] Plays a sound to them
console: <command> Runs a command as the server
player: <command> Runs a command as the player, with their own permissions
close Closes whatever screen they have open

on-success runs once the command has really worked — the moment the cooldown starts and the price is taken. For a teleport that is on arrival, not when it was typed.

on-fail runs when the command is refused: no permission, the wrong world, a requirement, the cooldown or the price. Not when the arguments are wrong, which is a usage line rather than a refusal.

%player% and %command% work in every action, and so does anything PlaceholderAPI knows.

There is no %args%. An action cannot see what the player typed after the command, on purpose: a console line that could be handed a second argument is a console line a player can steer.

console runs as the server. On Folia it runs on the global thread, a tick later.

Only players run them — the console runs none of them. A line the plugin does not understand is skipped and named in the console when the file is read.

The log#

commands:
  gamemode:
    log: true

Every use goes into the staff log with whatever was typed after the command, and reads in /stafflog as:

▪ Steve used /gamemode » creative (2m 5s ago)

Written when the command runs, once the permission, the world and the requirements have passed. A use with the wrong arguments is written too. So are console uses.

Needs staff-log.enabled: true in config.yml, which is how it ships.

Switching things off#

Three levels, from widest to narrowest:

# The whole module, in its file
enabled: false

# One command
commands:
  tpaall:
    enabled: false

A command that is off answers with the message from messages/core.yml rather than pretending not to exist, and it disappears from /commands. Its aliases are given back to the server.

A worked example#

Homes that take three seconds, cost money, are not allowed in the nether, and get slower the more you own:

# modules/homes.yml
homes:
  default-limit: 3
  price-per-home: 250.0

commands:
  home:
    warmup-seconds: 5
    cooldown-seconds: 60
    price: 25.0
    worlds: [ '!world_nether', '!world_the_end' ]

  sethome:
    price: 500.0
    cooldown-seconds: 30

Then let a rank out of it:

lp group vip permission set chorus.bypass.cooldown
lp group vip permission set chorus.home.limit.10