Skip to content

Commit

Permalink
GH-357 Add priority api, strict mode, event api and @DefaultExecute. …
Browse files Browse the repository at this point in the history
…Snapshot 3.6.0-SNAPSHOT (#366)

* Add priority API

* Implements priorities for executors.

* Pre sorting

* Revert spaces

* Add priority annotation

* Add priority unit tests.

* Rename builder actions methods.

* Event system (wip)

* Implement event api

* Move validation to event API.

* Better api for priority annotation. Refactor the priority list.

* Update publish api

* Use LookupMethodReflection for EventPublisher. Add @subscriber annotation. Fix cooldown controller.

* Remove LookupMethodReflection

* Remove unused field

* Fix programmatic flag

* Add @ExecuteDefault annotation. Move Cause mapping to InvalidUsageResultController. Add IGNORE_TOO_MANY_ARGUMENTS to Meta.

* Mark @markmeta annotation as deprecated. Add strict mode and strict service. Add unit tests for @ExecuteDefault. Add unit tests for strict mode feature.

* Add api to change default strict mode.

* Expose strict service.

* Snapshot 3.6.0-SNAPSHOT

* Fix suggestion#delateLeft method.

* Fix multiple optional suggestions.

* Fix docs
  • Loading branch information
Rollczi authored Sep 15, 2024
1 parent 68a88d1 commit 6fb8b76
Show file tree
Hide file tree
Showing 102 changed files with 2,196 additions and 273 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ jobs:
run: chmod +x gradlew

- name: Build with Gradle
run: ./gradlew clean test clean build
run: ./gradlew clean test build
env:
GIT_BRANCH: ${{ github.ref }}
GIT_COMMIT: ${{ github.sha }}
2 changes: 1 addition & 1 deletion buildSrc/src/main/kotlin/litecommands-publish.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ plugins {
}

group = "dev.rollczi"
version = "3.5.1-SNAPSHOT"
version = "3.6.0-SNAPSHOT"

java {
withSourcesJar()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import dev.rollczi.litecommands.LiteCommands;
import dev.rollczi.litecommands.join.JoinArgument;
import dev.rollczi.litecommands.programmatic.LiteCommand;
import dev.rollczi.litecommands.strict.StrictMode;
import dev.rollczi.litecommands.suggestion.SuggestionResult;
import dev.rollczi.litecommands.bukkit.LiteCommandsBukkit;
import dev.rollczi.litecommands.schematic.SchematicFormat;
Expand Down Expand Up @@ -98,6 +99,10 @@ public void onEnable() {
// Schematic generator is used to generate schematic for command, for example when you run invalid command.
.schematicGenerator(SchematicFormat.angleBrackets())

// strict mode - you can enable/disable strict mode for each command (default is enabled)
// if strict mode is enabled, the command will fail if the user provides too many arguments
.strictMode(StrictMode.ENABLED)

.build();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,23 @@

import dev.rollczi.litecommands.annotations.argument.Arg;
import dev.rollczi.litecommands.annotations.command.Command;
import dev.rollczi.litecommands.annotations.context.Context;
import dev.rollczi.litecommands.annotations.execute.Execute;
import dev.rollczi.litecommands.annotations.execute.ExecuteDefault;
import dev.rollczi.litecommands.annotations.permission.Permission;
import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;

@Command(name = "kickall")
@Permission("dev.rollczi.kickall")
public class KickAllCommand {

@ExecuteDefault
public void commandHelp(@Context CommandSender sender) {
sender.sendMessage("Correct usage: /kickall -all|<players...>");
}

@Execute(name = "-all")
public void kickAll() {
for (Player onlinePlayer : Bukkit.getOnlinePlayers()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@
public class TeleportCommand {

@Execute
public void teleportSelf(@Context Player sender, @Arg Player to) {
sender.teleport(to.getLocation());
public void teleportSelf(@Context Player sender, @Arg Player target) {
sender.teleport(target.getLocation());
}

@Execute
Expand All @@ -27,8 +27,8 @@ public void teleportSelfToPosition(@Context Player sender, @Arg Location locatio

@Execute
@Permission("dev.rollczi.teleport.other")
public void teleportOther(@Arg("target") Player target, @Arg("to") Player to) {
target.teleport(to.getLocation());
public void teleportOther(@Arg("other") Player other, @Arg("target") Player target) {
other.teleport(target.getLocation());
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -7,27 +7,27 @@
public interface AnnotationInvoker<SENDER> {

default <A extends Annotation>
AnnotationInvoker<SENDER> on(Class<A> annotationType, AnnotationProcessor.Listener<A> listener) {
AnnotationInvoker<SENDER> on(Class<A> annotationType, AnnotationProcessor.AnyListener<A> listener) {
return this;
}

default <A extends Annotation>
AnnotationInvoker<SENDER> onStructure(Class<A> annotationType, AnnotationProcessor.StructureListener<SENDER, A> listener) {
AnnotationInvoker<SENDER> onClass(Class<A> annotationType, AnnotationProcessor.ClassListener<SENDER, A> listener) {
return this;
}

default <A extends Annotation>
AnnotationInvoker<SENDER> onExecutorStructure(Class<A> annotationType, AnnotationProcessor.StructureExecutorListener<SENDER, A> listener) {
AnnotationInvoker<SENDER> onMethod(Class<A> annotationType, AnnotationProcessor.MethodListener<SENDER, A> listener) {
return this;
}

default <A extends Annotation>
AnnotationInvoker<SENDER> onRequirement(Class<A> annotationType, AnnotationProcessor.RequirementListener<SENDER, A> listener) {
AnnotationInvoker<SENDER> onParameter(Class<A> annotationType, AnnotationProcessor.ParameterListener<SENDER, A> listener) {
return this;
}

default <A extends Annotation>
AnnotationInvoker<SENDER> onRequirementMeta(Class<A> annotationType, AnnotationProcessor.RequirementMetaListener<SENDER, A> listener) {
AnnotationInvoker<SENDER> onParameterRequirement(Class<A> annotationType, AnnotationProcessor.ParameterRequirementListener<SENDER, A> listener) {
return this;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,30 +6,32 @@
import dev.rollczi.litecommands.requirement.Requirement;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.Optional;

public interface AnnotationProcessor<SENDER> {

AnnotationInvoker<SENDER> process(AnnotationInvoker<SENDER> invoker);

interface Listener<A extends Annotation> {
interface AnyListener<A extends Annotation> {
void call(A annotation, MetaHolder metaHolder);
}

interface StructureListener<SENDER, A extends Annotation> {
CommandBuilder<SENDER> call(A annotation, CommandBuilder<SENDER> builder);
interface ClassListener<SENDER, A extends Annotation> {
CommandBuilder<SENDER> call(Class<?> classType, A annotation, CommandBuilder<SENDER> builder);
}

interface StructureExecutorListener<SENDER, A extends Annotation> {
void call(A annotation, CommandBuilder<SENDER> builder, CommandExecutorProvider<SENDER> executorProvider);
interface MethodListener<SENDER, A extends Annotation> {
void call(Method method, A annotation, CommandBuilder<SENDER> builder, CommandExecutorProvider<SENDER> executorProvider);
}

interface RequirementListener<SENDER, A extends Annotation> {
Optional<Requirement<?>> call(AnnotationHolder<A, ?, ?> annotationHolder, CommandBuilder<SENDER> builder);
interface ParameterListener<SENDER, A extends Annotation> {
Optional<Requirement<?>> call(Parameter parameter, AnnotationHolder<A, ?, ?> annotationHolder, CommandBuilder<SENDER> builder);
}

interface RequirementMetaListener<SENDER, A extends Annotation> {
void call(AnnotationHolder<A, ?, ?> annotationHolder, CommandBuilder<SENDER> builder, Requirement<?> requirement);
interface ParameterRequirementListener<SENDER, A extends Annotation> {
void call(Parameter parameter, AnnotationHolder<A, ?, ?> annotationHolder, CommandBuilder<SENDER> builder, Requirement<?> requirement);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import dev.rollczi.litecommands.annotations.optional.OptionalArgArgumentProcessor;
import dev.rollczi.litecommands.annotations.permission.PermissionAnnotationResolver;
import dev.rollczi.litecommands.annotations.permission.PermissionsAnnotationResolver;
import dev.rollczi.litecommands.annotations.priority.PriorityAnnotationResolver;
import dev.rollczi.litecommands.annotations.quoted.QuotedAnnotationProcessor;
import dev.rollczi.litecommands.annotations.shortcut.ShortcutCommandAnnotationProcessor;
import dev.rollczi.litecommands.annotations.validator.ValidateAnnotationResolver;
Expand Down Expand Up @@ -56,6 +57,7 @@ public static <SENDER> AnnotationProcessorService<SENDER> defaultService() {
.register(new AsyncAnnotationResolver<>())
.register(new PermissionAnnotationResolver<>())
.register(new PermissionsAnnotationResolver<>())
.register(new PriorityAnnotationResolver<>())
.register(new ValidateAnnotationResolver<>())
.register(new CooldownAnnotationResolver<>())
// argument meta processors
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ public ClassInvoker(Class<?> type, CommandBuilder<SENDER> commandBuilder) {
}

@Override
public <A extends Annotation> AnnotationInvoker<SENDER> on(Class<A> annotationType, AnnotationProcessor.Listener<A> listener) {
public <A extends Annotation> AnnotationInvoker<SENDER> on(Class<A> annotationType, AnnotationProcessor.AnyListener<A> listener) {
A annotation = type.getAnnotation(annotationType);

if (annotation == null) {
Expand All @@ -27,14 +27,14 @@ public <A extends Annotation> AnnotationInvoker<SENDER> on(Class<A> annotationTy
}

@Override
public <A extends Annotation> AnnotationInvoker<SENDER> onStructure(Class<A> annotationType, AnnotationProcessor.StructureListener<SENDER, A> listener) {
public <A extends Annotation> AnnotationInvoker<SENDER> onClass(Class<A> annotationType, AnnotationProcessor.ClassListener<SENDER, A> listener) {
A annotation = type.getAnnotation(annotationType);

if (annotation == null) {
return this;
}

commandBuilder = listener.call(annotation, commandBuilder);
commandBuilder = listener.call(type, annotation, commandBuilder);
return this;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
import java.lang.reflect.Parameter;
import java.util.function.Supplier;

class MethodCommandExecutor<SENDER> extends AbstractCommandExecutor<SENDER> {
public class MethodCommandExecutor<SENDER> extends AbstractCommandExecutor<SENDER> {

private final Method method;
private final Parameter[] parameters;
Expand All @@ -46,6 +46,18 @@ class MethodCommandExecutor<SENDER> extends AbstractCommandExecutor<SENDER> {
this.meta.apply(meta);
}

public Object getInstance() {
return instance;
}

public Method getMethod() {
return method;
}

public MethodDefinition getDefinition() {
return definition;
}

@Override
public CommandExecutorMatchResult match(RequirementsResult<SENDER> results) {
Object[] objects = new Object[method.getParameterCount()];
Expand Down Expand Up @@ -103,6 +115,10 @@ public CommandExecuteResult get() {
} catch (InvocationTargetException exception) {
Throwable targetException = exception.getTargetException();

if (targetException instanceof InvalidUsageException) { //TODO: Use invalid usage handler (when InvalidUsage.Cause is mapped to InvalidUsage)
return CommandExecuteResult.failed(MethodCommandExecutor.this, ((InvalidUsageException) targetException).getErrorResult());
}

throw new LiteCommandsReflectInvocationException(MethodCommandExecutor.this.method, "Command method threw " + targetException.getClass().getSimpleName(), targetException);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ public MethodInvoker(AnnotationProcessorService<SENDER> annotationProcessorServi
}

@Override
public <A extends Annotation> AnnotationInvoker<SENDER> on(Class<A> annotationType, AnnotationProcessor.Listener<A> listener) {
public <A extends Annotation> AnnotationInvoker<SENDER> on(Class<A> annotationType, AnnotationProcessor.AnyListener<A> listener) {
A annotation = method.getAnnotation(annotationType);

if (annotation == null) {
Expand All @@ -50,20 +50,20 @@ public <A extends Annotation> AnnotationInvoker<SENDER> on(Class<A> annotationTy
}

@Override
public <A extends Annotation> AnnotationInvoker<SENDER> onExecutorStructure(Class<A> annotationType, AnnotationProcessor.StructureExecutorListener<SENDER, A> listener) {
public <A extends Annotation> AnnotationInvoker<SENDER> onMethod(Class<A> annotationType, AnnotationProcessor.MethodListener<SENDER, A> listener) {
A methodAnnotation = method.getAnnotation(annotationType);

if (methodAnnotation == null) {
return this;
}

listener.call(methodAnnotation, commandBuilder, executorProvider);
listener.call(method, methodAnnotation, commandBuilder, executorProvider);
isExecutorStructure = true;
return this;
}

@Override
public <A extends Annotation> AnnotationInvoker<SENDER> onRequirement(Class<A> annotationType, AnnotationProcessor.RequirementListener<SENDER, A> listener) {
public <A extends Annotation> AnnotationInvoker<SENDER> onParameter(Class<A> annotationType, AnnotationProcessor.ParameterListener<SENDER, A> listener) {
for (int index = 0; index < method.getParameterCount(); index++) {
Parameter parameter = method.getParameters()[index];
A parameterAnnotation = parameter.getAnnotation(annotationType);
Expand All @@ -76,7 +76,7 @@ public <A extends Annotation> AnnotationInvoker<SENDER> onRequirement(Class<A> a
continue;
}

Optional<Requirement<?>> requirementOptional = listener.call(createHolder(parameterAnnotation, parameter), commandBuilder);
Optional<Requirement<?>> requirementOptional = listener.call(parameter, createHolder(parameterAnnotation, parameter), commandBuilder);

if (requirementOptional.isPresent()) {
Requirement<?> requirement = requirementOptional.get();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ class ParameterInvoker<SENDER> implements AnnotationInvoker<SENDER> {
}

@Override
public <A extends Annotation> AnnotationInvoker<SENDER> on(Class<A> annotationType, AnnotationProcessor.Listener<A> listener) {
public <A extends Annotation> AnnotationInvoker<SENDER> on(Class<A> annotationType, AnnotationProcessor.AnyListener<A> listener) {
A annotation = parameter.getAnnotation(annotationType);

if (annotation == null) {
Expand All @@ -35,14 +35,14 @@ public <A extends Annotation> AnnotationInvoker<SENDER> on(Class<A> annotationTy
}

@Override
public <A extends Annotation> AnnotationInvoker<SENDER> onRequirementMeta(Class<A> annotationType, AnnotationProcessor.RequirementMetaListener<SENDER, A> listener) {
public <A extends Annotation> AnnotationInvoker<SENDER> onParameterRequirement(Class<A> annotationType, AnnotationProcessor.ParameterRequirementListener<SENDER, A> listener) {
A annotation = parameter.getAnnotation(annotationType);

if (annotation == null) {
return this;
}

listener.call(createHolder(annotation, parameter), commandBuilder, requirement);
listener.call(parameter, createHolder(annotation, parameter), commandBuilder, requirement);
return this;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import dev.rollczi.litecommands.annotations.execute.Execute;

import dev.rollczi.litecommands.strict.StrictMode;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
Expand All @@ -28,4 +29,10 @@
*/
String[] aliases() default {};

/**
* Disables/Enables the strict mode.
* If the strict mode is disabled, the method will be executed even if there are too many arguments.
*/
StrictMode strict() default StrictMode.DEFAULT;

}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

import dev.rollczi.litecommands.annotations.AnnotationInvoker;
import dev.rollczi.litecommands.annotations.AnnotationProcessor;
import dev.rollczi.litecommands.meta.Meta;
import dev.rollczi.litecommands.strict.StrictMode;
import dev.rollczi.litecommands.util.LiteCommandsUtil;

import java.util.Arrays;
Expand All @@ -10,17 +12,23 @@ public class CommandAnnotationProcessor<SENDER> implements AnnotationProcessor<S

@Override
public AnnotationInvoker<SENDER> process(AnnotationInvoker<SENDER> invoker) {
return invoker.onStructure(Command.class, (annotation, builder) -> {
boolean isNotEmpty = LiteCommandsUtil.checkConsistent(annotation.name(), annotation.aliases());
return invoker
.on(Command.class, (annotation, metaHolder) -> {
if (annotation.strict() != StrictMode.DEFAULT) {
metaHolder.meta().put(Meta.STRICT_MODE, annotation.strict());
}
})
.onClass(Command.class, (classType, annotation, builder) -> {
boolean isNotEmpty = LiteCommandsUtil.checkConsistent(annotation.name(), annotation.aliases());

if (isNotEmpty) {
return builder
.routeName(annotation.name())
.routeAliases(Arrays.asList(annotation.aliases()));
}
if (isNotEmpty) {
return builder
.routeName(annotation.name())
.routeAliases(Arrays.asList(annotation.aliases()));
}

throw new IllegalArgumentException("Route name cannot be empty");
});
throw new IllegalArgumentException("Route name cannot be empty");
});
}

}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package dev.rollczi.litecommands.annotations.command;

import dev.rollczi.litecommands.strict.StrictMode;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
Expand All @@ -15,4 +16,10 @@
@Retention(RetentionPolicy.RUNTIME)
public @interface RootCommand {

/**
* Disables/Enables the strict mode.
* If the strict mode is disabled, the method will be executed even if there are too many arguments.
*/
StrictMode strict() default StrictMode.DEFAULT;

}
Loading

0 comments on commit 6fb8b76

Please sign in to comment.