rather limited/bad command api
Find a file
2026-08-02 21:23:36 +02:00
.idea BAZEL + some code 2026-08-02 21:23:36 +02:00
kencommandapi-bukkit BAZEL + some code 2026-08-02 21:23:36 +02:00
kencommandapi-core BAZEL + some code 2026-08-02 21:23:36 +02:00
kencommandapi-velocity BAZEL + some code 2026-08-02 21:23:36 +02:00
third_party BAZEL + some code 2026-08-02 21:23:36 +02:00
.bazelrc BAZEL + some code 2026-08-02 21:23:36 +02:00
.gitignore BAZEL + some code 2026-08-02 21:23:36 +02:00
MODULE.bazel BAZEL 2026-08-01 23:12:48 +02:00
README.md BAZEL + some code 2026-08-02 21:23:36 +02:00

Limitations & Bugs

  • argument's can't require specific permissions.
  • errors are always formatted using the RootLiteral's MessageStyle

Design

Commands are trees of Literals. Literals can have arguments. Literals can also have Executors.

arguments can be optional by giving them a default value. arguments can have suggestions.

/feed <user>:

  • feed is the root literal
  • <user> is an argument: it's value is a User Object

To allow the use of /feed without giving a user's name, i.e. to make the argument optional, we need to assign the user-argument a default value.

An example command

Let's say we want to make a command that allows seeing how many coins another User has. If we don't specify a user, it should instead show the coins the sender has.

As a tree

Visualized as a tree, we have a Node/Literal coins with an alias balance with an optional argument called user. To make an argument optional, it must have a default value.

literal:coins/balance
- has argument:user
- has executor:getCoins

As code

/**
 * Show the amount coins a user has.
 * If no user is given, it should show the amount the sender of the command has.
 */
@NoArgsConstructor(access = AccessLevel.NONE)
public class CoinsCommand {

    @Getter
    private final Literal<User> rootLiteral;
    private final CommandArgumentSpec<User, User> userArg;

    public CoinsCommand() {
        userArg = CommandArgumentSpec.builder("user", new UserArgumentType<User>())
                .withRequirement(p -> !p.hasPermission("economy.immune.getcoins"),
                        "you can't see that player's balance")
                .withDefaultValue(CommandContext::getSender)
                .build();
        rootLiteral = Literal.<User>builder("coins", "balance")
                .withStyle(MessageStyle.PLAIN)
                .withPermission("economy.command.coins")
                .withArgument(userArg)
                .withSyncExecutor(this::getCoins)
                .build();
    }

    private Result<Object, String> getCoins(CommandContext<User> ctx) {
        var player = ctx.getArg(userArg);
        ctx.getSender().sendMessage(player.getName() + " has " + player.getCoins() + " coins");
        return Results.success(new Object());
    }
}

If we wanted to report an error, we could do for example return Results.failure("That user doesn't exist"). However, if we have a smart UserArgumentType, it automatically makes sure that the user exists. Additionally, we can also a Requirement in the CommandArgumentSpec.

The registration of the command is platform-dependant. Typically, a class called CommandAPI can be used.

CommandAPI api = new CommandAPI();
register(new CoinsCommand().getRootLiteral());