Merge remote-tracking branch 'origin/dev' into wrapper/d4j
This commit is contained in:
		| @@ -0,0 +1,12 @@ | ||||
| package net.tomatentum.marinara.interaction.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 AutoComplete { | ||||
|      | ||||
| } | ||||
| @@ -0,0 +1,5 @@ | ||||
| package net.tomatentum.marinara.interaction.commands; | ||||
|  | ||||
| public interface ChoiceValueProvider<T> { | ||||
|     T getChoiceValue(); | ||||
| } | ||||
| @@ -0,0 +1,78 @@ | ||||
| package net.tomatentum.marinara.interaction.commands; | ||||
|  | ||||
| import java.lang.reflect.InvocationTargetException; | ||||
| import java.lang.reflect.Method; | ||||
| import java.lang.reflect.ParameterizedType; | ||||
| import java.lang.reflect.Type; | ||||
| import java.util.ArrayList; | ||||
| import java.util.List; | ||||
| import java.util.Map; | ||||
|  | ||||
| import io.leangen.geantyref.AnnotationFormatException; | ||||
| import io.leangen.geantyref.GenericTypeReflector; | ||||
| import io.leangen.geantyref.TypeFactory; | ||||
| import net.tomatentum.marinara.interaction.commands.annotation.SlashCommandOptionChoice; | ||||
|  | ||||
| public record EnumChoices(Class<? extends Enum<?>> enumClass, ChoiceType type, SlashCommandOptionChoice[] choices) { | ||||
|  | ||||
|     private static Method method; | ||||
|  | ||||
|     static { | ||||
|         try { | ||||
|             method = ChoiceValueProvider.class.getMethod("getChoiceValue"); | ||||
|         } catch (NoSuchMethodException | SecurityException e) { | ||||
|             e.printStackTrace(); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public static EnumChoices of(Class<? extends Enum<?>> enumClass) { | ||||
|         if (!ChoiceValueProvider.class.isAssignableFrom(enumClass)) | ||||
|             throw new IllegalArgumentException("Provided class needs to implement the ChoiceValueProvider interface."); | ||||
|         ChoiceType type = parseChoiceType(enumClass); | ||||
|         SlashCommandOptionChoice[] choices = parseChoices(enumClass, type); | ||||
|         return new EnumChoices(enumClass, type, choices); | ||||
|     } | ||||
|  | ||||
|     private static ChoiceType parseChoiceType(Class<? extends Enum<?>> enumClass) { | ||||
|         ParameterizedType type = (ParameterizedType) GenericTypeReflector.getExactSuperType(enumClass, ChoiceValueProvider.class); | ||||
|         Type typeParam = type.getActualTypeArguments()[0]; | ||||
|  | ||||
|         if (!(typeParam instanceof Class<?>)) | ||||
|             throw new IllegalArgumentException("ChoiceValueProvider need either a String or Number type parameter."); | ||||
|  | ||||
|         if (Long.class.isAssignableFrom((Class<?>) typeParam)) | ||||
|             return ChoiceType.INTEGER; | ||||
|         if (Double.class.isAssignableFrom((Class<?>) typeParam)) | ||||
|             return ChoiceType.DOUBLE; | ||||
|         if (String.class.isAssignableFrom((Class<?>) typeParam)) | ||||
|             return ChoiceType.String; | ||||
|         throw new IllegalArgumentException("ChoiceValueProvider need either a String, Number or Decimal type parameter."); | ||||
|     } | ||||
|  | ||||
|     private static SlashCommandOptionChoice[] parseChoices(Class<? extends Enum<?>> enumClass, ChoiceType type) { | ||||
|         Enum<? extends Enum<?>>[] constants = enumClass.getEnumConstants(); | ||||
|         List<SlashCommandOptionChoice> choices = new ArrayList<>(); | ||||
|         for (Enum<? extends Enum<?>> enumInstance : constants) { | ||||
|             Object value; | ||||
|             try { | ||||
|                 value = method.invoke(enumInstance); | ||||
|                 if (type.equals(ChoiceType.INTEGER)) | ||||
|                     choices.add(TypeFactory.annotation(SlashCommandOptionChoice.class, Map.of("name", enumInstance.name(), "longValue", value))); | ||||
|                 if (type.equals(ChoiceType.DOUBLE)) | ||||
|                     choices.add(TypeFactory.annotation(SlashCommandOptionChoice.class, Map.of("name", enumInstance.name(), "doubleValue", value))); | ||||
|                 if (type.equals(ChoiceType.String)) | ||||
|                     choices.add(TypeFactory.annotation(SlashCommandOptionChoice.class, Map.of("name", enumInstance.name(), "stringValue", value))); | ||||
|             } catch (IllegalAccessException | InvocationTargetException | AnnotationFormatException e) { | ||||
|                 e.printStackTrace(); | ||||
|                 return null; | ||||
|             } | ||||
|         } | ||||
|         return choices.toArray(new SlashCommandOptionChoice[0]); | ||||
|     } | ||||
|  | ||||
|     public static enum ChoiceType { | ||||
|         String, | ||||
|         INTEGER, | ||||
|         DOUBLE | ||||
|     } | ||||
| } | ||||
| @@ -2,8 +2,10 @@ package net.tomatentum.marinara.interaction.commands; | ||||
|  | ||||
| import net.tomatentum.marinara.interaction.commands.annotation.SlashCommand; | ||||
| import net.tomatentum.marinara.interaction.commands.annotation.SlashCommandOption; | ||||
| import net.tomatentum.marinara.interaction.commands.annotation.SlashCommandOptionChoice; | ||||
| import net.tomatentum.marinara.interaction.commands.annotation.SubCommand; | ||||
| import net.tomatentum.marinara.interaction.commands.annotation.SubCommandGroup; | ||||
| import net.tomatentum.marinara.interaction.commands.annotation.SlashCommandOption.PlaceHolderEnum; | ||||
|  | ||||
| public record ExecutableSlashCommandDefinition( | ||||
|     SlashCommand applicationCommand, | ||||
| @@ -11,6 +13,13 @@ public record ExecutableSlashCommandDefinition( | ||||
|     SubCommandGroup subCommandGroup,  | ||||
|     SlashCommandOption[] options) { | ||||
|  | ||||
|     public static SlashCommandOptionChoice[] getActualChoices(SlashCommandOption option) { | ||||
|         SlashCommandOptionChoice[] choices = option.choices(); | ||||
|         if (choices.length <= 0 && !option.choiceEnum().equals(PlaceHolderEnum.class)) | ||||
|             choices = EnumChoices.of(option.choiceEnum()).choices(); | ||||
|         return choices; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public final boolean equals(Object o) { | ||||
|         if (!(o instanceof ExecutableSlashCommandDefinition)) | ||||
|   | ||||
| @@ -14,4 +14,11 @@ public @interface SlashCommandOption { | ||||
|     public String description() default ""; | ||||
|     public SlashCommandOptionType type() default SlashCommandOptionType.STRING; | ||||
|     public boolean required() default false; | ||||
|     public boolean autocomplete() default false; | ||||
|     public SlashCommandOptionChoice[] choices() default {}; | ||||
|     public Class<? extends Enum<?>> choiceEnum() default PlaceHolderEnum.class; | ||||
|  | ||||
|     public static enum PlaceHolderEnum { | ||||
|  | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -0,0 +1,8 @@ | ||||
| package net.tomatentum.marinara.interaction.commands.annotation; | ||||
|  | ||||
| public @interface SlashCommandOptionChoice { | ||||
|     public String name(); | ||||
|     public long longValue() default Long.MAX_VALUE; | ||||
|     public double doubleValue() default Double.MAX_VALUE; | ||||
|     public String stringValue() default ""; | ||||
| } | ||||
| @@ -1,16 +1,26 @@ | ||||
| package net.tomatentum.marinara.interaction.commands.option; | ||||
|  | ||||
| public enum SlashCommandOptionType { | ||||
|     ATTACHMENT, | ||||
|     BOOLEAN, | ||||
|     CHANNEL, | ||||
|     DECIMAL, | ||||
|     LONG, | ||||
|     MENTIONABLE, | ||||
|     ROLE, | ||||
|     STRING, | ||||
|     SUB_COMMAND, | ||||
|     SUB_COMMAND_GROUP, | ||||
|     UNKNOW, | ||||
|     USER | ||||
|     SUB_COMMAND(1), | ||||
|     SUB_COMMAND_GROUP(2), | ||||
|     STRING(3), | ||||
|     INTEGER(4), | ||||
|     BOOLEAN(5), | ||||
|     USER(6), | ||||
|     CHANNEL(7), | ||||
|     ROLE(8), | ||||
|     MENTIONABLE(9), | ||||
|     DOUBLE(10), | ||||
|     ATTACHMENT(11), | ||||
|     UNKNOWN(-1); | ||||
|  | ||||
|     private final int value; | ||||
|  | ||||
|     private SlashCommandOptionType(int value) { | ||||
|         this.value = value; | ||||
|     } | ||||
|  | ||||
|     public int getValue() { | ||||
|         return value; | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -0,0 +1,51 @@ | ||||
| package net.tomatentum.marinara.interaction.methods; | ||||
|  | ||||
| import java.lang.reflect.Method; | ||||
|  | ||||
| import net.tomatentum.marinara.Marinara; | ||||
| import net.tomatentum.marinara.interaction.InteractionHandler; | ||||
| import net.tomatentum.marinara.interaction.InteractionType; | ||||
| import net.tomatentum.marinara.interaction.commands.ExecutableSlashCommandDefinition; | ||||
| import net.tomatentum.marinara.parser.AnnotationParser; | ||||
| import net.tomatentum.marinara.parser.SlashCommandParser; | ||||
|  | ||||
| public class AutoCompleteInteractionMethod extends InteractionMethod { | ||||
|  | ||||
|     private ExecutableSlashCommandDefinition commandDefinition; | ||||
|  | ||||
|     public AutoCompleteInteractionMethod(Method method,  | ||||
|         InteractionHandler handler,  | ||||
|         Marinara marinara | ||||
|         ) { | ||||
|         super(method, handler, marinara); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public AnnotationParser[] getParsers() { | ||||
|         return new AnnotationParser[] {  | ||||
|             new SlashCommandParser(method, (x) -> { this.commandDefinition = x; } )  | ||||
|         }; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public Object getParameter(Object context, int index) { | ||||
|         Class<?> type = getMethod().getParameterTypes()[index+1]; | ||||
|         Object autocompleteOptionValue = marinara.getWrapper().getContextObjectProvider().getAutocompleteFocusedOption(context); | ||||
|         if (autocompleteOptionValue != null) | ||||
|             return autocompleteOptionValue; | ||||
|  | ||||
|         return marinara.getWrapper().getContextObjectProvider().getComponentContextObject(context, type); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public boolean canRun(Object context) { | ||||
|         ExecutableSlashCommandDefinition other = marinara.getWrapper().getCommandDefinition(context); | ||||
|         return commandDefinition.equals(other); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public InteractionType getType() { | ||||
|         return InteractionType.AUTOCOMPLETE; | ||||
|     } | ||||
|      | ||||
| } | ||||
| @@ -24,9 +24,9 @@ public class ButtonInteractionMethod extends InteractionMethod { | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public Object getParameter(Object parameter, int index) { | ||||
|     public Object getParameter(Object context, int index) { | ||||
|         Class<?> type = getMethod().getParameterTypes()[index+1]; | ||||
|         return marinara.getWrapper().getComponentContextObject(parameter, type); | ||||
|         return marinara.getWrapper().getContextObjectProvider().getComponentContextObject(context, type); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
| @@ -38,4 +38,5 @@ public class ButtonInteractionMethod extends InteractionMethod { | ||||
|     public InteractionType getType() { | ||||
|         return InteractionType.BUTTON; | ||||
|     } | ||||
|      | ||||
| } | ||||
|   | ||||
| @@ -13,6 +13,7 @@ import net.tomatentum.marinara.Marinara; | ||||
| import net.tomatentum.marinara.checks.AppliedCheck; | ||||
| import net.tomatentum.marinara.interaction.InteractionHandler; | ||||
| import net.tomatentum.marinara.interaction.InteractionType; | ||||
| import net.tomatentum.marinara.interaction.annotation.AutoComplete; | ||||
| import net.tomatentum.marinara.interaction.annotation.Button; | ||||
| import net.tomatentum.marinara.interaction.commands.annotation.SlashCommand; | ||||
| import net.tomatentum.marinara.interaction.commands.annotation.SubCommand; | ||||
| @@ -24,6 +25,8 @@ import net.tomatentum.marinara.util.ReflectionUtil; | ||||
| public abstract class InteractionMethod { | ||||
|  | ||||
|     public static InteractionMethod create(Method method, InteractionHandler handler, Marinara marinara) { | ||||
|         if (method.isAnnotationPresent(AutoComplete.class)) | ||||
|             return new AutoCompleteInteractionMethod(method, handler, marinara); | ||||
|         if (method.isAnnotationPresent(SlashCommand.class) || method.isAnnotationPresent(SubCommand.class)) | ||||
|             return new SlashCommandInteractionMethod(method, handler, marinara); | ||||
|         if (method.isAnnotationPresent(Button.class)) | ||||
| @@ -59,7 +62,7 @@ public abstract class InteractionMethod { | ||||
|  | ||||
|     public abstract AnnotationParser[] getParsers(); | ||||
|  | ||||
|     public abstract Object getParameter(Object parameter, int index); | ||||
|     public abstract Object getParameter(Object context, int index); | ||||
|  | ||||
|     public abstract boolean canRun(Object context); | ||||
|  | ||||
|   | ||||
| @@ -26,7 +26,7 @@ public class SlashCommandInteractionMethod extends InteractionMethod { | ||||
|  | ||||
|     @Override | ||||
|     public Object getParameter(Object context, int index) { | ||||
|         return marinara.getWrapper().convertCommandOption(context, commandDefinition.options()[index].type(), commandDefinition.options()[index].name()); | ||||
|         return marinara.getWrapper().getContextObjectProvider().convertCommandOption(context, commandDefinition.options()[index].name()); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|   | ||||
| @@ -0,0 +1,11 @@ | ||||
| package net.tomatentum.marinara.wrapper; | ||||
|  | ||||
| public interface ContextObjectProvider { | ||||
|  | ||||
|     public Object convertCommandOption(Object context, String optionName); | ||||
|  | ||||
|     public Object getComponentContextObject(Object context, Class<?> type); | ||||
|     public Object getInteractionContextObject(Object context, Class<?> type); | ||||
|  | ||||
|     public Object getAutocompleteFocusedOption(Object context); | ||||
| } | ||||
| @@ -6,7 +6,6 @@ import java.util.function.Consumer; | ||||
|  | ||||
| import net.tomatentum.marinara.interaction.commands.SlashCommandDefinition; | ||||
| import net.tomatentum.marinara.interaction.commands.ExecutableSlashCommandDefinition; | ||||
| import net.tomatentum.marinara.interaction.commands.option.SlashCommandOptionType; | ||||
| import net.tomatentum.marinara.interaction.InteractionType; | ||||
|  | ||||
| public abstract class LibraryWrapper { | ||||
| @@ -17,7 +16,6 @@ public abstract class LibraryWrapper { | ||||
|         interactionSubscriber = new ArrayList<>(); | ||||
|     } | ||||
|  | ||||
|  | ||||
|     public void handleInteraction(Object context) { | ||||
|         interactionSubscriber.forEach((o) -> o.accept(context)); | ||||
|     } | ||||
| @@ -32,9 +30,10 @@ public abstract class LibraryWrapper { | ||||
|     public abstract InteractionType getInteractionType(Object context); | ||||
|  | ||||
|     public abstract void registerSlashCommands(SlashCommandDefinition[] defs);  | ||||
|     public abstract Object convertCommandOption(Object context, SlashCommandOptionType type, String optionName); | ||||
|     public abstract ExecutableSlashCommandDefinition getCommandDefinition(Object context); | ||||
|  | ||||
|     public abstract String getButtonId(Object context); | ||||
|     public abstract Object getComponentContextObject(Object context, Class<?> type); | ||||
|  | ||||
|     public abstract ContextObjectProvider getContextObjectProvider(); | ||||
|  | ||||
| } | ||||
		Reference in New Issue
	
	Block a user