From 2fe88acd12f5e7b29c15c23f1f21b9add1aa68ae Mon Sep 17 00:00:00 2001 From: Bixilon Date: Mon, 29 Jun 2020 23:40:50 +0200 Subject: [PATCH] chunk parsing 1.9 --- .../game/datatypes/blocks/Blocks.java | 2 +- .../minosoft/game/datatypes/world/World.java | 6 ++ .../minosoft/protocol/network/Network.java | 2 +- .../clientbound/play/PacketChunkData.java | 21 +++++-- .../protocol/protocol/PacketHandler.java | 2 + .../de/bixilon/minosoft/util/ChunkUtil.java | 59 ++++++++++++++----- 6 files changed, 70 insertions(+), 22 deletions(-) diff --git a/src/main/java/de/bixilon/minosoft/game/datatypes/blocks/Blocks.java b/src/main/java/de/bixilon/minosoft/game/datatypes/blocks/Blocks.java index 942b088df..e1bdaa86d 100644 --- a/src/main/java/de/bixilon/minosoft/game/datatypes/blocks/Blocks.java +++ b/src/main/java/de/bixilon/minosoft/game/datatypes/blocks/Blocks.java @@ -131,6 +131,6 @@ public enum Blocks { } public int getData() { - return id; + return data; } } diff --git a/src/main/java/de/bixilon/minosoft/game/datatypes/world/World.java b/src/main/java/de/bixilon/minosoft/game/datatypes/world/World.java index 9cdde3624..5c77f9d78 100644 --- a/src/main/java/de/bixilon/minosoft/game/datatypes/world/World.java +++ b/src/main/java/de/bixilon/minosoft/game/datatypes/world/World.java @@ -141,4 +141,10 @@ public class World { public CompoundTag getBlockEntityData(BlockPosition position) { return blockEntityMeta.get(position); } + + public void setBlockEntityData(HashMap blockEntities) { + for (Map.Entry entrySet : blockEntities.entrySet()) { + blockEntityMeta.put(entrySet.getKey(), entrySet.getValue()); + } + } } diff --git a/src/main/java/de/bixilon/minosoft/protocol/network/Network.java b/src/main/java/de/bixilon/minosoft/protocol/network/Network.java index 402864422..c8c5bd320 100644 --- a/src/main/java/de/bixilon/minosoft/protocol/network/Network.java +++ b/src/main/java/de/bixilon/minosoft/protocol/network/Network.java @@ -212,7 +212,7 @@ public class Network { boolean success = packet.read(inPacketBuffer); if (inPacketBuffer.getBytesLeft() > 0 || !success) { // warn not all data used - Log.warn(String.format("[IN] Could not parse packet %s completely (used=%d, available=%d, total=%d)", ((p != null) ? p.name() : "null"), inPacketBuffer.getPosition(), inPacketBuffer.getBytesLeft(), inPacketBuffer.getLength())); + Log.warn(String.format("[IN] Could not parse packet %s (used=%d, available=%d, total=%d, success=%s)", ((p != null) ? p.name() : "null"), inPacketBuffer.getPosition(), inPacketBuffer.getBytesLeft(), inPacketBuffer.getLength(), success)); continue; } diff --git a/src/main/java/de/bixilon/minosoft/protocol/packets/clientbound/play/PacketChunkData.java b/src/main/java/de/bixilon/minosoft/protocol/packets/clientbound/play/PacketChunkData.java index 2909f5ee3..01602bba5 100644 --- a/src/main/java/de/bixilon/minosoft/protocol/packets/clientbound/play/PacketChunkData.java +++ b/src/main/java/de/bixilon/minosoft/protocol/packets/clientbound/play/PacketChunkData.java @@ -13,9 +13,11 @@ package de.bixilon.minosoft.protocol.packets.clientbound.play; +import de.bixilon.minosoft.game.datatypes.world.BlockPosition; import de.bixilon.minosoft.game.datatypes.world.Chunk; import de.bixilon.minosoft.game.datatypes.world.ChunkLocation; import de.bixilon.minosoft.logging.Log; +import de.bixilon.minosoft.nbt.tag.CompoundTag; import de.bixilon.minosoft.protocol.packets.ClientboundPacket; import de.bixilon.minosoft.protocol.protocol.InByteBuffer; import de.bixilon.minosoft.protocol.protocol.InPacketBuffer; @@ -23,10 +25,13 @@ import de.bixilon.minosoft.protocol.protocol.PacketHandler; import de.bixilon.minosoft.util.ChunkUtil; import de.bixilon.minosoft.util.Util; +import java.util.HashMap; + public class PacketChunkData implements ClientboundPacket { ChunkLocation location; Chunk chunk; + HashMap blockEntities = new HashMap<>(); @Override public boolean read(InPacketBuffer buffer) { @@ -55,16 +60,16 @@ public class PacketChunkData implements ClientboundPacket { case VERSION_1_9_4: { this.location = new ChunkLocation(buffer.readInteger(), buffer.readInteger()); boolean groundUpContinuous = buffer.readBoolean(); - short sectionBitMask = buffer.readShort(); + short sectionBitMask = (short) buffer.readVarInt(); int size = buffer.readVarInt(); chunk = ChunkUtil.readChunkPacket(buffer, sectionBitMask, (short) 0, groundUpContinuous, true); - int blockEntities = buffer.readVarInt(); - for (int i = 0; i < blockEntities; i++) { - buffer.readNBT(); - //ToDo + int blockEntitiesCount = buffer.readVarInt(); + for (int i = 0; i < blockEntitiesCount; i++) { + CompoundTag tag = buffer.readNBT(); + blockEntities.put(new BlockPosition(tag.getIntTag("x").getValue(), (short) tag.getIntTag("y").getValue(), tag.getIntTag("z").getValue()), tag); } - return false; + return true; } } @@ -85,6 +90,10 @@ public class PacketChunkData implements ClientboundPacket { return chunk; } + public HashMap getBlockEntities() { + return blockEntities; + } + @Override public void handle(PacketHandler h) { h.handle(this); diff --git a/src/main/java/de/bixilon/minosoft/protocol/protocol/PacketHandler.java b/src/main/java/de/bixilon/minosoft/protocol/protocol/PacketHandler.java index 0f5170b66..7a99e282a 100644 --- a/src/main/java/de/bixilon/minosoft/protocol/protocol/PacketHandler.java +++ b/src/main/java/de/bixilon/minosoft/protocol/protocol/PacketHandler.java @@ -300,6 +300,8 @@ public class PacketHandler { public void handle(PacketChunkData pkg) { connection.getPlayer().getWorld().setChunk(pkg.getLocation(), pkg.getChunk()); + connection.getPlayer().getWorld().setBlockEntityData(pkg.getBlockEntities()); + } public void handle(PacketEntityEffect pkg) { diff --git a/src/main/java/de/bixilon/minosoft/util/ChunkUtil.java b/src/main/java/de/bixilon/minosoft/util/ChunkUtil.java index eef629034..709f95be3 100644 --- a/src/main/java/de/bixilon/minosoft/util/ChunkUtil.java +++ b/src/main/java/de/bixilon/minosoft/util/ChunkUtil.java @@ -135,8 +135,7 @@ public class ChunkUtil { return new Chunk(nibbleMap); } case VERSION_1_9_4: { - byte sections = BitByte.getBitCount(sectionBitMask); - + // really big thanks to: https://wiki.vg/index.php?title=Chunk_Format&oldid=13712 HashMap nibbleMap = new HashMap<>(); for (byte c = 0; c < 16; c++) { // max sections per chunks in chunk column if (!BitByte.isBitSet(sectionBitMask, c)) { @@ -144,34 +143,66 @@ public class ChunkUtil { } byte bitsPerBlock = buffer.readByte(); - int[] palette = new int[buffer.readVarInt()]; - for (int i = 0; i < palette.length; i++) { - palette[i] = buffer.readVarInt(); + if (bitsPerBlock < 4) { + bitsPerBlock = 4; + } else if (bitsPerBlock > 8) { + bitsPerBlock = 13; } + boolean usePalette = (bitsPerBlock <= 8); + + int[] palette = null; + if (usePalette) { + palette = new int[buffer.readVarInt()]; + for (int i = 0; i < palette.length; i++) { + palette[i] = buffer.readVarInt(); + } + } else { + buffer.readVarInt(); + } + int individualValueMask = ((1 << bitsPerBlock) - 1); + long[] data = buffer.readLongs(buffer.readVarInt()); HashMap blockMap = new HashMap<>(); - int blocks = 0; -/* for (int nibbleY = 0; nibbleY < 16; nibbleY++) { for (int nibbleZ = 0; nibbleZ < 16; nibbleZ++) { for (int nibbleX = 0; nibbleX < 16; nibbleX++) { - Blocks block = Blocks.byId(blockData[arrayPos] >>> 4, blockData[arrayPos] & 0xF); + + + int blockNumber = (((nibbleY * 16) + nibbleZ) * 16) + nibbleX; + int startLong = (blockNumber * bitsPerBlock) / 64; + int startOffset = (blockNumber * bitsPerBlock) % 64; + int endLong = ((blockNumber + 1) * bitsPerBlock - 1) / 64; + + + int blockId; + if (startLong == endLong) { + blockId = (int) (data[startLong] >>> startOffset); + } else { + int endOffset = 64 - startOffset; + blockId = (int) (data[startLong] >>> startOffset | data[endLong] << endOffset); + } + blockId &= individualValueMask; + + if (usePalette) { + // data should always be within the palette length + // If you're reading a power of 2 minus one (15, 31, 63, 127, etc...) that's out of bounds, + // you're probably reading light data instead + blockId = palette[blockId]; + } + + Blocks block = Blocks.byId(blockId >>> 4, blockId & 0xF); if (block == Blocks.AIR) { - arrayPos++; continue; } blockMap.put(new ChunkNibbleLocation(nibbleX, nibbleY, nibbleZ), block); - arrayPos++; } } } - */ - - byte[] light = buffer.readBytes(blocks / 2); + byte[] light = buffer.readBytes(2048); if (containsSkyLight) { - byte[] skyLight = buffer.readBytes(blocks / 2); + byte[] skyLight = buffer.readBytes(2048); } nibbleMap.put(c, new ChunkNibble(blockMap));