Custom Arguments
Arguments
Arguments are the inputs your commands use. Each argument has:
- Name: How you reference it in code and command syntax.
- Type: What kind of data it accepts (string, number, etc).
- Required/Optional: Is it mandatory or can it be skipped?
- Default Value: What it defaults to if not provided.
- Suggestions: Helpful hints for users as they type.
the parsed-value is provided in the executable-pathway-methods for execution logic.
Argument States
Arguments start as unparsed (raw user input) and become parsed (converted to their type). Parsed arguments give you:
- Raw Value: The original input.
- Parsed Value: The processed value you use in your code.
Supported Argument Types
Imperat comes shipped with built-in support for native java types, an even specific types per platform. For more details on this, check out Supported-Types
Custom Argument Types
Want more than basic types? Create your own! Pick the right base class for your shape, define how to parse and validate your custom input, and Imperat handles the rest.
Choosing the right base class
Imperat exposes three layers — pick the one that matches what your type consumes:
| Base class | Consumes | Parse method receives | Use when |
|---|---|---|---|
SimpleArgumentType<S, T> |
A fixed number of tokens (1 by default) | a String |
Most types: numerics, names, IDs, single-word semantics. Multi-token via super(N). |
GreedyArgumentType<S, T> |
All remaining tokens (rest-of-line) | a String |
Free-form messages, descriptions, anything that captures everything left. |
ArgumentType<S, T> |
Variable, peek-driven | a Cursor<S> |
Full control: variable-arity, optional consumption, conditional reads. |
Default to SimpleArgumentType. Only drop down to raw ArgumentType when you need direct cursor control.
Example: Custom Rank Argument
Suppose you want a Rank argument that checks user input against a registry and gives helpful errors.
public class Rank {
private final String name;
private final List<String> permissions = new ArrayList<>();
public Rank(String name) {
this.name = name;
}
public String getName() {
return name;
}
public List<String> getPermissions() {
return permissions;
}
public void addPermission(String permission) {
permissions.add(permission);
}
}
And you have a registry of ranks that define the available ranks in your plugin.
You want to create a mechanism that when a user inputs a rank name as an argument, it gets parsed into a Rank object that you can use in your command logic.
and you would want the input to always be validated as an available rank otherwise an error message is sent to the user.
To handle errors, create a custom exception extending SelfHandledException:
public class UnknownRankException extends SelfHandledException {
private final String input;
public UnknownRankException(String input) {
this.input = input;
}
@Override
public <S extends Source> void handle(
CommandContext<S> context
) {
var sender = context.source();
sender.reply("Unknown rank: '" + input + "'");
}
}
Now, create the parsing logic for your custom argument. A rank is one token, so we extend SimpleArgumentType — the framework reads the token off the cursor and forwards it to us as a String:
public class RankArgumentType extends SimpleArgumentType<PLATFORMSOURCE, Rank> {
@Override
public @NotNull Rank parse(
@NotNull CommandContext<PLATFORMSOURCE> context,
@NotNull Argument<PLATFORMSOURCE> argument,
@NotNull String input
) throws CommandException {
Rank rank = yourRankRegistry.getRank(input);
if (rank == null) {
throw new UnknownRankException(input);
}
return rank;
}
@Override //assuming #getAllRanks returns a `List<Rank>`
public SuggestionProvider<PLATFORMSOURCE> getSuggestionProvider() {
return (ctx, arg)-> {
return yourRankRegistry.getAllRanks().stream()
.map(Rank::getName)
.toList();
};
}
}
How It Works
Your custom ArgumentType parses input, checks validity, and throws your exception if needed. Imperat catches errors and shows users clear messages.
Learn more about error handling and custom exceptions in the Error Handling section.
We overridded the getSuggestionProvider method to provide dynamic suggestions based on the available ranks in the registry.
This way, when users start typing a rank name, they get real-time suggestions of valid ranks.
Learn more about suggestions in the Suggestions section.
Registering Your Argument Type
Register your custom argument type so Imperat knows how to use it:
PLATFORMIMPERAT imperat = PLATFORMIMPERAT.builder()
.argType(Rank.class, new RankArgumentType())
.build();
Using Custom Argument Types
Now use your custom argument in commands just like built-in types:
@RootCommand("rank")
public class RankCommand {
@Execute
public void exec(PLATFORMSOURCE source) {
source.reply("/rank <rank>");
}
@Execute
public void exec(PLATFORMSOURCE source, Rank rank) {
// In a real implementation, you would set the player's rank here.
source.reply("/rank <rank> setpermission <permission>");
}
@SubCommand(value = "setpermission", attachTo = "<rank>")
public class SetPermission {
@Execute
public void setPermission(PLATFORMSOURCE source, @InheritedArg Rank rank, String permission) {
// In a real implementation, you would set the specified player's rank here.
rank.addPermission(permission);
source.reply("Added permission '" + permission + "' to rank '" + rank.getName() + "'");
}
}
}
And don’t forget to register your command:
PLATFORMIMPERAT imperat = PLATFORMIMPERAT.builder()
.argType(Rank.class, new RankArgumentType())
.build();
imperat.registerCommand(RankCommand.class);