From d838c9eccef51934427bdff6e33f2e492d3a5292 Mon Sep 17 00:00:00 2001 From: rfresh2 <89827146+rfresh2@users.noreply.github.com> Date: Thu, 17 Aug 2023 21:20:32 -0700 Subject: [PATCH] Translatable text component support --- src/main/java/com/zenith/Shared.java | 7 ++++ .../feature/language/LanguageManager.java | 33 +++++++++++++++++++ .../zenith/network/client/ClientListener.java | 3 +- .../client/handler/incoming/ChatHandler.java | 3 +- .../handler/incoming/TabListDataHandler.java | 3 +- .../handler/incoming/TitlePacketHandler.java | 6 ++-- .../network/server/ServerConnection.java | 3 +- .../outgoing/ServerChatOutgoingHandler.java | 3 +- .../logback/MCTextFormatANSIConverter.java | 9 ++++- .../logback/MCTextFormatConverter.java | 9 ++++- .../native-image/resource-config.json | 2 ++ .../zenith/TranslatableTextParserTest.java | 15 +++++++++ 12 files changed, 80 insertions(+), 16 deletions(-) create mode 100644 src/main/java/com/zenith/feature/language/LanguageManager.java create mode 100644 src/test/java/com/zenith/TranslatableTextParserTest.java diff --git a/src/main/java/com/zenith/Shared.java b/src/main/java/com/zenith/Shared.java index f11d2bdfe..f7a4395fa 100644 --- a/src/main/java/com/zenith/Shared.java +++ b/src/main/java/com/zenith/Shared.java @@ -7,6 +7,7 @@ import com.zenith.database.DatabaseManager; import com.zenith.discord.DiscordBot; import com.zenith.event.SimpleEventBus; +import com.zenith.feature.language.LanguageManager; import com.zenith.feature.pathing.Pathing; import com.zenith.feature.pathing.World; import com.zenith.feature.pathing.blockdata.BlockDataManager; @@ -44,6 +45,8 @@ import com.zenith.terminal.TerminalManager; import com.zenith.util.Config; import com.zenith.util.LaunchConfig; +import net.daporkchop.lib.minecraft.text.parser.AutoMCFormatParser; +import net.daporkchop.lib.minecraft.text.util.TranslationSource; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -95,6 +98,8 @@ public static boolean isReconnectableDisconnect(final String reason) { public static final Pathing PATHING; public static final TerminalManager TERMINAL_MANAGER; public static final CommandManager COMMAND_MANAGER; + public static final LanguageManager LANGUAGE_MANAGER; + public static final AutoMCFormatParser FORMAT_PARSER; public static final HandlerRegistry CLIENT_HANDLERS = new HandlerRegistry.Builder() .setLogger(CLIENT_LOG) .allowUnhandled(true) @@ -318,6 +323,8 @@ public static synchronized void saveLaunchConfig() { PATHING = new Pathing(WORLD); TERMINAL_MANAGER = new TerminalManager(); COMMAND_MANAGER = new CommandManager(); + LANGUAGE_MANAGER = new LanguageManager(); + FORMAT_PARSER = new AutoMCFormatParser(TranslationSource.ofMap(LANGUAGE_MANAGER.getLanguageDataMap())); } catch (final Throwable e) { DEFAULT_LOG.error("Unable to initialize!", e); throw e; diff --git a/src/main/java/com/zenith/feature/language/LanguageManager.java b/src/main/java/com/zenith/feature/language/LanguageManager.java new file mode 100644 index 000000000..0e63eca67 --- /dev/null +++ b/src/main/java/com/zenith/feature/language/LanguageManager.java @@ -0,0 +1,33 @@ +package com.zenith.feature.language; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; + +import java.util.Collections; +import java.util.Map; + +public class LanguageManager { + private final ObjectMapper objectMapper; + private Map languageDataMap = Collections.emptyMap(); + + public LanguageManager() { + this.objectMapper = new ObjectMapper(); + objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + init(); + } + + private void init() { + try { + this.languageDataMap = objectMapper.readValue( + getClass().getResourceAsStream("/pc/1.12/language.json"), + new TypeReference>() {}); + } catch (final Exception e) { + throw new RuntimeException(e); + } + } + + public Map getLanguageDataMap() { + return this.languageDataMap; + } +} diff --git a/src/main/java/com/zenith/network/client/ClientListener.java b/src/main/java/com/zenith/network/client/ClientListener.java index e8157d596..f5d3aaaf0 100644 --- a/src/main/java/com/zenith/network/client/ClientListener.java +++ b/src/main/java/com/zenith/network/client/ClientListener.java @@ -9,7 +9,6 @@ import lombok.Getter; import lombok.NonNull; import lombok.RequiredArgsConstructor; -import net.daporkchop.lib.minecraft.text.parser.AutoMCFormatParser; import static com.zenith.Shared.*; import static java.util.Objects.isNull; @@ -93,7 +92,7 @@ public void disconnected(DisconnectedEvent event) { session.setDisconnected(true); String reason; try { - reason = AutoMCFormatParser.DEFAULT.parse(event.getReason()).toRawString(); + reason = FORMAT_PARSER.parse(event.getReason()).toRawString(); } catch (final Exception e) { CLIENT_LOG.warn("Unable to parse disconnect reason: {}", event.getReason(), e); reason = isNull(event.getReason()) ? "Disconnected" : event.getReason(); diff --git a/src/main/java/com/zenith/network/client/handler/incoming/ChatHandler.java b/src/main/java/com/zenith/network/client/handler/incoming/ChatHandler.java index ad3240728..b47926bf4 100644 --- a/src/main/java/com/zenith/network/client/handler/incoming/ChatHandler.java +++ b/src/main/java/com/zenith/network/client/handler/incoming/ChatHandler.java @@ -12,7 +12,6 @@ import com.zenith.util.Color; import lombok.NonNull; import net.daporkchop.lib.minecraft.text.component.MCTextRoot; -import net.daporkchop.lib.minecraft.text.parser.AutoMCFormatParser; import java.time.Duration; import java.time.Instant; @@ -29,7 +28,7 @@ public class ChatHandler implements AsyncIncomingHandler parse2b2tTablistFooter(final String footer) { try { - return Optional.of(AutoMCFormatParser.DEFAULT.parse(footer)); + return Optional.of(FORMAT_PARSER.parse(footer)); } catch (final Exception e) { CLIENT_LOG.debug("Error parsing 2b2t tablist footer", e); return Optional.empty(); diff --git a/src/main/java/com/zenith/network/client/handler/incoming/TitlePacketHandler.java b/src/main/java/com/zenith/network/client/handler/incoming/TitlePacketHandler.java index fcd5c8585..28a83534b 100644 --- a/src/main/java/com/zenith/network/client/handler/incoming/TitlePacketHandler.java +++ b/src/main/java/com/zenith/network/client/handler/incoming/TitlePacketHandler.java @@ -5,12 +5,10 @@ import com.zenith.event.proxy.QueuePositionUpdateEvent; import com.zenith.network.client.ClientSession; import com.zenith.network.registry.AsyncIncomingHandler; -import net.daporkchop.lib.minecraft.text.parser.AutoMCFormatParser; import java.util.Optional; -import static com.zenith.Shared.CLIENT_LOG; -import static com.zenith.Shared.EVENT_BUS; +import static com.zenith.Shared.*; public class TitlePacketHandler implements AsyncIncomingHandler { @Override @@ -29,7 +27,7 @@ private void parse2bQueuePos(ServerTitlePacket serverTitlePacket, final ClientSe Optional position = Optional.of(serverTitlePacket) .filter(packet -> packet.getAction().equals(TitleAction.SUBTITLE)) .map(ServerTitlePacket::getSubtitle) - .map(title -> AutoMCFormatParser.DEFAULT.parse(title).toRawString()) + .map(title -> FORMAT_PARSER.parse(title).toRawString()) .map(text -> { String[] split = text.split(":"); if (split.length > 1) { diff --git a/src/main/java/com/zenith/network/server/ServerConnection.java b/src/main/java/com/zenith/network/server/ServerConnection.java index 1add6d0d9..bc806425f 100644 --- a/src/main/java/com/zenith/network/server/ServerConnection.java +++ b/src/main/java/com/zenith/network/server/ServerConnection.java @@ -21,7 +21,6 @@ import lombok.Getter; import lombok.NonNull; import lombok.Setter; -import net.daporkchop.lib.minecraft.text.parser.AutoMCFormatParser; import javax.crypto.SecretKey; import java.io.IOException; @@ -148,7 +147,7 @@ public void disconnected(DisconnectedEvent event) { return; } if (this.isPlayer) { - final String reason = AutoMCFormatParser.DEFAULT.parse(event.getReason()).toRawString(); + final String reason = FORMAT_PARSER.parse(event.getReason()).toRawString(); if (!isSpectator()) { SERVER_LOG.info("Player disconnected: UUID: {}, Username: {}, Address: {}, Reason {}", Optional.ofNullable(this.profileCache.getProfile()).map(GameProfile::getId).orElse(null), diff --git a/src/main/java/com/zenith/network/server/handler/player/outgoing/ServerChatOutgoingHandler.java b/src/main/java/com/zenith/network/server/handler/player/outgoing/ServerChatOutgoingHandler.java index f0aa09799..a13083e27 100644 --- a/src/main/java/com/zenith/network/server/handler/player/outgoing/ServerChatOutgoingHandler.java +++ b/src/main/java/com/zenith/network/server/handler/player/outgoing/ServerChatOutgoingHandler.java @@ -5,7 +5,6 @@ import com.zenith.network.server.ServerConnection; import com.zenith.util.Color; import net.daporkchop.lib.minecraft.text.component.MCTextRoot; -import net.daporkchop.lib.minecraft.text.parser.AutoMCFormatParser; import static com.zenith.Shared.*; import static java.util.Objects.nonNull; @@ -14,7 +13,7 @@ public class ServerChatOutgoingHandler implements OutgoingHandler translatableFormatParser = () -> Shared.FORMAT_PARSER; protected static String getUpdateTextFormatCommand(VGAColor textColor, VGAColor backgroundColor, int style) { return String.format( @@ -57,6 +62,8 @@ protected static CharSequence getStyleStuff(int style) { @Override public String convert(ILoggingEvent event) { + FormatParser formatParser = translatableFormatParser.get(); + if (formatParser == null) formatParser = defaultFormatParser; TextComponent textComponent = formatParser.parse(event.getFormattedMessage()); StringBuilder builder = new StringBuilder(); this.doBuild(builder, textComponent); diff --git a/src/main/java/com/zenith/terminal/logback/MCTextFormatConverter.java b/src/main/java/com/zenith/terminal/logback/MCTextFormatConverter.java index d06a9c89c..c76d8674b 100644 --- a/src/main/java/com/zenith/terminal/logback/MCTextFormatConverter.java +++ b/src/main/java/com/zenith/terminal/logback/MCTextFormatConverter.java @@ -2,13 +2,18 @@ import ch.qos.logback.classic.pattern.MessageConverter; import ch.qos.logback.classic.spi.ILoggingEvent; +import com.zenith.Shared; import com.zenith.util.ImageInfo; import net.daporkchop.lib.logging.format.FormatParser; import net.daporkchop.lib.logging.format.component.TextComponent; import net.daporkchop.lib.minecraft.text.parser.AutoMCFormatParser; +import java.util.function.Supplier; + public class MCTextFormatConverter extends MessageConverter { - private final FormatParser formatParser = AutoMCFormatParser.DEFAULT; + private final FormatParser defaultFormatParser = AutoMCFormatParser.DEFAULT; + // need to lazily init this to get around static init order + private final Supplier translatableFormatParser = () -> Shared.FORMAT_PARSER; @Override public String convert(ILoggingEvent event) { @@ -17,6 +22,8 @@ public String convert(ILoggingEvent event) { try { // if the message doesn't start with a curly brace it ain't json if (formattedMessage.startsWith("{") || formattedMessage.contains("ยง")) { + FormatParser formatParser = translatableFormatParser.get(); + if (formatParser == null) formatParser = defaultFormatParser; TextComponent textComponent = formatParser.parse(formattedMessage); return textComponent.toRawString(); } diff --git a/src/main/resources/META-INF/native-image/resource-config.json b/src/main/resources/META-INF/native-image/resource-config.json index 0bfb4bae5..67d55c8ab 100644 --- a/src/main/resources/META-INF/native-image/resource-config.json +++ b/src/main/resources/META-INF/native-image/resource-config.json @@ -172,6 +172,8 @@ "pattern":"\\Qpc/1.12/blocks.json\\E" }, { "pattern":"\\Qpc/1.12/foods.json\\E" + }, { + "pattern":"\\Qpc/1.12/language.json\\E" }, { "pattern":"\\Qproxy_commit.txt\\E" }, { diff --git a/src/test/java/com/zenith/TranslatableTextParserTest.java b/src/test/java/com/zenith/TranslatableTextParserTest.java new file mode 100644 index 000000000..f22632172 --- /dev/null +++ b/src/test/java/com/zenith/TranslatableTextParserTest.java @@ -0,0 +1,15 @@ +package com.zenith; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class TranslatableTextParserTest { + + @Test + public void translatableTextComponentParseTest() { + final String chatText = "{\"translate\":\"chat.type.text\",\"with\":[{\"text\":\"bonk2b2t\"},{\"text\":\"you should never talk about that with them\"}]}"; + final String rawString = Shared.FORMAT_PARSER.parse(chatText).toRawString(); + assertEquals(rawString, " you should never talk about that with them"); + } +}