optimize sky light (down) tracing

This commit is contained in:
Moritz Zwerger 2023-07-29 16:47:07 +02:00
parent 61228a9c05
commit a7b10aaa49
No known key found for this signature in database
GPG Key ID: 5CAD791931B09AC4
3 changed files with 43 additions and 10 deletions

View File

@ -87,6 +87,10 @@ class SkyLightPlaceIT {
fun filteredBelowBlock5() { fun filteredBelowBlock5() {
val world = createConnection(3, light = true).world val world = createConnection(3, light = true).world
world.fill(6, 10, 6, 10, 10, 10, SlimeTest0.state, false) 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) world.assertLight(8, 9, 8, 0xD0)
} }

View File

@ -39,7 +39,7 @@ class ChunkSkyLight(val light: ChunkLight) {
val baseY = sectionHeight * ProtocolDefinition.SECTION_HEIGHT_Y val baseY = sectionHeight * ProtocolDefinition.SECTION_HEIGHT_Y
for (y in topY downTo bottomY) { 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 section.light.update = true
} }
@ -80,7 +80,8 @@ class ChunkSkyLight(val light: ChunkLight) {
return return
} }
val section = chunk[y.sectionHeight] ?: 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<Chunk>, x: Int, z: Int) { private fun floodFill(neighbours: Array<Chunk>, 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 const val NEIGHBOUR_TRACE_LEVEL = ProtocolDefinition.MAX_LIGHT_LEVEL_I - 1
} }
} }

View File

@ -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
import de.bixilon.minosoft.data.world.chunk.ChunkSection.Companion.getIndex 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.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.data.world.chunk.neighbours.ChunkNeighbours
import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition 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) { fun traceSkyLightIncrease(x: Int, y: Int, z: Int, nextLevel: Int, target: 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) {
val chunk = section.chunk val chunk = section.chunk
val heightmapIndex = (z shl 4) or x 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 // this light level will be 15, don't care
return return
} }
val chunkNeighbours = chunk.neighbours.get() ?: return val chunkNeighbours = chunk.neighbours.get() ?: return
val index = heightmapIndex or (y shl 8) val index = heightmapIndex or (y shl 8)
val currentLight = this[index].toInt() 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 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<ChunkSection?>.get(direction: Int, neighbour: Int, neighbours: Array<Chunk>): ChunkSection? { private inline operator fun Array<ChunkSection?>.get(direction: Int, neighbour: Int, neighbours: Array<Chunk>): ChunkSection? {
return this[direction] ?: neighbours[neighbour].getOrPut(section.sectionHeight, false) return this[direction] ?: neighbours[neighbour].getOrPut(section.sectionHeight, false)
} }