Skip to content

Command API

MattMX edited this page Jul 7, 2024 · 7 revisions

Declarative

Introduced in @1.4.0, declarative commands allow you to create commands with vast customization and extensibility, while keeping minimal code.

We can create the declarative command via a string, or a chain command.

Let's begin by making a /msg command with two arguments

// Chain declaration
//val player by argument<Player>("player")
//val msg by argument<String>("string", true)

val player by playerArgument()
val msg by greedyStringArgument()

("msg" / player / msg) {
    runs<CommandSender> {
        // Make sure to invoke the arguments to get their values.
        player().sendMessage(!"[${sender.name} -> Me]: ${msg()}")
        reply(!"[Me -> ${player().name}]: ${msg()}")
    }
} register this
// Complete string declaration (Not recommended)
"/mgs <player:player!> <msg:string...>" {
    runs<CommandSender> {
        val player by argument<Player>()
        val msg by argument<String>()
        player.sendMessage(!"[${sender.name} -> Me]: ${msg}")
    }
} register this

Caution

String parse declaration will be deprecated in 2.5.0

Sub commands

We can declare subcommands using the div operator with a list of commands, or we can use the subcommand block.

("foo") {
    ("bar" / arg).runs<Player> { /* callback */ }
    ("fizz" / arg).runs<Player> { /* callback */ }
    ("buzz" / arg) {
        // code
    }
} register this

Arguments

Arguments can have callbacks for missing or invalid values in different scopes.

val name by argument<Player>("player")

name missing { reply(!"&cName arg is missing") } 

("foo" / name) {
    // Will run instead of top level missing callback
    name missing { reply(!"Test") }  
    
    runs<Player> {
        // ...
    }
} register this

("bar" / name) {
    // If missing will run the top level missing callback
    runs<CommandSender> {
    }
} register this

This feature is available for if the argument is missing or invalid.

You can also handle all missing or invalid args by not specifying the argument.

("bar" / name) {
    // If missing will run the top level missing callback
    runs<Player> {
    }

    invalid {
        // Handles all args, lowest priority
        reply(!"Missing arg ${argument.name()}")
    }
} register this

Suggestions

Caution

This section will be rewritten since CommandSuggestionRegistry will no longer be primarily used for supplying suggestions/values.

When specifying an argument type, KtGui will attempt to do tab suggestions and try to get the value of a provided argument by using the CommandSuggestionRegistry.

If we had a list of Dog objects which hold a name property, we can use the SimpleCommandSuggestion class.

class Dog(val name: String)

val dogs = arrayListOf(Dog("Foo"), Dog("Bar"))

fun getDogs() = dogs

CommandSuggestionRegistry.register(
    "dog_name",
    SimpleCommandSuggestion(Dog::name, ::getDogs)
)

// ...

val dog by argument<Dog>("dog_name")
("pet" / dog) {
    runs<CommandSender> {
        reply(!"Petted ${dog().name}")
    }
} register this

Permissions

You can call the function buildAutomaticPermissions(rootNode: String) to automatically register and assign permission nodes to all sub-commands in the command tree. The permission nodes will be the rootNode arg followed by the command name.

You can also individually assign permissions by calling permission(node: String) or permission(block: StorageCommandInvocation<*>.() -> Unit). This will be checked with the automatically assigned permission node.

Simple/Raw

Clone this wiki locally