Skip to content

Commit

Permalink
Major Updates
Browse files Browse the repository at this point in the history
* 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.
  • Loading branch information
Minecraftian14 committed Jun 24, 2022
1 parent d80292a commit 5806851
Show file tree
Hide file tree
Showing 11 changed files with 329 additions and 17 deletions.
23 changes: 23 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,26 @@ Hmm... Someone please help me write a short and simple _about_ in here...

* **Well, that's it so far.**<br/>
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: <br/>
`listenerAdapter.addEventListener(new MyNewMod());`
22 changes: 13 additions & 9 deletions src/main/java/in/mcxiv/gfg_bot/GFG_KIIT_Bot.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -28,7 +26,6 @@ public class GFG_KIIT_Bot extends ListenerAdapter {

public GFG_KIIT_Bot() {
refreshResources();
initializeBot();
}

public static GFG_KIIT_Bot getInstance() {
Expand All @@ -48,6 +45,7 @@ public static void main(String[] args) {
});
inputThread.setPriority(Thread.MIN_PRIORITY);
inputThread.start();
getInstance().initializeBot();
}

private void refreshResources() {
Expand All @@ -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)
Expand All @@ -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);
Expand All @@ -76,7 +76,7 @@ private void initializeBot() {

@Override
public void onReady(@NotNull ReadyEvent event) {

notice("Bot Event System", "Bot is Ready!");
}

@Format({" :: :#0f0 @050 <D hh;mm;ss> %*30s b: ::", "::\t:#090 @dfd n %-130s:"})
Expand All @@ -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);
}
}
Original file line number Diff line number Diff line change
@@ -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 {

Expand All @@ -20,12 +25,36 @@ public void addEventListener(SpecialisedListenerAdapter listener) {
listeners.add(Objects.requireNonNull(listener));
}

public List<SpecialisedListenerAdapter> getListeners() {
return Collections.unmodifiableList(listeners);
}

private Stream<SpecialisedListenerAdapter> 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));
}

}
4 changes: 3 additions & 1 deletion src/main/java/in/mcxiv/gfg_bot/Resources.java
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand All @@ -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);
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/in/mcxiv/gfg_bot/SJF4JBinder.java
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ public Logger getLogger(String name) {
@Format({" :: :#f80 @520 <D hh;mm;ss> %*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())
Expand Down
14 changes: 14 additions & 0 deletions src/main/java/in/mcxiv/gfg_bot/SpecialisedListenerAdapter.java
Original file line number Diff line number Diff line change
@@ -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;
}
Expand All @@ -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;
}
}
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -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;
Expand All @@ -50,21 +52,69 @@ 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;
if (isTheMessageAChannelCommand(event)) return;

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<String, String> fields = linesDoesntContainAllTheRequiredInformation(lines, event);
if (fields.isEmpty()) return;

ChannelAction<TextChannel> 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<TextChannel> 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) {
Expand Down
90 changes: 90 additions & 0 deletions src/main/java/in/mcxiv/gfg_bot/mods/HelpCommand.java
Original file line number Diff line number Diff line change
@@ -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<MessageEmbed, RestAction<?>> 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.");
}
}
Loading

0 comments on commit 5806851

Please sign in to comment.