diff --git a/CCH.iml b/CCH.iml index 740ca98..c9a6303 100644 --- a/CCH.iml +++ b/CCH.iml @@ -11,7 +11,7 @@ - + diff --git a/pom.xml b/pom.xml index 884b90d..3508758 100644 --- a/pom.xml +++ b/pom.xml @@ -7,24 +7,25 @@ tech.xigam CCH - 1.4.3 + 1.5.0 Complex Command Handler A really useful and simple command handler for JDA. https://github.com/KingRainbow44/Complex-Command-Handler/ - - - - - + + + + + + 17 @@ -127,7 +128,7 @@ net.dv8tion JDA - 5.0.0-alpha.5 + 5.0.0-alpha.9 provided diff --git a/src/main/java/tech/xigam/cch/ComplexCommandHandler.java b/src/main/java/tech/xigam/cch/ComplexCommandHandler.java index 91ae55f..7d4c1ee 100644 --- a/src/main/java/tech/xigam/cch/ComplexCommandHandler.java +++ b/src/main/java/tech/xigam/cch/ComplexCommandHandler.java @@ -1,15 +1,16 @@ package tech.xigam.cch; import net.dv8tion.jda.api.JDA; -import net.dv8tion.jda.api.JDABuilder; import net.dv8tion.jda.api.entities.Guild; import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.Message; import net.dv8tion.jda.api.entities.TextChannel; import net.dv8tion.jda.api.events.interaction.command.CommandAutoCompleteInteractionEvent; import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; +import net.dv8tion.jda.api.events.interaction.component.ButtonInteractionEvent; import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import net.dv8tion.jda.api.events.message.MessageUpdateEvent; +import net.dv8tion.jda.api.events.message.react.MessageReactionAddEvent; import net.dv8tion.jda.api.hooks.ListenerAdapter; import net.dv8tion.jda.api.interactions.commands.OptionType; import net.dv8tion.jda.api.interactions.commands.build.Commands; @@ -43,9 +44,6 @@ public final class ComplexCommandHandler extends ListenerAdapter public Consumer onArgumentError = interaction -> {}; - /** - * This constructor should be called in {@link JDABuilder#addEventListeners} - */ public ComplexCommandHandler(boolean usePrefix) { this.usePrefix = usePrefix; } @@ -59,6 +57,7 @@ public ComplexCommandHandler registerCommand(BaseCommand command) { } public void setJda(JDA jda) { + jda.addEventListener(this); this.jdaInstance = jda; } @@ -103,12 +102,6 @@ private void executeCommand(String command, Message message2, Member member, Tex ); } - /* - * Completing commands. - */ - - - /* * Handling interactive arguments. */ @@ -188,6 +181,22 @@ public void onCommandAutoCompleteInteraction(@NotNull CommandAutoCompleteInterac command.prepareForCompletion(event, this); } + @Override + public void onButtonInteraction(@NotNull ButtonInteractionEvent event) { + String rawReference = event.getComponentId(); + if (!rawReference.startsWith("<")) + return; + + var label = rawReference.split("<")[1].split(">")[0]; + var command = commands.get(label); + command.prepareForCallback(label, event, this); + } + + @Override + public void onMessageReactionAdd(@NotNull MessageReactionAddEvent event) { + + } + /** * Delete and create commands. */ diff --git a/src/main/java/tech/xigam/cch/command/BaseCommand.java b/src/main/java/tech/xigam/cch/command/BaseCommand.java index b2e1880..4d365cb 100644 --- a/src/main/java/tech/xigam/cch/command/BaseCommand.java +++ b/src/main/java/tech/xigam/cch/command/BaseCommand.java @@ -1,15 +1,21 @@ package tech.xigam.cch.command; +import net.dv8tion.jda.api.entities.Emoji; import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.Message; import net.dv8tion.jda.api.entities.TextChannel; import net.dv8tion.jda.api.events.interaction.command.CommandAutoCompleteInteractionEvent; import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; +import net.dv8tion.jda.api.events.interaction.component.ButtonInteractionEvent; +import net.dv8tion.jda.api.interactions.components.buttons.Button; +import net.dv8tion.jda.api.interactions.components.buttons.ButtonStyle; import tech.xigam.cch.ComplexCommandHandler; import tech.xigam.cch.utils.Interaction; import java.util.List; +import static tech.xigam.cch.utils.Validation.isUrl; + /** * An interface used by {@link Command}, {@link SubCommand}, and {@link Alias} */ @@ -17,6 +23,7 @@ public interface BaseCommand { /* * General command information. */ + String getLabel(); String getDescription(); @@ -24,6 +31,7 @@ public interface BaseCommand { /* * Back-end code. */ + void execute(Interaction interaction); void prepareForExecution(List arguments, Message message, Member sender, TextChannel channel, boolean skipArguments, ComplexCommandHandler handler); @@ -31,4 +39,45 @@ public interface BaseCommand { void prepareForExecution(SlashCommandInteractionEvent event, ComplexCommandHandler handler); void prepareForCompletion(CommandAutoCompleteInteractionEvent event, ComplexCommandHandler handler); + +// void prepareForCallback(MessageReactionAddEvent event, ComplexCommandHandler handler); + + void prepareForCallback(String cmdLabel, ButtonInteractionEvent event, ComplexCommandHandler handler); + + /** + * Creates a button with proper handling for this command. + * + * @param style The button style. + * @param reference The reference to the button (or a URL). + * @param text The text to display on the button. + * @return The button. + */ + default Button createButton(ButtonStyle style, String reference, String text) { + return Button.of(style, isUrl(reference) ? reference : "<" + this.getLabel().toLowerCase() + ">" + reference, text); + } + + /** + * Creates a button with proper handling for this command. + * + * @param style The button style. + * @param reference The reference to the button (or a URL). + * @param emoji The emoji to show on the button. + * @return The button. + */ + default Button createButton(ButtonStyle style, String reference, Emoji emoji) { + return Button.of(style, isUrl(reference) ? reference : "<" + this.getLabel().toLowerCase() + ">" + reference, emoji); + } + + /** + * Creates a button with proper handling for this command. + * + * @param style The button style. + * @param reference The reference to the button (or a URL). + * @param text The text to show to the right of the emoji. + * @param emoji The emoji to show on the button. + * @return The button. + */ + default Button createButton(ButtonStyle style, String reference, String text, Emoji emoji) { + return Button.of(style, isUrl(reference) ? reference : "<" + this.getLabel().toLowerCase() + ">" + reference, text, emoji); + } } diff --git a/src/main/java/tech/xigam/cch/command/Callable.java b/src/main/java/tech/xigam/cch/command/Callable.java new file mode 100644 index 0000000..eced3c2 --- /dev/null +++ b/src/main/java/tech/xigam/cch/command/Callable.java @@ -0,0 +1,12 @@ +package tech.xigam.cch.command; + +import tech.xigam.cch.utils.Callback; + +/** + * Declares a class as callable, allowing: + * - buttons to work + * - forms to work + */ +public interface Callable { + void callback(Callback callback); +} diff --git a/src/main/java/tech/xigam/cch/command/Command.java b/src/main/java/tech/xigam/cch/command/Command.java index 25aa3b7..6c18129 100644 --- a/src/main/java/tech/xigam/cch/command/Command.java +++ b/src/main/java/tech/xigam/cch/command/Command.java @@ -5,12 +5,10 @@ import net.dv8tion.jda.api.entities.TextChannel; import net.dv8tion.jda.api.events.interaction.command.CommandAutoCompleteInteractionEvent; import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; +import net.dv8tion.jda.api.events.interaction.component.ButtonInteractionEvent; import net.dv8tion.jda.api.interactions.commands.OptionMapping; import tech.xigam.cch.ComplexCommandHandler; -import tech.xigam.cch.utils.Argument; -import tech.xigam.cch.utils.Completion; -import tech.xigam.cch.utils.Interaction; -import tech.xigam.cch.utils.InteractiveArguments; +import tech.xigam.cch.utils.*; import java.util.ArrayList; import java.util.HashMap; @@ -130,6 +128,19 @@ public void prepareForCompletion(CommandAutoCompleteInteractionEvent event, Comp ((Completable) this).complete(new Completion(event)); } + @Override + public void prepareForCallback(String cmdLabel, ButtonInteractionEvent event, ComplexCommandHandler handler) { + if (subCommands.containsKey(cmdLabel)) { + var subCmd = this.getSubCommand(cmdLabel); + if (subCmd instanceof Callable) + ((Callable) subCmd).callback(new Callback(event)); + return; + } + + if (this instanceof Callable) + ((Callable) this).callback(new Callback(event)); + } + public final Map getSubCommands() { return subCommands; } diff --git a/src/main/java/tech/xigam/cch/defaults/DeployCommand.java b/src/main/java/tech/xigam/cch/defaults/DeployCommand.java index 65c5a85..05ead0e 100644 --- a/src/main/java/tech/xigam/cch/defaults/DeployCommand.java +++ b/src/main/java/tech/xigam/cch/defaults/DeployCommand.java @@ -1,11 +1,13 @@ package tech.xigam.cch.defaults; +import net.dv8tion.jda.api.entities.MessageEmbed; import net.dv8tion.jda.api.interactions.commands.OptionType; import tech.xigam.cch.command.Arguments; import tech.xigam.cch.command.Command; import tech.xigam.cch.utils.Argument; import tech.xigam.cch.utils.Interaction; +import javax.annotation.Nullable; import java.util.Collection; import java.util.List; @@ -16,6 +18,11 @@ public DeployCommand() { protected abstract boolean permissionCheck(Interaction interaction); + @Nullable + protected MessageEmbed embedify(String text) { + return null; + } + @Override public void execute(Interaction interaction) { if (!permissionCheck(interaction)) { @@ -28,15 +35,22 @@ public void execute(Interaction interaction) { if (!global && !interaction.isFromGuild()) { global = true; - interaction.sendMessage("You can't deploy slash commands to a DM, deploying globally instead."); + var embed = this.embedify("You can't deploy slash commands to a DM, deploying globally instead."); + if (embed == null) + interaction.reply("You can't deploy slash commands to a DM, deploying globally instead."); + else interaction.reply(embed); } if (delete) { interaction.getCommandHandler().downsert(global ? null : interaction.getGuild()); - interaction.reply("Deleted all commands."); + var embed = this.embedify("Deleted all commands."); + if (embed == null) interaction.reply("Deleted all commands."); + else interaction.reply(embed); } else { interaction.getCommandHandler().deployAll(global ? null : interaction.getGuild()); - interaction.reply("Deployed all commands."); + var embed = this.embedify("Deployed all commands."); + if (embed == null) interaction.reply("Deployed all commands."); + else interaction.reply(embed); } } diff --git a/src/main/java/tech/xigam/cch/utils/Callback.java b/src/main/java/tech/xigam/cch/utils/Callback.java new file mode 100644 index 0000000..b8e0f27 --- /dev/null +++ b/src/main/java/tech/xigam/cch/utils/Callback.java @@ -0,0 +1,44 @@ +package tech.xigam.cch.utils; + +import net.dv8tion.jda.api.events.interaction.component.ButtonInteractionEvent; +import net.dv8tion.jda.api.events.interaction.component.GenericComponentInteractionCreateEvent; + +/** + * A callback for buttons and forms. + */ +public final class Callback { + private final boolean isSlash, inGuild; + private final String reference; + + private GenericComponentInteractionCreateEvent interactionExecutor = null; + + private boolean deferred = false; + + public Callback(ButtonInteractionEvent event) { + this.isSlash = true; + this.inGuild = event.isFromGuild(); + this.interactionExecutor = event; + + var rawReference = event.getComponentId(); + this.reference = rawReference.split(">")[1]; + } + + public String getReference() { + return this.reference; + } + + // ---------- UTILITY METHODS ---------- \\ + + public Callback deferEdit() { + if (this.isSlash) + this.interactionExecutor.deferEdit().queue(); + this.deferred = true; + return this; + } + + // ---------- REPLY METHODS ---------- \\ + + public void reply(String message) { + + } +} diff --git a/src/main/java/tech/xigam/cch/utils/Completion.java b/src/main/java/tech/xigam/cch/utils/Completion.java index 192ca1a..5671ce8 100644 --- a/src/main/java/tech/xigam/cch/utils/Completion.java +++ b/src/main/java/tech/xigam/cch/utils/Completion.java @@ -56,6 +56,9 @@ public Completion addChoice(String mapping, Object value) { } public void reply() { - this.completeEvent.replyChoices(this.choices).queue(); + try { + this.completeEvent.replyChoices(this.choices).queue(); + } catch (IllegalStateException ignored) { + } } } diff --git a/src/main/java/tech/xigam/cch/utils/Interaction.java b/src/main/java/tech/xigam/cch/utils/Interaction.java index b7b82db..2ebd6de 100644 --- a/src/main/java/tech/xigam/cch/utils/Interaction.java +++ b/src/main/java/tech/xigam/cch/utils/Interaction.java @@ -4,6 +4,7 @@ import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; import net.dv8tion.jda.api.interactions.commands.OptionMapping; import net.dv8tion.jda.api.interactions.commands.OptionType; +import net.dv8tion.jda.api.interactions.components.buttons.Button; import tech.xigam.cch.ComplexCommandHandler; import tech.xigam.cch.command.Arguments; import tech.xigam.cch.command.BaseCommand; @@ -13,13 +14,8 @@ import java.util.concurrent.TimeUnit; import java.util.function.Consumer; -public final class Interaction implements Cloneable { - /* - * Global data. - * Set regardless of position. - */ +public final class Interaction { private final boolean isSlash, inGuild; - private final BaseCommand command; private final ComplexCommandHandler commandHandler; private final Member member; @@ -29,21 +25,19 @@ public final class Interaction implements Cloneable { private SlashCommandInteractionEvent slashExecutor = null; - /* - * Information storage. - */ private boolean ephemeral = false, sendToDMs = false; private boolean deferred = false; private final Map arguments = new HashMap<>(); private final List rawArguments = new ArrayList<>(); + private final List