mirror of
https://gitlab.bixilon.de/bixilon/minosoft.git
synced 2025-09-18 11:54:59 -04:00
basic block light engine
This commit is contained in:
parent
a7ab19277b
commit
decee49071
@ -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,
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
@ -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? {
|
||||
|
Loading…
x
Reference in New Issue
Block a user