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
fun traceFrom(direction: Directions)
fun traceFrom(position: InSectionPosition, direction: Directions)
fun clear()
fun propagate()
fun calculate()
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.positions.InChunkPosition
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.sectionHeight
import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition.*
@ -48,11 +49,7 @@ class ChunkLight(val chunk: Chunk) {
val sectionHeight = position.sectionHeight
val inSection = position.inSectionPosition
val light = when (sectionHeight) {
chunk.minSection - 1 -> bottom[inSection]
chunk.maxSection + 1 -> top[inSection]
else -> chunk[sectionHeight]?.light?.get(inSection) ?: LightLevel.EMPTY
}
val light = chunk.light[sectionHeight]?.get(inSection) ?: LightLevel.EMPTY
if (position.y >= heightmap[position]) {
return light.with(sky = LightLevel.MAX_LEVEL)
@ -70,7 +67,7 @@ class ChunkLight(val chunk: Chunk) {
fun calculate() {
for (section in chunk.sections) {
section?.light?.calculateBlocks()
section?.light?.calculateBlock()
}
calculateSky()
}
@ -147,4 +144,10 @@ class ChunkLight(val chunk: Chunk) {
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
import de.bixilon.kutil.exception.Broken
import de.bixilon.minosoft.data.Axes
import de.bixilon.minosoft.data.direction.Directions
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.Companion.MAX_LEVEL
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.gui.rendering.util.VecUtil.inSectionHeight
import de.bixilon.minosoft.gui.rendering.util.VecUtil.sectionHeight
@ -40,7 +42,7 @@ class SectionLight(
when {
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 < 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?) {
@ -69,8 +73,37 @@ class SectionLight(
trace(position, LightLevel(block = luminance, sky = this[position].sky), null)
}
private fun onDecrease(position: InSectionPosition) {
// 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).
private fun onDecrease(position: InSectionPosition, luminance: Int) {
// 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? {
@ -231,7 +264,7 @@ class SectionLight(
event = true
}
fun calculateBlocks() {
fun calculateBlock() {
if (section.blocks.isEmpty) return
val min = section.blocks.minPosition
val max = section.blocks.maxPosition
@ -263,12 +296,15 @@ class SectionLight(
}
}
protected fun getNeighbour(direction: Directions): AbstractSectionLight? {
return 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
}
override fun calculate() {
calculateSky()
calculateBlock()
}
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() {
@ -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() {
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
// TODO: merge both?
if (below != null) {
for (xz in 0 until SECTION_WIDTH_X * SECTION_WIDTH_Z) {
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)
}
}
below?.traceFrom(Directions.UP)
above?.traceFrom(Directions.DOWN)
}
override fun propagate() {

View File

@ -107,6 +107,8 @@ abstract class BorderSectionLight(
return null
}
override fun calculate() = Unit // TODO: bottom sky light
protected fun propagateVertical() {
for (x in 0 until SECTION_MAX_X) {
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
import de.bixilon.kutil.exception.Broken
import de.bixilon.minosoft.data.direction.Directions
import de.bixilon.minosoft.data.world.chunk.chunk.Chunk
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 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) {
var level = level

View File

@ -13,6 +13,7 @@
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.world.chunk.chunk.Chunk
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 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) {
val current = LightLevel(light[position.xz])
if (current.block >= level.block) return