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>
This commit is contained in:
Kas-tle 2023-11-28 20:33:07 -08:00 committed by GitHub
parent 3292718e69
commit 0f50a3cbe6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 42 additions and 25 deletions

View File

@ -1,5 +1,7 @@
plugins { plugins {
`java-library` `java-library`
// Ensure AP works in eclipse (no effect on other IDEs)
`eclipse`
id("geyser.build-logic") id("geyser.build-logic")
id("io.freefair.lombok") version "6.3.0" apply false id("io.freefair.lombok") version "6.3.0" apply false
} }
@ -35,4 +37,4 @@ subprojects {
in platforms -> plugins.apply("geyser.platform-conventions") in platforms -> plugins.apply("geyser.platform-conventions")
else -> plugins.apply("geyser.base-conventions") else -> plugins.apply("geyser.base-conventions")
} }
} }

View File

@ -30,18 +30,20 @@ import org.cloudburstmc.protocol.common.util.Preconditions;
public class GeyserChunkSection { public class GeyserChunkSection {
// Temporary reversion to v8 as it reduces the frequnecy of https://github.com/GeyserMC/Geyser/issues/4240 // As of at least 1.19.80
// This does not fully resolve the issue so a better solution is still needed private static final int CHUNK_SECTION_VERSION = 9;
private static final int CHUNK_SECTION_VERSION = 8;
private final BlockStorage[] storage; 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) { public GeyserChunkSection(int airBlockId, int subChunkIndex) {
this(new BlockStorage[]{new BlockStorage(airBlockId), new BlockStorage(airBlockId)}); this(new BlockStorage[]{new BlockStorage(airBlockId), new BlockStorage(airBlockId)}, subChunkIndex);
} }
public GeyserChunkSection(BlockStorage[] storage) { public GeyserChunkSection(BlockStorage[] storage, int subChunkIndex) {
this.storage = storage; this.storage = storage;
this.subChunkIndex = subChunkIndex;
} }
public int getFullBlock(int x, int y, int z, int layer) { 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(CHUNK_SECTION_VERSION);
buffer.writeByte(this.storage.length); buffer.writeByte(this.storage.length);
// Required for chunk version 9+ // Required for chunk version 9+
buffer.writeByte(this.subChunkIndex);
for (BlockStorage blockStorage : this.storage) { for (BlockStorage blockStorage : this.storage) {
blockStorage.writeToNetwork(buffer); blockStorage.writeToNetwork(buffer);
} }
@ -86,12 +89,12 @@ public class GeyserChunkSection {
return true; return true;
} }
public GeyserChunkSection copy() { public GeyserChunkSection copy(int subChunkIndex) {
BlockStorage[] storage = new BlockStorage[this.storage.length]; BlockStorage[] storage = new BlockStorage[this.storage.length];
for (int i = 0; i < storage.length; i++) { for (int i = 0; i < storage.length; i++) {
storage[i] = this.storage[i].copy(); 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) { public static int blockPosition(int x, int y, int z) {

View File

@ -78,7 +78,8 @@ import java.util.BitSet;
import java.util.List; import java.util.List;
import java.util.Map; 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; import static org.geysermc.geyser.util.ChunkUtils.indexYZXtoXZY;
@Translator(packet = ClientboundLevelChunkWithLightPacket.class) @Translator(packet = ClientboundLevelChunkWithLightPacket.class)
@ -127,6 +128,7 @@ public class JavaLevelChunkWithLightTranslator extends PacketTranslator<Clientbo
boolean thisExtendedCollisionNextSection = false; boolean thisExtendedCollisionNextSection = false;
int bedrockSectionY = sectionY + (yOffset - (bedrockDimension.minY() >> 4)); int bedrockSectionY = sectionY + (yOffset - (bedrockDimension.minY() >> 4));
int subChunkIndex = sectionY + yOffset;
if (bedrockSectionY < 0 || maxBedrockSectionY < bedrockSectionY) { if (bedrockSectionY < 0 || maxBedrockSectionY < bedrockSectionY) {
// Ignore this chunk section since it goes outside the bounds accepted by the Bedrock client // Ignore this chunk section since it goes outside the bounds accepted by the Bedrock client
if (useExtendedCollisions) { if (useExtendedCollisions) {
@ -154,7 +156,7 @@ public class JavaLevelChunkWithLightTranslator extends PacketTranslator<Clientbo
} }
BlockStorage[] layers = new BlockStorage[]{ layer0 }; BlockStorage[] layers = new BlockStorage[]{ layer0 };
sections[bedrockSectionY] = new GeyserChunkSection(layers); sections[bedrockSectionY] = new GeyserChunkSection(layers, subChunkIndex);
} }
EXTENDED_COLLISIONS_STORAGE.get().clear(); EXTENDED_COLLISIONS_STORAGE.get().clear();
extendedCollisionNextSection = false; extendedCollisionNextSection = false;
@ -167,7 +169,7 @@ public class JavaLevelChunkWithLightTranslator extends PacketTranslator<Clientbo
if (javaPalette instanceof GlobalPalette) { if (javaPalette instanceof GlobalPalette) {
// As this is the global palette, simply iterate through the whole chunk section once // As this is the global palette, simply iterate through the whole chunk section once
GeyserChunkSection section = new GeyserChunkSection(session.getBlockMappings().getBedrockAir().getRuntimeId()); GeyserChunkSection section = new GeyserChunkSection(session.getBlockMappings().getBedrockAir().getRuntimeId(), subChunkIndex);
for (int yzx = 0; yzx < BlockStorage.SIZE; yzx++) { for (int yzx = 0; yzx < BlockStorage.SIZE; yzx++) {
int javaId = javaData.get(yzx); int javaId = javaData.get(yzx);
int bedrockId = session.getBlockMappings().getBedrockBlockId(javaId); int bedrockId = session.getBlockMappings().getBedrockBlockId(javaId);
@ -217,9 +219,9 @@ public class JavaLevelChunkWithLightTranslator extends PacketTranslator<Clientbo
if (BlockRegistries.WATERLOGGED.get().get(javaId)) { if (BlockRegistries.WATERLOGGED.get().get(javaId)) {
BlockStorage waterlogged = new BlockStorage(SingletonBitArray.INSTANCE, IntLists.singleton(session.getBlockMappings().getBedrockWater().getRuntimeId())); BlockStorage waterlogged = new BlockStorage(SingletonBitArray.INSTANCE, IntLists.singleton(session.getBlockMappings().getBedrockWater().getRuntimeId()));
sections[bedrockSectionY] = new GeyserChunkSection(new BlockStorage[] {blockStorage, waterlogged}); sections[bedrockSectionY] = new GeyserChunkSection(new BlockStorage[] {blockStorage, waterlogged}, subChunkIndex);
} else { } else {
sections[bedrockSectionY] = new GeyserChunkSection(new BlockStorage[] {blockStorage}); sections[bedrockSectionY] = new GeyserChunkSection(new BlockStorage[] {blockStorage}, subChunkIndex);
} }
if (useExtendedCollisions) { if (useExtendedCollisions) {
EXTENDED_COLLISIONS_STORAGE.get().clear(); EXTENDED_COLLISIONS_STORAGE.get().clear();
@ -378,7 +380,7 @@ public class JavaLevelChunkWithLightTranslator extends PacketTranslator<Clientbo
layers = new BlockStorage[]{ layer0, new BlockStorage(BitArrayVersion.V1.createArray(BlockStorage.SIZE, layer1Data), layer1Palette) }; layers = new BlockStorage[]{ layer0, new BlockStorage(BitArrayVersion.V1.createArray(BlockStorage.SIZE, layer1Data), layer1Palette) };
} }
sections[bedrockSectionY] = new GeyserChunkSection(layers); sections[bedrockSectionY] = new GeyserChunkSection(layers, subChunkIndex);
extendedCollisionNextSection = thisExtendedCollisionNextSection; extendedCollisionNextSection = thisExtendedCollisionNextSection;
} }
@ -426,13 +428,14 @@ public class JavaLevelChunkWithLightTranslator extends PacketTranslator<Clientbo
BlockDefinition blockDefinition = SkullBlockEntityTranslator.translateSkull(session, tag, Vector3i.from(x + chunkBlockX, y, z + chunkBlockZ), blockState); BlockDefinition blockDefinition = SkullBlockEntityTranslator.translateSkull(session, tag, Vector3i.from(x + chunkBlockX, y, z + chunkBlockZ), blockState);
if (blockDefinition != null) { if (blockDefinition != null) {
int bedrockSectionY = (y >> 4) - (bedrockDimension.minY() >> 4); int bedrockSectionY = (y >> 4) - (bedrockDimension.minY() >> 4);
int subChunkIndex = (y >> 4) + (bedrockDimension.minY() >> 4);
if (0 <= bedrockSectionY && bedrockSectionY < maxBedrockSectionY) { if (0 <= bedrockSectionY && bedrockSectionY < maxBedrockSectionY) {
// Custom skull is in a section accepted by Bedrock // Custom skull is in a section accepted by Bedrock
GeyserChunkSection bedrockSection = sections[bedrockSectionY]; GeyserChunkSection bedrockSection = sections[bedrockSectionY];
IntList palette = bedrockSection.getBlockStorageArray()[0].getPalette(); IntList palette = bedrockSection.getBlockStorageArray()[0].getPalette();
if (palette instanceof IntImmutableList || palette instanceof IntLists.Singleton) { if (palette instanceof IntImmutableList || palette instanceof IntLists.Singleton) {
// TODO there has to be a better way to expand the palette .-. // TODO there has to be a better way to expand the palette .-.
bedrockSection = bedrockSection.copy(); bedrockSection = bedrockSection.copy(subChunkIndex);
sections[bedrockSectionY] = bedrockSection; sections[bedrockSectionY] = bedrockSection;
} }
bedrockSection.setFullBlock(x, y & 0xF, z, 0, blockDefinition.getRuntimeId()); bedrockSection.setFullBlock(x, y & 0xF, z, 0, blockDefinition.getRuntimeId());
@ -458,7 +461,7 @@ public class JavaLevelChunkWithLightTranslator extends PacketTranslator<Clientbo
if (section != null) { if (section != null) {
size += section.estimateNetworkSize(); size += section.estimateNetworkSize();
} else { } else {
size += SERIALIZED_CHUNK_DATA.length; size += EMPTY_CHUNK_SECTION_SIZE;
} }
} }
size += ChunkUtils.EMPTY_BIOME_DATA.length * biomeCount; size += ChunkUtils.EMPTY_BIOME_DATA.length * biomeCount;
@ -472,7 +475,8 @@ public class JavaLevelChunkWithLightTranslator extends PacketTranslator<Clientbo
if (section != null) { if (section != null) {
section.writeToNetwork(byteBuf); section.writeToNetwork(byteBuf);
} else { } else {
byteBuf.writeBytes(SERIALIZED_CHUNK_DATA); int subChunkIndex = (i + (bedrockDimension.minY() >> 4));
new GeyserChunkSection(EMPTY_BLOCK_STORAGE, subChunkIndex).writeToNetwork(byteBuf);
} }
} }

View File

@ -54,19 +54,27 @@ import static org.geysermc.geyser.level.block.BlockStateValues.JAVA_AIR_ID;
@UtilityClass @UtilityClass
public class ChunkUtils { public class ChunkUtils {
/**
* An empty subchunk.
*/
public static final byte[] SERIALIZED_CHUNK_DATA;
public static final byte[] EMPTY_BIOME_DATA; public static final byte[] EMPTY_BIOME_DATA;
public static final BlockStorage[] EMPTY_BLOCK_STORAGE;
public static final int EMPTY_CHUNK_SECTION_SIZE;
static { static {
EMPTY_BLOCK_STORAGE = new BlockStorage[0];
ByteBuf byteBuf = Unpooled.buffer(); ByteBuf byteBuf = Unpooled.buffer();
try { try {
new GeyserChunkSection(new BlockStorage[0]) new GeyserChunkSection(EMPTY_BLOCK_STORAGE, 0)
.writeToNetwork(byteBuf); .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 { } finally {
byteBuf.release(); byteBuf.release();
} }