docs/docs/webshare/developers/api/command.md

5.7 KiB

slug
/velocity/developers/command-api

The Command API

The Command API lets you create commands that can be executed by a player connected to the proxy or the console.

Creating a command

Each command class needs to implement a Command subinterface. The choice depends on the type of arguments and the granularity of suggestions provided to the client. These include:

BrigadierCommand

Internally, Velocity uses the Brigadier library to register and dispatch command actions. You can register your own CommandNodes by wrapping them in a BrigadierCommand. Let's see an example of a command that will tell whoever executes the command "Hello World" in light blue text.

package com.example.velocityplugin;

import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import com.mojang.brigadier.tree.LiteralCommandNode;
import com.velocitypowered.api.command.BrigadierCommand;
import com.velocitypowered.api.command.CommandSource;
import com.velocitypowered.api.event.Subscribe;
import com.velocitypowered.api.event.proxy.ProxyInitializeEvent;
import com.velocitypowered.api.plugin.Plugin;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;

@Plugin(id = "helloworld")
public class HelloWorldPlugin {

    public void createBrigadierCommand() {
        LiteralCommandNode<CommandSource> helloNode = LiteralArgumentBuilder
            .<CommandSource>literal("test")
            .executes(context -> {
                Component message = Component.text("Hello World", NamedTextColor.AQUA);
                context.getSource().sendMessage(message);
                return 1; // indicates success
            })
            .build();

        // BrigadierCommand implements Command
        BrigadierCommand command = new BrigadierCommand(helloNode);
    }
}

Brigadier commands have full backwards-compatibility with 1.12.2 and lower versions.

Custom plugin command argument types are not supported in Velocity, as they would require the client to also support them. We recommend sticking to the predefined Brigadier types provided.

SimpleCommand

Modelled after the convention popularized by Bukkit and BungeeCord, a SimpleCommand has three methods: one for when the command is executed, one to provide suggestions for tab completion, and one to check a CommandSource has permission to use the command. All methods receive a SimpleCommand.Invocation object, which contains the CommandSource that executed the command and the arguments as an array of strings. The previous example can also be implemented using this interface:

package com.example.velocityplugin;

import com.velocitypowered.api.command.CommandSource;
import com.velocitypowered.api.command.SimpleCommand;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;

public final class TestCommand implements SimpleCommand {

    @Override
    public void execute(final Invocation invocation) {
        CommandSource source = invocation.source();
        // Get the arguments after the command alias
        String[] args = invocation.arguments();

        source.sendMessage(Component.text("Hello World!").color(NamedTextColor.AQUA));
    }

    @Override
    public boolean hasPermission(final Invocation invocation) {
        return invocation.source().hasPermission("command.test");
    }
}

It's important to note invocation.arguments() doesn't include the command alias (e.g. teleport for /teleport foo bar). In the event that no arguments are specified, an empty array will be passed, rather than a null array.

If a player or the console executes the following command: /stats Player2 kills, the first argument will be Player2, which we can access using invocation.arguments()[0] and the second argument will be kills.

RawCommand

There's certain cases where you don't need to process the arguments. These may include:

  • A /say style command, where the arguments contain the message as a string; or
  • You're using an external command framework to process your commands.

A raw command indicates the proxy to pass the command alias and its arguments directly without further processing. Let's see an example of a command that echoes the received input:

package com.example.velocityplugin;

import com.velocitypowered.api.command.RawCommand;
import net.kyori.adventure.text.Component;

public final class EchoCommand implements RawCommand {

    @Override
    public void execute(final Invocation invocation) {
        invocation.source().sendMessage(Component.text(invocation.arguments()));
    }

    @Override
    public boolean hasPermission(final Invocation invocation) {
        return invocation.source().hasPermission("command.echo");
    }
}

Registering a command

Now that we have created a command, we need to register it in order for it to work. To register commands, you use the Command Manager. We get the command manager by executing proxyServer.getCommandManager() with the proxy instance, or by injecting it using the @Inject annotation in the main class. The register method requires two parameters, the command metadata and the command object.

The CommandMeta contains the case-insensitive aliases and more advanced features. The Command Manager provides a meta builder via the #metaBuilder(String alias) method.

CommandMeta meta = commandManager.metaBuilder("test")
    // Specify other aliases (optional)
    .aliases("otherAlias", "anotherAlias")
    .build();

Finally,

commandManager.register(meta, new TestCommand());

If you're registering a BrigadierCommand, you may prefer to use the #register(BrigadierCommand) method or #metaBuilder(BrigadierCommand) to specify additional aliases.