diff --git a/VelocityCore/src/de/steamwar/velocitycore/discord/DiscordBot.java b/VelocityCore/src/de/steamwar/velocitycore/discord/DiscordBot.java index ecdc5a53..8b522342 100644 --- a/VelocityCore/src/de/steamwar/velocitycore/discord/DiscordBot.java +++ b/VelocityCore/src/de/steamwar/velocitycore/discord/DiscordBot.java @@ -167,14 +167,19 @@ public class DiscordBot { checklistChannel = new ChecklistChannel(config.channel("checklist")); config.getCouncilThread().forEach((roleId, threadId) -> new CouncilChannel(DiscordBot.getGuild().getRoleById(roleId), DiscordBot.getGuild().getThreadChannelById(threadId))); - announcementChannel = new DiscordChannel(config.channel("announcement")) { + announcementChannel = new DiscordChannel(config.channel("announcement"), 0) { @Override public void received(MessageReceivedEvent event) { Chatter.broadcast().system("ALERT", event.getMessage().getContentDisplay()); } }; - ingameChat = new DiscordChatRoom(config.channel("ingame"), "CHAT_DISCORD_GLOBAL", Chatter::broadcast); - serverTeamChat = new DiscordChatRoom(config.channel("serverteam"), "CHAT_SERVERTEAM", Chatter::serverteam); + + // There is a hard limit of 30 messages per minute to send as a webhook, thus with 5 webhooks we can send + // 180 messages per minute. Which means 3 every second. I looked at the WGS fights and there were around + // ~70 in a short burst and then rather long no new message. + ingameChat = new DiscordChatRoom(config.channel("ingame"), "CHAT_DISCORD_GLOBAL", Chatter::broadcast, 5); + // 30 messages per minute should be enough for the server team! + serverTeamChat = new DiscordChatRoom(config.channel("serverteam"), "CHAT_SERVERTEAM", Chatter::serverteam, 1); VelocityCore.schedule(() -> { try { diff --git a/VelocityCore/src/de/steamwar/velocitycore/discord/channels/DiscordChannel.java b/VelocityCore/src/de/steamwar/velocitycore/discord/channels/DiscordChannel.java index 7092aeb4..08b2b3cd 100644 --- a/VelocityCore/src/de/steamwar/velocitycore/discord/channels/DiscordChannel.java +++ b/VelocityCore/src/de/steamwar/velocitycore/discord/channels/DiscordChannel.java @@ -26,17 +26,21 @@ import de.steamwar.velocitycore.discord.DiscordBot; import de.steamwar.velocitycore.discord.listeners.ChannelListener; import lombok.AllArgsConstructor; import lombok.Getter; -import net.dv8tion.jda.api.entities.Icon; import net.dv8tion.jda.api.entities.User; +import net.dv8tion.jda.api.entities.Webhook; +import net.dv8tion.jda.api.entities.WebhookClient; import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel; import net.dv8tion.jda.api.events.interaction.component.GenericComponentInteractionCreateEvent; import net.dv8tion.jda.api.events.message.MessageReceivedEvent; -import net.dv8tion.jda.api.utils.ImageProxy; import net.dv8tion.jda.api.utils.messages.MessageCreateBuilder; +import net.dv8tion.jda.internal.requests.IncomingWebhookClientImpl; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer; +import java.util.ArrayDeque; +import java.util.Queue; + @AllArgsConstructor public class DiscordChannel extends Chatter.PlayerlessChatter { @@ -46,31 +50,37 @@ public class DiscordChannel extends Chatter.PlayerlessChatter { return user != null ? user : SteamwarUser.get(0); } + private final Queue webhooks = new ArrayDeque<>(); + private final int maxNumberOfWebhooks; + private final SteamwarUser user; @Getter private final MessageChannel channel; public DiscordChannel(User user) { - this(userOrPublic(user), user.openPrivateChannel().complete()); + this(0, userOrPublic(user), user.openPrivateChannel().complete()); } - public DiscordChannel(String channel) { - this(DiscordBot.getGuild().getTextChannelById(channel)); + public DiscordChannel(String channel, int maxNumberOfWebhooks) { + this(DiscordBot.getGuild().getTextChannelById(channel), maxNumberOfWebhooks); } - public DiscordChannel(MessageChannel channel) { - this(SteamwarUser.get(-1), channel); + public DiscordChannel(MessageChannel channel, int maxNumberOfWebhooks) { + this(maxNumberOfWebhooks, SteamwarUser.get(-1), channel); ChannelListener.getChannels().put(this.channel, this); + if (channel instanceof TextChannel) { + webhooks.addAll(((TextChannel) channel).retrieveWebhooks().complete()); + } } - public void send(String message) { + public synchronized void send(String message) { message = message .replace("&", "") .replace("@everyone", "`@everyone`") .replace("@here", "`@here`") .replaceAll("<[@#]!?\\d+>", "`$0`"); - if (getChannel() instanceof TextChannel && message.contains("»")) { + if (maxNumberOfWebhooks > 0 && getChannel() instanceof TextChannel && message.contains("»")) { String[] strings = message.split("»", 2); String userName = strings[0]; String sendMessage = strings[1]; @@ -85,29 +95,28 @@ public class DiscordChannel extends Chatter.PlayerlessChatter { return; } - ImageProxy avatarUrl; + String avatarUrl; if (user.getDiscordId() != null) { - avatarUrl = DiscordBot.getGuild().retrieveMemberById(user.getDiscordId()).complete().getEffectiveAvatar(); + avatarUrl = DiscordBot.getGuild().retrieveMemberById(user.getDiscordId()).complete().getEffectiveAvatarUrl(); } else { - avatarUrl = DiscordBot.getInstance().getJda().getSelfUser().getAvatar(); + avatarUrl = DiscordBot.getInstance().getJda().getSelfUser().getAvatarUrl(); } TextChannel textChannel = (TextChannel) getChannel(); - try { - textChannel.createWebhook(userName) - .setAvatar(Icon.from(avatarUrl.download(128).get())) - .onSuccess(webhook -> { - webhook.sendMessage(sendMessage) - .onSuccess(__ -> { - webhook.delete().queue(); - }) - .queue(); - }) - .queue(); - return; - } catch (Exception e) { - // Ignore and send message as normal! + if (webhooks.size() < maxNumberOfWebhooks) { + webhooks.add(textChannel.createWebhook(DiscordBot.getInstance().getJda().getSelfUser().getName() + "_" + webhooks.size()).complete()); } + Webhook webhook = webhooks.poll(); + webhooks.add(webhook); + + // This works as per this documentation: https://discord.com/developers/docs/resources/webhook#execute-webhook + IncomingWebhookClientImpl webhookClient = (IncomingWebhookClientImpl) WebhookClient.createClient(DiscordBot.getInstance().getJda(), webhook.getUrl()); + webhookClient.sendRequest() + .setUsername(userName) + .setAvatarUrl(avatarUrl) + .setContent(sendMessage) + .queue(); + return; } send(new MessageCreateBuilder() diff --git a/VelocityCore/src/de/steamwar/velocitycore/discord/channels/DiscordChatRoom.java b/VelocityCore/src/de/steamwar/velocitycore/discord/channels/DiscordChatRoom.java index 7b05357c..2db981f1 100644 --- a/VelocityCore/src/de/steamwar/velocitycore/discord/channels/DiscordChatRoom.java +++ b/VelocityCore/src/de/steamwar/velocitycore/discord/channels/DiscordChatRoom.java @@ -33,8 +33,8 @@ public class DiscordChatRoom extends DiscordChannel { private final String format; private final Supplier target; - public DiscordChatRoom(String channel, String format, Supplier target) { - super(channel); + public DiscordChatRoom(String channel, String format, Supplier target, int maxNumberOfWebhooks) { + super(channel, maxNumberOfWebhooks); this.format = format; this.target = target; } diff --git a/VelocityCore/src/de/steamwar/velocitycore/discord/listeners/DiscordTicketHandler.java b/VelocityCore/src/de/steamwar/velocitycore/discord/listeners/DiscordTicketHandler.java index f32b4767..d58fc6a5 100644 --- a/VelocityCore/src/de/steamwar/velocitycore/discord/listeners/DiscordTicketHandler.java +++ b/VelocityCore/src/de/steamwar/velocitycore/discord/listeners/DiscordTicketHandler.java @@ -70,7 +70,7 @@ public class DiscordTicketHandler extends ListenerAdapter { Permission.MESSAGE_HISTORY).complete(); ticketChannel.getManager().setTopic(event.getUser().getId()).complete(); - DiscordChannel channel = new DiscordChannel(DiscordChannel.userOrPublic(event.getUser()), ticketChannel); + DiscordChannel channel = new DiscordChannel(0, DiscordChannel.userOrPublic(event.getUser()), ticketChannel); channel.send(new MessageCreateBuilder() .setEmbeds(new EmbedBuilder() .setTitle(channel.parseToPlain("DC_TICKET_TITLE"))