From a7b10aaa491c4912cbc9827597c9cf2834ac1727 Mon Sep 17 00:00:00 2001 From: Moritz Zwerger Date: Sat, 29 Jul 2023 16:47:07 +0200 Subject: [PATCH] optimize sky light (down) tracing --- .../chunk/light/place/SkyLightPlaceIT.kt | 4 ++ .../data/world/chunk/light/ChunkSkyLight.kt | 7 ++-- .../data/world/chunk/light/SectionLight.kt | 42 +++++++++++++++---- 3 files changed, 43 insertions(+), 10 deletions(-) diff --git a/src/integration-test/kotlin/de/bixilon/minosoft/data/world/chunk/light/place/SkyLightPlaceIT.kt b/src/integration-test/kotlin/de/bixilon/minosoft/data/world/chunk/light/place/SkyLightPlaceIT.kt index ca11130e7..b0841366e 100644 --- a/src/integration-test/kotlin/de/bixilon/minosoft/data/world/chunk/light/place/SkyLightPlaceIT.kt +++ b/src/integration-test/kotlin/de/bixilon/minosoft/data/world/chunk/light/place/SkyLightPlaceIT.kt @@ -87,6 +87,10 @@ class SkyLightPlaceIT { fun filteredBelowBlock5() { val world = createConnection(3, light = true).world world.fill(6, 10, 6, 10, 10, 10, SlimeTest0.state, false) + world.chunks[0, 0]!!.light.reset() + world.chunks[0, 0]!!.light.sky.calculate() + world.assertLight(8, 11, 8, 0xF0) + world.assertLight(8, 10, 8, 0xE0) world.assertLight(8, 9, 8, 0xD0) } diff --git a/src/main/java/de/bixilon/minosoft/data/world/chunk/light/ChunkSkyLight.kt b/src/main/java/de/bixilon/minosoft/data/world/chunk/light/ChunkSkyLight.kt index f1c4f506f..011b90bb7 100644 --- a/src/main/java/de/bixilon/minosoft/data/world/chunk/light/ChunkSkyLight.kt +++ b/src/main/java/de/bixilon/minosoft/data/world/chunk/light/ChunkSkyLight.kt @@ -39,7 +39,7 @@ class ChunkSkyLight(val light: ChunkLight) { val baseY = sectionHeight * ProtocolDefinition.SECTION_HEIGHT_Y for (y in topY downTo bottomY) { - section.light.traceSkyLightIncrease(x, y, z, NEIGHBOUR_TRACE_LEVEL, target, baseY + y, false) + section.light.traceSkyLightIncrease(x, y, z, NEIGHBOUR_TRACE_LEVEL, target, baseY + y) } section.light.update = true } @@ -80,7 +80,8 @@ class ChunkSkyLight(val light: ChunkLight) { return } val section = chunk[y.sectionHeight] ?: return - section.light.traceSkyLightIncrease(x, y.inSectionHeight, z, ProtocolDefinition.MAX_LIGHT_LEVEL_I, null, y, true) + + section.light.traceSkyLightDown(x, y.inSectionHeight, z, Directions.DOWN, y) } private fun floodFill(neighbours: Array, x: Int, z: Int) { @@ -170,7 +171,7 @@ class ChunkSkyLight(val light: ChunkLight) { } - private companion object { + companion object { const val NEIGHBOUR_TRACE_LEVEL = ProtocolDefinition.MAX_LIGHT_LEVEL_I - 1 } } diff --git a/src/main/java/de/bixilon/minosoft/data/world/chunk/light/SectionLight.kt b/src/main/java/de/bixilon/minosoft/data/world/chunk/light/SectionLight.kt index 6902773b0..b4fd4443d 100644 --- a/src/main/java/de/bixilon/minosoft/data/world/chunk/light/SectionLight.kt +++ b/src/main/java/de/bixilon/minosoft/data/world/chunk/light/SectionLight.kt @@ -19,6 +19,7 @@ import de.bixilon.minosoft.data.registries.blocks.state.BlockState import de.bixilon.minosoft.data.world.chunk.ChunkSection import de.bixilon.minosoft.data.world.chunk.ChunkSection.Companion.getIndex import de.bixilon.minosoft.data.world.chunk.chunk.Chunk +import de.bixilon.minosoft.data.world.chunk.light.ChunkSkyLight.Companion.NEIGHBOUR_TRACE_LEVEL import de.bixilon.minosoft.data.world.chunk.neighbours.ChunkNeighbours import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition @@ -316,21 +317,17 @@ class SectionLight( } } - internal inline fun traceSkyLightIncrease(x: Int, y: Int, z: Int, nextLevel: Int, direction: Directions?, totalY: Int) { - return traceSkyLightIncrease(x, y, z, nextLevel, direction, totalY, false) - } - - fun traceSkyLightIncrease(x: Int, y: Int, z: Int, nextLevel: Int, target: Directions?, totalY: Int, force: Boolean) { + fun traceSkyLightIncrease(x: Int, y: Int, z: Int, nextLevel: Int, target: Directions?, totalY: Int) { val chunk = section.chunk val heightmapIndex = (z shl 4) or x - if (!force && totalY >= chunk.light.heightmap[heightmapIndex]) { + if (totalY >= chunk.light.heightmap[heightmapIndex]) { // this light level will be 15, don't care return } val chunkNeighbours = chunk.neighbours.get() ?: return val index = heightmapIndex or (y shl 8) val currentLight = this[index].toInt() - if (!force && ((currentLight and SKY_LIGHT_MASK) shr 4) >= nextLevel) { + if (((currentLight and SKY_LIGHT_MASK) shr 4) >= nextLevel) { return } @@ -409,6 +406,37 @@ class SectionLight( } } + fun traceSkyLightDown(x: Int, y: Int, z: Int, target: Directions?, totalY: Int) { // TODO: remove code duplicates + val chunk = section.chunk + val index = (y shl 8) or (z shl 4) or x + + val state = section.blocks[index] + var lightProperties = state?.block?.getLightProperties(state) + + if (lightProperties == null) { + lightProperties = TransparentProperty + } else if (!lightProperties.propagatesLight || (target != null && !lightProperties.propagatesLight(target.inverted))) { + return + } + + val neighbours = this.section.neighbours ?: return + + this.light[index] = ((this[index].toInt() and BLOCK_LIGHT_MASK) or (ProtocolDefinition.MAX_LIGHT_LEVEL_I shl 4)).toByte() + + if (!update) { + update = true + } + + + if (lightProperties.propagatesLight(Directions.DOWN)) { + if (y > 0) { + traceSkyLightIncrease(x, y - 1, z, NEIGHBOUR_TRACE_LEVEL, Directions.DOWN, totalY - 1) + } else { + (neighbours[Directions.O_DOWN] ?: chunk.getOrPut(section.sectionHeight - 1, false))?.light?.traceSkyLightIncrease(x, ProtocolDefinition.SECTION_MAX_Y, z, NEIGHBOUR_TRACE_LEVEL, Directions.DOWN, totalY - 1) + } + } + } + private inline operator fun Array.get(direction: Int, neighbour: Int, neighbours: Array): ChunkSection? { return this[direction] ?: neighbours[neighbour].getOrPut(section.sectionHeight, false) }