package cc.fascinated.bat.service; import cc.fascinated.bat.command.BatCommand; import cc.fascinated.bat.command.BatSubCommand; import cc.fascinated.bat.common.EmbedUtils; import cc.fascinated.bat.features.scoresaber.command.numberone.NumberOneFeedCommand; import cc.fascinated.bat.features.scoresaber.command.scoresaber.ScoreSaberCommand; import cc.fascinated.bat.features.scoresaber.command.userfeed.UserFeedCommand; import cc.fascinated.bat.model.BatGuild; import cc.fascinated.bat.model.BatUser; import lombok.NonNull; import lombok.extern.log4j.Log4j2; import net.dv8tion.jda.api.JDA; import net.dv8tion.jda.api.entities.Guild; import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; import net.dv8tion.jda.api.hooks.ListenerAdapter; import org.jetbrains.annotations.NotNull; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.DependsOn; import org.springframework.stereotype.Service; import java.util.HashMap; import java.util.Map; /** * @author Fascinated (fascinated7) */ @Service @Log4j2 @DependsOn("discordService") public class CommandService extends ListenerAdapter { /** * The registered commands */ private final Map commands = new HashMap<>(); /** * The guild service to use */ private final GuildService guildService; /** * The user service to use */ private final UserService userService; @Autowired public CommandService(@NonNull GuildService guildService, @NonNull UserService userService, @NonNull ApplicationContext context) { this.guildService = guildService; this.userService = userService; DiscordService.JDA.addEventListener(this); // Guild commands registerCommand(context.getBean(UserFeedCommand.class)); registerCommand(context.getBean(NumberOneFeedCommand.class)); // Global commands registerCommand(context.getBean(ScoreSaberCommand.class)); registerSlashCommands(); // Register all slash commands } /** * Registers a command * * @param command The command to register */ public void registerCommand(@NonNull BatCommand command) { commands.put(command.getName().toLowerCase(), command); } /** * Registers all slash commands */ public void registerSlashCommands() { log.info("Registering all slash commands"); JDA jda = DiscordService.JDA; long before = System.currentTimeMillis(); // Unregister all commands that Discord has but we don't jda.retrieveCommands().complete().forEach(command -> { if (commands.containsKey(command.getName())) { return; } jda.deleteCommandById(command.getId()).complete(); // Unregister the command on Discord log.info("Unregistered unknown command \"{}\" from Discord", command.getName()); }); // Register all commands jda.updateCommands().addCommands(commands.values().stream().map(BatCommand::getCommandData).toList()).complete(); log.info("Registered all slash commands in {}ms", System.currentTimeMillis() - before); } @Override public void onSlashCommandInteraction(@NotNull SlashCommandInteractionEvent event) { Guild discordGuild = event.getGuild(); if (discordGuild == null || event.getUser().isBot() || event.getMember() == null) { return; } String commandName = event.getName(); BatCommand command = commands.get(commandName); if (command == null) { return; } BatGuild guild = guildService.getGuild(discordGuild.getId()); BatUser user = userService.getUser(event.getUser().getId()); try { // No args provided, use the main command executor if (event.getInteraction().getSubcommandName() == null) { command.execute(guild, user, event.getChannel().asTextChannel(), event.getMember(), event.getInteraction()); return; } // Subcommand provided, use the subcommand executor for (Map.Entry subCommand : command.getSubCommands().entrySet()) { if (subCommand.getKey().equalsIgnoreCase(event.getInteraction().getSubcommandName())) { subCommand.getValue().execute(guild, user, event.getChannel().asTextChannel(), event.getMember(), event.getInteraction()); break; } } } catch (Exception ex) { log.error("An error occurred while executing command \"{}\"", commandName, ex); event.replyEmbeds(EmbedUtils.buildErrorEmbed("An error occurred while executing the command\n\n" + ex.getLocalizedMessage()).build()).queue(); } } }