Arguments

Arguments in the CommandAPI are registered by using a LinkedHashMap<String, Argument> object. There are two things you need to keep in mind when creating arguments:

  • The order which they will be used
  • The type of each argument

By definition of a LinkedHashMap, the order of the elements inserted into it are preserved, meaning the order you add arguments to the LinkedHashMap will be the resulting order of which arguments are presented to the user when they run that command.

Adding arguments for registration is simple:

//Create LinkedHashMap
LinkedHashMap<String, Argument> arguments = new LinkedHashMap<>();

//Add an argument called "target", which is a PlayerArgument
arguments.put("target", new PlayerArgument());

The String value is the tooltip that is shown to a player when they are entering the command.


Argument Casting

To access arguments, they have to be casted to the type that the argument represents. The order of the arguments in the args[] is the same as the order in which the arguments were declared.

LinkedHashMap<String, ArgumentType> arguments = new LinkedHashMap<>();
arguments.put("arg0", new StringArgument());
arguments.put("arg1", new PotionEffectArgument());
arguments.put("arg2", new LocationArgument());

new CommandAPICommand("cmd")
    .withArguments(arguments)
    .executes((sender, args) -> {
        String stringArg = (String) args[0];
        PotionEffectType potionArg = (PotionEffectType) args[1];
        Location locationArg = (Location) args[2];
    })
	.register();

The type to cast each argument (declared in the dev.jorel.commandapi.arguments package) is listed below:

Argument classData type
AdvancementArgumentorg.bukkit.advancement.Advancement
AxisArgumentjava.util.EnumSet<org.bukkit.Axis>
BiomeArgumentorg.bukkit.block.Biome
BooleanArgumentboolean
ChatArgumentnet.md_5.bungee.api.chat.BaseComponent[]
ChatColorArgumentorg.bukkit.ChatColor
ChatComponentArgumentnet.md_5.bungee.api.chat.BaseComponent[]
CustomArgument<T>T
DoubleArgumentdouble
EnchantmentArgumentorg.bukkit.enchantments.Enchantment
EntitySelectorArgumentThe cast type changes depending on the input parameter:
  • EntitySelector.MANY_ENTITIES - Collection<org.bukkit.entity.Entity>

  • EntitySelector.MANY_PLAYERS - Collection<org.bukkit.entity.Player>

  • EntitySelector.ONE_ENTITY - org.bukkit.entity.Entity

  • EntitySelector.ONE_PLAYER - org.bukkit.entity.Player
EntityTypeArgumentorg.bukkit.entity.EntityType
EnvironmentArgumentorg.bukkit.World.Environment
FloatArgumentfloat
FloatRangeArgumentdev.jorel.commandapi.wrappers.FloatRange
FunctionArgumentdev.jorel.commandapi.wrappers.FunctionWrapper[]
GreedyStringArgumentString
IntegerArgumentint
IntegerRangeArgumentdev.jorel.commandapi.wrappers.IntegerRange
ItemStackArgumentorg.bukkit.inventory.ItemStack
LiteralArgumentN/A
Location2DArgumentdev.jorel.commandapi.wrappers.Location2D
LocationArgumentorg.bukkit.Location
LongArgumentlong
LootTableArgumentorg.bukkit.loot.LootTable
MathOperationArgumentdev.jorel.commandapi.wrappers.MathOperation
NBTCompoundArgumentde.tr7zw.nbtapi.NBTContainer
ObjectiveArgumentString
ObjectiveCriteriaArgumentString
ParticleArgumentorg.bukkit.Particle
PlayerArgumentorg.bukkit.entity.Player
PotionEffectArgumentorg.bukkit.potion.PotionEffectType
RecipeArgumentorg.bukkit.inventory.Recipe
RotationArgumentdev.jorel.commandapi.wrappers.Rotation
ScoreboardSlotArgumentdev.jorel.commandapi.wrappers.ScoreboardSlot
ScoreHolderArgumentThe cast type changes depending on the input parameter:
  • ScoreHolderType.SINGLE - String

  • ScoreHolderType.MULTIPLE - Collection<String>
SoundArgumentorg.bukkit.Sound
StringArgumentString
TeamArgumentString
TextArgumentString
TimeArgumentint

Overriding argument suggestions

Sometimes, you want to override the list of suggestions that are provided by an argument. To handle this, the CommandAPI arguments contain two methods to override suggestions:

Argument overrideSuggestions(String... suggestions);
Argument overrideSuggestions(Function<CommandSender, String[]> suggestions);

The first method, overrideSuggestions(String... suggestions) allows you to replace the suggestions normally associated with that argument with an array of strings.

Example - Teleport to worlds by overriding suggestions

Say we're creating a plugin with the ability to teleport to different worlds on the server. If we were to retrieve a list of worlds, we would be able to override the suggestions of a typical StringArgument to teleport to that world. Let's create a command with the following structure:

/tpworld <world>

We then implement our world teleporting command using overrideSuggestions() on the StringArgument to provide a list of worlds to teleport to:

//Populate a String[] with the names of worlds on the server
String[] worlds = Bukkit.getWorlds().stream().map(World::getName).toArray(String[]::new);

//Override the suggestions of the StringArgument with the aforementioned String[]
LinkedHashMap<String, ArgumentType> arguments = new LinkedHashMap<>();
arguments.put("world", new StringArgument().overrideSuggestions(worlds));

new CommandAPICommand("tpworld")
    .withArguments(arguments)
    .executesPlayer((player, args) -> {
       	String world = (String) args[0];
		player.teleport(Bukkit.getWorld(world).getSpawnLocation());
    })
    .register();

The overrideSuggestions(Function<CommandSender, String[]> suggestions) allows you to replace the suggestions normally associated with that argument with an array of strings that are evaluated dynamically using information about the commandsender.

Example - Friend list by overriding suggestions

Say you have a plugin which has a "friend list" for players. If you want to teleport to a friend in that list, you could use a PlayerArgument, which has the list of suggestions overridden with the list of friends that that player has. Since the list of friends depends on the sender, we can use the function to determine what our suggestions should be. Let's use the following command to teleport to a friend from our friend list:

/friendtp <friend>

Let's say we have a simple class to get the friends of a command sender:

public class Friends {
    public static String[] getFriends(CommandSender sender) {
        if(sender instanceof Player) {
            return //Look up friends in a database or file
        } else {
            return new String[0];
        }
    }
}

We can then use this to generate our suggested list of friends:

LinkedHashMap<String, ArgumentType> arguments = new LinkedHashMap<>();
arguments.put("friend", new PlayerArgument().overrideSuggestions((sender) -> {
    Friends.getFriends(sender);
}));

new CommandAPICommand("friendtp")
    .withArguments(arguments)
    .executesPlayer((player, args) -> {
       	Player target = (Player) args[0];
		player.teleport(target);
    })
    .register();

Developer's Note:

The syntax of inlining the .overrideSuggestions() method has been designed to work well with Java's lambdas. For example, we could write the above code more consisely, such as:

LinkedHashMap<String, ArgumentType> arguments = new LinkedHashMap<>();
arguments.put("friend", new PlayerArgument().overrideSuggestions(Friends::getFriends));