-
Notifications
You must be signed in to change notification settings - Fork 0
Custom ArgumentTypes
Before creating your own ArgumentType<T>
, make sure that neither Brigadier nor Grenadier provides what you're looking for.
You can check all inbuilt types here and all Brigadier types here
I'm going to use WorldArgument as an example for this.
Firstly, create a class which implements ArgumentType<World>
and implements the parse(StringReader reader)
method like so:
public class WorldArgumentType implements ArgumentType<World> {
public World parse(StringReader reader){
}
}
Now we first create an exception provider for unknown world names. It should look like this:
public static final DynamicCommandExceptionType UNKNOWN_WORLD = new DynamicCommandExceptionType(worldName -> new LiteralMessage("Unknown world: " + worldName));
And then we'll make a simple parse method where we read a world name and get the world from that, like so:
public class WorldArgumentType implements ArgumentType<World> {
public static final DynamicCommandExceptionType UNKNOWN_WORLD = new DynamicCommandExceptionType(inputMessage -> new LiteralMessage("Unknown world: " + inputMessage));
public World parse(StringReader reader) throws CommandSyntaxException {
int cursor = reader.getCursor(); //Will be used for placing the cursor in the correct position
String name = reader.readUnqotedString(); //Reads the world name
World result = Bukkit.getWorld(name);
if(result == null){ //If world wasn't found
reader.setCursor(cursor); //Set cursor back into correct position
throw UNKNOWN_WORLD.createWithContext(reader, name);
}
return result;
}
}
That's the base now done, the next part is optional and can be skipped over
The ArgumentType<T>
interface also includes the listSuggestions(CommandContext, SuggestionsBuilder);
method for listing tab completions.
We can implement this method to list world name suggestions like so:
public CompletableFuture<Suggestions> listSuggestions(CommandContext context, SuggestionsBuilder){
String token = builder.getRemaining().toLowerCase(); //What the user has already typed in
for(World w: Bukkit.getWorlds()){
//If world name matches what's already been typed in, suggest it
if(w.getName().toLowerCase().startsWith(token)) builder.suggest(w.getName());
}
return builder.buildFuture();
}
If what you want to suggest is already a list or collection of strings, you can use CommandSource.suggestMatching(SuggestionsBuilder, Iterable<String>)
to quickly suggest items.
To use the argument in commands we'll need an instance of it to use.
We do this by creating a static final instance variable like so: private static final WorldArgumentType WORLD = new WorldArgumentType();
Personally, I like to create a static method that returns that value instead of using the constant directly, in this case, it would look like this:
public static WorldArgumentType world(){
return WORLD;
}
Finally, we have to register the argument type. We can do this by simple calling RoyalArguments.register(WorldArgumentType.class, VanillaArgumentType.WORD);
in onEnable or onLoad.
Now we can easily use the argument type like so:
protected void createCommand(BrigadierCommand command){
command.then(argument("world", WorldArgumentType.world())
.executes(context -> {
CommandSource source = context.getSource();
World world = context.getArgument("world", World.class);
source.sendMessage(world.getName());
return 0;
})
)
}