Merge remote-tracking branch 'origin/dev' into wrapper/d4j

This commit is contained in:
2025-02-17 13:06:27 +01:00
21 changed files with 630 additions and 90 deletions

View File

@@ -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 {
}

View File

@@ -0,0 +1,5 @@
package net.tomatentum.marinara.interaction.commands;
public interface ChoiceValueProvider<T> {
T getChoiceValue();
}

View File

@@ -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
}
}

View File

@@ -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))

View File

@@ -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 {
}
}

View File

@@ -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 "";
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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);

View File

@@ -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

View File

@@ -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);
}

View File

@@ -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();
}