/* * 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.api.Via; import com.viaversion.viaversion.api.connection.UserConnection; 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.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 net.raphimc.vialegacy.ViaLegacy; import java.util.logging.Level; 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"); ID_TO_NAME.put(4, "cobblestone"); ID_TO_NAME.put(5, "planks"); ID_TO_NAME.put(6, "sapling"); ID_TO_NAME.put(7, "bedrock"); ID_TO_NAME.put(8, "flowing_water"); ID_TO_NAME.put(9, "water"); ID_TO_NAME.put(10, "flowing_lava"); ID_TO_NAME.put(11, "lava"); ID_TO_NAME.put(12, "sand"); ID_TO_NAME.put(13, "gravel"); ID_TO_NAME.put(14, "gold_ore"); ID_TO_NAME.put(15, "iron_ore"); ID_TO_NAME.put(16, "coal_ore"); ID_TO_NAME.put(17, "log"); ID_TO_NAME.put(18, "leaves"); ID_TO_NAME.put(19, "sponge"); ID_TO_NAME.put(20, "glass"); ID_TO_NAME.put(21, "lapis_ore"); ID_TO_NAME.put(22, "lapis_block"); ID_TO_NAME.put(23, "dispenser"); ID_TO_NAME.put(24, "sandstone"); ID_TO_NAME.put(25, "noteblock"); ID_TO_NAME.put(27, "golden_rail"); ID_TO_NAME.put(28, "detector_rail"); ID_TO_NAME.put(29, "sticky_piston"); ID_TO_NAME.put(30, "web"); ID_TO_NAME.put(31, "tallgrass"); ID_TO_NAME.put(32, "deadbush"); ID_TO_NAME.put(33, "piston"); ID_TO_NAME.put(35, "wool"); ID_TO_NAME.put(37, "yellow_flower"); ID_TO_NAME.put(38, "red_flower"); ID_TO_NAME.put(39, "brown_mushroom"); ID_TO_NAME.put(40, "red_mushroom"); ID_TO_NAME.put(41, "gold_block"); ID_TO_NAME.put(42, "iron_block"); ID_TO_NAME.put(43, "double_stone_slab"); ID_TO_NAME.put(44, "stone_slab"); ID_TO_NAME.put(45, "brick_block"); ID_TO_NAME.put(46, "tnt"); ID_TO_NAME.put(47, "bookshelf"); ID_TO_NAME.put(48, "mossy_cobblestone"); ID_TO_NAME.put(49, "obsidian"); ID_TO_NAME.put(50, "torch"); ID_TO_NAME.put(51, "fire"); ID_TO_NAME.put(52, "mob_spawner"); ID_TO_NAME.put(53, "oak_stairs"); ID_TO_NAME.put(54, "chest"); ID_TO_NAME.put(56, "diamond_ore"); ID_TO_NAME.put(57, "diamond_block"); ID_TO_NAME.put(58, "crafting_table"); ID_TO_NAME.put(60, "farmland"); ID_TO_NAME.put(61, "furnace"); ID_TO_NAME.put(62, "lit_furnace"); ID_TO_NAME.put(65, "ladder"); ID_TO_NAME.put(66, "rail"); ID_TO_NAME.put(67, "stone_stairs"); ID_TO_NAME.put(69, "lever"); ID_TO_NAME.put(70, "stone_pressure_plate"); ID_TO_NAME.put(72, "wooden_pressure_plate"); ID_TO_NAME.put(73, "redstone_ore"); ID_TO_NAME.put(76, "redstone_torch"); ID_TO_NAME.put(77, "stone_button"); ID_TO_NAME.put(78, "snow_layer"); ID_TO_NAME.put(79, "ice"); ID_TO_NAME.put(80, "snow"); ID_TO_NAME.put(81, "cactus"); ID_TO_NAME.put(82, "clay"); ID_TO_NAME.put(84, "jukebox"); ID_TO_NAME.put(85, "fence"); ID_TO_NAME.put(86, "pumpkin"); ID_TO_NAME.put(87, "netherrack"); ID_TO_NAME.put(88, "soul_sand"); ID_TO_NAME.put(89, "glowstone"); ID_TO_NAME.put(90, "portal"); ID_TO_NAME.put(91, "lit_pumpkin"); ID_TO_NAME.put(95, "stained_glass"); ID_TO_NAME.put(96, "trapdoor"); ID_TO_NAME.put(97, "monster_egg"); ID_TO_NAME.put(98, "stonebrick"); ID_TO_NAME.put(99, "brown_mushroom_block"); ID_TO_NAME.put(100, "red_mushroom_block"); ID_TO_NAME.put(101, "iron_bars"); ID_TO_NAME.put(102, "glass_pane"); ID_TO_NAME.put(103, "melon_block"); ID_TO_NAME.put(106, "vine"); ID_TO_NAME.put(107, "fence_gate"); ID_TO_NAME.put(108, "brick_stairs"); ID_TO_NAME.put(109, "stone_brick_stairs"); ID_TO_NAME.put(110, "mycelium"); ID_TO_NAME.put(111, "waterlily"); ID_TO_NAME.put(112, "nether_brick"); ID_TO_NAME.put(113, "nether_brick_fence"); ID_TO_NAME.put(114, "nether_brick_stairs"); ID_TO_NAME.put(116, "enchanting_table"); ID_TO_NAME.put(119, "end_portal"); ID_TO_NAME.put(120, "end_portal_frame"); ID_TO_NAME.put(121, "end_stone"); ID_TO_NAME.put(122, "dragon_egg"); ID_TO_NAME.put(123, "redstone_lamp"); ID_TO_NAME.put(125, "double_wooden_slab"); ID_TO_NAME.put(126, "wooden_slab"); ID_TO_NAME.put(127, "cocoa"); ID_TO_NAME.put(128, "sandstone_stairs"); ID_TO_NAME.put(129, "emerald_ore"); ID_TO_NAME.put(130, "ender_chest"); ID_TO_NAME.put(131, "tripwire_hook"); ID_TO_NAME.put(133, "emerald_block"); ID_TO_NAME.put(134, "spruce_stairs"); ID_TO_NAME.put(135, "birch_stairs"); ID_TO_NAME.put(136, "jungle_stairs"); ID_TO_NAME.put(137, "command_block"); ID_TO_NAME.put(138, "beacon"); ID_TO_NAME.put(139, "cobblestone_wall"); ID_TO_NAME.put(141, "carrots"); ID_TO_NAME.put(142, "potatoes"); ID_TO_NAME.put(143, "wooden_button"); ID_TO_NAME.put(145, "anvil"); ID_TO_NAME.put(146, "trapped_chest"); ID_TO_NAME.put(147, "light_weighted_pressure_plate"); ID_TO_NAME.put(148, "heavy_weighted_pressure_plate"); ID_TO_NAME.put(151, "daylight_detector"); ID_TO_NAME.put(152, "redstone_block"); ID_TO_NAME.put(153, "quartz_ore"); ID_TO_NAME.put(154, "hopper"); ID_TO_NAME.put(155, "quartz_block"); ID_TO_NAME.put(156, "quartz_stairs"); ID_TO_NAME.put(157, "activator_rail"); ID_TO_NAME.put(158, "dropper"); ID_TO_NAME.put(159, "stained_hardened_clay"); ID_TO_NAME.put(160, "stained_glass_pane"); ID_TO_NAME.put(161, "leaves2"); ID_TO_NAME.put(162, "log2"); ID_TO_NAME.put(163, "acacia_stairs"); ID_TO_NAME.put(164, "dark_oak_stairs"); ID_TO_NAME.put(170, "hay_block"); ID_TO_NAME.put(171, "carpet"); ID_TO_NAME.put(172, "hardened_clay"); ID_TO_NAME.put(173, "coal_block"); ID_TO_NAME.put(174, "packed_ice"); ID_TO_NAME.put(175, "double_plant"); ID_TO_NAME.put(256, "iron_shovel"); ID_TO_NAME.put(257, "iron_pickaxe"); ID_TO_NAME.put(258, "iron_axe"); ID_TO_NAME.put(259, "flint_and_steel"); ID_TO_NAME.put(260, "apple"); ID_TO_NAME.put(261, "bow"); ID_TO_NAME.put(262, "arrow"); ID_TO_NAME.put(263, "coal"); ID_TO_NAME.put(264, "diamond"); ID_TO_NAME.put(265, "iron_ingot"); ID_TO_NAME.put(266, "gold_ingot"); ID_TO_NAME.put(267, "iron_sword"); ID_TO_NAME.put(268, "wooden_sword"); ID_TO_NAME.put(269, "wooden_shovel"); ID_TO_NAME.put(270, "wooden_pickaxe"); ID_TO_NAME.put(271, "wooden_axe"); ID_TO_NAME.put(272, "stone_sword"); ID_TO_NAME.put(273, "stone_shovel"); ID_TO_NAME.put(274, "stone_pickaxe"); ID_TO_NAME.put(275, "stone_axe"); ID_TO_NAME.put(276, "diamond_sword"); ID_TO_NAME.put(277, "diamond_shovel"); ID_TO_NAME.put(278, "diamond_pickaxe"); ID_TO_NAME.put(279, "diamond_axe"); ID_TO_NAME.put(280, "stick"); ID_TO_NAME.put(281, "bowl"); ID_TO_NAME.put(282, "mushroom_stew"); ID_TO_NAME.put(283, "golden_sword"); ID_TO_NAME.put(284, "golden_shovel"); ID_TO_NAME.put(285, "golden_pickaxe"); ID_TO_NAME.put(286, "golden_axe"); ID_TO_NAME.put(287, "string"); ID_TO_NAME.put(288, "feather"); ID_TO_NAME.put(289, "gunpowder"); ID_TO_NAME.put(290, "wooden_hoe"); ID_TO_NAME.put(291, "stone_hoe"); ID_TO_NAME.put(292, "iron_hoe"); ID_TO_NAME.put(293, "diamond_hoe"); ID_TO_NAME.put(294, "golden_hoe"); ID_TO_NAME.put(295, "wheat_seeds"); ID_TO_NAME.put(296, "wheat"); ID_TO_NAME.put(297, "bread"); ID_TO_NAME.put(298, "leather_helmet"); ID_TO_NAME.put(299, "leather_chestplate"); ID_TO_NAME.put(300, "leather_leggings"); ID_TO_NAME.put(301, "leather_boots"); ID_TO_NAME.put(302, "chainmail_helmet"); ID_TO_NAME.put(303, "chainmail_chestplate"); ID_TO_NAME.put(304, "chainmail_leggings"); ID_TO_NAME.put(305, "chainmail_boots"); ID_TO_NAME.put(306, "iron_helmet"); ID_TO_NAME.put(307, "iron_chestplate"); ID_TO_NAME.put(308, "iron_leggings"); ID_TO_NAME.put(309, "iron_boots"); ID_TO_NAME.put(310, "diamond_helmet"); ID_TO_NAME.put(311, "diamond_chestplate"); ID_TO_NAME.put(312, "diamond_leggings"); ID_TO_NAME.put(313, "diamond_boots"); ID_TO_NAME.put(314, "golden_helmet"); ID_TO_NAME.put(315, "golden_chestplate"); ID_TO_NAME.put(316, "golden_leggings"); ID_TO_NAME.put(317, "golden_boots"); ID_TO_NAME.put(318, "flint"); ID_TO_NAME.put(319, "porkchop"); ID_TO_NAME.put(320, "cooked_porkchop"); ID_TO_NAME.put(321, "painting"); ID_TO_NAME.put(322, "golden_apple"); ID_TO_NAME.put(323, "sign"); ID_TO_NAME.put(324, "wooden_door"); ID_TO_NAME.put(325, "bucket"); ID_TO_NAME.put(326, "water_bucket"); ID_TO_NAME.put(327, "lava_bucket"); ID_TO_NAME.put(328, "minecart"); ID_TO_NAME.put(329, "saddle"); ID_TO_NAME.put(330, "iron_door"); ID_TO_NAME.put(331, "redstone"); ID_TO_NAME.put(332, "snowball"); ID_TO_NAME.put(333, "boat"); ID_TO_NAME.put(334, "leather"); ID_TO_NAME.put(335, "milk_bucket"); ID_TO_NAME.put(336, "brick"); ID_TO_NAME.put(337, "clay_ball"); ID_TO_NAME.put(338, "reeds"); ID_TO_NAME.put(339, "paper"); ID_TO_NAME.put(340, "book"); ID_TO_NAME.put(341, "slime_ball"); ID_TO_NAME.put(342, "chest_minecart"); ID_TO_NAME.put(343, "furnace_minecart"); ID_TO_NAME.put(344, "egg"); ID_TO_NAME.put(345, "compass"); ID_TO_NAME.put(346, "fishing_rod"); ID_TO_NAME.put(347, "clock"); ID_TO_NAME.put(348, "glowstone_dust"); ID_TO_NAME.put(349, "fish"); ID_TO_NAME.put(350, "cooked_fished"); ID_TO_NAME.put(351, "dye"); ID_TO_NAME.put(352, "bone"); ID_TO_NAME.put(353, "sugar"); ID_TO_NAME.put(354, "cake"); ID_TO_NAME.put(355, "bed"); ID_TO_NAME.put(356, "repeater"); ID_TO_NAME.put(357, "cookie"); ID_TO_NAME.put(358, "filled_map"); ID_TO_NAME.put(359, "shears"); ID_TO_NAME.put(360, "melon"); ID_TO_NAME.put(361, "pumpkin_seeds"); ID_TO_NAME.put(362, "melon_seeds"); ID_TO_NAME.put(363, "beef"); ID_TO_NAME.put(364, "cooked_beef"); ID_TO_NAME.put(365, "chicken"); ID_TO_NAME.put(366, "cooked_chicken"); ID_TO_NAME.put(367, "rotten_flesh"); ID_TO_NAME.put(368, "ender_pearl"); ID_TO_NAME.put(369, "blaze_rod"); ID_TO_NAME.put(370, "ghast_tear"); ID_TO_NAME.put(371, "gold_nugget"); ID_TO_NAME.put(372, "nether_wart"); ID_TO_NAME.put(373, "potion"); ID_TO_NAME.put(374, "glass_bottle"); ID_TO_NAME.put(375, "spider_eye"); ID_TO_NAME.put(376, "fermented_spider_eye"); ID_TO_NAME.put(377, "blaze_powder"); ID_TO_NAME.put(378, "magma_cream"); ID_TO_NAME.put(379, "brewing_stand"); ID_TO_NAME.put(380, "cauldron"); ID_TO_NAME.put(381, "ender_eye"); ID_TO_NAME.put(382, "speckled_melon"); ID_TO_NAME.put(383, "spawn_egg"); ID_TO_NAME.put(384, "experience_bottle"); ID_TO_NAME.put(385, "fire_charge"); ID_TO_NAME.put(386, "writable_book"); ID_TO_NAME.put(387, "written_book"); ID_TO_NAME.put(388, "emerald"); ID_TO_NAME.put(389, "item_frame"); ID_TO_NAME.put(390, "flower_pot"); ID_TO_NAME.put(391, "carrot"); ID_TO_NAME.put(392, "potato"); ID_TO_NAME.put(393, "baked_potato"); ID_TO_NAME.put(394, "poisonous_potato"); ID_TO_NAME.put(395, "map"); ID_TO_NAME.put(396, "golden_carrot"); ID_TO_NAME.put(397, "skull"); ID_TO_NAME.put(398, "carrot_on_a_stick"); ID_TO_NAME.put(399, "nether_star"); ID_TO_NAME.put(400, "pumpkin_pie"); ID_TO_NAME.put(401, "fireworks"); ID_TO_NAME.put(402, "firework_charge"); ID_TO_NAME.put(403, "enchanted_book"); ID_TO_NAME.put(404, "comparator"); ID_TO_NAME.put(405, "netherbrick"); ID_TO_NAME.put(406, "quartz"); ID_TO_NAME.put(407, "tnt_minecart"); ID_TO_NAME.put(408, "hopper_minecart"); ID_TO_NAME.put(417, "iron_horse_armor"); ID_TO_NAME.put(418, "golden_horse_armor"); ID_TO_NAME.put(419, "diamond_horse_armor"); ID_TO_NAME.put(420, "lead"); ID_TO_NAME.put(421, "name_tag"); ID_TO_NAME.put(422, "command_block_minecart"); ID_TO_NAME.put(2256, "record_13"); ID_TO_NAME.put(2257, "record_cat"); ID_TO_NAME.put(2258, "record_blocks"); ID_TO_NAME.put(2259, "record_chirp"); ID_TO_NAME.put(2260, "record_far"); ID_TO_NAME.put(2261, "record_mall"); ID_TO_NAME.put(2262, "record_mellohi"); ID_TO_NAME.put(2263, "record_stal"); ID_TO_NAME.put(2264, "record_strad"); ID_TO_NAME.put(2265, "record_ward"); ID_TO_NAME.put(2266, "record_11"); ID_TO_NAME.put(2267, "record_wait"); } private final Protocol protocol; public ChatComponentRewriter(final Protocol protocol) { this.protocol = protocol; } public String toClient(final UserConnection user, 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(user, 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) { if (!Via.getConfig().isSuppressConversionWarnings() || Via.getManager().isDebug()) { 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); } }