diff --git a/build.gradle.kts b/build.gradle.kts index cbaa57f4..803e50bf 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -5,7 +5,7 @@ plugins { allprojects { group = "com.viaversion" - version = "4.7.1-SNAPSHOT" + version = "4.8.0-23w31a-SNAPSHOT" description = "Allow older clients to join newer server versions." } diff --git a/common/src/main/java/com/viaversion/viabackwards/api/ViaBackwardsPlatform.java b/common/src/main/java/com/viaversion/viabackwards/api/ViaBackwardsPlatform.java index 29264f77..f94ef6d8 100644 --- a/common/src/main/java/com/viaversion/viabackwards/api/ViaBackwardsPlatform.java +++ b/common/src/main/java/com/viaversion/viabackwards/api/ViaBackwardsPlatform.java @@ -51,6 +51,7 @@ import com.viaversion.viabackwards.protocol.protocol1_19_1to1_19_3.Protocol1_19_ import com.viaversion.viabackwards.protocol.protocol1_19_3to1_19_4.Protocol1_19_3To1_19_4; import com.viaversion.viabackwards.protocol.protocol1_19_4to1_20.Protocol1_19_4To1_20; import com.viaversion.viabackwards.protocol.protocol1_19to1_19_1.Protocol1_19To1_19_1; +import com.viaversion.viabackwards.protocol.protocol1_20_4to1_20_2.Protocol1_20To1_20_2; import com.viaversion.viabackwards.protocol.protocol1_9_4to1_10.Protocol1_9_4To1_10; import com.viaversion.viaversion.api.Via; import com.viaversion.viaversion.api.protocol.ProtocolManager; @@ -61,7 +62,7 @@ import java.util.logging.Logger; public interface ViaBackwardsPlatform { - String MINIMUM_VV_VERSION = "4.7.0"; + String MINIMUM_VV_VERSION = "4.8.0"; String IMPL_VERSION = "$IMPL_VERSION"; /** @@ -126,6 +127,7 @@ public interface ViaBackwardsPlatform { protocolManager.registerProtocol(new Protocol1_19_3To1_19_4(), ProtocolVersion.v1_19_3, ProtocolVersion.v1_19_4); protocolManager.registerProtocol(new Protocol1_19_4To1_20(), ProtocolVersion.v1_19_4, ProtocolVersion.v1_20); + protocolManager.registerProtocol(new Protocol1_20To1_20_2(), ProtocolVersion.v1_20, ProtocolVersion.v1_20_2); } /** diff --git a/common/src/main/java/com/viaversion/viabackwards/api/rewriters/ItemRewriter.java b/common/src/main/java/com/viaversion/viabackwards/api/rewriters/ItemRewriter.java index 6f7e4ced..2ddb4bc7 100644 --- a/common/src/main/java/com/viaversion/viabackwards/api/rewriters/ItemRewriter.java +++ b/common/src/main/java/com/viaversion/viabackwards/api/rewriters/ItemRewriter.java @@ -40,6 +40,10 @@ public class ItemRewriter itemType, Type itemArrayType) { + super(protocol, itemType, itemArrayType, true); + } + @Override public @Nullable Item handleItemToClient(@Nullable Item item) { if (item == null) { diff --git a/common/src/main/java/com/viaversion/viabackwards/api/rewriters/ItemRewriterBase.java b/common/src/main/java/com/viaversion/viabackwards/api/rewriters/ItemRewriterBase.java index 43d84013..987603f3 100644 --- a/common/src/main/java/com/viaversion/viabackwards/api/rewriters/ItemRewriterBase.java +++ b/common/src/main/java/com/viaversion/viabackwards/api/rewriters/ItemRewriterBase.java @@ -21,6 +21,7 @@ import com.viaversion.viabackwards.api.BackwardsProtocol; import com.viaversion.viaversion.api.minecraft.item.Item; import com.viaversion.viaversion.api.protocol.packet.ClientboundPacketType; import com.viaversion.viaversion.api.protocol.packet.ServerboundPacketType; +import com.viaversion.viaversion.api.type.Type; import com.viaversion.viaversion.libs.opennbt.tag.builtin.CompoundTag; import com.viaversion.viaversion.libs.opennbt.tag.builtin.ListTag; import com.viaversion.viaversion.libs.opennbt.tag.builtin.StringTag; @@ -35,7 +36,11 @@ public abstract class ItemRewriterBase itemType, Type itemArrayType, boolean jsonNameFormat) { + super(protocol, itemType, itemArrayType); this.jsonNameFormat = jsonNameFormat; nbtTagName = "VB|" + protocol.getClass().getSimpleName(); } diff --git a/common/src/main/java/com/viaversion/viabackwards/protocol/protocol1_12_2to1_13/packets/BlockItemPackets1_13.java b/common/src/main/java/com/viaversion/viabackwards/protocol/protocol1_12_2to1_13/packets/BlockItemPackets1_13.java index b2580f0e..53e65979 100644 --- a/common/src/main/java/com/viaversion/viabackwards/protocol/protocol1_12_2to1_13/packets/BlockItemPackets1_13.java +++ b/common/src/main/java/com/viaversion/viabackwards/protocol/protocol1_12_2to1_13/packets/BlockItemPackets1_13.java @@ -240,7 +240,7 @@ public class BlockItemPackets1_13 extends com.viaversion.viabackwards.api.rewrit map(Type.UNSIGNED_BYTE); map(Type.FLAT_ITEM_ARRAY, Type.ITEM_ARRAY); - handler(itemArrayHandler(Type.ITEM_ARRAY)); + handler(itemArrayToClientHandler(Type.ITEM_ARRAY)); } }); diff --git a/common/src/main/java/com/viaversion/viabackwards/protocol/protocol1_16_4to1_17/packets/BlockItemPackets1_17.java b/common/src/main/java/com/viaversion/viabackwards/protocol/protocol1_16_4to1_17/packets/BlockItemPackets1_17.java index 5b459a75..b02e1345 100644 --- a/common/src/main/java/com/viaversion/viabackwards/protocol/protocol1_16_4to1_17/packets/BlockItemPackets1_17.java +++ b/common/src/main/java/com/viaversion/viabackwards/protocol/protocol1_16_4to1_17/packets/BlockItemPackets1_17.java @@ -203,7 +203,7 @@ public final class BlockItemPackets1_17 extends ItemRewriter. + */ +package com.viaversion.viabackwards.protocol.protocol1_20_4to1_20_2; + +import com.viaversion.viabackwards.api.BackwardsProtocol; +import com.viaversion.viabackwards.protocol.protocol1_20_4to1_20_2.rewriter.BlockItemPacketRewriter1_20_2; +import com.viaversion.viabackwards.protocol.protocol1_20_4to1_20_2.rewriter.EntityPacketRewriter1_20_2; +import com.viaversion.viabackwards.protocol.protocol1_20_4to1_20_2.storage.ConfigurationPacketStorage; +import com.viaversion.viaversion.api.Via; +import com.viaversion.viaversion.api.connection.UserConnection; +import com.viaversion.viaversion.api.minecraft.entities.Entity1_19_4Types; +import com.viaversion.viaversion.api.protocol.packet.Direction; +import com.viaversion.viaversion.api.protocol.packet.PacketWrapper; +import com.viaversion.viaversion.api.protocol.packet.State; +import com.viaversion.viaversion.api.rewriter.EntityRewriter; +import com.viaversion.viaversion.api.rewriter.ItemRewriter; +import com.viaversion.viaversion.api.type.Type; +import com.viaversion.viaversion.data.entity.EntityTrackerBase; +import com.viaversion.viaversion.exception.CancelException; +import com.viaversion.viaversion.libs.opennbt.tag.builtin.CompoundTag; +import com.viaversion.viaversion.protocols.base.ClientboundLoginPackets; +import com.viaversion.viaversion.protocols.base.ServerboundLoginPackets; +import com.viaversion.viaversion.protocols.protocol1_19_4to1_19_3.ClientboundPackets1_19_4; +import com.viaversion.viaversion.protocols.protocol1_19_4to1_19_3.ServerboundPackets1_19_4; +import com.viaversion.viaversion.protocols.protocol1_20_2to1_20.packet.ClientboundConfigurationPackets1_20_2; +import com.viaversion.viaversion.protocols.protocol1_20_2to1_20.packet.ClientboundPackets1_20_2; +import com.viaversion.viaversion.protocols.protocol1_20_2to1_20.packet.ServerboundConfigurationPackets1_20_2; +import com.viaversion.viaversion.protocols.protocol1_20_2to1_20.packet.ServerboundPackets1_20_2; +import java.util.UUID; + +public final class Protocol1_20To1_20_2 extends BackwardsProtocol { + + private final EntityPacketRewriter1_20_2 entityPacketRewriter = new EntityPacketRewriter1_20_2(this); + private final BlockItemPacketRewriter1_20_2 itemPacketRewriter = new BlockItemPacketRewriter1_20_2(this); + + public Protocol1_20To1_20_2() { + super(ClientboundPackets1_20_2.class, ClientboundPackets1_19_4.class, ServerboundPackets1_20_2.class, ServerboundPackets1_19_4.class); + } + + @Override + protected void registerPackets() { + super.registerPackets(); + Via.getManager().debugHandler().setEnabled(true); + + registerClientbound(ClientboundPackets1_20_2.SCOREBOARD_OBJECTIVE, wrapper -> { + final int slot = wrapper.read(Type.VAR_INT); + wrapper.write(Type.BYTE, (byte) slot); + }); + + registerClientbound(State.LOGIN, ClientboundLoginPackets.GAME_PROFILE.getId(), ClientboundLoginPackets.GAME_PROFILE.getId(), wrapper -> { + final ServerboundLoginPackets ackPacket = ServerboundLoginPackets.LOGIN_ACKNOWLEDGED; + wrapper.create(ackPacket).sendToServer(Protocol1_20To1_20_2.class); + + // We can't set the internal state to configuration here as protocols down the line will expect the state to be play + wrapper.user().put(new ConfigurationPacketStorage()); + System.out.println(wrapper.user().getProtocolInfo().getState()); + }); + + registerClientbound(State.CONFIGURATION, ClientboundConfigurationPackets1_20_2.FINISH_CONFIGURATION.getId(), ClientboundConfigurationPackets1_20_2.FINISH_CONFIGURATION.getId(), wrapper -> { + wrapper.cancel(); + wrapper.create(ServerboundConfigurationPackets1_20_2.FINISH_CONFIGURATION).sendToServer(Protocol1_20To1_20_2.class); + wrapper.user().getProtocolInfo().setState(State.PLAY); + }); + + registerServerbound(State.LOGIN, ServerboundLoginPackets.HELLO.getId(), ServerboundLoginPackets.HELLO.getId(), wrapper -> { + wrapper.passthrough(Type.STRING); // Name + + // TODO Bad + final UUID uuid = wrapper.read(Type.OPTIONAL_UUID); + wrapper.write(Type.UUID, uuid != null ? uuid : new UUID(0, 0)); + }); + + cancelClientbound(ClientboundPackets1_20_2.START_CONFIGURATION); // TODO + + // Some can be directly remapped to play packets, others need to be queued + registerClientbound(State.CONFIGURATION, ClientboundConfigurationPackets1_20_2.DISCONNECT.getId(), ClientboundPackets1_19_4.DISCONNECT.getId()); + registerClientbound(State.CONFIGURATION, ClientboundConfigurationPackets1_20_2.KEEP_ALIVE.getId(), ClientboundPackets1_19_4.KEEP_ALIVE.getId()); + registerClientbound(State.CONFIGURATION, ClientboundConfigurationPackets1_20_2.RESOURCE_PACK.getId(), ClientboundPackets1_19_4.RESOURCE_PACK.getId()); + registerClientbound(State.CONFIGURATION, ClientboundConfigurationPackets1_20_2.REGISTRY_DATA.getId(), -1, wrapper -> { + wrapper.cancel(); + + final CompoundTag registry = wrapper.read(Type.NAMELESS_NBT); + entityPacketRewriter.trackBiomeSize(wrapper.user(), registry); + entityPacketRewriter.cacheDimensionData(wrapper.user(), registry); + wrapper.user().get(ConfigurationPacketStorage.class).setRegistry(registry); + }); + registerClientbound(State.CONFIGURATION, ClientboundConfigurationPackets1_20_2.UPDATE_ENABLED_FEATURES.getId(), -1, wrapper -> { + wrapper.cancel(); + + final String[] enabledFeatures = wrapper.read(Type.STRING_ARRAY); + wrapper.user().get(ConfigurationPacketStorage.class).setEnabledFeatures(enabledFeatures); + }); + registerClientbound(State.CONFIGURATION, ClientboundConfigurationPackets1_20_2.UPDATE_TAGS.getId(), -1, wrapper -> { + wrapper.cancel(); + wrapper.user().get(ConfigurationPacketStorage.class).addRawPacket(wrapper, ClientboundPackets1_19_4.TAGS); + }); + registerClientbound(State.CONFIGURATION, ClientboundConfigurationPackets1_20_2.CUSTOM_PAYLOAD.getId(), -1, wrapper -> { + wrapper.cancel(); + wrapper.user().get(ConfigurationPacketStorage.class).addRawPacket(wrapper, ClientboundPackets1_19_4.PLUGIN_MESSAGE); + }); + } + + @Override + public void transform(final Direction direction, final State state, final PacketWrapper wrapper) throws Exception { + final ConfigurationPacketStorage configurationPacketStorage = wrapper.user().get(ConfigurationPacketStorage.class); + if (configurationPacketStorage == null) { + super.transform(direction, state, wrapper); + return; + } + if (direction == Direction.CLIENTBOUND) { + super.transform(direction, State.CONFIGURATION, wrapper); + return; + } + + // Map some of the packets to their configuration counterparts + final int id = wrapper.getId(); + if (id == ServerboundPackets1_19_4.PLUGIN_MESSAGE.getId()) { + wrapper.setPacketType(ServerboundConfigurationPackets1_20_2.CUSTOM_PAYLOAD); + } else if (id == ServerboundPackets1_19_4.KEEP_ALIVE.getId()) { + wrapper.setPacketType(ServerboundConfigurationPackets1_20_2.KEEP_ALIVE); + } else if (id == ServerboundPackets1_19_4.PONG.getId()) { + wrapper.setPacketType(ServerboundConfigurationPackets1_20_2.PONG); + } else if (id == ServerboundPackets1_19_4.RESOURCE_PACK_STATUS.getId()) { + wrapper.setPacketType(ServerboundConfigurationPackets1_20_2.RESOURCE_PACK); + } else { + // Can't do + // TODO Queue + System.out.println("Cancelling: " + state + " - " + wrapper.getPacketType() + " " + wrapper.getId()); + throw CancelException.generate(); + } + } + + @Override + public void init(final UserConnection connection) { + addEntityTracker(connection, new EntityTrackerBase(connection, Entity1_19_4Types.PLAYER)); + } + + @Override + public EntityRewriter getEntityRewriter() { + return entityPacketRewriter; + } + + @Override + public ItemRewriter getItemRewriter() { + return itemPacketRewriter; + } +} \ No newline at end of file diff --git a/common/src/main/java/com/viaversion/viabackwards/protocol/protocol1_20_4to1_20_2/rewriter/BlockItemPacketRewriter1_20_2.java b/common/src/main/java/com/viaversion/viabackwards/protocol/protocol1_20_4to1_20_2/rewriter/BlockItemPacketRewriter1_20_2.java new file mode 100644 index 00000000..d092a966 --- /dev/null +++ b/common/src/main/java/com/viaversion/viabackwards/protocol/protocol1_20_4to1_20_2/rewriter/BlockItemPacketRewriter1_20_2.java @@ -0,0 +1,300 @@ +/* + * This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards + * Copyright (C) 2023 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.viabackwards.protocol.protocol1_20_4to1_20_2.rewriter; + +import com.viaversion.viabackwards.api.rewriters.ItemRewriter; +import com.viaversion.viabackwards.protocol.protocol1_20_4to1_20_2.Protocol1_20To1_20_2; +import com.viaversion.viaversion.api.data.ParticleMappings; +import com.viaversion.viaversion.api.data.entity.EntityTracker; +import com.viaversion.viaversion.api.minecraft.chunks.Chunk; +import com.viaversion.viaversion.api.minecraft.item.Item; +import com.viaversion.viaversion.api.minecraft.metadata.ChunkPosition; +import com.viaversion.viaversion.api.protocol.packet.PacketWrapper; +import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers; +import com.viaversion.viaversion.api.type.Type; +import com.viaversion.viaversion.protocols.protocol1_18to1_17_1.types.Chunk1_18Type; +import com.viaversion.viaversion.protocols.protocol1_19_4to1_19_3.ServerboundPackets1_19_4; +import com.viaversion.viaversion.protocols.protocol1_19_4to1_19_3.rewriter.RecipeRewriter1_19_4; +import com.viaversion.viaversion.protocols.protocol1_20_2to1_20.packet.ClientboundPackets1_20_2; +import com.viaversion.viaversion.protocols.protocol1_20_2to1_20.type.ChunkType1_20_2; +import com.viaversion.viaversion.protocols.protocol1_20to1_19_4.Protocol1_20To1_19_4; +import com.viaversion.viaversion.util.MathUtil; + +public final class BlockItemPacketRewriter1_20_2 extends ItemRewriter { + + public BlockItemPacketRewriter1_20_2(final Protocol1_20To1_20_2 protocol) { + super(protocol, Type.ITEM1_20_2, Type.ITEM1_20_2_VAR_INT_ARRAY); + } + + @Override + public void registerPackets() { + protocol.cancelClientbound(ClientboundPackets1_20_2.CHUNK_BATCH_START); + protocol.cancelClientbound(ClientboundPackets1_20_2.CHUNK_BATCH_FINISHED); + + protocol.registerClientbound(ClientboundPackets1_20_2.UNLOAD_CHUNK, wrapper -> { + final ChunkPosition chunkPosition = wrapper.read(Type.CHUNK_POSITION); + wrapper.write(Type.INT, chunkPosition.chunkX()); + wrapper.write(Type.INT, chunkPosition.chunkZ()); + }); + + protocol.registerClientbound(ClientboundPackets1_20_2.NBT_QUERY, wrapper -> { + wrapper.passthrough(Type.VAR_INT); // Transaction id + wrapper.write(Type.NBT, wrapper.read(Type.NAMELESS_NBT)); + }); + + protocol.registerClientbound(ClientboundPackets1_20_2.BLOCK_ENTITY_DATA, wrapper -> { + wrapper.passthrough(Type.POSITION1_14); // Position + wrapper.passthrough(Type.VAR_INT); // Type + wrapper.write(Type.NBT, wrapper.read(Type.NAMELESS_NBT)); + }); + + protocol.registerClientbound(ClientboundPackets1_20_2.CHUNK_DATA, wrapper -> { + final EntityTracker tracker = protocol.getEntityRewriter().tracker(wrapper.user()); + final Type chunkType = new ChunkType1_20_2(tracker.currentWorldSectionHeight(), + MathUtil.ceilLog2(Protocol1_20To1_19_4.MAPPINGS.getBlockStateMappings().mappedSize()), + MathUtil.ceilLog2(tracker.biomesSent())); + final Chunk chunk = wrapper.read(chunkType); + + final Type newChunkType = new Chunk1_18Type(tracker.currentWorldSectionHeight(), + MathUtil.ceilLog2(Protocol1_20To1_19_4.MAPPINGS.getBlockStateMappings().mappedSize()), + MathUtil.ceilLog2(tracker.biomesSent())); + wrapper.write(newChunkType, chunk); + }); + + // Replace the NBT type everywhere + protocol.registerClientbound(ClientboundPackets1_20_2.WINDOW_ITEMS, new PacketHandlers() { + @Override + public void register() { + map(Type.UNSIGNED_BYTE); // Window id + map(Type.VAR_INT); // State id + handler(wrapper -> { + wrapper.write(Type.FLAT_VAR_INT_ITEM_ARRAY_VAR_INT, wrapper.read(Type.ITEM1_20_2_VAR_INT_ARRAY)); // Items + wrapper.write(Type.FLAT_VAR_INT_ITEM, wrapper.read(Type.ITEM1_20_2)); // Carried item + }); + } + }); + protocol.registerClientbound(ClientboundPackets1_20_2.SET_SLOT, new PacketHandlers() { + @Override + public void register() { + map(Type.UNSIGNED_BYTE); // Window id + map(Type.VAR_INT); // State id + map(Type.SHORT); // Slot id + map(Type.ITEM1_20_2, Type.FLAT_VAR_INT_ITEM); // Item + } + }); + protocol.registerClientbound(ClientboundPackets1_20_2.ADVANCEMENTS, wrapper -> { + wrapper.passthrough(Type.BOOLEAN); // Reset/clear + int size = wrapper.passthrough(Type.VAR_INT); // Mapping size + for (int i = 0; i < size; i++) { + wrapper.passthrough(Type.STRING); // Identifier + + // Parent + if (wrapper.passthrough(Type.BOOLEAN)) + wrapper.passthrough(Type.STRING); + + // Display data + if (wrapper.passthrough(Type.BOOLEAN)) { + wrapper.passthrough(Type.COMPONENT); // Title + wrapper.passthrough(Type.COMPONENT); // Description + wrapper.write(Type.FLAT_VAR_INT_ITEM, wrapper.read(Type.ITEM1_20_2)); // Icon + wrapper.passthrough(Type.VAR_INT); // Frame type + int flags = wrapper.passthrough(Type.INT); // Flags + if ((flags & 1) != 0) { + wrapper.passthrough(Type.STRING); // Background texture + } + wrapper.passthrough(Type.FLOAT); // X + wrapper.passthrough(Type.FLOAT); // Y + } + + wrapper.passthrough(Type.STRING_ARRAY); // Criteria + + int arrayLength = wrapper.passthrough(Type.VAR_INT); + for (int array = 0; array < arrayLength; array++) { + wrapper.passthrough(Type.STRING_ARRAY); // String array + } + + wrapper.passthrough(Type.BOOLEAN); // Send telemetry + } + }); + protocol.registerClientbound(ClientboundPackets1_20_2.ENTITY_EQUIPMENT, new PacketHandlers() { + @Override + public void register() { + map(Type.VAR_INT); // 0 - Entity ID + handler(wrapper -> { + byte slot; + do { + slot = wrapper.passthrough(Type.BYTE); + wrapper.write(Type.FLAT_VAR_INT_ITEM, wrapper.read(Type.ITEM1_20_2)); + } while ((slot & 0xFFFFFF80) != 0); + }); + } + }); + protocol.registerServerbound(ServerboundPackets1_19_4.CLICK_WINDOW, new PacketHandlers() { + @Override + public void register() { + map(Type.UNSIGNED_BYTE); // Window Id + map(Type.VAR_INT); // State id + map(Type.SHORT); // Slot + map(Type.BYTE); // Button + map(Type.VAR_INT); // Mode + + handler(wrapper -> { + // Affected items + int length = wrapper.passthrough(Type.VAR_INT); + for (int i = 0; i < length; i++) { + wrapper.passthrough(Type.SHORT); // Slot + wrapper.write(Type.ITEM1_20_2, wrapper.read(Type.FLAT_VAR_INT_ITEM)); + } + + // Carried item + wrapper.write(Type.ITEM1_20_2, wrapper.read(Type.FLAT_VAR_INT_ITEM)); + }); + } + }); + protocol.registerClientbound(ClientboundPackets1_20_2.TRADE_LIST, wrapper -> { + wrapper.cancel(); + wrapper.passthrough(Type.VAR_INT); // Container id + int size = wrapper.passthrough(Type.VAR_INT); + for (int i = 0; i < size; i++) { + wrapper.write(Type.FLAT_VAR_INT_ITEM, wrapper.read(Type.ITEM1_20_2)); // Input + wrapper.write(Type.FLAT_VAR_INT_ITEM, wrapper.read(Type.ITEM1_20_2)); // Output + wrapper.write(Type.FLAT_VAR_INT_ITEM, wrapper.read(Type.ITEM1_20_2)); // Second Item + + wrapper.passthrough(Type.BOOLEAN); // Trade disabled + wrapper.passthrough(Type.INT); // Number of tools uses + wrapper.passthrough(Type.INT); // Maximum number of trade uses + wrapper.passthrough(Type.INT); // XP + wrapper.passthrough(Type.INT); // Special price + wrapper.passthrough(Type.FLOAT); // Price multiplier + wrapper.passthrough(Type.INT); // Demand + } + }); + protocol.registerServerbound(ServerboundPackets1_19_4.CREATIVE_INVENTORY_ACTION, new PacketHandlers() { + @Override + public void register() { + map(Type.SHORT); // 0 - Slot + map(Type.FLAT_VAR_INT_ITEM, Type.ITEM1_20_2); // 1 - Clicked Item + } + }); + protocol.registerClientbound(ClientboundPackets1_20_2.SPAWN_PARTICLE, new PacketHandlers() { + @Override + public void register() { + map(Type.VAR_INT); // 0 - Particle ID + map(Type.BOOLEAN); // 1 - Long Distance + map(Type.DOUBLE); // 2 - X + map(Type.DOUBLE); // 3 - Y + map(Type.DOUBLE); // 4 - Z + map(Type.FLOAT); // 5 - Offset X + map(Type.FLOAT); // 6 - Offset Y + map(Type.FLOAT); // 7 - Offset Z + map(Type.FLOAT); // 8 - Particle Data + map(Type.INT); // 9 - Particle Count + handler(wrapper -> { + int id = wrapper.get(Type.VAR_INT, 0); + ParticleMappings mappings = Protocol1_20To1_19_4.MAPPINGS.getParticleMappings(); + if (mappings.isItemParticle(id)) { + wrapper.write(Type.FLAT_VAR_INT_ITEM, wrapper.read(Type.ITEM1_20_2)); + } + }); + } + }); + + new RecipeRewriter1_19_4(protocol) { + @Override + public void handleCraftingShapeless(final PacketWrapper wrapper) throws Exception { + wrapper.passthrough(Type.STRING); // Group + wrapper.passthrough(Type.VAR_INT); // Crafting book category + handleIngredients(wrapper); + + final Item result = wrapper.read(itemType()); + rewrite(result); + wrapper.write(Type.FLAT_VAR_INT_ITEM, result); + } + + @Override + public void handleSmelting(final PacketWrapper wrapper) throws Exception { + wrapper.passthrough(Type.STRING); // Group + wrapper.passthrough(Type.VAR_INT); // Crafting book category + handleIngredient(wrapper); + + final Item result = wrapper.read(itemType()); + rewrite(result); + wrapper.write(Type.FLAT_VAR_INT_ITEM, result); + + wrapper.passthrough(Type.FLOAT); // EXP + wrapper.passthrough(Type.VAR_INT); // Cooking time + } + + @Override + public void handleCraftingShaped(final PacketWrapper wrapper) throws Exception { + final int ingredients = wrapper.passthrough(Type.VAR_INT) * wrapper.passthrough(Type.VAR_INT); + wrapper.passthrough(Type.STRING); // Group + wrapper.passthrough(Type.VAR_INT); // Crafting book category + for (int i = 0; i < ingredients; i++) { + handleIngredient(wrapper); + } + + final Item result = wrapper.read(itemType()); + rewrite(result); + wrapper.write(Type.FLAT_VAR_INT_ITEM, result); + + wrapper.passthrough(Type.BOOLEAN); // Show notification + } + + @Override + public void handleStonecutting(final PacketWrapper wrapper) throws Exception { + wrapper.passthrough(Type.STRING); // Group + handleIngredient(wrapper); + + final Item result = wrapper.read(itemType()); + rewrite(result); + wrapper.write(Type.FLAT_VAR_INT_ITEM, result); + } + + @Override + public void handleSmithing(final PacketWrapper wrapper) throws Exception { + handleIngredient(wrapper); // Base + handleIngredient(wrapper); // Addition + + final Item result = wrapper.read(itemType()); + rewrite(result); + wrapper.write(Type.FLAT_VAR_INT_ITEM, result); + } + + @Override + public void handleSmithingTransform(final PacketWrapper wrapper) throws Exception { + handleIngredient(wrapper); // Template + handleIngredient(wrapper); // Base + handleIngredient(wrapper); // Additions + + final Item result = wrapper.read(itemType()); + rewrite(result); + wrapper.write(Type.FLAT_VAR_INT_ITEM, result); + } + + @Override + protected void handleIngredient(final PacketWrapper wrapper) throws Exception { + final Item[] items = wrapper.read(itemArrayType()); + wrapper.write(Type.FLAT_VAR_INT_ITEM_ARRAY_VAR_INT, items); + for (final Item item : items) { + rewrite(item); + } + } + }.register(ClientboundPackets1_20_2.DECLARE_RECIPES); + } +} \ No newline at end of file diff --git a/common/src/main/java/com/viaversion/viabackwards/protocol/protocol1_20_4to1_20_2/rewriter/EntityPacketRewriter1_20_2.java b/common/src/main/java/com/viaversion/viabackwards/protocol/protocol1_20_4to1_20_2/rewriter/EntityPacketRewriter1_20_2.java new file mode 100644 index 00000000..2b33fe40 --- /dev/null +++ b/common/src/main/java/com/viaversion/viabackwards/protocol/protocol1_20_4to1_20_2/rewriter/EntityPacketRewriter1_20_2.java @@ -0,0 +1,137 @@ +/* + * This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards + * Copyright (C) 2023 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.viabackwards.protocol.protocol1_20_4to1_20_2.rewriter; + +import com.viaversion.viabackwards.api.rewriters.EntityRewriter; +import com.viaversion.viabackwards.protocol.protocol1_20_4to1_20_2.Protocol1_20To1_20_2; +import com.viaversion.viabackwards.protocol.protocol1_20_4to1_20_2.storage.ConfigurationPacketStorage; +import com.viaversion.viaversion.api.minecraft.GlobalPosition; +import com.viaversion.viaversion.api.minecraft.entities.Entity1_19_4Types; +import com.viaversion.viaversion.api.minecraft.entities.EntityType; +import com.viaversion.viaversion.api.protocol.packet.PacketWrapper; +import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers; +import com.viaversion.viaversion.api.type.Type; +import com.viaversion.viaversion.api.type.types.version.Types1_20; +import com.viaversion.viaversion.api.type.types.version.Types1_20_2; +import com.viaversion.viaversion.protocols.protocol1_19_4to1_19_3.ClientboundPackets1_19_4; +import com.viaversion.viaversion.protocols.protocol1_20_2to1_20.packet.ClientboundPackets1_20_2; + +public final class EntityPacketRewriter1_20_2 extends EntityRewriter { + + public EntityPacketRewriter1_20_2(final Protocol1_20To1_20_2 protocol) { + super(protocol); + } + + @Override + public void registerPackets() { + registerTrackerWithData1_19(ClientboundPackets1_20_2.SPAWN_ENTITY, Entity1_19_4Types.FALLING_BLOCK); + registerMetadataRewriter(ClientboundPackets1_20_2.ENTITY_METADATA, Types1_20_2.METADATA_LIST, Types1_20.METADATA_LIST); + registerRemoveEntities(ClientboundPackets1_20_2.REMOVE_ENTITIES); + + protocol.registerClientbound(ClientboundPackets1_20_2.JOIN_GAME, new PacketHandlers() { + @Override + public void register() { + handler(wrapper -> { + final ConfigurationPacketStorage configurationPacketStorage = wrapper.user().get(ConfigurationPacketStorage.class); + wrapper.passthrough(Type.INT); // Entity id + wrapper.passthrough(Type.BOOLEAN); // Hardcore + + final String[] worlds = wrapper.read(Type.STRING_ARRAY); + final int maxPlayers = wrapper.read(Type.VAR_INT); + final int viewDistance = wrapper.read(Type.VAR_INT); + final int simulationDistance = wrapper.read(Type.VAR_INT); + final boolean reducedDebugInfo = wrapper.read(Type.BOOLEAN); + final boolean showRespawnScreen = wrapper.read(Type.BOOLEAN); + final String dimensionType = wrapper.read(Type.STRING); + final String world = wrapper.read(Type.STRING); + final long seed = wrapper.read(Type.LONG); + + wrapper.write(Type.UNSIGNED_BYTE, wrapper.read(Type.BYTE).shortValue()); // Gamemode + wrapper.passthrough(Type.BYTE); // Previous gamemode + + wrapper.write(Type.STRING_ARRAY, worlds); + wrapper.write(Type.NBT, configurationPacketStorage.registry()); + wrapper.write(Type.STRING, dimensionType); + wrapper.write(Type.STRING, world); + wrapper.write(Type.LONG, seed); + wrapper.write(Type.VAR_INT, maxPlayers); + wrapper.write(Type.VAR_INT, viewDistance); + wrapper.write(Type.VAR_INT, simulationDistance); + wrapper.write(Type.BOOLEAN, reducedDebugInfo); + wrapper.write(Type.BOOLEAN, showRespawnScreen); + + wrapper.cancel(); + wrapper.send(Protocol1_20To1_20_2.class); + + final PacketWrapper featuresPacket = wrapper.create(ClientboundPackets1_19_4.UPDATE_ENABLED_FEATURES); + featuresPacket.write(Type.STRING_ARRAY, configurationPacketStorage.enabledFeatures()); + featuresPacket.send(Protocol1_20To1_20_2.class); + + configurationPacketStorage.sendQueuedPackets(wrapper.user()); + }); + handler(worldDataTrackerHandlerByKey()); + } + }); + + protocol.registerClientbound(ClientboundPackets1_20_2.RESPAWN, new PacketHandlers() { + @Override + public void register() { + handler(wrapper -> { + wrapper.passthrough(Type.STRING); // Dimension type + wrapper.passthrough(Type.STRING); // World + wrapper.passthrough(Type.LONG); // Seed + wrapper.write(Type.UNSIGNED_BYTE, wrapper.read(Type.BYTE).shortValue()); // Gamemode + wrapper.passthrough(Type.BYTE); // Previous gamemode + wrapper.passthrough(Type.BOOLEAN); // Debug + wrapper.passthrough(Type.BOOLEAN); // Flat + + final GlobalPosition lastDeathPosition = wrapper.read(Type.OPTIONAL_GLOBAL_POSITION); + final int portalCooldown = wrapper.read(Type.VAR_INT); + + wrapper.passthrough(Type.BYTE); // Data to keep + + wrapper.write(Type.OPTIONAL_GLOBAL_POSITION, lastDeathPosition); + wrapper.write(Type.VAR_INT, portalCooldown); + }); + handler(worldDataTrackerHandlerByKey()); // Tracks world height and name for chunk data and entity (un)tracking + } + }); + + protocol.registerClientbound(ClientboundPackets1_20_2.ENTITY_EFFECT, wrapper -> { + wrapper.passthrough(Type.VAR_INT); // Entity id + wrapper.passthrough(Type.VAR_INT); // Effect id + wrapper.passthrough(Type.BYTE); // Amplifier + wrapper.passthrough(Type.VAR_INT); // Duration + wrapper.passthrough(Type.BYTE); // Flags + if (wrapper.passthrough(Type.BOOLEAN)) { + wrapper.write(Type.NBT, wrapper.read(Type.NAMELESS_NBT)); // Factor data + } + }); + } + + @Override + protected void registerRewrites() { + filter().handler((event, meta) -> meta.setMetaType(Types1_20.META_TYPES.byId(meta.metaType().typeId()))); + filter().filterFamily(Entity1_19_4Types.DISPLAY).removeIndex(10); + } + + @Override + public EntityType typeFromId(final int type) { + return Entity1_19_4Types.getTypeFromId(type); + } +} \ No newline at end of file diff --git a/common/src/main/java/com/viaversion/viabackwards/protocol/protocol1_20_4to1_20_2/storage/ConfigurationPacketStorage.java b/common/src/main/java/com/viaversion/viabackwards/protocol/protocol1_20_4to1_20_2/storage/ConfigurationPacketStorage.java new file mode 100644 index 00000000..06ea1223 --- /dev/null +++ b/common/src/main/java/com/viaversion/viabackwards/protocol/protocol1_20_4to1_20_2/storage/ConfigurationPacketStorage.java @@ -0,0 +1,95 @@ +/* + * This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards + * Copyright (C) 2023 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.viabackwards.protocol.protocol1_20_4to1_20_2.storage; + +import com.viaversion.viabackwards.protocol.protocol1_20_4to1_20_2.Protocol1_20To1_20_2; +import com.viaversion.viaversion.api.connection.StorableObject; +import com.viaversion.viaversion.api.connection.UserConnection; +import com.viaversion.viaversion.api.protocol.packet.PacketType; +import com.viaversion.viaversion.api.protocol.packet.PacketWrapper; +import com.viaversion.viaversion.libs.opennbt.tag.builtin.CompoundTag; +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import java.util.ArrayList; +import java.util.List; + +public final class ConfigurationPacketStorage implements StorableObject { + + private final List rawPackets = new ArrayList<>(); + private CompoundTag registry; + private String[] enabledFeatures; + + public CompoundTag registry() { + return registry; + } + + public void setRegistry(final CompoundTag registry) { + this.registry = registry; + } + + public String[] enabledFeatures() { + return enabledFeatures; + } + + public void setEnabledFeatures(final String[] enabledFeatures) { + this.enabledFeatures = enabledFeatures; + } + + public List getRawPackets() { + return rawPackets; + } + + public void addRawPacket(final PacketWrapper wrapper, final PacketType type) throws Exception { + // It's easier to just copy it to a byte array buffer than to manually read the data + final ByteBuf buf = Unpooled.buffer(); + final int id = wrapper.getId(); + //noinspection deprecation + wrapper.setId(-1); // Don't write the packet id to the buffer + wrapper.writeToBuffer(buf); + rawPackets.add(new QueuedPacket(buf, type)); + } + + public void sendQueuedPackets(final UserConnection connection) throws Exception { + for (final QueuedPacket queuedPacket : rawPackets) { + try { + final PacketWrapper packet = PacketWrapper.create(queuedPacket.packetType(), queuedPacket.buf(), connection); + packet.send(Protocol1_20To1_20_2.class); + } finally { + queuedPacket.buf().release(); + } + } + } + + public static final class QueuedPacket { + private final ByteBuf buf; + private final PacketType packetType; + + public QueuedPacket(final ByteBuf buf, final PacketType packetType) { + this.buf = buf; + this.packetType = packetType; + } + + public ByteBuf buf() { + return buf; + } + + public PacketType packetType() { + return packetType; + } + } +} diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 08c0ef92..d03f12e5 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -3,7 +3,7 @@ metadata.format.version = "1.1" [versions] # ViaVersion -viaver = "4.7.1-SNAPSHOT" +viaver = "4.8.0-23w31a-SNAPSHOT" # Common provided netty = "4.0.20.Final"