From 258e9bbe1a4767d3ff025d400d7a1c9d0b0f482d Mon Sep 17 00:00:00 2001 From: JFronny Date: Sat, 2 Apr 2022 17:34:17 +0200 Subject: [PATCH] Rework impl, allow for regex filters (closes #1) --- build.gradle | 1 + .../gitlab/jfronny/googlechat/GoogleChat.java | 91 +++++++++++++++++++ .../jfronny/googlechat/GoogleChatConfig.java | 30 ++++++ .../mixin/ChatMessageC2SPacketMixin.java | 13 +-- .../mixin/GameMessageS2CPacketMixin.java | 40 ++------ .../assets/google-chat/lang/en_us.json | 15 ++- src/main/resources/fabric.mod.json | 5 + 7 files changed, 149 insertions(+), 46 deletions(-) diff --git a/build.gradle b/build.gradle index 03f4e7b..ce3ff43 100644 --- a/build.gradle +++ b/build.gradle @@ -11,4 +11,5 @@ dependencies { // Compat fix include modImplementation(fabricApi.module("fabric-command-api-v1", "${project.fabric_version}")) + include modImplementation(fabricApi.module("fabric-lifecycle-events-v1", "${project.fabric_version}")) } diff --git a/src/main/java/io/gitlab/jfronny/googlechat/GoogleChat.java b/src/main/java/io/gitlab/jfronny/googlechat/GoogleChat.java index eea9958..e2c3442 100644 --- a/src/main/java/io/gitlab/jfronny/googlechat/GoogleChat.java +++ b/src/main/java/io/gitlab/jfronny/googlechat/GoogleChat.java @@ -1,10 +1,16 @@ package io.gitlab.jfronny.googlechat; +import io.gitlab.jfronny.libjf.translate.api.Language; +import io.gitlab.jfronny.libjf.translate.api.TranslateException; import io.gitlab.jfronny.libjf.translate.api.TranslateService; +import net.fabricmc.api.EnvType; +import net.fabricmc.loader.api.FabricLoader; import net.minecraft.client.MinecraftClient; +import net.minecraft.text.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.Arrays; import java.util.UUID; public class GoogleChat { @@ -16,4 +22,89 @@ public class GoogleChat { MinecraftClient mc = MinecraftClient.getInstance(); return mc == null || mc.player == null || sender.equals(mc.player.getUuid()); } + + public static Text translateIfNeeded(Text source, Direction direction, boolean respectRegex) { + if (shouldSkipOutright(direction)) return source; + String sourceString = toString(source); + if (respectRegex && failsRegex(sourceString, direction)) + return source; + if (GoogleChatConfig.desugar) { + LiteralText translatedText = new LiteralText(translateIfNeeded(sourceString, direction, true)); + if (GoogleChatConfig.translationTooltip) + return source.copy().setStyle(addHover(Style.EMPTY, new LiteralText("Translated: ").append(translatedText))); + else + return translatedText.setStyle(addHover(Style.EMPTY, new LiteralText("Original: ").append(source))); + } + MutableText translated; + if (source instanceof TranslatableText tx) { + Object[] args = tx.getArgs(); + args = Arrays.copyOf(args, args.length); + // We're not translating TranslatableText but want potential keys + for (int i = 0; i < args.length; i++) { + args[i] = args[i] instanceof Text tx1 ? translateIfNeeded(tx1, direction, false) + : args[i] instanceof String tx1 ? translateIfNeeded(tx1, direction, false) + : args[i]; + } + translated = new TranslatableText(tx.getKey(), args); + } else if (source instanceof LiteralText tx) { + translated = new LiteralText(translateIfNeeded(tx.getRawString(), direction, false)).setStyle(tx.getStyle()); + } else { + //LOGGER.info("Unhandled text type: " + source.getClass() + " (" + source + ")"); + translated = source.copy(); + } + if (GoogleChatConfig.translationTooltip) + return source.copy().styled(style -> addHover(style, translated)); + else + return translated; + } + + private static String toString(Text text) { + StringBuilder sb = new StringBuilder(); + text.asOrderedText().accept((index, style, codePoint) -> { + sb.append((char)codePoint); + return true; + }); + return sb.toString(); + } + + private static Style addHover(Style style, Text hoverText) { + return style.withHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, hoverText)); + } + + public static String translateIfNeeded(String source, Direction direction, boolean respectRegex) { + if (shouldSkipOutright(direction)) return source; + if (respectRegex && failsRegex(source, direction)) + return source; + TranslateService svc = (TranslateService) GoogleChat.TRANSLATE_SERVICE; // Generics bypass + TLang clientLang = svc.parseLang(GoogleChatConfig.clientLanguage); + TLang serverLang = svc.parseLang(GoogleChatConfig.serverLanguage); + try { + return svc.translate(source, + direction == Direction.C2S ? clientLang : serverLang, + direction == Direction.C2S ? serverLang : clientLang); + } catch (TranslateException e) { + LOGGER.error("Could not translate text: " + source, e); + return source; + } + } + + private static boolean failsRegex(String text, Direction direction) { + boolean isSender = (FabricLoader.getInstance().getEnvironmentType() == EnvType.CLIENT) == (direction == Direction.C2S); + if (isSender) return text.matches(GoogleChatConfig.sendingRegex) == GoogleChatConfig.sendingRegexIsBlacklist; + else return text.matches(GoogleChatConfig.receivingRegex) == GoogleChatConfig.receivingRegexIsBlacklist; + } + + private static boolean shouldSkipOutright(Direction direction) { + if (!GoogleChatConfig.enabled) return true; + Language clientLang = TRANSLATE_SERVICE.parseLang(GoogleChatConfig.clientLanguage); + Language serverLang = TRANSLATE_SERVICE.parseLang(GoogleChatConfig.serverLanguage); + if (direction == Direction.S2C && clientLang.getIdentifier().equals("auto")) return true; + if (direction == Direction.C2S && serverLang.getIdentifier().equals("auto")) return true; + return false; + } + + public enum Direction { + C2S, + S2C + } } diff --git a/src/main/java/io/gitlab/jfronny/googlechat/GoogleChatConfig.java b/src/main/java/io/gitlab/jfronny/googlechat/GoogleChatConfig.java index 302ba55..d998fba 100644 --- a/src/main/java/io/gitlab/jfronny/googlechat/GoogleChatConfig.java +++ b/src/main/java/io/gitlab/jfronny/googlechat/GoogleChatConfig.java @@ -2,10 +2,40 @@ package io.gitlab.jfronny.googlechat; import io.gitlab.jfronny.libjf.config.api.Entry; import io.gitlab.jfronny.libjf.config.api.JfConfig; +import io.gitlab.jfronny.libjf.config.api.Preset; public class GoogleChatConfig implements JfConfig { @Entry public static Boolean enabled = true; @Entry public static String serverLanguage = "auto"; @Entry public static String clientLanguage = "en"; @Entry public static Boolean translationTooltip = false; + @Entry public static Boolean desugar = false; + @Entry public static String receivingRegex = ""; + @Entry public static Boolean receivingRegexIsBlacklist = true; + @Entry public static String sendingRegex = ""; + @Entry public static Boolean sendingRegexIsBlacklist = true; + + @Preset + public static void client() { + enabled = true; + if (!serverLanguage.equals("auto")) { + serverLanguage = "auto"; + clientLanguage = "en"; + String tmp = receivingRegex; + receivingRegex = sendingRegex; + sendingRegex = tmp; + } + } + + @Preset + public static void server() { + enabled = true; + if (!clientLanguage.equals("auto")) { + clientLanguage = "auto"; + serverLanguage = "en"; + String tmp = receivingRegex; + receivingRegex = sendingRegex; + sendingRegex = tmp; + } + } } diff --git a/src/main/java/io/gitlab/jfronny/googlechat/mixin/ChatMessageC2SPacketMixin.java b/src/main/java/io/gitlab/jfronny/googlechat/mixin/ChatMessageC2SPacketMixin.java index a994a7b..65d3d63 100644 --- a/src/main/java/io/gitlab/jfronny/googlechat/mixin/ChatMessageC2SPacketMixin.java +++ b/src/main/java/io/gitlab/jfronny/googlechat/mixin/ChatMessageC2SPacketMixin.java @@ -1,9 +1,7 @@ package io.gitlab.jfronny.googlechat.mixin; import io.gitlab.jfronny.googlechat.GoogleChat; -import io.gitlab.jfronny.googlechat.GoogleChatConfig; import io.gitlab.jfronny.libjf.translate.api.Language; -import io.gitlab.jfronny.libjf.translate.api.TranslateException; import io.gitlab.jfronny.libjf.translate.api.TranslateService; import net.minecraft.network.PacketByteBuf; import net.minecraft.network.packet.c2s.play.ChatMessageC2SPacket; @@ -33,15 +31,8 @@ public class ChatMessageC2SPacketMixin { } private void googlechat$translate(TranslateService ts) { - if (!GoogleChatConfig.enabled) return; - T server = ts.parseLang(GoogleChatConfig.serverLanguage); - if (server == ts.parseLang("auto") || chatMessage.startsWith("/")) return; - try { - chatMessage = ts.translate(chatMessage, ts.parseLang(GoogleChatConfig.clientLanguage), server); - } catch (TranslateException e) { - GoogleChat.LOGGER.error("Could not translate sent message", e); - return; - } + if (chatMessage.startsWith("/")) return; + chatMessage = GoogleChat.translateIfNeeded(chatMessage, GoogleChat.Direction.C2S, true); if (chatMessage.length() > 256) chatMessage = chatMessage.substring(0, 256); } } diff --git a/src/main/java/io/gitlab/jfronny/googlechat/mixin/GameMessageS2CPacketMixin.java b/src/main/java/io/gitlab/jfronny/googlechat/mixin/GameMessageS2CPacketMixin.java index f92f8d3..e347ffa 100644 --- a/src/main/java/io/gitlab/jfronny/googlechat/mixin/GameMessageS2CPacketMixin.java +++ b/src/main/java/io/gitlab/jfronny/googlechat/mixin/GameMessageS2CPacketMixin.java @@ -3,14 +3,12 @@ package io.gitlab.jfronny.googlechat.mixin; import io.gitlab.jfronny.googlechat.GoogleChat; import io.gitlab.jfronny.googlechat.GoogleChatConfig; import io.gitlab.jfronny.libjf.translate.api.Language; -import io.gitlab.jfronny.libjf.translate.api.TranslateException; -import io.gitlab.jfronny.libjf.translate.api.TranslateService; import net.fabricmc.api.EnvType; import net.fabricmc.loader.api.FabricLoader; import net.minecraft.network.MessageType; import net.minecraft.network.PacketByteBuf; import net.minecraft.network.packet.s2c.play.GameMessageS2CPacket; -import net.minecraft.text.*; +import net.minecraft.text.Text; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mutable; @@ -19,7 +17,6 @@ import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import java.util.List; import java.util.UUID; @Mixin(GameMessageS2CPacket.class) @@ -29,42 +26,17 @@ public class GameMessageS2CPacketMixin { @Inject(at = @At("RETURN"), method = "(Lnet/minecraft/text/Text;Lnet/minecraft/network/MessageType;Ljava/util/UUID;)V") private void init(Text message, MessageType type, UUID sender, CallbackInfo ci) { - googlechat$translate(GoogleChat.TRANSLATE_SERVICE); + googlechat$translate(); } @Inject(at = @At("RETURN"), method = "(Lnet/minecraft/network/PacketByteBuf;)V") private void init(PacketByteBuf buf, CallbackInfo ci) { - googlechat$translate(GoogleChat.TRANSLATE_SERVICE); + googlechat$translate(); } - private void googlechat$translate(TranslateService ts) { + private void googlechat$translate() { if (!GoogleChatConfig.enabled) return; - if (FabricLoader.getInstance().getEnvironmentType() == EnvType.CLIENT && GoogleChat.isSelf(sender)) { - return; - } - T client = ts.parseLang(GoogleChatConfig.clientLanguage); - if (client == ts.parseLang("auto")) return; - StringBuilder sb = new StringBuilder(); - message.asOrderedText().accept((index, style, codePoint) -> { - sb.append((char)codePoint); - return true; - }); - try { - LiteralText translatedText = new LiteralText(ts.translate(sb.toString(), ts.parseLang(GoogleChatConfig.serverLanguage), client)); - if (GoogleChatConfig.translationTooltip) - message = googlechat$concat(message.getWithStyle(Style.EMPTY.withHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new LiteralText("Translated: ").append(translatedText))))); - else - message = translatedText.setStyle(Style.EMPTY.withHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new LiteralText("Original: ").append(message)))); - } catch (TranslateException e) { - GoogleChat.LOGGER.error("Could not translate received message", e); - } - } - - private Text googlechat$concat(List texts) { - MutableText res = null; - for (Text text : texts) { - res = res == null ? (MutableText) text : res.append(text); - } - return res; + if (FabricLoader.getInstance().getEnvironmentType() == EnvType.CLIENT && GoogleChat.isSelf(sender)) return; + message = GoogleChat.translateIfNeeded(message, GoogleChat.Direction.S2C, true); } } diff --git a/src/main/resources/assets/google-chat/lang/en_us.json b/src/main/resources/assets/google-chat/lang/en_us.json index a08fd96..282405d 100644 --- a/src/main/resources/assets/google-chat/lang/en_us.json +++ b/src/main/resources/assets/google-chat/lang/en_us.json @@ -7,5 +7,18 @@ "google-chat.jfconfig.clientLanguage": "Client Language", "google-chat.jfconfig.clientLanguage.tooltip": "Your own language used in translations. \"auto\" will disable translating messages by other server members", "google-chat.jfconfig.translationTooltip": "Translation Tooltip", - "google-chat.jfconfig.translationTooltip.tooltip": "Display translations as a tooltip (on hover) and keep the original message" + "google-chat.jfconfig.translationTooltip.tooltip": "Display translations as a tooltip (on hover) and keep the original message. This will overwrite other tooltips", + "google-chat.jfconfig.desugar": "Desugar", + "google-chat.jfconfig.desugar.tooltip": "Translate all messages as plain strings. This will remove formatting but may be more accurate", + "google-chat.jfconfig.receivingRegex": "Receiving Regex", + "google-chat.jfconfig.receivingRegex.tooltip": "A Regex pattern to check whether a received message should be translated", + "google-chat.jfconfig.receivingRegexIsBlacklist": "Receiving Regex Is Blacklist", + "google-chat.jfconfig.receivingRegexIsBlacklist.tooltip": "Whether the relevant regex should blacklist messages from translation instead of whitelisting", + "google-chat.jfconfig.sendingRegex": "Sending Regex", + "google-chat.jfconfig.sendingRegex.tooltip": "A Regex pattern to check whether a sent message should be translated", + "google-chat.jfconfig.sendingRegexIsBlacklist": "Sending Regex Is Blacklist", + "google-chat.jfconfig.sendingRegexIsBlacklist.tooltip": "Whether the relevant regex should blacklist messages from translation instead of whitelisting", + + "google-chat.jfconfig.client": "Client", + "google-chat.jfconfig.server": "Server" } \ No newline at end of file diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json index 3cc1425..666bac4 100644 --- a/src/main/resources/fabric.mod.json +++ b/src/main/resources/fabric.mod.json @@ -20,5 +20,10 @@ "depends": { "fabricloader": ">=0.12.12", "minecraft": "*" + }, + "custom": { + "libjf:config": { + "referencedConfigs": ["libjf-translate-v1"] + } } }