Skip to content

Custom Argument Types

Redempt edited this page Nov 16, 2021 · 9 revisions

Sometimes the basic data types don't cut it. Sometimes you need to take a more complex type, like World, or even your own data type. Command Manager makes that easy.

To start with, you have to create an ArgType, which tells the command manager how to convert from a String (the command argument) to another data type. Defining this is simple. Here's an example of how to create one for World:

ArgType<World> worldType = new ArgType<>("world", Bukkit::getWorld);

world is now the name of this ArgType, and Bukkit::getWorld is a lambda for a Function<String, World> that will convert from String to World. You can also create an ArgType by passing a BiFunction<CommandSender, String, T> where T is the argument type.

Optionally, you can also give your argument type tab completion. For World, it would look like this:

ArgType<World> worldType = new ArgType<>("world", Bukkit::getWorld)
	.tabStream(c -> Bukkit.getWorlds().stream().map(World::getName));

Alternatively, if you want a command (not an argument type) to not be tab-completable, you can add the notab tag to it in the command file.

Calling tabStream, you must pass a Function<CommandSender, Stream<String>> which will provide tab completions for this type. In this case, it gets the list of worlds, and maps the Stream to be of their names, which are Strings.

Now that you've finished your ArgType, a whopping 2 lines of code, you're ready to register it and start using it in your commands. First, you have to add it to the CommandParser:

new CommandParser(this.getResource("command.rdcml"))
	.setArgTypes(worldType)
	.parse().register("prefix", this);

setArgTypes takes a vararg of ArgType, so you can pass as many as you need into it. Once you've done that, you can start using it in your command file:

worldspawn world:target {
	help Teleports you to the spawn of the given world
	user player
	permission worldspawn.use
	hook worldspawn
}

Since we created our ArgType with the name world, that's what we give as the argument type in our command file now.

Now your command hook method would look like this:

@CommandHook("worldspawn")
public void worldSpawn(Player player, World world) {
	player.teleport(world.getSpawnLocation());
}

This saves you from having to convert from String to other types every time you write another command.

Additionally, if your custom type is an enum or you have a Map<String, T> for your type, you can do it even more simply:

ArgType<Material> materialType = ArgType.of("material", Material.class);

Using this will create an ArgType named material for the Material enum, and it will automatically tab-complete for all the elements of the enum. Likewise, you can call the same method with a Map<String, T> with T being the type returned by your ArgType, and it will automatically be able to tab-complete all keys in the map.

Map<String, Team> teamMap = new HashMap<>(); //Assume values are already populated in this map
ArgType<Team> teamType = ArgType.of("team", teamMap);
Clone this wiki locally