Rework impl, allow for regex filters (closes #1)

This commit is contained in:
Johannes Frohnmeyer 2022-04-02 17:34:17 +02:00
parent ec7cff19db
commit 258e9bbe1a
Signed by: Johannes
GPG Key ID: E76429612C2929F4
7 changed files with 149 additions and 46 deletions

View File

@ -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}"))
}

View File

@ -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 <TLang extends Language> String translateIfNeeded(String source, Direction direction, boolean respectRegex) {
if (shouldSkipOutright(direction)) return source;
if (respectRegex && failsRegex(source, direction))
return source;
TranslateService<TLang> svc = (TranslateService<TLang>) 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
}
}

View File

@ -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;
}
}
}

View File

@ -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 <T extends Language> void googlechat$translate(TranslateService<T> 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);
}
}

View File

@ -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 = "<init>(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 = "<init>(Lnet/minecraft/network/PacketByteBuf;)V")
private void init(PacketByteBuf buf, CallbackInfo ci) {
googlechat$translate(GoogleChat.TRANSLATE_SERVICE);
googlechat$translate();
}
private <T extends Language> void googlechat$translate(TranslateService<T> ts) {
private <T extends Language> 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<Text> 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);
}
}

View File

@ -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"
}

View File

@ -20,5 +20,10 @@
"depends": {
"fabricloader": ">=0.12.12",
"minecraft": "*"
},
"custom": {
"libjf:config": {
"referencedConfigs": ["libjf-translate-v1"]
}
}
}