Compare commits

...

10 Commits

20 changed files with 375 additions and 106 deletions

View File

@ -1,7 +1,22 @@
package net.tomatentum.marinara; package net.tomatentum.marinara;
import net.tomatentum.marinara.registry.InteractionRegistry;
import net.tomatentum.marinara.wrapper.LibraryWrapper;
public class Marinara { public class Marinara {
public static Marinara load() {
public static Marinara load(LibraryWrapper wrapper) {
InteractionRegistry registry = new InteractionRegistry(wrapper);
return new Marinara(registry);
}
private InteractionRegistry registry;
private Marinara(InteractionRegistry registry) {
this.registry = registry;
}
public InteractionRegistry getRegistry() {
return registry;
} }
} }

View File

@ -1,28 +0,0 @@
package net.tomatentum.marinara.command;
import net.tomatentum.marinara.handler.InteractionHandler;
public abstract class DiscordCommand implements InteractionHandler {
private String name;
private String description;
private String[] aliases;
protected DiscordCommand(String name, String description, String... aliases) {
this.name = name;
this.description = description;
this.aliases = aliases;
}
public String getName() {
return name;
}
public String getDescription() {
return description;
}
public String[] getAliases() {
return aliases;
}
}

View File

@ -1,17 +0,0 @@
package net.tomatentum.marinara.command;
public class GlobalDiscordCommand extends DiscordCommand{
private boolean enabledInDms = false;
public GlobalDiscordCommand(String name, String description, String... aliases) {
super(name, description, aliases);
}
public boolean isEnabledInDms() {
return enabledInDms;
}
public void setEnabledInDms(boolean enabledInDms) {
this.enabledInDms = enabledInDms;
}
}

View File

@ -1,13 +0,0 @@
package net.tomatentum.marinara.command;
public class ServerDiscordCommand extends DiscordCommand {
private long[] servers;
public ServerDiscordCommand(String name, String description, String... aliases) {
super(name, description, aliases);
}
public long[] getServers() {
return servers;
}
}

View File

@ -1,11 +0,0 @@
package net.tomatentum.marinara.command.annotation;
import net.tomatentum.marinara.command.option.OptionType;
public @interface CommandOption {
public String name();
public String description() default "";
public OptionType type() default OptionType.STRING;
public boolean required() default false;
}

View File

@ -1,7 +0,0 @@
package net.tomatentum.marinara.command.annotation;
public @interface RootCommand {
public String name();
public String description() default "";
public CommandOption[] options() default {};
}

View File

@ -1,7 +0,0 @@
package net.tomatentum.marinara.command.annotation;
public @interface SubCommand {
public String name();
public String description() default "";
public CommandOption[] options() default {};
}

View File

@ -1,6 +0,0 @@
package net.tomatentum.marinara.command.annotation;
public @interface SubCommandGroup {
public String name();
public String description() default "";
}

View File

@ -0,0 +1,73 @@
package net.tomatentum.marinara.interaction.commands;
public record CommandDefinition(String applicationCommand, String applicationCommandDescription, String[] subCommandGroups, String subCommand, String subCommandDescription) {
@Override
public final boolean equals(Object o) {
if (!(o instanceof CommandDefinition))
return false;
CommandDefinition other = (CommandDefinition) o;
return other.applicationCommand.equals(this.applicationCommand) &&
other.subCommandGroups.equals(this.subCommandGroups) &&
other.subCommand.equals(this.subCommand);
}
public static class Builder {
private String applicationCommandName;
private String applicationCommandDescription;
private String[] subCommandGroupNames;
private String subCommandName;
private String subCommandDescription;
public Builder() {
this.subCommandGroupNames = new String[0];
}
public CommandDefinition build() {
if (applicationCommandName == null)
throw new IllegalArgumentException("applicationCommandName cant be null");
return new CommandDefinition(applicationCommandName, applicationCommandDescription, subCommandGroupNames, subCommandName, subCommandDescription);
}
public void setApplicationCommandName(String applicationCommandName) {
this.applicationCommandName = applicationCommandName;
}
public void setApplicationCommandDescription(String applicationCommandDescription) {
this.applicationCommandDescription = applicationCommandDescription;
}
public void setSubCommandGroupNames(String[] subCommandGroupNames) {
this.subCommandGroupNames = subCommandGroupNames;
}
public void setSubCommandName(String subCommandName) {
this.subCommandName = subCommandName;
}
public void setSubCommandDescription(String subCommandDescription) {
this.subCommandDescription = subCommandDescription;
}
public String getApplicationCommandName() {
return applicationCommandName;
}
public String getApplicationCommandDescription() {
return applicationCommandDescription;
}
public String[] getSubCommandGroupNames() {
return subCommandGroupNames;
}
public String getSubCommandName() {
return subCommandName;
}
public String getSubCommandDescription() {
return subCommandDescription;
}
}
}

View File

