From a900e784726051de057edfef5537fc8ec8192578 Mon Sep 17 00:00:00 2001 From: Hammy Date: Tue, 21 Sep 2021 01:47:58 +0100 Subject: [PATCH] I. Don't. Even. Know. --- .../goudham/command/SlashCommandLoader.java | 164 ++++++++++++------ 1 file changed, 115 insertions(+), 49 deletions(-) diff --git a/src/main/java/me/goudham/command/SlashCommandLoader.java b/src/main/java/me/goudham/command/SlashCommandLoader.java index 684c86b7..0cc33bbe 100644 --- a/src/main/java/me/goudham/command/SlashCommandLoader.java +++ b/src/main/java/me/goudham/command/SlashCommandLoader.java @@ -3,31 +3,37 @@ package me.goudham.command; import io.micronaut.context.ApplicationContext; import io.micronaut.context.BeanContext; import io.micronaut.core.annotation.AnnotationValue; -import io.micronaut.core.annotation.Introspected; import io.micronaut.inject.BeanDefinition; +import io.micronaut.inject.qualifiers.Qualifiers; import jakarta.inject.Inject; import jakarta.inject.Singleton; -import java.lang.annotation.Annotation; +import java.lang.reflect.Method; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.OptionalDouble; import java.util.OptionalInt; -import me.goudham.bot.command.ISlashCommand; +import java.util.stream.Collectors; import me.goudham.command.annotation.Choice; import me.goudham.command.annotation.Option; +import me.goudham.command.annotation.SlashCommand; import me.goudham.command.annotation.SubCommand; import me.goudham.command.annotation.SubCommandGroup; +import net.dv8tion.jda.api.events.interaction.SlashCommandEvent; +import net.dv8tion.jda.api.interactions.commands.Command; import net.dv8tion.jda.api.interactions.commands.OptionType; import net.dv8tion.jda.api.interactions.commands.build.CommandData; import net.dv8tion.jda.api.interactions.commands.build.OptionData; import net.dv8tion.jda.api.interactions.commands.build.SubcommandData; import net.dv8tion.jda.api.interactions.commands.build.SubcommandGroupData; +import net.dv8tion.jda.internal.utils.tuple.ImmutablePair; +import net.dv8tion.jda.internal.utils.tuple.Pair; @Singleton -@Introspected public class SlashCommandLoader implements CommandLoader { private final BeanContext beanContext; private final ApplicationContext applicationContext; @@ -40,80 +46,126 @@ public class SlashCommandLoader implements CommandLoader { } @Override - public List loadIntoMapAndReturnCommands(Map commandMap) { - Collection> beanDefinitions = beanContext.getBeanDefinitions(ISlashCommand.class); + public List loadIntoMapAndReturnCommands(Map> commandMap) { + Collection> slashCommandDefinitions = beanContext.getBeanDefinitions(Qualifiers.byStereotype(SlashCommand.class)); + Collection> subCommandGroupDefinitions = beanContext.getBeanDefinitions(Qualifiers.byStereotype(SubCommandGroup.class)); + Collection> subCommandDefinitions = beanContext.getBeanDefinitions(Qualifiers.byStereotype(SubCommand.class)); + Map commandDataMap = new HashMap<>(); List commandDataList = new ArrayList<>(); - for (BeanDefinition beanDefinition : beanDefinitions) { - AnnotationValue slashCommand = beanDefinition.getDeclaredAnnotation("me.goudham.command.annotation.SlashCommand"); + for (BeanDefinition slashCommandDefinition : slashCommandDefinitions) { + AnnotationValue slashCommand = slashCommandDefinition.getDeclaredAnnotation(SlashCommand.class); if (slashCommand != null) { String name = slashCommand.stringValue("name").orElseThrow(); String description = slashCommand.stringValue("description").orElseThrow(); boolean isVisible = slashCommand.booleanValue("isVisible").orElseThrow(); + String[] subCommandGroups = slashCommand.stringValues("subCommandGroups"); + String[] subCommands = slashCommand.stringValues("subCommands"); CommandData commandData = new CommandData(name, description); commandData.setDefaultEnabled(isVisible); - List subcommandGroupDataList = loadSubCommandGroups(slashCommand); - List subcommandData = loadSubCommands(slashCommand); - List optionData = loadOptions(slashCommand); - - if (subcommandGroupDataList != null) commandData.addSubcommandGroups(subcommandGroupDataList); - if (subcommandData != null) commandData.addSubcommands(subcommandData); - if (optionData != null) commandData.addOptions(optionData); + if (subCommandGroups.length == 0 && subCommands.length == 0) { + List optionData = loadOptions(slashCommand); + if (optionData != null) commandData.addOptions(optionData); + + storeIntoCommandMap(commandMap, slashCommandDefinition, name, "handle"); + commandDataMap.put(name, commandData); + } else { + Arrays.stream(subCommandGroups) + .map(subCommandGroup -> name + "/" + subCommandGroup) + .forEach(subCommandGroupName -> commandDataMap.put(subCommandGroupName, commandData)); + Arrays.stream(subCommands) + .map(subCommand -> name + "/" + subCommand) + .forEach(subCommandName -> commandDataMap.put(subCommandName, commandData)); + } commandDataList.add(commandData); - commandMap.put(name, applicationContext.getBean(beanDefinition)); } else { - throw new RuntimeException("Slash Command Annotation For " + beanDefinition + " Was Null"); + throw new RuntimeException("Slash Command Annotation For " + slashCommandDefinition + " Was Null"); } } - return commandDataList; - } - - private List loadSubCommandGroups(AnnotationValue slashCommand) { - if (slashCommand.contains("subCommandGroups")) { - List subcommandGroupDataList = new ArrayList<>(); - List> subCommandGroupAnnotations = slashCommand.getAnnotations("subCommandGroups", SubCommandGroup.class); - for (AnnotationValue subCommandGroup : subCommandGroupAnnotations) { + for (BeanDefinition subCommandGroupDefinition : subCommandGroupDefinitions) { + AnnotationValue subCommandGroup = subCommandGroupDefinition.getDeclaredAnnotation(SubCommandGroup.class); + if (subCommandGroup != null) { + String parent = subCommandGroup.stringValue("parent").orElseThrow(); String name = subCommandGroup.stringValue("name").orElseThrow(); String description = subCommandGroup.stringValue("description").orElseThrow(); + String commandPath = parent + "/" + name; + CommandData commandData = commandDataMap.get(commandPath); SubcommandGroupData subcommandGroupData = new SubcommandGroupData(name, description); - List subcommandData = loadSubCommands(subCommandGroup); - if (subcommandData != null) subcommandGroupData.addSubcommands(subcommandData); - subcommandGroupDataList.add(subcommandGroupData); - } + Class beanType = subCommandGroupDefinition.getBeanType(); + List subCommandList = new ArrayList<>(); + List subCommands = Arrays.stream(beanType.getDeclaredMethods()) + .filter(method -> method.isAnnotationPresent(SubCommand.class)) + .collect(Collectors.toList()); + + for (Method subCommand : subCommands) { + SubCommand annotation = subCommand.getDeclaredAnnotation(SubCommand.class); + String subCommandName = annotation.name(); + String subCommandDescription = annotation.description(); + List optionDataList = Arrays.stream(annotation.options()) + .map(option -> { + OptionData optionData = new OptionData(option.optionType(), option.name(), option.description(), option.isRequired()); + List choiceDataList = Arrays.stream(option.choices()) + .map(choice -> { + int intValue = (int) choice.intValue(); + double doubleValue = choice.doubleValue(); + String stringValue = choice.stringValue(); + + Command.Choice choiceData = null; + if (intValue != 0) { + choiceData = new Command.Choice(name, intValue); + } else if (!Double.isNaN(doubleValue)) { + choiceData = new Command.Choice(name, doubleValue); + } else if (!stringValue.isBlank()) { + choiceData = new Command.Choice(name, stringValue); + } + + return choiceData; + }).collect(Collectors.toList()); + return optionData.addChoices(choiceDataList); + }).collect(Collectors.toList()); + + SubcommandData subcommandData = new SubcommandData(subCommandName, subCommandDescription); + subcommandData.addOptions(optionDataList); + subCommandList.add(subcommandData); + + String subCommandPath = parent + "/" + name + "/" + subCommandName; + storeIntoCommandMap(commandMap, subCommandGroupDefinition, subCommandPath, subCommandName); + commandDataMap.put(subCommandPath, commandData); + } - return subcommandGroupDataList; + subcommandGroupData.addSubcommands(subCommandList); + commandData.addSubcommandGroups(subcommandGroupData); + } else { + throw new RuntimeException("Sub Command Annotation For " + subCommandGroupDefinition + " Was Null"); + } } - return null; - } - - private List loadSubCommands(AnnotationValue slashCommand) { - if (slashCommand.contains("subCommands")) { - List subcommandDataList = new ArrayList<>(); - List> subCommandAnnotations = slashCommand.getAnnotations("subCommands", SubCommand.class); - - for (AnnotationValue subCommand : subCommandAnnotations) { + for (BeanDefinition subCommandDefinition : subCommandDefinitions) { + AnnotationValue subCommand = subCommandDefinition.getDeclaredAnnotation(SubCommand.class); + if (subCommand != null) { + String commandParent = subCommand.stringValue("commandParent").orElseThrow(); String name = subCommand.stringValue("name").orElseThrow(); String description = subCommand.stringValue("description").orElseThrow(); + String commandPath = commandParent + "/" + name; - SubcommandData subCommandData = new SubcommandData(name, description); + CommandData commandData = commandDataMap.get(commandPath); + SubcommandData subcommandData = new SubcommandData(name, description); List optionData = loadOptions(subCommand); - if (optionData != null) subCommandData.addOptions(optionData); - + if (optionData != null) subcommandData.addOptions(optionData); - subcommandDataList.add(subCommandData); + storeIntoCommandMap(commandMap, subCommandDefinition, commandPath, "handle"); + commandData.addSubcommands(subcommandData); + } else { + throw new RuntimeException("Sub Command Annotation For " + subCommandDefinition + " Was Null"); } - - return subcommandDataList; } - - return null; + return commandDataList; } private List loadOptions(AnnotationValue slashCommand) { @@ -131,7 +183,7 @@ public class SlashCommandLoader implements CommandLoader { List choiceList = loadChoices(option); if (choiceList != null) optionData.addChoices(choiceList); - optionList.add(optionData); + optionList.add(optionData); } return optionList; @@ -168,7 +220,7 @@ public class SlashCommandLoader implements CommandLoader { } if (intValue != 0) { - choiceData = new net.dv8tion.jda.api.interactions.commands.Command.Choice(name, intValue); + choiceData = new net.dv8tion.jda.api.interactions.commands.Command.Choice(name, intValue); } else if (!Double.isNaN(doubleValue)) { choiceData = new net.dv8tion.jda.api.interactions.commands.Command.Choice(name, doubleValue); } else if (!stringValue.isBlank()) { @@ -183,4 +235,18 @@ public class SlashCommandLoader implements CommandLoader { return null; } + + private void storeIntoCommandMap(Map> commandMap, BeanDefinition beanDefinition, String commandPath, String methodName) { + Class clazz = beanDefinition.getBeanType(); + Object bean = applicationContext.getBean(clazz); + + Method method = null; + try { + method = clazz.getMethod(methodName, SlashCommandEvent.class); + } catch (NoSuchMethodException e) { + e.printStackTrace(); + } + + commandMap.put(commandPath, new ImmutablePair<>(bean, method)); + } }