diff --git a/connector/pom.xml b/connector/pom.xml index 4c8391766..ae81ffab5 100644 --- a/connector/pom.xml +++ b/connector/pom.xml @@ -130,7 +130,7 @@ com.github.GeyserMC MCProtocolLib - 6e318f5 + e427237 compile diff --git a/connector/src/main/java/org/geysermc/connector/network/session/UpstreamSession.java b/connector/src/main/java/org/geysermc/connector/network/session/UpstreamSession.java index edefd2f23..11df3139c 100644 --- a/connector/src/main/java/org/geysermc/connector/network/session/UpstreamSession.java +++ b/connector/src/main/java/org/geysermc/connector/network/session/UpstreamSession.java @@ -41,7 +41,6 @@ public class UpstreamSession { private boolean initialized = false; public void sendPacket(@NonNull BedrockPacket packet) { - System.out.println(packet); if (!isClosed()) { session.sendPacket(packet); } diff --git a/connector/src/main/java/org/geysermc/connector/network/session/cache/ChunkCache.java b/connector/src/main/java/org/geysermc/connector/network/session/cache/ChunkCache.java index 72d271a79..f5bc250c8 100644 --- a/connector/src/main/java/org/geysermc/connector/network/session/cache/ChunkCache.java +++ b/connector/src/main/java/org/geysermc/connector/network/session/cache/ChunkCache.java @@ -74,19 +74,19 @@ public class ChunkCache { return; } - if (y < minY || (y >> 4) > column.getChunks().length - 1) { + if (y < minY || ((y - minY) >> 4) > column.getChunks().length - 1) { // Y likely goes above or below the height limit of this world return; } - Chunk chunk = column.getChunks()[(y >> 4) - getChunkMinY()]; + Chunk chunk = column.getChunks()[(y - minY) >> 4]; if (chunk == null) { if (block != BlockStateValues.JAVA_AIR_ID) { // A previously empty chunk, which is no longer empty as a block has been added to it chunk = new Chunk(); // Fixes the chunk assuming that all blocks is the `block` variable we are updating. /shrug chunk.getPalette().stateToId(BlockStateValues.JAVA_AIR_ID); - column.getChunks()[(y >> 4) - getChunkMinY()] = chunk; + column.getChunks()[(y - minY) >> 4] = chunk; } else { // Nothing to update return; @@ -106,12 +106,12 @@ public class ChunkCache { return BlockStateValues.JAVA_AIR_ID; } - if (y < minY || (y >> 4) > column.getChunks().length - 1) { + if (y < minY || ((y - minY) >> 4) > column.getChunks().length - 1) { // Y likely goes above or below the height limit of this world return BlockStateValues.JAVA_AIR_ID; } - Chunk chunk = column.getChunks()[(y >> 4) - getChunkMinY()]; + Chunk chunk = column.getChunks()[(y - minY) >> 4]; if (chunk != null) { return chunk.get(x & 0xF, y & 0xF, z & 0xF); } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaChunkDataTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaChunkDataTranslator.java index 8c6720863..0b2b1ce5f 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaChunkDataTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaChunkDataTranslator.java @@ -37,14 +37,16 @@ import io.netty.buffer.ByteBufAllocator; import io.netty.buffer.ByteBufOutputStream; import org.geysermc.connector.GeyserConnector; import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.utils.BiomeUtils; import org.geysermc.connector.network.translators.PacketTranslator; import org.geysermc.connector.network.translators.Translator; import org.geysermc.connector.network.translators.world.chunk.ChunkSection; +import org.geysermc.connector.utils.BiomeUtils; import org.geysermc.connector.utils.ChunkUtils; @Translator(packet = ServerChunkDataPacket.class) public class JavaChunkDataTranslator extends PacketTranslator { + // Caves and cliffs supports 3D biomes by implementing a very similar palette system to blocks + private static final boolean NEW_BIOME_WRITE = GeyserConnector.getInstance().getConfig().isExtendedWorldHeight(); @Override public void translate(ServerChunkDataPacket packet, GeyserSession session) { @@ -79,7 +81,7 @@ public class JavaChunkDataTranslator extends PacketTranslator> 2) & 63) << 4 | ((z >> 2) & 3) << 2 | ((x >> 2) & 3)]; if (biomeId == 0) { biomeId = 42; // Ocean @@ -58,6 +78,6 @@ public class BiomeUtils { } else if (biomeId >= 170) { // Nether biomes. Dunno why it's like this :microjang: biomeId += 8; } - return (byte) biomeId; + return biomeId; } } diff --git a/connector/src/main/java/org/geysermc/connector/utils/ChunkUtils.java b/connector/src/main/java/org/geysermc/connector/utils/ChunkUtils.java index 77f0d2c90..912d0e8ee 100644 --- a/connector/src/main/java/org/geysermc/connector/utils/ChunkUtils.java +++ b/connector/src/main/java/org/geysermc/connector/utils/ChunkUtils.java @@ -41,6 +41,8 @@ import com.nukkitx.nbt.NbtMap; import com.nukkitx.protocol.bedrock.packet.LevelChunkPacket; import com.nukkitx.protocol.bedrock.packet.NetworkChunkPublisherUpdatePacket; import com.nukkitx.protocol.bedrock.packet.UpdateBlockPacket; +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; import it.unimi.dsi.fastutil.ints.IntArrayList; import it.unimi.dsi.fastutil.ints.IntList; import lombok.Data; @@ -71,11 +73,41 @@ public class ChunkUtils { /** * The minimum height Bedrock Edition will accept. */ - private static final int MINIMUM_ACCEPTED_HEIGHT = GeyserConnector.getInstance().getConfig().isExtendedWorldHeight() ? -64 : 0; + private static final int MINIMUM_ACCEPTED_HEIGHT = 0; + private static final int MINIMUM_ACCEPTED_HEIGHT_OVERWORLD = GeyserConnector.getInstance().getConfig().isExtendedWorldHeight() ? -64 : MINIMUM_ACCEPTED_HEIGHT; /** * The maximum chunk height Bedrock Edition will accept, from the lowest point to the highest. */ - private static final int MAXIMUM_ACCEPTED_HEIGHT = GeyserConnector.getInstance().getConfig().isExtendedWorldHeight() ? 380 : 256; + private static final int MAXIMUM_ACCEPTED_HEIGHT = 256; + private static final int MAXIMUM_ACCEPTED_HEIGHT_OVERWORLD = GeyserConnector.getInstance().getConfig().isExtendedWorldHeight() ? 384 : MAXIMUM_ACCEPTED_HEIGHT; + + private static final byte[] EMPTY_CHUNK_DATA; + public static final byte[] EMPTY_BIOME_DATA; + + static { + ByteBuf byteBuf = Unpooled.buffer(); + try { + BlockStorage blockStorage = new BlockStorage(0); + blockStorage.writeToNetwork(byteBuf); + + EMPTY_BIOME_DATA = new byte[byteBuf.readableBytes()]; + byteBuf.readBytes(EMPTY_BIOME_DATA); + } finally { + byteBuf.release(); + } + + byteBuf = Unpooled.buffer(); + try { + for (int i = 0; i < 32; i++) { + byteBuf.writeBytes(EMPTY_BIOME_DATA); + } + + EMPTY_CHUNK_DATA = new byte[byteBuf.readableBytes()]; + byteBuf.readBytes(EMPTY_CHUNK_DATA); + } finally { + byteBuf.release(); + } + } private static int indexYZXtoXZY(int yzx) { return (yzx >> 8) | (yzx & 0x0F0) | ((yzx & 0x00F) << 8); @@ -91,8 +123,10 @@ public class ChunkUtils { BitSet waterloggedPaletteIds = new BitSet(); BitSet pistonOrFlowerPaletteIds = new BitSet(); + boolean overworld = session.getDimension().equals(DimensionUtils.OVERWORLD); + for (int sectionY = 0; sectionY < javaSections.length; sectionY++) { - if (yOffset < MINIMUM_ACCEPTED_HEIGHT && sectionY < -yOffset) { + if (yOffset < ((overworld ? MINIMUM_ACCEPTED_HEIGHT_OVERWORLD : MINIMUM_ACCEPTED_HEIGHT) >> 4) && sectionY < -yOffset) { // Ignore this chunk since it goes below the accepted height limit continue; } @@ -128,7 +162,7 @@ public class ChunkUtils { )); } } - sections[sectionY + yOffset] = section; + sections[sectionY + (yOffset - ((overworld ? MINIMUM_ACCEPTED_HEIGHT_OVERWORLD : MINIMUM_ACCEPTED_HEIGHT) >> 4))] = section; continue; } @@ -201,7 +235,7 @@ public class ChunkUtils { layers = new BlockStorage[]{ layer0, new BlockStorage(BitArrayVersion.V1.createArray(BlockStorage.SIZE, layer1Data), layer1Palette) }; } - sections[sectionY + yOffset] = new ChunkSection(layers); + sections[sectionY + (yOffset - ((overworld ? MINIMUM_ACCEPTED_HEIGHT_OVERWORLD : MINIMUM_ACCEPTED_HEIGHT) >> 4))] = new ChunkSection(layers); } CompoundTag[] blockEntities = column.getTileEntities(); @@ -383,7 +417,7 @@ public class ChunkUtils { data.setChunkX(chunkX + x); data.setChunkZ(chunkZ + z); data.setSubChunksLength(0); - data.setData(new byte[0]); + data.setData(EMPTY_CHUNK_DATA); data.setCachingEnabled(false); session.sendUpstreamPacket(data);