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)
This commit is contained in:
Moritz Zwerger 2025-02-08 21:06:05 +01:00
parent 1b869e4761
commit d3dfcb2a92
No known key found for this signature in database
GPG Key ID: 5CAD791931B09AC4
5 changed files with 39 additions and 18 deletions

View File

@ -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<T>()
if (unpacked.isEmpty()) return null
if (unpacked.isAllNull()) return null
return unpacked
} finally {
data.free()
}
}
fun <T> Array<T>.isAllNull(): Boolean {
for (entry in this) {
if (entry == null) continue
return false
}
return true
}
}

View File

@ -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

View File

@ -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

View File

@ -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 {

View File

@ -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<BlockState?>.isEmpty(): Boolean {
for (entry in this) {
if (entry == null) continue
return false
}
return true
}
}