Skip to content

Custom Processors

mario edited this page Mar 29, 2026 · 1 revision

Custom Processors

A Processor<T> teaches the framework how to convert a raw String argument into any type T, and optionally how to tab-complete it. Registering a processor makes that type available as a @Param parameter across all commands.

Creating a Processor

Extend Processor<T> on Bukkit, BungeeProcessor<T> on BungeeCord, or VelocityProcessor<T> on Velocity.

  • process() — converts the raw string into T. Return null to abort execution; the sender has already been notified.
  • tabComplete() — returns suggestions for tab completion. Optional — defaults to an empty list.
public enum Rank { MEMBER, MODERATOR, ADMIN }

public class RankProcessor extends Processor<Rank> {
    @Override
    public Rank process(CommandSender sender, String supplied) {
        try {
            return Rank.valueOf(supplied.toUpperCase());
        } catch (IllegalArgumentException e) {
            sender.sendMessage(ChatColor.RED + "Unknown rank. Valid: MEMBER, MODERATOR, ADMIN.");
            return null;
        }
    }

    @Override
    public List<String> tabComplete(CommandSender sender, String supplied) {
        return Arrays.stream(Rank.values())
                .map(r -> r.name().toLowerCase())
                .filter(name -> name.startsWith(supplied.toLowerCase()))
                .collect(Collectors.toList());
    }
}

Registering a Processor

Instantiate it before registering commands, or scan an entire package:

public void onEnable() {
    new RankProcessor();
    // Or scan a package:
    BukkitCommandHandler.registerProcessors("me.myplugin.processors", this);

    BukkitCommandHandler.registerCommands("me.myplugin.commands", this);
}

Using the Type

Once registered, the type is available anywhere as a @Param:

@Command(names = {"setrank"}, permission = "plugin.setrank")
public void setRankCommand(CommandSender sender,
                           @Param(name = "player") Player target,
                           @Param(name = "rank") Rank rank) {
    sender.sendMessage("Set " + target.getName() + "'s rank to " + rank.name() + ".");
}

Processors with Constructor Arguments

If your processor needs dependencies (e.g. a ProxyServer on Velocity), use super(TheType.class) so the framework can identify the type without relying on generic type inference:

public class ConnectedPlayerProcessor extends VelocityProcessor<Player> {
    private final ProxyServer server;

    public ConnectedPlayerProcessor(ProxyServer server) {
        super(Player.class);
        this.server = server;
    }

    @Override
    public Player process(CommandSource source, String supplied) {
        return server.getPlayer(supplied).orElseGet(() -> {
            source.sendMessage(Component.text("Player not found.", NamedTextColor.RED));
            return null;
        });
    }
}

Clone this wiki locally