Why
Paper moved to Brigadier, and command registration now goes through lifecycle events in onLoad. Argument completion has to be described separately from execution.
EffectiveCommand registers the command itself and uses one CommandNode tree for both execution and completion: choice is a literal, dynamic a runtime list, executes the action.
Minimal example
Command
object ArenaCommand : EffectiveCommand() {
override fun getNamespacedData() = MyPlugin.instance to "arena"
override fun getDescription() = "Arena control"
override fun getPermission() = "myplugin.arena"
override fun commandTree() = CommandNode.build {
choice("start") {
executes { Arena.start(); sendMessage("started") }
}
choice("kick") {
dynamic({ Bukkit.getOnlinePlayers().map { it.name } }) {
executes { args -> Bukkit.getPlayer(args[1])?.kick() }
}
}
}
fun init() {}
}ArenaCommand.init() is called from onLoad.
What to override
- getNamespacedData() *Plugin and command name
- getDescription() *Description for /help
- getPermission() *Permission; empty string — none
- commandTree() *Argument tree
* required
Pitfalls
- Created the command in onEnable — it does not exist. onLoad only.
- executes runs on the deepest matching node; args is the whole argument array from zero.