sky light handle block breaks, some border light fixes

This commit is contained in:
Moritz Zwerger 2025-04-11 15:52:13 +02:00
parent 7ac796f8cf
commit ca7020a698
No known key found for this signature in database
GPG Key ID: 5CAD791931B09AC4
6 changed files with 95 additions and 28 deletions

View File

@ -23,10 +23,12 @@ interface AbstractSectionLight {
operator fun get(position: InSectionPosition): LightLevel operator fun get(position: InSectionPosition): LightLevel
fun traceFrom(direction: Directions)
fun traceFrom(position: InSectionPosition, direction: Directions) fun traceFrom(position: InSectionPosition, direction: Directions)
fun clear() fun clear()
fun propagate() fun propagate()
fun calculate()
fun update(array: LightArray) fun update(array: LightArray)

View File

@ -25,6 +25,7 @@ import de.bixilon.minosoft.data.world.chunk.light.section.border.TopSectionLight
import de.bixilon.minosoft.data.world.chunk.light.types.LightLevel import de.bixilon.minosoft.data.world.chunk.light.types.LightLevel
import de.bixilon.minosoft.data.world.positions.InChunkPosition import de.bixilon.minosoft.data.world.positions.InChunkPosition
import de.bixilon.minosoft.data.world.positions.InSectionPosition import de.bixilon.minosoft.data.world.positions.InSectionPosition
import de.bixilon.minosoft.data.world.positions.SectionHeight
import de.bixilon.minosoft.gui.rendering.util.VecUtil.inSectionHeight import de.bixilon.minosoft.gui.rendering.util.VecUtil.inSectionHeight
import de.bixilon.minosoft.gui.rendering.util.VecUtil.sectionHeight import de.bixilon.minosoft.gui.rendering.util.VecUtil.sectionHeight
import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition.* import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition.*
@ -48,11 +49,7 @@ class ChunkLight(val chunk: Chunk) {
val sectionHeight = position.sectionHeight val sectionHeight = position.sectionHeight
val inSection = position.inSectionPosition val inSection = position.inSectionPosition
val light = when (sectionHeight) { val light = chunk.light[sectionHeight]?.get(inSection) ?: LightLevel.EMPTY
chunk.minSection - 1 -> bottom[inSection]
chunk.maxSection + 1 -> top[inSection]
else -> chunk[sectionHeight]?.light?.get(inSection) ?: LightLevel.EMPTY
}
if (position.y >= heightmap[position]) { if (position.y >= heightmap[position]) {
return light.with(sky = LightLevel.MAX_LEVEL) return light.with(sky = LightLevel.MAX_LEVEL)
@ -70,7 +67,7 @@ class ChunkLight(val chunk: Chunk) {
fun calculate() { fun calculate() {
for (section in chunk.sections) { for (section in chunk.sections) {
section?.light?.calculateBlocks() section?.light?.calculateBlock()
} }
calculateSky() calculateSky()
} }
@ -147,4 +144,10 @@ class ChunkLight(val chunk: Chunk) {
traceSkyDown(position, maxOf(bottomY, chunk.minSection - 1), topY) traceSkyDown(position, maxOf(bottomY, chunk.minSection - 1), topY)
} }
} }
operator fun get(height: SectionHeight) = when {
height < chunk.minSection -> bottom
height > chunk.maxSection -> top
else -> chunk[height]?.light
}
} }

View File

