From 70e5e5ca3312231604b97949e5a8e6db09e1c89c Mon Sep 17 00:00:00 2001 From: freya02 <41875020+freya022@users.noreply.github.com> Date: Tue, 23 Jul 2024 12:07:13 +0200 Subject: [PATCH] Add user-installed slash command example --- src/examples/java/SlashBotExample.java | 90 +++++++++++++++++++++++++- 1 file changed, 87 insertions(+), 3 deletions(-) diff --git a/src/examples/java/SlashBotExample.java b/src/examples/java/SlashBotExample.java index 6807e227a4..ba35517447 100644 --- a/src/examples/java/SlashBotExample.java +++ b/src/examples/java/SlashBotExample.java @@ -19,6 +19,8 @@ import net.dv8tion.jda.api.Permission; import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.User; +import net.dv8tion.jda.api.entities.Webhook; +import net.dv8tion.jda.api.entities.channel.attribute.IWebhookContainer; import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel; import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; import net.dv8tion.jda.api.events.interaction.component.ButtonInteractionEvent; @@ -36,6 +38,7 @@ import java.util.EnumSet; import java.util.concurrent.TimeUnit; +import java.util.function.Consumer; import static net.dv8tion.jda.api.interactions.commands.OptionType.*; @@ -47,7 +50,7 @@ public static void main(String[] args) .addEventListeners(new SlashBotExample()) .build(); - // These commands might take a few minutes to be active after creation/update/delete + // You might need to reload your Discord client if you don't see the commands CommandListUpdateAction commands = jda.updateCommands(); // Moderation commands with required options @@ -63,6 +66,13 @@ public static void main(String[] args) ); // Simple reply commands + commands.addCommands( + Commands.slash("echo", "Makes the bot reply to yourself") + .setContexts(InteractionContextType.ALL) // Allow the command to be used anywhere (Bot DMs, Guild, Friend DMs, Group DMs) + .setIntegrationTypes(IntegrationType.ALL) // Allow the command to be installed anywhere (Guilds, Users) + .addOption(STRING, "content", "What the bot should reply to yourself", true) // you can add required options like this too + ); + commands.addCommands( Commands.slash("say", "Makes the bot say what you tell it to") .setContexts(InteractionContextType.ALL) // Allow the command to be used anywhere (Bot DMs, Guild, Friend DMs, Group DMs) @@ -73,13 +83,17 @@ public static void main(String[] args) // Commands without any inputs commands.addCommands( Commands.slash("leave", "Make the bot leave the server") - .setContexts(InteractionContextType.GUILD) // this doesn't make sense in DMs + // The default integration types are GUILD_INSTALL. + // Can't use this in DMs, and in guilds the bot isn't in. + .setContexts(InteractionContextType.GUILD) .setDefaultPermissions(DefaultMemberPermissions.DISABLED) // only admins should be able to use this command. ); commands.addCommands( Commands.slash("prune", "Prune messages from this channel") .addOption(INTEGER, "amount", "How many messages to prune (Default 100)") // simple optional argument + // The default integration types are GUILD_INSTALL. + // Can't use this in DMs, and in guilds the bot isn't in. .setContexts(InteractionContextType.GUILD) .setDefaultPermissions(DefaultMemberPermissions.enabledFor(Permission.MESSAGE_MANAGE)) ); @@ -102,6 +116,9 @@ public void onSlashCommandInteraction(SlashCommandInteractionEvent event) User user = event.getOption("user").getAsUser(); ban(event, user, member); break; + case "echo": + echo(event, event.getOption("content").getAsString()); // content is required so no null-check here + break; case "say": say(event, event.getOption("content").getAsString()); // content is required so no null-check here break; @@ -181,11 +198,78 @@ public void ban(SlashCommandInteractionEvent event, User user, Member member) .queue(); // execute the entire call chain } - public void say(SlashCommandInteractionEvent event, String content) + public void echo(SlashCommandInteractionEvent event, String content) { event.reply(content).queue(); // This requires no permissions! } + public void say(SlashCommandInteractionEvent event, String content) + { + event.deferReply().queue(); + + // To use a webhook, the bot needs to be in the guild, + // reply to the interaction in other cases (detached guilds, DMs, Group DMs). + tryUseWebhook( + event, + // If we can use a webhook + webhook -> + { + // Remove the bot thinking message + event.getHook().deleteOriginal().queue(); + + webhook.sendMessage(content) + .setUsername(event.getMember().getEffectiveName()) + .setAvatarUrl(event.getMember().getEffectiveAvatarUrl()) + .queue(); + }, + // Fallback + () -> event.getHook().sendMessage(content).queue() // This requires no permissions! + ); + } + + private void tryUseWebhook(SlashCommandInteractionEvent event, Consumer webhookCallback, Runnable noWebhookCallback) + { + // If the bot isn't in the guild, fallback to a normal reply + if (!event.hasFullGuild()) + { + noWebhookCallback.run(); + return; + } + + // In case the channel doesn't support webhooks, fallback to a normal reply + if (!(event.getGuildChannel() instanceof IWebhookContainer)) + { + noWebhookCallback.run(); + return; + } + + // If we don't have permissions to create a webhook, fallback to a normal reply + final IWebhookContainer webhookContainer = (IWebhookContainer) event.getGuildChannel(); + // Make sure to take the permission overrides into account by supplying the channel! + if (!event.getGuild().getSelfMember().hasPermission(webhookContainer, Permission.MANAGE_WEBHOOKS)) + { + noWebhookCallback.run(); + return; + } + + // We can use webhooks! Try to find an existing one, or create one + webhookContainer.retrieveWebhooks().queue(webhooks -> + { + // Try to find an existing webhook, one which we own + for (Webhook webhook : webhooks) + { + if (event.getJDA().getSelfUser().equals(webhook.getOwnerAsUser())) + { + webhookCallback.accept(webhook); + return; + } + } + + // No webhook found, create one and pass it to the callback + webhookContainer.createWebhook("/say webhook").queue(webhookCallback); + }); + } + public void leave(SlashCommandInteractionEvent event) { if (!event.getMember().hasPermission(Permission.KICK_MEMBERS))