From 4f1add582dd8efcf992ced19c384d640cadb28bb Mon Sep 17 00:00:00 2001 From: Bixilon Date: Sun, 25 Sep 2022 19:47:30 +0200 Subject: [PATCH] skylight: create section if not present, fix locking bugs --- .../minosoft/data/world/chunk/Chunk.kt | 22 +++++++------- .../data/world/chunk/light/SectionLight.kt | 29 +++++++++++-------- 2 files changed, 27 insertions(+), 24 deletions(-) diff --git a/src/main/java/de/bixilon/minosoft/data/world/chunk/Chunk.kt b/src/main/java/de/bixilon/minosoft/data/world/chunk/Chunk.kt index 5618d17cf..28406bd7c 100644 --- a/src/main/java/de/bixilon/minosoft/data/world/chunk/Chunk.kt +++ b/src/main/java/de/bixilon/minosoft/data/world/chunk/Chunk.kt @@ -49,7 +49,7 @@ class Chunk( var sections: Array? = null, var biomeSource: BiomeSource? = null, ) : Iterable, BiomeAccessor { - private val lock = ThreadLock() + private val lock = ThreadLock() private val world = connection.world var bottomLight = BorderSectionLight(false, this) var topLight = BorderSectionLight(true, this) @@ -192,16 +192,15 @@ class Chunk( fun setBlockEntity(position: Vec3i, blockEntity: BlockEntity?) = setBlockEntity(position.x, position.y, position.z, blockEntity) - @Synchronized - private fun initialize(): Array { - val sections: Array = arrayOfNulls(world.dimension!!.sections) - this.sections = sections - return sections + private fun initialize() { + lock.lock() + this.sections = arrayOfNulls(world.dimension!!.sections) + lock.unlock() } - @Synchronized fun setData(data: ChunkData) { + lock.lock() if (sections == null) { initialize() } @@ -236,6 +235,7 @@ class Chunk( biomesInitialized = true } } + lock.unlock() world.onChunkUpdate(chunkPosition, this) connection.fireEvent(ChunkDataChangeEvent(connection, EventInitiators.UNKNOWN, chunkPosition, this)) } @@ -440,9 +440,8 @@ class Chunk( Broken("Can not get chunk from offset: $chunkOffset") } - - @Synchronized private fun updateHeightmap() { + lock.lock() val maxY = highestSection * ProtocolDefinition.SECTION_HEIGHT_Y for (x in 0 until ProtocolDefinition.SECTION_WIDTH_X) { @@ -450,6 +449,7 @@ class Chunk( checkHeightmapY(x, maxY, z) } } + lock.unlock() recalculateSkylight() } @@ -506,18 +506,16 @@ class Chunk( } private fun recalculateSkylight() { - if (world.dimension?.hasSkyLight != true) { + if (world.dimension?.hasSkyLight != true || this.neighbours == null) { // no need to calculate it return } - lock.lock() for (x in 0 until ProtocolDefinition.SECTION_WIDTH_X) { for (z in 0 until ProtocolDefinition.SECTION_WIDTH_Z) { traceSkylightDown(x, z) startSkylightFloodFill(x, z) } } - lock.unlock() } private inline fun traceSkylightDown(x: Int, z: Int) { 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 b3cdbbd90..16ce78085 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 @@ -152,28 +152,28 @@ class SectionLight( if (z > 0) { traceIncrease(x, y, z - 1, neighbourLuminance, Directions.SOUTH) } else { - (neighbours[Directions.O_NORTH] ?: section.chunk?.neighbours?.get(ChunkNeighbours.NORTH)?.getOrPut(section.sectionHeight - 1, false))?.light?.traceIncrease(x, y, ProtocolDefinition.SECTION_MAX_Z, neighbourLuminance, Directions.SOUTH) + neighbours[Directions.O_NORTH, ChunkNeighbours.NORTH]?.light?.traceIncrease(x, y, ProtocolDefinition.SECTION_MAX_Z, neighbourLuminance, Directions.SOUTH) } } if (source == null || (source != Directions.SOUTH && block?.lightProperties?.propagatesLight(source, Directions.SOUTH) != false)) { if (z < ProtocolDefinition.SECTION_MAX_Y) { traceIncrease(x, y, z + 1, neighbourLuminance, Directions.NORTH) } else { - (neighbours[Directions.O_SOUTH] ?: section.chunk?.neighbours?.get(ChunkNeighbours.SOUTH)?.getOrPut(section.sectionHeight, false))?.light?.traceIncrease(x, y, 0, neighbourLuminance, Directions.NORTH) + neighbours[Directions.O_SOUTH, ChunkNeighbours.SOUTH]?.light?.traceIncrease(x, y, 0, neighbourLuminance, Directions.NORTH) } } if (source == null || (source != Directions.WEST && block?.lightProperties?.propagatesLight(source, Directions.WEST) != false)) { if (x > 0) { traceIncrease(x - 1, y, z, neighbourLuminance, Directions.EAST) } else { - (neighbours[Directions.O_WEST] ?: section.chunk?.neighbours?.get(ChunkNeighbours.WEST)?.getOrPut(section.sectionHeight, false))?.light?.traceIncrease(ProtocolDefinition.SECTION_MAX_X, y, z, neighbourLuminance, Directions.EAST) + neighbours[Directions.O_WEST, ChunkNeighbours.WEST]?.light?.traceIncrease(ProtocolDefinition.SECTION_MAX_X, y, z, neighbourLuminance, Directions.EAST) } } if (source == null || (source != Directions.EAST && block?.lightProperties?.propagatesLight(source, Directions.EAST) != false)) { if (x < ProtocolDefinition.SECTION_MAX_X) { traceIncrease(x + 1, y, z, neighbourLuminance, Directions.WEST) } else { - (neighbours[Directions.O_EAST] ?: section.chunk?.neighbours?.get(ChunkNeighbours.EAST)?.getOrPut(section.sectionHeight, false))?.light?.traceIncrease(0, y, z, neighbourLuminance, Directions.WEST) + neighbours[Directions.O_EAST, ChunkNeighbours.EAST]?.light?.traceIncrease(0, y, z, neighbourLuminance, Directions.WEST) } } } @@ -265,48 +265,53 @@ class SectionLight( if (direction != Directions.UP && (direction == null || light.propagatesLight(direction, Directions.DOWN))) { if (y > 0) { traceSkylight(x, y - 1, z, nextNeighbourLevel, Directions.DOWN, totalY - 1, false) - } else { - neighbours[Directions.O_UP]?.light?.traceSkylight(x, 0, z, nextLevel, direction, totalY, false) + } else if (section.sectionHeight != section.chunk?.highestSection) { + (neighbours[Directions.O_UP] ?: section.chunk?.getOrPut(section.sectionHeight + 1, false))?.light?.traceSkylight(x, 0, z, nextLevel, direction, totalY, false) } } if (direction != Directions.DOWN && direction != null && (light.propagatesLight(direction, Directions.UP))) { if (y < ProtocolDefinition.SECTION_MAX_Y) { traceSkylight(x, y + 1, z, nextNeighbourLevel, Directions.UP, totalY + 1, false) - } else { + } else if (section.sectionHeight == section.chunk?.lowestSection) { // ToDo: Trace through bottom light - neighbours[Directions.O_DOWN]?.light?.traceSkylight(x, ProtocolDefinition.SECTION_MAX_Y, z, nextLevel, direction, totalY, false) + } else { + (neighbours[Directions.O_DOWN] ?: section.chunk?.getOrPut(section.sectionHeight - 1, false))?.light?.traceSkylight(x, ProtocolDefinition.SECTION_MAX_Y, z, nextLevel, direction, totalY, false) } } if (direction != Directions.NORTH && (direction == null || light.propagatesLight(direction, Directions.SOUTH))) { if (z > 0) { traceSkylight(x, y, z - 1, nextNeighbourLevel, Directions.SOUTH, totalY, false) } else { - neighbours[Directions.O_NORTH]?.light?.traceSkylight(x, y, ProtocolDefinition.SECTION_MAX_Z, nextNeighbourLevel, Directions.SOUTH, totalY, false) + neighbours[Directions.O_NORTH, ChunkNeighbours.NORTH]?.light?.traceSkylight(x, y, ProtocolDefinition.SECTION_MAX_Z, nextNeighbourLevel, Directions.SOUTH, totalY, false) } } if (direction != Directions.SOUTH && (direction == null || light.propagatesLight(direction, Directions.NORTH))) { if (z < ProtocolDefinition.SECTION_MAX_Z) { traceSkylight(x, y, z + 1, nextNeighbourLevel, Directions.NORTH, totalY, false) } else { - neighbours[Directions.O_SOUTH]?.light?.traceSkylight(x, y, 0, nextNeighbourLevel, Directions.NORTH, totalY, false) + neighbours[Directions.O_SOUTH, ChunkNeighbours.SOUTH]?.light?.traceSkylight(x, y, 0, nextNeighbourLevel, Directions.NORTH, totalY, false) } } if (direction != Directions.WEST && (direction == null || light.propagatesLight(direction, Directions.EAST))) { if (x > 0) { traceSkylight(x - 1, y, z, nextNeighbourLevel, Directions.EAST, totalY, false) } else { - neighbours[Directions.O_WEST]?.light?.traceSkylight(ProtocolDefinition.SECTION_MAX_X, y, z, nextLevel, direction, totalY, false) + neighbours[Directions.O_WEST, ChunkNeighbours.WEST]?.light?.traceSkylight(ProtocolDefinition.SECTION_MAX_X, y, z, nextLevel, direction, totalY, false) } } if (direction != Directions.EAST && (direction == null || light.propagatesLight(direction, Directions.WEST))) { if (x < ProtocolDefinition.SECTION_MAX_X) { traceSkylight(x + 1, y, z, nextNeighbourLevel, Directions.WEST, totalY, false) } else { - neighbours[Directions.O_EAST]?.light?.traceSkylight(0, y, z, nextLevel, direction, totalY, false) + neighbours[Directions.O_EAST, ChunkNeighbours.EAST]?.light?.traceSkylight(0, y, z, nextLevel, direction, totalY, false) } } } + private operator fun Array.get(direction: Int, neighbour: Int): ChunkSection? { + return this[direction] ?: section.chunk?.neighbours?.get(neighbour)?.getOrPut(section.sectionHeight, false) + } + companion object { const val BLOCK_LIGHT_MASK = 0x0F const val SKY_LIGHT_MASK = 0xF0