diff --git a/.gitignore b/.gitignore index d11a53b..1dffc61 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ build .vscode lib/bin wrapper/javacord/bin +wrapper/discord4j/bin diff --git a/lib/src/main/java/net/tomatentum/marinara/interaction/commands/CommandConverter.java b/lib/src/main/java/net/tomatentum/marinara/interaction/commands/CommandConverter.java index fcbfb85..cd90895 100644 --- a/lib/src/main/java/net/tomatentum/marinara/interaction/commands/CommandConverter.java +++ b/lib/src/main/java/net/tomatentum/marinara/interaction/commands/CommandConverter.java @@ -12,7 +12,7 @@ public class CommandConverter { return null; } - public interface Spec { + public static interface Spec { public A convertCommand(SlashCommandDefinition def); public O convertSubCommand(SubCommand def, O[] options); diff --git a/lib/src/main/java/net/tomatentum/marinara/interaction/commands/ExecutableSlashCommandDefinition.java b/lib/src/main/java/net/tomatentum/marinara/interaction/commands/ExecutableSlashCommandDefinition.java deleted file mode 100644 index 480d363..0000000 --- a/lib/src/main/java/net/tomatentum/marinara/interaction/commands/ExecutableSlashCommandDefinition.java +++ /dev/null @@ -1,95 +0,0 @@ -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; -import net.tomatentum.marinara.interaction.commands.choice.EnumChoices; - -public record ExecutableSlashCommandDefinition( - SlashCommand applicationCommand, - SubCommand subCommand, - 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)) - return false; - ExecutableSlashCommandDefinition other = (ExecutableSlashCommandDefinition) o; - boolean equals = false; - - if (this.applicationCommand() != null && other.applicationCommand() != null) - equals = this.applicationCommand().name().equals(other.applicationCommand().name()); - - if (this.subCommandGroup() != null && other.subCommandGroup() != null) - equals = this.subCommandGroup().name().equals(other.subCommandGroup().name()); - - if (this.subCommand() != null && other.subCommand() != null) - equals = this.subCommand().name().equals(other.subCommand().name()); - - return equals; - } - - @Override - public final String toString() { - StringBuilder builder = new StringBuilder(); - builder.append(applicationCommand.name()); - if (subCommandGroup != null && subCommandGroup.name() != null) - builder.append("::").append(subCommandGroup.name()); - if (subCommand != null && subCommand.name() != null) - builder.append("::").append(subCommand.name()); - return builder.toString(); - } - - public boolean isRootCommand() { - return subCommand == null; - } - - public static class Builder { - private SlashCommand applicationCommand; - private SubCommand subCommand; - private SubCommandGroup subCommandGroup; - - public ExecutableSlashCommandDefinition build() { - if (applicationCommand == null) - throw new IllegalArgumentException("applicationCommandName cant be null"); - - return new ExecutableSlashCommandDefinition(applicationCommand, subCommand, subCommandGroup, subCommand != null ? subCommand.options() : applicationCommand.options()); - } - - public void setApplicationCommand(SlashCommand applicationCommand) { - this.applicationCommand = applicationCommand; - } - - public void setSubCommand(SubCommand subCommand) { - this.subCommand = subCommand; - } - - public void setSubCommandGroup(SubCommandGroup subCommandGroup) { - this.subCommandGroup = subCommandGroup; - } - - public SlashCommand getApplicationCommand() { - return applicationCommand; - } - - public SubCommand getSubCommand() { - return subCommand; - } - - public SubCommandGroup getSubCommandGroup() { - return subCommandGroup; - } - - } -} diff --git a/lib/src/main/java/net/tomatentum/marinara/interaction/commands/SlashCommandDefinition.java b/lib/src/main/java/net/tomatentum/marinara/interaction/commands/SlashCommandDefinition.java index 376f7a2..1fb073d 100644 --- a/lib/src/main/java/net/tomatentum/marinara/interaction/commands/SlashCommandDefinition.java +++ b/lib/src/main/java/net/tomatentum/marinara/interaction/commands/SlashCommandDefinition.java @@ -1,100 +1,106 @@ package net.tomatentum.marinara.interaction.commands; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; +import java.util.HashSet; import java.util.List; +import java.util.Set; -import net.tomatentum.marinara.interaction.commands.annotation.SlashCommand; -import net.tomatentum.marinara.interaction.commands.annotation.SubCommand; -import net.tomatentum.marinara.interaction.commands.annotation.SubCommandGroup; +import org.apache.logging.log4j.Logger; + +import net.tomatentum.marinara.interaction.commands.annotation.SlashCommandOption; +import net.tomatentum.marinara.interaction.commands.annotation.SlashCommandOption.PlaceHolderEnum; +import net.tomatentum.marinara.interaction.commands.annotation.SlashCommandOptionChoice; +import net.tomatentum.marinara.interaction.commands.choice.EnumChoices; +import net.tomatentum.marinara.interaction.ident.InteractionIdentifier; +import net.tomatentum.marinara.interaction.ident.RootCommandIdentifier; +import net.tomatentum.marinara.interaction.ident.SlashCommandIdentifier; +import net.tomatentum.marinara.util.LoggerUtil; public class SlashCommandDefinition { - private List executableDefinitons; - private SlashCommand slashCommand; - private boolean isRootCommand; - public SlashCommandDefinition(SlashCommand applicationCommand) { - this.executableDefinitons = new ArrayList<>(); - this.slashCommand = applicationCommand; + 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; } - public SlashCommandDefinition addExecutableCommand(ExecutableSlashCommandDefinition def) { - if (def.applicationCommand() != null) { - if (slashCommand == null) - this.slashCommand = def.applicationCommand(); - if (!this.slashCommand.name().equals(def.applicationCommand().name())) - throw new IllegalArgumentException(def + ": has a non matching Application Command description. Please edit it to equal all other descriptions or remove it to use other definitions descriptions"); - } + private Set entries; + private RootCommandIdentifier rootIdentifier; + private boolean isRootCommand; - if (executableDefinitons.isEmpty()) - this.isRootCommand = def.isRootCommand(); + private Logger logger = LoggerUtil.getLogger(getClass()); - if ((isRootCommand && !def.isRootCommand()) || (!isRootCommand && def.isRootCommand())) { - throw new IllegalArgumentException(def + ": cannot have subcommands and rootcommand definitions together"); + public SlashCommandDefinition(RootCommandIdentifier rootIdentifier) { + this.entries = new HashSet<>(); + this.rootIdentifier = rootIdentifier; + this.isRootCommand = false; + } + + public SlashCommandDefinition addIdentifier(InteractionIdentifier identifier) { + RootCommandIdentifier rootIdentifier = (RootCommandIdentifier) identifier.rootNode(); + + if (!this.rootIdentifier.equals(rootIdentifier)) + throw new IllegalArgumentException("Root Node did not match."); + + if (this.rootIdentifier.description() == null) + this.rootIdentifier = rootIdentifier; + + if (!isRootCommand) + this.isRootCommand = identifier.parent() == null ? true : false; + + if ((isRootCommand && identifier.parent() != null) || (!isRootCommand && identifier.parent() == null)) { + throw new IllegalArgumentException(identifier.toString() + ": cannot have subcommands and rootcommand definitions together"); } - executableDefinitons.add(def); + entries.add(identifier); + this.logger.debug("Added identifer {} to command {}", identifier, rootIdentifier); return this; } - public SubCommandGroup[] getSubCommandGroups() { - List subCommandGroups = Arrays.stream(getExecutableDefinitons()) - .filter((x) -> x.subCommandGroup() != null) - .map((x) -> x.subCommandGroup()) + public SlashCommandIdentifier[] getSubCommandGroups() { + if (isRootCommand) + return null; + + List subCommandGroups = entries().stream() + .filter(x -> x.parent().parent() != null) + .map(x -> x.parent()) .toList(); - HashMap subCommandGroupMap = new HashMap<>(); - subCommandGroups.forEach((x) -> { - SubCommandGroup current = subCommandGroupMap.get(x.name()); - if (current == null || (current.description().isBlank() && !x.description().isBlank())) - subCommandGroupMap.put(x.name(), x); - }); - - return subCommandGroupMap.values().toArray(SubCommandGroup[]::new); + return InteractionIdentifier.distinct(subCommandGroups).toArray(SlashCommandIdentifier[]::new); } - public SubCommand[] getSubCommands() { - List subCommands; - subCommands = Arrays.stream(getExecutableDefinitons()) - .filter((x) -> x.subCommandGroup() == null && x.subCommand() != null) - .map((x) -> x.subCommand()) - .toList(); - - - HashMap subCommandMap = new HashMap<>(); - subCommands.forEach((x) -> { - SubCommand current = subCommandMap.get(x.name()); - if (current == null || (current.description().isBlank() && !x.description().isBlank())) - subCommandMap.put(x.name(), x); - }); - - return subCommandMap.values().toArray(SubCommand[]::new); + public SlashCommandIdentifier[] getSubCommands() { + if (isRootCommand) + return null; + return InteractionIdentifier.distinct(entries.stream().toList()).toArray(SlashCommandIdentifier[]::new); } - public SubCommand[] getSubCommands(String groupName) { - List subCommands; - subCommands = Arrays.stream(getExecutableDefinitons()) - .filter((x) -> x.subCommandGroup().name().equals(groupName) && x.subCommand() != null) - .map((x) -> x.subCommand()) - .toList(); - - HashMap subCommandMap = new HashMap<>(); - subCommands.forEach((x) -> { - SubCommand current = subCommandMap.get(x.name()); - if (current == null || (current.description().isBlank() && !x.description().isBlank())) - subCommandMap.put(x.name(), x); - }); + public SlashCommandIdentifier[] getSubCommands(String groupName) { + if (isRootCommand) + return null; - return subCommandMap.values().toArray(SubCommand[]::new); + List subCommands = entries().stream() + .filter(x -> x.parent().parent() != null && x.parent().name().equals(groupName)) + .map(x -> x.parent().parent()) + .toList(); + + return InteractionIdentifier.distinct(subCommands).toArray(SlashCommandIdentifier[]::new); } - public SlashCommand getSlashCommand() { - return slashCommand; + @Override + public boolean equals(Object obj) { + if (!(obj instanceof SlashCommandDefinition)) + return false; + SlashCommandDefinition other = (SlashCommandDefinition) obj; + return this.rootIdentifier().equals(other.rootIdentifier()); } - public ExecutableSlashCommandDefinition[] getExecutableDefinitons() { - return executableDefinitons.toArray(new ExecutableSlashCommandDefinition[0]); + public Set entries() { + return this.entries; + } + + public RootCommandIdentifier rootIdentifier() { + return rootIdentifier; } public boolean isRootCommand() { diff --git a/lib/src/main/java/net/tomatentum/marinara/interaction/ident/InteractionIdentifier.java b/lib/src/main/java/net/tomatentum/marinara/interaction/ident/InteractionIdentifier.java new file mode 100644 index 0000000..14a6bfd --- /dev/null +++ b/lib/src/main/java/net/tomatentum/marinara/interaction/ident/InteractionIdentifier.java @@ -0,0 +1,158 @@ +package net.tomatentum.marinara.interaction.ident; + +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Objects; + +import net.tomatentum.marinara.interaction.InteractionType; + +public class InteractionIdentifier { + + public static InteractionIdentifier.Builder builder() { + return new InteractionIdentifier.Builder(); + } + + public static RootCommandIdentifier.Builder rootBuilder() { + return new RootCommandIdentifier.Builder(); + } + + public static SlashCommandIdentifier.Builder slashBuilder() { + return new SlashCommandIdentifier.Builder(); + } + + public static InteractionIdentifier createHierarchy(InteractionType type, String... names) { + InteractionIdentifier last = null; + for (String string : names) { + last = builder().name(string).type(type).parent(last).build(); + } + return last; + } + + public static void tryAddDescriptions(InteractionIdentifier receiver, InteractionIdentifier provider) { + if (receiver == null || provider == null) + return; + + if (receiver.description().isBlank()) + receiver.description = provider.description(); + tryAddDescriptions(receiver.parent(), provider.parent()); + } + + /* + * TODO: Might not be the best solution. Propagating to future + * returns only one Identifier per name and takes the first present description + */ + public static Collection distinct(List identifiers) { + HashMap distinctIdentifiers = new HashMap<>(); + identifiers.forEach((x) -> { + InteractionIdentifier current = distinctIdentifiers.get(x.name()); + if (current == null || (current.description().isBlank() && !x.description().isBlank())) + distinctIdentifiers.put(x.name(), x); + }); + return distinctIdentifiers.values(); + } + + private InteractionIdentifier parent; + private String name; + private String description; + private InteractionType type; + + InteractionIdentifier(InteractionIdentifier parent, String name, String description, InteractionType type) { + this.parent = parent; + this.name = name; + this.description = description; + this.type = type; + } + + public InteractionIdentifier rootNode() { return rootNode(this); } + + private InteractionIdentifier rootNode(InteractionIdentifier identifier) { + if (identifier.parent() == null) + return identifier; + return rootNode(identifier.parent()); + } + + public String name() { + return name; + } + + public String description() { + return description; + } + + public InteractionIdentifier parent() { + return parent; + } + + public InteractionType type() { + return type; + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof InteractionIdentifier)) + return false; + InteractionIdentifier ident = (InteractionIdentifier) obj; + if (!type().equals(ident.type())) + return false; + if (!name().equals(ident.name())) + return false; + return Objects.equals(ident, obj); + } + + @Override + public String toString() { + if (parent() == null) + return name(); + return "{}.{}".formatted(name(), parent().toString()); + } + + public static class Builder { + private InteractionIdentifier parent; + private String name; + private String description; + private InteractionType type; + + public InteractionIdentifier parent() { + return parent; + } + + public Builder parent(InteractionIdentifier parent) { + this.parent = parent; + return this; + } + + public String name() { + return name; + } + + public Builder name(String name) { + this.name = name; + return this; + } + + public String description() { + return description; + } + + public Builder description(String description) { + this.description = description; + return this; + } + + public InteractionType type() { + return type; + } + + public Builder type(InteractionType type) { + this.type = type; + return this; + } + + public InteractionIdentifier build() { + return new InteractionIdentifier(parent, name, description, type); + } + + } + +} diff --git a/lib/src/main/java/net/tomatentum/marinara/interaction/ident/RootCommandIdentifier.java b/lib/src/main/java/net/tomatentum/marinara/interaction/ident/RootCommandIdentifier.java new file mode 100644 index 0000000..d32a6a7 --- /dev/null +++ b/lib/src/main/java/net/tomatentum/marinara/interaction/ident/RootCommandIdentifier.java @@ -0,0 +1,93 @@ +package net.tomatentum.marinara.interaction.ident; + +import net.tomatentum.marinara.interaction.commands.annotation.SlashCommandOption; + +public class RootCommandIdentifier extends SlashCommandIdentifier { + + private long[] serverIds; + + public RootCommandIdentifier( + InteractionIdentifier parent, + String name, + String description, + SlashCommandOption[] options, + boolean isAutocomplete, + long[] serverIds) { + super(parent, name, description, options, isAutocomplete); + this.serverIds = serverIds; + } + + public long[] serverIds() { + return serverIds; + } + + public static class Builder { + private InteractionIdentifier parent; + private String name; + private String description; + private SlashCommandOption[] options; + private boolean isAutocomplete = false; + private long[] serverIds; + + + public InteractionIdentifier parent() { + return parent; + } + + public Builder parent(InteractionIdentifier parent) { + this.parent = parent; + return this; + } + + public String name() { + return name; + } + + public Builder name(String name) { + this.name = name; + return this; + } + + public String description() { + return this.description; + } + + public Builder description(String description) { + this.description = description; + return this; + } + + public SlashCommandOption[] options() { + return this.options; + } + + public Builder options(SlashCommandOption[] options) { + this.options = options; + return this; + } + + public boolean autocomplete() { + return this.isAutocomplete; + } + + public Builder autocomplete(boolean isAutocomplete) { + this.isAutocomplete = isAutocomplete; + return this; + } + + public long[] serverIds() { + return this.serverIds; + } + + public Builder serverIds(long[] serverIds) { + this.serverIds = serverIds; + return this; + } + + public SlashCommandIdentifier build() { + return new RootCommandIdentifier(parent, name, description, options, isAutocomplete, serverIds); + } + + } + +} diff --git a/lib/src/main/java/net/tomatentum/marinara/interaction/ident/SlashCommandIdentifier.java b/lib/src/main/java/net/tomatentum/marinara/interaction/ident/SlashCommandIdentifier.java new file mode 100644 index 0000000..8ecad75 --- /dev/null +++ b/lib/src/main/java/net/tomatentum/marinara/interaction/ident/SlashCommandIdentifier.java @@ -0,0 +1,83 @@ +package net.tomatentum.marinara.interaction.ident; + +import net.tomatentum.marinara.interaction.InteractionType; +import net.tomatentum.marinara.interaction.commands.annotation.SlashCommandOption; + +public class SlashCommandIdentifier extends InteractionIdentifier { + + private SlashCommandOption[] options; + + protected SlashCommandIdentifier( + InteractionIdentifier parent, + String name, + String description, + SlashCommandOption[] options, + boolean isAutocomplete + ) { + super(parent, name, description, isAutocomplete ? InteractionType.AUTOCOMPLETE : InteractionType.COMMAND); + this.options = options; + } + + public SlashCommandOption[] options() { + return this.options; + } + + public static class Builder { + private InteractionIdentifier parent; + private String name; + private String description; + private SlashCommandOption[] options; + private boolean isAutocomplete = false; + + public InteractionIdentifier parent() { + return parent; + } + + public Builder parent(InteractionIdentifier parent) { + this.parent = parent; + return this; + } + + public String name() { + return name; + } + + public Builder name(String name) { + this.name = name; + return this; + } + + public String description() { + return this.description; + } + + public Builder description(String description) { + this.description = description; + return this; + } + + public SlashCommandOption[] options() { + return this.options; + } + + public Builder options(SlashCommandOption[] options) { + this.options = options; + return this; + } + + public boolean autocomplete() { + return this.isAutocomplete; + } + + public Builder autocomplete(boolean isAutocomplete) { + this.isAutocomplete = isAutocomplete; + return this; + } + + public SlashCommandIdentifier build() { + return new SlashCommandIdentifier(parent, name, description, options, isAutocomplete); + } + + } + +} diff --git a/lib/src/main/java/net/tomatentum/marinara/interaction/methods/AutoCompleteInteractionMethod.java b/lib/src/main/java/net/tomatentum/marinara/interaction/methods/AutoCompleteInteractionMethod.java index ffed507..fc08e4d 100644 --- a/lib/src/main/java/net/tomatentum/marinara/interaction/methods/AutoCompleteInteractionMethod.java +++ b/lib/src/main/java/net/tomatentum/marinara/interaction/methods/AutoCompleteInteractionMethod.java @@ -4,14 +4,13 @@ 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.interaction.ident.InteractionIdentifier; import net.tomatentum.marinara.parser.AnnotationParser; import net.tomatentum.marinara.parser.SlashCommandParser; public class AutoCompleteInteractionMethod extends InteractionMethod { - private ExecutableSlashCommandDefinition commandDefinition; + private InteractionIdentifier interactionIdentifier; public AutoCompleteInteractionMethod(Method method, InteractionHandler handler, @@ -21,15 +20,15 @@ public class AutoCompleteInteractionMethod extends InteractionMethod { } @Override - public AnnotationParser[] getParsers() { + public AnnotationParser[] parsers() { return new AnnotationParser[] { - new SlashCommandParser(method, (x) -> { this.commandDefinition = x; } ) + new SlashCommandParser(method, true, (x) -> { this.interactionIdentifier = x; } ) }; } @Override public Object getParameter(Object context, int index) { - Class type = getMethod().getParameterTypes()[index+1]; + Class type = method().getParameterTypes()[index+1]; Object autocompleteOptionValue = marinara.getWrapper().getContextObjectProvider().getAutocompleteFocusedOption(context); if (autocompleteOptionValue != null) return autocompleteOptionValue; @@ -38,14 +37,8 @@ public class AutoCompleteInteractionMethod extends InteractionMethod { } @Override - public boolean canRun(Object context) { - ExecutableSlashCommandDefinition other = marinara.getWrapper().getCommandDefinition(context); - return commandDefinition.equals(other); - } - - @Override - public InteractionType getType() { - return InteractionType.AUTOCOMPLETE; + public InteractionIdentifier identifier() { + return interactionIdentifier; } } diff --git a/lib/src/main/java/net/tomatentum/marinara/interaction/methods/ButtonInteractionMethod.java b/lib/src/main/java/net/tomatentum/marinara/interaction/methods/ButtonInteractionMethod.java index fe039ac..ec011a4 100644 --- a/lib/src/main/java/net/tomatentum/marinara/interaction/methods/ButtonInteractionMethod.java +++ b/lib/src/main/java/net/tomatentum/marinara/interaction/methods/ButtonInteractionMethod.java @@ -5,6 +5,7 @@ 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.ident.InteractionIdentifier; import net.tomatentum.marinara.parser.AnnotationParser; import net.tomatentum.marinara.parser.ButtonParser; @@ -17,7 +18,7 @@ public class ButtonInteractionMethod extends InteractionMethod { } @Override - public AnnotationParser[] getParsers() { + public AnnotationParser[] parsers() { return new AnnotationParser[] { new ButtonParser(method, (x) -> { this.customId = x; } ) }; @@ -25,18 +26,17 @@ public class ButtonInteractionMethod extends InteractionMethod { @Override public Object getParameter(Object context, int index) { - Class type = getMethod().getParameterTypes()[index+1]; + Class type = method().getParameterTypes()[index+1]; return marinara.getWrapper().getContextObjectProvider().getComponentContextObject(context, type); } @Override - public boolean canRun(Object context) { - return marinara.getWrapper().getButtonId(context).equals(customId); + public InteractionIdentifier identifier() { + return InteractionIdentifier.builder() + .name(customId) + .description("Button") + .type(InteractionType.BUTTON) + .build(); } - @Override - public InteractionType getType() { - return InteractionType.BUTTON; - } - } diff --git a/lib/src/main/java/net/tomatentum/marinara/interaction/methods/InteractionMethod.java b/lib/src/main/java/net/tomatentum/marinara/interaction/methods/InteractionMethod.java index ddc3618..09d7c61 100644 --- a/lib/src/main/java/net/tomatentum/marinara/interaction/methods/InteractionMethod.java +++ b/lib/src/main/java/net/tomatentum/marinara/interaction/methods/InteractionMethod.java @@ -12,11 +12,11 @@ import org.apache.logging.log4j.Logger; 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; +import net.tomatentum.marinara.interaction.ident.InteractionIdentifier; import net.tomatentum.marinara.parser.AnnotationParser; import net.tomatentum.marinara.parser.InteractionCheckParser; import net.tomatentum.marinara.util.LoggerUtil; @@ -42,7 +42,8 @@ public abstract class InteractionMethod { private Logger logger = LoggerUtil.getLogger(getClass()); - protected InteractionMethod(Method method, + protected InteractionMethod( + Method method, InteractionHandler handler, Marinara marinara ) { @@ -52,7 +53,7 @@ public abstract class InteractionMethod { this.method = method; this.handler = handler; this.marinara = marinara; - this.parsers = new ArrayList<>(Arrays.asList(getParsers())); + this.parsers = new ArrayList<>(Arrays.asList(parsers())); this.appliedChecks = new ArrayList<>(); parsers.add(new InteractionCheckParser(method, appliedChecks::add, marinara.getCheckRegistry())); @@ -60,14 +61,6 @@ public abstract class InteractionMethod { parsers.stream().forEach(AnnotationParser::parse); } - public abstract AnnotationParser[] getParsers(); - - public abstract Object getParameter(Object context, int index); - - public abstract boolean canRun(Object context); - - public abstract InteractionType getType(); - public void run(Object context) { if (this.appliedChecks.stream().filter(x -> !x.pre(context)).count() > 0) return; @@ -82,7 +75,13 @@ public abstract class InteractionMethod { this.appliedChecks.forEach(x -> x.post(context)); } - public Method getMethod() { + public abstract AnnotationParser[] parsers(); + + public abstract Object getParameter(Object context, int index); + + public abstract InteractionIdentifier identifier(); + + public Method method() { return method; } diff --git a/lib/src/main/java/net/tomatentum/marinara/interaction/methods/SlashCommandInteractionMethod.java b/lib/src/main/java/net/tomatentum/marinara/interaction/methods/SlashCommandInteractionMethod.java index 2f5faf4..d89d709 100644 --- a/lib/src/main/java/net/tomatentum/marinara/interaction/methods/SlashCommandInteractionMethod.java +++ b/lib/src/main/java/net/tomatentum/marinara/interaction/methods/SlashCommandInteractionMethod.java @@ -4,48 +4,34 @@ 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.interaction.ident.InteractionIdentifier; +import net.tomatentum.marinara.interaction.ident.SlashCommandIdentifier; import net.tomatentum.marinara.parser.AnnotationParser; import net.tomatentum.marinara.parser.SlashCommandParser; public class SlashCommandInteractionMethod extends InteractionMethod { - private ExecutableSlashCommandDefinition commandDefinition; + private SlashCommandIdentifier interactionIdentifier; SlashCommandInteractionMethod(Method method, InteractionHandler handler, Marinara marinara) { super(method, handler, marinara); } @Override - public AnnotationParser[] getParsers() { + public AnnotationParser[] parsers() { return new AnnotationParser[] { - new SlashCommandParser(method, (x) -> { this.commandDefinition = x; } ) + new SlashCommandParser(method, false, (x) -> { this.interactionIdentifier = x; } ) }; } @Override public Object getParameter(Object context, int index) { - return marinara.getWrapper().getContextObjectProvider().convertCommandOption(context, commandDefinition.options()[index].name()); + return marinara.getWrapper().getContextObjectProvider().convertCommandOption(context, interactionIdentifier.options()[index].name()); } @Override - public boolean canRun(Object context) { - ExecutableSlashCommandDefinition other = marinara.getWrapper().getCommandDefinition(context); - return commandDefinition.equals(other); - } - - @Override - public InteractionType getType() { - return InteractionType.COMMAND; - } - - public ExecutableSlashCommandDefinition getCommandDefinition() { - return commandDefinition; - } - - public void setCommandDefinition(ExecutableSlashCommandDefinition commandDefinition) { - this.commandDefinition = commandDefinition; + public InteractionIdentifier identifier() { + return interactionIdentifier; } } diff --git a/lib/src/main/java/net/tomatentum/marinara/parser/SlashCommandParser.java b/lib/src/main/java/net/tomatentum/marinara/parser/SlashCommandParser.java index cf2a244..0cd7072 100644 --- a/lib/src/main/java/net/tomatentum/marinara/parser/SlashCommandParser.java +++ b/lib/src/main/java/net/tomatentum/marinara/parser/SlashCommandParser.java @@ -5,22 +5,26 @@ import java.util.function.Consumer; import org.apache.logging.log4j.Logger; -import net.tomatentum.marinara.interaction.commands.ExecutableSlashCommandDefinition; +import net.tomatentum.marinara.interaction.InteractionType; import net.tomatentum.marinara.interaction.commands.annotation.SlashCommand; import net.tomatentum.marinara.interaction.commands.annotation.SubCommand; import net.tomatentum.marinara.interaction.commands.annotation.SubCommandGroup; +import net.tomatentum.marinara.interaction.ident.InteractionIdentifier; +import net.tomatentum.marinara.interaction.ident.SlashCommandIdentifier; import net.tomatentum.marinara.util.LoggerUtil; import net.tomatentum.marinara.util.ReflectionUtil; public class SlashCommandParser implements AnnotationParser { private Method method; - private Consumer consumer; + private boolean isAutoComplete; + private Consumer consumer; private Logger logger = LoggerUtil.getLogger(getClass()); - public SlashCommandParser(Method method, Consumer consumer) { + public SlashCommandParser(Method method, boolean isAutoComplete, Consumer consumer) { this.method = method; + this.isAutoComplete = isAutoComplete; this.consumer = consumer; } @@ -29,23 +33,36 @@ public class SlashCommandParser implements AnnotationParser { this.checkValidCommandMethod(method); SlashCommand cmd = ReflectionUtil.getAnnotation(method, SlashCommand.class); - ExecutableSlashCommandDefinition.Builder builder = new ExecutableSlashCommandDefinition.Builder(); - builder.setApplicationCommand(cmd); + InteractionIdentifier lastIdentifier = InteractionIdentifier.rootBuilder() + .name(cmd.name()) + .description(cmd.description()) + .options(cmd.options()) + .autocomplete(isAutoComplete) + .serverIds(cmd.serverIds()) + .build(); if (ReflectionUtil.isAnnotationPresent(method, SubCommandGroup.class)) { SubCommandGroup cmdGroup = ReflectionUtil.getAnnotation(method, SubCommandGroup.class); - builder.setSubCommandGroup(cmdGroup); + lastIdentifier = InteractionIdentifier.builder() + .name(cmdGroup.name()) + .description(cmdGroup.description()) + .type(isAutoComplete ? InteractionType.AUTOCOMPLETE : InteractionType.COMMAND) + .parent(lastIdentifier) + .build(); } if (ReflectionUtil.isAnnotationPresent(method, SubCommand.class)) { SubCommand subCmd = ReflectionUtil.getAnnotation(method, SubCommand.class); - builder.setSubCommand(subCmd); + lastIdentifier = InteractionIdentifier.slashBuilder() + .name(subCmd.name()) + .description(subCmd.description()) + .options(subCmd.options()) + .autocomplete(isAutoComplete) + .build(); } - ExecutableSlashCommandDefinition def = builder.build(); - - logger.trace("Parsed using SlashCommandParser for method {} with the result:\n{}", ReflectionUtil.getFullMethodName(method), def.toString()); - consumer.accept(builder.build()); + logger.trace("Parsed using SlashCommandParser for method {} with the result:\n{}", ReflectionUtil.getFullMethodName(method), lastIdentifier.toString()); + consumer.accept((SlashCommandIdentifier) lastIdentifier); } @Override diff --git a/lib/src/main/java/net/tomatentum/marinara/registry/InteractionEntry.java b/lib/src/main/java/net/tomatentum/marinara/registry/InteractionEntry.java new file mode 100644 index 0000000..6e2735b --- /dev/null +++ b/lib/src/main/java/net/tomatentum/marinara/registry/InteractionEntry.java @@ -0,0 +1,65 @@ +package net.tomatentum.marinara.registry; + +import java.util.HashSet; +import java.util.Set; + +import org.apache.logging.log4j.Logger; + +import net.tomatentum.marinara.interaction.InteractionType; +import net.tomatentum.marinara.interaction.ident.InteractionIdentifier; +import net.tomatentum.marinara.interaction.methods.InteractionMethod; +import net.tomatentum.marinara.util.LoggerUtil; + +public class InteractionEntry { + private InteractionIdentifier identifier; + private Set methods; + + private Logger logger = LoggerUtil.getLogger(getClass()); + + public InteractionEntry(InteractionIdentifier identifier) { + this.identifier = identifier; + this.methods = new HashSet<>(); + } + + public InteractionEntry addMethod(InteractionMethod method) { + if (!method.identifier().equals(this.identifier)) + throw new IllegalArgumentException("Method's identifier did not match the entry's identifier"); + + this.methods.add(method); + InteractionIdentifier.tryAddDescriptions(identifier, method.identifier()); + return this; + } + + public void runAll(Object context) { + this.methods.stream().forEach(x -> { + logger.debug("Running Method {} from {} with context {}", x.toString(), this.toString(), context.toString()); + x.run(context); + }); + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof InteractionEntry)) + return false; + InteractionEntry other = (InteractionEntry) obj; + return other.identifier().equals(identifier()); + } + + @Override + public String toString() { + return "InteractionEntry(%s)".formatted(identifier().toString()); + } + + public InteractionType type() { + return identifier().type(); + } + + public InteractionIdentifier identifier() { + return identifier; + } + + public Set methods() { + return methods; + } + +} diff --git a/lib/src/main/java/net/tomatentum/marinara/registry/InteractionRegistry.java b/lib/src/main/java/net/tomatentum/marinara/registry/InteractionRegistry.java index 27a2152..59d01b7 100644 --- a/lib/src/main/java/net/tomatentum/marinara/registry/InteractionRegistry.java +++ b/lib/src/main/java/net/tomatentum/marinara/registry/InteractionRegistry.java @@ -2,8 +2,10 @@ package net.tomatentum.marinara.registry; import java.lang.reflect.Method; import java.util.ArrayList; +import java.util.HashSet; import java.util.List; import java.util.Optional; +import java.util.Set; import org.apache.logging.log4j.Logger; @@ -11,28 +13,36 @@ import net.tomatentum.marinara.Marinara; import net.tomatentum.marinara.interaction.InteractionHandler; import net.tomatentum.marinara.interaction.InteractionType; import net.tomatentum.marinara.interaction.commands.SlashCommandDefinition; -import net.tomatentum.marinara.interaction.commands.ExecutableSlashCommandDefinition; -import net.tomatentum.marinara.interaction.methods.SlashCommandInteractionMethod; +import net.tomatentum.marinara.interaction.ident.RootCommandIdentifier; +import net.tomatentum.marinara.interaction.ident.SlashCommandIdentifier; import net.tomatentum.marinara.util.LoggerUtil; +import net.tomatentum.marinara.wrapper.LibraryWrapper; import net.tomatentum.marinara.interaction.methods.InteractionMethod; public class InteractionRegistry { private Logger logger = LoggerUtil.getLogger(getClass()); - private List interactionMethods; + private Set interactions; private Marinara marinara; public InteractionRegistry(Marinara marinara) { - this.interactionMethods = new ArrayList<>(); + this.interactions = new HashSet<>(); this.marinara = marinara; marinara.getWrapper().subscribeInteractions(this::handle); } + /* + * TODO: Maybe relocate InteractionEntry checking to another class with description merging. + */ public void addInteractions(InteractionHandler interactionHandler) { for (Method method : interactionHandler.getClass().getMethods()) { InteractionMethod iMethod = InteractionMethod.create(method, interactionHandler, marinara); if (iMethod != null) { - this.interactionMethods.add(iMethod); - logger.debug("Added {} method from {}", iMethod.getMethod().getName(), interactionHandler.getClass().getSimpleName()); + Optional entry = this.interactions.stream().filter(iMethod::equals).findFirst(); + if (entry.isEmpty()) { + interactions.add(new InteractionEntry(iMethod.identifier()).addMethod(iMethod)); + }else + entry.get().addMethod(iMethod); + logger.debug("Added {} method from {}", iMethod.method().getName(), interactionHandler.getClass().getSimpleName()); } } logger.info("Added all Interactions from {}", interactionHandler.getClass().getSimpleName()); @@ -40,25 +50,22 @@ public class InteractionRegistry { public void registerCommands() { List defs = new ArrayList<>(); - List execDefs = interactionMethods.stream() - .filter((x) -> x.getClass().isAssignableFrom(SlashCommandInteractionMethod.class)) - .map((x) -> ((SlashCommandInteractionMethod)x).getCommandDefinition()) + List slashIdentifiers = interactions.stream() + .filter((x) -> x.type().equals(InteractionType.COMMAND)) + .map((x) -> (SlashCommandIdentifier)x.identifier()) .toList(); - execDefs.forEach((def) -> { + slashIdentifiers.forEach((ident) -> { Optional appDef = defs.stream() - .filter((x) -> x.getSlashCommand().equals(def.applicationCommand())) + .filter((x) -> x.rootIdentifier().equals(ident.rootNode())) .findFirst(); - if (appDef.isPresent()) - appDef.get().addExecutableCommand(def); - else - defs.add(new SlashCommandDefinition(def.applicationCommand()).addExecutableCommand(def)); - logger.debug("Added Executable Command {}{}{} for registration", - def.applicationCommand().name(), - def.subCommandGroup() == null ? "" : "." + def.subCommandGroup().name(), - def.subCommand() == null ? "" : "." + def.subCommand().name() - ); + if (appDef.isPresent()) + appDef.get().addIdentifier(ident); + else + defs.add( + new SlashCommandDefinition((RootCommandIdentifier) ident.rootNode()) + .addIdentifier(ident)); }); marinara.getWrapper().registerSlashCommands(defs.toArray(SlashCommandDefinition[]::new)); @@ -66,12 +73,12 @@ public class InteractionRegistry { } public void handle(Object context) { - InteractionType type = marinara.getWrapper().getInteractionType(context); logger.debug("Received {} interaction ", context); - interactionMethods.forEach((m) -> { - if (m.getType().equals(type) && m.canRun(context)) { - logger.info("Running {} interaction using {}\ncontext: {}", type, m.getMethod().toString(), context.toString()); - m.run(context); + LibraryWrapper wrapper = marinara.getWrapper(); + interactions.forEach((e) -> { + if (wrapper.getInteractionIdentifier(context).equals(e.identifier())) { + logger.info("Running {} interaction using {}\ncontext: {}", e.type(), e.toString(), context.toString()); + e.runAll(context); } }); } diff --git a/lib/src/main/java/net/tomatentum/marinara/wrapper/LibraryWrapper.java b/lib/src/main/java/net/tomatentum/marinara/wrapper/LibraryWrapper.java index 7bf932a..0a4ede7 100644 --- a/lib/src/main/java/net/tomatentum/marinara/wrapper/LibraryWrapper.java +++ b/lib/src/main/java/net/tomatentum/marinara/wrapper/LibraryWrapper.java @@ -5,8 +5,7 @@ import java.util.List; import java.util.function.Consumer; import net.tomatentum.marinara.interaction.commands.SlashCommandDefinition; -import net.tomatentum.marinara.interaction.commands.ExecutableSlashCommandDefinition; -import net.tomatentum.marinara.interaction.InteractionType; +import net.tomatentum.marinara.interaction.ident.InteractionIdentifier; public abstract class LibraryWrapper { @@ -27,12 +26,8 @@ public abstract class LibraryWrapper { interactionSubscriber.remove(consumer); } - public abstract InteractionType getInteractionType(Object context); - public abstract void registerSlashCommands(SlashCommandDefinition[] defs); - public abstract ExecutableSlashCommandDefinition getCommandDefinition(Object context); - - public abstract String getButtonId(Object context); + public abstract InteractionIdentifier getInteractionIdentifier(Object context); public abstract ContextObjectProvider getContextObjectProvider(); diff --git a/wrapper/discord4j/src/main/java/net/tomatentum/marinara/wrapper/discord4j/Discord4JWrapper.java b/wrapper/discord4j/src/main/java/net/tomatentum/marinara/wrapper/discord4j/Discord4JWrapper.java index b5f7f73..7c046b3 100644 --- a/wrapper/discord4j/src/main/java/net/tomatentum/marinara/wrapper/discord4j/Discord4JWrapper.java +++ b/wrapper/discord4j/src/main/java/net/tomatentum/marinara/wrapper/discord4j/Discord4JWrapper.java @@ -4,7 +4,6 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; -import java.util.Map; import java.util.function.Function; import org.apache.logging.log4j.Logger; @@ -20,16 +19,13 @@ import discord4j.discordjson.json.ApplicationCommandOptionChoiceData; import discord4j.discordjson.json.ApplicationCommandOptionData; import discord4j.discordjson.json.ApplicationCommandRequest; -import io.leangen.geantyref.AnnotationFormatException; -import io.leangen.geantyref.TypeFactory; import net.tomatentum.marinara.interaction.InteractionType; -import net.tomatentum.marinara.interaction.commands.ExecutableSlashCommandDefinition; import net.tomatentum.marinara.interaction.commands.SlashCommandDefinition; -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.ident.InteractionIdentifier; +import net.tomatentum.marinara.interaction.ident.RootCommandIdentifier; +import net.tomatentum.marinara.interaction.ident.SlashCommandIdentifier; import net.tomatentum.marinara.util.LoggerUtil; import net.tomatentum.marinara.wrapper.ContextObjectProvider; import net.tomatentum.marinara.wrapper.LibraryWrapper; @@ -63,18 +59,6 @@ public class Discord4JWrapper extends LibraryWrapper { logger.info("Discord4J wrapper loaded!"); } - @Override - public InteractionType getInteractionType(Object context) { - if (ChatInputAutoCompleteEvent.class.isAssignableFrom(context.getClass())) - return InteractionType.AUTOCOMPLETE; - if (ChatInputInteractionEvent.class.isAssignableFrom(context.getClass())) - return InteractionType.COMMAND; - if (ButtonInteractionEvent.class.isAssignableFrom(context.getClass())) - return InteractionType.BUTTON; - - return null; - } - @Override public void registerSlashCommands(SlashCommandDefinition[] defs) { HashMap> serverCommands = new HashMap<>(); @@ -83,8 +67,8 @@ public class Discord4JWrapper extends LibraryWrapper { for (SlashCommandDefinition slashCommandDefinition : defs) { ApplicationCommandRequest request = convertSlashCommand(slashCommandDefinition); - if (slashCommandDefinition.getSlashCommand().serverIds().length > 0) { - for (long serverId : slashCommandDefinition.getSlashCommand().serverIds()) { + if (slashCommandDefinition.rootIdentifier().serverIds().length > 0) { + for (long serverId : slashCommandDefinition.rootIdentifier().serverIds()) { serverCommands.putIfAbsent(serverId, new ArrayList<>()); serverCommands.get(serverId).add(request); } @@ -99,9 +83,16 @@ public class Discord4JWrapper extends LibraryWrapper { } @Override - public ExecutableSlashCommandDefinition getCommandDefinition(Object context) { + public InteractionIdentifier getInteractionIdentifier(Object context) { + + if (context instanceof ButtonInteractionEvent) { + ButtonInteractionEvent interaction = (ButtonInteractionEvent) context; + return InteractionIdentifier.builder().name(interaction.getCustomId()).type(InteractionType.BUTTON).build(); + } + List options; String commandName; + boolean isAutocomplete = false; if (context instanceof ChatInputInteractionEvent) { ChatInputInteractionEvent interaction = (ChatInputInteractionEvent) context; @@ -111,30 +102,35 @@ public class Discord4JWrapper extends LibraryWrapper { ChatInputAutoCompleteEvent interaction = (ChatInputAutoCompleteEvent) context; options = SUB_FILTER.apply(interaction.getOptions()); commandName = interaction.getCommandName(); + isAutocomplete = true; }else return null; - ExecutableSlashCommandDefinition.Builder builder = new ExecutableSlashCommandDefinition.Builder(); + InteractionIdentifier last = InteractionIdentifier.slashBuilder().name(commandName).autocomplete(isAutocomplete).build(); - try { - builder.setApplicationCommand(TypeFactory.annotation(SlashCommand.class, Map.of("name", commandName))); - if (!options.isEmpty()) { - if (!ARG_FILTER.apply(options.getFirst().getOptions()).isEmpty()) { - builder.setSubCommandGroup(TypeFactory.annotation(SubCommandGroup.class, Map.of("name", options.getFirst().getName()))); - builder.setSubCommand(TypeFactory.annotation(SubCommand.class, Map.of("name", SUB_FILTER.apply(options.getFirst().getOptions()).getFirst().getName()))); - }else - builder.setSubCommand(TypeFactory.annotation(SubCommand.class, Map.of("name", options.getFirst().getName()))); - } - } catch (AnnotationFormatException e) { - logger.fatal(e); + if (!options.isEmpty()) { + List sub_options = SUB_FILTER.apply(options.getFirst().getOptions()); + if (!sub_options.isEmpty()) { + last = InteractionIdentifier.builder() + .name(options.getFirst().getName()) + .type(isAutocomplete ? InteractionType.AUTOCOMPLETE : InteractionType.COMMAND) + .parent(last).build(); + last = InteractionIdentifier.slashBuilder() + .name(sub_options.getFirst().getName()) + .autocomplete(isAutocomplete) + .parent(last).build(); + }else + last = InteractionIdentifier.slashBuilder() + .name(options.getFirst().getName()) + .autocomplete(isAutocomplete) + .parent(last).build(); } - - return builder.build(); + return last; } private ApplicationCommandRequest convertSlashCommand(SlashCommandDefinition def) { List options = new ArrayList<>(); - SlashCommand cmd = def.getSlashCommand(); + RootCommandIdentifier cmd = def.rootIdentifier(); if (!def.isRootCommand()) { Arrays.stream(def.getSubCommands(null)).map(this::convertSubCommandDef).forEach(options::add); Arrays.stream(def.getSubCommandGroups()).map((x) -> convertSubCommandGroupDef(def, x)).forEach(options::add); @@ -149,8 +145,8 @@ public class Discord4JWrapper extends LibraryWrapper { .build(); } - private ApplicationCommandOptionData convertSubCommandGroupDef(SlashCommandDefinition def, SubCommandGroup subGroup) { - SubCommand[] subCommands = def.getSubCommands(subGroup.name()); + private ApplicationCommandOptionData convertSubCommandGroupDef(SlashCommandDefinition def, SlashCommandIdentifier subGroup) { + SlashCommandIdentifier[] subCommands = def.getSubCommands(subGroup.name()); List convertedSubCommands = Arrays.stream(subCommands).map(this::convertSubCommandDef).toList(); return ApplicationCommandOptionData.builder() .type(Type.SUB_COMMAND_GROUP.getValue()) @@ -160,7 +156,7 @@ public class Discord4JWrapper extends LibraryWrapper { .build(); } - private ApplicationCommandOptionData convertSubCommandDef(SubCommand sub) { + private ApplicationCommandOptionData convertSubCommandDef(SlashCommandIdentifier sub) { List convertedOptions = Arrays.stream(sub.options()).map(this::convertOptionDef).toList(); return ApplicationCommandOptionData.builder() .type(Type.SUB_COMMAND_GROUP.getValue()) @@ -184,7 +180,7 @@ public class Discord4JWrapper extends LibraryWrapper { private List convertChoices(SlashCommandOption option) { List convertedChoices = new ArrayList<>(); - for (SlashCommandOptionChoice choice : ExecutableSlashCommandDefinition.getActualChoices(option)) { + for (SlashCommandOptionChoice choice : SlashCommandDefinition.getActualChoices(option)) { var builder = ApplicationCommandOptionChoiceData.builder(); builder.name(choice.name()); if (choice.longValue() != Long.MAX_VALUE) @@ -198,12 +194,6 @@ public class Discord4JWrapper extends LibraryWrapper { return convertedChoices; } - @Override - public String getButtonId(Object context) { - ButtonInteractionEvent button = (ButtonInteractionEvent) context; - return button.getCustomId(); - } - @Override public ContextObjectProvider getContextObjectProvider() { return this.contextObjectProvider; diff --git a/wrapper/javacord/src/main/java/net/tomatentum/marinara/wrapper/javacord/JavacordWrapper.java b/wrapper/javacord/src/main/java/net/tomatentum/marinara/wrapper/javacord/JavacordWrapper.java index 38d0d55..6c1932d 100644 --- a/wrapper/javacord/src/main/java/net/tomatentum/marinara/wrapper/javacord/JavacordWrapper.java +++ b/wrapper/javacord/src/main/java/net/tomatentum/marinara/wrapper/javacord/JavacordWrapper.java @@ -5,12 +5,10 @@ import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.List; -import java.util.Map; import java.util.Set; import org.apache.logging.log4j.Logger; import org.javacord.api.DiscordApi; -import org.javacord.api.interaction.ApplicationCommandInteraction; import org.javacord.api.interaction.AutocompleteInteraction; import org.javacord.api.interaction.ButtonInteraction; import org.javacord.api.interaction.SlashCommandBuilder; @@ -20,16 +18,13 @@ import org.javacord.api.interaction.SlashCommandOptionBuilder; import org.javacord.api.interaction.SlashCommandOptionChoiceBuilder; import org.javacord.api.interaction.SlashCommandOptionType; -import io.leangen.geantyref.AnnotationFormatException; -import io.leangen.geantyref.TypeFactory; import net.tomatentum.marinara.interaction.InteractionType; -import net.tomatentum.marinara.interaction.commands.ExecutableSlashCommandDefinition; import net.tomatentum.marinara.interaction.commands.SlashCommandDefinition; -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.ident.InteractionIdentifier; +import net.tomatentum.marinara.interaction.ident.RootCommandIdentifier; +import net.tomatentum.marinara.interaction.ident.SlashCommandIdentifier; import net.tomatentum.marinara.wrapper.ContextObjectProvider; import net.tomatentum.marinara.util.LoggerUtil; import net.tomatentum.marinara.wrapper.LibraryWrapper; @@ -51,25 +46,14 @@ public class JavacordWrapper extends LibraryWrapper { logger.info("Javacord wrapper loaded!"); } - @Override - public InteractionType getInteractionType(Object context) { - if (AutocompleteInteraction.class.isAssignableFrom(context.getClass())) - return InteractionType.AUTOCOMPLETE; - if (ApplicationCommandInteraction.class.isAssignableFrom(context.getClass())) - return InteractionType.COMMAND; - if (ButtonInteraction.class.isAssignableFrom(context.getClass())) - return InteractionType.BUTTON; - return null; - } - @Override public void registerSlashCommands(SlashCommandDefinition[] defs) { HashMap> serverCommands = new HashMap<>(); Set globalCommands = new HashSet<>(); for (SlashCommandDefinition slashCommandDefinition : defs) { SlashCommandBuilder builder = convertSlashCommand(slashCommandDefinition); - if (slashCommandDefinition.getSlashCommand().serverIds().length > 0) { - for (long serverId : slashCommandDefinition.getSlashCommand().serverIds()) { + if (slashCommandDefinition.rootIdentifier().serverIds().length > 0) { + for (long serverId : slashCommandDefinition.rootIdentifier().serverIds()) { serverCommands.putIfAbsent(serverId, new HashSet<>()); serverCommands.get(serverId).add(builder); } @@ -84,32 +68,52 @@ public class JavacordWrapper extends LibraryWrapper { } @Override - public ExecutableSlashCommandDefinition getCommandDefinition(Object context) { + public InteractionIdentifier getInteractionIdentifier(Object context) { + if (context instanceof ButtonInteraction) { + ButtonInteraction button = (ButtonInteraction) context; + return InteractionIdentifier.builder().name(button.getCustomId()).type(InteractionType.BUTTON).build(); + } + if (!(context instanceof SlashCommandInteraction)) return null; + boolean isAutocomplete = false; + + if (context instanceof AutocompleteInteraction) + isAutocomplete = true; + SlashCommandInteraction interaction = (SlashCommandInteraction) context; - ExecutableSlashCommandDefinition.Builder builder = new ExecutableSlashCommandDefinition.Builder(); + InteractionIdentifier lastIdentifier = InteractionIdentifier.rootBuilder() + .name(interaction.getCommandName()) + .autocomplete(isAutocomplete) + .build(); List options = interaction.getOptions(); - try { - builder.setApplicationCommand(TypeFactory.annotation(SlashCommand.class, Map.of("name", interaction.getCommandName()))); - if (!options.isEmpty()) { - if (!options.getFirst().getArguments().isEmpty()) { - builder.setSubCommandGroup(TypeFactory.annotation(SubCommandGroup.class, Map.of("name", options.getFirst().getName()))); - builder.setSubCommand(TypeFactory.annotation(SubCommand.class, Map.of("name", options.getFirst().getOptions().getFirst().getName()))); - }else - builder.setSubCommand(TypeFactory.annotation(SubCommand.class, Map.of("name", options.getFirst().getName()))); - } - } catch (AnnotationFormatException e) { - logger.fatal(e); + if (!options.isEmpty()) { + if (!options.getFirst().getArguments().isEmpty()) { + lastIdentifier = InteractionIdentifier.builder() + .name(options.getFirst().getName()) + .type(isAutocomplete ? InteractionType.AUTOCOMPLETE : InteractionType.COMMAND) + .parent(lastIdentifier) + .build(); + lastIdentifier = InteractionIdentifier.slashBuilder() + .name(options.getFirst().getOptions().getFirst().getName()) + .autocomplete(isAutocomplete) + .parent(lastIdentifier) + .build(); + }else + lastIdentifier = InteractionIdentifier.slashBuilder() + .name(options.getFirst().getName()) + .autocomplete(isAutocomplete) + .parent(lastIdentifier) + .build(); } - return builder.build(); + return lastIdentifier; } private SlashCommandBuilder convertSlashCommand(SlashCommandDefinition def) { List options = new ArrayList<>(); - SlashCommand cmd = def.getSlashCommand(); + RootCommandIdentifier cmd = def.rootIdentifier(); if (!def.isRootCommand()) { Arrays.stream(def.getSubCommands(null)).map(this::convertSubCommandDef).forEach(options::add); Arrays.stream(def.getSubCommandGroups()).map((x) -> convertSubCommandGroupDef(def, x)).forEach(options::add); @@ -120,8 +124,8 @@ public class JavacordWrapper extends LibraryWrapper { return org.javacord.api.interaction.SlashCommand.with(cmd.name(), cmd.description(), options); } - private org.javacord.api.interaction.SlashCommandOption convertSubCommandGroupDef(SlashCommandDefinition def, SubCommandGroup subGroup) { - SubCommand[] subCommands = def.getSubCommands(subGroup.name()); + private org.javacord.api.interaction.SlashCommandOption convertSubCommandGroupDef(SlashCommandDefinition def, SlashCommandIdentifier subGroup) { + SlashCommandIdentifier[] subCommands = def.getSubCommands(subGroup.name()); List convertedSubCommands = Arrays.stream(subCommands).map(this::convertSubCommandDef).toList(); return org.javacord.api.interaction.SlashCommandOption.createWithOptions( org.javacord.api.interaction.SlashCommandOptionType.SUB_COMMAND_GROUP, @@ -130,7 +134,7 @@ public class JavacordWrapper extends LibraryWrapper { convertedSubCommands); } - private org.javacord.api.interaction.SlashCommandOption convertSubCommandDef(SubCommand sub) { + private org.javacord.api.interaction.SlashCommandOption convertSubCommandDef(SlashCommandIdentifier sub) { List convertedOptions = Arrays.stream(sub.options()).map(this::convertOptionDef).toList(); return org.javacord.api.interaction.SlashCommandOption.createWithOptions( org.javacord.api.interaction.SlashCommandOptionType.SUB_COMMAND, @@ -155,7 +159,7 @@ public class JavacordWrapper extends LibraryWrapper { private List convertChoices(SlashCommandOption option) { List convertedChoices = new ArrayList<>(); - for (SlashCommandOptionChoice choice : ExecutableSlashCommandDefinition.getActualChoices(option)) { + for (SlashCommandOptionChoice choice : SlashCommandDefinition.getActualChoices(option)) { SlashCommandOptionChoiceBuilder builder = new SlashCommandOptionChoiceBuilder(); builder.setName(choice.name()); if (choice.longValue() != Long.MAX_VALUE) @@ -172,12 +176,6 @@ public class JavacordWrapper extends LibraryWrapper { return convertedChoices; } - @Override - public String getButtonId(Object context) { - ButtonInteraction button = (ButtonInteraction) context; - return button.getCustomId(); - } - @Override public ContextObjectProvider getContextObjectProvider() { return contextObjectProvider;