From 58068516c4d3935848a10b90878de6e579d5ad57 Mon Sep 17 00:00:00 2001 From: Anirudh Sharma Date: Fri, 24 Jun 2022 16:57:34 +0530 Subject: [PATCH] Major Updates * Added functionality for the Help command * *Slightly* improved the readme * Do check out the help commands... in discord. * Now, individual mods can be disabled or enabled. --- README.md | 23 +++++ .../java/in/mcxiv/gfg_bot/GFG_KIIT_Bot.java | 22 +++-- .../PreliminaryTestedListenerAdapter.java | 33 ++++++- src/main/java/in/mcxiv/gfg_bot/Resources.java | 4 +- .../java/in/mcxiv/gfg_bot/SJF4JBinder.java | 2 +- .../gfg_bot/SpecialisedListenerAdapter.java | 14 +++ .../mods/GFGSummerProjectCampUtilities.java | 58 +++++++++++- .../in/mcxiv/gfg_bot/mods/HelpCommand.java | 90 +++++++++++++++++++ .../java/in/mcxiv/gfg_bot/mods/InviteMe.java | 14 +++ .../in/mcxiv/gfg_bot/mods/ManageMods.java | 73 +++++++++++++++ .../gfg_bot/mods/ResponsivenessHelper.java | 13 +++ 11 files changed, 329 insertions(+), 17 deletions(-) create mode 100644 src/main/java/in/mcxiv/gfg_bot/mods/HelpCommand.java create mode 100644 src/main/java/in/mcxiv/gfg_bot/mods/ManageMods.java diff --git a/README.md b/README.md index bffb0f6..b02b9da 100644 --- a/README.md +++ b/README.md @@ -15,3 +15,26 @@ Hmm... Someone please help me write a short and simple _about_ in here... * **Well, that's it so far.**
As new mods are added, this will be updated accordingly. + +## How to contribute + +* The source root is present at `src/main/java` and the resource root is present at `src/main/resources`. +* The resources must include a resource bundle named `privateResources.properties` with the following keys: + * `discord_bot_token` - This is the main authentication token used for the deployment bot. One may leave it blank + and use development mode. + * `development_discord_bot_token` - This is an alternative token which is used when testing out new features. + * `discord_bot_invite_link` - This field contains an up-to-date invite link for the bot, which contains only the + necessary permissions. +* Adding new functionality: + * Create a new class `MyNewMod` under the package `mods`. + * Make it extend the class `SpecialisedListenerAdapter`. + * Optionally override the `isSuperior` method. If it returns `true`, the message events will be called on all + occasions. If it returns `false`, the events will be called only when the bot is mentioned using the command + string. + * Override `getName` to return a suitable name for your mod, for example, `My New Mod`. + * Override `getHelpEmbed` to return a title-less embed containing information about your mod. + * Override on of the default JDA events like `onMessageReceived` to start working on your mod. + * Make sure to read the `Resources` and `Utilities` class. + * For logging, you can use the generalised logging methods in `GFG_KIIT_Bot`. + * To register your Mod, navigate to `GFG_KIIT_Bot#initializeBot` add the line:
+ `listenerAdapter.addEventListener(new MyNewMod());` \ No newline at end of file diff --git a/src/main/java/in/mcxiv/gfg_bot/GFG_KIIT_Bot.java b/src/main/java/in/mcxiv/gfg_bot/GFG_KIIT_Bot.java index ffaafed..0237731 100644 --- a/src/main/java/in/mcxiv/gfg_bot/GFG_KIIT_Bot.java +++ b/src/main/java/in/mcxiv/gfg_bot/GFG_KIIT_Bot.java @@ -2,9 +2,7 @@ import com.mcxiv.logger.decorations.Format; import com.mcxiv.logger.tables.Table; -import in.mcxiv.gfg_bot.mods.GFGSummerProjectCampUtilities; -import in.mcxiv.gfg_bot.mods.InviteMe; -import in.mcxiv.gfg_bot.mods.ResponsivenessHelper; +import in.mcxiv.gfg_bot.mods.*; import in.mcxiv.tryCatchSuite.Try; import net.dv8tion.jda.api.JDA; import net.dv8tion.jda.api.JDABuilder; @@ -28,7 +26,6 @@ public class GFG_KIIT_Bot extends ListenerAdapter { public GFG_KIIT_Bot() { refreshResources(); - initializeBot(); } public static GFG_KIIT_Bot getInstance() { @@ -48,6 +45,7 @@ public static void main(String[] args) { }); inputThread.setPriority(Thread.MIN_PRIORITY); inputThread.start(); + getInstance().initializeBot(); } private void refreshResources() { @@ -59,7 +57,7 @@ private void initializeBot() { JDABuilder builder = JDABuilder .createDefault(resources.botToken) - .setActivity(Activity.watching("you 👀")) + .setActivity(Activity.watching("you \uD83D\uDC40")) .disableCache(CacheFlag.VOICE_STATE, CacheFlag.EMOTE) .disableIntents(Arrays.asList(GatewayIntent.values())) .enableIntents(GatewayIntent.GUILD_MESSAGES) @@ -68,6 +66,8 @@ private void initializeBot() { listenerAdapter.addEventListener(new ResponsivenessHelper()); listenerAdapter.addEventListener(new InviteMe(this)); listenerAdapter.addEventListener(new GFGSummerProjectCampUtilities(this)); + listenerAdapter.addEventListener(new ManageMods(this)); + listenerAdapter.addEventListener(new HelpCommand(this)); jda = Try.get(builder::build); Try.run(jda::awaitReady); @@ -76,7 +76,7 @@ private void initializeBot() { @Override public void onReady(@NotNull ReadyEvent event) { - + notice("Bot Event System", "Bot is Ready!"); } @Format({" :: :#0f0 @050 %*30s b: ::", "::\t:#090 @dfd n %-130s:"}) @@ -89,10 +89,14 @@ public void error(String title, String msg) { resources.log.prt(title, msg); } - public String stripCommand(String contentRaw) { + public String stripCommand(String contentRaw, String command) { contentRaw = contentRaw.stripLeading(); - if (!contentRaw.startsWith(resources.botCommand)) + if (!contentRaw.startsWith(command)) return contentRaw; - return contentRaw.substring(resources.botCommand.length()).stripLeading(); + return contentRaw.substring(command.length()).stripLeading(); + } + + public String stripCommand(String contentRaw) { + return stripCommand(contentRaw, resources.botCommand); } } diff --git a/src/main/java/in/mcxiv/gfg_bot/PreliminaryTestedListenerAdapter.java b/src/main/java/in/mcxiv/gfg_bot/PreliminaryTestedListenerAdapter.java index f7369db..f078686 100644 --- a/src/main/java/in/mcxiv/gfg_bot/PreliminaryTestedListenerAdapter.java +++ b/src/main/java/in/mcxiv/gfg_bot/PreliminaryTestedListenerAdapter.java @@ -1,11 +1,16 @@ package in.mcxiv.gfg_bot; +import net.dv8tion.jda.api.entities.ChannelType; +import net.dv8tion.jda.api.events.GenericEvent; import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import net.dv8tion.jda.api.hooks.ListenerAdapter; import org.jetbrains.annotations.NotNull; import java.util.ArrayList; +import java.util.Collections; +import java.util.List; import java.util.Objects; +import java.util.stream.Stream; public final class PreliminaryTestedListenerAdapter extends ListenerAdapter { @@ -20,12 +25,36 @@ public void addEventListener(SpecialisedListenerAdapter listener) { listeners.add(Objects.requireNonNull(listener)); } + public List getListeners() { + return Collections.unmodifiableList(listeners); + } + + private Stream getActiveListeners() { + return listeners.stream().filter(SpecialisedListenerAdapter::isActivated); + } + + public SpecialisedListenerAdapter getListenerByName(String name) { + for (SpecialisedListenerAdapter listener : listeners) + if (listener.getName().equalsIgnoreCase(name)) + return listener; + return null; + } + + @Override + public void onGenericEvent(@NotNull GenericEvent event) { + if (event instanceof MessageReceivedEvent) return; + getActiveListeners().forEach(el -> el.onEvent(event)); + } + @Override public void onMessageReceived(@NotNull MessageReceivedEvent event) { if (event.getAuthor().isBot()) return; - listeners.stream().filter(SpecialisedListenerAdapter::isSuperior).forEach(listenerAdapter -> listenerAdapter.onMessageReceived(event)); + if (event.getChannel().getType() != ChannelType.TEXT) return; + getActiveListeners().filter(SpecialisedListenerAdapter::isSuperior) + .forEach(listenerAdapter -> listenerAdapter.onMessageReceived(event)); if (!event.getMessage().getContentDisplay().startsWith(bot.resources.botCommand)) return; - listeners.stream().filter(SpecialisedListenerAdapter::isInferior).forEach(listenerAdapter -> listenerAdapter.onMessageReceived(event)); + getActiveListeners().filter(SpecialisedListenerAdapter::isInferior) + .forEach(listenerAdapter -> listenerAdapter.onMessageReceived(event)); } } diff --git a/src/main/java/in/mcxiv/gfg_bot/Resources.java b/src/main/java/in/mcxiv/gfg_bot/Resources.java index 71dd0c9..9acfea6 100644 --- a/src/main/java/in/mcxiv/gfg_bot/Resources.java +++ b/src/main/java/in/mcxiv/gfg_bot/Resources.java @@ -19,7 +19,7 @@ public class Resources { public final FLog log; public final int cores; public final String inviteLink; - final String botCommand = "kb"; + public final String botCommand = "kb"; final String botToken; public Resources() { @@ -30,6 +30,8 @@ public Resources() { System.setProperty("java.util.concurrent.ForkJoinPool.common.parallelism", "1"); } + // 250 Jaspinik, 322 gfgkiitbot + FLog file_logger = FileLog.getNew(NAME_U + ".log"); FLog strm_logger = FLog.getNew(); file_logger.setDecorationType(Decorations.TAG); diff --git a/src/main/java/in/mcxiv/gfg_bot/SJF4JBinder.java b/src/main/java/in/mcxiv/gfg_bot/SJF4JBinder.java index 0b79b85..c10c327 100644 --- a/src/main/java/in/mcxiv/gfg_bot/SJF4JBinder.java +++ b/src/main/java/in/mcxiv/gfg_bot/SJF4JBinder.java @@ -35,7 +35,7 @@ public Logger getLogger(String name) { @Format({" :: :#f80 @520 %*30s b: ::", "::\t:#940 @fca n %-130s:"}) public final class SLF4J_to_FLOG_Bridge extends MarkerIgnoringBase { - static final String NAME = "SLF4J"; + static final String NAME = "JDA - Internals"; public void logIt(LogLevel logLevel, String msg) { if (logLevel.accepted()) diff --git a/src/main/java/in/mcxiv/gfg_bot/SpecialisedListenerAdapter.java b/src/main/java/in/mcxiv/gfg_bot/SpecialisedListenerAdapter.java index 0dd1749..3bff507 100644 --- a/src/main/java/in/mcxiv/gfg_bot/SpecialisedListenerAdapter.java +++ b/src/main/java/in/mcxiv/gfg_bot/SpecialisedListenerAdapter.java @@ -1,9 +1,12 @@ package in.mcxiv.gfg_bot; +import net.dv8tion.jda.api.EmbedBuilder; import net.dv8tion.jda.api.hooks.ListenerAdapter; public abstract class SpecialisedListenerAdapter extends ListenerAdapter { + private boolean isActivated = true; + public boolean isSuperior() { return false; } @@ -12,4 +15,15 @@ public final boolean isInferior() { return !isSuperior(); } + public abstract String getName(); + + public abstract EmbedBuilder getHelpEmbed(); + + public final boolean isActivated() { + return isActivated; + } + + public final void setActivated(boolean activated) { + isActivated = activated; + } } diff --git a/src/main/java/in/mcxiv/gfg_bot/mods/GFGSummerProjectCampUtilities.java b/src/main/java/in/mcxiv/gfg_bot/mods/GFGSummerProjectCampUtilities.java index 6dcc520..abdd29f 100644 --- a/src/main/java/in/mcxiv/gfg_bot/mods/GFGSummerProjectCampUtilities.java +++ b/src/main/java/in/mcxiv/gfg_bot/mods/GFGSummerProjectCampUtilities.java @@ -1,5 +1,6 @@ package in.mcxiv.gfg_bot.mods; +import com.mcxiv.logger.tables.Table; import in.mcxiv.gfg_bot.GFG_KIIT_Bot; import in.mcxiv.gfg_bot.SpecialisedListenerAdapter; import in.mcxiv.gfg_bot.utils.Utilities; @@ -30,6 +31,7 @@ public GFGSummerProjectCampUtilities(GFG_KIIT_Bot bot) { this.bot = bot; } + private static boolean isMessageFromSummerCampProjectCategory(Channel channel) { if (!(channel instanceof ICategorizableChannel iCategorizableChannel)) return false; if (iCategorizableChannel.getParentCategory() == null) return false; @@ -50,6 +52,47 @@ public boolean isSuperior() { return true; } + @Override + public String getName() { + return "Summer Project Camp Helper"; + } + + @Override + public EmbedBuilder getHelpEmbed() { + return new EmbedBuilder() + .addField("Create a new Channel for Summer Project Camp", """ + Please tell us about yourself and your project in the following format + **Item Name: Item Value** + + Information must include your _Name_, your _Project Name_, your project _Domain_ and your _Project Description_. + Feel free to add in more details using the same format, for example your project's GitHub link... + (The values can be multi-lined.) + + For example: + + Name: Anirudh Sharma + Domain: App Development + Project Name: GFG KIIT Bot + + Project Description: + A simple discord bot written in Java for + automating server management for various + events organised in the GFG KIIT discord + server. + + Github Link: https://github.com/GFG-CLUB-KIIT/GFG_KIIT_Bot/tree/deployment + """, false) + .addField("Deleting channels made by this bot", """ + Just type _delete_ and mention any channels you wish to delete. + + For example, + delete #channel-1 #channel-2 + + This will delete the two channels. + (This command can only delete channels made for Summer Project Camp!) + """, false); + } + @Override public void onMessageReceived(@NotNull MessageReceivedEvent event) { if (!isMessageFromSummerCampProjectChannel(event.getChannel())) return; @@ -57,14 +100,21 @@ public void onMessageReceived(@NotNull MessageReceivedEvent event) { var raw_content = bot.stripCommand(event.getMessage().getContentRaw()) .strip().replaceAll("[\n\r]+", "\n"); + if (raw_content.indexOf(':') >= raw_content.indexOf("\n")) return; + var lines = Utilities.simplifyContent(raw_content); Map fields = linesDoesntContainAllTheRequiredInformation(lines, event); if (fields.isEmpty()) return; - ChannelAction channel = event.getGuild().createTextChannel(fields.get("Project's Name")); - channel.setParent(((TextChannel) event.getChannel()).getParentCategory()); - channel.setTopic(fields.get("Project's Description")); - channel.queue(textChannel -> sendProjectInfoEmbed(event.getMember(), textChannel, fields)); + try { + ChannelAction channel = event.getGuild().createTextChannel(fields.get("Project's Name")); + channel.setParent(((TextChannel) event.getChannel()).getParentCategory()); + channel.setTopic(fields.get("Project's Description")); + channel.queue(textChannel -> sendProjectInfoEmbed(event.getMember(), textChannel, fields)); + } catch (Throwable t) { + bot.error("Sumr Proj Mod", fields.toString()); + Table.tabulate(bot.resources.log, t); + } } private boolean isTheMessageAChannelCommand(MessageReceivedEvent event) { diff --git a/src/main/java/in/mcxiv/gfg_bot/mods/HelpCommand.java b/src/main/java/in/mcxiv/gfg_bot/mods/HelpCommand.java new file mode 100644 index 0000000..7eb8252 --- /dev/null +++ b/src/main/java/in/mcxiv/gfg_bot/mods/HelpCommand.java @@ -0,0 +1,90 @@ +package in.mcxiv.gfg_bot.mods; + +import in.mcxiv.gfg_bot.GFG_KIIT_Bot; +import in.mcxiv.gfg_bot.Resources; +import in.mcxiv.gfg_bot.SpecialisedListenerAdapter; +import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.entities.MessageEmbed; +import net.dv8tion.jda.api.events.ReadyEvent; +import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; +import net.dv8tion.jda.api.events.message.MessageReceivedEvent; +import net.dv8tion.jda.api.requests.RestAction; +import org.jetbrains.annotations.NotNull; + +import java.util.function.Function; + +public class HelpCommand extends SpecialisedListenerAdapter { + + private final GFG_KIIT_Bot bot; + private final EmbedBuilder botDescriptiveEmbed; + + public HelpCommand(GFG_KIIT_Bot bot) { + this.bot = bot; + this.botDescriptiveEmbed = new EmbedBuilder() + .setTitle(Resources.NAME) + .setDescription(Resources.IS_UNDER_TEST ? "Development Build" : "A simple bot to automate server management.") + .appendDescription("\nMention mod name to load more details.") + .appendDescription("\nFor example: `%s help responsiveness helper`".formatted(bot.resources.botCommand)) + .addField("GH Link", "https://github.com/GFG-CLUB-KIIT/GFG_KIIT_Bot/tree/deployment", false) + .addField("Bot Command", bot.resources.botCommand, false); + updateBotDescriptiveEmbed(); + } + + @Override + public void onReady(@NotNull ReadyEvent event) { + this.bot.jda.upsertCommand("help", "Show some information about this bot.").queue(); + } + + @Override + public String getName() { + return "Help Command"; + } + + private void updateBotDescriptiveEmbed() { + botDescriptiveEmbed.getFields().stream().filter(field -> field.getName().equals("List of all the mods loaded")).findFirst().ifPresent(field -> botDescriptiveEmbed.getFields().remove(field)); + StringBuilder mods = new StringBuilder(); + int length = bot.listenerAdapter.getListeners().stream().map(SpecialisedListenerAdapter::getName).mapToInt(String::length).max().orElse(26); + bot.listenerAdapter.getListeners() + .forEach(la -> mods.append(la.isActivated() ? "o:" : "#:").append(" %%-%ds".formatted(length).formatted(la.getName())).append("\n")); + botDescriptiveEmbed.addField("List of all the mods loaded", "```haskell\n%s\n```".formatted(mods), false); + } + + @Override + public void onMessageReceived(@NotNull MessageReceivedEvent event) { + String content = event.getMessage().getContentDisplay(); + if (!content.contains("help")) return; + content = bot.stripCommand(bot.stripCommand(content), "help").strip(); + if (content.isEmpty()) + sendBotDescriptiveMessage(event.getChannel()::sendMessageEmbeds); + else + sendModHelpMessage(event, content); + } + + @Override + public void onSlashCommandInteraction(@NotNull SlashCommandInteractionEvent event) { + if (!event.getName().equals("help")) return; + sendBotDescriptiveMessage(event::replyEmbeds); + } + + private void sendBotDescriptiveMessage(@NotNull Function> function) { + updateBotDescriptiveEmbed(); + function.apply(botDescriptiveEmbed.build()).queue(); + } + + private void sendModHelpMessage(MessageReceivedEvent event, String processedContent) { + if (processedContent.strip().equals("help")) return; + SpecialisedListenerAdapter la = bot.listenerAdapter.getListenerByName(processedContent); + if (la == null) { + event.getMessage().reply("I don't have any mod with that name loaded 🤔...").queue(); + return; + } + event.getChannel().sendMessageEmbeds(la.getHelpEmbed() + .setTitle("Help - %s".formatted(la.getName())) + .build()).queue(); + } + + @Override + public EmbedBuilder getHelpEmbed() { + throw new UnsupportedOperationException("Help command isn't supposed to contain more information."); + } +} diff --git a/src/main/java/in/mcxiv/gfg_bot/mods/InviteMe.java b/src/main/java/in/mcxiv/gfg_bot/mods/InviteMe.java index 0af8ae4..f1a10c9 100644 --- a/src/main/java/in/mcxiv/gfg_bot/mods/InviteMe.java +++ b/src/main/java/in/mcxiv/gfg_bot/mods/InviteMe.java @@ -2,6 +2,7 @@ import in.mcxiv.gfg_bot.GFG_KIIT_Bot; import in.mcxiv.gfg_bot.SpecialisedListenerAdapter; +import net.dv8tion.jda.api.EmbedBuilder; import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import org.jetbrains.annotations.NotNull; @@ -13,6 +14,19 @@ public InviteMe(GFG_KIIT_Bot bot) { this.bot = bot; } + @Override + public String getName() { + return "Bot Invitation"; + } + + @Override + public EmbedBuilder getHelpEmbed() { + return new EmbedBuilder() + .addField("Invite this bot to your own server.", """ + Just use the command _invite_ to receive a link, using which you can add this bot to servers you own. + """, false); + } + @Override public void onMessageReceived(@NotNull MessageReceivedEvent event) { if (!event.getMessage().getContentDisplay().contains("invite")) return; diff --git a/src/main/java/in/mcxiv/gfg_bot/mods/ManageMods.java b/src/main/java/in/mcxiv/gfg_bot/mods/ManageMods.java new file mode 100644 index 0000000..86d99e2 --- /dev/null +++ b/src/main/java/in/mcxiv/gfg_bot/mods/ManageMods.java @@ -0,0 +1,73 @@ +package in.mcxiv.gfg_bot.mods; + +import in.mcxiv.gfg_bot.GFG_KIIT_Bot; +import in.mcxiv.gfg_bot.SpecialisedListenerAdapter; +import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.Permission; +import net.dv8tion.jda.api.events.message.MessageReceivedEvent; +import org.jetbrains.annotations.NotNull; + +import java.util.Objects; + +public class ManageMods extends SpecialisedListenerAdapter { + + private final GFG_KIIT_Bot bot; + + public ManageMods(GFG_KIIT_Bot bot) { + this.bot = bot; + } + + @Override + public String getName() { + return "Mods Manager"; + } + + @Override + public void onMessageReceived(@NotNull MessageReceivedEvent event) { + String content = event.getMessage().getContentDisplay(); + if (!content.contains("mod")) return; + if (!event.getMember().hasPermission(Permission.MANAGE_SERVER)) return; + + String name = event.getMessage().getContentRaw(); + name = name.substring(name.indexOf("able") + 4).strip(); + if (name.isEmpty()) return; + SpecialisedListenerAdapter la = bot.listenerAdapter.getListenerByName(name); + if (isNull(la, name, event)) return; + + if (content.contains("mod enable")) enableMod(event, la); + else if (content.contains("mod disable")) disableMod(event, la); + } + + private void enableMod(MessageReceivedEvent event, SpecialisedListenerAdapter la) { + if (la.isActivated()) event.getMessage().reply("The mod is already online :eyes:...").queue(); + else { + la.setActivated(true); + event.getMessage().reply("%s has successfully been activated!".formatted(la.getName())).queue(); + } + } + + private void disableMod(MessageReceivedEvent event, SpecialisedListenerAdapter la) { + if (Objects.equals(la.getName(), getName())) + event.getMessage().reply("What are you trying to do :eyes:...?").queue(); + else if (!la.isActivated()) + event.getMessage().reply("The mod is already offline :eyes:...").queue(); + else { + la.setActivated(false); + event.getMessage().reply("%s has successfully been deactivated!".formatted(la.getName())).queue(); + } + } + + private boolean isNull(SpecialisedListenerAdapter la, String content, MessageReceivedEvent event) { + if (la != null) return false; + event.getMessage().reply("'%s' doesn't seems to be one of the mods which I have installed \uD83E\uDD14...".formatted(content)).queue(); + return true; + } + + @Override + public EmbedBuilder getHelpEmbed() { + return new EmbedBuilder() + .addField("mod enable", "Enable a mod.", false) + .addField("mod disable", "Disable a mod.", false); + } + +} diff --git a/src/main/java/in/mcxiv/gfg_bot/mods/ResponsivenessHelper.java b/src/main/java/in/mcxiv/gfg_bot/mods/ResponsivenessHelper.java index 45a7b08..8211b81 100644 --- a/src/main/java/in/mcxiv/gfg_bot/mods/ResponsivenessHelper.java +++ b/src/main/java/in/mcxiv/gfg_bot/mods/ResponsivenessHelper.java @@ -1,12 +1,25 @@ package in.mcxiv.gfg_bot.mods; import in.mcxiv.gfg_bot.SpecialisedListenerAdapter; +import net.dv8tion.jda.api.EmbedBuilder; import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import org.jetbrains.annotations.NotNull; public class ResponsivenessHelper extends SpecialisedListenerAdapter { + @Override public void onMessageReceived(@NotNull MessageReceivedEvent event) { event.getMessage().addReaction("\uD83D\uDC40").queue(); } + + @Override + public String getName() { + return "Responsiveness Helper"; + } + + @Override + public EmbedBuilder getHelpEmbed() { + return new EmbedBuilder() + .setDescription("This is a mod underdevelopment, which aims at making the bot more responsive."); + } }