From 56b668851bc0c2425188b2c53529fd85778dc6e7 Mon Sep 17 00:00:00 2001 From: Tueem Date: Mon, 3 Mar 2025 23:32:25 +0100 Subject: [PATCH] add CommandConverter logic and wrapper implementations --- .../commands/CommandConverter.java | 57 ++++++++++--- .../discord4j/Discord4JConverterSpec.java | 75 +++++++++++++++++ .../wrapper/discord4j/Discord4JWrapper.java | 77 ++--------------- .../javacord/JavacordConverterSpec.java | 73 +++++++++++++++++ .../wrapper/javacord/JavacordWrapper.java | 82 ++----------------- 5 files changed, 207 insertions(+), 157 deletions(-) create mode 100644 wrapper/discord4j/src/main/java/net/tomatentum/marinara/wrapper/discord4j/Discord4JConverterSpec.java create mode 100644 wrapper/javacord/src/main/java/net/tomatentum/marinara/wrapper/javacord/JavacordConverterSpec.java 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 cd90895..e2f78f2 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 @@ -1,23 +1,60 @@ package net.tomatentum.marinara.interaction.commands; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + import net.tomatentum.marinara.interaction.commands.annotation.SlashCommandOption; -import net.tomatentum.marinara.interaction.commands.annotation.SubCommand; -import net.tomatentum.marinara.interaction.commands.annotation.SubCommandGroup; +import net.tomatentum.marinara.interaction.commands.annotation.SlashCommandOptionChoice; +import net.tomatentum.marinara.interaction.ident.InteractionIdentifier; +import net.tomatentum.marinara.interaction.ident.RootCommandIdentifier; +import net.tomatentum.marinara.interaction.ident.SlashCommandIdentifier; -public class CommandConverter { +public class CommandConverter { - private Spec spec; + public static CommandConverter of(Spec spec) { + return new CommandConverter<>(spec); + } + + private Spec spec; + + CommandConverter(Spec spec) { + this.spec = spec; + } public A convert(SlashCommandDefinition def) { - return null; + List options = new ArrayList<>(); + if (!def.isRootCommand()) { + Arrays.stream(def.getSubCommands()).map(this::convertSubCommand).forEach(options::add); + Arrays.stream(def.getSubCommandGroups()).map(x -> this.convertSubCommandGroup(def, x)).forEach(options::add); + }else + Arrays.stream(def.rootIdentifier().options()).map(this::convertOption).forEach(options::add); + + return spec.convertCommand(def.rootIdentifier(), options); + } + + private O convertSubCommandGroup(SlashCommandDefinition def, InteractionIdentifier identifier) { + SlashCommandIdentifier[] subCommands = def.getSubCommands(identifier.name()); + List convertedSubCommands = Arrays.stream(subCommands).map(this::convertSubCommand).toList(); + return spec.convertSubCommandGroup(identifier, convertedSubCommands); + } + + private O convertSubCommand(SlashCommandIdentifier identifier) { + List options = Arrays.stream(identifier.options()).map(this::convertOption).toList(); + return spec.convertSubCommand(identifier, options); + } + + private O convertOption(SlashCommandOption option) { + List choices = Arrays.stream(SlashCommandDefinition.getActualChoices(option)).map(spec::convertChoice).toList(); + return spec.convertOption(option, choices); } public static interface Spec { - public A convertCommand(SlashCommandDefinition def); - public O convertSubCommand(SubCommand def, O[] options); - public O convertSubCommandGroup(SubCommandGroup def, O[] options); - public O convertOption(SlashCommandOption option, C[] choices); - public C[] convertChoice(SlashCommandOption option); + public A convertCommand(RootCommandIdentifier rootIdentifier, List options); + public O convertSubCommandGroup(InteractionIdentifier identifier, List subCommands); + public O convertSubCommand(InteractionIdentifier identifier, List options); + public O convertOption(SlashCommandOption option, List choices); + public C convertChoice(SlashCommandOptionChoice choice); } } diff --git a/wrapper/discord4j/src/main/java/net/tomatentum/marinara/wrapper/discord4j/Discord4JConverterSpec.java b/wrapper/discord4j/src/main/java/net/tomatentum/marinara/wrapper/discord4j/Discord4JConverterSpec.java new file mode 100644 index 0000000..6045b94 --- /dev/null +++ b/wrapper/discord4j/src/main/java/net/tomatentum/marinara/wrapper/discord4j/Discord4JConverterSpec.java @@ -0,0 +1,75 @@ +package net.tomatentum.marinara.wrapper.discord4j; + +import java.util.List; + +import discord4j.core.object.command.ApplicationCommandOption.Type; +import discord4j.discordjson.json.ApplicationCommandOptionChoiceData; +import discord4j.discordjson.json.ApplicationCommandOptionData; +import discord4j.discordjson.json.ApplicationCommandRequest; +import net.tomatentum.marinara.interaction.commands.CommandConverter; +import net.tomatentum.marinara.interaction.commands.annotation.SlashCommandOption; +import net.tomatentum.marinara.interaction.commands.annotation.SlashCommandOptionChoice; +import net.tomatentum.marinara.interaction.ident.InteractionIdentifier; +import net.tomatentum.marinara.interaction.ident.RootCommandIdentifier; + +public class Discord4JConverterSpec implements CommandConverter.Spec { + + @Override + public ApplicationCommandRequest convertCommand(RootCommandIdentifier rootIdentifier, + List options) { + return ApplicationCommandRequest.builder() + .name(rootIdentifier.name()) + .description(rootIdentifier.description()) + .options(options) + .build(); + } + + @Override + public ApplicationCommandOptionData convertSubCommandGroup(InteractionIdentifier identifier, + List subCommands) { + return ApplicationCommandOptionData.builder() + .type(Type.SUB_COMMAND_GROUP.getValue()) + .name(identifier.name()) + .description(identifier.description()) + .options(subCommands) + .build(); + } + + @Override + public ApplicationCommandOptionData convertSubCommand(InteractionIdentifier identifier, + List options) { + return ApplicationCommandOptionData.builder() + .type(Type.SUB_COMMAND_GROUP.getValue()) + .name(identifier.name()) + .description(identifier.description()) + .options(options) + .build(); + } + + @Override + public ApplicationCommandOptionData convertOption(SlashCommandOption option, + List choices) { + Type type = Type.of(option.type().getValue()); + return ApplicationCommandOptionData.builder() + .type(type.getValue()) + .name(option.name()) + .description(option.description()) + .required(option.required()) + .autocomplete(option.autocomplete()) + .choices(choices) + .build(); + } + + @Override + public ApplicationCommandOptionChoiceData convertChoice(SlashCommandOptionChoice choice) { + var builder = ApplicationCommandOptionChoiceData.builder().name(choice.name()); + if (choice.longValue() != Long.MAX_VALUE) + builder.value(choice.longValue()); + if (choice.doubleValue() != Double.MAX_VALUE) + builder.value(choice.doubleValue()); + if (!choice.stringValue().isEmpty()) + builder.value(choice.stringValue()); + return builder.build(); + } + +} 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 7c046b3..85a1e28 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 @@ -1,7 +1,6 @@ package net.tomatentum.marinara.wrapper.discord4j; import java.util.ArrayList; -import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.function.Function; @@ -20,12 +19,9 @@ import discord4j.discordjson.json.ApplicationCommandOptionData; import discord4j.discordjson.json.ApplicationCommandRequest; import net.tomatentum.marinara.interaction.InteractionType; +import net.tomatentum.marinara.interaction.commands.CommandConverter; import net.tomatentum.marinara.interaction.commands.SlashCommandDefinition; -import net.tomatentum.marinara.interaction.commands.annotation.SlashCommandOption; -import net.tomatentum.marinara.interaction.commands.annotation.SlashCommandOptionChoice; 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; @@ -44,12 +40,15 @@ public class Discord4JWrapper extends LibraryWrapper { private GatewayDiscordClient api; private Discord4JContextObjectProvider contextObjectProvider; + private CommandConverter commandConverter; private Logger logger = LoggerUtil.getLogger(getClass()); public Discord4JWrapper(GatewayDiscordClient api) { this.api = api; this.contextObjectProvider = new Discord4JContextObjectProvider(); + this.commandConverter = CommandConverter.of(new Discord4JConverterSpec()); + if (api != null) api.on(InteractionCreateEvent.class) .subscribe(event -> handleInteraction(event)); @@ -66,7 +65,7 @@ public class Discord4JWrapper extends LibraryWrapper { long applicationId = api.getRestClient().getApplicationId().block(); for (SlashCommandDefinition slashCommandDefinition : defs) { - ApplicationCommandRequest request = convertSlashCommand(slashCommandDefinition); + ApplicationCommandRequest request = this.commandConverter.convert(slashCommandDefinition); if (slashCommandDefinition.rootIdentifier().serverIds().length > 0) { for (long serverId : slashCommandDefinition.rootIdentifier().serverIds()) { serverCommands.putIfAbsent(serverId, new ArrayList<>()); @@ -128,72 +127,6 @@ public class Discord4JWrapper extends LibraryWrapper { return last; } - private ApplicationCommandRequest convertSlashCommand(SlashCommandDefinition def) { - List options = new ArrayList<>(); - 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); - }else { - Arrays.stream(cmd.options()).map(this::convertOptionDef).forEach(options::add); - } - - return ApplicationCommandRequest.builder() - .name(cmd.name()) - .description(cmd.description()) - .options(options) - .build(); - } - - 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()) - .name(subGroup.name()) - .description(subGroup.description()) - .options(convertedSubCommands) - .build(); - } - - private ApplicationCommandOptionData convertSubCommandDef(SlashCommandIdentifier sub) { - List convertedOptions = Arrays.stream(sub.options()).map(this::convertOptionDef).toList(); - return ApplicationCommandOptionData.builder() - .type(Type.SUB_COMMAND_GROUP.getValue()) - .name(sub.name()) - .description(sub.description()) - .options(convertedOptions) - .build(); - } - - private ApplicationCommandOptionData convertOptionDef(SlashCommandOption option) { - Type type = Enum.valueOf(Type.class, option.type().toString()); - return ApplicationCommandOptionData.builder() - .type(type.getValue()) - .name(option.name()) - .description(option.description()) - .required(option.required()) - .autocomplete(option.autocomplete()) - .choices(convertChoices(option)) - .build(); - } - - private List convertChoices(SlashCommandOption option) { - List convertedChoices = new ArrayList<>(); - for (SlashCommandOptionChoice choice : SlashCommandDefinition.getActualChoices(option)) { - var builder = ApplicationCommandOptionChoiceData.builder(); - builder.name(choice.name()); - if (choice.longValue() != Long.MAX_VALUE) - builder.value(choice.longValue()); - if (choice.doubleValue() != Double.MAX_VALUE) - builder.value(choice.doubleValue()); - if (!choice.stringValue().isEmpty()) - builder.value(choice.stringValue()); - convertedChoices.add(builder.build()); - } - return convertedChoices; - } - @Override public ContextObjectProvider getContextObjectProvider() { return this.contextObjectProvider; diff --git a/wrapper/javacord/src/main/java/net/tomatentum/marinara/wrapper/javacord/JavacordConverterSpec.java b/wrapper/javacord/src/main/java/net/tomatentum/marinara/wrapper/javacord/JavacordConverterSpec.java new file mode 100644 index 0000000..e2748a1 --- /dev/null +++ b/wrapper/javacord/src/main/java/net/tomatentum/marinara/wrapper/javacord/JavacordConverterSpec.java @@ -0,0 +1,73 @@ +package net.tomatentum.marinara.wrapper.javacord; + +import java.util.List; + +import org.javacord.api.interaction.SlashCommand; +import org.javacord.api.interaction.SlashCommandBuilder; +import org.javacord.api.interaction.SlashCommandOption; +import org.javacord.api.interaction.SlashCommandOptionBuilder; +import org.javacord.api.interaction.SlashCommandOptionChoice; +import org.javacord.api.interaction.SlashCommandOptionChoiceBuilder; +import org.javacord.api.interaction.SlashCommandOptionType; + +import net.tomatentum.marinara.interaction.commands.CommandConverter; +import net.tomatentum.marinara.interaction.ident.InteractionIdentifier; +import net.tomatentum.marinara.interaction.ident.RootCommandIdentifier; + +public class JavacordConverterSpec implements CommandConverter.Spec { + + @Override + public SlashCommandBuilder convertCommand(RootCommandIdentifier rootIdentifier, List options) { + return SlashCommand.with(rootIdentifier.name(), rootIdentifier.description(), options); + } + + @Override + public SlashCommandOption convertSubCommandGroup(InteractionIdentifier identifier, + List subCommands) { + return SlashCommandOption.createWithOptions( + SlashCommandOptionType.SUB_COMMAND_GROUP, + identifier.name(), + identifier.description(), + subCommands); + } + + @Override + public SlashCommandOption convertSubCommand(InteractionIdentifier identifier, List options) { + return SlashCommandOption.createWithOptions( + SlashCommandOptionType.SUB_COMMAND, + identifier.name(), + identifier.description(), + options); + } + + @Override + public SlashCommandOption convertOption( + net.tomatentum.marinara.interaction.commands.annotation.SlashCommandOption option, + List choices) { + SlashCommandOptionType type = SlashCommandOptionType.fromValue(option.type().getValue()); + return new SlashCommandOptionBuilder() + .setType(type) + .setName(option.name()) + .setDescription(option.description()) + .setRequired(option.required()) + .setAutocompletable(option.autocomplete()) + .setChoices(choices) + .build(); + } + + @Override + public SlashCommandOptionChoice convertChoice( + net.tomatentum.marinara.interaction.commands.annotation.SlashCommandOptionChoice choice) { + SlashCommandOptionChoiceBuilder builder = new SlashCommandOptionChoiceBuilder().setName(choice.name()); + if (choice.longValue() != Long.MAX_VALUE) + builder.setValue(choice.longValue()); + /* + not yet available + if (choice.doubleValue() != Double.MAX_VALUE) + builder.setValue(choice.doubleValue()); + */ + if (!choice.stringValue().isEmpty()) + builder.setValue(choice.stringValue()); + return builder.build(); + } +} 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 6c1932d..57e9c64 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 @@ -1,7 +1,5 @@ package net.tomatentum.marinara.wrapper.javacord; -import java.util.ArrayList; -import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -14,17 +12,13 @@ import org.javacord.api.interaction.ButtonInteraction; import org.javacord.api.interaction.SlashCommandBuilder; import org.javacord.api.interaction.SlashCommandInteraction; import org.javacord.api.interaction.SlashCommandInteractionOption; -import org.javacord.api.interaction.SlashCommandOptionBuilder; -import org.javacord.api.interaction.SlashCommandOptionChoiceBuilder; -import org.javacord.api.interaction.SlashCommandOptionType; +import org.javacord.api.interaction.SlashCommandOption; +import org.javacord.api.interaction.SlashCommandOptionChoice; import net.tomatentum.marinara.interaction.InteractionType; +import net.tomatentum.marinara.interaction.commands.CommandConverter; import net.tomatentum.marinara.interaction.commands.SlashCommandDefinition; -import net.tomatentum.marinara.interaction.commands.annotation.SlashCommandOption; -import net.tomatentum.marinara.interaction.commands.annotation.SlashCommandOptionChoice; 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; @@ -33,12 +27,15 @@ public class JavacordWrapper extends LibraryWrapper { private DiscordApi api; private JavacordContextObjectProvider contextObjectProvider; + private CommandConverter commandConverter; private Logger logger = LoggerUtil.getLogger(getClass()); public JavacordWrapper(DiscordApi api) { this.api = api; this.contextObjectProvider = new JavacordContextObjectProvider(); + this.commandConverter = CommandConverter.of(new JavacordConverterSpec()); + if (api != null) api.addInteractionCreateListener((e) -> handleInteraction(e.getInteraction())); else @@ -51,7 +48,7 @@ public class JavacordWrapper extends LibraryWrapper { HashMap> serverCommands = new HashMap<>(); Set globalCommands = new HashSet<>(); for (SlashCommandDefinition slashCommandDefinition : defs) { - SlashCommandBuilder builder = convertSlashCommand(slashCommandDefinition); + SlashCommandBuilder builder = commandConverter.convert(slashCommandDefinition); if (slashCommandDefinition.rootIdentifier().serverIds().length > 0) { for (long serverId : slashCommandDefinition.rootIdentifier().serverIds()) { serverCommands.putIfAbsent(serverId, new HashSet<>()); @@ -111,71 +108,6 @@ public class JavacordWrapper extends LibraryWrapper { return lastIdentifier; } - private SlashCommandBuilder convertSlashCommand(SlashCommandDefinition def) { - List options = new ArrayList<>(); - 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); - }else { - Arrays.stream(cmd.options()).map(this::convertOptionDef).forEach(options::add); - } - - return org.javacord.api.interaction.SlashCommand.with(cmd.name(), cmd.description(), options); - } - - 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, - subGroup.name(), - subGroup.description(), - convertedSubCommands); - } - - 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, - sub.name(), - sub.description(), - convertedOptions); - } - - private org.javacord.api.interaction.SlashCommandOption convertOptionDef(SlashCommandOption option) { - SlashCommandOptionType type = SlashCommandOptionType.fromValue(option.type().getValue()); - SlashCommandOptionBuilder builder = new SlashCommandOptionBuilder(); - builder - .setType(type) - .setName(option.name()) - .setDescription(option.description()) - .setRequired(option.required()) - .setAutocompletable(option.autocomplete()) - .setChoices(convertChoices(option)); - - return builder.build(); - } - - private List convertChoices(SlashCommandOption option) { - List convertedChoices = new ArrayList<>(); - for (SlashCommandOptionChoice choice : SlashCommandDefinition.getActualChoices(option)) { - SlashCommandOptionChoiceBuilder builder = new SlashCommandOptionChoiceBuilder(); - builder.setName(choice.name()); - if (choice.longValue() != Long.MAX_VALUE) - builder.setValue(choice.longValue()); - /* - not yet available - if (choice.doubleValue() != Double.MAX_VALUE) - builder.setValue(choice.doubleValue()); - */ - if (!choice.stringValue().isEmpty()) - builder.setValue(choice.stringValue()); - convertedChoices.add(builder.build()); - } - return convertedChoices; - } - @Override public ContextObjectProvider getContextObjectProvider() { return contextObjectProvider;