Skip to content

Defining Commands

TheLipe edited this page Apr 17, 2026 · 2 revisions

🧩 Defining Commands

🏷️ Command Class

Every command starts with a class that extends CustomCommand.

@Command("example")
public final class ExampleCommand extends CustomCommand {

}

πŸ“Œ Class-Level Annotations

@Command

Declares the command name and aliases.

@Command({"warp", "warps"})
public final class WarpCommand extends CustomCommand {

}

@Permission

Declares a base permission for the whole command.

@Command("warp")
@Permission("example.warp")
public final class WarpCommand extends CustomCommand {

}

If the sender lacks this permission, the framework stops before selecting a handler.

πŸ› οΈ Method-Level Annotations

@Default

Defines the root handler for the command.

@Default
public void defaultCommand(CommandSender sender) {
    sender.sendMessage("Use /warp teleport <player>");
}

@SubCommand

Defines one or more subcommand labels handled by a method.

@SubCommand("teleport")
public void teleport(CommandSender sender, Player target) {

}

Multiple values are allowed:

@SubCommand({"delete", "remove"})
public void delete(CommandSender sender, String warpName) {

}

Multi-word subcommands are also supported:

@SubCommand({"set public", "set private"})
public void setVisibility(CommandSender sender) {

}

@Permission on a Handler

Adds a permission requirement only to that handler:

@SubCommand("teleport")
@Permission("example.warp.teleport")
public void teleport(CommandSender sender, Player target) {

}

@Unknown

Defines a fallback for unmatched subcommands:

@Unknown(false)
public void unknown(CommandSender sender) {
    sender.sendMessage("Unknown subcommand.");
}

If @Unknown(true) is used, the same method is also exposed as a help subcommand.

@Unknown(true)
public void help(CommandSender sender) {
    sender.sendMessage("/warp teleport <player>");
}

You can also protect that generated help subcommand with a specific permission:

@Unknown(value = true, helpPermission = "example.warp.help")
public void help(CommandSender sender) {

}

πŸ“ Handler Method Structure

A valid handler method follows this layout:

  1. first parameter = sender type
  2. remaining parameters = parsed command arguments

Supported sender types:

  • CommandSender
  • Player
  • ConsoleCommandSender

Any other first parameter causes a runtime failure during command setup.

🧠 Real Usage Patterns

In larger plugins, command sets often use patterns like:

  • player-only subcommands
  • optional trailing arguments
  • explicit manual help through @Unknown(false)
  • class-level base permissions with method-level special permissions

πŸ§ͺ Full Example

@Command("mail")
@Permission("example.mail")
public final class MailCommand extends CustomCommand {

    @Default
    public void defaultCommand(CommandSender sender) {
        sender.sendMessage("/mail send <player> <message>");
    }

    @SubCommand("send")
    @Permission("example.mail.send")
    public void send(
            Player sender,
            @Name("player") Player target,
            @Join @Name("message") String message
    ) {
        target.sendMessage(sender.getName() + ": " + message);
    }

    @Unknown(true)
    public void unknown(CommandSender sender) {
        sender.sendMessage("Unknown subcommand.");
    }

}