basic block light engine

This commit is contained in:
Bixilon 2022-06-18 11:44:27 +02:00
parent a7ab19277b
commit decee49071
No known key found for this signature in database
GPG Key ID: 5CAD791931B09AC4
4 changed files with 92 additions and 6 deletions

View File

@ -16,6 +16,7 @@ import de.bixilon.kutil.cast.CastUtil.unsafeCast
import de.bixilon.kutil.json.JsonUtil.toJsonObject
import de.bixilon.kutil.primitive.BooleanUtil.toBoolean
import de.bixilon.kutil.primitive.FloatUtil.toFloat
import de.bixilon.kutil.primitive.IntUtil.toInt
import de.bixilon.minosoft.data.registries.ResourceLocation
import de.bixilon.minosoft.data.registries.VoxelShape
import de.bixilon.minosoft.data.registries.blocks.properties.BlockProperties
@ -34,6 +35,7 @@ data class BlockState(
val hardness: Float,
val requiresTool: Boolean,
val isSolid: Boolean,
val luminance: Byte,
) {
var blockModel: BakedBlockModel? = null
@ -131,6 +133,7 @@ data class BlockState(
hardness = data["hardness"]?.toFloat() ?: 1.0f,
requiresTool = data["requires_tool"]?.toBoolean() ?: material.soft,
isSolid = data["solid_render"]?.toBoolean() ?: false,
luminance = data["luminance"]?.toInt()?.toByte() ?: 0,
)
}

View File

@ -78,8 +78,17 @@ class Chunk(
fun set(x: Int, y: Int, z: Int, blockState: BlockState?, blockEntity: BlockEntity? = null) {
val section = getOrPut(y.sectionHeight) ?: return
section.blocks[x, y.inSectionHeight, z] = blockState
section.blockEntities[x, y.inSectionHeight, z] = blockEntity // ToDo
val inSectionHeight = y.inSectionHeight
val previous = section.blocks.set(x, inSectionHeight, z, blockState)
section.blockEntities[x, inSectionHeight, z] = blockEntity // ToDo
val previousLuminance = previous?.luminance ?: 0
val luminance = blockState?.luminance ?: 0
if (luminance > previousLuminance) {
section.onLightIncrease(x, inSectionHeight, z, luminance)
} else if (previousLuminance > luminance) {
section.onLightDecrease(x, inSectionHeight, z, luminance)
}
}
operator fun set(position: Vec3i, blockState: BlockState?) = set(position.x, position.y, position.z, blockState)

View File

@ -28,11 +28,16 @@ import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition
* Collection of 16x16x16 blocks
*/
class ChunkSection(
var blocks: BlockSectionDataProvider,
blocks: BlockSectionDataProvider,
var biomes: SectionDataProvider<Biome> = SectionDataProvider(checkSize = false),
var blockEntities: SectionDataProvider<BlockEntity?> = SectionDataProvider(checkSize = false),
var light: ByteArray = ByteArray(ProtocolDefinition.BLOCKS_PER_SECTION) { 0xFF.toByte() }, // packed (skyLight: 0xF0, blockLight: 0x0F)
var light: ByteArray = ByteArray(ProtocolDefinition.BLOCKS_PER_SECTION) { 0x00.toByte() }, // packed (skyLight: 0xF0, blockLight: 0x0F)
) {
var blocks = blocks
set(value) {
field = value
recalculateLight()
}
fun tick(connection: PlayConnection, chunkPosition: Vec2i, sectionHeight: Int) {
if (blockEntities.isEmpty) {
@ -98,4 +103,73 @@ class ChunkSection(
}
this.biomes.setData(biomes.unsafeCast())
}
fun onLightDecrease(x: Int, y: Int, z: Int, luminance: Byte) {
// ToDo: make faster, set light to 0 and trace to next night increase. then backtrace
recalculateLight()
}
fun onLightIncrease(x: Int, y: Int, z: Int, luminance: Byte) {
traceLightIncrease(x, y, z, luminance)
}
private fun traceLightIncrease(x: Int, y: Int, z: Int, nextLuminance: Byte) {
val index = getIndex(x, y, z)
val block = blocks.unsafeGet(index)
if (block != null && block.luminance == 0.toByte() && block.isSolid) {
// light can not pass through the block
return
}
// get block or next luminance level
var luminance = nextLuminance
val currentLuminance = block?.luminance ?: nextLuminance
if (currentLuminance > luminance) {
luminance = currentLuminance
}
val currentLight = light[index].toInt() and 0x0F // we just care about block light
if (currentLight >= luminance) {
// light is already higher, no need to trace
return
}
light[index] = luminance
val neighbourLuminance = (luminance - 1).toByte()
if (neighbourLuminance == 0.toByte()) {
// luminance is 1, we can not further increase the light
return
}
// ToDo: check neighbours and trace there
if (x > 0) traceLightIncrease(x - 1, y, z, neighbourLuminance)
if (x < ProtocolDefinition.SECTION_MAX_X) traceLightIncrease(x + 1, y, z, neighbourLuminance)
if (y > 0) traceLightIncrease(x, y - 1, z, neighbourLuminance)
if (y < ProtocolDefinition.SECTION_MAX_Y) traceLightIncrease(x, y + 1, z, neighbourLuminance)
if (z > 0) traceLightIncrease(x, y, z - 1, neighbourLuminance)
if (z < ProtocolDefinition.SECTION_MAX_Y) traceLightIncrease(x, y, z + 1, neighbourLuminance)
}
fun recalculateLight() {
// clear light
for (index in light.indices) {
light[index] = 0x00.toByte()
}
blocks.acquire()
for (y in 0 until ProtocolDefinition.SECTION_HEIGHT_Y) {
for (z in 0 until ProtocolDefinition.SECTION_WIDTH_Z) {
for (x in 0 until ProtocolDefinition.SECTION_WIDTH_X) {
val index = getIndex(x, y, z)
val luminance = blocks.unsafeGet(index)?.luminance ?: continue
if (luminance == 0.toByte()) {
// block is not emitting light, ignore it
continue
}
traceLightIncrease(x, y, z, luminance)
}
}
}
blocks.release()
}
}

View File

@ -126,8 +126,8 @@ open class SectionDataProvider<T>(
return get(y shl 8 or (z shl 4) or x)
}
operator fun set(x: Int, y: Int, z: Int, value: T) {
set(y shl 8 or (z shl 4) or x, value)
operator fun set(x: Int, y: Int, z: Int, value: T): T? {
return set(y shl 8 or (z shl 4) or x, value)
}
open operator fun set(index: Int, value: T): T? {