@ -13,6 +13,7 @@
package de.bixilon.minosoft.data.world.chunk.light.section package de.bixilon.minosoft.data.world.chunk.light.section
import de.bixilon.kutil.exception.Broken
import de.bixilon.minosoft.data.Axes import de.bixilon.minosoft.data.Axes
import de.bixilon.minosoft.data.direction.Directions import de.bixilon.minosoft.data.direction.Directions
import de.bixilon.minosoft.data.registries.blocks.light.LightProperties import de.bixilon.minosoft.data.registries.blocks.light.LightProperties
@ -23,6 +24,7 @@ import de.bixilon.minosoft.data.world.chunk.light.types.LightArray
import de.bixilon.minosoft.data.world.chunk.light.types.LightLevel import de.bixilon.minosoft.data.world.chunk.light.types.LightLevel
import de.bixilon.minosoft.data.world.chunk.light.types.LightLevel.Companion.MAX_LEVEL import de.bixilon.minosoft.data.world.chunk.light.types.LightLevel.Companion.MAX_LEVEL
import de.bixilon.minosoft.data.world.chunk.update.chunk.SectionLightUpdate import de.bixilon.minosoft.data.world.chunk.update.chunk.SectionLightUpdate
import de.bixilon.minosoft.data.world.positions.ChunkPosition
import de.bixilon.minosoft.data.world.positions.InSectionPosition import de.bixilon.minosoft.data.world.positions.InSectionPosition
import de.bixilon.minosoft.gui.rendering.util.VecUtil.inSectionHeight import de.bixilon.minosoft.gui.rendering.util.VecUtil.inSectionHeight
import de.bixilon.minosoft.gui.rendering.util.VecUtil.sectionHeight import de.bixilon.minosoft.gui.rendering.util.VecUtil.sectionHeight
@ -40,7 +42,7 @@ class SectionLight(
when { when {
luminance > previousLuminance -> onIncrease(position, luminance) luminance > previousLuminance -> onIncrease(position, luminance)
luminance < previousLuminance -> onDecrease(position) luminance < previousLuminance -> onDecrease(position, previousLuminance)
} }
} }
@ -58,6 +60,8 @@ class SectionLight(
if (position.z > 0) traceFrom(position.minusZ(), Directions.NORTH) else getNeighbour(Directions.SOUTH)?.traceFrom(position.with(z = SECTION_MAX_Z), Directions.NORTH) if (position.z > 0) traceFrom(position.minusZ(), Directions.NORTH) else getNeighbour(Directions.SOUTH)?.traceFrom(position.with(z = SECTION_MAX_Z), Directions.NORTH)
if (position.z < SECTION_MAX_Z) traceFrom(position.plusZ(), Directions.SOUTH) else getNeighbour(Directions.NORTH)?.traceFrom(position.with(z = 0), Directions.SOUTH) if (position.z < SECTION_MAX_Z) traceFrom(position.plusZ(), Directions.SOUTH) else getNeighbour(Directions.NORTH)?.traceFrom(position.with(z = 0), Directions.SOUTH)
// TODO: This just handles increase in light (i.e. breaking a block), what if a block is placed?
} }
fun onBlockChange(position: InSectionPosition, previous: BlockState?, state: BlockState?) { fun onBlockChange(position: InSectionPosition, previous: BlockState?, state: BlockState?) {
@ -69,8 +73,37 @@ class SectionLight(
trace(position, LightLevel(block = luminance, sky = this[position].sky), null) trace(position, LightLevel(block = luminance, sky = this[position].sky), null)
} }
private fun onDecrease(position: InSectionPosition) { private fun onDecrease(position: InSectionPosition, luminance: Int) {
// TODO: Trace until next light increase (or level 0), set all those levels to 0 and then force trace all blocks in range (also from neighbours). // TODO: Optimize (trace in direction and then propagate from edges and trace back again)
val minX = (position.x - luminance).sectionHeight
val maxX = (position.x + luminance).sectionHeight
val minY = (position.y - luminance).sectionHeight
val maxY = (position.y + luminance).sectionHeight
val minZ = (position.z - luminance).sectionHeight
val maxZ = (position.z + luminance).sectionHeight
for (x in minX..maxX) {
for (z in minZ..maxZ) {
val chunk = section.chunk.neighbours.traceChunk(ChunkPosition(x, z)) ?: continue
for (y in minY..maxY) {
val neighbour = chunk.light[section.height + y] ?: continue
neighbour.clear()
}
}
}
for (x in minX..maxX) {
for (z in minZ..maxZ) {
val chunk = section.chunk.neighbours.traceChunk(ChunkPosition(x, z)) ?: continue
for (y in minY..maxY) {
val neighbour = chunk.light[section.height + y] ?: continue
neighbour.propagate()
neighbour.calculate()
}
}
}
} }
private inline fun getOrPut(direction: Directions): SectionLight? { private inline fun getOrPut(direction: Directions): SectionLight? {
@ -231,7 +264,7 @@ class SectionLight(
event = true event = true
} }
fun calculateBlocks() { fun calculateBlock() {
if (section.blocks.isEmpty) return if (section.blocks.isEmpty) return
val min = section.blocks.minPosition val min = section.blocks.minPosition
val max = section.blocks.maxPosition val max = section.blocks.maxPosition
@ -263,12 +296,15 @@ class SectionLight(
} }
} }
protected fun getNeighbour(direction: Directions): AbstractSectionLight? { override fun calculate() {
return when (direction) { calculateSky()
Directions.UP -> if (section.height == section.chunk.maxSection) section.chunk.light.top else section.chunk[section.height + 1]?.light calculateBlock()
Directions.DOWN -> if (section.height == section.chunk.minSection) section.chunk.light.bottom else section.chunk[section.height - 1]?.light }
else -> section.chunk.neighbours[direction]?.get(section.height)?.light
} protected fun getNeighbour(direction: Directions) = when (direction) {
Directions.UP -> if (section.height == section.chunk.maxSection) section.chunk.light.top else section.chunk[section.height + 1]?.light
Directions.DOWN -> if (section.height == section.chunk.minSection) section.chunk.light.bottom else section.chunk[section.height - 1]?.light
else -> section.chunk.neighbours[direction]?.get(section.height)?.light
} }
private fun propagateVertical() { private fun propagateVertical() {
@ -290,23 +326,20 @@ class SectionLight(
} }
} }
override fun traceFrom(direction: Directions) {
if (direction.axis != Axes.Y) Broken()
for (xz in 0 until SECTION_WIDTH_X * SECTION_WIDTH_Z) {
traceFrom(InSectionPosition(xz), direction)
}
}
private fun propagateHorizontal() { private fun propagateHorizontal() {
val below = if (section.height == section.chunk.minSection) section.chunk.light.bottom else section.chunk[section.height - 1]?.light val below = if (section.height == section.chunk.minSection) section.chunk.light.bottom else section.chunk[section.height - 1]?.light
val above = if (section.height == section.chunk.maxSection) section.chunk.light.top else section.chunk[section.height + 1]?.light val above = if (section.height == section.chunk.maxSection) section.chunk.light.top else section.chunk[section.height + 1]?.light
// TODO: merge both? // TODO: merge both?
if (below != null) { below?.traceFrom(Directions.UP)
for (xz in 0 until SECTION_WIDTH_X * SECTION_WIDTH_Z) { above?.traceFrom(Directions.DOWN)
val position = InSectionPosition(xz).with(y = SECTION_MAX_Y)
below.traceFrom(position, Directions.UP)
}
}
if (above != null) {
for (xz in 0 until SECTION_WIDTH_X * SECTION_WIDTH_Z) {
val position = InSectionPosition(xz).with(y = 0)
above.traceFrom(position, Directions.DOWN)
}
}
} }
override fun propagate() { override fun propagate() {

View File

@ -107,6 +107,8 @@ abstract class BorderSectionLight(
return null return null
} }
override fun calculate() = Unit // TODO: bottom sky light
protected fun propagateVertical() { protected fun propagateVertical() {
for (x in 0 until SECTION_MAX_X) { for (x in 0 until SECTION_MAX_X) {
chunk.neighbours[Directions.NORTH]?.light?.bottom?.traceFrom(InSectionPosition(x, 0, SECTION_MAX_Z), Directions.SOUTH) chunk.neighbours[Directions.NORTH]?.light?.bottom?.traceFrom(InSectionPosition(x, 0, SECTION_MAX_Z), Directions.SOUTH)

View File

@ -13,6 +13,7 @@
package de.bixilon.minosoft.data.world.chunk.light.section.border package de.bixilon.minosoft.data.world.chunk.light.section.border
import de.bixilon.kutil.exception.Broken
import de.bixilon.minosoft.data.direction.Directions import de.bixilon.minosoft.data.direction.Directions
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.types.LightArray import de.bixilon.minosoft.data.world.chunk.light.types.LightArray
@ -31,6 +32,18 @@ class BottomSectionLight(
override fun Chunk.getBorderLight() = this.light.bottom override fun Chunk.getBorderLight() = this.light.bottom
override fun traceFrom(direction: Directions) {
if (direction != Directions.UP) Broken()
val above = chunk[chunk.minSection]?.light ?: return
for (xz in 0 until SECTION_WIDTH_X * SECTION_WIDTH_Z) {
val position = InSectionPosition(xz)
val current = LightLevel(light[xz])
if (current.block <= 1) return
val next = current.decrease()
above.trace(position.with(y = 0), next, Directions.UP)
}
}
override fun trace(position: InSectionPosition, level: LightLevel) { override fun trace(position: InSectionPosition, level: LightLevel) {
var level = level var level = level

View File

@ -13,6 +13,7 @@
package de.bixilon.minosoft.data.world.chunk.light.section.border package de.bixilon.minosoft.data.world.chunk.light.section.border
import de.bixilon.kutil.exception.Broken
import de.bixilon.minosoft.data.direction.Directions import de.bixilon.minosoft.data.direction.Directions
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.types.LightArray import de.bixilon.minosoft.data.world.chunk.light.types.LightArray
@ -31,6 +32,19 @@ class TopSectionLight(
override fun Chunk.getBorderLight() = this.light.top override fun Chunk.getBorderLight() = this.light.top
override fun traceFrom(direction: Directions) {
if (direction != Directions.DOWN) Broken()
val above = chunk[chunk.maxSection]?.light ?: return
for (xz in 0 until SECTION_WIDTH_X * SECTION_WIDTH_Z) {
val position = InSectionPosition(xz)
val current = LightLevel(light[xz])
if (current.block <= 1) return
val next = current.decrease()
above.trace(position.with(y = SECTION_MAX_Y), next, Directions.DOWN)
}
}
override fun trace(position: InSectionPosition, level: LightLevel) { override fun trace(position: InSectionPosition, level: LightLevel) {
val current = LightLevel(light[position.xz]) val current = LightLevel(light[position.xz])
if (current.block >= level.block) return if (current.block >= level.block) return