@ -0,0 +1,15 @@
package net.tomatentum.marinara.interaction.commands.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface ApplicationCommand {
public String name();
public String description() default "";
public String[] aliases() default {};
public CommandOption[] options() default {};
}

View File

@ -0,0 +1,17 @@
package net.tomatentum.marinara.interaction.commands.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import net.tomatentum.marinara.interaction.commands.option.OptionType;
@Target({ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface CommandOption {
public String name();
public String description() default "";
public OptionType type() default OptionType.STRING;
public boolean required() default false;
}

View File

@ -0,0 +1,14 @@
package net.tomatentum.marinara.interaction.commands.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface SubCommand {
public String name();
public String description() default "";
public CommandOption[] options() default {};
}

View File

@ -0,0 +1,13 @@
package net.tomatentum.marinara.interaction.commands.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface SubCommandGroup {
public String name();
public String description() default "";
}

View File

@ -1,4 +1,4 @@
package net.tomatentum.marinara.command.option; package net.tomatentum.marinara.interaction.commands.option;
public enum OptionType { public enum OptionType {
ATTACHMENT, ATTACHMENT,

View File

@ -0,0 +1,83 @@
package net.tomatentum.marinara.interaction.methods;
import java.lang.reflect.Method;
import net.tomatentum.marinara.interaction.InteractionType;
import net.tomatentum.marinara.interaction.commands.CommandDefinition;
import net.tomatentum.marinara.interaction.commands.annotation.ApplicationCommand;
import net.tomatentum.marinara.interaction.commands.annotation.CommandOption;
import net.tomatentum.marinara.interaction.commands.annotation.SubCommand;
import net.tomatentum.marinara.interaction.commands.annotation.SubCommandGroup;
import net.tomatentum.marinara.util.ReflectionUtil;
import net.tomatentum.marinara.handler.InteractionHandler;
import net.tomatentum.marinara.wrapper.LibraryWrapper;
public class CommandInteractionMethod extends InteractionMethod {
private CommandOption[] options;
private CommandDefinition commandDefinition;
CommandInteractionMethod(Method method, InteractionHandler handler, LibraryWrapper wrapper) {
super(method, handler, wrapper);
parseMethod();
}
@Override
public Object getParameter(Object context, int index) {
return wrapper.convertCommandOption(context, options[index].type(), options[index].name());
}
@Override
public boolean canRun(Object context) {
CommandDefinition other = wrapper.getCommandDefinition(context);
return commandDefinition.equals(other);
}
@Override
public InteractionType getType() {
return InteractionType.COMMAND;
}
public CommandOption[] getOptions() {
return options;
}
public CommandDefinition getCommandDefinition() {
return commandDefinition;
}
private void parseMethod() {
ReflectionUtil.checkValidCommandMethod(method);
parseOptions();
ApplicationCommand cmd = ReflectionUtil.getAnnotation(method, ApplicationCommand.class);
CommandDefinition.Builder builder = new CommandDefinition.Builder();
builder.setApplicationCommandName(cmd.name());
builder.setApplicationCommandDescription(cmd.description());
if (ReflectionUtil.isAnnotationPresent(method, SubCommandGroup.class)) {
SubCommandGroup cmdGroup = ReflectionUtil.getAnnotation(method, SubCommandGroup.class);
builder.setSubCommandGroupNames(cmdGroup.name().split(" "));
}
if (ReflectionUtil.isAnnotationPresent(method, SubCommand.class)) {
SubCommand subCmd = ReflectionUtil.getAnnotation(method, SubCommand.class);
builder.setSubCommandName(subCmd.name());
builder.setSubCommandDescription(subCmd.description());
}
this.commandDefinition = builder.build();
}
private CommandOption[] parseOptions() {
if (method.isAnnotationPresent(SubCommand.class)) {
SubCommand subCmd = method.getAnnotation(SubCommand.class);
return subCmd.options();
}else {
ApplicationCommand subCmd = method.getAnnotation(ApplicationCommand.class);
return subCmd.options();
}
}
}

View File

@ -0,0 +1,65 @@
package net.tomatentum.marinara.interaction.methods;
import java.lang.reflect.Method;
import java.security.InvalidParameterException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import net.tomatentum.marinara.handler.InteractionHandler;
import net.tomatentum.marinara.interaction.InteractionType;
import net.tomatentum.marinara.interaction.commands.annotation.ApplicationCommand;
import net.tomatentum.marinara.interaction.commands.annotation.SubCommand;
import net.tomatentum.marinara.wrapper.LibraryWrapper;
public abstract class InteractionMethod {
public static InteractionMethod create(Method method, InteractionHandler handler, LibraryWrapper wrapper) {
if (method.isAnnotationPresent(ApplicationCommand.class) || method.isAnnotationPresent(SubCommand.class))
return new CommandInteractionMethod(method, handler, wrapper);
return null;
}
protected Method method;
protected InteractionHandler handler;
protected LibraryWrapper wrapper;
protected InteractionMethod(Method method, InteractionHandler handler, LibraryWrapper wrapper) {
if (!Arrays.asList(handler.getClass().getMethods()).contains(method))
throw new InvalidParameterException("Method does not apply to specified handler");
this.method = method;
this.handler = handler;
this.wrapper = wrapper;
}
public abstract Object getParameter(Object parameter, int index);
public abstract boolean canRun(Object context);
public abstract InteractionType getType();
public void run(Object context) {
int parameterCount = method.getParameterCount();
List<Object> parameters = new ArrayList<>();
for (int i = 0; i < parameterCount; i++) {
if (i == 0) {
parameters.add(context);
continue;
}
parameters.add(getParameter(context, i-1));
}
method.setAccessible(true);
try {
method.invoke(handler, parameters);
}catch (Exception ex) {
throw new RuntimeException(ex);
}
}
public Method getMethod() {
return method;
}
}

View File

@ -0,0 +1,33 @@
package net.tomatentum.marinara.registry;
import java.lang.reflect.Method;
import java.util.List;
import net.tomatentum.marinara.handler.InteractionHandler;
import net.tomatentum.marinara.interaction.InteractionType;
import net.tomatentum.marinara.interaction.methods.InteractionMethod;
import net.tomatentum.marinara.wrapper.LibraryWrapper;
public class InteractionRegistry {
private List<InteractionMethod> interactionMethods;
private LibraryWrapper wrapper;
public InteractionRegistry(LibraryWrapper wrapper) {
this.wrapper = wrapper;
wrapper.subscribeInteractions(this::handle);
}
public void addInteractions(InteractionHandler interactionHandler) {
for (Method method : interactionHandler.getClass().getMethods()) {
interactionMethods.add(InteractionMethod.create(method, interactionHandler, wrapper));
}
}
public void handle(Object context) {
interactionMethods.forEach((m) -> {
InteractionType type = wrapper.getInteractionType(context.getClass());
if (m.getType().equals(type))
m.run(context);
});
}
}

View File

@ -0,0 +1,39 @@
package net.tomatentum.marinara.util;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import net.tomatentum.marinara.interaction.commands.annotation.ApplicationCommand;
import net.tomatentum.marinara.interaction.commands.annotation.SubCommand;
public final class ReflectionUtil {
public static <T extends Annotation> boolean isAnnotationPresent(Method method, Class<T> annotationClass) {
if (method.isAnnotationPresent(annotationClass) || method.getDeclaringClass().isAnnotationPresent(annotationClass))
return true;
return false;
}
public static <T extends Annotation> T getAnnotation(Method method, Class<T> annotationClass) {
return method.isAnnotationPresent(annotationClass) ?
method.getAnnotation(annotationClass) :
method.getDeclaringClass().getAnnotation(annotationClass);
}
public static void checkValidCommandMethod(Method method) {
if (method.isAnnotationPresent(ApplicationCommand.class) &&
method.getDeclaringClass().isAnnotationPresent(ApplicationCommand.class)) {
throw new RuntimeException(method.getName() + ": Can't have ApplicationCommand Annotation on Class and Method");
}
if (!isAnnotationPresent(method, ApplicationCommand.class))
throw new RuntimeException(method.getName() + ": Missing ApplicationCommand Annotation on either Class or Method");
if (!(method.isAnnotationPresent(SubCommand.class) &&
isAnnotationPresent(method, ApplicationCommand.class))) {
throw new RuntimeException(method.getName() + ": Missing ApplicationCommand Annotation on either Method or Class");
}
}
}

View File

@ -1,9 +0,0 @@
package net.tomatentum.marinara.wrapper;
public interface LibraryConverter {
public Object toAttachment(Object context, String option);
public Object toChannel(Object context, String option);
public Object toMentionable(Object context, String option);
public Object toRole(Object context, String option);
public Object toUser(Object context, String option);
}

View File

@ -4,7 +4,8 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.function.Consumer; import java.util.function.Consumer;
import net.tomatentum.marinara.command.option.OptionType; import net.tomatentum.marinara.interaction.commands.CommandDefinition;
import net.tomatentum.marinara.interaction.commands.option.OptionType;
import net.tomatentum.marinara.interaction.InteractionType; import net.tomatentum.marinara.interaction.InteractionType;
public abstract class LibraryWrapper { public abstract class LibraryWrapper {
@ -30,7 +31,6 @@ public abstract class LibraryWrapper {
} }
public abstract InteractionType getInteractionType(Class<?> clazz); public abstract InteractionType getInteractionType(Class<?> clazz);
public abstract OptionType getOptionType(Class<?> clazz); public abstract Object convertCommandOption(Object context, OptionType type, String optionName);
public abstract LibraryConverter getConverter(); public abstract CommandDefinition getCommandDefinition(Object context);
}
}