Skip to content

Command API: Function based

Lorenzo Rutayisire edited this page Jun 13, 2020 · 8 revisions

The same result achieved in the Class-based wiki-page can be obtained using the function-based approach. Specifically, this is useful if you have one node command and many children that belong to it.

For example, say we need to create these commands:

/quake create <arena>
/quake delete <arena>

Then, within any class, we can define them this way. Every command takes a function marked with @AsCommand.

public class QuakeArenaCommands { // Could be any class you'd like.
    // ================================================================================
    // create <arena>
    // ================================================================================
    @AsCommand(
            description = "Creates a new arena.",
            aliases = {"c"},
            sender = SenderType.PLAYER
    )
    // The command name will be the same as the function name.
    // - The first parameter must be a CommandSender implementation according to the SenderType.
    // - The usage of the command goes from the second parameter onwards.
    public void create(Player player, String arena) {
        // (...) Does some stuff to actually create the arena...
        player.sendMessage(GREEN + "Arena created.");
    }

    // ================================================================================
    // arena delete <arena>
    // ================================================================================
    @AsCommand(
            description = "Deletes an arena."
            alaises = {"d", "rm", "remove"},
            //sender = SenderType.ALL (by default)
    )
    public void delete(CommandSender sender, String arena) {
        // (...) Does some stuff to delete the arena...
        player.sendMessage(GREEN + "Arena removed: " + arena.getId());
    }

There's no way to create a functional node command, we have keep the QuakeCommand we've created before:

public class QuakeCommand extends NodeCommand {
    public QuakeCommand() {
        super("quake");

        setDescription("The main Quake command.");
        //setSenderType(SenderType.ALL);
        addAliases("q");

        // Appends to the node the list of commands returned by FunctionalCommand#load.
        append(FunctionalCommand.load(new QuakeArenaCommands())); // <---
    }
}

Finally, we have to register QuakeCommand the same as we did before.

@WithOptional

There are some commands where a parameter could be optional. For example:

/give <item> <amount> [player]

If the player isn't specified the plugin must assume the player wants to give the item to himself. How do we achieve that with the command-api?

@AsCommand(
        description = "Gives the specified item to a player."
        sender = SenderType.PLAYER,
)
public void give(Player sender, Material item, int amount, @WithOptional String player) {
    if (player == null) {
        player = sender.getName();
    }
    Player target = Bukkit.getPlayer(player);
    // (...)
    sender.sendMessage(GREEN + "Item sent to: " + target.getName());
    if (target != sender) {
        sender.sendMessage(GREEN + "You received an item from: " + sender.getName());
    }
}

If the player isn't specified the plugin sets the optional parameter to the default value.


Function-based is better than Class-based

Using this approach is more powerful than creating classes, here some advantages:

  • You don't have to take care of args parsing, the API does it for you. Handling also eventual syntax errors.
  • Auto-generates the usage that is displayed by the help command.
  • Less verbosity, you don't have to create one class for every command you have.
  • Embedded management of tab-complete for parameters.

Parameter types to use

By itself, Uppercore supports the following types of parameters:

  • Primitives: boolean, char, byte, float, double, short, int, long, String, String[].
  • Some Bukkit's utils: Color, Enchantment, Material, Sound, Vector

It is also possible to include your own parameter parser.

Clone this wiki locally