diff --git a/.gitignore b/.gitignore index 054870a..3c7663d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,26 +1,128 @@ +# ---> Java +# Compiled class file +*.class +# Log file +*.log +# BlueJ files +*.ctxt +# Mobile Tools for Java (J2ME) +.mtj.tmp/ +# Package Files # +*.jar +*.war +*.nar +*.ear +*.zip +*.tar.gz +*.rar +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml +hs_err_pid* +replay_pid* +# ---> Windows +# Windows thumbnail cache files +Thumbs.db +Thumbs.db:encryptable +ehthumbs.db +ehthumbs_vista.db +# Dump file +*.stackdump +# Folder config file +[Dd]esktop.ini +# Recycle Bin used on file shares +$RECYCLE.BIN/ +# Windows Installer files +*.cab +*.msi +*.msix +*.msm +*.msp +# Windows shortcuts +*.lnk +# ---> JetBrains +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 +# User-specific stuff +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/**/usage.statistics.xml +.idea/**/dictionaries +.idea/**/shelf +# AWS User-specific +.idea/**/aws.xml +# Generated files +.idea/**/contentModel.xml +# Sensitive or high-churn files +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml +.idea/**/dbnavigator.xml +# Gradle +.idea/**/gradle.xml +.idea/**/libraries +# Gradle and Maven with auto-import +# When using Gradle or Maven with auto-import, you should exclude module files, +# since they will be recreated, and may cause churn. Uncomment if using +# auto-import. +# .idea/artifacts +# .idea/compiler.xml +# .idea/jarRepositories.xml +# .idea/modules.xml +# .idea/*.iml +# .idea/modules +# *.iml +# *.ipr +# CMake +cmake-build-*/ +# Mongo Explorer plugin +.idea/**/mongoSettings.xml +# File-based project format +*.iws +# IntelliJ +out/ +# mpeltonen/sbt-idea plugin +.idea_modules/ +# JIRA plugin +atlassian-ide-plugin.xml +# Cursive Clojure plugin +.idea/replstate.xml +# SonarLint plugin +.idea/sonarlint/ +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties +# Editor-based Rest Client +.idea/httpRequests +# Android studio 3.1+ serialized cache file +.idea/caches/build_file_checksums.ser +# ---> Gradle .gradle -build/ -!gradle/wrapper/gradle-wrapper.jar -!**/src/main/**/build/ -!**/src/test/**/build/ +**/build/ +!src/**/build/ +# Ignore Gradle GUI config +gradle-app.setting +# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored) +!gradle-wrapper.jar +# Cache of project +.gradletasknamecache +# Eclipse Gradle plugin generated files +# Eclipse Core +.project +# JDT-specific (Eclipse Java Development Tools) +.classpath + ### IntelliJ IDEA ### -.idea/modules.xml -.idea/jarRepositories.xml -.idea/compiler.xml -.idea/libraries/ -*.iws -*.iml -*.ipr -out/ !**/src/main/**/out/ !**/src/test/**/out/ ### Eclipse ### .apt_generated -.classpath .factorypath -.project .settings .springBeans .sts4-cache @@ -40,4 +142,9 @@ bin/ ### Mac OS ### .DS_Store -*-config.yml \ No newline at end of file + +# Ignore Gradle build output directory +build + +*-config.yml +modules/ diff --git a/.idea/.name b/.idea/.name new file mode 100644 index 0000000..f23a249 --- /dev/null +++ b/.idea/.name @@ -0,0 +1 @@ +ModularBot \ No newline at end of file diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..b589d56 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml deleted file mode 100644 index e578f4a..0000000 --- a/.idea/gradle.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml new file mode 100644 index 0000000..faf1c28 --- /dev/null +++ b/.idea/jarRepositories.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/workspace.xml b/.idea/workspace.xml deleted file mode 100644 index 00be228..0000000 --- a/.idea/workspace.xml +++ /dev/null @@ -1,56 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - 1660073510005 - - - - - - - \ No newline at end of file diff --git a/src/main/java/tech/nevets/modbot/CoreBot.java b/src/main/java/tech/nevets/modbot/CoreBot.java index 88b1808..4feeeaf 100644 --- a/src/main/java/tech/nevets/modbot/CoreBot.java +++ b/src/main/java/tech/nevets/modbot/CoreBot.java @@ -8,7 +8,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import tech.nevets.modbot.api.BotModule; import tech.nevets.modbot.api.Config; -import tech.nevets.modbot.util.commands.CommandListener; +import tech.nevets.modbot.util.commands.CoreListener; import javax.security.auth.login.LoginException; import java.util.*; @@ -24,10 +24,11 @@ public class CoreBot { CORE_CONFIG.addDefaults(getDefaults()); CORE_CONFIG.loadConfig(); modules = ModuleLoader.loadModules(); + CoreListener coreListener = new CoreListener(); JDABuilder builder = JDABuilder.createDefault(CORE_CONFIG.getConfig().getString("bot.token")) .enableCache(CacheFlag.VOICE_STATE) - .addEventListeners(new CommandListener()); + .addEventListeners(coreListener); for (ListenerAdapter listener : PLUGIN_LISTENERS) { builder.addEventListeners(listener); @@ -39,8 +40,9 @@ public class CoreBot { e.printStackTrace(); } - //CommandManager.registerSlashCommands(); + coreListener.getCommandRegistry().registerSlashCommands(); for (BotModule module : modules) { + module.loadCommandRegistry().registerSlashCommands(); module.onEnable(jda); } @@ -50,6 +52,8 @@ public class CoreBot { PLUGIN_LISTENERS.add(listener); } + + private static Map getDefaults() { Map defaults = new HashMap<>(); defaults.put("bot.token", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"); diff --git a/src/main/java/tech/nevets/modbot/api/BotModule.java b/src/main/java/tech/nevets/modbot/api/BotModule.java index d9fdaa8..a9a815e 100644 --- a/src/main/java/tech/nevets/modbot/api/BotModule.java +++ b/src/main/java/tech/nevets/modbot/api/BotModule.java @@ -1,11 +1,14 @@ package tech.nevets.modbot.api; import net.dv8tion.jda.api.JDA; +import tech.nevets.modbot.api.commands.CommandRegistry; public interface BotModule { default void onPreEnable() {} + CommandRegistry loadCommandRegistry(); + void onEnable(JDA jda); void onDisable(); diff --git a/src/main/java/tech/nevets/modbot/api/commands/CommandRegistry.java b/src/main/java/tech/nevets/modbot/api/commands/CommandRegistry.java new file mode 100644 index 0000000..5fb595a --- /dev/null +++ b/src/main/java/tech/nevets/modbot/api/commands/CommandRegistry.java @@ -0,0 +1,154 @@ +package tech.nevets.modbot.api.commands; + +import net.dv8tion.jda.api.entities.Member; +import net.dv8tion.jda.api.entities.Role; +import net.dv8tion.jda.api.events.interaction.SlashCommandEvent; +import net.dv8tion.jda.api.events.message.guild.GuildMessageReceivedEvent; +import net.dv8tion.jda.api.interactions.commands.build.CommandData; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import tech.nevets.modbot.CoreBot; +import tech.nevets.modbot.util.commands.CommandContext; + +import javax.annotation.Nullable; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.regex.Pattern; + +public class CommandRegistry { + private static final Logger LOGGER = LoggerFactory.getLogger(CommandRegistry.class); + private final List commands = new ArrayList<>(); + private final List prefixCommands = new ArrayList<>(); + private final List slashCommands = new ArrayList<>(); + + public CommandRegistry() {} + + public void addCommand(ICommand cmd) { + boolean nameFound = commands.stream().anyMatch(it -> it.getName().equalsIgnoreCase(cmd.getName())); + if (nameFound) { + throw new IllegalArgumentException("A command with that name is already present!"); + } + + commands.add(cmd); + + if (cmd instanceof IPrefixCommand) { + prefixCommands.add((IPrefixCommand) cmd); + } + + if (cmd instanceof ISlashCommand) { + slashCommands.add((ISlashCommand) cmd); + } + } + + public void registerSlashCommands() { + if (slashCommands.size() > 0) { + List cmdDataList = new ArrayList<>(); + for (ISlashCommand slashCmd : slashCommands) { + cmdDataList.add(slashCmd.getCommandData()); + } + CoreBot.jda.updateCommands().addCommands(cmdDataList).queue(); + } + } + + @Nullable + public IPrefixCommand getPrefixCommand(String search) { + String searchLower = search.toLowerCase(); + + for (IPrefixCommand cmd : prefixCommands) { + if (cmd.getName().equals(searchLower) || cmd.getAliases().contains(searchLower)) { + return cmd; + } + } + return null; + } + + @Nullable + public ISlashCommand getSlashCommand(String search) { + String searchLower = search.toLowerCase(); + + for (ISlashCommand cmd : slashCommands) { + if (cmd.getName().equals(searchLower) || cmd.getAliases().contains(searchLower)) { + return cmd; + } + } + return null; + } + + public List getCommands() { + return commands; + } + + public List getPrefixCommands() { + return prefixCommands; + } + + public List getSlashCommands() { + return slashCommands; + } + + public boolean hasPermission(Member member, ICommand cmd) { + List memberRoles = member.getRoles(); + int permLevel = 0; + + for (Role memberRole : memberRoles) { + switch (memberRole.getName().toLowerCase()) { + case "helper", "1": + if (permLevel < 1) permLevel = 1; + continue; + case "moderator", "mod", "2": + if (permLevel < 2) permLevel = 2; + continue; + case "administrator", "admin", "3": + if (permLevel < 3) permLevel = 3; + continue; + case "owner", "4": + if (permLevel < 4) permLevel = 4; + } + } + return permLevel >= cmd.getPermissionLevel(); + } + + public void handle(GuildMessageReceivedEvent event) { + String[] split = event.getMessage().getContentRaw() + .replaceFirst("(?i)" + Pattern.quote(CoreBot.CORE_CONFIG.getConfig().getString("bot.prefix")), "") + .split("\\s+"); + + String invoke = split[0].toLowerCase(); + IPrefixCommand cmd = getPrefixCommand(invoke); + + assert event.getMember() != null; + if (!hasPermission(event.getMember(), cmd)) { + event.getMessage().reply("You do not have permission to use this command.").queue(); + return; + } + + if (cmd != null) { + event.getChannel().sendTyping().queue(); + List args = Arrays.asList(split).subList(1, split.length); + + CommandContext ctx = new CommandContext(event, args); + + cmd.handle(ctx); + } + } + + public void handle(SlashCommandEvent event) { + String invoke = event.getName(); + ISlashCommand cmd = getSlashCommand(invoke); + + if (cmd != null) { + event.deferReply().queue(); + + assert event.getMember() != null; + if (!hasPermission(event.getMember(), cmd)) { + event.getHook().sendMessage("You do not have permission to use this command.").queue(); + return; + } + + CommandContext ctx = new CommandContext(event); + + cmd.handleSlash(ctx); + } + } +} diff --git a/src/main/java/tech/nevets/modbot/api/commands/ICommand.java b/src/main/java/tech/nevets/modbot/api/commands/ICommand.java index fdbe68d..1220c4e 100644 --- a/src/main/java/tech/nevets/modbot/api/commands/ICommand.java +++ b/src/main/java/tech/nevets/modbot/api/commands/ICommand.java @@ -1,4 +1,22 @@ package tech.nevets.modbot.api.commands; +import java.util.List; + public interface ICommand { + + String getName(); + + /** + * @apiNote 0 = default, 1 = helper, 2 = moderator, 3 = admin, 4 = owner + * @return int + */ + default int getPermissionLevel() { + return 0; + } + + String getHelp(); + + default List getAliases(){ + return List.of(); + } } diff --git a/src/main/java/tech/nevets/modbot/api/commands/IPrefixCommand.java b/src/main/java/tech/nevets/modbot/api/commands/IPrefixCommand.java index 3f01d0a..31db4d2 100644 --- a/src/main/java/tech/nevets/modbot/api/commands/IPrefixCommand.java +++ b/src/main/java/tech/nevets/modbot/api/commands/IPrefixCommand.java @@ -1,4 +1,9 @@ package tech.nevets.modbot.api.commands; +import tech.nevets.modbot.util.commands.CommandContext; + public interface IPrefixCommand extends ICommand { + + void handle(CommandContext ctx); + } diff --git a/src/main/java/tech/nevets/modbot/api/commands/ISlashCommand.java b/src/main/java/tech/nevets/modbot/api/commands/ISlashCommand.java index 6f45f7a..c0f692e 100644 --- a/src/main/java/tech/nevets/modbot/api/commands/ISlashCommand.java +++ b/src/main/java/tech/nevets/modbot/api/commands/ISlashCommand.java @@ -1,4 +1,14 @@ package tech.nevets.modbot.api.commands; +import net.dv8tion.jda.api.interactions.commands.build.CommandData; +import tech.nevets.modbot.util.commands.CommandContext; + public interface ISlashCommand extends ICommand { + + void handleSlash(CommandContext ctx); + + String getDescription(); + + CommandData getCommandData(); + } diff --git a/src/main/java/tech/nevets/modbot/util/commands/CommandContext.java b/src/main/java/tech/nevets/modbot/util/commands/CommandContext.java new file mode 100644 index 0000000..ccb17d4 --- /dev/null +++ b/src/main/java/tech/nevets/modbot/util/commands/CommandContext.java @@ -0,0 +1,36 @@ +package tech.nevets.modbot.util.commands; + +import net.dv8tion.jda.api.events.interaction.SlashCommandEvent; +import net.dv8tion.jda.api.events.message.guild.GuildMessageReceivedEvent; + +import java.util.List; + +public class CommandContext implements ICommandContext { + private GuildMessageReceivedEvent event; + private SlashCommandEvent slashEvent; + private List args; + + public CommandContext(GuildMessageReceivedEvent event, List args) { + this.event = event; + this.args = args; + } + + public CommandContext(SlashCommandEvent slashEvent) { + this.slashEvent = slashEvent; + this.args = null; + } + + @Override + public GuildMessageReceivedEvent getEvent() { + return this.event; + } + + @Override + public SlashCommandEvent getSlashEvent() { + return this.slashEvent; + } + + public List getArgs() { + return this.args; + } +} diff --git a/src/main/java/tech/nevets/modbot/util/commands/CommandListener.java b/src/main/java/tech/nevets/modbot/util/commands/CommandListener.java deleted file mode 100644 index d6c9bea..0000000 --- a/src/main/java/tech/nevets/modbot/util/commands/CommandListener.java +++ /dev/null @@ -1,10 +0,0 @@ -package tech.nevets.modbot.util.commands; - -import net.dv8tion.jda.api.hooks.ListenerAdapter; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class CommandListener extends ListenerAdapter { - private static final Logger LOGGER = LoggerFactory.getLogger(CommandListener.class); - private final CommandManager commandManager = new CommandManager(); -} diff --git a/src/main/java/tech/nevets/modbot/util/commands/CommandManager.java b/src/main/java/tech/nevets/modbot/util/commands/CommandManager.java index dbaa129..3e5f4dc 100644 --- a/src/main/java/tech/nevets/modbot/util/commands/CommandManager.java +++ b/src/main/java/tech/nevets/modbot/util/commands/CommandManager.java @@ -1,9 +1,71 @@ package tech.nevets.modbot.util.commands; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import tech.nevets.modbot.api.commands.CommandRegistry; +import tech.nevets.modbot.api.commands.ICommand; +import tech.nevets.modbot.api.commands.IPrefixCommand; +import tech.nevets.modbot.api.commands.ISlashCommand; + +import javax.annotation.Nullable; +import java.util.ArrayList; +import java.util.List; public class CommandManager { - private static final Logger LOGGER = LoggerFactory.getLogger(CommandManager.class); + public static final List ALL_COMMANDS = new ArrayList<>(); + public static final List ALL_PREFIX_COMMANDS = new ArrayList<>(); + public static final List ALL_SLASH_COMMANDS = new ArrayList<>(); + public static void addFromRegistry(CommandRegistry registry) { + ALL_COMMANDS.addAll(registry.getCommands()); + ALL_PREFIX_COMMANDS.addAll(registry.getPrefixCommands()); + ALL_SLASH_COMMANDS.addAll(registry.getSlashCommands()); + } + + @Nullable + public static ICommand getCommand(String search) { + String searchLower = search.toLowerCase(); + + for (ICommand cmd : ALL_COMMANDS) { + if (cmd.getName().equals(searchLower) || cmd.getAliases().contains(searchLower)) { + return cmd; + } + } + return null; + } + + public static List getAllCommands() { + return ALL_COMMANDS; + } + + + @Nullable + public static IPrefixCommand getPrefixCommand(String search) { + String searchLower = search.toLowerCase(); + + for (IPrefixCommand cmd : ALL_PREFIX_COMMANDS) { + if (cmd.getName().equals(searchLower) || cmd.getAliases().contains(searchLower)) { + return cmd; + } + } + return null; + } + + public static List getAllPrefixCommands() { + return ALL_PREFIX_COMMANDS; + } + + @Nullable + public static ISlashCommand getSlashCommand(String search) { + String searchLower = search.toLowerCase(); + + for (ISlashCommand cmd : ALL_SLASH_COMMANDS) { + if (cmd.getName().equals(searchLower) || cmd.getAliases().contains(searchLower)) { + return cmd; + } + } + return null; + } + + public static List getAllSlashCommands() { + return ALL_SLASH_COMMANDS; + } } diff --git a/src/main/java/tech/nevets/modbot/util/commands/CoreListener.java b/src/main/java/tech/nevets/modbot/util/commands/CoreListener.java new file mode 100644 index 0000000..7bbc7e4 --- /dev/null +++ b/src/main/java/tech/nevets/modbot/util/commands/CoreListener.java @@ -0,0 +1,52 @@ +package tech.nevets.modbot.util.commands; + +import net.dv8tion.jda.api.entities.User; +import net.dv8tion.jda.api.events.ReadyEvent; +import net.dv8tion.jda.api.events.interaction.SlashCommandEvent; +import net.dv8tion.jda.api.events.message.guild.GuildMessageReceivedEvent; +import net.dv8tion.jda.api.hooks.ListenerAdapter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import tech.nevets.modbot.CoreBot; +import tech.nevets.modbot.api.commands.CommandRegistry; + +import javax.annotation.Nonnull; + +public class CoreListener extends ListenerAdapter { + private static final Logger LOGGER = LoggerFactory.getLogger(CoreListener.class); + private final CommandRegistry registry = new CommandRegistry(); + + { + registry.addCommand(new HelpCmd()); + registry.addCommand(new TestCmd()); + CommandManager.addFromRegistry(registry); + } + + public CommandRegistry getCommandRegistry() { + return registry; + } + + @Override + public void onReady(@Nonnull ReadyEvent event) { + LOGGER.info("BuzzBot is ready: " + event.getJDA().getSelfUser().getAsTag()); + } + + @Override + public void onGuildMessageReceived(@Nonnull GuildMessageReceivedEvent event) { + User user = event.getAuthor(); + String raw = event.getMessage().getContentRaw(); + + if (user.isBot() || event.isWebhookMessage()) { + return; + } + + if (raw.startsWith(CoreBot.CORE_CONFIG.getConfig().getString("bot.prefix"))) { + registry.handle(event); + } + } + + @Override + public void onSlashCommand(@Nonnull SlashCommandEvent event) { + registry.handle(event); + } +} diff --git a/src/main/java/tech/nevets/modbot/util/commands/HelpCmd.java b/src/main/java/tech/nevets/modbot/util/commands/HelpCmd.java new file mode 100644 index 0000000..32ededb --- /dev/null +++ b/src/main/java/tech/nevets/modbot/util/commands/HelpCmd.java @@ -0,0 +1,98 @@ +package tech.nevets.modbot.util.commands; + +import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.interactions.commands.Command; +import net.dv8tion.jda.api.interactions.commands.OptionMapping; +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 org.jetbrains.annotations.NotNull; +import tech.nevets.modbot.CoreBot; +import tech.nevets.modbot.api.commands.ICommand; +import tech.nevets.modbot.api.commands.IPrefixCommand; +import tech.nevets.modbot.api.commands.ISlashCommand; + +import java.util.ArrayList; +import java.util.List; + +public class HelpCmd implements ISlashCommand { + + @Override + public void handleSlash(CommandContext ctx) { + + StringBuilder sb = new StringBuilder(); + EmbedBuilder eb = new EmbedBuilder(); + + OptionMapping option = ctx.getSlashEvent().getOption("command"); + String cmd = null; + if (option != null) { + cmd = option.getAsString(); + } + + if (cmd == null){ + IPrefixCommand prefixCommand = CommandManager.getPrefixCommand(ctx.getSlashEvent().getName()); + ISlashCommand slashCommand = CommandManager.getSlashCommand(ctx.getSlashEvent().getName()); + + if (prefixCommand == null && slashCommand == null) { + ctx.getSlashEvent().getHook().sendMessage("Nothing found for " + ctx.getSlashEvent()).queue(); + return; + } + + eb.setTitle("Commands"); + + CommandManager.getAllCommands().stream().map(ICommand::getName).forEach( + (it) -> sb.append('`').append(CoreBot.CORE_CONFIG.getConfig().getString("bot.prefix")).append(it).append("`\n") + ); + + eb.addField("", sb.toString(), false); + } else { + ICommand command = CommandManager.getCommand(cmd); + + if (command != null) { + eb.setTitle(command.getName()); + eb.addField("", command.getHelp(), false); + } else { + eb.setTitle("Error"); + eb.addField("", "Unknown command, run `/help` to see a list of available commands", false); + } + } + + ctx.getSlashEvent().getHook().sendMessageEmbeds(eb.build()).queue(); + } + + @Override + public String getName() { + return "help"; + } + + @Override + public String getHelp() { + return "Shows the list of bot commands\n" + + "Usage: `" + CoreBot.CORE_CONFIG.getConfig().getString("bot.prefix") + "help [command]`"; + } + + + @Override + public String getDescription() { + return "Lists bot commands"; + } + + @Override + public @NotNull CommandData getCommandData() { + List choices = new ArrayList<>(); + + for (IPrefixCommand cmd : CommandManager.getAllPrefixCommands()) { + choices.add(new Command.Choice(cmd.getName(), cmd.getName())); + } + + for (ISlashCommand cmd : CommandManager.getAllSlashCommands()) { + choices.add(new Command.Choice(cmd.getName(), cmd.getName())); + } + + OptionData option = new OptionData(OptionType.STRING, "command", "Gives info on specified command", false); + option.addChoices(choices); + + return new CommandData(this.getName(), this.getDescription()) + .addOptions(option); + } +} diff --git a/src/main/java/tech/nevets/modbot/util/commands/ICommandContext.java b/src/main/java/tech/nevets/modbot/util/commands/ICommandContext.java new file mode 100644 index 0000000..6aa18ec --- /dev/null +++ b/src/main/java/tech/nevets/modbot/util/commands/ICommandContext.java @@ -0,0 +1,150 @@ +package tech.nevets.modbot.util.commands; + +import net.dv8tion.jda.api.JDA; +import net.dv8tion.jda.api.entities.*; +import net.dv8tion.jda.api.events.interaction.SlashCommandEvent; +import net.dv8tion.jda.api.events.message.guild.GuildMessageReceivedEvent; +import net.dv8tion.jda.api.interactions.InteractionHook; +import net.dv8tion.jda.api.sharding.ShardManager; + +public interface ICommandContext { + /** + * Returns the {@link net.dv8tion.jda.api.entities.Guild} for the current command/event + * + * @return the {@link net.dv8tion.jda.api.entities.Guild} for this command/event + */ + default Guild getGuild() { + if (this.getEvent() == null) { + return this.getSlashEvent().getGuild(); + } else if (this.getSlashEvent() == null) { + return this.getEvent().getGuild(); + } + return null; + } + + /** + * Returns the {@link net.dv8tion.jda.api.events.message.guild.GuildMessageReceivedEvent message event} that was received for this instance + * + * @return the {@link net.dv8tion.jda.api.events.message.guild.GuildMessageReceivedEvent message event} that was received for this instance + */ + GuildMessageReceivedEvent getEvent(); + + /** + * Returns the {@link net.dv8tion.jda.api.events.interaction.SlashCommandEvent interaction event} that was received for this instance + * + * @returns the {@link net.dv8tion.jda.api.events.interaction.SlashCommandEvent interaction event} that was received for this instance + */ + SlashCommandEvent getSlashEvent(); + + /** + * Returns the {@link net.dv8tion.jda.api.entities.TextChannel channel} that the message for this event was send in + * + * @return the {@link net.dv8tion.jda.api.entities.TextChannel channel} that the message for this event was send in + */ + default TextChannel getChannel() { + if (this.getEvent() == null) { + return this.getSlashEvent().getTextChannel(); + } else if (this.getSlashEvent() == null) { + return this.getEvent().getChannel(); + } + return null; + } + + /** + * Returns the {@link net.dv8tion.jda.api.entities.Message message} that triggered this event + * + * @return the {@link net.dv8tion.jda.api.entities.Message message} that triggered this event + */ + default Message getMessage() { + if (this.getEvent() == null) { + return null; + } else if (this.getSlashEvent() == null) { + return this.getEvent().getMessage(); + } + return null; + } + + default String getCommandString() { + if (this.getEvent() == null) { + return this.getSlashEvent().getCommandString(); + } + return null; + } + + /** + * Returns the {@link net.dv8tion.jda.api.entities.User author} of the message as user + * + * @return the {@link net.dv8tion.jda.api.entities.User author} of the message as user + */ + default User getAuthor() { + if (this.getEvent() == null) { + return this.getSlashEvent().getUser(); + } else if (this.getSlashEvent() == null) { + return this.getEvent().getAuthor(); + } + return null; + } + /** + * Returns the {@link net.dv8tion.jda.api.entities.Member author} of the message as member + * + * @return the {@link net.dv8tion.jda.api.entities.Member author} of the message as member + */ + default Member getMember() { + if (this.getEvent() == null) { + return this.getSlashEvent().getMember(); + } else if (this.getSlashEvent() == null) { + return this.getEvent().getMember(); + } + return null; + } + + /** + * Returns the {@link net.dv8tion.jda.api.interactions.InteractionHook interaction hook} of the slash command + * + * @return the {@link net.dv8tion.jda.api.interactions.InteractionHook interaction hook} of the slash command + */ + default InteractionHook getHook() { + return this.getSlashEvent().getHook(); + } + + /** + * Returns the current {@link net.dv8tion.jda.api.JDA jda} instance + * + * @return the current {@link net.dv8tion.jda.api.JDA jda} instance + */ + default JDA getJDA() { + if (this.getEvent() == null) { + return this.getSlashEvent().getJDA(); + } else if (this.getSlashEvent() == null) { + return this.getEvent().getJDA(); + } + return null; + } + + /** + * Returns the current {@link net.dv8tion.jda.api.sharding.ShardManager} instance + * + * @return the current {@link net.dv8tion.jda.api.sharding.ShardManager} instance + */ + default ShardManager getShardManager() { + return this.getJDA().getShardManager(); + } + + /** + * Returns the {@link net.dv8tion.jda.api.entities.User user} for the currently logged in account + * + * @return the {@link net.dv8tion.jda.api.entities.User user} for the currently logged in account + */ + default User getSelfUser() { + return this.getJDA().getSelfUser(); + } + + /** + * Returns the {@link net.dv8tion.jda.api.entities.Member member} in the guild for the currently logged in account + * + * @return the {@link net.dv8tion.jda.api.entities.Member member} in the guild for the currently logged in account + */ + default Member getSelfMember() { + return this.getGuild().getSelfMember(); + } +} diff --git a/src/main/java/tech/nevets/modbot/util/commands/TestCmd.java b/src/main/java/tech/nevets/modbot/util/commands/TestCmd.java new file mode 100644 index 0000000..8094cdc --- /dev/null +++ b/src/main/java/tech/nevets/modbot/util/commands/TestCmd.java @@ -0,0 +1,44 @@ +package tech.nevets.modbot.util.commands; + +import net.dv8tion.jda.api.entities.IMentionable; +import net.dv8tion.jda.api.interactions.commands.OptionType; +import net.dv8tion.jda.api.interactions.commands.build.CommandData; +import tech.nevets.modbot.api.commands.ISlashCommand; + +public class TestCmd implements ISlashCommand { + @Override + public void handleSlash(CommandContext ctx) { + long number = ctx.getSlashEvent().getOption("number").getAsLong(); + IMentionable member = ctx.getSlashEvent().getOption("mention").getAsMentionable(); + boolean testBoolean = ctx.getSlashEvent().getOption("boolean").getAsBoolean(); + String commandString = ctx.getSlashEvent().getCommandString(); + + String content = "number: " + number + ", mention: " + member.getAsMention() + ", boolean: " + testBoolean + ", command string: " + commandString; + + ctx.getHook().sendMessage(content).queue(); + } + + @Override + public String getDescription() { + return "Checks the ping between bot and API"; + } + + @Override + public CommandData getCommandData() { + return new CommandData(this.getName(), this.getDescription()) + .addOption(OptionType.INTEGER, "number", "test number", true) + .addOption(OptionType.USER, "mention", "mentioned member or role", true) + .addOption(OptionType.BOOLEAN, "boolean", "test boolean", true); + } + + @Override + public String getName() { + return "test"; + } + + + @Override + public String getHelp() { + return "tests api ping"; + } +}