Ranged arguments

A float range argument command with the argument "0.5.3.5" entered

Ranged arguments allow players to provide a range between two numbers, all within a single argument. The CommandAPI provides two ranged arguments, IntegerRangeArgument for ranges with only integer values, and FloatRangeArgument for ranged with potential floating point values.

These consist of values such as:

InputWhat it means
5The number 5
5..10Numbers between 5 and 10, including 5 and 10
5..Numbers greater than or equal to 5 (bounded by Java's max number size)
..5Numbers less than or equal to 5 (bounded by Java's min number size)

This allows you to let users define a range of values, which can be used to limit a value, such as the number of players in a region or for a random number generator.


The IntegerRange & FloatRange class

The CommandAPI returns an IntegerRange from the IntegerRangeArgument, and a FloatRange from the FloatRangeArgument, which represents the upper and lower bounds of the numbers provided by the command sender, as well as a method to check if a number is within that range.

The IntegerRange class has the following methods:

class IntegerRange {
    public int getLowerBound();
    public int getUpperBound();
    public boolean isInRange(int);
}

The FloatRange class has the following methods:

class FloatRange {
    public float getLowerBound();
    public float getUpperBound();
    public boolean isInRange(float);
}

Example - Searching chests for certain items

Say you're working on a plugin for server administrators to help them find restricted items. A method of doing so would be to search chests in a given radius for certain items. As such, we can use the following syntax:

/searchchests <range> <item>

Now, we simply create our arguments using IntegerRangeArgument for our range and ItemStackArgument as the item to search for. We can then find all chests in a given area and determine if it is within the range provided by the command sender by using range.isInRange(distance):

new CommandAPICommand("searchrange")
    .withArguments(new IntegerRangeArgument("range")) // Range argument
    .withArguments(new ItemStackArgument("item"))     // The item to search for
    .executesPlayer((player, args) -> {
        // Retrieve the range from the arguments
        IntegerRange range = (IntegerRange) args[0];
        ItemStack itemStack = (ItemStack) args[1];

        // Store the locations of chests with certain items
        List<Location> locations = new ArrayList<>();

        // Iterate through all chunks, and then all tile entities within each chunk
        for (Chunk chunk : player.getWorld().getLoadedChunks()) {
            for (BlockState blockState : chunk.getTileEntities()) {

                // The distance between the block and the player
                int distance = (int) blockState.getLocation().distance(player.getLocation());

                // Check if the distance is within the specified range 
                if (range.isInRange(distance)) {

                    // Check if the tile entity is a chest
                    if (blockState instanceof Chest chest) {
                        
                        // Check if the chest contains the item specified by the player
                        if (chest.getInventory().contains(itemStack.getType())) {
                            locations.add(chest.getLocation());
                        }
                    }
                }

            }
        }

        // Output the locations of the chests, or whether no chests were found
        if (locations.isEmpty()) {
            player.sendMessage("No chests were found");
        } else {
            player.sendMessage("Found " + locations.size() + " chests:");
            locations.forEach(location -> {
                player.sendMessage("  Found at: " 
                        + location.getX() + ", " 
                        + location.getY() + ", " 
                        + location.getZ());
            });
        }
    })
    .register();
CommandAPICommand("searchrange")
    .withArguments(IntegerRangeArgument("range")) // Range argument
    .withArguments(ItemStackArgument("item"))     // The item to search for
    .executesPlayer(PlayerCommandExecutor { player, args ->
        // Retrieve the range from the arguments
        val range = args[0] as IntegerRange
        val itemStack = args[1] as ItemStack

        // Store the locations of chests with certain items
        val locations = mutableListOf<Location>()

        // Iterate through all chunks, and then all tile entities within each chunk
        for (chunk in player.world.loadedChunks) {
            for (blockState in chunk.tileEntities) {

                // The distance between the block and the player
                val distance = blockState.location.distance(player.location).toInt()

                // Check if the distance is within the specified range
                if (range.isInRange(distance)) {

                    // Check if the tile entity is a chest
                    if (blockState is Chest) {

                        // Check if the chest contains the item specified by the player
                        if (blockState.inventory.contains(itemStack.type)) {
                            locations.add(blockState.location)
                        }
                    }
                }

            }
        }

        // Output the locations of the chests, or whether no chests were found
        if (locations.isEmpty()) {
            player.sendMessage("No chests were found")
        } else {
            player.sendMessage("Found ${locations.size} chests:")
            locations.forEach({
                player.sendMessage("  Found at: ${it.getX()}, ${it.getY()}, ${it.getZ()}")
            })
        }
    })
    .register()