Improve and fix the discord rate limit warnings

This commit is contained in:
2025-04-08 20:52:54 +02:00
parent eefe17e5f7
commit 4c6ab2c1a0
4 changed files with 46 additions and 32 deletions
@@ -167,14 +167,19 @@ public class DiscordBot {
checklistChannel = new ChecklistChannel(config.channel("checklist")); checklistChannel = new ChecklistChannel(config.channel("checklist"));
config.getCouncilThread().forEach((roleId, threadId) -> new CouncilChannel(DiscordBot.getGuild().getRoleById(roleId), DiscordBot.getGuild().getThreadChannelById(threadId))); 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 @Override
public void received(MessageReceivedEvent event) { public void received(MessageReceivedEvent event) {
Chatter.broadcast().system("ALERT", event.getMessage().getContentDisplay()); 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(() -> { VelocityCore.schedule(() -> {
try { try {
@@ -26,17 +26,21 @@ import de.steamwar.velocitycore.discord.DiscordBot;
import de.steamwar.velocitycore.discord.listeners.ChannelListener; import de.steamwar.velocitycore.discord.listeners.ChannelListener;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Getter; import lombok.Getter;
import net.dv8tion.jda.api.entities.Icon;
import net.dv8tion.jda.api.entities.User; 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.concrete.TextChannel;
import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel; import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel;
import net.dv8tion.jda.api.events.interaction.component.GenericComponentInteractionCreateEvent; import net.dv8tion.jda.api.events.interaction.component.GenericComponentInteractionCreateEvent;
import net.dv8tion.jda.api.events.message.MessageReceivedEvent; 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.api.utils.messages.MessageCreateBuilder;
import net.dv8tion.jda.internal.requests.IncomingWebhookClientImpl;
import net.kyori.adventure.text.Component; import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer; import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer;
import java.util.ArrayDeque;
import java.util.Queue;
@AllArgsConstructor @AllArgsConstructor
public class DiscordChannel extends Chatter.PlayerlessChatter { public class DiscordChannel extends Chatter.PlayerlessChatter {
@@ -46,31 +50,37 @@ public class DiscordChannel extends Chatter.PlayerlessChatter {
return user != null ? user : SteamwarUser.get(0); return user != null ? user : SteamwarUser.get(0);
} }
private final Queue<Webhook> webhooks = new ArrayDeque<>();
private final int maxNumberOfWebhooks;
private final SteamwarUser user; private final SteamwarUser user;
@Getter @Getter
private final MessageChannel channel; private final MessageChannel channel;
public DiscordChannel(User user) { public DiscordChannel(User user) {
this(userOrPublic(user), user.openPrivateChannel().complete()); this(0, userOrPublic(user), user.openPrivateChannel().complete());
} }
public DiscordChannel(String channel) { public DiscordChannel(String channel, int maxNumberOfWebhooks) {
this(DiscordBot.getGuild().getTextChannelById(channel)); this(DiscordBot.getGuild().getTextChannelById(channel), maxNumberOfWebhooks);
} }
public DiscordChannel(MessageChannel channel) { public DiscordChannel(MessageChannel channel, int maxNumberOfWebhooks) {
this(SteamwarUser.get(-1), channel); this(maxNumberOfWebhooks, SteamwarUser.get(-1), channel);
ChannelListener.getChannels().put(this.channel, this); 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 message = message
.replace("&", "") .replace("&", "")
.replace("@everyone", "`@everyone`") .replace("@everyone", "`@everyone`")
.replace("@here", "`@here`") .replace("@here", "`@here`")
.replaceAll("<[@#]!?\\d+>", "`$0`"); .replaceAll("<[@#]!?\\d+>", "`$0`");
if (getChannel() instanceof TextChannel && message.contains("»")) { if (maxNumberOfWebhooks > 0 && getChannel() instanceof TextChannel && message.contains("»")) {
String[] strings = message.split("»", 2); String[] strings = message.split("»", 2);
String userName = strings[0]; String userName = strings[0];
String sendMessage = strings[1]; String sendMessage = strings[1];
@@ -85,29 +95,28 @@ public class DiscordChannel extends Chatter.PlayerlessChatter {
return; return;
} }
ImageProxy avatarUrl; String avatarUrl;
if (user.getDiscordId() != null) { if (user.getDiscordId() != null) {
avatarUrl = DiscordBot.getGuild().retrieveMemberById(user.getDiscordId()).complete().getEffectiveAvatar(); avatarUrl = DiscordBot.getGuild().retrieveMemberById(user.getDiscordId()).complete().getEffectiveAvatarUrl();
} else { } else {
avatarUrl = DiscordBot.getInstance().getJda().getSelfUser().getAvatar(); avatarUrl = DiscordBot.getInstance().getJda().getSelfUser().getAvatarUrl();
} }
TextChannel textChannel = (TextChannel) getChannel(); TextChannel textChannel = (TextChannel) getChannel();
try { if (webhooks.size() < maxNumberOfWebhooks) {
textChannel.createWebhook(userName) webhooks.add(textChannel.createWebhook(DiscordBot.getInstance().getJda().getSelfUser().getName() + "_" + webhooks.size()).complete());
.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!
} }
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() send(new MessageCreateBuilder()
@@ -33,8 +33,8 @@ public class DiscordChatRoom extends DiscordChannel {
private final String format; private final String format;
private final Supplier<ChatterGroup> target; private final Supplier<ChatterGroup> target;
public DiscordChatRoom(String channel, String format, Supplier<ChatterGroup> target) { public DiscordChatRoom(String channel, String format, Supplier<ChatterGroup> target, int maxNumberOfWebhooks) {
super(channel); super(channel, maxNumberOfWebhooks);
this.format = format; this.format = format;
this.target = target; this.target = target;
} }
@@ -70,7 +70,7 @@ public class DiscordTicketHandler extends ListenerAdapter {
Permission.MESSAGE_HISTORY).complete(); Permission.MESSAGE_HISTORY).complete();
ticketChannel.getManager().setTopic(event.getUser().getId()).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() channel.send(new MessageCreateBuilder()
.setEmbeds(new EmbedBuilder() .setEmbeds(new EmbedBuilder()
.setTitle(channel.parseToPlain("DC_TICKET_TITLE")) .setTitle(channel.parseToPlain("DC_TICKET_TITLE"))