From 0f50a3cbe604f6c4ab8d6004c6dd09d7a071879c Mon Sep 17 00:00:00 2001 From: Kas-tle <26531652+Kas-tle@users.noreply.github.com> Date: Tue, 28 Nov 2023 20:33:07 -0800 Subject: [PATCH] Re-implement subchunk v9 with proper index (#4287) * Re-implement subchunk v9 with proper index Signed-off-by: Joshua Castle <26531652+Kas-tle@users.noreply.github.com> * typo in comment --------- Signed-off-by: Joshua Castle <26531652+Kas-tle@users.noreply.github.com> --- build.gradle.kts | 4 +++- .../level/chunk/GeyserChunkSection.java | 19 +++++++++------- .../JavaLevelChunkWithLightTranslator.java | 22 +++++++++++-------- .../org/geysermc/geyser/util/ChunkUtils.java | 22 +++++++++++++------ 4 files changed, 42 insertions(+), 25 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 9eb8a6ed0..d7360b701 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,5 +1,7 @@ plugins { `java-library` + // Ensure AP works in eclipse (no effect on other IDEs) + `eclipse` id("geyser.build-logic") id("io.freefair.lombok") version "6.3.0" apply false } @@ -35,4 +37,4 @@ subprojects { in platforms -> plugins.apply("geyser.platform-conventions") else -> plugins.apply("geyser.base-conventions") } -} \ No newline at end of file +} diff --git a/core/src/main/java/org/geysermc/geyser/level/chunk/GeyserChunkSection.java b/core/src/main/java/org/geysermc/geyser/level/chunk/GeyserChunkSection.java index f3e6b8399..8a3534a8e 100644 --- a/core/src/main/java/org/geysermc/geyser/level/chunk/GeyserChunkSection.java +++ b/core/src/main/java/org/geysermc/geyser/level/chunk/GeyserChunkSection.java @@ -30,18 +30,20 @@ import org.cloudburstmc.protocol.common.util.Preconditions; public class GeyserChunkSection { - // Temporary reversion to v8 as it reduces the frequnecy of https://github.com/GeyserMC/Geyser/issues/4240 - // This does not fully resolve the issue so a better solution is still needed - private static final int CHUNK_SECTION_VERSION = 8; + // As of at least 1.19.80 + private static final int CHUNK_SECTION_VERSION = 9; private final BlockStorage[] storage; + // Counts up from 00 for y >= 0 and down from FF for y < 0 + private final int subChunkIndex; - public GeyserChunkSection(int airBlockId) { - this(new BlockStorage[]{new BlockStorage(airBlockId), new BlockStorage(airBlockId)}); + public GeyserChunkSection(int airBlockId, int subChunkIndex) { + this(new BlockStorage[]{new BlockStorage(airBlockId), new BlockStorage(airBlockId)}, subChunkIndex); } - public GeyserChunkSection(BlockStorage[] storage) { + public GeyserChunkSection(BlockStorage[] storage, int subChunkIndex) { this.storage = storage; + this.subChunkIndex = subChunkIndex; } public int getFullBlock(int x, int y, int z, int layer) { @@ -60,6 +62,7 @@ public class GeyserChunkSection { buffer.writeByte(CHUNK_SECTION_VERSION); buffer.writeByte(this.storage.length); // Required for chunk version 9+ + buffer.writeByte(this.subChunkIndex); for (BlockStorage blockStorage : this.storage) { blockStorage.writeToNetwork(buffer); } @@ -86,12 +89,12 @@ public class GeyserChunkSection { return true; } - public GeyserChunkSection copy() { + public GeyserChunkSection copy(int subChunkIndex) { BlockStorage[] storage = new BlockStorage[this.storage.length]; for (int i = 0; i < storage.length; i++) { storage[i] = this.storage[i].copy(); } - return new GeyserChunkSection(storage); + return new GeyserChunkSection(storage, subChunkIndex); } public static int blockPosition(int x, int y, int z) { diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaLevelChunkWithLightTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaLevelChunkWithLightTranslator.java index 85eec40e0..9a8681542 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaLevelChunkWithLightTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaLevelChunkWithLightTranslator.java @@ -78,7 +78,8 @@ import java.util.BitSet; import java.util.List; import java.util.Map; -import static org.geysermc.geyser.util.ChunkUtils.SERIALIZED_CHUNK_DATA; +import static org.geysermc.geyser.util.ChunkUtils.EMPTY_BLOCK_STORAGE; +import static org.geysermc.geyser.util.ChunkUtils.EMPTY_CHUNK_SECTION_SIZE; import static org.geysermc.geyser.util.ChunkUtils.indexYZXtoXZY; @Translator(packet = ClientboundLevelChunkWithLightPacket.class) @@ -127,6 +128,7 @@ public class JavaLevelChunkWithLightTranslator extends PacketTranslator> 4)); + int subChunkIndex = sectionY + yOffset; if (bedrockSectionY < 0 || maxBedrockSectionY < bedrockSectionY) { // Ignore this chunk section since it goes outside the bounds accepted by the Bedrock client if (useExtendedCollisions) { @@ -154,7 +156,7 @@ public class JavaLevelChunkWithLightTranslator extends PacketTranslator> 4) - (bedrockDimension.minY() >> 4); + int subChunkIndex = (y >> 4) + (bedrockDimension.minY() >> 4); if (0 <= bedrockSectionY && bedrockSectionY < maxBedrockSectionY) { // Custom skull is in a section accepted by Bedrock GeyserChunkSection bedrockSection = sections[bedrockSectionY]; IntList palette = bedrockSection.getBlockStorageArray()[0].getPalette(); if (palette instanceof IntImmutableList || palette instanceof IntLists.Singleton) { // TODO there has to be a better way to expand the palette .-. - bedrockSection = bedrockSection.copy(); + bedrockSection = bedrockSection.copy(subChunkIndex); sections[bedrockSectionY] = bedrockSection; } bedrockSection.setFullBlock(x, y & 0xF, z, 0, blockDefinition.getRuntimeId()); @@ -458,7 +461,7 @@ public class JavaLevelChunkWithLightTranslator extends PacketTranslator> 4)); + new GeyserChunkSection(EMPTY_BLOCK_STORAGE, subChunkIndex).writeToNetwork(byteBuf); } } diff --git a/core/src/main/java/org/geysermc/geyser/util/ChunkUtils.java b/core/src/main/java/org/geysermc/geyser/util/ChunkUtils.java index cded234f9..114a7b6de 100644 --- a/core/src/main/java/org/geysermc/geyser/util/ChunkUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/ChunkUtils.java @@ -54,19 +54,27 @@ import static org.geysermc.geyser.level.block.BlockStateValues.JAVA_AIR_ID; @UtilityClass public class ChunkUtils { - /** - * An empty subchunk. - */ - public static final byte[] SERIALIZED_CHUNK_DATA; + public static final byte[] EMPTY_BIOME_DATA; + public static final BlockStorage[] EMPTY_BLOCK_STORAGE; + + public static final int EMPTY_CHUNK_SECTION_SIZE; + static { + EMPTY_BLOCK_STORAGE = new BlockStorage[0]; + ByteBuf byteBuf = Unpooled.buffer(); try { - new GeyserChunkSection(new BlockStorage[0]) + new GeyserChunkSection(EMPTY_BLOCK_STORAGE, 0) .writeToNetwork(byteBuf); - SERIALIZED_CHUNK_DATA = new byte[byteBuf.readableBytes()]; - byteBuf.readBytes(SERIALIZED_CHUNK_DATA); + + byte[] emptyChunkData = new byte[byteBuf.readableBytes()]; + byteBuf.readBytes(emptyChunkData); + + EMPTY_CHUNK_SECTION_SIZE = emptyChunkData.length; + + emptyChunkData = null; } finally { byteBuf.release(); }