From 0d21edbd43a55dc3cbbbd89bfce9b38a120d42ef Mon Sep 17 00:00:00 2001 From: nnnlog Date: Fri, 24 Nov 2023 21:58:23 +0900 Subject: [PATCH 1/4] Update for 1.20.2 --- src/main/java/config/Version.java | 1 + .../java/game/data/chunk/ChunkFactory.java | 1 + .../game/data/chunk/version/Chunk_1_18.java | 4 +- .../game/data/chunk/version/Chunk_1_20_2.java | 51 +++++++++++ .../game/data/dimension/DimensionCodec.java | 8 +- .../java/game/data/entity/EntityRegistry.java | 79 +++++++++++++--- .../java/game/data/entity/PlayerEntity.java | 11 ++- src/main/java/packets/DataTypeProvider.java | 4 +- .../java/packets/builder/PacketBuilder.java | 1 + .../handler/ClientBoundGamePacketHandler.java | 8 +- .../ClientBoundGamePacketHandler_1_16.java | 2 +- .../ClientBoundGamePacketHandler_1_19.java | 2 +- .../ClientBoundGamePacketHandler_1_20_2.java | 90 +++++++++++++++++++ .../version/DataTypeProvider_1_20_2.java | 32 +++++++ src/main/resources/protocol-versions.json | 41 +++++++++ .../protocol/ProtocolVersionHandlerTest.java | 1 + 16 files changed, 308 insertions(+), 28 deletions(-) create mode 100644 src/main/java/game/data/chunk/version/Chunk_1_20_2.java create mode 100644 src/main/java/packets/handler/version/ClientBoundGamePacketHandler_1_20_2.java create mode 100644 src/main/java/packets/version/DataTypeProvider_1_20_2.java diff --git a/src/main/java/config/Version.java b/src/main/java/config/Version.java index 8723162c..5f5eec4d 100644 --- a/src/main/java/config/Version.java +++ b/src/main/java/config/Version.java @@ -12,6 +12,7 @@ public enum Version { V1_19(759, 3105), V1_19_3(761, 3218), V1_20(763, 3463), + V1_20_2(764, 3578), ANY(0, 0); public final int dataVersion; diff --git a/src/main/java/game/data/chunk/ChunkFactory.java b/src/main/java/game/data/chunk/ChunkFactory.java index fea95978..a821b526 100644 --- a/src/main/java/game/data/chunk/ChunkFactory.java +++ b/src/main/java/game/data/chunk/ChunkFactory.java @@ -45,6 +45,7 @@ public void clear() { */ private static Chunk getVersionedChunk(int dataVersion, CoordinateDim2D chunkPos) { return VersionReporter.select(dataVersion, Chunk.class, + Option.of(Version.V1_20_2, () -> new Chunk_1_20_2(chunkPos, dataVersion)), Option.of(Version.V1_20, () -> new Chunk_1_20(chunkPos, dataVersion)), Option.of(Version.V1_18, () -> new Chunk_1_18(chunkPos, dataVersion)), Option.of(Version.V1_17, () -> new Chunk_1_17(chunkPos, dataVersion)), diff --git a/src/main/java/game/data/chunk/version/Chunk_1_18.java b/src/main/java/game/data/chunk/version/Chunk_1_18.java index 073b2adb..fa55e2b8 100644 --- a/src/main/java/game/data/chunk/version/Chunk_1_18.java +++ b/src/main/java/game/data/chunk/version/Chunk_1_18.java @@ -133,7 +133,7 @@ public void readChunkColumn(DataTypeProvider dataProvider) { } } - private void findBlockEntities(ChunkSection section, int sectionY) { + protected void findBlockEntities(ChunkSection section, int sectionY) { BlockEntityRegistry blockEntities = RegistryManager.getInstance().getBlockEntityRegistry(); GlobalPalette globalPalette = GlobalPaletteProvider.getGlobalPalette(getDataVersion()); @@ -151,7 +151,7 @@ private void findBlockEntities(ChunkSection section, int sectionY) { } } - private boolean containsBlockEntities(Palette p) { + protected boolean containsBlockEntities(Palette p) { BlockEntityRegistry blockEntities = RegistryManager.getInstance().getBlockEntityRegistry(); for (SpecificTag tag : p.toNbt()) { if (blockEntities.isBlockEntity(tag.get("Name").stringValue())) { diff --git a/src/main/java/game/data/chunk/version/Chunk_1_20_2.java b/src/main/java/game/data/chunk/version/Chunk_1_20_2.java new file mode 100644 index 00000000..6c3c4319 --- /dev/null +++ b/src/main/java/game/data/chunk/version/Chunk_1_20_2.java @@ -0,0 +1,51 @@ +package game.data.chunk.version; + +import game.data.chunk.palette.Palette; +import game.data.chunk.palette.PaletteType; +import game.data.coordinates.CoordinateDim2D; +import packets.DataTypeProvider; + +public class Chunk_1_20_2 extends Chunk_1_20 { + + + public Chunk_1_20_2(CoordinateDim2D location, int version) { + super(location, version); + } + + /** + * Read a chunk column for 1.20.2 + */ + public void readChunkColumn(DataTypeProvider dataProvider) { + // Loop through section Y values, starting from the lowest section that has blocks inside it. + for (int sectionY = getMinBlockSection(); sectionY <= getMaxBlockSection() && dataProvider.hasNext(); sectionY++) { + ChunkSection_1_18 section = (ChunkSection_1_18) getChunkSection(sectionY); + + dataProvider.readShort(); + Palette blockPalette = Palette.readPalette(dataProvider, PaletteType.BLOCKS); + + if (section == null) { + section = (ChunkSection_1_18) createNewChunkSection((byte) (sectionY & 0xFF), blockPalette); + } else { + section.setBlockPalette(blockPalette); + } + + section.setBlocks(dataProvider.readLongArray(dataProvider.readVarInt())); + + Palette biomePalette = Palette.readPalette(dataProvider, PaletteType.BIOMES); + section.setBiomePalette(biomePalette); + + // check how many longs we expect, if there's more discard the rest + int longsExpectedBiomes = ChunkSection_1_18.longsRequiredBiomes(biomePalette.getBitsPerBlock()); + section.setBiomes(dataProvider.readLongArray(dataProvider.readVarInt())); + + // May replace an existing section or a null one + setChunkSection(sectionY, section); + + // servers don't (always?) include containers in the list of block_entities. We need to know that these block + // entities exist, otherwise we'll end up not writing block entity data for them + if (containsBlockEntities(blockPalette)) { + findBlockEntities(section, sectionY); + } + } + } +} diff --git a/src/main/java/game/data/dimension/DimensionCodec.java b/src/main/java/game/data/dimension/DimensionCodec.java index b0ea1e7b..a38da1bf 100644 --- a/src/main/java/game/data/dimension/DimensionCodec.java +++ b/src/main/java/game/data/dimension/DimensionCodec.java @@ -63,16 +63,20 @@ private DimensionCodec() { this.biomes = new HashMap<>(); } - public static DimensionCodec fromNbt(String[] dimensionNames, SpecificTag tag) { + public static DimensionCodec fromNbt(SpecificTag tag) { DimensionCodec codec = new DimensionCodec(); - codec.readDimensions(dimensionNames); codec.readDimensionTypes(tag.get("minecraft:dimension_type").asCompound().get("value").asList()); codec.readBiomes(tag.get("minecraft:worldgen/biome").asCompound().get("value").asList()); return codec; } + public DimensionCodec setDimensionNames(String[] dimensionNames) { + this.readDimensions(dimensionNames); + return this; + } + public Collection getDimensions() { return dimensions.values(); } diff --git a/src/main/java/game/data/entity/EntityRegistry.java b/src/main/java/game/data/entity/EntityRegistry.java index 47f397eb..873e48c4 100644 --- a/src/main/java/game/data/entity/EntityRegistry.java +++ b/src/main/java/game/data/entity/EntityRegistry.java @@ -2,11 +2,7 @@ import static util.ExceptionHandling.attempt; -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.Set; +import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; @@ -18,11 +14,12 @@ import game.data.coordinates.CoordinateDim2D; import game.data.entity.specific.Villager; import packets.DataTypeProvider; +import packets.UUID; import se.llbit.nbt.SpecificTag; public class EntityRegistry { - private final Map players; + private final Map players; private final Map> perChunk; private final Map entities; private final WorldManager worldManager; @@ -73,7 +70,6 @@ public void addEntity(DataTypeProvider provider, Function markUnsaved(pos.globalToDimChunk())); } })); @@ -81,8 +77,64 @@ public void addEntity(DataTypeProvider provider, Function attempt(() -> { - int entId = provider.readVarInt(); - players.put(entId, PlayerEntity.parse(provider)); + PlayerEntity player = PlayerEntity.parse(provider); + players.put(player.getUUID(), player); + })); + } + + public void updatePlayerAction(DataTypeProvider provider) { + executor.execute(() -> attempt(() -> { + byte actions = provider.readNext(); + int playerCnt = provider.readVarInt(); + + for (int i = 0; i < playerCnt; i++) { + UUID uuid = provider.readUUID(); + + if ((actions & 0x01) > 0) { + PlayerEntity player = new PlayerEntity(uuid); + players.put(uuid, player); + + String name = provider.readString(); + int properties = provider.readVarInt(); + for (int j = 0; j < properties; j++) { + provider.readString(); + provider.readString(); + boolean signed = provider.readBoolean(); + if (signed) provider.readString(); + } + } + + if ((actions & 0x02) > 0) { + boolean signature = provider.readBoolean(); + if (signature) { + provider.readUUID(); + provider.readLong(); + int encKeySz = provider.readVarInt(); + provider.readByteArray(encKeySz); + int pubKeySz = provider.readVarInt(); + provider.readByteArray(pubKeySz); + } + } + + if ((actions & 0x04) > 0) { + provider.readVarInt(); + } + + if ((actions & 0x08) > 0) { + provider.readBoolean(); + } + + if ((actions & 0x10) > 0) { + provider.readVarInt(); + } + + if ((actions & 0x20) > 0) { + boolean displayName = provider.readBoolean(); + if (displayName) { + provider.readChat(); + } + } + } })); } @@ -139,12 +191,14 @@ public void updatePositionAbsolute(DataTypeProvider provider) { } public IMovableEntity getMovableEntity(int entId) { - IMovableEntity ent = players.get(entId); + Entity tmpEnt = entities.get(entId); + if (tmpEnt == null) return null; + IMovableEntity ent = players.get(tmpEnt.uuid); if (ent != null) { return ent; } - return entities.get(entId); + return tmpEnt; } public List getEntitiesNbt(CoordinateDim2D location) { @@ -183,9 +237,8 @@ public void destroyEntities(DataTypeProvider provider) { while (count-- > 0) { int id = provider.readVarInt(); if (entities.containsKey(id)) { + players.remove(entities.get(id).uuid); entities.remove(id); - } else { - players.remove(id); } } } diff --git a/src/main/java/game/data/entity/PlayerEntity.java b/src/main/java/game/data/entity/PlayerEntity.java index 7d89b005..6103d8a6 100644 --- a/src/main/java/game/data/entity/PlayerEntity.java +++ b/src/main/java/game/data/entity/PlayerEntity.java @@ -17,9 +17,12 @@ public class PlayerEntity implements IMovableEntity { private boolean hasRequestedName = false; private String name; + PlayerEntity(UUID uuid) { + this.uuid = uuid; + } + public static PlayerEntity parse(DataTypeProvider provider) { - PlayerEntity ent = new PlayerEntity(); - ent.uuid = provider.readUUID(); + PlayerEntity ent = new PlayerEntity(provider.readUUID()); ent.readPosition(provider); return ent; @@ -86,4 +89,8 @@ public String getName() { } return name; } + + public UUID getUUID() { + return uuid; + } } diff --git a/src/main/java/packets/DataTypeProvider.java b/src/main/java/packets/DataTypeProvider.java index 24a411dc..2a5cd7d0 100644 --- a/src/main/java/packets/DataTypeProvider.java +++ b/src/main/java/packets/DataTypeProvider.java @@ -9,6 +9,7 @@ import game.data.coordinates.CoordinateDouble3D; import packets.version.DataTypeProvider_1_13; import packets.version.DataTypeProvider_1_14; +import packets.version.DataTypeProvider_1_20_2; import se.llbit.nbt.NamedTag; import se.llbit.nbt.SpecificTag; @@ -37,6 +38,7 @@ public DataTypeProvider(byte[] finalFullPacket) { public static DataTypeProvider ofPacket(byte[] finalFullPacket) { return Config.versionReporter().select(DataTypeProvider.class, + Option.of(Version.V1_20_2, () -> new DataTypeProvider_1_20_2(finalFullPacket)), Option.of(Version.V1_14, () -> new DataTypeProvider_1_14(finalFullPacket)), Option.of(Version.V1_13, () -> new DataTypeProvider_1_13(finalFullPacket)), Option.of(Version.ANY, () -> new DataTypeProvider(finalFullPacket)) @@ -223,7 +225,7 @@ public double readDouble() { public UUID readUUID() { return new UUID(readLong(), readLong()); } - + public UUID readOptUUID() { if (readBoolean()) { return readUUID(); diff --git a/src/main/java/packets/builder/PacketBuilder.java b/src/main/java/packets/builder/PacketBuilder.java index 53e31292..c7ba2c83 100644 --- a/src/main/java/packets/builder/PacketBuilder.java +++ b/src/main/java/packets/builder/PacketBuilder.java @@ -199,6 +199,7 @@ public void writeBoolean(boolean val) { /** * Writes an NBT tag. We need to wrap this in a NamedTag, as the named tag is not written itself. + * TODO: update on 1.20.2 */ public void writeNbt(SpecificTag nbt) { try { diff --git a/src/main/java/packets/handler/ClientBoundGamePacketHandler.java b/src/main/java/packets/handler/ClientBoundGamePacketHandler.java index 74542ab9..3474e6ae 100644 --- a/src/main/java/packets/handler/ClientBoundGamePacketHandler.java +++ b/src/main/java/packets/handler/ClientBoundGamePacketHandler.java @@ -13,12 +13,7 @@ import game.data.entity.EntityRegistry; import game.data.entity.MobEntity; import game.data.entity.ObjectEntity; -import packets.handler.version.ClientBoundGamePacketHandler_1_14; -import packets.handler.version.ClientBoundGamePacketHandler_1_15; -import packets.handler.version.ClientBoundGamePacketHandler_1_16; -import packets.handler.version.ClientBoundGamePacketHandler_1_17; -import packets.handler.version.ClientBoundGamePacketHandler_1_18; -import packets.handler.version.ClientBoundGamePacketHandler_1_19; +import packets.handler.version.*; import packets.handler.plugins.PluginChannelHandler; import proxy.ConnectionManager; import se.llbit.nbt.SpecificTag; @@ -184,6 +179,7 @@ public ClientBoundGamePacketHandler(ConnectionManager connectionManager) { public static PacketHandler of(ConnectionManager connectionManager) { return Config.versionReporter().select(PacketHandler.class, + Option.of(Version.V1_20_2, () -> new ClientBoundGamePacketHandler_1_20_2(connectionManager)), Option.of(Version.V1_19, () -> new ClientBoundGamePacketHandler_1_19(connectionManager)), Option.of(Version.V1_18, () -> new ClientBoundGamePacketHandler_1_18(connectionManager)), Option.of(Version.V1_17, () -> new ClientBoundGamePacketHandler_1_17(connectionManager)), diff --git a/src/main/java/packets/handler/version/ClientBoundGamePacketHandler_1_16.java b/src/main/java/packets/handler/version/ClientBoundGamePacketHandler_1_16.java index 828c9ad3..a5426dd3 100644 --- a/src/main/java/packets/handler/version/ClientBoundGamePacketHandler_1_16.java +++ b/src/main/java/packets/handler/version/ClientBoundGamePacketHandler_1_16.java @@ -34,7 +34,7 @@ public ClientBoundGamePacketHandler_1_16(ConnectionManager connectionManager) { String[] dimensionNames = provider.readStringArray(numDimensions); SpecificTag dimensionCodec = provider.readNbtTag(); - WorldManager.getInstance().setDimensionCodec(DimensionCodec.fromNbt(dimensionNames, dimensionCodec)); + WorldManager.getInstance().setDimensionCodec(DimensionCodec.fromNbt(dimensionCodec).setDimensionNames(dimensionNames)); SpecificTag dimensionNbt = provider.readNbtTag(); diff --git a/src/main/java/packets/handler/version/ClientBoundGamePacketHandler_1_19.java b/src/main/java/packets/handler/version/ClientBoundGamePacketHandler_1_19.java index 0a011f93..f264cfae 100644 --- a/src/main/java/packets/handler/version/ClientBoundGamePacketHandler_1_19.java +++ b/src/main/java/packets/handler/version/ClientBoundGamePacketHandler_1_19.java @@ -35,7 +35,7 @@ public ClientBoundGamePacketHandler_1_19(ConnectionManager connectionManager) { String[] dimensionNames = provider.readStringArray(numDimensions); SpecificTag dimensionCodec = provider.readNbtTag(); - WorldManager.getInstance().setDimensionCodec(DimensionCodec.fromNbt(dimensionNames, dimensionCodec)); + WorldManager.getInstance().setDimensionCodec(DimensionCodec.fromNbt(dimensionCodec).setDimensionNames(dimensionNames)); String dimensionType = provider.readString(); // current active dimension diff --git a/src/main/java/packets/handler/version/ClientBoundGamePacketHandler_1_20_2.java b/src/main/java/packets/handler/version/ClientBoundGamePacketHandler_1_20_2.java new file mode 100644 index 00000000..9b521468 --- /dev/null +++ b/src/main/java/packets/handler/version/ClientBoundGamePacketHandler_1_20_2.java @@ -0,0 +1,90 @@ +package packets.handler.version; + +import config.Config; +import game.data.WorldManager; +import game.data.dimension.Dimension; +import game.data.dimension.DimensionCodec; +import game.data.entity.EntityRegistry; +import game.protocol.Protocol; +import packets.builder.PacketBuilder; +import packets.handler.PacketOperator; +import proxy.ConnectionManager; +import se.llbit.nbt.CompoundTag; +import se.llbit.nbt.SpecificTag; + +import java.util.Map; + +import static packets.builder.NetworkType.*; + +public class ClientBoundGamePacketHandler_1_20_2 extends ClientBoundGamePacketHandler_1_19 { + public ClientBoundGamePacketHandler_1_20_2(ConnectionManager connectionManager) { + super(connectionManager); + + Protocol protocol = Config.versionReporter().getProtocol(); + WorldManager worldManager = WorldManager.getInstance(); + EntityRegistry entityRegistry = WorldManager.getInstance().getEntityRegistry(); + + Map operators = getOperators(); + operators.put("Login", provider -> { + PacketBuilder replacement = new PacketBuilder(protocol.clientBound("Login")); + + replacement.copy(provider, INT, BOOL); + + // handle dimension codec + int numDimensions = provider.readVarInt(); + String[] dimensionNames = provider.readStringArray(numDimensions); + WorldManager.getInstance().getDimensionCodec().setDimensionNames(dimensionNames); + + replacement.writeVarInt(numDimensions); + replacement.writeStringArray(dimensionNames); + + replacement.copy(provider, VARINT); + + // extend view distance communicated to the client to the given value + int viewDist = provider.readVarInt(); + replacement.writeVarInt(Math.max(viewDist, Config.getExtendedRenderDistance())); + + replacement.copy(provider, VARINT, BOOL, BOOL, BOOL); + + // current active dimension + String dimensionType = provider.readString(); + String dimensionName = provider.readString(); + Dimension dimension = Dimension.fromString(dimensionName); + dimension.setType(dimensionType); + WorldManager.getInstance().setDimension(dimension); + + replacement.writeString(dimensionType); + replacement.writeString(dimensionName); + + replacement.copy(provider, LONG, BYTE, BYTE, BOOL, BOOL); + + replacement.copyRemainder(provider); + + getConnectionManager().getEncryptionManager().sendImmediately(replacement); + return false; + }); + + operators.put("UpdatePlayerInfo", provider -> { + entityRegistry.updatePlayerAction(provider); + return true; + }); + + operators.put("RegistryData", provider -> { + try { + SpecificTag dimensionCodec = provider.readNbtTag(); + if (!(dimensionCodec instanceof CompoundTag)) { + return true; + } + for (var nbt : ((CompoundTag) dimensionCodec)) { + if (nbt.name.equals("minecraft:dimension_type")) { + worldManager.setDimensionCodec(DimensionCodec.fromNbt(dimensionCodec)); + break; + } + } + } catch (Exception ex) { + ex.printStackTrace(); + } + return true; + }); + } +} \ No newline at end of file diff --git a/src/main/java/packets/version/DataTypeProvider_1_20_2.java b/src/main/java/packets/version/DataTypeProvider_1_20_2.java new file mode 100644 index 00000000..63213527 --- /dev/null +++ b/src/main/java/packets/version/DataTypeProvider_1_20_2.java @@ -0,0 +1,32 @@ +package packets.version; + +import packets.DataTypeProvider; +import se.llbit.nbt.SpecificTag; + +import java.io.DataInputStream; +import java.io.InputStream; + +public class DataTypeProvider_1_20_2 extends DataTypeProvider_1_14 { + public DataTypeProvider_1_20_2(byte[] finalFullPacket) { + super(finalFullPacket); + } + + public SpecificTag readNbtTag() { + try { + return (SpecificTag) SpecificTag.read(readNext(), new DataInputStream(new InputStream() { + @Override + public int read() { + return readNext() & 0xFF; + } + })).unpack(); + } catch (Exception ex) { + ex.printStackTrace(); + return null; + } + } + + @Override + public DataTypeProvider ofLength(int length) { + return new DataTypeProvider_1_20_2(this.readByteArray(length)); + } +} diff --git a/src/main/resources/protocol-versions.json b/src/main/resources/protocol-versions.json index 3349954d..ec0e444b 100644 --- a/src/main/resources/protocol-versions.json +++ b/src/main/resources/protocol-versions.json @@ -399,6 +399,47 @@ "0x31": "UseItemOn", "0x32": "UseItem" } + }, + "764": { + "version": "1.20.2", + "dataVersion": 3578, + "clientBound": { + "0x01": "AddEntity", + "0x05": "RegistryData", + "0x3c": "UpdatePlayerInfo", + "0x07": "BlockEntityData", + "0x09": "BlockUpdate", + "0x12": "ContainerClose", + "0x13": "ContainerSetContent", + "0x1f": "ForgetLevelChunk", + "0x25": "LevelChunkWithLight", + "0x28": "LightUpdate", + "0x29": "Login", + "0x2a": "MapItemData", + "0x2b": "TradeList", + "0x2c": "MoveEntityPos", + "0x2d": "MoveEntityPosRot", + "0x31": "OpenScreen", + "0x40": "RemoveEntities", + "0x43": "Respawn", + "0x45": "SectionBlocksUpdate", + "0x51": "SetChunkCacheRadius", + "0x54": "SetEntityData", + "0x57": "SetEquipment", + "0x67": "SystemChat", + "0x6b": "TeleportEntity" + }, + "serverBound": { + "0x0c": "ContainerClose", + "0x12": "Interact", + "0x16": "MovePlayerPos", + "0x17": "MovePlayerPosRot", + "0x18": "MovePlayerRot", + "0x1a": "MoveVehicle", + "0x2c": "SetCommandBlock", + "0x34": "UseItemOn", + "0x35": "UseItem" + } } } } \ No newline at end of file diff --git a/src/test/java/game/protocol/ProtocolVersionHandlerTest.java b/src/test/java/game/protocol/ProtocolVersionHandlerTest.java index 824200e1..3de7aa43 100644 --- a/src/test/java/game/protocol/ProtocolVersionHandlerTest.java +++ b/src/test/java/game/protocol/ProtocolVersionHandlerTest.java @@ -25,6 +25,7 @@ void bestMatch() { versions.put(758, "1.18"); versions.put(761, "1.19.3"); versions.put(763, "1.20"); + versions.put(764, "1.20.2"); versions.forEach((k, v) -> { assertThat(pvh.getProtocolByProtocolVersion(k).getVersion()).isEqualTo(v); From 4b4570fe4db9c55bbd9a1b2db60bc7133fce824f Mon Sep 17 00:00:00 2001 From: Mirco Kroon <23699979+mircokroon@users.noreply.github.com> Date: Sun, 26 Nov 2023 18:30:34 +0100 Subject: [PATCH 2/4] Added support for network Configuration stage --- src/main/java/game/NetworkMode.java | 18 ++---------- .../game/protocol/ConfigurationProtocol.java | 26 +++++++++++++++++ .../java/game/protocol/HandshakeProtocol.java | 6 ++-- .../java/game/protocol/LoginProtocol.java | 6 ++-- .../java/game/protocol/StatusProtocol.java | 6 ++-- ...ClientBoundConfigurationPacketHandler.java | 21 ++++++++++++++ .../ClientBoundLoginPacketHandler.java | 7 ++++- ...ServerBoundConfigurationPacketHandler.java | 29 +++++++++++++++++++ .../handler/ServerBoundGamePacketHandler.java | 6 ++++ src/main/java/proxy/ConnectionManager.java | 6 ++++ src/main/resources/protocol-versions.json | 1 + 11 files changed, 103 insertions(+), 29 deletions(-) create mode 100644 src/main/java/game/protocol/ConfigurationProtocol.java create mode 100644 src/main/java/packets/handler/ClientBoundConfigurationPacketHandler.java create mode 100644 src/main/java/packets/handler/ServerBoundConfigurationPacketHandler.java diff --git a/src/main/java/game/NetworkMode.java b/src/main/java/game/NetworkMode.java index cd264283..40fcf1da 100644 --- a/src/main/java/game/NetworkMode.java +++ b/src/main/java/game/NetworkMode.java @@ -4,20 +4,6 @@ public enum NetworkMode { HANDSHAKE, STATUS, LOGIN, - GAME; - - @Override - public String toString() { - switch (this) { - case HANDSHAKE: - return "HANDSHAKE"; - case STATUS: - return "STATUS"; - case LOGIN: - return "LOGIN"; - case GAME: - return "GAME"; - } - return ""; - } + GAME, + CONFIGURATION; } diff --git a/src/main/java/game/protocol/ConfigurationProtocol.java b/src/main/java/game/protocol/ConfigurationProtocol.java new file mode 100644 index 00000000..4e119638 --- /dev/null +++ b/src/main/java/game/protocol/ConfigurationProtocol.java @@ -0,0 +1,26 @@ +package game.protocol; + +import java.util.HashMap; +import java.util.Map; + +public class ConfigurationProtocol extends Protocol { + private final Map clientBound; + private final Map serverBound; + + public ConfigurationProtocol() { + clientBound = new HashMap<>(); + serverBound = new HashMap<>(); + + serverBound.put(0x03, "FinishConfiguration"); + } + + @Override + protected String clientBound(int packet) { + return clientBound.getOrDefault(packet, "UNKNOWN"); + } + + @Override + protected String serverBound(int packet) { + return serverBound.getOrDefault(packet, "UNKNOWN"); + } +} diff --git a/src/main/java/game/protocol/HandshakeProtocol.java b/src/main/java/game/protocol/HandshakeProtocol.java index e08165f4..0bc169c6 100644 --- a/src/main/java/game/protocol/HandshakeProtocol.java +++ b/src/main/java/game/protocol/HandshakeProtocol.java @@ -4,12 +4,10 @@ import java.util.Map; public class HandshakeProtocol extends Protocol { - private String version; - private Map clientBound; - private Map serverBound; + private final Map clientBound; + private final Map serverBound; public HandshakeProtocol() { - version = "LOGIN"; clientBound = new HashMap<>(); serverBound = new HashMap<>(); diff --git a/src/main/java/game/protocol/LoginProtocol.java b/src/main/java/game/protocol/LoginProtocol.java index e5899bdf..ccf0e144 100644 --- a/src/main/java/game/protocol/LoginProtocol.java +++ b/src/main/java/game/protocol/LoginProtocol.java @@ -4,12 +4,10 @@ import java.util.Map; public class LoginProtocol extends Protocol { - private String version; - private Map clientBound; - private Map serverBound; + private final Map clientBound; + private final Map serverBound; public LoginProtocol() { - version = "LOGIN"; clientBound = new HashMap<>(); serverBound = new HashMap<>(); diff --git a/src/main/java/game/protocol/StatusProtocol.java b/src/main/java/game/protocol/StatusProtocol.java index b669258e..eae97023 100644 --- a/src/main/java/game/protocol/StatusProtocol.java +++ b/src/main/java/game/protocol/StatusProtocol.java @@ -4,12 +4,10 @@ import java.util.Map; public class StatusProtocol extends Protocol { - private String version; - private Map clientBound; - private Map serverBound; + private final Map clientBound; + private final Map serverBound; public StatusProtocol() { - version = "LOGIN"; clientBound = new HashMap<>(); serverBound = new HashMap<>(); } diff --git a/src/main/java/packets/handler/ClientBoundConfigurationPacketHandler.java b/src/main/java/packets/handler/ClientBoundConfigurationPacketHandler.java new file mode 100644 index 00000000..48af4308 --- /dev/null +++ b/src/main/java/packets/handler/ClientBoundConfigurationPacketHandler.java @@ -0,0 +1,21 @@ +package packets.handler; + +import java.util.HashMap; +import java.util.Map; +import proxy.ConnectionManager; + +public class ClientBoundConfigurationPacketHandler extends PacketHandler { + public ClientBoundConfigurationPacketHandler(ConnectionManager connectionManager) { + super(connectionManager); + } + + @Override + public Map getOperators() { + return new HashMap<>(); + } + + @Override + public boolean isClientBound() { + return true; + } +} diff --git a/src/main/java/packets/handler/ClientBoundLoginPacketHandler.java b/src/main/java/packets/handler/ClientBoundLoginPacketHandler.java index 2454828e..6251c643 100644 --- a/src/main/java/packets/handler/ClientBoundLoginPacketHandler.java +++ b/src/main/java/packets/handler/ClientBoundLoginPacketHandler.java @@ -35,7 +35,12 @@ public ClientBoundLoginPacketHandler(ConnectionManager connectionManager) { String username = provider.readString(); System.out.println("Login success: " + username + " logged in with uuid " + uuid); - getConnectionManager().setMode(NetworkMode.GAME); + + if (Config.versionReporter().isAtLeast(Version.V1_20_2)) { + getConnectionManager().setMode(NetworkMode.CONFIGURATION); + } else { + getConnectionManager().setMode(NetworkMode.GAME); + } return true; }); operations.put("set_compression", provider -> { diff --git a/src/main/java/packets/handler/ServerBoundConfigurationPacketHandler.java b/src/main/java/packets/handler/ServerBoundConfigurationPacketHandler.java new file mode 100644 index 00000000..e28cd5da --- /dev/null +++ b/src/main/java/packets/handler/ServerBoundConfigurationPacketHandler.java @@ -0,0 +1,29 @@ +package packets.handler; + +import game.NetworkMode; +import java.util.HashMap; +import java.util.Map; +import proxy.ConnectionManager; + +public class ServerBoundConfigurationPacketHandler extends PacketHandler { + private HashMap operations = new HashMap<>(); + + public ServerBoundConfigurationPacketHandler(ConnectionManager connectionManager) { + super(connectionManager); + + operations.put("FinishConfiguration", provider -> { + getConnectionManager().setMode(NetworkMode.GAME); + return true; + }); + } + + @Override + public Map getOperators() { + return operations; + } + + @Override + public boolean isClientBound() { + return false; + } +} diff --git a/src/main/java/packets/handler/ServerBoundGamePacketHandler.java b/src/main/java/packets/handler/ServerBoundGamePacketHandler.java index db009495..4d4038e2 100644 --- a/src/main/java/packets/handler/ServerBoundGamePacketHandler.java +++ b/src/main/java/packets/handler/ServerBoundGamePacketHandler.java @@ -1,6 +1,7 @@ package packets.handler; import config.Version; +import game.NetworkMode; import java.util.HashMap; import java.util.Map; @@ -80,6 +81,11 @@ public ServerBoundGamePacketHandler(ConnectionManager connectionManager) { WorldManager.getInstance().getVillagerManager().lastInteractedWith(provider); return true; }); + + operations.put("ConfigurationAcknowledged", provider ->{ + getConnectionManager().setMode(NetworkMode.CONFIGURATION); + return true; + }); } @Override diff --git a/src/main/java/proxy/ConnectionManager.java b/src/main/java/proxy/ConnectionManager.java index 1f6e6fc1..9d9ee8ed 100644 --- a/src/main/java/proxy/ConnectionManager.java +++ b/src/main/java/proxy/ConnectionManager.java @@ -3,6 +3,7 @@ import config.Config; import game.NetworkMode; import game.data.WorldManager; +import game.protocol.ConfigurationProtocol; import game.protocol.HandshakeProtocol; import game.protocol.LoginProtocol; import game.protocol.StatusProtocol; @@ -48,6 +49,11 @@ public void setMode(NetworkMode mode) { serverBoundDataReader.setPacketHandler(new ServerBoundHandshakePacketHandler(this)); clientBoundDataReader.setPacketHandler(new ClientBoundHandshakePacketHandler(this)); break; + case CONFIGURATION: + PacketHandler.setProtocol(new ConfigurationProtocol()); + serverBoundDataReader.setPacketHandler(new ServerBoundConfigurationPacketHandler(this)); + clientBoundDataReader.setPacketHandler(new ClientBoundConfigurationPacketHandler(this)); + break; } } diff --git a/src/main/resources/protocol-versions.json b/src/main/resources/protocol-versions.json index ec0e444b..c47d56c0 100644 --- a/src/main/resources/protocol-versions.json +++ b/src/main/resources/protocol-versions.json @@ -430,6 +430,7 @@ "0x6b": "TeleportEntity" }, "serverBound": { + "0x0b": "ConfigurationAcknowledged", "0x0c": "ContainerClose", "0x12": "Interact", "0x16": "MovePlayerPos", From dbf8a075f9a7ff0f4c012bc4cea6002f5eff54ac Mon Sep 17 00:00:00 2001 From: nnnlog Date: Thu, 8 Feb 2024 16:45:23 +0900 Subject: [PATCH 3/4] Update for 1.20.3 --- src/main/java/config/Version.java | 1 + .../game/data/dimension/DimensionCodec.java | 6 ++- .../game/protocol/ConfigurationProtocol.java | 11 ++++- ...ClientBoundConfigurationPacketHandler.java | 18 +++++++- .../java/packets/handler/PacketHandler.java | 4 +- .../handler/ServerBoundGamePacketHandler.java | 2 + ...oundConfigurationPacketHandler_1_20_2.java | 26 +++++++++++ .../ClientBoundGamePacketHandler_1_20_2.java | 19 -------- src/main/java/proxy/ConnectionManager.java | 2 +- src/main/resources/protocol-versions.json | 44 ++++++++++++++++++- 10 files changed, 105 insertions(+), 28 deletions(-) create mode 100644 src/main/java/packets/handler/version/ClientBoundConfigurationPacketHandler_1_20_2.java diff --git a/src/main/java/config/Version.java b/src/main/java/config/Version.java index 5f5eec4d..fcea1f89 100644 --- a/src/main/java/config/Version.java +++ b/src/main/java/config/Version.java @@ -13,6 +13,7 @@ public enum Version { V1_19_3(761, 3218), V1_20(763, 3463), V1_20_2(764, 3578), + V1_20_3(765, 3698), ANY(0, 0); public final int dataVersion; diff --git a/src/main/java/game/data/dimension/DimensionCodec.java b/src/main/java/game/data/dimension/DimensionCodec.java index a38da1bf..5c7ea402 100644 --- a/src/main/java/game/data/dimension/DimensionCodec.java +++ b/src/main/java/game/data/dimension/DimensionCodec.java @@ -4,7 +4,7 @@ import game.data.chunk.palette.StateProvider; import se.llbit.nbt.*; -import java.io.*; +import java.io.IOException; import java.nio.file.Path; import java.util.Collection; import java.util.HashMap; @@ -16,6 +16,7 @@ */ public class DimensionCodec { public static final Gson GSON; + static { /* * To convert the properties to JSON, we need to register adapters so that GSON knows how to turn our NBT object @@ -56,6 +57,7 @@ public class DimensionCodec { private final Map dimensionTypesByHash; private final Map dimensionTypesByName; private final Map biomes; + private DimensionCodec() { this.dimensions = new HashMap<>(); this.dimensionTypesByHash = new HashMap<>(); @@ -103,7 +105,7 @@ private void readDimensionTypes(ListTag dimensionList) { String[] parts = identifier.split(":"); String namespace = parts[0]; String name = parts[1]; - + DimensionType type = new DimensionType(namespace, name, d); this.dimensionTypesByHash.put(type.getSignature(), type); this.dimensionTypesByName.put(type.getName(), type); diff --git a/src/main/java/game/protocol/ConfigurationProtocol.java b/src/main/java/game/protocol/ConfigurationProtocol.java index 4e119638..2bbfa1dd 100644 --- a/src/main/java/game/protocol/ConfigurationProtocol.java +++ b/src/main/java/game/protocol/ConfigurationProtocol.java @@ -1,5 +1,8 @@ package game.protocol; +import config.Config; +import config.Version; + import java.util.HashMap; import java.util.Map; @@ -11,7 +14,13 @@ public ConfigurationProtocol() { clientBound = new HashMap<>(); serverBound = new HashMap<>(); - serverBound.put(0x03, "FinishConfiguration"); + if (Config.versionReporter().isAtLeast(Version.V1_20_2)) { + serverBound.put(0x02, "FinishConfiguration"); + + clientBound.put(0x05, "RegistryData"); + } else { + serverBound.put(0x03, "FinishConfiguration"); + } } @Override diff --git a/src/main/java/packets/handler/ClientBoundConfigurationPacketHandler.java b/src/main/java/packets/handler/ClientBoundConfigurationPacketHandler.java index 48af4308..2166ae5c 100644 --- a/src/main/java/packets/handler/ClientBoundConfigurationPacketHandler.java +++ b/src/main/java/packets/handler/ClientBoundConfigurationPacketHandler.java @@ -1,17 +1,31 @@ package packets.handler; +import config.Config; +import config.Option; +import config.Version; +import packets.handler.version.ClientBoundConfigurationPacketHandler_1_20_2; +import proxy.ConnectionManager; + import java.util.HashMap; import java.util.Map; -import proxy.ConnectionManager; public class ClientBoundConfigurationPacketHandler extends PacketHandler { + private final HashMap operations = new HashMap<>(); + public ClientBoundConfigurationPacketHandler(ConnectionManager connectionManager) { super(connectionManager); } + public static PacketHandler of(ConnectionManager connectionManager) { + return Config.versionReporter().select(PacketHandler.class, + Option.of(Version.V1_20_2, () -> new ClientBoundConfigurationPacketHandler_1_20_2(connectionManager)), + Option.of(Version.ANY, () -> new ClientBoundConfigurationPacketHandler(connectionManager)) + ); + } + @Override public Map getOperators() { - return new HashMap<>(); + return operations; } @Override diff --git a/src/main/java/packets/handler/PacketHandler.java b/src/main/java/packets/handler/PacketHandler.java index 000bf264..faf1b645 100644 --- a/src/main/java/packets/handler/PacketHandler.java +++ b/src/main/java/packets/handler/PacketHandler.java @@ -6,8 +6,8 @@ import packets.DataTypeProvider; import proxy.ConnectionManager; -import java.util.Map; import javax.naming.SizeLimitExceededException; +import java.util.Map; /** * Family of classes to handle incoming packets and perform appropriate actions based on the packet type and contents. @@ -34,6 +34,7 @@ protected ConnectionManager getConnectionManager() { /** * Build the given packet, will generate a type provider to parse the contents of the packages to real values. Will * determine if the packet is to be forwarded using its return value. + * * @param size the size of the packet to build * @return true if the packet should be forwarded, otherwise false. */ @@ -58,6 +59,7 @@ public final boolean handle(int size) { } public abstract Map getOperators(); + public abstract boolean isClientBound(); public void setReader(DataProvider reader) { diff --git a/src/main/java/packets/handler/ServerBoundGamePacketHandler.java b/src/main/java/packets/handler/ServerBoundGamePacketHandler.java index 4d4038e2..c941c951 100644 --- a/src/main/java/packets/handler/ServerBoundGamePacketHandler.java +++ b/src/main/java/packets/handler/ServerBoundGamePacketHandler.java @@ -28,6 +28,8 @@ public ServerBoundGamePacketHandler(ConnectionManager connectionManager) { PacketOperator updatePlayerRotation = provider -> { double yaw = provider.readFloat() % 360; + provider.readFloat(); // pitch + provider.readBoolean(); // on ground WorldManager.getInstance().setPlayerRotation(yaw); return true; }; diff --git a/src/main/java/packets/handler/version/ClientBoundConfigurationPacketHandler_1_20_2.java b/src/main/java/packets/handler/version/ClientBoundConfigurationPacketHandler_1_20_2.java new file mode 100644 index 00000000..9bb313bc --- /dev/null +++ b/src/main/java/packets/handler/version/ClientBoundConfigurationPacketHandler_1_20_2.java @@ -0,0 +1,26 @@ +package packets.handler.version; + +import game.data.WorldManager; +import game.data.dimension.DimensionCodec; +import packets.handler.ClientBoundConfigurationPacketHandler; +import packets.handler.PacketOperator; +import proxy.ConnectionManager; +import se.llbit.nbt.SpecificTag; + +import java.util.Map; + +public class ClientBoundConfigurationPacketHandler_1_20_2 extends ClientBoundConfigurationPacketHandler { + public ClientBoundConfigurationPacketHandler_1_20_2(ConnectionManager connectionManager) { + super(connectionManager); + + Map operators = getOperators(); + WorldManager worldManager = WorldManager.getInstance(); + + operators.put("RegistryData", provider -> { + SpecificTag registryData = provider.readNbtTag(); + worldManager.setDimensionCodec(DimensionCodec.fromNbt(registryData)); + + return true; + }); + } +} diff --git a/src/main/java/packets/handler/version/ClientBoundGamePacketHandler_1_20_2.java b/src/main/java/packets/handler/version/ClientBoundGamePacketHandler_1_20_2.java index 9b521468..4599deb3 100644 --- a/src/main/java/packets/handler/version/ClientBoundGamePacketHandler_1_20_2.java +++ b/src/main/java/packets/handler/version/ClientBoundGamePacketHandler_1_20_2.java @@ -21,7 +21,6 @@ public ClientBoundGamePacketHandler_1_20_2(ConnectionManager connectionManager) super(connectionManager); Protocol protocol = Config.versionReporter().getProtocol(); - WorldManager worldManager = WorldManager.getInstance(); EntityRegistry entityRegistry = WorldManager.getInstance().getEntityRegistry(); Map operators = getOperators(); @@ -68,23 +67,5 @@ public ClientBoundGamePacketHandler_1_20_2(ConnectionManager connectionManager) entityRegistry.updatePlayerAction(provider); return true; }); - - operators.put("RegistryData", provider -> { - try { - SpecificTag dimensionCodec = provider.readNbtTag(); - if (!(dimensionCodec instanceof CompoundTag)) { - return true; - } - for (var nbt : ((CompoundTag) dimensionCodec)) { - if (nbt.name.equals("minecraft:dimension_type")) { - worldManager.setDimensionCodec(DimensionCodec.fromNbt(dimensionCodec)); - break; - } - } - } catch (Exception ex) { - ex.printStackTrace(); - } - return true; - }); } } \ No newline at end of file diff --git a/src/main/java/proxy/ConnectionManager.java b/src/main/java/proxy/ConnectionManager.java index 9d9ee8ed..9cfe5af7 100644 --- a/src/main/java/proxy/ConnectionManager.java +++ b/src/main/java/proxy/ConnectionManager.java @@ -52,7 +52,7 @@ public void setMode(NetworkMode mode) { case CONFIGURATION: PacketHandler.setProtocol(new ConfigurationProtocol()); serverBoundDataReader.setPacketHandler(new ServerBoundConfigurationPacketHandler(this)); - clientBoundDataReader.setPacketHandler(new ClientBoundConfigurationPacketHandler(this)); + clientBoundDataReader.setPacketHandler(ClientBoundConfigurationPacketHandler.of(this)); break; } } diff --git a/src/main/resources/protocol-versions.json b/src/main/resources/protocol-versions.json index c47d56c0..31e9d17e 100644 --- a/src/main/resources/protocol-versions.json +++ b/src/main/resources/protocol-versions.json @@ -405,8 +405,6 @@ "dataVersion": 3578, "clientBound": { "0x01": "AddEntity", - "0x05": "RegistryData", - "0x3c": "UpdatePlayerInfo", "0x07": "BlockEntityData", "0x09": "BlockUpdate", "0x12": "ContainerClose", @@ -420,6 +418,7 @@ "0x2c": "MoveEntityPos", "0x2d": "MoveEntityPosRot", "0x31": "OpenScreen", + "0x3c": "UpdatePlayerInfo", "0x40": "RemoveEntities", "0x43": "Respawn", "0x45": "SectionBlocksUpdate", @@ -441,6 +440,47 @@ "0x34": "UseItemOn", "0x35": "UseItem" } + }, + "765": { + "version": "1.20.3", + "dataVersion": 3698, + "clientBound": { + "0x01": "AddEntity", + "0x07": "BlockEntityData", + "0x09": "BlockUpdate", + "0x12": "ContainerClose", + "0x13": "ContainerSetContent", + "0x1f": "ForgetLevelChunk", + "0x25": "LevelChunkWithLight", + "0x28": "LightUpdate", + "0x29": "Login", + "0x2a": "MapItemData", + "0x2b": "TradeList", + "0x2c": "MoveEntityPos", + "0x2d": "MoveEntityPosRot", + "0x31": "OpenScreen", + "0x3c": "UpdatePlayerInfo", + "0x40": "RemoveEntities", + "0x45": "Respawn", + "0x47": "SectionBlocksUpdate", + "0x53": "SetChunkCacheRadius", + "0x56": "SetEntityData", + "0x59": "SetEquipment", + "0x69": "SystemChat", + "0x6d": "TeleportEntity" + }, + "serverBound": { + "0x0b": "ConfigurationAcknowledged", + "0x0c": "ContainerClose", + "0x12": "Interact", + "0x16": "MovePlayerPos", + "0x18": "MovePlayerPosRot", + "0x19": "MovePlayerRot", + "0x1b": "MoveVehicle", + "0x2d": "SetCommandBlock", + "0x35": "UseItemOn", + "0x36": "UseItem" + } } } } \ No newline at end of file From 0f9cedc2fd556d70201b47488578a7e9bffc55d4 Mon Sep 17 00:00:00 2001 From: Mirco Kroon <23699979+mircokroon@users.noreply.github.com> Date: Thu, 8 Feb 2024 23:10:22 +0100 Subject: [PATCH 4/4] Removed unneeded class --- .../java/game/data/chunk/ChunkFactory.java | 1 - .../game/data/chunk/version/Chunk_1_20_2.java | 51 ------------------- 2 files changed, 52 deletions(-) delete mode 100644 src/main/java/game/data/chunk/version/Chunk_1_20_2.java diff --git a/src/main/java/game/data/chunk/ChunkFactory.java b/src/main/java/game/data/chunk/ChunkFactory.java index a821b526..fea95978 100644 --- a/src/main/java/game/data/chunk/ChunkFactory.java +++ b/src/main/java/game/data/chunk/ChunkFactory.java @@ -45,7 +45,6 @@ public void clear() { */ private static Chunk getVersionedChunk(int dataVersion, CoordinateDim2D chunkPos) { return VersionReporter.select(dataVersion, Chunk.class, - Option.of(Version.V1_20_2, () -> new Chunk_1_20_2(chunkPos, dataVersion)), Option.of(Version.V1_20, () -> new Chunk_1_20(chunkPos, dataVersion)), Option.of(Version.V1_18, () -> new Chunk_1_18(chunkPos, dataVersion)), Option.of(Version.V1_17, () -> new Chunk_1_17(chunkPos, dataVersion)), diff --git a/src/main/java/game/data/chunk/version/Chunk_1_20_2.java b/src/main/java/game/data/chunk/version/Chunk_1_20_2.java deleted file mode 100644 index 6c3c4319..00000000 --- a/src/main/java/game/data/chunk/version/Chunk_1_20_2.java +++ /dev/null @@ -1,51 +0,0 @@ -package game.data.chunk.version; - -import game.data.chunk.palette.Palette; -import game.data.chunk.palette.PaletteType; -import game.data.coordinates.CoordinateDim2D; -import packets.DataTypeProvider; - -public class Chunk_1_20_2 extends Chunk_1_20 { - - - public Chunk_1_20_2(CoordinateDim2D location, int version) { - super(location, version); - } - - /** - * Read a chunk column for 1.20.2 - */ - public void readChunkColumn(DataTypeProvider dataProvider) { - // Loop through section Y values, starting from the lowest section that has blocks inside it. - for (int sectionY = getMinBlockSection(); sectionY <= getMaxBlockSection() && dataProvider.hasNext(); sectionY++) { - ChunkSection_1_18 section = (ChunkSection_1_18) getChunkSection(sectionY); - - dataProvider.readShort(); - Palette blockPalette = Palette.readPalette(dataProvider, PaletteType.BLOCKS); - - if (section == null) { - section = (ChunkSection_1_18) createNewChunkSection((byte) (sectionY & 0xFF), blockPalette); - } else { - section.setBlockPalette(blockPalette); - } - - section.setBlocks(dataProvider.readLongArray(dataProvider.readVarInt())); - - Palette biomePalette = Palette.readPalette(dataProvider, PaletteType.BIOMES); - section.setBiomePalette(biomePalette); - - // check how many longs we expect, if there's more discard the rest - int longsExpectedBiomes = ChunkSection_1_18.longsRequiredBiomes(biomePalette.getBitsPerBlock()); - section.setBiomes(dataProvider.readLongArray(dataProvider.readVarInt())); - - // May replace an existing section or a null one - setChunkSection(sectionY, section); - - // servers don't (always?) include containers in the list of block_entities. We need to know that these block - // entities exist, otherwise we'll end up not writing block entity data for them - if (containsBlockEntities(blockPalette)) { - findBlockEntities(section, sectionY); - } - } - } -}