cloud-processor-requirements#
Command requirement system for Cloud v2.
The requirements are evaluated before the command is executed to determine whether the command sender should be able to execute the command. The requirements are defined on a per-command basis.
Installation#
<dependencies>
<dependency>
<groupId>org.incendo</groupId>
<artifactId>cloud-processors-requirements</artifactId>
<version>1.0.0-rc.1</version>
</dependency>
</dependencies>
implementation("org.incendo:cloud-processors-requirements:1.0.0-rc.1")
implementation 'org.incendo:cloud-processors-requirements:1.0.0-rc.1'
Usage#
You create requirements by implementing the Requirement
interface. It is recommended to create an intermediary
requirement interface that extends Requirement
that can contain shared logic. This also reduces verbosity introduced
by the generic types. Example:
public interface YourRequirementInterface
extends Requirement<YourSenderType, YourRequirementInterface> {
// Example method
@NonNull String errorMessage();
}
you can then create a requirement:
public final class YourRequirement
implements YourRequirementInterface {
@Override
public @NonNull String errorMessage() {
return "not cool enough";
}
@Override
public boolean evaluateRequirement(
final @NonNull CommandContext<YourSenderType> context
) {
return false; // You should probably put some logic here :)
}
}
You then need to create a CloudKey<Requirements<YourSenderType, YourRequirementInterface>
which is used to store
the requirements in the command meta and for the processor to access the stored requirements:
public static final CloudKey<Requirements<YourSenderType, YourRequirementInterface>>
REQUIREMENT_KEY = CloudKey.of(
"requirements",
new TypeToken<Requirements<YourSenderType, YourRequirementInterface>>() {}
);
You then need to create an instance of the postprocessor and register it to your command manager:
final RequirementPostprocessor<YourSenderType, YourRequirementInterface>
postprocessor = RequirementPostprocessor.of(
REQUIREMENTS_KEY,
new YourFailureHandler()
);
commandManager.registerPostprocessor(postprocessor);
the failure handler gets invoked when the command sender fails to meet a requirement:
public final class YourFailureHandler
implements RequirementFailureHandler<YourSenderType, YourRequirementInterface> {
@Override
public void handleFailure(
final @NonNull CommandContext<YourSenderType> context,
final YourRequirementInterface requirement
) {
context.sender().sendMessage("Requirement failed: " + requirement.errorMessage());
}
}
You then need to register the requirements to your command. This step depends on whether you use builders or annotations.
Builders#
You have two different options when it comes to registering requirements to commands using the command builders. You may store the requirements directly:
commandBuilder.meta(REQUIREMENT_KEY, Requirements.of(requirement, requirement1, ...));
or by using the RequirementApplicable
system:
// Store this somewhere:
RequirementApplicable.RequirementApplicableFactory<YourSenderType,
YourRequirementInterface> factory = RequirementApplicable.factory(REQUIREMENT_KEY);
// Then register the requirements:
commandBuilder.apply(factory.create(requirement, requirement1, ...));
Annotations#
When using cloud-annotations
you may use the RequirementBindings
system to register bindings between
annotations and requirements:
// Create some annotation:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface YourAnnotation {
// ...
}
// Then register a binding for it:
RequirementBindings.create(this.annotationParser, REQUIREMENT_KEY).register(
YourAnnotation.class,
annotation -> new YourRequirement()
);
// Then annotate a method with it:
@YourAnnotation
@Command("command")
public void commandMethod() {
// ...
}