Skip to content

Command

Rick van Sloten edited this page Aug 22, 2020 · 6 revisions

Command

This wiki page is all about the command features! If you need more information you can also take a look at the Command package.

Creating a new (sub-)command

Before you can add a new command class to you codebase you will first have to add it to your plugin.yml, the same goes for sub-commands.

Here is an example partial plugin.yml that has a command and a sub-command:

commands:

  example:
    usage: /example <message> <count> [player...]
    description: Spams the given players.
    permission: example.permission.main
    aliases: [spam]
    
  example sub:
    usage: /example sub
    description: Does nothing...
    permission: example.permission.sub
    aliases: [nothing]  

NOTE: The alias for the sub-command is used as an alias for full command. Meaning that the command /example sub will also be triggered with the command /nothing.

You can now create a command class that inherits from nl.tabuu.tabuucore.command.Command.

Here is an example of an empty command class:

public class ExampleCommand extends Command {

    public ExampleCommand() {
        // Generating the command class based on the command registered in the plugin.yml.
        super("example");
    }

    @Override
    protected CommandResult onCommand(CommandSender sender, List<Optional<?>> arguments) {
        // Executes when the main command is executed.
        return CommandResult.SUCCESS;
    }
}

To register this command you can use the following code in the main class of your plugin:

getCommand("example").setExecutor(new ExampleCommand());

Sub-commands

Adding a sub-command to your command is relativity easy, you only need to create another command class and register it in your main command.

Here is an example of how this might look (based on the example plugin.yml of earlier):

public class ExampleCommand extends Command {

    public ExampleCommand() {
        // Generating the command class based on the command registered in the plugin.yml.
        super("example");

        // Adds and registers a sub-command to the command.
        addSubCommand("sub", new ExampleSubCommand(this));
    }

    @Override
    protected CommandResult onCommand(CommandSender sender, List<Optional<?>> arguments) {
        // Executes when the main command is executed.
        return CommandResult.SUCCESS;
    }
}

public class ExampleSubCommand extends Command {

    protected ExampleSubCommand(Command parent) {
        // Generating the command class based on the command registered in the plugin.yml.
        super("example sub", parent);
    }

    @Override
    protected CommandResult onCommand(CommandSender commandSender, List<Optional<?>> list) {
        // Executes when '/example sub' or one of this sub-command's aliases is executed.
        return CommandResult.SUCCESS;
    }
}

Handling execution and arguments

Now that you have created your command classes and structure, set how exactly the command should convert its arguments. The command will convert the string arguments it receives and converts them based on the provided ArgumentConverter.

TabuuCore comes with the OrderedArgumentConverter which converts the provided arguments from left to right, this is the way most plugins handle their commands. You can provide the converter with a sequence of ArgumentTypes. This sequence dictates in which order in which the arguments are converted, and to what objects they are converted to. If the argument cannot be converted, TabuuCore will send the executor a message specified in TabuuCore's lang.yml.

You can also set what SenderType can execute the command.

Here is an example of how a command class could look (features based on the plugin.yml created earlier):

public class ExampleCommand extends Command {

    public ExampleCommand() {
        // Generating the command class based on the command registered in the plugin.yml.
        super("example");

        // Creating a new OrderedArgumentConverter which converts string arguments to the desired objects.
        OrderedArgumentConverter converter = new OrderedArgumentConverter();

        // Setting the sequence/order of the objects as they should appear in the command.
        converter.setSequence(ArgumentType.STRING, ArgumentType.INTEGER);

        // Adds a parameter which can repeat itself infinitely, similar to how Varargs work in Java.
        converter.setParameter(ArgumentType.PLAYER);

        // Sets the created OrderedArgumentConverter as ArgumentConverter for the command.
        setArgumentConverter(converter);

        // Sets the required SenderType (ANY by default).
        setRequiredSenderType(SenderType.PLAYER);
    }

