From 359cf9a19c57e7cfb7c516d9acf1f63f9386ab0c Mon Sep 17 00:00:00 2001 From: ChomeNS <95471003+ChomeNS@users.noreply.github.com> Date: Fri, 11 Apr 2025 14:08:39 +0700 Subject: [PATCH] refactor: move the discord message handler into a separate class to make the mess only live in that class refactor: use ConcurrentHashMap instead of HashMap in the discord message queue --- build-number.txt | 2 +- .../java/me/chayapak1/chomens_bot/Main.java | 2 +- .../discord/GuildMessageEventHandler.java | 357 +++++++++++++++ .../chomens_bot/plugins/DiscordPlugin.java | 419 +++--------------- 4 files changed, 409 insertions(+), 371 deletions(-) create mode 100644 src/main/java/me/chayapak1/chomens_bot/discord/GuildMessageEventHandler.java diff --git a/build-number.txt b/build-number.txt index 6e53eca1..9275af72 100644 --- a/build-number.txt +++ b/build-number.txt @@ -1 +1 @@ -2626 \ No newline at end of file +2634 \ No newline at end of file diff --git a/src/main/java/me/chayapak1/chomens_bot/Main.java b/src/main/java/me/chayapak1/chomens_bot/Main.java index d13dc0a7..598511d9 100644 --- a/src/main/java/me/chayapak1/chomens_bot/Main.java +++ b/src/main/java/me/chayapak1/chomens_bot/Main.java @@ -230,7 +230,7 @@ public class Main { } catch (final InterruptedException ignored) { } } - discord.jda.shutdown(); + if (discord != null && discord.jda != null) discord.jda.shutdown(); } if (callSystemExit) System.exit(exitCode); diff --git a/src/main/java/me/chayapak1/chomens_bot/discord/GuildMessageEventHandler.java b/src/main/java/me/chayapak1/chomens_bot/discord/GuildMessageEventHandler.java new file mode 100644 index 00000000..2064e937 --- /dev/null +++ b/src/main/java/me/chayapak1/chomens_bot/discord/GuildMessageEventHandler.java @@ -0,0 +1,357 @@ +package me.chayapak1.chomens_bot.discord; + +import me.chayapak1.chomens_bot.Bot; +import me.chayapak1.chomens_bot.Main; +import me.chayapak1.chomens_bot.command.contexts.DiscordCommandContext; +import me.chayapak1.chomens_bot.util.ChatMessageUtilities; +import me.chayapak1.chomens_bot.util.ComponentUtilities; +import net.dv8tion.jda.api.JDA; +import net.dv8tion.jda.api.entities.Member; +import net.dv8tion.jda.api.entities.Message; +import net.dv8tion.jda.api.entities.MessageEmbed; +import net.dv8tion.jda.api.entities.Role; +import net.dv8tion.jda.api.entities.messages.MessageSnapshot; +import net.dv8tion.jda.api.entities.sticker.StickerItem; +import net.dv8tion.jda.api.events.message.MessageReceivedEvent; +import net.dv8tion.jda.api.hooks.ListenerAdapter; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.JoinConfiguration; +import net.kyori.adventure.text.event.ClickEvent; +import net.kyori.adventure.text.event.HoverEvent; +import net.kyori.adventure.text.format.NamedTextColor; +import net.kyori.adventure.text.format.TextColor; +import net.kyori.adventure.text.format.TextDecoration; +import org.jetbrains.annotations.NotNull; + +import java.awt.*; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public class GuildMessageEventHandler extends ListenerAdapter { + private final String prefix; + private final Component messagePrefix; + + private final JDA jda; + + public GuildMessageEventHandler ( + final JDA jda, + final String prefix, + final Component messagePrefix + ) { + this.jda = jda; + this.prefix = prefix; + this.messagePrefix = messagePrefix; + + jda.addEventListener(this); + } + + @Override + public void onMessageReceived (@NotNull final MessageReceivedEvent event) { + if (event.getAuthor().getId().equals(jda.getSelfUser().getId())) return; + + for (final Bot bot : Main.bots) { + final String channelId = Main.discord.servers.get(bot.getServerString(true)); + + if (!bot.loggedIn || !event.getChannel().getId().equals(channelId)) continue; + + final Message messageObject = event.getMessage(); + final String messageString = messageObject.getContentDisplay(); + + if (messageString.startsWith(prefix)) { + final DiscordCommandContext context = new DiscordCommandContext(bot, prefix, event); + + bot.commandHandler.executeCommand(messageString.substring(prefix.length()), context, event); + + return; + } + + final boolean isForwarded = !messageObject.getMessageSnapshots().isEmpty(); + + Component output = Component.empty(); + + if (isForwarded) { + for (final MessageSnapshot snapshot : messageObject.getMessageSnapshots()) { + final List extraComponents = new ArrayList<>(); + + addExtraComponents( + extraComponents, + snapshot.getAttachments(), + snapshot.getEmbeds(), + snapshot.getStickers(), + bot + ); + + final String replacedMessageContent = replaceMessageContent(snapshot.getContentRaw()); + + Component messageComponent = Component.text(replacedMessageContent); + + if (!extraComponents.isEmpty()) { + if (!replacedMessageContent.isBlank()) + messageComponent = messageComponent.append(Component.space()); + + messageComponent = messageComponent + .append( + Component.join( + JoinConfiguration.spaces(), + extraComponents + ) + ); + } + + output = Component + .translatable( + "[%s] %s › %s", + this.messagePrefix, + Component + .translatable( + "%s forwarded", + Component.text( + messageObject.getMember() == null ? + messageObject.getAuthor().getName() : + messageObject.getMember().getEffectiveName() + ).color(NamedTextColor.RED) + ) + .color(NamedTextColor.GRAY), + messageComponent.color(NamedTextColor.GRAY) + ) + .color(NamedTextColor.DARK_GRAY); + } + } else { + final Message reference = event.getMessage().getReferencedMessage(); + + if (reference != null) { + output = output + .append( + Component.empty() + .append(Component.text("Replying to ").color(NamedTextColor.GRAY)) + .append(getMessageComponent(bot, reference)) + .decorate(TextDecoration.ITALIC) + ) + .append(Component.newline()); + } + + output = output.append(getMessageComponent(bot, event.getMessage())); + } + + bot.chat.tellraw(output); + } + } + + private Component getMessageComponent ( + final Bot bot, + final Message message + ) { + final List extraComponents = new ArrayList<>(); + + addExtraComponents( + extraComponents, + message.getAttachments(), + message.getEmbeds(), + message.getStickers(), + bot + ); + + final String username = message.getAuthor().getName(); + final Member member = message.getMember(); + + final String displayName = member == null ? username : member.getEffectiveName(); + + final List roles = member == null ? Collections.emptyList() : member.getRoles(); + + Component rolesComponent = Component.empty(); + if (!roles.isEmpty()) { + rolesComponent = rolesComponent + .append(Component.text("Roles:").color(NamedTextColor.GRAY)) + .append(Component.newline()); + + final List rolesList = new ArrayList<>(); + + for (final Role role : roles) { + final Color color = role.getColor(); + + rolesList.add( + Component + .text(role.getName()) + .color( + color == null ? + NamedTextColor.WHITE : + TextColor.color( + color.getRed(), + color.getGreen(), + color.getBlue() + ) + ) + ); + } + + rolesComponent = rolesComponent.append(Component.join(JoinConfiguration.newlines(), rolesList)); + } else { + rolesComponent = rolesComponent.append(Component.text("No roles").color(NamedTextColor.GRAY)); + } + + Component nameComponent = Component + .text(displayName) + .clickEvent(ClickEvent.copyToClipboard(username)) + .hoverEvent( + HoverEvent.showText( + Component.translatable( + """ + %s + %s + + %s""", + Component.text(username).color(NamedTextColor.WHITE), + rolesComponent, + Component.text("Click here to copy the tag to your clipboard").color(NamedTextColor.GREEN) + ).color(NamedTextColor.DARK_GRAY) + ) + ); + + for (final Role role : roles) { + final Color color = role.getColor(); + + if (color == null) continue; + + nameComponent = nameComponent.color( + TextColor.color( + color.getRed(), + color.getGreen(), + color.getBlue() + ) + ); + + break; + } + + if (nameComponent.color() == null) nameComponent = nameComponent.color(NamedTextColor.RED); + + final String replacedMessageContent = replaceMessageContent(message.getContentDisplay()); + + Component actualMessage = ChatMessageUtilities.applyChatMessageStyling(replacedMessageContent); + + if (!extraComponents.isEmpty()) { + if (!replacedMessageContent.isBlank()) actualMessage = actualMessage.append(Component.space()); + + actualMessage = actualMessage + .append( + Component.join( + JoinConfiguration.spaces(), + extraComponents + ) + ); + } + + final Component messageComponent = Component.empty() + .color(NamedTextColor.GRAY) + .append(actualMessage) + .hoverEvent( + HoverEvent.showText( + Component + .text("Click here to copy the message to your clipboard") + .color(NamedTextColor.GREEN) + ) + ) + .clickEvent( + ClickEvent.copyToClipboard( + replacedMessageContent + ) + ); + + return Component.translatable( + "[%s] %s › %s", + messagePrefix, + nameComponent, + messageComponent + ).color(NamedTextColor.DARK_GRAY); + } + + private String replaceMessageContent (final String content) { + return ComponentUtilities + // replaces the ANSI codes (from the bot) with section signs corresponding to the color/style + .deserializeFromDiscordAnsi(content) + // replaces skull emoji + .replace("\uD83D\uDC80", "☠") + // replaces all ZWSP with nothing + .replace("\u200b", ""); + } + + private void addExtraComponents ( + final List extraComponents, + final List attachments, + final List embeds, + final List stickers, + final Bot bot + ) { + addAttachmentsComponent(attachments, extraComponents); + addEmbedsComponent(embeds, extraComponents, bot); + addStickersComponent(stickers, extraComponents); + } + + private void addAttachmentsComponent (final List attachments, final List extraComponents) { + for (final Message.Attachment attachment : attachments) { + extraComponents.add( + Component + .text("[Attachment]") + .clickEvent(ClickEvent.openUrl(attachment.getUrl())) + .hoverEvent( + HoverEvent.showText( + Component + .text(attachment.getFileName()) + .color(NamedTextColor.GREEN) + ) + ) + .color(NamedTextColor.GREEN) + ); + } + } + + private void addEmbedsComponent (final List embeds, final List extraComponents, final Bot bot) { + for (final MessageEmbed embed : embeds) { + final Component hoverEvent = Component.translatable( + """ + Title: %s + %s""", + embed.getTitle() == null ? + Component.text("No title").color(NamedTextColor.GRAY) : + Component.text(embed.getTitle()).color(bot.colorPalette.string), + embed.getDescription() == null ? + Component.text("No description").color(NamedTextColor.GRAY) : + Component.text(embed.getDescription()).color(NamedTextColor.WHITE) + ).color(NamedTextColor.GREEN); + + extraComponents.add( + Component + .text("[Embed]") + .hoverEvent(HoverEvent.showText(hoverEvent)) + .color(NamedTextColor.GREEN) + ); + } + } + + private void addStickersComponent (final List stickers, final List extraComponents) { + for (final StickerItem sticker : stickers) { + extraComponents.add( + Component + .translatable( + "[%s]", + Component + .text(sticker.getName()) + .hoverEvent( + HoverEvent.showText( + Component + .text(sticker.getId()) + .color(NamedTextColor.GREEN) + ) + ) + .clickEvent( + ClickEvent.openUrl( + sticker.getIconUrl() + ) + ) + ) + .color(NamedTextColor.GREEN) + ); + } + } +} diff --git a/src/main/java/me/chayapak1/chomens_bot/plugins/DiscordPlugin.java b/src/main/java/me/chayapak1/chomens_bot/plugins/DiscordPlugin.java index a2488a7c..498043c6 100644 --- a/src/main/java/me/chayapak1/chomens_bot/plugins/DiscordPlugin.java +++ b/src/main/java/me/chayapak1/chomens_bot/plugins/DiscordPlugin.java @@ -3,40 +3,30 @@ package me.chayapak1.chomens_bot.plugins; import me.chayapak1.chomens_bot.Bot; import me.chayapak1.chomens_bot.Configuration; import me.chayapak1.chomens_bot.Main; -import me.chayapak1.chomens_bot.command.contexts.DiscordCommandContext; -import me.chayapak1.chomens_bot.util.ChatMessageUtilities; +import me.chayapak1.chomens_bot.discord.GuildMessageEventHandler; import me.chayapak1.chomens_bot.util.CodeBlockUtilities; import me.chayapak1.chomens_bot.util.ComponentUtilities; import me.chayapak1.chomens_bot.util.LoggerUtilities; import net.dv8tion.jda.api.JDA; import net.dv8tion.jda.api.JDABuilder; -import net.dv8tion.jda.api.entities.*; +import net.dv8tion.jda.api.entities.Activity; +import net.dv8tion.jda.api.entities.Message; import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; -import net.dv8tion.jda.api.entities.messages.MessageSnapshot; -import net.dv8tion.jda.api.entities.sticker.StickerItem; -import net.dv8tion.jda.api.events.message.MessageReceivedEvent; -import net.dv8tion.jda.api.hooks.ListenerAdapter; import net.dv8tion.jda.api.requests.GatewayIntent; import net.dv8tion.jda.api.requests.restaction.MessageCreateAction; import net.kyori.adventure.text.Component; -import net.kyori.adventure.text.JoinConfiguration; import net.kyori.adventure.text.event.ClickEvent; import net.kyori.adventure.text.event.HoverEvent; import net.kyori.adventure.text.format.NamedTextColor; -import net.kyori.adventure.text.format.TextColor; -import net.kyori.adventure.text.format.TextDecoration; import org.geysermc.mcprotocollib.network.event.session.ConnectedEvent; import org.geysermc.mcprotocollib.network.event.session.DisconnectedEvent; -import org.jetbrains.annotations.NotNull; -import java.awt.*; -import java.util.*; -import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.TimeUnit; import java.util.regex.Matcher; -// this is one of the classes which has >500 lines LMAO -public class DiscordPlugin extends ListenerAdapter { +public class DiscordPlugin { public JDA jda; public final Map servers; @@ -65,6 +55,7 @@ public class DiscordPlugin extends ListenerAdapter { final JDABuilder builder = JDABuilder.createDefault(config.discord.token); builder.enableIntents(GatewayIntent.MESSAGE_CONTENT); builder.setEnableShutdownHook(false); + try { jda = builder.build(); jda.awaitReady(); @@ -74,7 +65,7 @@ public class DiscordPlugin extends ListenerAdapter { jda.getPresence().setPresence(Activity.playing(config.discord.statusMessage), false); - jda.addEventListener(this); + new GuildMessageEventHandler(jda, prefix, messagePrefix); for (final Bot bot : Main.bots) { final String channelId = servers.get(bot.getServerString(true)); @@ -149,329 +140,21 @@ public class DiscordPlugin extends ListenerAdapter { } } - @Override - public void onMessageReceived (@NotNull final MessageReceivedEvent event) { - for (final Bot bot : Main.bots) { - final String channelId = servers.get(bot.getServerString(true)); - - if ( - !bot.loggedIn || - !event.getChannel().getId().equals(channelId) || - event.getAuthor().getId().equals(jda.getSelfUser().getId()) - ) continue; - - final Message messageEvent = event.getMessage(); - final String message = messageEvent.getContentDisplay(); - - if (message.startsWith(prefix)) { - final DiscordCommandContext context = new DiscordCommandContext(bot, prefix, event); - - bot.commandHandler.executeCommand(message.substring(prefix.length()), context, event); - - return; - } - - final boolean isForwarded = !messageEvent.getMessageSnapshots().isEmpty(); - - Component output = Component.empty(); - - if (isForwarded) { - for (final MessageSnapshot snapshot : messageEvent.getMessageSnapshots()) { - final List extraComponents = new ArrayList<>(); - - addExtraComponents( - extraComponents, - snapshot.getAttachments(), - snapshot.getEmbeds(), - snapshot.getStickers(), - bot - ); - - Component messageComponent = Component.text(replaceMessageContent(snapshot.getContentRaw())); - - if (!extraComponents.isEmpty()) { - messageComponent = messageComponent - .append( - Component.join( - JoinConfiguration.spaces(), - extraComponents - ) - ); - } - - output = Component - .translatable( - "[%s] %s › %s", - this.messagePrefix, - Component - .translatable( - "%s forwarded", - Component.text( - messageEvent.getMember() == null ? - messageEvent.getAuthor().getName() : - messageEvent.getMember().getEffectiveName() - ).color(NamedTextColor.RED) - ) - .color(NamedTextColor.GRAY), - messageComponent.color(NamedTextColor.GRAY) - ) - .color(NamedTextColor.DARK_GRAY); - } - } else { - final Message reference = event.getMessage().getReferencedMessage(); - - if (reference != null) { - output = output - .append( - Component.empty() - .append(Component.text("Replying to ").color(NamedTextColor.GRAY)) - .append(getMessageComponent(bot, reference)) - .decorate(TextDecoration.ITALIC) - ) - .append(Component.newline()); - } - - output = output.append(getMessageComponent(bot, event.getMessage())); - } - - bot.chat.tellraw(output); - } - } - - private Component getMessageComponent ( - final Bot bot, - final Message message - ) { - final List extraComponents = new ArrayList<>(); - - addExtraComponents( - extraComponents, - message.getAttachments(), - message.getEmbeds(), - message.getStickers(), - bot - ); - - final String username = message.getAuthor().getName(); - final Member member = message.getMember(); - - final String displayName = member == null ? username : member.getEffectiveName(); - - final List roles = member == null ? Collections.emptyList() : member.getRoles(); - - Component rolesComponent = Component.empty(); - if (!roles.isEmpty()) { - rolesComponent = rolesComponent - .append(Component.text("Roles:").color(NamedTextColor.GRAY)) - .append(Component.newline()); - - final List rolesList = new ArrayList<>(); - - for (final Role role : roles) { - final Color color = role.getColor(); - - rolesList.add( - Component - .text(role.getName()) - .color( - color == null ? - NamedTextColor.WHITE : - TextColor.color( - color.getRed(), - color.getGreen(), - color.getBlue() - ) - ) - ); - } - - rolesComponent = rolesComponent.append(Component.join(JoinConfiguration.newlines(), rolesList)); - } else { - rolesComponent = rolesComponent.append(Component.text("No roles").color(NamedTextColor.GRAY)); - } - - Component nameComponent = Component - .text(displayName) - .clickEvent(ClickEvent.copyToClipboard(username)) - .hoverEvent( - HoverEvent.showText( - Component.translatable( - """ - %s - %s - - %s""", - Component.text(username).color(NamedTextColor.WHITE), - rolesComponent, - Component.text("Click here to copy the tag to your clipboard").color(NamedTextColor.GREEN) - ).color(NamedTextColor.DARK_GRAY) - ) - ); - - for (final Role role : roles) { - final Color color = role.getColor(); - - if (color == null) continue; - - nameComponent = nameComponent.color( - TextColor.color( - color.getRed(), - color.getGreen(), - color.getBlue() - ) - ); - - break; - } - - if (nameComponent.color() == null) nameComponent = nameComponent.color(NamedTextColor.RED); - - final String replacedMessageContent = replaceMessageContent(message.getContentDisplay()); - - Component actualMessage = ChatMessageUtilities.applyChatMessageStyling(replacedMessageContent); - - if (!extraComponents.isEmpty()) { - if (!replacedMessageContent.isBlank()) actualMessage = actualMessage.append(Component.space()); - - actualMessage = actualMessage - .append( - Component.join( - JoinConfiguration.spaces(), - extraComponents - ) - ); - } - - final Component messageComponent = Component.empty() - .color(NamedTextColor.GRAY) - .append(actualMessage) - .hoverEvent( - HoverEvent.showText( - Component - .text("Click here to copy the message to your clipboard") - .color(NamedTextColor.GREEN) - ) - ) - .clickEvent( - ClickEvent.copyToClipboard( - replacedMessageContent - ) - ); - - return Component.translatable( - "[%s] %s › %s", - messagePrefix, - nameComponent, - messageComponent - ).color(NamedTextColor.DARK_GRAY); - } - - private String replaceMessageContent (final String content) { - return ComponentUtilities - // replaces the ANSI codes (from the bot) with section signs corresponding to the color/style - .deserializeFromDiscordAnsi(content) - // replaces skull emoji - .replace("\uD83D\uDC80", "☠") - // replaces all ZWSP with nothing - .replace("\u200b", ""); - } - - private void addExtraComponents ( - final List extraComponents, - final List attachments, - final List embeds, - final List stickers, - final Bot bot - ) { - addAttachmentsComponent(attachments, extraComponents); - addEmbedsComponent(embeds, extraComponents, bot); - addStickersComponent(stickers, extraComponents); - } - - private void addAttachmentsComponent (final List attachments, final List extraComponents) { - for (final Message.Attachment attachment : attachments) { - extraComponents.add( - Component - .text("[Attachment]") - .clickEvent(ClickEvent.openUrl(attachment.getUrl())) - .hoverEvent( - HoverEvent.showText( - Component - .text(attachment.getFileName()) - .color(NamedTextColor.GREEN) - ) - ) - .color(NamedTextColor.GREEN) - ); - } - } - - private void addEmbedsComponent (final List embeds, final List extraComponents, final Bot bot) { - for (final MessageEmbed embed : embeds) { - final Component hoverEvent = Component.translatable( - """ - Title: %s - %s""", - embed.getTitle() == null ? - Component.text("No title").color(NamedTextColor.GRAY) : - Component.text(embed.getTitle()).color(bot.colorPalette.string), - embed.getDescription() == null ? - Component.text("No description").color(NamedTextColor.GRAY) : - Component.text(embed.getDescription()).color(NamedTextColor.WHITE) - ).color(NamedTextColor.GREEN); - - extraComponents.add( - Component - .text("[Embed]") - .hoverEvent(HoverEvent.showText(hoverEvent)) - .color(NamedTextColor.GREEN) - ); - } - } - - private void addStickersComponent (final List stickers, final List extraComponents) { - for (final StickerItem sticker : stickers) { - extraComponents.add( - Component - .translatable( - "[%s]", - Component - .text(sticker.getName()) - .hoverEvent( - HoverEvent.showText( - Component - .text(sticker.getId()) - .color(NamedTextColor.GREEN) - ) - ) - .clickEvent( - ClickEvent.openUrl( - sticker.getIconUrl() - ) - ) - ) - .color(NamedTextColor.GREEN) - ); - } - } - - // totallynotskidded™️ from HBot (and changed a bit) - final Map logMessages = new HashMap<>(); - final Map nextLogTimes = new HashMap<>(); - final Map doneSendingInLogs = new HashMap<>(); + // based from HBot (and modified quite a bit) + private final Map logMessages = new ConcurrentHashMap<>(); + private final Map nextLogTimes = new ConcurrentHashMap<>(); + private final Map doneSendingInLogs = new ConcurrentHashMap<>(); public void sendMessage (final String message, final String channelId) { - synchronized (logMessages) { - if (!logMessages.containsKey(channelId)) { - logMessages.put(channelId, new StringBuilder()); - } - final StringBuilder logMessage = logMessages.get(channelId); - if (logMessage.length() < 2000) { - if (!logMessage.isEmpty()) { - logMessage.append('\n'); - } - logMessage.append(message); + logMessages.putIfAbsent(channelId, new StringBuilder()); + + final StringBuilder logMessage = logMessages.get(channelId); + + if (logMessage.length() < 2000) { + if (!logMessage.isEmpty()) { + logMessage.append('\n'); } + logMessage.append(message); } } @@ -504,52 +187,50 @@ public class DiscordPlugin extends ListenerAdapter { } public void onDiscordTick (final String channelId) { - synchronized (logMessages) { - if (!logMessages.containsKey(channelId) || logMessages.get(channelId).isEmpty()) { - return; - } + if (!logMessages.containsKey(channelId) || logMessages.get(channelId).isEmpty()) { + return; } final long currentTime = System.currentTimeMillis(); - if (!nextLogTimes.containsKey(channelId) || (currentTime >= nextLogTimes.get(channelId) && doneSendingInLogs.get(channelId)) - || currentTime - nextLogTimes.get(channelId) > 5000) { + if (!nextLogTimes.containsKey(channelId) + || (currentTime >= nextLogTimes.get(channelId) && doneSendingInLogs.get(channelId)) + || currentTime - nextLogTimes.get(channelId) > 5000 + ) { final long logDelay = 2000; nextLogTimes.put(channelId, currentTime + logDelay); String message; - synchronized (logMessages) { - final StringBuilder logMessage = logMessages.get(channelId); + final StringBuilder logMessage = logMessages.get(channelId); - final Matcher inviteMatcher = Message.INVITE_PATTERN.matcher(logMessage.toString()); + final Matcher inviteMatcher = Message.INVITE_PATTERN.matcher(logMessage.toString()); - final StringBuilder messageBuilder = new StringBuilder(); + final StringBuilder messageBuilder = new StringBuilder(); - while (inviteMatcher.find()) { - inviteMatcher.appendReplacement( - messageBuilder, - Matcher.quoteReplacement( - inviteMatcher.group() - // fixes discord.gg (and some more discord urls) showing invite - .replace(".", "\u200b.") - ) - ); - } - - inviteMatcher.appendTail(messageBuilder); - - final int maxLength = 2_000 - (""" - ```ansi - - ```""" - ).length(); // kinda sus - - message = messageBuilder.substring(0, Math.min(messageBuilder.length(), maxLength)); - - logMessage.setLength(0); + while (inviteMatcher.find()) { + inviteMatcher.appendReplacement( + messageBuilder, + Matcher.quoteReplacement( + inviteMatcher.group() + // fixes discord.gg (and some more discord urls) showing invite + .replace(".", "\u200b.") + ) + ); } + inviteMatcher.appendTail(messageBuilder); + + final int maxLength = 2_000 - (""" + ```ansi + + ```""" + ).length(); // kinda sus + + message = messageBuilder.substring(0, Math.min(messageBuilder.length(), maxLength)); + + logMessage.setLength(0); + if (message.trim().isBlank()) return; sendMessageInstantly("```ansi\n" + message + "\n```", channelId);