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 7d7d5284a..1e6adf5cc 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
@@ -497,6 +497,11 @@ public class Blocks {
blockList.add(block);
}
+ // set nullBlock
+ if (block.getIdentifier().equals("air")) {
+ nullBlock = block;
+ }
+
int blockId = getBlockId(statesJSON, version);
checkAndCrashIfBlockIsIn(blockId, identifierName, versionMapping, version);
versionMapping.put(blockId, block);
diff --git a/src/main/java/de/bixilon/minosoft/game/datatypes/world/palette/DirectPalette.java b/src/main/java/de/bixilon/minosoft/game/datatypes/world/palette/DirectPalette.java
new file mode 100644
index 000000000..a71237cbe
--- /dev/null
+++ b/src/main/java/de/bixilon/minosoft/game/datatypes/world/palette/DirectPalette.java
@@ -0,0 +1,49 @@
+/*
+ * Codename Minosoft
+ * Copyright (C) 2020 Moritz Zwerger
+ *
+ * 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 .
+ *
+ * This software is not affiliated with Mojang AB, the original developer of Minecraft.
+ */
+
+package de.bixilon.minosoft.game.datatypes.world.palette;
+
+import de.bixilon.minosoft.game.datatypes.blocks.Block;
+import de.bixilon.minosoft.game.datatypes.blocks.Blocks;
+import de.bixilon.minosoft.protocol.protocol.InByteBuffer;
+import de.bixilon.minosoft.protocol.protocol.ProtocolVersion;
+
+public class DirectPalette implements Palette {
+ ProtocolVersion version;
+
+ @Override
+ public Block byId(int id) {
+ return Blocks.getBlock(id, version);
+ }
+
+ @Override
+ public byte getBitsPerBlock() {
+ switch (version) {
+ case VERSION_1_9_4:
+ case VERSION_1_10:
+ case VERSION_1_11_2:
+ case VERSION_1_12_2:
+ return 13;
+ case VERSION_1_13_2:
+ case VERSION_1_14_4:
+ return 14;
+ }
+ return -1;
+ }
+
+ @Override
+ public void read(InByteBuffer buffer) {
+ this.version = buffer.getVersion();
+ buffer.readVarInt();
+ }
+}
diff --git a/src/main/java/de/bixilon/minosoft/game/datatypes/world/palette/IndirectPalette.java b/src/main/java/de/bixilon/minosoft/game/datatypes/world/palette/IndirectPalette.java
new file mode 100644
index 000000000..373ab9033
--- /dev/null
+++ b/src/main/java/de/bixilon/minosoft/game/datatypes/world/palette/IndirectPalette.java
@@ -0,0 +1,65 @@
+/*
+ * Codename Minosoft
+ * Copyright (C) 2020 Moritz Zwerger
+ *
+ * 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 .
+ *
+ * This software is not affiliated with Mojang AB, the original developer of Minecraft.
+ */
+
+package de.bixilon.minosoft.game.datatypes.world.palette;
+
+import com.google.common.collect.HashBiMap;
+import de.bixilon.minosoft.game.datatypes.blocks.Block;
+import de.bixilon.minosoft.game.datatypes.blocks.Blocks;
+import de.bixilon.minosoft.protocol.protocol.InByteBuffer;
+import de.bixilon.minosoft.protocol.protocol.ProtocolVersion;
+
+public class IndirectPalette implements Palette {
+ ProtocolVersion version;
+ HashBiMap map = HashBiMap.create();
+ byte bitsPerBlock;
+
+ public IndirectPalette(byte bitsPerBlock) {
+ this.bitsPerBlock = bitsPerBlock;
+ }
+
+ @Override
+ public Block byId(int id) {
+ Block block;
+ if (map.containsKey(id)) {
+ block = Blocks.getBlock(map.get(id), version);
+ } else {
+ block = Blocks.getBlock(id, version);
+ }
+ return block;
+ }
+
+ @Override
+ public byte getBitsPerBlock() {
+ return bitsPerBlock;
+ }
+
+ @Override
+ public void read(InByteBuffer buffer) {
+ this.version = buffer.getVersion();
+ switch (version) {
+ case VERSION_1_9_4:
+ case VERSION_1_10:
+ case VERSION_1_11_2:
+ case VERSION_1_12_2:
+ case VERSION_1_13_2:
+ case VERSION_1_14_4: {
+ int paletteLength = buffer.readVarInt();
+ for (int i = 0; i < paletteLength; i++) {
+ map.put(i, buffer.readVarInt());
+ }
+ break;
+ }
+ }
+ }
+}
diff --git a/src/main/java/de/bixilon/minosoft/game/datatypes/world/palette/Palette.java b/src/main/java/de/bixilon/minosoft/game/datatypes/world/palette/Palette.java
new file mode 100644
index 000000000..090be6a77
--- /dev/null
+++ b/src/main/java/de/bixilon/minosoft/game/datatypes/world/palette/Palette.java
@@ -0,0 +1,34 @@
+/*
+ * Codename Minosoft
+ * Copyright (C) 2020 Moritz Zwerger
+ *
+ * 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 .
+ *
+ * This software is not affiliated with Mojang AB, the original developer of Minecraft.
+ */
+
+package de.bixilon.minosoft.game.datatypes.world.palette;
+
+import de.bixilon.minosoft.game.datatypes.blocks.Block;
+import de.bixilon.minosoft.protocol.protocol.InByteBuffer;
+
+public interface Palette {
+ static Palette choosePalette(byte bitsPerBlock) {
+ if (bitsPerBlock <= 4) {
+ return new IndirectPalette((byte) 4);
+ } else if (bitsPerBlock <= 8) {
+ return new IndirectPalette(bitsPerBlock);
+ }
+ return new DirectPalette();
+ }
+
+ Block byId(int id);
+
+ byte getBitsPerBlock();
+
+ void read(InByteBuffer buffer);
+}
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 4ea902946..4c04fb9c2 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
@@ -23,6 +23,7 @@ import de.bixilon.minosoft.protocol.packets.ClientboundPacket;
import de.bixilon.minosoft.protocol.protocol.InByteBuffer;
import de.bixilon.minosoft.protocol.protocol.InPacketBuffer;
import de.bixilon.minosoft.protocol.protocol.PacketHandler;
+import de.bixilon.minosoft.protocol.protocol.ProtocolVersion;
import de.bixilon.minosoft.util.ChunkUtil;
import de.bixilon.minosoft.util.Util;
@@ -31,6 +32,7 @@ import java.util.HashMap;
public class PacketChunkData implements ClientboundPacket {
ChunkLocation location;
Chunk chunk;
+ CompoundTag heightMap;
HashMap blockEntities = new HashMap<>();
@@ -70,10 +72,14 @@ public class PacketChunkData implements ClientboundPacket {
case VERSION_1_10:
case VERSION_1_11_2:
case VERSION_1_12_2:
- case VERSION_1_13_2: {
+ case VERSION_1_13_2:
+ case VERSION_1_14_4: {
this.location = new ChunkLocation(buffer.readInt(), buffer.readInt());
boolean groundUpContinuous = buffer.readBoolean();
short sectionBitMask = (short) buffer.readVarInt();
+ if (buffer.getVersion().getVersionNumber() >= ProtocolVersion.VERSION_1_14_4.getVersionNumber()) {
+ heightMap = buffer.readNBT();
+ }
int size = buffer.readVarInt();
int lastPos = buffer.getPosition();
@@ -109,6 +115,10 @@ public class PacketChunkData implements ClientboundPacket {
return blockEntities;
}
+ public CompoundTag getHeightMap() {
+ return heightMap;
+ }
+
@Override
public void handle(PacketHandler h) {
h.handle(this);
diff --git a/src/main/java/de/bixilon/minosoft/protocol/packets/clientbound/play/PacketTags.java b/src/main/java/de/bixilon/minosoft/protocol/packets/clientbound/play/PacketTags.java
index 061d1f7c4..163296521 100644
--- a/src/main/java/de/bixilon/minosoft/protocol/packets/clientbound/play/PacketTags.java
+++ b/src/main/java/de/bixilon/minosoft/protocol/packets/clientbound/play/PacketTags.java
@@ -48,6 +48,7 @@ public class PacketTags implements ClientboundPacket {
Tag[] ret = new Tag[buffer.readVarInt()];
switch (buffer.getVersion()) {
case VERSION_1_13_2:
+ case VERSION_1_14_4:
for (int i = 0; i < ret.length; i++) {
ret[i] = new Tag(buffer.readString(), buffer.readVarIntArray(buffer.readVarInt()));
}
diff --git a/src/main/java/de/bixilon/minosoft/util/ChunkUtil.java b/src/main/java/de/bixilon/minosoft/util/ChunkUtil.java
index d7965dd74..c01df3760 100644
--- a/src/main/java/de/bixilon/minosoft/util/ChunkUtil.java
+++ b/src/main/java/de/bixilon/minosoft/util/ChunkUtil.java
@@ -18,6 +18,7 @@ import de.bixilon.minosoft.game.datatypes.blocks.Blocks;
import de.bixilon.minosoft.game.datatypes.world.Chunk;
import de.bixilon.minosoft.game.datatypes.world.ChunkNibble;
import de.bixilon.minosoft.game.datatypes.world.ChunkNibbleLocation;
+import de.bixilon.minosoft.game.datatypes.world.palette.Palette;
import de.bixilon.minosoft.protocol.protocol.InByteBuffer;
import de.bixilon.minosoft.protocol.protocol.ProtocolVersion;
@@ -148,32 +149,20 @@ public class ChunkUtil {
case VERSION_1_10:
case VERSION_1_11_2:
case VERSION_1_12_2:
- case VERSION_1_13_2: {
+ case VERSION_1_13_2:
+ case VERSION_1_14_4: {
// 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)) {
continue;
}
-
- byte bitsPerBlock = buffer.readByte();
- if (bitsPerBlock < 4) {
- bitsPerBlock = 4;
- } else if (bitsPerBlock > 8) {
- bitsPerBlock = (byte) ((buffer.getVersion().getVersionNumber() >= ProtocolVersion.VERSION_1_13_2.getVersionNumber()) ? 14 : 13);
+ if (buffer.getVersion().getVersionNumber() >= ProtocolVersion.VERSION_1_14_4.getVersionNumber()) {
+ buffer.readShort(); // block count
}
- 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);
+ Palette palette = Palette.choosePalette(buffer.readByte());
+ palette.read(buffer);
+ int individualValueMask = ((1 << palette.getBitsPerBlock()) - 1);
long[] data = buffer.readLongs(buffer.readVarInt());
@@ -184,9 +173,9 @@ public class ChunkUtil {
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 startLong = (blockNumber * palette.getBitsPerBlock()) / 64;
+ int startOffset = (blockNumber * palette.getBitsPerBlock()) % 64;
+ int endLong = ((blockNumber + 1) * palette.getBitsPerBlock() - 1) / 64;
int blockId;
@@ -198,19 +187,7 @@ public class ChunkUtil {
}
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];
- }
- Block block;
- if (buffer.getVersion().getVersionNumber() >= ProtocolVersion.VERSION_1_13_2.getVersionNumber()) {
- // no meta data anymore
- block = Blocks.getBlock(blockId, buffer.getVersion());
- } else {
- block = Blocks.getBlockByLegacy(blockId >>> 4, blockId & 0xF);
- }
+ Block block = palette.byId(blockId);
if (block == Blocks.nullBlock) {
continue;
}
@@ -219,9 +196,11 @@ public class ChunkUtil {
}
}
- byte[] light = buffer.readBytes(2048);
- if (containsSkyLight) {
- byte[] skyLight = buffer.readBytes(2048);
+ if (buffer.getVersion().getVersionNumber() < ProtocolVersion.VERSION_1_14_4.getVersionNumber()) {
+ byte[] light = buffer.readBytes(2048);
+ if (containsSkyLight) {
+ byte[] skyLight = buffer.readBytes(2048);
+ }
}
nibbleMap.put(c, new ChunkNibble(blockMap));