From a7c3e2d74535a31f3ae6c04840d464cd290d8d4d Mon Sep 17 00:00:00 2001 From: Liam Date: Thu, 27 Jun 2024 16:01:27 +0100 Subject: [PATCH] impl basic help command --- src/main/java/cc/fascinated/bat/Consts.java | 9 ++ .../cc/fascinated/bat/command/BatCommand.java | 29 +++++- .../cc/fascinated/bat/command/Category.java | 39 ++++++++ .../bat/command/impl/HelpCommand.java | 89 +++++++++++++++++++ .../bat/command/impl/InviteCommand.java | 5 +- .../bat/command/impl/fun/CatCommand.java | 4 +- .../bat/command/impl/fun/DogCommand.java | 4 +- .../fascinated/bat/event/EventListener.java | 9 ++ .../cc/fascinated/bat/features/Feature.java | 24 +++-- .../bat/features/afk/AfkFeature.java | 3 +- .../features/autorole/AutoRoleFeature.java | 1 + .../features/birthday/BirthdayFeature.java | 3 +- .../scoresaber/ScoreSaberFeature.java | 7 +- .../bat/service/CommandService.java | 9 +- .../fascinated/bat/service/EventService.java | 14 +++ 15 files changed, 219 insertions(+), 30 deletions(-) create mode 100644 src/main/java/cc/fascinated/bat/Consts.java create mode 100644 src/main/java/cc/fascinated/bat/command/Category.java create mode 100644 src/main/java/cc/fascinated/bat/command/impl/HelpCommand.java diff --git a/src/main/java/cc/fascinated/bat/Consts.java b/src/main/java/cc/fascinated/bat/Consts.java new file mode 100644 index 0000000..06dca16 --- /dev/null +++ b/src/main/java/cc/fascinated/bat/Consts.java @@ -0,0 +1,9 @@ +package cc.fascinated.bat; + +/** + * @author Fascinated (fascinated7) + */ +public class Consts { + public static final String INVITE_URL = "https://discord.com/oauth2/authorize?client_id=1254161119975833652&permissions=8&integration_type=0&scope=bot+applications.commands"; + public static final String SUPPORT_INVITE_URL = "https://discord.gg/invite/yjj2U3ctEG"; +} diff --git a/src/main/java/cc/fascinated/bat/command/BatCommand.java b/src/main/java/cc/fascinated/bat/command/BatCommand.java index 670243e..4948619 100644 --- a/src/main/java/cc/fascinated/bat/command/BatCommand.java +++ b/src/main/java/cc/fascinated/bat/command/BatCommand.java @@ -18,6 +18,11 @@ import java.util.Map; */ @Getter @Setter public abstract class BatCommand implements BatCommandExecutor { + /** + * The category of the command + */ + private Category category; + /** * The name of the command */ @@ -43,7 +48,13 @@ public abstract class BatCommand implements BatCommandExecutor { */ private final Map subCommands = new HashMap<>(); - public BatCommand(@NonNull String name, @NonNull String description, boolean guildOnly, Permission... permissions) { + /** + * The commands snowflake from Discord + */ + private long commandSnowflake; + + public BatCommand(@NonNull Category category, @NonNull String name, @NonNull String description, boolean guildOnly, Permission... permissions) { + this.category = category; this.name = name; this.description = description; this.requiredPermissions = List.of(permissions); @@ -52,12 +63,24 @@ public abstract class BatCommand implements BatCommandExecutor { .setGuildOnly(guildOnly); } + public BatCommand(@NonNull Category category, @NonNull String name) { + this(category, name, "No description provided.", false); + } + + public BatCommand(@NonNull Category category, @NonNull String name, @NonNull String description) { + this(category, name, description, false); + } + + public BatCommand(@NonNull String name, @NonNull String description, boolean guildOnly, Permission... permissions) { + this(Category.GENERAL, name, description, guildOnly, permissions); + } + public BatCommand(@NonNull String name) { - this(name, "No description provided.", false); + this(Category.GENERAL, name, "No description provided.", false); } public BatCommand(@NonNull String name, @NonNull String description) { - this(name, description, false); + this(Category.GENERAL, name, description, false); } /** diff --git a/src/main/java/cc/fascinated/bat/command/Category.java b/src/main/java/cc/fascinated/bat/command/Category.java new file mode 100644 index 0000000..d4545df --- /dev/null +++ b/src/main/java/cc/fascinated/bat/command/Category.java @@ -0,0 +1,39 @@ +package cc.fascinated.bat.command; + +/** + * @author Fascinated (fascinated7) + */ + +import lombok.AllArgsConstructor; +import lombok.Getter; +import net.dv8tion.jda.api.entities.emoji.Emoji; + +/** + * The category of the command + */ +@AllArgsConstructor @Getter +public enum Category { + GENERAL(Emoji.fromUnicode("U+2699"), "General"), + FUN(Emoji.fromFormatted("U+1F973"), "Fun"), + SERVER(Emoji.fromFormatted("U+1F5A5"), "Server"), + BEAT_SABER(Emoji.fromFormatted("U+1FA84"), "Beat Saber"); + + /** + * The emoji for the category + */ + private final Emoji emoji; + + /** + * The name of the category + */ + private final String name; + + public static Category getByName(String name) { + for (Category category : Category.values()) { + if (category.getName().equalsIgnoreCase(name)) { + return category; + } + } + return null; + } +} diff --git a/src/main/java/cc/fascinated/bat/command/impl/HelpCommand.java b/src/main/java/cc/fascinated/bat/command/impl/HelpCommand.java new file mode 100644 index 0000000..187095c --- /dev/null +++ b/src/main/java/cc/fascinated/bat/command/impl/HelpCommand.java @@ -0,0 +1,89 @@ +package cc.fascinated.bat.command.impl; + +import cc.fascinated.bat.Consts; +import cc.fascinated.bat.command.BatCommand; +import cc.fascinated.bat.command.Category; +import cc.fascinated.bat.common.EmbedUtils; +import cc.fascinated.bat.event.EventListener; +import cc.fascinated.bat.model.BatGuild; +import cc.fascinated.bat.model.BatUser; +import cc.fascinated.bat.service.CommandService; +import lombok.NonNull; +import net.dv8tion.jda.api.entities.Member; +import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel; +import net.dv8tion.jda.api.events.interaction.component.StringSelectInteractionEvent; +import net.dv8tion.jda.api.interactions.commands.SlashCommandInteraction; +import net.dv8tion.jda.api.interactions.components.ActionRow; +import net.dv8tion.jda.api.interactions.components.buttons.Button; +import net.dv8tion.jda.api.interactions.components.buttons.ButtonStyle; +import net.dv8tion.jda.api.interactions.components.selections.SelectOption; +import net.dv8tion.jda.api.interactions.components.selections.StringSelectMenu; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.Arrays; + +/** + * @author Fascinated (fascinated7) + */ +@Component +public class HelpCommand extends BatCommand implements EventListener { + private final CommandService commandService; + + @Autowired + public HelpCommand(@NonNull CommandService commandService) { + super("help", "View the bots command categories."); + this.commandService = commandService; + } + + @Override + public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction interaction) { + String categories = ""; + for (Category category : Category.values()) { + long commandCount = commandService.getCommands().values().stream().filter(command -> command.getCategory() == category).count(); + categories += "**%s** - %s Commands\n".formatted(category.getName(), commandCount); + } + + SelectOption[] options = Arrays.stream(Category.values()).map(category -> + SelectOption.of(category.getName(), category.getName()).withEmoji(category.getEmoji())) + .toArray(SelectOption[]::new); + + interaction.replyEmbeds(EmbedUtils.genericEmbed() + .setDescription("Here are the available command categories: \n\n" + categories) + .build()).addComponents( + ActionRow.of( + Button.of(ButtonStyle.LINK, Consts.INVITE_URL, "Invite"), + Button.of(ButtonStyle.LINK, Consts.SUPPORT_INVITE_URL, "Support") + ), + ActionRow.of( + StringSelectMenu.create("help-menu") + .addOptions(options) + .build() + ) + ).queue(); + } + + @Override + public void onStringSelectInteraction(BatGuild guild, @NonNull BatUser user, @NonNull StringSelectInteractionEvent event) { + Category category = Category.getByName(event.getSelectedOptions().get(0).getValue()); + if (category == null) { + event.reply("Invalid category selected.").queue(); + return; + } + + String commands = ""; + for (BatCommand command : commandService.getCommands().values()) { + if (command.getCategory() == category) { + commands += " - %s\n".formatted( + command.getName(), + command.getCommandSnowflake(), + command.getDescription() + ); + } + } + + event.editMessageEmbeds(EmbedUtils.genericEmbed() + .setDescription("The available commands in the **%s** category: \n\n%s".formatted(category.getName(), commands)) + .build()).queue(); + } +} diff --git a/src/main/java/cc/fascinated/bat/command/impl/InviteCommand.java b/src/main/java/cc/fascinated/bat/command/impl/InviteCommand.java index 53e1d5a..aedb2cf 100644 --- a/src/main/java/cc/fascinated/bat/command/impl/InviteCommand.java +++ b/src/main/java/cc/fascinated/bat/command/impl/InviteCommand.java @@ -1,5 +1,6 @@ package cc.fascinated.bat.command.impl; +import cc.fascinated.bat.Consts; import cc.fascinated.bat.command.BatCommand; import cc.fascinated.bat.common.EmbedUtils; import cc.fascinated.bat.model.BatGuild; @@ -15,8 +16,6 @@ import org.springframework.stereotype.Component; */ @Component public class InviteCommand extends BatCommand { - private static final String INVITE_URL = "https://discord.com/oauth2/authorize?client_id=1254161119975833652&permissions=8&integration_type=0&scope=bot+applications.commands"; - public InviteCommand() { super("invite", "Invite the bot to your server!"); } @@ -24,7 +23,7 @@ public class InviteCommand extends BatCommand { @Override public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction interaction) { interaction.replyEmbeds(EmbedUtils.genericEmbed() - .setDescription("You can invite the bot to your server by clicking [here](%s)".formatted(INVITE_URL)) + .setDescription("You can invite the bot to your server by clicking [here](%s)".formatted(Consts.INVITE_URL)) .build()) .setEphemeral(true) .queue(); diff --git a/src/main/java/cc/fascinated/bat/command/impl/fun/CatCommand.java b/src/main/java/cc/fascinated/bat/command/impl/fun/CatCommand.java index 2db32c1..a534f7d 100644 --- a/src/main/java/cc/fascinated/bat/command/impl/fun/CatCommand.java +++ b/src/main/java/cc/fascinated/bat/command/impl/fun/CatCommand.java @@ -1,6 +1,7 @@ package cc.fascinated.bat.command.impl.fun; import cc.fascinated.bat.command.BatCommand; +import cc.fascinated.bat.command.Category; import cc.fascinated.bat.common.EmbedUtils; import cc.fascinated.bat.common.WebRequest; import cc.fascinated.bat.model.BatGuild; @@ -10,7 +11,6 @@ import lombok.NonNull; import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel; import net.dv8tion.jda.api.interactions.commands.SlashCommandInteraction; -import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Component; /** @@ -19,7 +19,7 @@ import org.springframework.stereotype.Component; @Component public class CatCommand extends BatCommand { public CatCommand() { - super("cat", "Get a random cat image"); + super(Category.FUN, "cat", "Get a random cat image"); } @Override diff --git a/src/main/java/cc/fascinated/bat/command/impl/fun/DogCommand.java b/src/main/java/cc/fascinated/bat/command/impl/fun/DogCommand.java index b6ef285..befa8fb 100644 --- a/src/main/java/cc/fascinated/bat/command/impl/fun/DogCommand.java +++ b/src/main/java/cc/fascinated/bat/command/impl/fun/DogCommand.java @@ -1,12 +1,12 @@ package cc.fascinated.bat.command.impl.fun; import cc.fascinated.bat.command.BatCommand; +import cc.fascinated.bat.command.Category; import cc.fascinated.bat.common.EmbedUtils; import cc.fascinated.bat.common.WebRequest; import cc.fascinated.bat.model.BatGuild; import cc.fascinated.bat.model.BatUser; import cc.fascinated.bat.model.token.dogceo.RandomImage; -import cc.fascinated.bat.model.token.thecatapi.CatImageToken; import lombok.NonNull; import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel; @@ -19,7 +19,7 @@ import org.springframework.stereotype.Component; @Component public class DogCommand extends BatCommand { public DogCommand() { - super("dog", "Get a random dog image"); + super(Category.FUN, "dog", "Get a random dog image"); } @Override diff --git a/src/main/java/cc/fascinated/bat/event/EventListener.java b/src/main/java/cc/fascinated/bat/event/EventListener.java index 2befe95..6a9c3ff 100644 --- a/src/main/java/cc/fascinated/bat/event/EventListener.java +++ b/src/main/java/cc/fascinated/bat/event/EventListener.java @@ -8,6 +8,7 @@ import cc.fascinated.bat.model.token.beatsaber.scoresaber.ScoreSaberScoreToken; import lombok.NonNull; import net.dv8tion.jda.api.events.guild.member.GuildMemberJoinEvent; import net.dv8tion.jda.api.events.guild.member.GuildMemberRemoveEvent; +import net.dv8tion.jda.api.events.interaction.component.StringSelectInteractionEvent; import net.dv8tion.jda.api.events.message.MessageReceivedEvent; /** @@ -47,4 +48,12 @@ public interface EventListener { * @param user the user that sent the message */ default void onGuildMessageReceive(@NonNull BatGuild guild, @NonNull BatUser user, @NonNull MessageReceivedEvent event) {} + + /** + * Called when a user selects a string + * + * @param guild the guild that the string was selected in + * @param user the user that selected the string + */ + default void onStringSelectInteraction(BatGuild guild, @NonNull BatUser user, @NonNull StringSelectInteractionEvent event) {} } diff --git a/src/main/java/cc/fascinated/bat/features/Feature.java b/src/main/java/cc/fascinated/bat/features/Feature.java index f2db86e..0fc395c 100644 --- a/src/main/java/cc/fascinated/bat/features/Feature.java +++ b/src/main/java/cc/fascinated/bat/features/Feature.java @@ -1,7 +1,10 @@ package cc.fascinated.bat.features; -import lombok.AllArgsConstructor; +import cc.fascinated.bat.command.BatCommand; +import cc.fascinated.bat.command.Category; +import cc.fascinated.bat.service.CommandService; import lombok.Getter; +import lombok.NonNull; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Component; @@ -23,18 +26,13 @@ public abstract class Feature { private final Category category; /** - * The category of the feature + * Registers the command for the feature + * + * @param commandService The command service + * @param command The command to register */ - @AllArgsConstructor @Getter - public enum Category { - GENERAL("General"), - MODERATION("Moderation"), - SERVER("Server"), - BEAT_SABER("Beat Saber"); - - /** - * The name of the category - */ - private final String name; + public void registerCommand(@NonNull CommandService commandService, @NonNull BatCommand command) { + command.setCategory(category); + commandService.registerCommand(command); } } diff --git a/src/main/java/cc/fascinated/bat/features/afk/AfkFeature.java b/src/main/java/cc/fascinated/bat/features/afk/AfkFeature.java index dd80f05..1e7fcf5 100644 --- a/src/main/java/cc/fascinated/bat/features/afk/AfkFeature.java +++ b/src/main/java/cc/fascinated/bat/features/afk/AfkFeature.java @@ -1,5 +1,6 @@ package cc.fascinated.bat.features.afk; +import cc.fascinated.bat.command.Category; import cc.fascinated.bat.features.Feature; import cc.fascinated.bat.features.afk.command.AfkCommand; import cc.fascinated.bat.service.CommandService; @@ -15,6 +16,6 @@ public class AfkFeature extends Feature { public AfkFeature(@NonNull ApplicationContext context, @NonNull CommandService commandService) { super("AFK", Category.GENERAL); - commandService.registerCommand(context.getBean(AfkCommand.class)); + registerCommand(commandService, context.getBean(AfkCommand.class)); } } diff --git a/src/main/java/cc/fascinated/bat/features/autorole/AutoRoleFeature.java b/src/main/java/cc/fascinated/bat/features/autorole/AutoRoleFeature.java index 2225968..078919f 100644 --- a/src/main/java/cc/fascinated/bat/features/autorole/AutoRoleFeature.java +++ b/src/main/java/cc/fascinated/bat/features/autorole/AutoRoleFeature.java @@ -1,5 +1,6 @@ package cc.fascinated.bat.features.autorole; +import cc.fascinated.bat.command.Category; import cc.fascinated.bat.features.Feature; import cc.fascinated.bat.features.autorole.command.AutoRoleCommand; import cc.fascinated.bat.service.CommandService; diff --git a/src/main/java/cc/fascinated/bat/features/birthday/BirthdayFeature.java b/src/main/java/cc/fascinated/bat/features/birthday/BirthdayFeature.java index 07b5585..0f1befd 100644 --- a/src/main/java/cc/fascinated/bat/features/birthday/BirthdayFeature.java +++ b/src/main/java/cc/fascinated/bat/features/birthday/BirthdayFeature.java @@ -1,5 +1,6 @@ package cc.fascinated.bat.features.birthday; +import cc.fascinated.bat.command.Category; import cc.fascinated.bat.features.Feature; import cc.fascinated.bat.features.birthday.command.BirthdayCommand; import cc.fascinated.bat.features.birthday.profile.BirthdayProfile; @@ -22,7 +23,7 @@ public class BirthdayFeature extends Feature { super("Birthday", Category.GENERAL); this.guildService = guildService; - commandService.registerCommand(context.getBean(BirthdayCommand.class)); + registerCommand(commandService, context.getBean(BirthdayCommand.class)); } /** diff --git a/src/main/java/cc/fascinated/bat/features/scoresaber/ScoreSaberFeature.java b/src/main/java/cc/fascinated/bat/features/scoresaber/ScoreSaberFeature.java index adec925..43df435 100644 --- a/src/main/java/cc/fascinated/bat/features/scoresaber/ScoreSaberFeature.java +++ b/src/main/java/cc/fascinated/bat/features/scoresaber/ScoreSaberFeature.java @@ -1,5 +1,6 @@ package cc.fascinated.bat.features.scoresaber; +import cc.fascinated.bat.command.Category; import cc.fascinated.bat.common.DateUtils; import cc.fascinated.bat.common.EmbedUtils; import cc.fascinated.bat.common.NumberUtils; @@ -27,9 +28,9 @@ public class ScoreSaberFeature extends Feature { public ScoreSaberFeature(@NonNull ApplicationContext context, @NonNull CommandService commandService) { super("ScoreSaber", Category.BEAT_SABER); - commandService.registerCommand(context.getBean(ScoreSaberCommand.class)); - commandService.registerCommand(context.getBean(UserFeedCommand.class)); - commandService.registerCommand(context.getBean(NumberOneFeedCommand.class)); + registerCommand(commandService, context.getBean(ScoreSaberCommand.class)); + registerCommand(commandService, context.getBean(UserFeedCommand.class)); + registerCommand(commandService, context.getBean(NumberOneFeedCommand.class)); } /** diff --git a/src/main/java/cc/fascinated/bat/service/CommandService.java b/src/main/java/cc/fascinated/bat/service/CommandService.java index 5aee29a..5667b9e 100644 --- a/src/main/java/cc/fascinated/bat/service/CommandService.java +++ b/src/main/java/cc/fascinated/bat/service/CommandService.java @@ -6,6 +6,7 @@ import cc.fascinated.bat.command.BatSubCommand; import cc.fascinated.bat.common.EmbedUtils; import cc.fascinated.bat.model.BatGuild; import cc.fascinated.bat.model.BatUser; +import lombok.Getter; import lombok.NonNull; import lombok.extern.log4j.Log4j2; import net.dv8tion.jda.api.JDA; @@ -13,6 +14,7 @@ import net.dv8tion.jda.api.Permission; import net.dv8tion.jda.api.entities.Guild; import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; import net.dv8tion.jda.api.hooks.ListenerAdapter; +import net.dv8tion.jda.api.interactions.commands.Command; import org.jetbrains.annotations.NotNull; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.DependsOn; @@ -27,7 +29,7 @@ import java.util.Map; * @author Fascinated (fascinated7) */ @Service -@Log4j2 +@Log4j2 @Getter @DependsOn("discordService") public class CommandService extends ListenerAdapter { /** @@ -84,7 +86,10 @@ public class CommandService extends ListenerAdapter { }); // Register all commands - jda.updateCommands().addCommands(commands.values().stream().map(BatCommand::getCommandData).toList()).complete(); + List discordCommands = jda.updateCommands().addCommands(commands.values().stream().map(BatCommand::getCommandData).toList()).complete(); + for (Command discordCommand : discordCommands) { + commands.get(discordCommand.getName()).setCommandSnowflake(discordCommand.getIdLong()); + } log.info("Registered all slash commands in {}ms", System.currentTimeMillis() - before); } diff --git a/src/main/java/cc/fascinated/bat/service/EventService.java b/src/main/java/cc/fascinated/bat/service/EventService.java index 4810e00..4e80322 100644 --- a/src/main/java/cc/fascinated/bat/service/EventService.java +++ b/src/main/java/cc/fascinated/bat/service/EventService.java @@ -7,6 +7,7 @@ import lombok.NonNull; import lombok.extern.log4j.Log4j2; import net.dv8tion.jda.api.events.guild.member.GuildMemberJoinEvent; import net.dv8tion.jda.api.events.guild.member.GuildMemberRemoveEvent; +import net.dv8tion.jda.api.events.interaction.component.StringSelectInteractionEvent; import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import net.dv8tion.jda.api.hooks.ListenerAdapter; import org.jetbrains.annotations.NotNull; @@ -89,4 +90,17 @@ public class EventService extends ListenerAdapter { listener.onGuildMessageReceive(guild, user, event); } } + + @Override + public void onStringSelectInteraction(StringSelectInteractionEvent event) { + if (event.getUser().isBot()) { + return; + } + BatGuild guild = event.getGuild() != null ? guildService.getGuild(event.getGuild().getId()) : null; + BatUser user = userService.getUser(event.getUser().getId()); + + for (EventListener listener : LISTENERS) { + listener.onStringSelectInteraction(guild, user, event); + } + } }