package net.tylermurphy.ken.command; import net.dv8tion.jda.api.EmbedBuilder; import net.dv8tion.jda.api.JDA; import net.dv8tion.jda.api.entities.Guild; import net.dv8tion.jda.api.entities.GuildMessageChannel; import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.Message; import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; import net.dv8tion.jda.api.events.interaction.component.ButtonInteractionEvent; import net.dv8tion.jda.api.hooks.ListenerAdapter; import net.dv8tion.jda.api.interactions.commands.build.Commands; import net.dv8tion.jda.api.interactions.commands.build.OptionData; import net.dv8tion.jda.api.interactions.commands.build.SlashCommandData; import net.dv8tion.jda.api.interactions.components.buttons.Button; import net.dv8tion.jda.api.requests.restaction.WebhookMessageAction; import net.tylermurphy.ken.Ken; import net.tylermurphy.ken.util.*; import org.reflections.Reflections; import org.reflections.scanners.MethodAnnotationsScanner; import java.awt.*; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.*; import java.util.List; public class Responder extends ListenerAdapter { private final Map register; private final JDA api; public Responder(JDA api) { this.register = new HashMap<>(); this.api = api; } public void registerCommands() throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException { // Reset register register.clear(); // Get all Methods that use the @Command annotation for (Method method : new Reflections("net.tylermurphy.ken.command", new MethodAnnotationsScanner()).getMethodsAnnotatedWith(Command.class)) { if(method.getReturnType() != Response.class) continue; // Register Main Command Information If Not Already Registered; Command command = method.getAnnotation(Command.class); if (register.containsKey(command.name())) continue; // Create Command Container Container container = new Container(method); // Check For Permissions if (method.isAnnotationPresent(Requirement.class)) container.setPermission(method.getAnnotation(Requirement.class).value()); // Add Command To Register register.put(command.name(), container); // Create Slash Command Data SlashCommandData data = Commands.slash(command.name(), command.description()); // Add Options to Slash Command Data if @Option is used if(method.isAnnotationPresent(Options.class)) { Option[] options = method.getAnnotation(Options.class).value(); for(Option option : options){ data = data.addOption(option.type(), option.name(), option.description(), option.required()); } } else if (method.isAnnotationPresent(Option.class)) { Option option = method.getAnnotation(Option.class); data = data.addOption(option.type(), option.name(), option.description(), option.required()); } if(method.isAnnotationPresent(Selections.class)){ Selection[] selections = method.getAnnotation(Selections.class).value(); for(Selection selection : selections){ OptionData optionData = new OptionData(selection.type(), selection.name(), selection.description(), selection.required()); Arrays.stream(selection.choices()).forEach(choice -> optionData.addChoice(choice, choice.toLowerCase(Locale.ROOT))); data.addOptions(optionData); } } else if(method.isAnnotationPresent(Selection.class)){ Selection selection = method.getAnnotation(Selection.class); OptionData optionData = new OptionData(selection.type(), selection.name(), selection.description(), selection.required()); Arrays.stream(selection.choices()).forEach(choice -> optionData.addChoice(choice, choice.toLowerCase(Locale.ROOT))); data.addOptions(optionData); } api.upsertCommand(data).queue(); } // Get all Methods that use the @ButtonCallback annotation for (Method method : new Reflections("net.tylermurphy.ken.command", new MethodAnnotationsScanner()).getMethodsAnnotatedWith(ButtonCallback.class)) { if(method.getReturnType() != Response.class) continue; ButtonCallback callback = method.getAnnotation(ButtonCallback.class); if(!register.containsKey(callback.name())) continue; Container container = register.get(callback.name()); container.setButtonCallback(method); register.put(callback.name(), container); } } public void onSlashCommandInteraction(SlashCommandInteractionEvent event) { // Make sure the Bot can Talk if(!event.getChannel().canTalk()) return; // Bots are not allowed to use commands if (event.getMember() == null || event.getUser().isBot()) return; // Get Command Information From Invoke final String invoke = event.getName().toLowerCase(Locale.ROOT); if(!register.containsKey(invoke)) return; Container container = register.get(invoke); Method method = container.getMethod(); // Check Permissions if(!event.getMember().hasPermission(container.getPermission())) { EmbedBuilder builder = Ken.getInstance().getDefaultEmbed() .appendDescription(":x: **Invalid Permissions**\n") .appendDescription("You require the "+ container.getPermission().toString()+" permission to use this command."); event.getHook().sendMessageEmbeds(builder.build()).queue(); return; } // Defer Reply event.deferReply().queue(); // Get slash command options if there are any List args = new ArrayList<>(); event.getOptions().forEach(option -> { switch (option.getType()){ case STRING: args.add(option.getAsString()); break; case INTEGER: args.add(option.getAsInt()); break; case BOOLEAN: args.add(option.getAsBoolean()); break; case USER: args.add(option.getAsMember()); break; case CHANNEL: args.add(option.getAsChannel()); break; case ROLE: args.add(option.getAsRole()); break; case MENTIONABLE: args.add(option.getAsMentionable()); break; default: break; } }); // Get parameters to send to Method Object[] parameters = new Object[method.getParameterTypes().length]; Class[] types = method.getParameterTypes(); for(int i = 0; i < types.length; i++){ if(types[i] == Member.class){ parameters[i] = event.getMember(); } else if(types[i] == GuildMessageChannel.class){ parameters[i] = event.getGuildChannel(); } else if(types[i] == Guild.class) { parameters[i] = event.getGuild(); } else if(types[i] == List.class) { parameters[i] = args; } else { parameters[i] = null; } } // Invoke Method and Respond to User try { Object temp = method.invoke(container.getHandle(), parameters); Response response = (Response)temp; if(response.error()) { EmbedBuilder builder = Ken.getInstance().getDefaultEmbed() .setColor(Color.RED) .setTitle(":x: **Error**") .setDescription(response.getMessage()); event.getHook().sendMessageEmbeds(builder.build()).queue(); } else { WebhookMessageAction message; if(response.hasEmbed()) { message = event.getHook().sendMessageEmbeds(response.getEmbeds()); } else { message = event.getHook().sendMessage(response.getMessage()); } if(response.hasButtons()) message = message.addActionRow(response.getButtons()); if(response.hasFile()) message = message.addFile(response.getFile()); message.queue(); } } catch (Exception e) { EmbedBuilder builder = Ken.getInstance().getDefaultEmbed() .setColor(Color.RED) .setTitle(":x: **Error**") .setDescription(e.getMessage()); event.getHook().sendMessageEmbeds(builder.build()).queue(); e.printStackTrace(); } } public void onButtonInteraction(ButtonInteractionEvent event) { // Make sure the Bot can Talk if(!event.getChannel().canTalk()) return; // Bots are not allowed to use commands if (event.getMember() == null || event.getUser().isBot()) return; // Get Command Information From Invoke final String invoke = event.getComponentId().toLowerCase(Locale.ROOT).split("_")[0]; if(!register.containsKey(invoke)) return; Container container = register.get(invoke); Method method = container.getButtonCallback(); // Defer Reply event.deferEdit().queue(); // Get parameters to send to Method Object[] parameters = new Object[method.getParameterTypes().length]; Class[] types = method.getParameterTypes(); for(int i = 0; i < types.length; i++){ if(types[i] == Member.class){ parameters[i] = event.getMember(); } else if(types[i] == GuildMessageChannel.class){ parameters[i] = event.getGuildChannel(); } else if(types[i] == Guild.class) { parameters[i] = event.getGuild(); } else if(types[i] == Button.class) { parameters[i] = event.getButton(); } else if(types[i] == Message.class) { parameters[i] = event.getMessage(); } else if(types[i] == String.class) { parameters[i] = event.getComponentId().substring(invoke.length()+1); } else { parameters[i] = null; } } // Invoke Method and Respond to User try { Object temp = method.invoke(container.getHandle(), parameters); Response response = (Response) temp; if(response.error()) { EmbedBuilder builder = Ken.getInstance().getDefaultEmbed() .setColor(Color.RED) .setTitle(":x: **Error**") .setDescription(response.getMessage()); event.getHook().sendMessageEmbeds(builder.build()).queue(); } else { if(response.hasEmbed()) { event.getHook().editOriginalEmbeds(response.getEmbeds()).queue(); } else { event.getHook().editOriginal(response.getMessage()).queue(); } } } catch (Exception e) { event.getHook().sendMessage(e.getMessage()).queue(); e.printStackTrace(); } } }