diff --git a/VelocityCore/src/de/steamwar/velocitycore/discord/DiscordBot.java b/VelocityCore/src/de/steamwar/velocitycore/discord/DiscordBot.java index ecdc5a53..637b0c7e 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 8 webhooks we can send + // 240 messages per minute. Which means 4 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, 8); + // 60 messages per minute should be enough for the server team! + serverTeamChat = new DiscordChatRoom(config.channel("serverteam"), "CHAT_SERVERTEAM", Chatter::serverteam, 2); VelocityCore.schedule(() -> { try { diff --git a/VelocityCore/src/de/steamwar/velocitycore/discord/channels/ChecklistChannel.java b/VelocityCore/src/de/steamwar/velocitycore/discord/channels/ChecklistChannel.java index 6f19f34e..18bbff4a 100644 --- a/VelocityCore/src/de/steamwar/velocitycore/discord/channels/ChecklistChannel.java +++ b/VelocityCore/src/de/steamwar/velocitycore/discord/channels/ChecklistChannel.java @@ -32,7 +32,7 @@ public class ChecklistChannel extends DiscordChannel { private final List lastSchematics = new ArrayList<>(); public ChecklistChannel(String channel) { - super(channel); + super(channel, 0); } public void update() { diff --git a/VelocityCore/src/de/steamwar/velocitycore/discord/channels/DiscordChannel.java b/VelocityCore/src/de/steamwar/velocitycore/discord/channels/DiscordChannel.java index 7092aeb4..5fcbcf6a 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,21 +50,36 @@ public class DiscordChannel extends Chatter.PlayerlessChatter { return user != null ? user : SteamwarUser.get(0); } + private final Queue webhooks = new ArrayDeque<>(); + private final SteamwarUser user; @Getter private final MessageChannel channel; + private final int maxNumberOfWebhooks; + public DiscordChannel(User user) { - this(userOrPublic(user), user.openPrivateChannel().complete()); + this(userOrPublic(user), user.openPrivateChannel().complete(), 0); } - 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(SteamwarUser.get(-1), channel, maxNumberOfWebhooks); ChannelListener.getChannels().put(this.channel, this); + + if (channel instanceof TextChannel) { + TextChannel textChannel = (TextChannel) channel; + webhooks.addAll(textChannel.retrieveWebhooks().complete()); + while (webhooks.size() > maxNumberOfWebhooks) { + webhooks.remove().delete().queue(); + } + while (webhooks.size() < maxNumberOfWebhooks) { + webhooks.add(textChannel.createWebhook(DiscordBot.getInstance().getJda().getSelfUser().getName()).complete()); + } + } } public void send(String message) { @@ -70,7 +89,7 @@ public class DiscordChannel extends Chatter.PlayerlessChatter { .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 +104,24 @@ 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! - } + 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/channels/StaticMessageChannel.java b/VelocityCore/src/de/steamwar/velocitycore/discord/channels/StaticMessageChannel.java index 69549d38..9ab2920e 100644 --- a/VelocityCore/src/de/steamwar/velocitycore/discord/channels/StaticMessageChannel.java +++ b/VelocityCore/src/de/steamwar/velocitycore/discord/channels/StaticMessageChannel.java @@ -46,14 +46,14 @@ public class StaticMessageChannel extends DiscordChannel { } public StaticMessageChannel(String channel, Supplier supplier, Consumer interaction) { - super(channel); + super(channel, 0); this.supplier = supplier; this.interaction = interaction; init(); } public StaticMessageChannel(MessageChannel channel, Supplier supplier, Consumer interaction) { - super(channel); + super(channel, 0); this.supplier = supplier; this.interaction = interaction; init(); diff --git a/VelocityCore/src/de/steamwar/velocitycore/discord/listeners/DiscordTicketHandler.java b/VelocityCore/src/de/steamwar/velocitycore/discord/listeners/DiscordTicketHandler.java index f32b4767..5c5e708b 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(DiscordChannel.userOrPublic(event.getUser()), ticketChannel, 0); channel.send(new MessageCreateBuilder() .setEmbeds(new EmbedBuilder() .setTitle(channel.parseToPlain("DC_TICKET_TITLE"))