skylight: create section if not present, fix locking bugs

This commit is contained in:
Bixilon 2022-09-25 19:47:30 +02:00
parent 68af0e1f0f
commit 4f1add582d
No known key found for this signature in database
GPG Key ID: 5CAD791931B09AC4
2 changed files with 27 additions and 24 deletions

View File

@ -49,7 +49,7 @@ class Chunk(
var sections: Array<ChunkSection?>? = null, var sections: Array<ChunkSection?>? = null,
var biomeSource: BiomeSource? = null, var biomeSource: BiomeSource? = null,
) : Iterable<ChunkSection?>, BiomeAccessor { ) : Iterable<ChunkSection?>, BiomeAccessor {
private val lock = ThreadLock() private val lock = ThreadLock()
private val world = connection.world private val world = connection.world
var bottomLight = BorderSectionLight(false, this) var bottomLight = BorderSectionLight(false, this)
var topLight = BorderSectionLight(true, 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) fun setBlockEntity(position: Vec3i, blockEntity: BlockEntity?) = setBlockEntity(position.x, position.y, position.z, blockEntity)
@Synchronized private fun initialize() {
private fun initialize(): Array<ChunkSection?> { lock.lock()
val sections: Array<ChunkSection?> = arrayOfNulls(world.dimension!!.sections) this.sections = arrayOfNulls(world.dimension!!.sections)
this.sections = sections lock.unlock()
return sections
} }
@Synchronized
fun setData(data: ChunkData) { fun setData(data: ChunkData) {
lock.lock()
if (sections == null) { if (sections == null) {
initialize() initialize()
} }
@ -236,6 +235,7 @@ class Chunk(
biomesInitialized = true biomesInitialized = true
} }
} }
lock.unlock()
world.onChunkUpdate(chunkPosition, this) world.onChunkUpdate(chunkPosition, this)
connection.fireEvent(ChunkDataChangeEvent(connection, EventInitiators.UNKNOWN, chunkPosition, this)) connection.fireEvent(ChunkDataChangeEvent(connection, EventInitiators.UNKNOWN, chunkPosition, this))
} }
@ -440,9 +440,8 @@ class Chunk(
Broken("Can not get chunk from offset: $chunkOffset") Broken("Can not get chunk from offset: $chunkOffset")
} }
@Synchronized
private fun updateHeightmap() { private fun updateHeightmap() {
lock.lock()
val maxY = highestSection * ProtocolDefinition.SECTION_HEIGHT_Y val maxY = highestSection * ProtocolDefinition.SECTION_HEIGHT_Y
for (x in 0 until ProtocolDefinition.SECTION_WIDTH_X) { for (x in 0 until ProtocolDefinition.SECTION_WIDTH_X) {
@ -450,6 +449,7 @@ class Chunk(
checkHeightmapY(x, maxY, z) checkHeightmapY(x, maxY, z)
} }
} }
lock.unlock()
recalculateSkylight() recalculateSkylight()
} }
@ -506,18 +506,16 @@ class Chunk(
} }
private fun recalculateSkylight() { private fun recalculateSkylight() {
if (world.dimension?.hasSkyLight != true) { if (world.dimension?.hasSkyLight != true || this.neighbours == null) {
// no need to calculate it // no need to calculate it
return return
} }
lock.lock()
for (x in 0 until ProtocolDefinition.SECTION_WIDTH_X) { for (x in 0 until ProtocolDefinition.SECTION_WIDTH_X) {
for (z in 0 until ProtocolDefinition.SECTION_WIDTH_Z) { for (z in 0 until ProtocolDefinition.SECTION_WIDTH_Z) {
traceSkylightDown(x, z) traceSkylightDown(x, z)
startSkylightFloodFill(x, z) startSkylightFloodFill(x, z)
} }
} }
lock.unlock()
} }
private inline fun traceSkylightDown(x: Int, z: Int) { private inline fun traceSkylightDown(x: Int, z: Int) {

View File

@ -152,28 +152,28 @@ class SectionLight(
if (z > 0) { if (z > 0) {
traceIncrease(x, y, z - 1, neighbourLuminance, Directions.SOUTH) traceIncrease(x, y, z - 1, neighbourLuminance, Directions.SOUTH)
} else { } 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 (source == null || (source != Directions.SOUTH && block?.lightProperties?.propagatesLight(source, Directions.SOUTH) != false)) {
if (z < ProtocolDefinition.SECTION_MAX_Y) { if (z < ProtocolDefinition.SECTION_MAX_Y) {
traceIncrease(x, y, z + 1, neighbourLuminance, Directions.NORTH) traceIncrease(x, y, z + 1, neighbourLuminance, Directions.NORTH)
} else { } 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 (source == null || (source != Directions.WEST && block?.lightProperties?.propagatesLight(source, Directions.WEST) != false)) {
if (x > 0) { if (x > 0) {
traceIncrease(x - 1, y, z, neighbourLuminance, Directions.EAST) traceIncrease(x - 1, y, z, neighbourLuminance, Directions.EAST)
} else { } 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 (source == null || (source != Directions.EAST && block?.lightProperties?.propagatesLight(source, Directions.EAST) != false)) {
if (x < ProtocolDefinition.SECTION_MAX_X) { if (x < ProtocolDefinition.SECTION_MAX_X) {
traceIncrease(x + 1, y, z, neighbourLuminance, Directions.WEST) traceIncrease(x + 1, y, z, neighbourLuminance, Directions.WEST)
} else { } 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 (direction != Directions.UP && (direction == null || light.propagatesLight(direction, Directions.DOWN))) {
if (y > 0) { if (y > 0) {
traceSkylight(x, y - 1, z, nextNeighbourLevel, Directions.DOWN, totalY - 1, false) traceSkylight(x, y - 1, z, nextNeighbourLevel, Directions.DOWN, totalY - 1, false)
} else { } else if (section.sectionHeight != section.chunk?.highestSection) {
neighbours[Directions.O_UP]?.light?.traceSkylight(x, 0, z, nextLevel, direction, totalY, false) (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 (direction != Directions.DOWN && direction != null && (light.propagatesLight(direction, Directions.UP))) {
if (y < ProtocolDefinition.SECTION_MAX_Y) { if (y < ProtocolDefinition.SECTION_MAX_Y) {
traceSkylight(x, y + 1, z, nextNeighbourLevel, Directions.UP, totalY + 1, false) traceSkylight(x, y + 1, z, nextNeighbourLevel, Directions.UP, totalY + 1, false)
} else { } else if (section.sectionHeight == section.chunk?.lowestSection) {
// ToDo: Trace through bottom light // 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 (direction != Directions.NORTH && (direction == null || light.propagatesLight(direction, Directions.SOUTH))) {
if (z > 0) { if (z > 0) {
traceSkylight(x, y, z - 1, nextNeighbourLevel, Directions.SOUTH, totalY, false) traceSkylight(x, y, z - 1, nextNeighbourLevel, Directions.SOUTH, totalY, false)
} else { } 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 (direction != Directions.SOUTH && (direction == null || light.propagatesLight(direction, Directions.NORTH))) {
if (z < ProtocolDefinition.SECTION_MAX_Z) { if (z < ProtocolDefinition.SECTION_MAX_Z) {
traceSkylight(x, y, z + 1, nextNeighbourLevel, Directions.NORTH, totalY, false) traceSkylight(x, y, z + 1, nextNeighbourLevel, Directions.NORTH, totalY, false)
} else { } 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 (direction != Directions.WEST && (direction == null || light.propagatesLight(direction, Directions.EAST))) {
if (x > 0) { if (x > 0) {
traceSkylight(x - 1, y, z, nextNeighbourLevel, Directions.EAST, totalY, false) traceSkylight(x - 1, y, z, nextNeighbourLevel, Directions.EAST, totalY, false)
} else { } 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 (direction != Directions.EAST && (direction == null || light.propagatesLight(direction, Directions.WEST))) {
if (x < ProtocolDefinition.SECTION_MAX_X) { if (x < ProtocolDefinition.SECTION_MAX_X) {
traceSkylight(x + 1, y, z, nextNeighbourLevel, Directions.WEST, totalY, false) traceSkylight(x + 1, y, z, nextNeighbourLevel, Directions.WEST, totalY, false)
} else { } 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<ChunkSection?>.get(direction: Int, neighbour: Int): ChunkSection? {
return this[direction] ?: section.chunk?.neighbours?.get(neighbour)?.getOrPut(section.sectionHeight, false)
}
companion object { companion object {
const val BLOCK_LIGHT_MASK = 0x0F const val BLOCK_LIGHT_MASK = 0x0F
const val SKY_LIGHT_MASK = 0xF0 const val SKY_LIGHT_MASK = 0xF0