From 96e98e11e4d123c5b3584457bf53b2c9a02ea949 Mon Sep 17 00:00:00 2001 From: Xujiayao Date: Wed, 6 Dec 2023 23:56:00 +0800 Subject: [PATCH] =?UTF-8?q?=E5=85=BC=E5=AE=B91.20.3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes #202 --- build.gradle | 2 + gradle.properties | 6 +- settings.gradle | 3 +- .../discord/DiscordEventListener.java | 10 +- .../mixins/MixinPlayerAdvancementTracker.java | 6 +- .../minecraft/mixins/MixinPlayerManager.java | 24 +- .../mixins/MixinServerPlayNetworkHandler.java | 29 +- .../mixins/MixinServerPlayerEntity.java | 12 +- .../multi_server/client/ReadThread.java | 10 +- .../xujiayao/mcdiscordchat/utils/Utils.java | 18 +- versions/1.20.2/gradle.properties | 2 +- .../mixins/MixinServerPlayNetworkHandler.java | 317 ++++++++++++++++++ versions/1.20.3/gradle.properties | 11 + versions/mainProject | 2 +- 14 files changed, 410 insertions(+), 42 deletions(-) create mode 100644 versions/1.20.2/src/main/java/top/xujiayao/mcdiscordchat/minecraft/mixins/MixinServerPlayNetworkHandler.java create mode 100644 versions/1.20.3/gradle.properties diff --git a/build.gradle b/build.gradle index ba418410..24c08cf7 100644 --- a/build.gradle +++ b/build.gradle @@ -11,6 +11,7 @@ preprocess { def mc1194 = createNode("1.19.4", 1_19_04, "yarn") def mc1201 = createNode("1.20.1", 1_20_01, "yarn") def mc1202 = createNode("1.20.2", 1_20_02, "yarn") + def mc1203 = createNode("1.20.3", 1_20_03, "yarn") mc1152.link(mc1165, null) mc1165.link(mc1171, null) @@ -18,4 +19,5 @@ preprocess { mc1182.link(mc1194, null) mc1194.link(mc1201, null) mc1201.link(mc1202, null) + mc1202.link(mc1203, null) } \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index b354934c..a9bca1e7 100644 --- a/gradle.properties +++ b/gradle.properties @@ -9,7 +9,7 @@ archives_base_name=MC-Discord-Chat # Wrapper Properties # check these on https://fabricmc.net/develop -minecraft_version=1.20.2 -yarn_mappings=1.20.2+build.4 +minecraft_version=1.20.3 +yarn_mappings=1.20.3+build.1 loader_version=0.15.0 -fabric_version=0.91.1+1.20.2 \ No newline at end of file +fabric_version=0.91.1+1.20.3 \ No newline at end of file diff --git a/settings.gradle b/settings.gradle index aa664b60..bf14f90d 100644 --- a/settings.gradle +++ b/settings.gradle @@ -24,7 +24,8 @@ def versions = Arrays.asList( "1.18.2", "1.19.4", "1.20.1", - "1.20.2" + "1.20.2", + "1.20.3" ) for (String version : versions) { include(":$version") diff --git a/src/main/java/top/xujiayao/mcdiscordchat/discord/DiscordEventListener.java b/src/main/java/top/xujiayao/mcdiscordchat/discord/DiscordEventListener.java index 9cda040b..fe9a3fcc 100644 --- a/src/main/java/top/xujiayao/mcdiscordchat/discord/DiscordEventListener.java +++ b/src/main/java/top/xujiayao/mcdiscordchat/discord/DiscordEventListener.java @@ -95,7 +95,7 @@ public class DiscordEventListener extends ListenerAdapter { .replace("%command%", e.getCommandString()))); if (CONFIG.generic.broadcastSlashCommandExecution) { - Text commandNoticeText = Text.Serializer.fromJson(Translations.translateMessage("message.formattedCommandNotice") + Text commandNoticeText = Text.Serialization.fromJson(Translations.translateMessage("message.formattedCommandNotice") .replace("%name%", (CONFIG.generic.useServerNickname ? e.getMember().getEffectiveName() : e.getMember().getUser().getName()).replace("\\", "\\\\").replace("\"", "\\\"")) .replace("%roleName%", roleName) .replace("%roleColor%", "#" + Integer.toHexString(e.getMember().getColorRaw())) @@ -110,7 +110,7 @@ public class DiscordEventListener extends ListenerAdapter { //$$ .append(commandNoticeText), false)); //#else List commandNoticeTextList = new ArrayList<>(); - commandNoticeTextList.add(Text.Serializer.fromJson(Translations.translateMessage("message.formattedOtherMessage") + commandNoticeTextList.add(Text.Serialization.fromJson(Translations.translateMessage("message.formattedOtherMessage") .replace("%server%", (CONFIG.multiServer.enable ? CONFIG.multiServer.name : "Discord")) .replace("%message%", ""))); commandNoticeTextList.add(commandNoticeText); @@ -120,7 +120,7 @@ public class DiscordEventListener extends ListenerAdapter { //#endif if (CONFIG.multiServer.enable) { - MULTI_SERVER.sendMessage(false, false, true, null, Text.Serializer.toJson(commandNoticeText)); + MULTI_SERVER.sendMessage(false, false, true, null, Text.Serialization.toJsonString(commandNoticeText)); } } @@ -552,7 +552,7 @@ public class DiscordEventListener extends ListenerAdapter { if (CONFIG.generic.broadcastChatMessages) { if (e.getMessage().getReferencedMessage() != null) { String s = Translations.translateMessage("message.formattedResponseMessage"); - Text referenceFinalText = Text.Serializer.fromJson(s + Text referenceFinalText = Text.Serialization.fromJson(s .replace("%message%", (CONFIG.generic.formatChatMessages ? finalReferencedMessage : EmojiParser.parseToAliases(referencedMessageTemp).replace("\"", "\\\"")) .replace("\n", "\n" + textAfterPlaceholder[0] + "}," + s.substring(1, s.indexOf("%message%")))) .replace("%server%", "Discord") @@ -565,7 +565,7 @@ public class DiscordEventListener extends ListenerAdapter { } String s = Translations.translateMessage("message.formattedChatMessage"); - Text finalText = Text.Serializer.fromJson(s + Text finalText = Text.Serialization.fromJson(s .replace("%message%", (CONFIG.generic.formatChatMessages ? finalMessage : EmojiParser.parseToAliases(messageTemp).replace("\"", "\\\"")) .replace("\n", "\n" + textAfterPlaceholder[1] + "}," + s.substring(1, s.indexOf("%message%")))) .replace("%server%", "Discord") diff --git a/src/main/java/top/xujiayao/mcdiscordchat/minecraft/mixins/MixinPlayerAdvancementTracker.java b/src/main/java/top/xujiayao/mcdiscordchat/minecraft/mixins/MixinPlayerAdvancementTracker.java index 0c3344b4..744e89a8 100644 --- a/src/main/java/top/xujiayao/mcdiscordchat/minecraft/mixins/MixinPlayerAdvancementTracker.java +++ b/src/main/java/top/xujiayao/mcdiscordchat/minecraft/mixins/MixinPlayerAdvancementTracker.java @@ -48,7 +48,11 @@ public abstract class MixinPlayerAdvancementTracker { String description = Translations.translate("advancements." + advancement.id().getPath().replace("/", ".") + ".description"); message = message - .replace("%playerName%", MarkdownSanitizer.escape(owner.getEntityName())) + //#if MC >= 12003 + .replace("%playerName%", MarkdownSanitizer.escape(owner.getNameForScoreboard())) + //#else + //$$ .replace("%playerName%", MarkdownSanitizer.escape(owner.getEntityName())) + //#endif .replace("%advancement%", title.contains("TranslateError") ? advancement.value().display().get().getTitle().getString() : title) .replace("%description%", description.contains("TranslateError") ? advancement.value().display().get().getDescription().getString() : description); diff --git a/src/main/java/top/xujiayao/mcdiscordchat/minecraft/mixins/MixinPlayerManager.java b/src/main/java/top/xujiayao/mcdiscordchat/minecraft/mixins/MixinPlayerManager.java index 0889c724..a1aaac52 100644 --- a/src/main/java/top/xujiayao/mcdiscordchat/minecraft/mixins/MixinPlayerManager.java +++ b/src/main/java/top/xujiayao/mcdiscordchat/minecraft/mixins/MixinPlayerManager.java @@ -98,10 +98,18 @@ public class MixinPlayerManager { if (CONFIG.generic.announcePlayerJoinLeave) { CHANNEL.sendMessage(Translations.translateMessage("message.joinServer") - .replace("%playerName%", MarkdownSanitizer.escape(player.getEntityName()))).queue(); + //#if MC >= 12003 + .replace("%playerName%", MarkdownSanitizer.escape(player.getNameForScoreboard()))).queue(); + //#else + //$$ .replace("%playerName%", MarkdownSanitizer.escape(player.getEntityName()))).queue(); + //#endif if (CONFIG.multiServer.enable) { MULTI_SERVER.sendMessage(false, false, false, null, Translations.translateMessage("message.joinServer") - .replace("%playerName%", MarkdownSanitizer.escape(player.getEntityName()))); + //#if MC >= 12003 + .replace("%playerName%", MarkdownSanitizer.escape(player.getNameForScoreboard()))); + //#else + //$$ .replace("%playerName%", MarkdownSanitizer.escape(player.getEntityName()))); + //#endif } } } @@ -112,10 +120,18 @@ public class MixinPlayerManager { if (CONFIG.generic.announcePlayerJoinLeave) { CHANNEL.sendMessage(Translations.translateMessage("message.leftServer") - .replace("%playerName%", MarkdownSanitizer.escape(player.getEntityName()))).queue(); + //#if MC >= 12003 + .replace("%playerName%", MarkdownSanitizer.escape(player.getNameForScoreboard()))).queue(); + //#else + //$$ .replace("%playerName%", MarkdownSanitizer.escape(player.getEntityName()))).queue(); + //#endif if (CONFIG.multiServer.enable) { MULTI_SERVER.sendMessage(false, false, false, null, Translations.translateMessage("message.leftServer") - .replace("%playerName%", MarkdownSanitizer.escape(player.getEntityName()))); + //#if MC >= 12003 + .replace("%playerName%", MarkdownSanitizer.escape(player.getNameForScoreboard()))); + //#else + //$$ .replace("%playerName%", MarkdownSanitizer.escape(player.getEntityName()))); + //#endif } } } diff --git a/src/main/java/top/xujiayao/mcdiscordchat/minecraft/mixins/MixinServerPlayNetworkHandler.java b/src/main/java/top/xujiayao/mcdiscordchat/minecraft/mixins/MixinServerPlayNetworkHandler.java index b1b7c162..88221b9e 100644 --- a/src/main/java/top/xujiayao/mcdiscordchat/minecraft/mixins/MixinServerPlayNetworkHandler.java +++ b/src/main/java/top/xujiayao/mcdiscordchat/minecraft/mixins/MixinServerPlayNetworkHandler.java @@ -40,7 +40,6 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import top.xujiayao.mcdiscordchat.utils.MarkdownParser; import top.xujiayao.mcdiscordchat.utils.Translations; -import java.time.Instant; import java.util.List; import java.util.Objects; import java.util.Optional; @@ -81,7 +80,7 @@ public abstract class MixinServerPlayNetworkHandler extends ServerCommonNetworkH public abstract CompletableFuture filterText(String text); @Shadow - public abstract Optional validateMessage(String message, Instant timestamp, LastSeenMessageList.Acknowledgment acknowledgment); + public abstract Optional validateMessage(LastSeenMessageList.Acknowledgment acknowledgment); @Shadow public abstract void handleCommandExecution(CommandExecutionC2SPacket packet, LastSeenMessageList lastSeenMessages); @@ -100,7 +99,7 @@ public abstract class MixinServerPlayNetworkHandler extends ServerCommonNetworkH if (hasIllegalCharacter(packet.chatMessage())) { disconnect(Text.translatable("multiplayer.disconnect.illegal_characters")); } else { - Optional optional = validateMessage(packet.chatMessage(), packet.timestamp(), packet.acknowledgment()); + Optional optional = validateMessage(packet.acknowledgment()); if (optional.isPresent()) { String contentToDiscord = packet.chatMessage(); String contentToMinecraft = packet.chatMessage(); @@ -182,7 +181,7 @@ public abstract class MixinServerPlayNetworkHandler extends ServerCommonNetworkH if (CONFIG.generic.formatChatMessages) { try { SignedMessage signedMessage = getSignedMessage(packet, optional.get()); - server.getPlayerManager().broadcast(signedMessage.withUnsignedContent(Objects.requireNonNull(Text.Serializer.fromJson("[{\"text\":\"" + contentToMinecraft + "\"}]"))), player, MessageType.params(MessageType.CHAT, player)); + server.getPlayerManager().broadcast(signedMessage.withUnsignedContent(Objects.requireNonNull(Text.Serialization.fromJson("[{\"text\":\"" + contentToMinecraft + "\"}]"))), player, MessageType.params(MessageType.CHAT, player)); } catch (MessageChain.MessageChainException e) { handleMessageChainException(e); } @@ -198,17 +197,17 @@ public abstract class MixinServerPlayNetworkHandler extends ServerCommonNetworkH CompletableFuture completableFuture = filterText(signedMessage.getSignedContent()); Text text = server.getMessageDecorator().decorate(player, signedMessage.getContent()); - messageChainTaskQueue.append((executor) -> completableFuture.thenAcceptAsync((filteredMessage) -> { - SignedMessage signedMessage2 = signedMessage.withUnsignedContent(text).withFilterMask(filteredMessage.mask()); + messageChainTaskQueue.append(completableFuture, (filtered) -> { + SignedMessage signedMessage2 = signedMessage.withUnsignedContent(text).withFilterMask(filtered.mask()); handleDecoratedMessage(signedMessage2); - }, executor)); + }); }); } if (CONFIG.generic.broadcastChatMessages) { sendMessage(contentToDiscord, false); if (CONFIG.multiServer.enable) { - MULTI_SERVER.sendMessage(false, true, false, player.getEntityName(), CONFIG.generic.formatChatMessages ? contentToMinecraft : packet.chatMessage()); + MULTI_SERVER.sendMessage(false, true, false, player.getNameForScoreboard(), CONFIG.generic.formatChatMessages ? contentToMinecraft : packet.chatMessage()); } } } @@ -223,7 +222,7 @@ public abstract class MixinServerPlayNetworkHandler extends ServerCommonNetworkH if (hasIllegalCharacter(packet.command())) { disconnect(Text.translatable("multiplayer.disconnect.illegal_characters")); } else { - Optional optional = validateMessage(packet.command(), packet.timestamp(), packet.acknowledgment()); + Optional optional = validateMessage(packet.acknowledgment()); if (optional.isPresent()) { server.submit(() -> { handleCommandExecution(packet, optional.get()); @@ -246,7 +245,7 @@ public abstract class MixinServerPlayNetworkHandler extends ServerCommonNetworkH MINECRAFT_SEND_COUNT++; if (MINECRAFT_SEND_COUNT <= 20) { - Text text = Text.of("<" + player.getEntityName() + "> " + input); + Text text = Text.of("<" + player.getNameForScoreboard() + "> " + input); server.getPlayerManager().getPlayerList().forEach( player -> player.sendMessage(text, false)); @@ -255,7 +254,7 @@ public abstract class MixinServerPlayNetworkHandler extends ServerCommonNetworkH sendMessage(input, true); if (CONFIG.multiServer.enable) { - MULTI_SERVER.sendMessage(false, true, false, player.getEntityName(), MarkdownSanitizer.escape(input)); + MULTI_SERVER.sendMessage(false, true, false, player.getNameForScoreboard(), MarkdownSanitizer.escape(input)); } } } @@ -272,18 +271,18 @@ public abstract class MixinServerPlayNetworkHandler extends ServerCommonNetworkH if (CONFIG.multiServer.enable) { CHANNEL.sendMessage(Translations.translateMessage("message.messageWithoutWebhookForMultiServer") .replace("%server%", CONFIG.multiServer.name) - .replace("%name%", player.getEntityName()) + .replace("%name%", player.getNameForScoreboard()) .replace("%message%", content)).queue(); } else { CHANNEL.sendMessage(Translations.translateMessage("message.messageWithoutWebhook") - .replace("%name%", player.getEntityName()) + .replace("%name%", player.getNameForScoreboard()) .replace("%message%", content)).queue(); } } else { JsonObject body = new JsonObject(); body.addProperty("content", content); - body.addProperty("username", ((CONFIG.multiServer.enable) ? ("[" + CONFIG.multiServer.name + "] " + player.getEntityName()) : player.getEntityName())); - body.addProperty("avatar_url", CONFIG.generic.avatarApi.replace("%player%", (CONFIG.generic.useUuidInsteadOfName ? player.getUuid().toString() : player.getEntityName()))); + body.addProperty("username", ((CONFIG.multiServer.enable) ? ("[" + CONFIG.multiServer.name + "] " + player.getNameForScoreboard()) : player.getNameForScoreboard())); + body.addProperty("avatar_url", CONFIG.generic.avatarApi.replace("%player%", (CONFIG.generic.useUuidInsteadOfName ? player.getUuid().toString() : player.getNameForScoreboard()))); JsonObject allowedMentions = new JsonObject(); allowedMentions.add("parse", new Gson().toJsonTree(CONFIG.generic.allowedMentions).getAsJsonArray()); diff --git a/src/main/java/top/xujiayao/mcdiscordchat/minecraft/mixins/MixinServerPlayerEntity.java b/src/main/java/top/xujiayao/mcdiscordchat/minecraft/mixins/MixinServerPlayerEntity.java index a9cf30c7..d37769a9 100644 --- a/src/main/java/top/xujiayao/mcdiscordchat/minecraft/mixins/MixinServerPlayerEntity.java +++ b/src/main/java/top/xujiayao/mcdiscordchat/minecraft/mixins/MixinServerPlayerEntity.java @@ -65,11 +65,19 @@ public abstract class MixinServerPlayerEntity extends PlayerEntity { CHANNEL.sendMessage(Translations.translateMessage("message.deathMessage") .replace("%deathMessage%", MarkdownSanitizer.escape(Translations.translate(key, args))) - .replace("%playerName%", MarkdownSanitizer.escape(this.getEntityName()))).queue(); + //#if MC >= 12003 + .replace("%playerName%", MarkdownSanitizer.escape(this.getNameForScoreboard()))).queue(); + //#else + //$$ .replace("%playerName%", MarkdownSanitizer.escape(this.getEntityName()))).queue(); + //#endif if (CONFIG.multiServer.enable) { MULTI_SERVER.sendMessage(false, false, false, null, Translations.translateMessage("message.deathMessage") .replace("%deathMessage%", MarkdownSanitizer.escape(Translations.translate(key, args))) - .replace("%playerName%", MarkdownSanitizer.escape(this.getEntityName()))); + //#if MC >= 12003 + .replace("%playerName%", MarkdownSanitizer.escape(this.getNameForScoreboard()))); + //#else + //$$ .replace("%playerName%", MarkdownSanitizer.escape(this.getEntityName()))); + //#endif } } } diff --git a/src/main/java/top/xujiayao/mcdiscordchat/multi_server/client/ReadThread.java b/src/main/java/top/xujiayao/mcdiscordchat/multi_server/client/ReadThread.java index 05061c35..ea365c28 100644 --- a/src/main/java/top/xujiayao/mcdiscordchat/multi_server/client/ReadThread.java +++ b/src/main/java/top/xujiayao/mcdiscordchat/multi_server/client/ReadThread.java @@ -98,7 +98,7 @@ public class ReadThread extends Thread { .replace("%name%", json.get("playerName").getAsString()) .replace("%message%", json.get("message").getAsString())); - Text text = Text.Serializer.fromJson(Translations.translateMessage("message.formattedChatMessage") + Text text = Text.Serialization.fromJson(Translations.translateMessage("message.formattedChatMessage") .replace("%server%", json.get("serverName").getAsString()) .replace("%name%", json.get("playerName").getAsString()) .replace("%roleColor%", "white") @@ -110,9 +110,9 @@ public class ReadThread extends Thread { if (json.get("isText").getAsBoolean()) { LOGGER.info(Translations.translateMessage("message.unformattedOtherMessage") .replace("%server%", json.get("serverName").getAsString()) - .replace("%message%", Objects.requireNonNull(Text.Serializer.fromJson(json.get("message").getAsString())).getString())); + .replace("%message%", Objects.requireNonNull(Text.Serialization.fromJson(json.get("message").getAsString())).getString())); - Text text = Text.Serializer.fromJson(Translations.translateMessage("message.formattedOtherMessage") + Text text = Text.Serialization.fromJson(Translations.translateMessage("message.formattedOtherMessage") .replace("%server%", json.get("serverName").getAsString()) .replace("%message%", "")); @@ -124,7 +124,7 @@ public class ReadThread extends Thread { //#else List textList = new ArrayList<>(); textList.add(text); - textList.add(Text.Serializer.fromJson(json.get("message").getAsString())); + textList.add(Text.Serialization.fromJson(json.get("message").getAsString())); SERVER.getPlayerManager().getPlayerList().forEach( player -> player.sendMessage(Texts.join(textList, Text.of("")), false)); @@ -134,7 +134,7 @@ public class ReadThread extends Thread { .replace("%server%", json.get("serverName").getAsString()) .replace("%message%", json.get("message").getAsString())); - Text text = Text.Serializer.fromJson(Translations.translateMessage("message.formattedOtherMessage") + Text text = Text.Serialization.fromJson(Translations.translateMessage("message.formattedOtherMessage") .replace("%server%", json.get("serverName").getAsString()) .replace("%message%", MarkdownParser.parseMarkdown(json.get("message").getAsString()))); diff --git a/src/main/java/top/xujiayao/mcdiscordchat/utils/Utils.java b/src/main/java/top/xujiayao/mcdiscordchat/utils/Utils.java index 516b707a..dd1e900e 100644 --- a/src/main/java/top/xujiayao/mcdiscordchat/utils/Utils.java +++ b/src/main/java/top/xujiayao/mcdiscordchat/utils/Utils.java @@ -402,8 +402,10 @@ public class Utils { message.append(Translations.translate("utils.utils.gicMessage.noPlayersOnline")); } else { for (ServerPlayerEntity player : onlinePlayers) { - //#if MC >= 12002 - message.append("[").append(player.networkHandler.getLatency()).append("ms] ").append(player.getEntityName()).append("\n"); + //#if MC >= 12003 + message.append("[").append(player.networkHandler.getLatency()).append("ms] ").append(player.getNameForScoreboard()).append("\n"); + //#elseif MC >= 12002 + //$$ message.append("[").append(player.networkHandler.getLatency()).append("ms] ").append(player.getEntityName()).append("\n"); //#else //$$ message.append("[").append(player.pingMilliseconds).append("ms] ").append(player.getEntityName()).append("\n"); //#endif @@ -411,7 +413,11 @@ public class Utils { } // Server TPS - double serverTickTime = average(SERVER.lastTickLengths) * 1.0E-6D; + //#if MC >= 12003 + double serverTickTime = average(SERVER.getTickTimes()) * 1.0E-6D; + //#else + //$$ double serverTickTime = average(SERVER.lastTickLengths) * 1.0E-6D; + //#endif message.append(Translations.translate("utils.utils.gicMessage.serverTps", String.format("%.2f", Math.min(1000.0 / serverTickTime, 20)))); // Server MSPT @@ -520,7 +526,11 @@ public class Utils { MSPT_MONITOR_TIMER.schedule(new TimerTask() { @Override public void run() { - double mspt = average(SERVER.lastTickLengths) * 1.0E-6D; + //#if MC >= 12003 + double mspt = average(SERVER.getTickTimes()) * 1.0E-6D; + //#else + //$$ double mspt = average(SERVER.lastTickLengths) * 1.0E-6D; + //#endif if (mspt > CONFIG.generic.msptLimit) { String message = Translations.translateMessage("message.highMspt") diff --git a/versions/1.20.2/gradle.properties b/versions/1.20.2/gradle.properties index da0674d6..7c75ae55 100644 --- a/versions/1.20.2/gradle.properties +++ b/versions/1.20.2/gradle.properties @@ -5,7 +5,7 @@ yarn_mappings=1.20.2+build.4 loader_version=0.15.0 # Fabric Mod Metadata -minecraft_dependency=~1.20.2 +minecraft_dependency=1.20.2 # Dependencies fabric_version=0.91.1+1.20.2 \ No newline at end of file diff --git a/versions/1.20.2/src/main/java/top/xujiayao/mcdiscordchat/minecraft/mixins/MixinServerPlayNetworkHandler.java b/versions/1.20.2/src/main/java/top/xujiayao/mcdiscordchat/minecraft/mixins/MixinServerPlayNetworkHandler.java new file mode 100644 index 00000000..d983f76e --- /dev/null +++ b/versions/1.20.2/src/main/java/top/xujiayao/mcdiscordchat/minecraft/mixins/MixinServerPlayNetworkHandler.java @@ -0,0 +1,317 @@ +//#if MC >= 12002 +package top.xujiayao.mcdiscordchat.minecraft.mixins; + +import com.google.gson.Gson; +import com.google.gson.JsonObject; +import com.vdurmont.emoji.EmojiManager; +import net.dv8tion.jda.api.entities.Member; +import net.dv8tion.jda.api.entities.Role; +import net.dv8tion.jda.api.entities.emoji.RichCustomEmoji; +import net.dv8tion.jda.api.utils.MarkdownSanitizer; +import net.minecraft.SharedConstants; +import net.minecraft.network.ClientConnection; +import net.minecraft.network.message.LastSeenMessageList; +import net.minecraft.network.message.MessageChain; +import net.minecraft.network.message.MessageChainTaskQueue; +import net.minecraft.network.message.MessageType; +import net.minecraft.network.message.SignedMessage; +import net.minecraft.network.packet.c2s.play.ChatMessageC2SPacket; +import net.minecraft.network.packet.c2s.play.CommandExecutionC2SPacket; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.filter.FilteredMessage; +import net.minecraft.server.network.ConnectedClientData; +import net.minecraft.server.network.ServerCommonNetworkHandler; +import net.minecraft.server.network.ServerPlayNetworkHandler; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.text.Text; +import net.minecraft.util.Formatting; +import okhttp3.MediaType; +import okhttp3.Request; +import okhttp3.RequestBody; +import okhttp3.Response; +import org.apache.commons.lang3.ArrayUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.exception.ExceptionUtils; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import top.xujiayao.mcdiscordchat.utils.MarkdownParser; +import top.xujiayao.mcdiscordchat.utils.Translations; + +import java.time.Instant; +import java.util.List; +import java.util.Objects; +import java.util.Optional; +import java.util.concurrent.CompletableFuture; + +import static top.xujiayao.mcdiscordchat.Main.CHANNEL; +import static top.xujiayao.mcdiscordchat.Main.CONFIG; +import static top.xujiayao.mcdiscordchat.Main.HTTP_CLIENT; +import static top.xujiayao.mcdiscordchat.Main.JDA; +import static top.xujiayao.mcdiscordchat.Main.LOGGER; +import static top.xujiayao.mcdiscordchat.Main.MINECRAFT_LAST_RESET_TIME; +import static top.xujiayao.mcdiscordchat.Main.MINECRAFT_SEND_COUNT; +import static top.xujiayao.mcdiscordchat.Main.MULTI_SERVER; +import static top.xujiayao.mcdiscordchat.Main.SERVER; +import static top.xujiayao.mcdiscordchat.Main.WEBHOOK; + +/** + * @author Xujiayao + */ +@Mixin(ServerPlayNetworkHandler.class) +public abstract class MixinServerPlayNetworkHandler extends ServerCommonNetworkHandler { + + @Shadow + private ServerPlayerEntity player; + + @Final + @Shadow + private MessageChainTaskQueue messageChainTaskQueue; + + protected MixinServerPlayNetworkHandler(MinecraftServer server, ClientConnection connection, ConnectedClientData clientData) { + super(server, connection, clientData); + } + + @Shadow + public abstract void checkForSpam(); + + @Shadow + public abstract CompletableFuture filterText(String text); + + @Shadow + public abstract Optional validateMessage(String message, Instant timestamp, LastSeenMessageList.Acknowledgment acknowledgment); + + @Shadow + public abstract void handleCommandExecution(CommandExecutionC2SPacket packet, LastSeenMessageList lastSeenMessages); + + @Shadow + public abstract SignedMessage getSignedMessage(ChatMessageC2SPacket packet, LastSeenMessageList lastSeenMessages) throws MessageChain.MessageChainException; + + @Shadow + public abstract void handleDecoratedMessage(SignedMessage message); + + @Shadow + public abstract void handleMessageChainException(MessageChain.MessageChainException exception); + + @Inject(method = "onChatMessage", at = @At("HEAD"), cancellable = true) + private void onChatMessage(ChatMessageC2SPacket packet, CallbackInfo ci) { + if (hasIllegalCharacter(packet.chatMessage())) { + disconnect(Text.translatable("multiplayer.disconnect.illegal_characters")); + } else { + Optional optional = validateMessage(packet.chatMessage(), packet.timestamp(), packet.acknowledgment()); + if (optional.isPresent()) { + String contentToDiscord = packet.chatMessage(); + String contentToMinecraft = packet.chatMessage(); + + if (StringUtils.countMatches(contentToDiscord, ":") >= 2) { + String[] emojiNames = StringUtils.substringsBetween(contentToDiscord, ":", ":"); + for (String emojiName : emojiNames) { + List emojis = JDA.getEmojisByName(emojiName, true); + if (!emojis.isEmpty()) { + contentToDiscord = StringUtils.replaceIgnoreCase(contentToDiscord, (":" + emojiName + ":"), emojis.get(0).getAsMention()); + contentToMinecraft = StringUtils.replaceIgnoreCase(contentToMinecraft, (":" + emojiName + ":"), (Formatting.YELLOW + ":" + emojiName + ":" + Formatting.RESET)); + } else if (EmojiManager.getForAlias(emojiName) != null) { + contentToMinecraft = StringUtils.replaceIgnoreCase(contentToMinecraft, (":" + emojiName + ":"), (Formatting.YELLOW + ":" + emojiName + ":" + Formatting.RESET)); + } + } + } + + if (!CONFIG.generic.allowedMentions.isEmpty() && contentToDiscord.contains("@")) { + if (CONFIG.generic.allowedMentions.contains("users")) { + for (Member member : CHANNEL.getMembers()) { + String usernameMention = "@" + member.getUser().getName(); + String displayNameMention = "@" + member.getUser().getEffectiveName(); + String formattedMention = Formatting.YELLOW + "@" + member.getEffectiveName() + Formatting.RESET; + + contentToDiscord = StringUtils.replaceIgnoreCase(contentToDiscord, usernameMention, member.getAsMention()); + contentToMinecraft = StringUtils.replaceIgnoreCase(contentToMinecraft, usernameMention, MarkdownSanitizer.escape(formattedMention)); + + contentToDiscord = StringUtils.replaceIgnoreCase(contentToDiscord, displayNameMention, member.getAsMention()); + contentToMinecraft = StringUtils.replaceIgnoreCase(contentToMinecraft, displayNameMention, MarkdownSanitizer.escape(formattedMention)); + + if (member.getNickname() != null) { + String nicknameMention = "@" + member.getNickname(); + contentToDiscord = StringUtils.replaceIgnoreCase(contentToDiscord, nicknameMention, member.getAsMention()); + contentToMinecraft = StringUtils.replaceIgnoreCase(contentToMinecraft, nicknameMention, MarkdownSanitizer.escape(formattedMention)); + } + } + } + + if (CONFIG.generic.allowedMentions.contains("roles")) { + for (Role role : CHANNEL.getGuild().getRoles()) { + String roleMention = "@" + role.getName(); + String formattedMention = Formatting.YELLOW + "@" + role.getName() + Formatting.RESET; + contentToDiscord = StringUtils.replaceIgnoreCase(contentToDiscord, roleMention, role.getAsMention()); + contentToMinecraft = StringUtils.replaceIgnoreCase(contentToMinecraft, roleMention, MarkdownSanitizer.escape(formattedMention)); + } + } + + if (CONFIG.generic.allowedMentions.contains("everyone")) { + contentToMinecraft = StringUtils.replaceIgnoreCase(contentToMinecraft, "@everyone", Formatting.YELLOW + "@everyone" + Formatting.RESET); + contentToMinecraft = StringUtils.replaceIgnoreCase(contentToMinecraft, "@here", Formatting.YELLOW + "@here" + Formatting.RESET); + } + } + + contentToMinecraft = MarkdownParser.parseMarkdown(contentToMinecraft.replace("\\", "\\\\")); + + for (String protocol : new String[]{"http://", "https://"}) { + if (contentToMinecraft.contains(protocol)) { + String[] links = StringUtils.substringsBetween(contentToMinecraft, protocol, " "); + if (!StringUtils.substringAfterLast(contentToMinecraft, protocol).contains(" ")) { + links = ArrayUtils.add(links, StringUtils.substringAfterLast(contentToMinecraft, protocol)); + } + for (String link : links) { + if (link.contains("\n")) { + link = StringUtils.substringBefore(link, "\n"); + } + + String hyperlinkInsert; + if (StringUtils.containsIgnoreCase(link, "gif") + && StringUtils.containsIgnoreCase(link, "tenor.com")) { + hyperlinkInsert = "\"},{\"text\":\"\",\"underlined\":true,\"color\":\"yellow\",\"clickEvent\":{\"action\":\"open_url\",\"value\":\"" + protocol + link + "\"},\"hoverEvent\":{\"action\":\"show_text\",\"contents\":[{\"text\":\"Open URL\"}]}},{\"text\":\""; + } else { + hyperlinkInsert = "\"},{\"text\":\"" + protocol + link + "\",\"underlined\":true,\"color\":\"yellow\",\"clickEvent\":{\"action\":\"open_url\",\"value\":\"" + protocol + link + "\"},\"hoverEvent\":{\"action\":\"show_text\",\"contents\":[{\"text\":\"Open URL\"}]}},{\"text\":\""; + } + contentToMinecraft = StringUtils.replaceIgnoreCase(contentToMinecraft, (protocol + link), hyperlinkInsert); + } + } + } + + if (CONFIG.generic.formatChatMessages) { + try { + SignedMessage signedMessage = getSignedMessage(packet, optional.get()); + server.getPlayerManager().broadcast(signedMessage.withUnsignedContent(Objects.requireNonNull(Text.Serializer.fromJson("[{\"text\":\"" + contentToMinecraft + "\"}]"))), player, MessageType.params(MessageType.CHAT, player)); + } catch (MessageChain.MessageChainException e) { + handleMessageChainException(e); + } + } else { + server.submit(() -> { + SignedMessage signedMessage; + try { + signedMessage = getSignedMessage(packet, optional.get()); + } catch (MessageChain.MessageChainException var6) { + handleMessageChainException(var6); + return; + } + + CompletableFuture completableFuture = filterText(signedMessage.getSignedContent()); + Text text = server.getMessageDecorator().decorate(player, signedMessage.getContent()); + messageChainTaskQueue.append((executor) -> completableFuture.thenAcceptAsync((filteredMessage) -> { + SignedMessage signedMessage2 = signedMessage.withUnsignedContent(text).withFilterMask(filteredMessage.mask()); + handleDecoratedMessage(signedMessage2); + }, executor)); + }); + } + + if (CONFIG.generic.broadcastChatMessages) { + sendMessage(contentToDiscord, false); + if (CONFIG.multiServer.enable) { + MULTI_SERVER.sendMessage(false, true, false, player.getEntityName(), CONFIG.generic.formatChatMessages ? contentToMinecraft : packet.chatMessage()); + } + } + } + } + + ci.cancel(); + } + + @Inject(method = "onCommandExecution", at = @At(value = "HEAD"), cancellable = true) + private void onCommandExecution(CommandExecutionC2SPacket packet, CallbackInfo ci) { + if (CONFIG.generic.broadcastPlayerCommandExecution) { + if (hasIllegalCharacter(packet.command())) { + disconnect(Text.translatable("multiplayer.disconnect.illegal_characters")); + } else { + Optional optional = validateMessage(packet.command(), packet.timestamp(), packet.acknowledgment()); + if (optional.isPresent()) { + server.submit(() -> { + handleCommandExecution(packet, optional.get()); + checkForSpam(); + }); + + String input = "/" + packet.command(); + + for (String command : CONFIG.generic.excludedCommands) { + if (input.startsWith(command + " ")) { + ci.cancel(); + return; + } + } + + if ((System.currentTimeMillis() - MINECRAFT_LAST_RESET_TIME) > 20000) { + MINECRAFT_SEND_COUNT = 0; + MINECRAFT_LAST_RESET_TIME = System.currentTimeMillis(); + } + + MINECRAFT_SEND_COUNT++; + if (MINECRAFT_SEND_COUNT <= 20) { + Text text = Text.of("<" + player.getEntityName() + "> " + input); + + server.getPlayerManager().getPlayerList().forEach( + player -> player.sendMessage(text, false)); + + SERVER.sendMessage(text); + + sendMessage(input, true); + if (CONFIG.multiServer.enable) { + MULTI_SERVER.sendMessage(false, true, false, player.getEntityName(), MarkdownSanitizer.escape(input)); + } + } + } + } + + ci.cancel(); + } + } + + private void sendMessage(String message, boolean escapeMarkdown) { + String content = (escapeMarkdown ? MarkdownSanitizer.escape(message) : message); + + if (!CONFIG.generic.useWebhook) { + if (CONFIG.multiServer.enable) { + CHANNEL.sendMessage(Translations.translateMessage("message.messageWithoutWebhookForMultiServer") + .replace("%server%", CONFIG.multiServer.name) + .replace("%name%", player.getEntityName()) + .replace("%message%", content)).queue(); + } else { + CHANNEL.sendMessage(Translations.translateMessage("message.messageWithoutWebhook") + .replace("%name%", player.getEntityName()) + .replace("%message%", content)).queue(); + } + } else { + JsonObject body = new JsonObject(); + body.addProperty("content", content); + body.addProperty("username", ((CONFIG.multiServer.enable) ? ("[" + CONFIG.multiServer.name + "] " + player.getEntityName()) : player.getEntityName())); + body.addProperty("avatar_url", CONFIG.generic.avatarApi.replace("%player%", (CONFIG.generic.useUuidInsteadOfName ? player.getUuid().toString() : player.getEntityName()))); + + JsonObject allowedMentions = new JsonObject(); + allowedMentions.add("parse", new Gson().toJsonTree(CONFIG.generic.allowedMentions).getAsJsonArray()); + body.add("allowed_mentions", allowedMentions); + + Request request = new Request.Builder() + .url(WEBHOOK.getUrl()) + .post(RequestBody.create(body.toString(), MediaType.get("application/json"))) + .build(); + + try { + Response response = HTTP_CLIENT.newCall(request).execute(); + response.close(); + } catch (Exception e) { + LOGGER.error(ExceptionUtils.getStackTrace(e)); + } + } + } + + private boolean hasIllegalCharacter(String message) { + for (int i = 0; i < message.length(); ++i) { + if (!SharedConstants.isValidChar(message.charAt(i))) { + return true; + } + } + + return false; + } +} +//#endif \ No newline at end of file diff --git a/versions/1.20.3/gradle.properties b/versions/1.20.3/gradle.properties new file mode 100644 index 00000000..ae540302 --- /dev/null +++ b/versions/1.20.3/gradle.properties @@ -0,0 +1,11 @@ +# Fabric Properties +# check these on https://fabricmc.net/develop +minecraft_version=1.20.3 +yarn_mappings=1.20.3+build.1 +loader_version=0.15.0 + +# Fabric Mod Metadata +minecraft_dependency=~1.20.3 + +# Dependencies +fabric_version=0.91.1+1.20.3 \ No newline at end of file diff --git a/versions/mainProject b/versions/mainProject index 341e509f..3cb1511d 100644 --- a/versions/mainProject +++ b/versions/mainProject @@ -1 +1 @@ -1.20.2 \ No newline at end of file +1.20.3 \ No newline at end of file