From d3dfcb2a92249ac1b74529a68d513f8127cea406 Mon Sep 17 00:00:00 2001 From: Moritz Zwerger Date: Sat, 8 Feb 2025 21:06:05 +0100 Subject: [PATCH] chunk reading: check early if data is empty Now it does not allocate chunk data when the section is truly empty (servers sometimes send the opposite and then it turns out that they are empty) --- .../palette/PalettedContainerReader.kt | 14 +++++++- .../palette/data/EmptyPaletteData.kt | 1 + .../container/palette/data/PaletteData.kt | 1 + .../palette/data/array/ArrayPaletteData.kt | 33 ++++++++++++++----- .../packets/s2c/play/block/chunk/ChunkUtil.kt | 8 ----- 5 files changed, 39 insertions(+), 18 deletions(-) diff --git a/src/main/java/de/bixilon/minosoft/data/world/container/palette/PalettedContainerReader.kt b/src/main/java/de/bixilon/minosoft/data/world/container/palette/PalettedContainerReader.kt index 0ed3ce407..7e91f29c4 100644 --- a/src/main/java/de/bixilon/minosoft/data/world/container/palette/PalettedContainerReader.kt +++ b/src/main/java/de/bixilon/minosoft/data/world/container/palette/PalettedContainerReader.kt @@ -15,6 +15,7 @@ package de.bixilon.minosoft.data.world.container.palette import de.bixilon.minosoft.data.registries.registries.registry.AbstractRegistry import de.bixilon.minosoft.data.world.container.palette.data.PaletteData +import de.bixilon.minosoft.data.world.container.palette.palettes.BlockStatePaletteFactory import de.bixilon.minosoft.data.world.container.palette.palettes.PaletteFactory import de.bixilon.minosoft.protocol.protocol.buffers.play.PlayInByteBuffer @@ -41,16 +42,27 @@ object PalettedContainerReader { val data = PaletteData.create(buffer.versionId, palette.bits, factory.containerSize) try { data.read(buffer) + if (factory == BlockStatePaletteFactory && data.isEmpty) { // id 0 is air + return null + } val container = PalettedContainer(factory.edgeBits, palette, data) if (container.isEmpty) return null val unpacked = container.unpack() - if (unpacked.isEmpty()) return null + if (unpacked.isAllNull()) return null return unpacked } finally { data.free() } } + + fun Array.isAllNull(): Boolean { + for (entry in this) { + if (entry == null) continue + return false + } + return true + } } diff --git a/src/main/java/de/bixilon/minosoft/data/world/container/palette/data/EmptyPaletteData.kt b/src/main/java/de/bixilon/minosoft/data/world/container/palette/data/EmptyPaletteData.kt index a1d0c1599..6e02df236 100644 --- a/src/main/java/de/bixilon/minosoft/data/world/container/palette/data/EmptyPaletteData.kt +++ b/src/main/java/de/bixilon/minosoft/data/world/container/palette/data/EmptyPaletteData.kt @@ -16,6 +16,7 @@ package de.bixilon.minosoft.data.world.container.palette.data import de.bixilon.minosoft.protocol.protocol.buffers.play.PlayInByteBuffer class EmptyPaletteData(override val size: Int) : PaletteData { + override val isEmpty: Boolean get() = true override fun free() = Unit diff --git a/src/main/java/de/bixilon/minosoft/data/world/container/palette/data/PaletteData.kt b/src/main/java/de/bixilon/minosoft/data/world/container/palette/data/PaletteData.kt index 3d85c7698..d124be644 100644 --- a/src/main/java/de/bixilon/minosoft/data/world/container/palette/data/PaletteData.kt +++ b/src/main/java/de/bixilon/minosoft/data/world/container/palette/data/PaletteData.kt @@ -17,6 +17,7 @@ import de.bixilon.minosoft.data.world.container.palette.data.array.ArrayPaletteD import de.bixilon.minosoft.protocol.protocol.buffers.play.PlayInByteBuffer interface PaletteData { + val isEmpty: Boolean val size: Int fun get(index: Int): Int diff --git a/src/main/java/de/bixilon/minosoft/data/world/container/palette/data/array/ArrayPaletteData.kt b/src/main/java/de/bixilon/minosoft/data/world/container/palette/data/array/ArrayPaletteData.kt index 5daf4039b..e04237bb5 100644 --- a/src/main/java/de/bixilon/minosoft/data/world/container/palette/data/array/ArrayPaletteData.kt +++ b/src/main/java/de/bixilon/minosoft/data/world/container/palette/data/array/ArrayPaletteData.kt @@ -27,25 +27,40 @@ class ArrayPaletteData( private val valuesPerLong = Long.SIZE_BITS / elementBits private lateinit var data: LongArray + override var isEmpty = true + init { check(elementBits in 0..32) } - override fun read(buffer: PlayInByteBuffer) { - val packetSize = buffer.readVarInt() - val size: Int = if (versionId < LONG_BIT_SPLITTING_VERSION) { + private fun calculateLongs(): Int { + if (versionId < LONG_BIT_SPLITTING_VERSION) { val bits = this.size * elementBits - (bits + (Long.SIZE_BITS - 1)) / Long.SIZE_BITS // divide up - } else { - (this.size + valuesPerLong - 1) / valuesPerLong + return (bits + (Long.SIZE_BITS - 1)) / Long.SIZE_BITS // divide up } - this.data = ALLOCATOR.allocate(this.size) - if (packetSize != size) { + return (this.size + valuesPerLong - 1) / valuesPerLong + } + + private fun checkEmpty(size: Int): Boolean { + for (i in 0 until size) { + if (this.data[i] != 0L) { + return false + } + } + return true + } + + override fun read(buffer: PlayInByteBuffer) { + val packetSize = buffer.readVarInt() + val longs = calculateLongs() + this.data = ALLOCATOR.allocate(longs) + if (packetSize != longs) { buffer.pointer += packetSize * Long.SIZE_BYTES // data is ignored return } - buffer.readLongArray(this.data, size) + buffer.readLongArray(this.data, longs) + this.isEmpty = checkEmpty(longs) } override operator fun get(index: Int): Int { diff --git a/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/block/chunk/ChunkUtil.kt b/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/block/chunk/ChunkUtil.kt index 16114cdcf..77e436f6a 100644 --- a/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/block/chunk/ChunkUtil.kt +++ b/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/block/chunk/ChunkUtil.kt @@ -305,12 +305,4 @@ object ChunkUtil { fun ChunkPosition.isInViewDistance(viewDistance: Int, cameraPosition: ChunkPosition): Boolean { return abs(this.x - cameraPosition.x) <= viewDistance && abs(this.y - cameraPosition.y) <= viewDistance } - - private fun Array.isEmpty(): Boolean { - for (entry in this) { - if (entry == null) continue - return false - } - return true - } }