Subcommand class
The abstract class a plugin extends. Two constructors, two abstract methods, three getters — nothing else.
| Signature | Description |
|---|---|
protected Subcommand(String label) | Visible, no permission requirement. |
protected Subcommand(String label, boolean hidden, String permission) | Full form. A null permission means anyone may run it; hidden keeps it out of tab completion. |
final String label() | The label, as registered. Matching is case-insensitive but the label is reported exactly as given. |
final boolean hidden() | True when the command is excluded from tab completion and help output. |
final String permission() | The permission node checked before execution, or null. |
abstract void execute(Player, String label, String[] args) | label is the subcommand label, args the arguments after it (no label included). |
abstract List<String> onTabComplete(Player, String[] args) | Return the completions for the current argument list; return an empty list for none. |
public final class BrandSubcommand extends Subcommand {
private static final List<String> ARGUMENTS = List.of("alerts", "verbose", "brands");
public BrandSubcommand() {
super("stafftool", false, "myplugin.staff");
}
@Override
public void execute(Player player, String label, String[] args) {
if (args.length == 0) {
player.sendMessage("Usage: /venus " + label + " <" + String.join("|", ARGUMENTS) + ">");
return;
}
switch (args[0].toLowerCase(Locale.ROOT)) {
case "alerts" -> toggle(player, AlertService.Channel.DETECTIONS);
case "verbose" -> toggle(player, AlertService.Channel.VERBOSE);
case "brands" -> toggle(player, AlertService.Channel.BRANDS);
default -> player.sendMessage("Unknown option: " + args[0]);
}
}
private static void toggle(Player player, AlertService.Channel channel) {
VenusApi api = VenusAPIProvider.get();
api.users().queryUserByUuid(player.getUniqueId()).ifPresent(user -> {
AlertSettings settings = api.alerts().settings(user, channel);
settings.setEnabled(!settings.enabled());
player.sendMessage(channel + " is now " + (settings.enabled() ? "on" : "off"));
});
}
@Override
public List<String> onTabComplete(Player player, String[] args) {
if (args.length != 1) return List.of();
String prefix = args[0].toLowerCase(Locale.ROOT);
return ARGUMENTS.stream().filter(option -> option.startsWith(prefix)).toList();
}
}Arguments
The args array never contains the subcommand label. For /venus stafftool verbose you receive args = ["verbose"] and label = "stafftool". Length checks are part of your job; the dispatcher does not validate arity.
Errors
An exception thrown from execute is caught by the dispatcher and reported to the sender as a generic failure, so a bug in your subcommand cannot break /venus for everyone else. Log the detail yourself if you need it.
Registration is covered on the subcommands interface.