diff --git a/build.gradle b/build.gradle index 1e8d83c..d640c23 100644 --- a/build.gradle +++ b/build.gradle @@ -45,6 +45,8 @@ dependencies { implementation("net.dv8tion:JDA:${project.jda_version}") { exclude module: 'opus-java' } + + include implementation("club.minnced:discord-webhooks:${project.webhooks_version}") } processResources { diff --git a/gradle.properties b/gradle.properties index c5a62fe..6c7a7d9 100644 --- a/gradle.properties +++ b/gradle.properties @@ -14,4 +14,5 @@ archives_base_name=discord fabric_version=0.107.0+1.21.1 owo_version=0.12.15+1.21 -jda_version=5.1.2 \ No newline at end of file +jda_version=5.1.2 +webhooks_version=0.8.4 diff --git a/src/main/java/sad/ovh/discord/Discord.java b/src/main/java/sad/ovh/discord/Discord.java index ec4f395..a4bbc68 100644 --- a/src/main/java/sad/ovh/discord/Discord.java +++ b/src/main/java/sad/ovh/discord/Discord.java @@ -13,7 +13,7 @@ public class Discord implements ModInitializer { @Override public void onInitialize() { LOGGER.info("slop's custom discord plugin"); - DiscordRegistration.createClient(); - + DiscordRegistration.register(); + MinecraftRegistration.register(); } } diff --git a/src/main/java/sad/ovh/discord/DiscordConfigModel.java b/src/main/java/sad/ovh/discord/DiscordConfigModel.java index 1c64a5d..f5506bf 100644 --- a/src/main/java/sad/ovh/discord/DiscordConfigModel.java +++ b/src/main/java/sad/ovh/discord/DiscordConfigModel.java @@ -1,14 +1,12 @@ package sad.ovh.discord; -import io.wispforest.owo.config.Option; import io.wispforest.owo.config.annotation.Config; -import io.wispforest.owo.config.annotation.Sync; -@Sync(Option.SyncMode.NONE) @Config(name = "slop-discord-config", wrapperName = "DiscordConfig") public class DiscordConfigModel { public String token = ""; public String channelId = ""; public String consoleId = ""; + public String webhookName = "mc-bridge"; public String avatarApiUrl = "https://vzge.me/bust/256/%s"; } diff --git a/src/main/java/sad/ovh/discord/DiscordRegistration.java b/src/main/java/sad/ovh/discord/DiscordRegistration.java index b863277..fc17019 100644 --- a/src/main/java/sad/ovh/discord/DiscordRegistration.java +++ b/src/main/java/sad/ovh/discord/DiscordRegistration.java @@ -1,7 +1,12 @@ package sad.ovh.discord; +import club.minnced.discord.webhook.WebhookClient; +import club.minnced.discord.webhook.WebhookClientBuilder; +import club.minnced.discord.webhook.receive.ReadonlyMessage; +import club.minnced.discord.webhook.send.*; import net.dv8tion.jda.api.JDA; import net.dv8tion.jda.api.JDABuilder; +import net.dv8tion.jda.api.entities.Webhook; import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import net.dv8tion.jda.api.events.message.MessageUpdateEvent; @@ -12,15 +17,21 @@ import net.dv8tion.jda.api.utils.cache.CacheFlag; import org.jetbrains.annotations.NotNull; import java.util.EnumSet; +import java.util.UUID; public class DiscordRegistration { static public JDA client; static public TextChannel channel; static public TextChannel consoleChannel; + static public WebhookClient webhookClient; static public Boolean isReady; - static public void createClient() { + static public Webhook webhook; + + static private Long lastId; + + static public void register() { client = JDABuilder .create(Discord.CONFIG.token(), EnumSet.of(GatewayIntent.GUILD_MESSAGES, GatewayIntent.GUILD_MEMBERS, GatewayIntent.MESSAGE_CONTENT)) .disableCache(CacheFlag.ACTIVITY, CacheFlag.VOICE_STATE, CacheFlag.EMOJI, CacheFlag.STICKER, CacheFlag.CLIENT_STATUS, CacheFlag.ONLINE_STATUS, CacheFlag.SCHEDULED_EVENTS) @@ -28,6 +39,57 @@ public class DiscordRegistration { .build(); } + static public void sendPlayerMessage(String message, String name, UUID playerUuid) { + if (!isReady) + return; + + String avatarUrl = String.format(Discord.CONFIG.avatarApiUrl(), playerUuid.toString()); + + WebhookMessage webhookMessage = new WebhookMessageBuilder() + .setAvatarUrl(avatarUrl) + .setUsername(name) + .setContent(message) + .setAllowedMentions( + new AllowedMentions() + .withParseUsers(true) + .withParseRoles(true) + .withParseEveryone(false) + ) + .build(); + webhookClient.send(webhookMessage); + } + + static public void sendPlayerStatus(String message, int color, UUID playerUuid) { + if (!isReady) + return; + + String avatarUrl = String.format(Discord.CONFIG.avatarApiUrl(), playerUuid.toString()); + + var embed = new WebhookEmbedBuilder() + .setAuthor(new WebhookEmbed.EmbedAuthor(message, avatarUrl, null)) + .setColor(color) + .build(); + + webhookClient.send(embed); + } + + + static public void sendServerUpdate(String message, int color, Boolean deleteLastOne) { + if (!isReady) + return; + + if(deleteLastOne && lastId != null) { + channel.deleteMessageById(lastId).complete(); + } + + WebhookEmbed webhookMessage = new WebhookEmbedBuilder() + .setDescription(message) + .setColor(color) + .build(); + + webhookClient.send(webhookMessage) + .thenAccept((msg) -> lastId = msg.getId()); + } private static class DiscordEvents extends ListenerAdapter { @Override public void onReady(@NotNull ReadyEvent event) { @@ -45,6 +107,27 @@ public class DiscordRegistration { if (consoleChannel == null) { Discord.LOGGER.warn("No console channel was set."); } + var webhookName = Discord.CONFIG.webhookName(); + var webhooks = channel.retrieveWebhooks().complete(); + + webhooks.stream() + .filter((wh) -> wh.getName().equals(webhookName)) + .findFirst() + .ifPresent((wh) -> webhook = wh); + + if (webhook == null) { + webhook = channel.createWebhook(webhookName).complete(); + } + + if (webhook == null) { + Discord.LOGGER.error("Attempt to create a webhook failed! Please create a WebHook by the name {} and restart the server", webhookName); + client.shutdown(); + return; + } + + webhookClient = new WebhookClientBuilder(webhook.getUrl()) + .setDaemon(true) + .buildJDA(); isReady = true; } diff --git a/src/main/java/sad/ovh/discord/MinecraftRegistration.java b/src/main/java/sad/ovh/discord/MinecraftRegistration.java index 89aeaac..87406bf 100644 --- a/src/main/java/sad/ovh/discord/MinecraftRegistration.java +++ b/src/main/java/sad/ovh/discord/MinecraftRegistration.java @@ -6,32 +6,41 @@ import net.fabricmc.fabric.api.message.v1.ServerMessageEvents; import net.fabricmc.fabric.api.networking.v1.ServerPlayConnectionEvents; import net.minecraft.server.network.ServerPlayerEntity; +import java.awt.*; + public class MinecraftRegistration { public static void register() { ServerLifecycleEvents.SERVER_STARTING.register(server -> { if (!DiscordRegistration.isReady) return; + DiscordRegistration.sendServerUpdate(":hourglass: **Server is starting...**", Color.YELLOW.getRGB(), false); }); ServerLifecycleEvents.SERVER_STARTED.register(server -> { if (!DiscordRegistration.isReady) return; + + DiscordRegistration.sendServerUpdate(":white_check_mark: **Server has started!**", Color.GREEN.getRGB(), true); }); ServerLifecycleEvents.SERVER_STOPPING.register(server -> { if (!DiscordRegistration.isReady) return; - + DiscordRegistration.sendServerUpdate(":x: **Server stopping.**", Color.RED.getRGB(), false); }); ServerPlayConnectionEvents.JOIN.register((handler, sender, server) -> { if (!DiscordRegistration.isReady) return; + DiscordRegistration.sendPlayerStatus(String.format("%s has joined the server.", handler.player.getDisplayName().getString()), Color.GREEN.getRGB(), handler.player.getUuid()); + }); ServerPlayConnectionEvents.DISCONNECT.register((handler, server) -> { if (!DiscordRegistration.isReady) return; + DiscordRegistration.sendPlayerStatus(String.format("%s has left the server.", handler.player.getDisplayName().getString()), Color.RED.getRGB(), handler.player.getUuid()); + }); ServerLivingEntityEvents.AFTER_DEATH.register((entity, damageSource) -> { @@ -39,11 +48,16 @@ public class MinecraftRegistration { return; if (!(entity instanceof ServerPlayerEntity player)) return; + var message = damageSource.getDeathMessage(entity).getString(); + DiscordRegistration.sendPlayerStatus(message, Color.RED.getRGB(), player.getUuid()); + }); ServerMessageEvents.CHAT_MESSAGE.register((message, sender, params) -> { if (!DiscordRegistration.isReady) return; + + DiscordRegistration.sendPlayerMessage(message.getContent().getString(), sender.getDisplayName().getString(), sender.getUuid()); }); } }