diff --git a/src/integration-test/kotlin/de/bixilon/minosoft/data/world/chunk/light/GeneralHeightmapTest.kt b/src/integration-test/kotlin/de/bixilon/minosoft/data/world/chunk/light/GeneralHeightmapTest.kt
index 0390fc61d..15a369502 100644
--- a/src/integration-test/kotlin/de/bixilon/minosoft/data/world/chunk/light/GeneralHeightmapTest.kt
+++ b/src/integration-test/kotlin/de/bixilon/minosoft/data/world/chunk/light/GeneralHeightmapTest.kt
@@ -14,6 +14,8 @@
package de.bixilon.minosoft.data.world.chunk.light
import de.bixilon.kotlinglm.vec3.Vec3i
+import de.bixilon.minosoft.data.registries.blocks.GlassTest0
+import de.bixilon.minosoft.data.registries.blocks.LeavesTest0
import de.bixilon.minosoft.data.registries.blocks.types.stone.StoneTest0
import de.bixilon.minosoft.data.world.chunk.ChunkTestingUtil.createChunkWithNeighbours
import de.bixilon.minosoft.data.world.chunk.chunk.Chunk
@@ -25,15 +27,6 @@ import org.testng.annotations.Test
@Test(groups = ["light"], dependsOnGroups = ["block"])
class GeneralHeightmapTest {
- fun testMaxHeightEast() {
- val chunk: Chunk = createChunkWithNeighbours()
- chunk[Vec3i(2, 10, 3)] = StoneTest0.state
- chunk[Vec3i(3, 11, 2)] = StoneTest0.state
- chunk[Vec3i(3, 12, 4)] = StoneTest0.state
- chunk[Vec3i(4, 13, 3)] = StoneTest0.state
- assertEquals(chunk.light.getNeighbourMaxHeight(chunk.neighbours.get()!!, 3, 3), 14)
- }
-
fun testMinHeightEast() {
val chunk: Chunk = createChunkWithNeighbours()
chunk[Vec3i(2, 10, 3)] = StoneTest0.state
@@ -43,16 +36,6 @@ class GeneralHeightmapTest {
assertEquals(chunk.light.getNeighbourMinHeight(chunk.neighbours.get()!!, 3, 3), 11)
}
- fun testMaxHeightNeighbourEast() {
- val chunk: Chunk = createChunkWithNeighbours()
- val neighbours = chunk.neighbours.get()!!
- chunk[Vec3i(14, 10, 3)] = StoneTest0.state
- chunk[Vec3i(15, 11, 2)] = StoneTest0.state
- chunk[Vec3i(15, 12, 4)] = StoneTest0.state
- neighbours[ChunkNeighbours.EAST][Vec3i(0, 13, 3)] = StoneTest0.state
- assertEquals(chunk.light.getNeighbourMaxHeight(neighbours, 15, 3), 14)
- }
-
fun testMinHeightNeighbourEast() {
val chunk: Chunk = createChunkWithNeighbours()
val neighbours = chunk.neighbours.get()!!
@@ -62,6 +45,24 @@ class GeneralHeightmapTest {
neighbours[ChunkNeighbours.EAST][Vec3i(0, 10, 3)] = StoneTest0.state
assertEquals(chunk.light.getNeighbourMinHeight(neighbours, 15, 3), 11)
}
-
// TODO: Test other directions
+
+ fun `top of the world and not passing`() {
+ val chunk: Chunk = createChunkWithNeighbours()
+ chunk[Vec3i(2, 255, 3)] = StoneTest0.state
+ assertEquals(chunk.light.heightmap[2, 3], 256)
+ }
+
+ fun `top of the world and entering`() {
+ val chunk: Chunk = createChunkWithNeighbours()
+ chunk[Vec3i(2, 255, 3)] = LeavesTest0.state
+ assertEquals(chunk.light.heightmap[2, 3], 255)
+ }
+
+ fun `top of the world and passing`() {
+ val chunk: Chunk = createChunkWithNeighbours()
+ chunk[Vec3i(2, 255, 3)] = GlassTest0.state
+ assertEquals(chunk.light.heightmap[2, 3], Int.MIN_VALUE)
+ }
+
}
diff --git a/src/integration-test/kotlin/de/bixilon/minosoft/data/world/chunk/light/SkyLightTraceIT.kt b/src/integration-test/kotlin/de/bixilon/minosoft/data/world/chunk/light/SkyLightTraceIT.kt
new file mode 100644
index 000000000..50418fd20
--- /dev/null
+++ b/src/integration-test/kotlin/de/bixilon/minosoft/data/world/chunk/light/SkyLightTraceIT.kt
@@ -0,0 +1,59 @@
+/*
+ * Minosoft
+ * Copyright (C) 2020-2023 Moritz Zwerger
+ *
+ * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with this program. If not, see .
+ *
+ * This software is not affiliated with Mojang AB, the original developer of Minecraft.
+ */
+
+package de.bixilon.minosoft.data.world.chunk.light
+
+import de.bixilon.kotlinglm.vec3.Vec3i
+import de.bixilon.minosoft.data.registries.blocks.types.stone.StoneTest0
+import de.bixilon.minosoft.data.world.chunk.light.LightTestUtil.assertLight
+import de.bixilon.minosoft.protocol.network.connection.play.ConnectionTestUtil.createConnection
+import org.testng.annotations.Test
+
+
+@Test(groups = ["light"], dependsOnGroups = ["block"], threadPoolSize = 8, priority = 1000)
+class SkyLightTraceIT {
+
+ fun `check level below block`() {
+ val world = createConnection(3, light = true).world
+ world[Vec3i(8, 10, 8)] = StoneTest0.state
+ world.assertLight(8, 9, 8, 0xD0)
+ }
+
+ fun `heightmap optimization west, upper block set`() {
+ val world = createConnection(3, light = true).world
+ world[Vec3i(8, 10, 8)] = StoneTest0.state
+ world[Vec3i(7, 12, 8)] = StoneTest0.state
+ world.assertLight(7, 11, 8, 0xD0)
+ }
+
+ fun `heightmap optimization east, upper block set`() {
+ val world = createConnection(3, light = true).world
+ world[Vec3i(8, 10, 8)] = StoneTest0.state
+ world[Vec3i(9, 12, 8)] = StoneTest0.state
+ world.assertLight(9, 11, 8, 0xD0)
+ }
+
+ fun `heightmap optimization north, upper block set`() {
+ val world = createConnection(3, light = true).world
+ world[Vec3i(8, 10, 8)] = StoneTest0.state
+ world[Vec3i(8, 12, 7)] = StoneTest0.state
+ world.assertLight(8, 11, 7, 0xD0)
+ }
+
+ fun `heightmap optimization south, upper block set`() {
+ val world = createConnection(3, light = true).world
+ world[Vec3i(8, 10, 8)] = StoneTest0.state
+ world[Vec3i(8, 12, 9)] = StoneTest0.state
+ world.assertLight(8, 11, 9, 0xD0)
+ }
+}
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 34e9d7317..131ff0d67 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
@@ -23,7 +23,7 @@ import de.bixilon.minosoft.protocol.network.connection.play.ConnectionTestUtil.c
import org.testng.annotations.Test
-@Test(groups = ["light"], dependsOnGroups = ["block"], threadPoolSize = 8, priority = -100)
+@Test(groups = ["light"], dependsOnGroups = ["block"], threadPoolSize = 8, priority = 1000)
class SkyLightPlaceIT {
fun aboveBlock() {
diff --git a/src/main/java/de/bixilon/minosoft/data/world/World.kt b/src/main/java/de/bixilon/minosoft/data/world/World.kt
index 9d5d8a3fa..b1d7fe616 100644
--- a/src/main/java/de/bixilon/minosoft/data/world/World.kt
+++ b/src/main/java/de/bixilon/minosoft/data/world/World.kt
@@ -228,7 +228,7 @@ class World(
reset += { chunk.light.reset() }
calculate += {
if (heightmap) {
- chunk.light.recalculateHeightmap()
+ chunk.light.heightmap.recalculate()
}
chunk.light.calculate()
}
diff --git a/src/main/java/de/bixilon/minosoft/data/world/chunk/chunk/Chunk.kt b/src/main/java/de/bixilon/minosoft/data/world/chunk/chunk/Chunk.kt
index 6c6053ca7..ed2c01de4 100644
--- a/src/main/java/de/bixilon/minosoft/data/world/chunk/chunk/Chunk.kt
+++ b/src/main/java/de/bixilon/minosoft/data/world/chunk/chunk/Chunk.kt
@@ -62,7 +62,7 @@ class Chunk(
init {
- light.recalculateHeightmap()
+ light.heightmap.recalculate()
}
@Deprecated("neighbours.complete", ReplaceWith("neighbours.complete"))
@@ -162,7 +162,7 @@ class Chunk(
if (executed.isEmpty()) {
return lock.unlock()
}
- light.recalculateHeightmap()
+ light.heightmap.recalculate()
light.recalculate()
for (section in sections) {
diff --git a/src/main/java/de/bixilon/minosoft/data/world/chunk/heightmap/AbstractHeightmap.kt b/src/main/java/de/bixilon/minosoft/data/world/chunk/heightmap/AbstractHeightmap.kt
new file mode 100644
index 000000000..abb57c339
--- /dev/null
+++ b/src/main/java/de/bixilon/minosoft/data/world/chunk/heightmap/AbstractHeightmap.kt
@@ -0,0 +1,26 @@
+/*
+ * Minosoft
+ * Copyright (C) 2020-2023 Moritz Zwerger
+ *
+ * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with this program. If not, see .
+ *
+ * This software is not affiliated with Mojang AB, the original developer of Minecraft.
+ */
+
+package de.bixilon.minosoft.data.world.chunk.heightmap
+
+import de.bixilon.minosoft.data.registries.blocks.state.BlockState
+
+interface AbstractHeightmap {
+
+ fun recalculate()
+
+ operator fun get(x: Int, z: Int): Int
+ operator fun get(index: Int): Int
+
+ fun onBlockChange(x: Int, y: Int, z: Int, next: BlockState?)
+}
diff --git a/src/main/java/de/bixilon/minosoft/data/world/chunk/heightmap/FixedHeightmap.kt b/src/main/java/de/bixilon/minosoft/data/world/chunk/heightmap/FixedHeightmap.kt
new file mode 100644
index 000000000..0381936bc
--- /dev/null
+++ b/src/main/java/de/bixilon/minosoft/data/world/chunk/heightmap/FixedHeightmap.kt
@@ -0,0 +1,30 @@
+/*
+ * Minosoft
+ * Copyright (C) 2020-2023 Moritz Zwerger
+ *
+ * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with this program. If not, see .
+ *
+ * This software is not affiliated with Mojang AB, the original developer of Minecraft.
+ */
+
+package de.bixilon.minosoft.data.world.chunk.heightmap
+
+import de.bixilon.minosoft.data.registries.blocks.state.BlockState
+
+class FixedHeightmap(val value: Int) : AbstractHeightmap {
+
+ override fun recalculate() = Unit
+
+ override fun get(x: Int, z: Int) = value
+ override fun get(index: Int) = value
+
+ override fun onBlockChange(x: Int, y: Int, z: Int, next: BlockState?) = Unit
+
+ companion object {
+ val MAX_VALUE = FixedHeightmap(Int.MAX_VALUE)
+ }
+}
diff --git a/src/main/java/de/bixilon/minosoft/data/world/chunk/heightmap/Heightmap.kt b/src/main/java/de/bixilon/minosoft/data/world/chunk/heightmap/Heightmap.kt
new file mode 100644
index 000000000..7a8825d9d
--- /dev/null
+++ b/src/main/java/de/bixilon/minosoft/data/world/chunk/heightmap/Heightmap.kt
@@ -0,0 +1,117 @@
+/*
+ * Minosoft
+ * Copyright (C) 2020-2023 Moritz Zwerger
+ *
+ * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with this program. If not, see .
+ *
+ * This software is not affiliated with Mojang AB, the original developer of Minecraft.
+ */
+
+package de.bixilon.minosoft.data.world.chunk.heightmap
+
+import de.bixilon.minosoft.data.registries.blocks.state.BlockState
+import de.bixilon.minosoft.data.world.chunk.chunk.Chunk
+import de.bixilon.minosoft.gui.rendering.util.VecUtil.sectionHeight
+import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition
+
+abstract class Heightmap(protected val chunk: Chunk) : AbstractHeightmap {
+ protected val heightmap = IntArray(ProtocolDefinition.SECTION_WIDTH_X * ProtocolDefinition.SECTION_WIDTH_Z) { Int.MIN_VALUE }
+
+ override fun get(index: Int) = heightmap[index]
+ override fun get(x: Int, z: Int) = heightmap[(z shl 4) or x]
+
+
+ protected abstract fun passes(state: BlockState): HeightmapPass
+ protected abstract fun onHeightmapUpdate(x: Int, z: Int, previous: Int, now: Int)
+
+
+ override fun recalculate() {
+ chunk.lock.lock()
+ val maxY = chunk.maxSection * ProtocolDefinition.SECTION_HEIGHT_Y
+
+ for (x in 0 until ProtocolDefinition.SECTION_WIDTH_X) {
+ for (z in 0 until ProtocolDefinition.SECTION_WIDTH_Z) {
+ trace(x, maxY, z, false)
+ }
+ }
+ chunk.lock.unlock()
+ }
+
+
+ private fun trace(x: Int, startY: Int, z: Int, notify: Boolean) {
+ val sections = chunk.sections
+
+ var y = Int.MIN_VALUE
+
+ sectionLoop@ for (sectionIndex in (startY.sectionHeight - chunk.minSection) downTo 0) {
+ if (sectionIndex >= sections.size) {
+ // starting from above world
+ continue
+ }
+ val section = sections[sectionIndex] ?: continue
+ if (section.blocks.isEmpty) continue
+
+ section.acquire()
+ for (sectionY in ProtocolDefinition.SECTION_MAX_Y downTo 0) {
+ val state = section.blocks[x, sectionY, z] ?: continue
+ val pass = passes(state)
+ if (pass == HeightmapPass.PASSES) continue
+
+ y = (sectionIndex + chunk.minSection) * ProtocolDefinition.SECTION_HEIGHT_Y + sectionY + 1
+ if (pass == HeightmapPass.ABOVE) y++
+
+ section.release()
+ break@sectionLoop
+ }
+ section.release()
+ }
+ val index = (z shl 4) or x
+ val previous = heightmap[index]
+
+ if (previous == y) return
+
+ heightmap[index] = y
+
+ if (notify) {
+ onHeightmapUpdate(x, z, previous, y)
+ }
+ }
+
+
+ override fun onBlockChange(x: Int, y: Int, z: Int, next: BlockState?) {
+ chunk.lock.lock()
+ val index = (z shl 4) or x
+
+ val current = heightmap[index]
+
+ if (current > y + 1) {
+ // our block is/was not the highest, ignore everything
+ chunk.lock.unlock()
+ return
+ }
+ if (next == null) {
+ trace(x, y, z, true)
+ chunk.lock.unlock()
+ return
+ }
+
+ when (passes(next)) {
+ HeightmapPass.ABOVE -> heightmap[index] = y + 1
+ HeightmapPass.IN -> heightmap[index] = y
+ HeightmapPass.PASSES -> Unit
+ }
+
+ chunk.lock.unlock()
+ }
+
+ protected enum class HeightmapPass {
+ ABOVE,
+ IN,
+ PASSES,
+ ;
+ }
+}
diff --git a/src/main/java/de/bixilon/minosoft/data/world/chunk/heightmap/LightHeightmap.kt b/src/main/java/de/bixilon/minosoft/data/world/chunk/heightmap/LightHeightmap.kt
new file mode 100644
index 000000000..49cf5a3b0
--- /dev/null
+++ b/src/main/java/de/bixilon/minosoft/data/world/chunk/heightmap/LightHeightmap.kt
@@ -0,0 +1,63 @@
+/*
+ * Minosoft
+ * Copyright (C) 2020-2023 Moritz Zwerger
+ *
+ * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with this program. If not, see .
+ *
+ * This software is not affiliated with Mojang AB, the original developer of Minecraft.
+ */
+
+package de.bixilon.minosoft.data.world.chunk.heightmap
+
+import de.bixilon.minosoft.data.direction.Directions
+import de.bixilon.minosoft.data.registries.blocks.state.BlockState
+import de.bixilon.minosoft.data.world.chunk.chunk.Chunk
+import de.bixilon.minosoft.gui.rendering.util.VecUtil.sectionHeight
+
+class LightHeightmap(chunk: Chunk) : Heightmap(chunk) {
+
+
+ override fun recalculate() {
+ super.recalculate()
+ chunk.light.calculateSkylight()
+ }
+
+ override fun onHeightmapUpdate(x: Int, z: Int, previous: Int, now: Int) {
+ if (previous > now) {
+ // block is lower
+ return chunk.light.startSkylightFloodFill(x, z)
+ }
+ // block is now higher
+ // ToDo: Neighbours
+ val sections = chunk.sections
+ val maxIndex = previous.sectionHeight - chunk.minSection
+ val minIndex = now.sectionHeight - chunk.minSection
+ chunk.light.bottom.reset()
+ for (index in maxIndex downTo minIndex) {
+ val section = sections[index] ?: continue
+ section.light.reset()
+ }
+ for (index in maxIndex downTo minIndex) {
+ val section = sections[index] ?: continue
+ section.light.calculate()
+ }
+ chunk.light.calculateSkylight()
+ }
+
+
+ override fun passes(state: BlockState): HeightmapPass {
+ val light = state.block.getLightProperties(state)
+ if (!light.skylightEnters) return HeightmapPass.ABOVE
+
+ if (!light.filtersSkylight && light.propagatesLight(Directions.DOWN)) {
+ // can go through block
+ return HeightmapPass.PASSES
+ }
+
+ return HeightmapPass.IN
+ }
+}
diff --git a/src/main/java/de/bixilon/minosoft/data/world/chunk/light/ChunkLight.kt b/src/main/java/de/bixilon/minosoft/data/world/chunk/light/ChunkLight.kt
index 63ded434d..a48ff7d50 100644
--- a/src/main/java/de/bixilon/minosoft/data/world/chunk/light/ChunkLight.kt
+++ b/src/main/java/de/bixilon/minosoft/data/world/chunk/light/ChunkLight.kt
@@ -20,6 +20,8 @@ import de.bixilon.minosoft.data.registries.blocks.state.BlockState
import de.bixilon.minosoft.data.registries.dimension.DimensionProperties
import de.bixilon.minosoft.data.world.chunk.ChunkSection
import de.bixilon.minosoft.data.world.chunk.chunk.Chunk
+import de.bixilon.minosoft.data.world.chunk.heightmap.FixedHeightmap
+import de.bixilon.minosoft.data.world.chunk.heightmap.LightHeightmap
import de.bixilon.minosoft.data.world.chunk.neighbours.ChunkNeighbours
import de.bixilon.minosoft.data.world.chunk.update.AbstractWorldUpdate
import de.bixilon.minosoft.data.world.chunk.update.chunk.ChunkLightUpdate
@@ -29,7 +31,7 @@ import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition
class ChunkLight(private val chunk: Chunk) {
private val connection = chunk.connection
- val heightmap = IntArray(ProtocolDefinition.SECTION_WIDTH_X * ProtocolDefinition.SECTION_WIDTH_Z) { if (chunk.world.dimension.canSkylight()) Int.MIN_VALUE else Int.MAX_VALUE }
+ val heightmap = if (chunk.world.dimension.canSkylight()) LightHeightmap(chunk) else FixedHeightmap.MAX_VALUE
val bottom = BorderSectionLight(false, chunk)
val top = BorderSectionLight(true, chunk)
@@ -39,10 +41,7 @@ class ChunkLight(private val chunk: Chunk) {
if (!chunk.world.dimension.light) {
return
}
- val heightmapIndex = (z shl 4) or x
- val previous = heightmap[heightmapIndex]
- recalculateHeightmap(x, y, z, next)
- onHeightmapUpdate(x, y, z, previous, heightmap[heightmapIndex])
+ heightmap.onBlockChange(x, y, z, next)
val neighbours = chunk.neighbours.get() ?: return
@@ -180,118 +179,8 @@ class ChunkLight(private val chunk: Chunk) {
}
}
- fun recalculateHeightmap() {
- if (!chunk.world.dimension.canSkylight()) {
- return
- }
- chunk.lock.lock()
- val maxY = chunk.maxSection * ProtocolDefinition.SECTION_HEIGHT_Y
- for (x in 0 until ProtocolDefinition.SECTION_WIDTH_X) {
- for (z in 0 until ProtocolDefinition.SECTION_WIDTH_Z) {
- checkHeightmapY(x, maxY, z)
- }
- }
- chunk.lock.unlock()
- calculateSkylight()
- }
-
- private fun checkHeightmapY(x: Int, startY: Int, z: Int) {
- val sections = chunk.sections
-
- var y = Int.MIN_VALUE
-
- sectionLoop@ for (sectionIndex in (startY.sectionHeight - chunk.minSection) downTo 0) {
- if (sectionIndex >= sections.size) {
- // starting from above world
- continue
- }
- val section = sections[sectionIndex] ?: continue
- if (section.blocks.isEmpty) continue
-
- section.acquire()
- for (sectionY in ProtocolDefinition.SECTION_MAX_Y downTo 0) {
- val state = section.blocks[x, sectionY, z] ?: continue
- val light = state.block.getLightProperties(state)
-
- if (light.skylightEnters && !light.filtersSkylight && light.propagatesLight(Directions.DOWN)) {
- // can go through block
- continue
- }
- y = (sectionIndex + chunk.minSection) * ProtocolDefinition.SECTION_HEIGHT_Y + sectionY
- if (!light.skylightEnters) {
- y++
- }
- section.release()
- break@sectionLoop
- }
- section.release()
- }
- val heightmapIndex = (z shl 4) or x
- heightmap[heightmapIndex] = y
- }
-
- private fun onHeightmapUpdate(x: Int, y: Int, z: Int, previous: Int, now: Int) {
- if (previous == now) {
- return
- }
-
- if (previous < y) {
- // block is now higher
- // ToDo: Neighbours
- val sections = chunk.sections
- val maxIndex = previous.sectionHeight - chunk.minSection
- val minIndex = now.sectionHeight - chunk.minSection
- bottom.reset()
- for (index in maxIndex downTo minIndex) {
- val section = sections[index] ?: continue
- section.light.reset()
- }
- for (index in maxIndex downTo minIndex) {
- val section = sections[index] ?: continue
- section.light.calculate()
- }
- calculateSkylight()
- } else if (previous > y && chunk.world.dimension.canSkylight()) {
- // block is lower
- startSkylightFloodFill(x, z)
- }
- }
-
- private fun recalculateHeightmap(x: Int, y: Int, z: Int, blockState: BlockState?) {
- if (!chunk.world.dimension.canSkylight()) {
- return
- }
- chunk.lock.lock()
- val index = (z shl 4) or x
-
- val current = heightmap[index]
-
- if (current > y + 1) {
- // our block is/was not the highest, ignore everything
- chunk.lock.unlock()
- return
- }
- if (blockState == null) {
- checkHeightmapY(x, y, z)
- chunk.lock.unlock()
- return
- }
-
- // we are the highest block now
- // check if light can pass
- val light = blockState.block.getLightProperties(blockState)
- if (!light.skylightEnters) {
- heightmap[index] = y + 1
- } else if (light.filtersSkylight || !light.propagatesLight(Directions.DOWN)) {
- heightmap[index] = y
- }
-
- chunk.lock.unlock()
- return
- }
-
- private fun calculateSkylight() {
+ fun calculateSkylight() {
if (!chunk.world.dimension.canSkylight() || !chunk.neighbours.complete) {
// no need to calculate it
return
@@ -400,6 +289,7 @@ class ChunkLight(private val chunk: Chunk) {
}
}
+ @Deprecated("heightmap")
inline fun getMaxHeight(x: Int, z: Int): Int {
return heightmap[(z shl 4) or x]
}