Command Conditions - adamtomi/grapefruit GitHub Wiki

Basic Usage

The command condition system is a powerful tool that lets you make the execution of commands depend on certain conditions. A condition receives the current command context to permorm the test, and throw ConditionFailedException in case one of the conditions is not met. More or less. Let's look at a simple example. Suppose that our CommandSender class has a CommandSender#name function, which we would like to invoke to see if the source's name is longer than 15 characters, in which case the execution will be blocked. This is a dumb example or course, but just for the sake of demonstration, here we go...

First, a custom command condition has to be created:

public class NameLengthCondition implements CommandCondition<CommandSource> {
    public static final String ID = "name_length_test";

    @Override
    public @NotNull String id() {
        return ID;
    }
   
    @Override
    public void test(final @NotNull CommandContext<CommandSource> context) throws ConditionFailedException {
        final CommandSource source = context.source();
        final String name = source.name();
        if (name.lenght() > 15) {
            throw new ConditionFailedException(ID, context);
        }
    }
}

Notice, how the ID is a public constant. This is absolutely not necessary, but makes potential refactors a lot easier, since the only place where the id has to change is in the above class. Moving on, the next step is to register this condition, which is easily done like this:

final CommandDispatcher<CommandSource> dispatcher = // ...
dispatcher.conditions().registerCondition(new NameLengthCondition());

Now we can start using our shiny new condition:

@Condition(NameLengthCondition.ID)
@CommandDefinition(route = "test")
public void testCommand(final @Source CommandSource source) {
   // run command logic
}

Please note, that conditions are tested once all parameters have been successfully parsed, so it's guaranteed, that the context contains all parsed values.

Combining Conditions

At this point in time, it's possible to define conditions in OR relation using a single @Condition annotation, and by adding more annotations, each condition group is AND-ed together. Consider the following example:

@Condition({"a", "b"})
@Condition("c")
@Condition({"d", "e", "f"})
@CommandDefinition(route = "dummy")
public void dummyCommand(final @Source CommandSource source) {}

If we translate this to boolean algebra, the result will be something like the following: (a+b)*(c)*(d+e+f). In case you aren't familiar with boolean algebra, here comes a little explanation. An OR relation means that at least one of the conditions has to pass in order for the whole condition to pass. An AND relation means that all conditions have to pass. So in the above case a or b has to pass and c has to pass and either d or e or f has to pass, otherwise the check fails and the command execution will be cancelled.