/* * This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion * Copyright (C) 2016-2024 ViaVersion 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 com.viaversion.viaversion.protocols.protocol1_9to1_8; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.viaversion.viaversion.api.Via; import com.viaversion.viaversion.api.connection.UserConnection; import com.viaversion.viaversion.api.minecraft.ClientWorld; import com.viaversion.viaversion.api.minecraft.item.Item; import com.viaversion.viaversion.api.platform.providers.ViaProviders; import com.viaversion.viaversion.api.protocol.AbstractProtocol; import com.viaversion.viaversion.api.protocol.packet.PacketWrapper; import com.viaversion.viaversion.api.protocol.packet.State; import com.viaversion.viaversion.api.protocol.remapper.ValueTransformer; import com.viaversion.viaversion.api.type.Type; import com.viaversion.viaversion.protocols.protocol1_8.ClientboundPackets1_8; import com.viaversion.viaversion.protocols.protocol1_8.ServerboundPackets1_8; import com.viaversion.viaversion.protocols.protocol1_9to1_8.metadata.MetadataRewriter1_9To1_8; import com.viaversion.viaversion.protocols.protocol1_9to1_8.packets.EntityPackets; import com.viaversion.viaversion.protocols.protocol1_9to1_8.packets.InventoryPackets; import com.viaversion.viaversion.protocols.protocol1_9to1_8.packets.PlayerPackets; import com.viaversion.viaversion.protocols.protocol1_9to1_8.packets.SpawnPackets; import com.viaversion.viaversion.protocols.protocol1_9to1_8.packets.WorldPackets; import com.viaversion.viaversion.protocols.protocol1_9to1_8.providers.BossBarProvider; import com.viaversion.viaversion.protocols.protocol1_9to1_8.providers.CommandBlockProvider; import com.viaversion.viaversion.protocols.protocol1_9to1_8.providers.CompressionProvider; import com.viaversion.viaversion.protocols.protocol1_9to1_8.providers.EntityIdProvider; import com.viaversion.viaversion.protocols.protocol1_9to1_8.providers.HandItemProvider; import com.viaversion.viaversion.protocols.protocol1_9to1_8.providers.MainHandProvider; import com.viaversion.viaversion.protocols.protocol1_9to1_8.providers.MovementTransmitterProvider; import com.viaversion.viaversion.protocols.protocol1_9to1_8.storage.ClientChunks; import com.viaversion.viaversion.protocols.protocol1_9to1_8.storage.CommandBlockStorage; import com.viaversion.viaversion.protocols.protocol1_9to1_8.storage.EntityTracker1_9; import com.viaversion.viaversion.protocols.protocol1_9to1_8.storage.InventoryTracker; import com.viaversion.viaversion.protocols.protocol1_9to1_8.storage.MovementTracker; import com.viaversion.viaversion.util.GsonUtil; public class Protocol1_9To1_8 extends AbstractProtocol { public static final ValueTransformer FIX_JSON = new ValueTransformer(Type.COMPONENT) { @Override public JsonElement transform(PacketWrapper wrapper, String line) { return fixJson(line); } }; private final MetadataRewriter1_9To1_8 metadataRewriter = new MetadataRewriter1_9To1_8(this); public Protocol1_9To1_8() { super(ClientboundPackets1_8.class, ClientboundPackets1_9.class, ServerboundPackets1_8.class, ServerboundPackets1_9.class); } public static JsonElement fixJson(String line) { if (line == null || line.equalsIgnoreCase("null")) { line = "{\"text\":\"\"}"; } else { if ((!line.startsWith("\"") || !line.endsWith("\"")) && (!line.startsWith("{") || !line.endsWith("}"))) { return constructJson(line); } if (line.startsWith("\"") && line.endsWith("\"")) { line = "{\"text\":" + line + "}"; } } try { return GsonUtil.getGson().fromJson(line, JsonObject.class); } catch (Exception e) { if (Via.getConfig().isForceJsonTransform()) { return constructJson(line); } else { Via.getPlatform().getLogger().warning("Invalid JSON String: \"" + line + "\" Please report this issue to the ViaVersion Github: " + e.getMessage()); return GsonUtil.getGson().fromJson("{\"text\":\"\"}", JsonObject.class); } } } private static JsonElement constructJson(String text) { JsonObject jsonObject = new JsonObject(); jsonObject.addProperty("text", text); return jsonObject; } public static Item getHandItem(final UserConnection info) { return Via.getManager().getProviders().get(HandItemProvider.class).getHandItem(info); } public static boolean isSword(int id) { switch (id) { case 267: // Iron sword case 268: // Wooden sword case 272: // Stone sword case 276: // Diamond sword case 283: // Gold sword return true; default: return false; } } @Override protected void registerPackets() { super.registerPackets(); // Disconnect workaround (JSON!) registerClientbound(State.LOGIN, 0x00, 0x00, wrapper -> { if (wrapper.isReadable(Type.COMPONENT, 0)) { // Already written as json somewhere else return; } wrapper.write(Type.COMPONENT, fixJson(wrapper.read(Type.STRING))); }); // Other Handlers SpawnPackets.register(this); InventoryPackets.register(this); EntityPackets.register(this); PlayerPackets.register(this); WorldPackets.register(this); } @Override public void register(ViaProviders providers) { providers.register(HandItemProvider.class, new HandItemProvider()); providers.register(CommandBlockProvider.class, new CommandBlockProvider()); providers.register(EntityIdProvider.class, new EntityIdProvider()); providers.register(BossBarProvider.class, new BossBarProvider()); providers.register(MainHandProvider.class, new MainHandProvider()); providers.register(CompressionProvider.class, new CompressionProvider()); providers.register(MovementTransmitterProvider.class, new MovementTransmitterProvider()); } @Override public void init(UserConnection userConnection) { // Entity tracker userConnection.addEntityTracker(this.getClass(), new EntityTracker1_9(userConnection)); // Chunk tracker userConnection.put(new ClientChunks()); // Movement tracker userConnection.put(new MovementTracker()); // Inventory tracker userConnection.put(new InventoryTracker()); // CommandBlock storage userConnection.put(new CommandBlockStorage()); if (!userConnection.has(ClientWorld.class)) { userConnection.put(new ClientWorld()); } } @Override public MetadataRewriter1_9To1_8 getEntityRewriter() { return metadataRewriter; } }