Commands
Axi provides a command API wrapping around Cloud with a Kotlin DSL and coroutines integration.
Declaring your first Command
To declare a command, all you need to do is to call the Command
function:
val TestCommand = Command("test")
Adding an executor
Now, this command is very basic. It does not have any executor, arguments, nor subcommands. To make this a little more interesting, we can use the DSL to add an executor:
val TestCommand = Command("test") {
executor {
ctx.sendMesage(text("Hello, world!"))
}
}
INFO
Executors are executed inside of a CommandExecutionContext
and are always suspending, but run synchronous by default. CommandExecutionContext
implements CoroutineScope
so you can launch jobs inside of your command just fine.
We could even make this a bit fancier and use a player-specific executor that only accepts players:
val TestCommand = Command("test") {
playerExecutor { player ->
player.sendMesage(text("Hello, world!"))
}
}
We could also make the executor run asynchronously:
val TestCommand = Command("test") {
async()
executor {
ctx.sendMesage(text("Hello, world!"))
}
}
WARNING
Never call any of the Bukkit API from an async executor without using a synchronous coroutine context like the syncContext
function offers.
Asynchronous executors are experimental.
Adding aliases
This is already much better. This will create a /test
command that will respond to the sender with Hello, world
.
Now, maybe we would like to add an alias to this command. We can do that by using the aliases
function:
val TestCommand = Command("test") {
aliases("hello")
executor {
ctx.sendMesage(text("Hello, world!"))
}
}
Adding subcommands
What if we want to add a subcommand? Well, that's easy, we can use the sub
function provided by the CommandBuilder
DSL:
val TestCommand = Command("test") {
aliases("hello")
executor {
ctx.sendMesage(text("Hello, world!"))
}
sub("bye") {
executor {
ctx.sendMessage(text("Bye, world!"))
}
}
}
This sub
function will create a new CommandBuilder
, to which you can apply the same concepts, we won't be repeating them here.
Adding arguments
Now, we obviously want to have an argument in our command. Let's take in a name
to greet or say goodbye to:
val TestCommand = Command("test") {
aliases("hello")
val name by arg("name", stringParser()) // stringParser comes from Cloud's StringParser
executor {
ctx.sendMesage(text("Hello, $name!"))
}
sub("bye") {
executor {
ctx.sendMessage(text("Bye, $name!"))
}
}
}
This will work for /hello rad
: Hello, rad!
. But when we try to do /hello bye rad
or /hello rad bye
, we will either get a syntax exception or this cloud exception:
There is no object in the registry identified by the key 'name'
This happens because we are declaring a command argument to our root command, but not to our subcommand. This means we will have to redeclare it in the subcommand's builder:
val TestCommand = Command("test") {
aliases("hello")
val name by arg("name", stringParser())
executor {
ctx.sendMesage(text("Hello, $name!"))
}
sub("bye") {
val name by arg("name", stringParser())
executor {
ctx.sendMessage(text("Bye, $name!"))
}
}
}
Now, we can use /hello bye rad
and it will say Bye, rad!
. Great! We now have a working command. But what if we want to restrict this so only some users can execute it?
Using Permissions
Axi commands default to the permission <plugin>.command.<name>
, where plugin
is the name of the plugin that is adding this command and name
is the name of the command. In our case, it would be:
axi-demo.command.test
axi-demo.command.test.bye
We can change this using the permission
function:
val TestCommand = Command("test") {
aliases("hello")
val name by arg("name", stringParser())
permission("axi.testcommands.hello")
executor {
ctx.sendMesage(text("Hello, $name!"))
}
// ...
}
Now, we would need to give players access to our axi.testcommands.hello
permission in our permission plugin in order for them to be able to use it.
INFO
Subcommand permissions append .<name>
to the parent command permission. In our case it would be axi.testcommands.hello.bye
.
Registering your command
Great! We now have our command! But... how do we actually register it?
Well, there's two options:
- Use the KSP processor to register them automatically
- Register them manually
Automatic Registration
First, make sure you are using the Axi gradle plugin, as specified in the Quickstart page.
Then, all you need to do is to add the @AutoRegistered
annotation to your command field:
@AutoRegistered
val MyCommand = Command("hello")
WARNING
If you are making an Axi module used by other people, this will not work due to library loading and classloaders. See the manual section below.
Manual Registration
You can simply call Command#register
in your plugin and it will register to the plugin provided to the command builder.