Skip to content
JOO200 edited this page Jun 23, 2020 · 7 revisions

Command Conditions

Context resolvers are designed to be a way to resolve (dependency inject) the desired value of an object based on the users input.

Initially, we added some flags that allowed you to perform additional validation AFTER the object was resolved, such as Players "itemheld".

However it was not possible for end users to add even more flags without defining the entire context handler and duplicate the code.

Command Conditions resolves this problem.

Purpose / Why to use them

Command Conditions allow you to register independent validation/restrictions to be placed on the resolved value of a parameter, the command method itself, or an entire command class.

Say for example you want to restrict that players are in creative mode when they run a command. You may now put @Conditions("creative") on your command to enforce creative restrictions.

Or say you wanted to put a restriction that commands must be ran during day time, you might add @Conditions("daytime")

Multiple conditions in one annotation

To use multiple conditions simply split them with "|"

e.g. @Conditions("daytime|creative")

Registering your own conditions

Example:

    public void validateTime(World world) {
            if (world.getTime() < DAY_START || world.getTime() > DAY_END) {
                throw new ConditionFailedException("Target world must be currently day.");
            }
    }
    public void registerConditions() {
        // Method or Class based - Can only be used on methods
        manager.getCommandConditions().addCondition("daytime", (context) -> {
            BukkitCommandIssuer issuer = context.getIssuer();
            World world = Bukkit.getWorlds().get(0);
            if (issuer.isPlayer()) {
                world = issuer.getPlayer().getWorld();
            }
            validateTime(world);
        }));

        // Parameter Based - Only applicable on Parameters of type SomeObject
        // Integer.class can be any object, but it has to be the type of object the parameter
        // that you'll be using it on is.
        manager.getCommandConditions().addCondition(Integer.class, "limits", (c, exec, value) -> {
            if (value == null) {
                return;
            }
            if (c.hasConfig("min") && c.getConfigValue("min", 0) > value) {
                throw new ConditionFailedException("Min value must be " + c.getConfigValue("min", 0));
            }
            if (c.hasConfig("max") && c.getConfigValue("max", 3) < value) {
                throw new ConditionFailedException("Max value must be " + c.getConfigValue("max", 3));
            }
        });

        // Register the equivalent daytime condition for Player parameters
        manager.getCommandConditions().addCondition(Player.class, "daytime", (context, executionContext, player) -> {
            validateTime(player.getWorld());
        }));
    }

Example on commands

    @Subcommand("dark") @Conditions("daytime") @CommandPermission("darkenself")
    public void onDarken(Player player) { 
        makeDark(player); 
    }

    @Subcommand("darkother") @CommandPermission("darken.others")
    public void onDarken(Player player, @Flags("other") @Conditions("daytime") Player target) { 
        makeDark(player); 
    }

    @CommandAlias("limitstest")
    public void onLimitsTest(CommandSender sender, @Default("7") @Conditions("limits:min=5,max=10") Integer number) {
	        sender.sendMessage(number.toString());
    }