    /**
     * Called when the command is executed.
     *
     * @param sender    The executor of the command.
     * @param arguments The converted arguments.
     *                  This is list is at least the size of the sequence, but might be longer depending on the parameters.
     *                  If the executor failed to provide an argument from sequence, the optional will be empty.
     *                  If an argument could not be converted, the executor will receive an error message.
     *                  Additional parameters are always present in the Optional.
     * @return The result of the command.
     */
    @Override
    protected CommandResult onCommand(CommandSender sender, List<Optional<?>> arguments) {
        // Checks if all arguments are present.
        for (Optional<?> argument : arguments) {
            if (!argument.isPresent())
                return CommandResult.WRONG_SYNTAX;
        }

        // Gets the first converted argument and casts it to the correct type.
        String message = (String) arguments.get(0).get();

        // Gets the second converted argument and casts it to the correct type.
        int count = (Integer) arguments.get(1).get();

        // Exits the command if no players are provided.
        if (arguments.size() == 2)
            return CommandResult.SUCCESS;

        // Creates a list of the additional parameters.
        List<Optional<?>> additionalParameters = arguments.subList(2, arguments.size());

        // Converts the additional parameters to a list.
        List<Player> recipients = new ArrayList<>();
        for (Optional<?> argument : additionalParameters) {
            Player player = (Player) argument.get();
            recipients.add(player);
        }

        // Do something with the variables
        for (Player player : recipients) {
            for (int i = 0; i < count; i++)
                player.sendMessage(message);
        }

        // Returns the result of the command.
        return CommandResult.SUCCESS;
    }
}

Command Arguments

A quick way to create command is to make use of the command register annotations. This system works similar to the event listener system in Spigot/Bukkit.

Here is an example of a valid class containing 4 commands, of which one is a sub-command.

public class ExampleCommands implements ICommandListener {

    @CommandExecutor(
            command = "example1",
            argumentSequence = { ArgumentType.STRING, ArgumentType.INTEGER },
            parameter = ArgumentType.PLAYER,
            children = @ChildCommand(label = "sub", method = "exampleSub")
    )
    private CommandResult example(CommandSender sender, List<Optional<?>> arguments) {
        return CommandResult.SUCCESS;
    }

    @CommandExecutor(command = "example1 sub")
    private CommandResult exampleSub(CommandSender sender, List<Optional<?>> arguments) {
        return CommandResult.SUCCESS;
    }

    @CommandExecutor(command = "example2")
    private CommandResult exampleRequiresPlayer(Player sender, List<Optional<?>> arguments) {
        return CommandResult.SUCCESS;
    }

    @CommandExecutor(
            command = "example3",
            argumentSequence = { ArgumentType.STRING, ArgumentType.INTEGER }
    )
    private CommandResult exampleRequiresAllArguments(CommandSender sender, List<?> arguments) {
        String string = (String) arguments.get(0);
        int integer = (Integer) arguments.get(1);

        return CommandResult.SUCCESS;
    }
}

It is also possible to add TabSuggesters to these commands by creating TabSuggest methods:

@CommandExecutor(
    command = "give",
    argumentSequence = ArgumentType.STRING,
    tabSuggestMethod = "materialSuggest"
)
public CommandResult giveMaterial(Player player, List<?> arguments) {
    String materialString = (String) arguments.get(0);
    XMaterial material = XMaterial.valueOf(materialString.toUpperCase());
    player.getInventory().addItem(material.parseItem());
    return CommandResult.SUCCESS;
}

@TabSuggester
public List<String> materialSuggest(CommandSender sender, List<String> arguments, String partial, List<String> suggestions) {
    return Arrays.stream(XMaterial.values()).map(Enum::name).collect(Collectors.toList());
}
  • The arguments are the completed arguments typed by the command sender (in string format).
  • The partial is the partial string the command sender is typing.
  • The suggestions is a list of suggestions done by TabuuCore (like player names/uuids when requesting a player argument).

You can register these listeners by registering them to the command register like so:

TabuuCore.getInstance().getCommandRegister().registerExecutors(commandlistener, plugin);

Or, if your plugin extends from TabuuCorePlugin:

TabuuCorePlugin#registerExecutors(commandlistener);

Clone this wiki locally