From 4d2161d5f1568b60e738056529b94116c0637402 Mon Sep 17 00:00:00 2001 From: RaphiMC <50594595+RaphiMC@users.noreply.github.com> Date: Fri, 5 Apr 2024 19:01:04 +0200 Subject: [PATCH] Replaced chat component translation with mcstructs --- .../Protocol1_7_2_5to1_6_4.java | 7 +- .../rewriter/ChatComponentRewriter.java | 76 ++++++- .../rewriter/TranslationRewriter.java | 84 -------- .../Protocol1_7_6_10to1_7_2_5.java | 4 +- ...writer.java => ChatComponentRewriter.java} | 31 +-- .../Protocol1_8to1_7_6_10.java | 7 +- ...writer.java => ChatComponentRewriter.java} | 185 ++++++++++++------ .../rewriter/TranslationRewriter.java | 106 ---------- 8 files changed, 215 insertions(+), 285 deletions(-) delete mode 100644 src/main/java/net/raphimc/vialegacy/protocols/release/protocol1_7_2_5to1_6_4/rewriter/TranslationRewriter.java rename src/main/java/net/raphimc/vialegacy/protocols/release/protocol1_7_6_10to1_7_2_5/rewriter/{TranslationRewriter.java => ChatComponentRewriter.java} (89%) rename src/main/java/net/raphimc/vialegacy/protocols/release/protocol1_8to1_7_6_10/rewriter/{ChatItemRewriter.java => ChatComponentRewriter.java} (62%) delete mode 100644 src/main/java/net/raphimc/vialegacy/protocols/release/protocol1_8to1_7_6_10/rewriter/TranslationRewriter.java diff --git a/src/main/java/net/raphimc/vialegacy/protocols/release/protocol1_7_2_5to1_6_4/Protocol1_7_2_5to1_6_4.java b/src/main/java/net/raphimc/vialegacy/protocols/release/protocol1_7_2_5to1_6_4/Protocol1_7_2_5to1_6_4.java index 0a8af73..b099fa0 100644 --- a/src/main/java/net/raphimc/vialegacy/protocols/release/protocol1_7_2_5to1_6_4/Protocol1_7_2_5to1_6_4.java +++ b/src/main/java/net/raphimc/vialegacy/protocols/release/protocol1_7_2_5to1_6_4/Protocol1_7_2_5to1_6_4.java @@ -54,7 +54,10 @@ import net.raphimc.vialegacy.api.remapper.LegacyItemRewriter; import net.raphimc.vialegacy.api.splitter.PreNettySplitter; import net.raphimc.vialegacy.api.util.PacketUtil; import net.raphimc.vialegacy.protocols.release.protocol1_7_2_5to1_6_4.providers.EncryptionProvider; -import net.raphimc.vialegacy.protocols.release.protocol1_7_2_5to1_6_4.rewriter.*; +import net.raphimc.vialegacy.protocols.release.protocol1_7_2_5to1_6_4.rewriter.ChatComponentRewriter; +import net.raphimc.vialegacy.protocols.release.protocol1_7_2_5to1_6_4.rewriter.ItemRewriter; +import net.raphimc.vialegacy.protocols.release.protocol1_7_2_5to1_6_4.rewriter.SoundRewriter; +import net.raphimc.vialegacy.protocols.release.protocol1_7_2_5to1_6_4.rewriter.StatisticRewriter; import net.raphimc.vialegacy.protocols.release.protocol1_7_2_5to1_6_4.storage.*; import net.raphimc.vialegacy.protocols.release.protocol1_7_2_5to1_6_4.types.MetaType1_6_4; import net.raphimc.vialegacy.protocols.release.protocol1_7_2_5to1_6_4.types.Types1_6_4; @@ -125,7 +128,7 @@ public class Protocol1_7_2_5to1_6_4 extends StatelessTransitionProtocol TranslationRewriter.toClient(ChatComponentRewriter.toClient(msg))); // message + map(Types1_6_4.STRING, Type.STRING, ChatComponentRewriter::toClient); // message } }); this.registerClientbound(ClientboundPackets1_6_4.ENTITY_EQUIPMENT, new PacketHandlers() { diff --git a/src/main/java/net/raphimc/vialegacy/protocols/release/protocol1_7_2_5to1_6_4/rewriter/ChatComponentRewriter.java b/src/main/java/net/raphimc/vialegacy/protocols/release/protocol1_7_2_5to1_6_4/rewriter/ChatComponentRewriter.java index e0a44c8..59e95d4 100644 --- a/src/main/java/net/raphimc/vialegacy/protocols/release/protocol1_7_2_5to1_6_4/rewriter/ChatComponentRewriter.java +++ b/src/main/java/net/raphimc/vialegacy/protocols/release/protocol1_7_2_5to1_6_4/rewriter/ChatComponentRewriter.java @@ -18,6 +18,8 @@ package net.raphimc.vialegacy.protocols.release.protocol1_7_2_5to1_6_4.rewriter; +import com.viaversion.viaversion.libs.fastutil.objects.Object2ObjectMap; +import com.viaversion.viaversion.libs.fastutil.objects.Object2ObjectOpenHashMap; import com.viaversion.viaversion.libs.mcstructs.text.ATextComponent; import com.viaversion.viaversion.libs.mcstructs.text.components.StringComponent; import com.viaversion.viaversion.libs.mcstructs.text.components.TranslationComponent; @@ -27,27 +29,81 @@ import com.viaversion.viaversion.libs.mcstructs.text.utils.TextUtils; public class ChatComponentRewriter { + private static final Object2ObjectMap TRANSLATIONS = new Object2ObjectOpenHashMap<>(37, 0.99F); + + static { + TRANSLATIONS.put("menu.playdemo", "Play Demo World"); + TRANSLATIONS.put("options.ao.off", "Off"); + TRANSLATIONS.put("options.framerateLimit", "Performance"); + TRANSLATIONS.put("options.resourcepack", "Resource Packs"); + TRANSLATIONS.put("performance.max", "Max FPS"); + TRANSLATIONS.put("performance.balanced", "Balanced"); + TRANSLATIONS.put("performance.powersaver", "Power saver"); + TRANSLATIONS.put("key.forward", "Forward"); + TRANSLATIONS.put("key.left", "Left"); + TRANSLATIONS.put("key.back", "Back"); + TRANSLATIONS.put("key.right", "Right"); + TRANSLATIONS.put("key.drop", "Drop"); + TRANSLATIONS.put("key.chat", "Chat"); + TRANSLATIONS.put("key.fog", "Toggle Fog"); + TRANSLATIONS.put("key.attack", "Attack"); + TRANSLATIONS.put("key.use", "Use Item"); + TRANSLATIONS.put("key.command", "Command"); + TRANSLATIONS.put("resourcePack.title", "Select Resource Pack"); + TRANSLATIONS.put("tile.dirt.name", "Dirt"); + TRANSLATIONS.put("tile.sand.name", "Sand"); + TRANSLATIONS.put("tile.flower.name", "Flower"); + TRANSLATIONS.put("tile.rose.name", "Rose"); + TRANSLATIONS.put("item.fishRaw.name", "Raw Fish"); + TRANSLATIONS.put("item.fishCooked.name", "Cooked Fish"); + TRANSLATIONS.put("commands.give.usage", "/give [amount] [data]"); + TRANSLATIONS.put("commands.give.success", "Given %s (ID %s) * %s to %s"); + TRANSLATIONS.put("commands.scoreboard.objectives.add.wrongType", "Invalid objective criteria type. Valid types are: %s"); + TRANSLATIONS.put("commands.scoreboard.objectives.list.count", "Showing %s objective(s) on scoreboard"); + TRANSLATIONS.put("commands.scoreboard.players.list.count", "Showing %s tracked players on the scoreboard"); + TRANSLATIONS.put("commands.scoreboard.players.list.player.count", "Showing %s tracked objective(s) for %s"); + TRANSLATIONS.put("commands.scoreboard.teams.list.count", "Showing %s teams on the scoreboard"); + TRANSLATIONS.put("commands.scoreboard.teams.list.player.count", "Showing %s player(s) in team %s"); + TRANSLATIONS.put("commands.scoreboard.teams.empty.usage", "/scoreboard teams clear "); + TRANSLATIONS.put("commands.scoreboard.teams.option.usage", "/scoreboard teams option "); + TRANSLATIONS.put("commands.weather.usage", "/weather [duration in seconds]"); + TRANSLATIONS.put("mco.configure.world.subscription.extend", "Extend"); + TRANSLATIONS.put("mco.configure.world.restore.question.line1", "Your realm will be restored to a previous version"); + } + public static String toClient(final String text) { - final ATextComponent component = TextComponentSerializer.V1_6.deserialize(text); + ATextComponent component = TextComponentSerializer.V1_6.deserialize(text); + // Replace translation keys with their actual translations + TextUtils.iterateAll(component, c -> { + if (c instanceof TranslationComponent) { + final TranslationComponent translationComponent = (TranslationComponent) c; + if (TRANSLATIONS.containsKey(translationComponent.getKey())) { + translationComponent.setKey(TRANSLATIONS.get(translationComponent.getKey())); + } + } + }); // Convert all section sign formatted strings to json formatted ones with styles so the formatting isn't reset on chat line split - ATextComponent newComponent = TextUtils.replace(component, ".*", c -> LegacyStringDeserializer.parse(c.asSingleString(), true).setParentStyle(c.getStyle())); + component = TextUtils.replace(component, c -> { + if (c instanceof StringComponent) { + return LegacyStringDeserializer.parse(c.asSingleString(), true).setParentStyle(c.getStyle()); + } else { + return c; + } + }); // Clickable URLs are handled clientside -> Add click events to the json components - newComponent.forEach(c -> { + TextUtils.iterateAll(component, c -> { if (c instanceof TranslationComponent) { final TranslationComponent translationComponent = (TranslationComponent) c; final Object[] args = translationComponent.getArgs(); for (int i = 0; i < args.length; i++) { - if (args[i] instanceof ATextComponent) { - args[i] = TextUtils.makeURLsClickable((ATextComponent) args[i]); - } else { - args[i] = TextUtils.makeURLsClickable(new StringComponent(args[i].toString())); + if (args[i] != null && !(args[i] instanceof ATextComponent)) { + args[i] = new StringComponent(args[i].toString()); } } } }); - newComponent = TextUtils.makeURLsClickable(newComponent); - // Also convert "using" -> "with" in translatable components - return TextComponentSerializer.V1_7.serialize(newComponent); + component = TextUtils.replace(component, TextUtils::makeURLsClickable); + return TextComponentSerializer.V1_7.serialize(component); } public static String toClientDisconnect(final String reason) { diff --git a/src/main/java/net/raphimc/vialegacy/protocols/release/protocol1_7_2_5to1_6_4/rewriter/TranslationRewriter.java b/src/main/java/net/raphimc/vialegacy/protocols/release/protocol1_7_2_5to1_6_4/rewriter/TranslationRewriter.java deleted file mode 100644 index 9a5e994..0000000 --- a/src/main/java/net/raphimc/vialegacy/protocols/release/protocol1_7_2_5to1_6_4/rewriter/TranslationRewriter.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * This file is part of ViaLegacy - https://github.com/RaphiMC/ViaLegacy - * Copyright (C) 2020-2024 RK_01/RaphiMC and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package net.raphimc.vialegacy.protocols.release.protocol1_7_2_5to1_6_4.rewriter; - -import com.viaversion.viaversion.libs.fastutil.objects.Object2ObjectMap; -import com.viaversion.viaversion.libs.fastutil.objects.Object2ObjectOpenHashMap; -import com.viaversion.viaversion.libs.gson.JsonObject; -import com.viaversion.viaversion.rewriter.ComponentRewriter; -import net.raphimc.vialegacy.protocols.release.protocol1_7_2_5to1_6_4.ClientboundPackets1_6_4; - -public class TranslationRewriter { - - private static final Object2ObjectMap TRANSLATIONS = new Object2ObjectOpenHashMap<>(37, 0.99F); - - static { - TRANSLATIONS.put("menu.playdemo", "Play Demo World"); - TRANSLATIONS.put("options.ao.off", "Off"); - TRANSLATIONS.put("options.framerateLimit", "Performance"); - TRANSLATIONS.put("options.resourcepack", "Resource Packs"); - TRANSLATIONS.put("performance.max", "Max FPS"); - TRANSLATIONS.put("performance.balanced", "Balanced"); - TRANSLATIONS.put("performance.powersaver", "Power saver"); - TRANSLATIONS.put("key.forward", "Forward"); - TRANSLATIONS.put("key.left", "Left"); - TRANSLATIONS.put("key.back", "Back"); - TRANSLATIONS.put("key.right", "Right"); - TRANSLATIONS.put("key.drop", "Drop"); - TRANSLATIONS.put("key.chat", "Chat"); - TRANSLATIONS.put("key.fog", "Toggle Fog"); - TRANSLATIONS.put("key.attack", "Attack"); - TRANSLATIONS.put("key.use", "Use Item"); - TRANSLATIONS.put("key.command", "Command"); - TRANSLATIONS.put("resourcePack.title", "Select Resource Pack"); - TRANSLATIONS.put("tile.dirt.name", "Dirt"); - TRANSLATIONS.put("tile.sand.name", "Sand"); - TRANSLATIONS.put("tile.flower.name", "Flower"); - TRANSLATIONS.put("tile.rose.name", "Rose"); - TRANSLATIONS.put("item.fishRaw.name", "Raw Fish"); - TRANSLATIONS.put("item.fishCooked.name", "Cooked Fish"); - TRANSLATIONS.put("commands.give.usage", "/give [amount] [data]"); - TRANSLATIONS.put("commands.give.success", "Given %s (ID %s) * %s to %s"); - TRANSLATIONS.put("commands.scoreboard.objectives.add.wrongType", "Invalid objective criteria type. Valid types are: %s"); - TRANSLATIONS.put("commands.scoreboard.objectives.list.count", "Showing %s objective(s) on scoreboard"); - TRANSLATIONS.put("commands.scoreboard.players.list.count", "Showing %s tracked players on the scoreboard"); - TRANSLATIONS.put("commands.scoreboard.players.list.player.count", "Showing %s tracked objective(s) for %s"); - TRANSLATIONS.put("commands.scoreboard.teams.list.count", "Showing %s teams on the scoreboard"); - TRANSLATIONS.put("commands.scoreboard.teams.list.player.count", "Showing %s player(s) in team %s"); - TRANSLATIONS.put("commands.scoreboard.teams.empty.usage", "/scoreboard teams clear "); - TRANSLATIONS.put("commands.scoreboard.teams.option.usage", "/scoreboard teams option "); - TRANSLATIONS.put("commands.weather.usage", "/weather [duration in seconds]"); - TRANSLATIONS.put("mco.configure.world.subscription.extend", "Extend"); - TRANSLATIONS.put("mco.configure.world.restore.question.line1", "Your realm will be restored to a previous version"); - } - - private static final ComponentRewriter REWRITER = new ComponentRewriter(null, ComponentRewriter.ReadType.JSON) { - @Override - protected void handleTranslate(JsonObject object, String translate) { - final String text = TRANSLATIONS.get(translate); - if (text != null) { - object.addProperty("translate", text); - } - } - }; - - public static String toClient(final String text) { - return REWRITER.processText(text).toString(); - } - -} diff --git a/src/main/java/net/raphimc/vialegacy/protocols/release/protocol1_7_6_10to1_7_2_5/Protocol1_7_6_10to1_7_2_5.java b/src/main/java/net/raphimc/vialegacy/protocols/release/protocol1_7_6_10to1_7_2_5/Protocol1_7_6_10to1_7_2_5.java index 320b024..70b8c29 100644 --- a/src/main/java/net/raphimc/vialegacy/protocols/release/protocol1_7_6_10to1_7_2_5/Protocol1_7_6_10to1_7_2_5.java +++ b/src/main/java/net/raphimc/vialegacy/protocols/release/protocol1_7_6_10to1_7_2_5/Protocol1_7_6_10to1_7_2_5.java @@ -32,7 +32,7 @@ import com.viaversion.viaversion.protocols.base.BaseProtocol1_7; import com.viaversion.viaversion.protocols.base.ClientboundLoginPackets; import net.raphimc.vialegacy.ViaLegacy; import net.raphimc.vialegacy.api.util.UuidUtil; -import net.raphimc.vialegacy.protocols.release.protocol1_7_6_10to1_7_2_5.rewriter.TranslationRewriter; +import net.raphimc.vialegacy.protocols.release.protocol1_7_6_10to1_7_2_5.rewriter.ChatComponentRewriter; import net.raphimc.vialegacy.protocols.release.protocol1_8to1_7_6_10.model.GameProfile; import net.raphimc.vialegacy.protocols.release.protocol1_8to1_7_6_10.providers.GameProfileFetcher; import net.raphimc.vialegacy.protocols.release.protocol1_8to1_7_6_10.types.Types1_7_6; @@ -79,7 +79,7 @@ public class Protocol1_7_6_10to1_7_2_5 extends AbstractProtocol TRANSLATIONS = new Object2ObjectOpenHashMap<>(86, 0.99F); @@ -116,18 +117,18 @@ public class TranslationRewriter { TRANSLATIONS.put("mco.invites.nopending", "No pending invitations!"); } - private static final ComponentRewriter REWRITER = new ComponentRewriter(null, ComponentRewriter.ReadType.JSON) { - @Override - protected void handleTranslate(JsonObject object, String translate) { - final String text = TRANSLATIONS.get(translate); - if (text != null) { - object.addProperty("translate", text); - } - } - }; - public static String toClient(final String text) { - return REWRITER.processText(text).toString(); + final ATextComponent component = TextComponentSerializer.V1_7.deserialize(text); + // Replace translation keys with their actual translations + TextUtils.iterateAll(component, c -> { + if (c instanceof TranslationComponent) { + final TranslationComponent translationComponent = (TranslationComponent) c; + if (TRANSLATIONS.containsKey(translationComponent.getKey())) { + translationComponent.setKey(TRANSLATIONS.get(translationComponent.getKey())); + } + } + }); + return TextComponentSerializer.V1_7.serialize(component); } } diff --git a/src/main/java/net/raphimc/vialegacy/protocols/release/protocol1_8to1_7_6_10/Protocol1_8to1_7_6_10.java b/src/main/java/net/raphimc/vialegacy/protocols/release/protocol1_8to1_7_6_10/Protocol1_8to1_7_6_10.java index 8ba770e..f8eedb2 100644 --- a/src/main/java/net/raphimc/vialegacy/protocols/release/protocol1_8to1_7_6_10/Protocol1_8to1_7_6_10.java +++ b/src/main/java/net/raphimc/vialegacy/protocols/release/protocol1_8to1_7_6_10/Protocol1_8to1_7_6_10.java @@ -60,9 +60,8 @@ import net.raphimc.vialegacy.protocols.release.protocol1_8to1_7_6_10.model.MapDa import net.raphimc.vialegacy.protocols.release.protocol1_8to1_7_6_10.model.MapIcon; import net.raphimc.vialegacy.protocols.release.protocol1_8to1_7_6_10.model.TabListEntry; import net.raphimc.vialegacy.protocols.release.protocol1_8to1_7_6_10.providers.GameProfileFetcher; -import net.raphimc.vialegacy.protocols.release.protocol1_8to1_7_6_10.rewriter.ChatItemRewriter; +import net.raphimc.vialegacy.protocols.release.protocol1_8to1_7_6_10.rewriter.ChatComponentRewriter; import net.raphimc.vialegacy.protocols.release.protocol1_8to1_7_6_10.rewriter.ItemRewriter; -import net.raphimc.vialegacy.protocols.release.protocol1_8to1_7_6_10.rewriter.TranslationRewriter; import net.raphimc.vialegacy.protocols.release.protocol1_8to1_7_6_10.storage.*; import net.raphimc.vialegacy.protocols.release.protocol1_8to1_7_6_10.types.Types1_7_6; @@ -72,7 +71,7 @@ import java.util.*; public class Protocol1_8to1_7_6_10 extends AbstractProtocol { private final LegacyItemRewriter itemRewriter = new ItemRewriter(this); - private final ChatItemRewriter chatItemRewriter = new ChatItemRewriter(this); + private final ChatComponentRewriter chatComponentRewriter = new ChatComponentRewriter(this); private final MetadataRewriter metadataRewriter = new MetadataRewriter(this); public Protocol1_8to1_7_6_10() { @@ -154,7 +153,7 @@ public class Protocol1_8to1_7_6_10 extends AbstractProtocol TranslationRewriter.toClient(chatItemRewriter.remapShowItem(msg))); // message + map(Type.STRING, Type.STRING, chatComponentRewriter::toClient); // message create(Type.BYTE, (byte) 0); // position } }); diff --git a/src/main/java/net/raphimc/vialegacy/protocols/release/protocol1_8to1_7_6_10/rewriter/ChatItemRewriter.java b/src/main/java/net/raphimc/vialegacy/protocols/release/protocol1_8to1_7_6_10/rewriter/ChatComponentRewriter.java similarity index 62% rename from src/main/java/net/raphimc/vialegacy/protocols/release/protocol1_8to1_7_6_10/rewriter/ChatItemRewriter.java rename to src/main/java/net/raphimc/vialegacy/protocols/release/protocol1_8to1_7_6_10/rewriter/ChatComponentRewriter.java index b328c7c..dacd4db 100644 --- a/src/main/java/net/raphimc/vialegacy/protocols/release/protocol1_8to1_7_6_10/rewriter/ChatItemRewriter.java +++ b/src/main/java/net/raphimc/vialegacy/protocols/release/protocol1_8to1_7_6_10/rewriter/ChatComponentRewriter.java @@ -17,30 +17,94 @@ */ package net.raphimc.vialegacy.protocols.release.protocol1_8to1_7_6_10.rewriter; + import com.viaversion.viaversion.api.minecraft.item.DataItem; import com.viaversion.viaversion.api.minecraft.item.Item; +import com.viaversion.viaversion.api.protocol.Protocol; import com.viaversion.viaversion.libs.fastutil.ints.Int2ObjectOpenHashMap; -import com.viaversion.viaversion.libs.gson.JsonArray; -import com.viaversion.viaversion.libs.gson.JsonElement; -import com.viaversion.viaversion.libs.gson.JsonObject; +import com.viaversion.viaversion.libs.fastutil.objects.Object2ObjectMap; +import com.viaversion.viaversion.libs.fastutil.objects.Object2ObjectOpenHashMap; import com.viaversion.viaversion.libs.mcstructs.snbt.SNbtSerializer; import com.viaversion.viaversion.libs.mcstructs.text.ATextComponent; +import com.viaversion.viaversion.libs.mcstructs.text.components.StringComponent; +import com.viaversion.viaversion.libs.mcstructs.text.components.TranslationComponent; +import com.viaversion.viaversion.libs.mcstructs.text.events.hover.HoverEventAction; +import com.viaversion.viaversion.libs.mcstructs.text.events.hover.impl.TextHoverEvent; import com.viaversion.viaversion.libs.mcstructs.text.serializer.TextComponentSerializer; +import com.viaversion.viaversion.libs.mcstructs.text.utils.TextUtils; import com.viaversion.viaversion.libs.opennbt.tag.builtin.CompoundTag; import com.viaversion.viaversion.libs.opennbt.tag.builtin.ShortTag; import com.viaversion.viaversion.libs.opennbt.tag.builtin.StringTag; -import com.viaversion.viaversion.rewriter.ComponentRewriter; import net.raphimc.vialegacy.ViaLegacy; -import net.raphimc.vialegacy.protocols.release.protocol1_7_6_10to1_7_2_5.ClientboundPackets1_7_2; -import net.raphimc.vialegacy.protocols.release.protocol1_8to1_7_6_10.Protocol1_8to1_7_6_10; import java.util.logging.Level; -public class ChatItemRewriter { +public class ChatComponentRewriter { + private static final Object2ObjectMap TRANSLATIONS = new Object2ObjectOpenHashMap<>(59, 0.99F); private static final Int2ObjectOpenHashMap ID_TO_NAME = new Int2ObjectOpenHashMap<>(315, 0.99F); static { + TRANSLATIONS.put("gui.toMenu", "Back to title screen"); + TRANSLATIONS.put("generator.amplified", "Amplified"); + TRANSLATIONS.put("disconnect.loginFailedInfo.serversUnavailable", "The authentication are currently down for maintenance."); + TRANSLATIONS.put("options.aoDesc0", "Enable faux ambient occlusion on blocks."); + TRANSLATIONS.put("options.framerateLimitDesc0", "Selects the maximum frame rate:"); + TRANSLATIONS.put("options.framerateLimitDesc1", "35fps, 120fps, or 200+fps."); + TRANSLATIONS.put("options.viewBobbingDesc0", "Enables view-bob when moving."); + TRANSLATIONS.put("options.renderCloudsDesc0", "Enables the rendering of clouds."); + TRANSLATIONS.put("options.graphicsDesc0", "'Fancy': Enables extra transparency."); + TRANSLATIONS.put("options.graphicsDesc1", "'Fast': Suggested for lower-end hardware."); + TRANSLATIONS.put("options.renderDistanceDesc0", "Maximum render distance. Smaller values"); + TRANSLATIONS.put("options.renderDistanceDesc1", "run better on lower-end hardware."); + TRANSLATIONS.put("options.particlesDesc0", "Selects the overall amount of particles."); + TRANSLATIONS.put("options.particlesDesc1", "On lower-end hardware, less is better."); + TRANSLATIONS.put("options.advancedOpenglDesc0", "Enables occlusion queries. On AMD and Intel"); + TRANSLATIONS.put("options.advancedOpenglDesc1", "hardware, this may decrease performance."); + TRANSLATIONS.put("options.fboEnableDesc0", "Enables the use of Framebuffer Objects."); + TRANSLATIONS.put("options.fboEnableDesc1", "Necessary for certain Minecraft features."); + TRANSLATIONS.put("options.postProcessEnableDesc0", "Enables post-processing. Disabling will"); + TRANSLATIONS.put("options.postProcessEnableDesc1", "result in reduction in Awesome Levels."); + TRANSLATIONS.put("options.showCape", "Show Cape"); + TRANSLATIONS.put("options.anisotropicFiltering", "Anisotropic Filtering"); + TRANSLATIONS.put("tile.stone.name", "Stone"); + TRANSLATIONS.put("tile.sapling.roofed_oak.name", "Dark Oak Sapling"); + TRANSLATIONS.put("tile.sponge.name", "Sponge"); + TRANSLATIONS.put("tile.stairsStone.name", "Stone Stairs"); + TRANSLATIONS.put("tile.pressurePlate.name", "Pressure Plate"); + TRANSLATIONS.put("tile.fence.name", "Fence"); + TRANSLATIONS.put("tile.fenceGate.name", "Fence Gate"); + TRANSLATIONS.put("tile.trapdoor.name", "Trapdoor"); + TRANSLATIONS.put("item.doorWood.name", "Wooden Door"); + TRANSLATIONS.put("entity.Arrow.name", "arrow"); + TRANSLATIONS.put("achievement.overkill.desc", "Deal eight hearts of damage in a single hit"); + TRANSLATIONS.put("commands.generic.deprecatedId", "Warning: Using numeric IDs will not be supported in the future. Please use names, such as '%s'"); + TRANSLATIONS.put("commands.give.notFound", "There is no such item with ID %s"); + TRANSLATIONS.put("commands.effect.usage", "/effect [seconds] [amplifier]"); + TRANSLATIONS.put("commands.clear.usage", "/clear [item] [data]"); + TRANSLATIONS.put("commands.time.usage", "/time "); + TRANSLATIONS.put("commands.kill.usage", "/kill"); + TRANSLATIONS.put("commands.kill.success", "Ouch! That looked like it hurt"); + TRANSLATIONS.put("commands.tp.success.coordinates", "Teleported %s to %s,%s,%s"); + TRANSLATIONS.put("commands.tp.usage", "/tp [target player] OR /tp [target player] "); + TRANSLATIONS.put("commands.scoreboard.usage", "/scoreboard "); + TRANSLATIONS.put("commands.scoreboard.objectives.usage", "/scoreboard objectives "); + TRANSLATIONS.put("commands.scoreboard.players.usage", "/scoreboard players "); + TRANSLATIONS.put("commands.scoreboard.players.set.usage", "/scoreboard players set "); + TRANSLATIONS.put("commands.scoreboard.players.add.usage", "/scoreboard players add "); + TRANSLATIONS.put("commands.scoreboard.players.remove.usage", "/scoreboard players remove "); + TRANSLATIONS.put("commands.scoreboard.players.reset.usage", "/scoreboard players reset "); + TRANSLATIONS.put("commands.scoreboard.players.reset.success", "Reset all scores of player %s"); + TRANSLATIONS.put("commands.scoreboard.teams.usage", "/scoreboard teams "); + TRANSLATIONS.put("commands.scoreboard.teams.empty.usage", "/scoreboard teams empty"); + TRANSLATIONS.put("commands.scoreboard.teams.option.usage", "/scoreboard teams option "); + TRANSLATIONS.put("commands.spawnpoint.usage", "/spawnpoint OR /spawnpoint OR /spawnpoint "); + TRANSLATIONS.put("commands.setworldspawn.usage", "/setworldspawn OR /setworldspawn "); + TRANSLATIONS.put("commands.gamerule.usage", "/gamerule OR /gamerule "); + TRANSLATIONS.put("commands.testfor.usage", "/testfor "); + TRANSLATIONS.put("commands.testfor.failed", "/testfor is only usable by commandblocks with analog output"); + TRANSLATIONS.put("commands.achievement.usage", "/achievement give [player]"); + ID_TO_NAME.put(1, "stone"); ID_TO_NAME.put(2, "grass"); ID_TO_NAME.put(3, "dirt"); @@ -358,64 +422,61 @@ public class ChatItemRewriter { ID_TO_NAME.put(2267, "record_wait"); } - private final ComponentRewriter SHOW_ITEM; + private final Protocol protocol; - public ChatItemRewriter(final Protocol1_8to1_7_6_10 protocol) { - this.SHOW_ITEM = new ComponentRewriter(protocol, ComponentRewriter.ReadType.JSON) { - @Override - protected void handleHoverEvent(JsonObject hoverEvent) { - super.handleHoverEvent(hoverEvent); - final String action = hoverEvent.getAsJsonPrimitive("action").getAsString(); - if (!action.equals("show_item")) return; - - final JsonElement value = hoverEvent.get("value"); - if (value == null) return; - - final ATextComponent nbt = TextComponentSerializer.V1_7.deserialize(value); - - try { - final CompoundTag tag = (CompoundTag) SNbtSerializer.V1_7.deserialize(nbt.asUnformattedString()); - final CompoundTag itemTag = tag.get("tag"); - final ShortTag idTag = tag.get("id"); - final ShortTag damageTag = tag.get("Damage"); - - // Call item converter - final short damage = damageTag != null ? damageTag.asShort() : 0; - final short id = idTag != null ? idTag.asShort() : 1; - final Item item = new DataItem(); - item.setIdentifier(id); - item.setData(damage); - item.setTag(itemTag); - this.handleItem(item); - - // Serialize again - if (damage != item.data()) { - tag.put("Damage", new ShortTag(item.data())); - } - tag.put("id", new StringTag("minecraft:" + ID_TO_NAME.getOrDefault(item.identifier(), "stone"))); - if (item.tag() != null) { - tag.put("tag", new CompoundTag(item.tag().getValue())); - } - - final JsonArray array = new JsonArray(); - final JsonObject object = new JsonObject(); - array.add(object); - final String serializedNBT = SNbtSerializer.V1_8.serialize(tag); - object.addProperty("text", serializedNBT); - hoverEvent.add("value", array); - } catch (Throwable e) { - ViaLegacy.getPlatform().getLogger().log(Level.WARNING, "Error remapping NBT in show_item:" + nbt.asUnformattedString(), e); - } - } - - private void handleItem(Item item) { - this.protocol.getItemRewriter().handleItemToClient(item); - } - }; + public ChatComponentRewriter(final Protocol protocol) { + this.protocol = protocol; } - public String remapShowItem(final String text) { - return SHOW_ITEM.processText(text).toString(); + public String toClient(final String text) { + final ATextComponent component = TextComponentSerializer.V1_7.deserialize(text); + // Replace translation keys with their actual translations + TextUtils.iterateAll(component, c -> { + if (c instanceof TranslationComponent) { + final TranslationComponent translationComponent = (TranslationComponent) c; + if (TRANSLATIONS.containsKey(translationComponent.getKey())) { + translationComponent.setKey(TRANSLATIONS.get(translationComponent.getKey())); + } + } + }); + // Translate item hover events + TextUtils.iterateAll(component, c -> { + if (c.getStyle().getHoverEvent() instanceof TextHoverEvent) { + final TextHoverEvent textHoverEvent = (TextHoverEvent) c.getStyle().getHoverEvent(); + if (textHoverEvent.getAction().equals(HoverEventAction.SHOW_ITEM)) { + try { + final CompoundTag tag = (CompoundTag) SNbtSerializer.V1_7.deserialize(textHoverEvent.getText().asUnformattedString()); + final ShortTag idTag = tag.get("id"); + final ShortTag damageTag = tag.get("Damage"); + final CompoundTag itemTag = tag.get("tag"); + + final short damage = damageTag != null ? damageTag.asShort() : 0; + Item item = new DataItem(); + item.setIdentifier(idTag.asShort()); + item.setData(damage); + item.setTag(itemTag); + item = this.protocol.getItemRewriter().handleItemToClient(item); + + if (!ID_TO_NAME.containsKey(item.identifier())) { + throw new IllegalArgumentException("Invalid item ID: " + item.identifier()); + } + tag.put("id", new StringTag("minecraft:" + ID_TO_NAME.get(item.identifier()))); + if (damage != item.data()) { + tag.put("Damage", new ShortTag(item.data())); + } + if (item.tag() != itemTag) { + tag.put("tag", item.tag()); + } + + c.getStyle().setHoverEvent(new TextHoverEvent(textHoverEvent.getAction(), new StringComponent(SNbtSerializer.V1_8.serialize(tag)))); + } catch (Throwable e) { + ViaLegacy.getPlatform().getLogger().log(Level.WARNING, "Error remapping NBT in show_item:" + textHoverEvent.getText().asUnformattedString(), e); + c.getStyle().setHoverEvent(new TextHoverEvent(textHoverEvent.getAction(), new StringComponent())); // Invalid item + } + } + } + }); + return TextComponentSerializer.V1_8.serialize(component); } } diff --git a/src/main/java/net/raphimc/vialegacy/protocols/release/protocol1_8to1_7_6_10/rewriter/TranslationRewriter.java b/src/main/java/net/raphimc/vialegacy/protocols/release/protocol1_8to1_7_6_10/rewriter/TranslationRewriter.java deleted file mode 100644 index 88114f1..0000000 --- a/src/main/java/net/raphimc/vialegacy/protocols/release/protocol1_8to1_7_6_10/rewriter/TranslationRewriter.java +++ /dev/null @@ -1,106 +0,0 @@ -/* - * This file is part of ViaLegacy - https://github.com/RaphiMC/ViaLegacy - * Copyright (C) 2020-2024 RK_01/RaphiMC and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package net.raphimc.vialegacy.protocols.release.protocol1_8to1_7_6_10.rewriter; - -import com.viaversion.viaversion.libs.fastutil.objects.Object2ObjectMap; -import com.viaversion.viaversion.libs.fastutil.objects.Object2ObjectOpenHashMap; -import com.viaversion.viaversion.libs.gson.JsonObject; -import com.viaversion.viaversion.rewriter.ComponentRewriter; -import net.raphimc.vialegacy.protocols.release.protocol1_7_6_10to1_7_2_5.ClientboundPackets1_7_2; - -public class TranslationRewriter { - - private static final Object2ObjectMap TRANSLATIONS = new Object2ObjectOpenHashMap<>(59, 0.99F); - - static { - TRANSLATIONS.put("gui.toMenu", "Back to title screen"); - TRANSLATIONS.put("generator.amplified", "Amplified"); - TRANSLATIONS.put("disconnect.loginFailedInfo.serversUnavailable", "The authentication are currently down for maintenance."); - TRANSLATIONS.put("options.aoDesc0", "Enable faux ambient occlusion on blocks."); - TRANSLATIONS.put("options.framerateLimitDesc0", "Selects the maximum frame rate:"); - TRANSLATIONS.put("options.framerateLimitDesc1", "35fps, 120fps, or 200+fps."); - TRANSLATIONS.put("options.viewBobbingDesc0", "Enables view-bob when moving."); - TRANSLATIONS.put("options.renderCloudsDesc0", "Enables the rendering of clouds."); - TRANSLATIONS.put("options.graphicsDesc0", "'Fancy': Enables extra transparency."); - TRANSLATIONS.put("options.graphicsDesc1", "'Fast': Suggested for lower-end hardware."); - TRANSLATIONS.put("options.renderDistanceDesc0", "Maximum render distance. Smaller values"); - TRANSLATIONS.put("options.renderDistanceDesc1", "run better on lower-end hardware."); - TRANSLATIONS.put("options.particlesDesc0", "Selects the overall amount of particles."); - TRANSLATIONS.put("options.particlesDesc1", "On lower-end hardware, less is better."); - TRANSLATIONS.put("options.advancedOpenglDesc0", "Enables occlusion queries. On AMD and Intel"); - TRANSLATIONS.put("options.advancedOpenglDesc1", "hardware, this may decrease performance."); - TRANSLATIONS.put("options.fboEnableDesc0", "Enables the use of Framebuffer Objects."); - TRANSLATIONS.put("options.fboEnableDesc1", "Necessary for certain Minecraft features."); - TRANSLATIONS.put("options.postProcessEnableDesc0", "Enables post-processing. Disabling will"); - TRANSLATIONS.put("options.postProcessEnableDesc1", "result in reduction in Awesome Levels."); - TRANSLATIONS.put("options.showCape", "Show Cape"); - TRANSLATIONS.put("options.anisotropicFiltering", "Anisotropic Filtering"); - TRANSLATIONS.put("tile.stone.name", "Stone"); - TRANSLATIONS.put("tile.sapling.roofed_oak.name", "Dark Oak Sapling"); - TRANSLATIONS.put("tile.sponge.name", "Sponge"); - TRANSLATIONS.put("tile.stairsStone.name", "Stone Stairs"); - TRANSLATIONS.put("tile.pressurePlate.name", "Pressure Plate"); - TRANSLATIONS.put("tile.fence.name", "Fence"); - TRANSLATIONS.put("tile.fenceGate.name", "Fence Gate"); - TRANSLATIONS.put("tile.trapdoor.name", "Trapdoor"); - TRANSLATIONS.put("item.doorWood.name", "Wooden Door"); - TRANSLATIONS.put("entity.Arrow.name", "arrow"); - TRANSLATIONS.put("achievement.overkill.desc", "Deal eight hearts of damage in a single hit"); - TRANSLATIONS.put("commands.generic.deprecatedId", "Warning: Using numeric IDs will not be supported in the future. Please use names, such as '%s'"); - TRANSLATIONS.put("commands.give.notFound", "There is no such item with ID %s"); - TRANSLATIONS.put("commands.effect.usage", "/effect [seconds] [amplifier]"); - TRANSLATIONS.put("commands.clear.usage", "/clear [item] [data]"); - TRANSLATIONS.put("commands.time.usage", "/time "); - TRANSLATIONS.put("commands.kill.usage", "/kill"); - TRANSLATIONS.put("commands.kill.success", "Ouch! That looked like it hurt"); - TRANSLATIONS.put("commands.tp.success.coordinates", "Teleported %s to %s,%s,%s"); - TRANSLATIONS.put("commands.tp.usage", "/tp [target player] OR /tp [target player] "); - TRANSLATIONS.put("commands.scoreboard.usage", "/scoreboard "); - TRANSLATIONS.put("commands.scoreboard.objectives.usage", "/scoreboard objectives "); - TRANSLATIONS.put("commands.scoreboard.players.usage", "/scoreboard players "); - TRANSLATIONS.put("commands.scoreboard.players.set.usage", "/scoreboard players set "); - TRANSLATIONS.put("commands.scoreboard.players.add.usage", "/scoreboard players add "); - TRANSLATIONS.put("commands.scoreboard.players.remove.usage", "/scoreboard players remove "); - TRANSLATIONS.put("commands.scoreboard.players.reset.usage", "/scoreboard players reset "); - TRANSLATIONS.put("commands.scoreboard.players.reset.success", "Reset all scores of player %s"); - TRANSLATIONS.put("commands.scoreboard.teams.usage", "/scoreboard teams "); - TRANSLATIONS.put("commands.scoreboard.teams.empty.usage", "/scoreboard teams empty"); - TRANSLATIONS.put("commands.scoreboard.teams.option.usage", "/scoreboard teams option "); - TRANSLATIONS.put("commands.spawnpoint.usage", "/spawnpoint OR /spawnpoint OR /spawnpoint "); - TRANSLATIONS.put("commands.setworldspawn.usage", "/setworldspawn OR /setworldspawn "); - TRANSLATIONS.put("commands.gamerule.usage", "/gamerule OR /gamerule "); - TRANSLATIONS.put("commands.testfor.usage", "/testfor "); - TRANSLATIONS.put("commands.testfor.failed", "/testfor is only usable by commandblocks with analog output"); - TRANSLATIONS.put("commands.achievement.usage", "/achievement give [player]"); - } - - private static final ComponentRewriter REWRITER = new ComponentRewriter(null, ComponentRewriter.ReadType.JSON) { - @Override - protected void handleTranslate(JsonObject object, String translate) { - final String text = TRANSLATIONS.get(translate); - if (text != null) { - object.addProperty("translate", text); - } - } - }; - - public static String toClient(final String text) { - return REWRITER.processText(text).toString(); - } - -}