fix some merge bugs, fix some biome bugs

This commit is contained in:
Bixilon 2021-11-15 10:33:14 +01:00
parent 8d99db5376
commit 6032900b42
No known key found for this signature in database
GPG Key ID: 5CAD791931B09AC4
11 changed files with 45 additions and 109 deletions

View File

@ -18,18 +18,14 @@ import de.bixilon.minosoft.data.registries.blocks.BlockState
import de.bixilon.minosoft.data.world.ChunkSection.Companion.index
import de.bixilon.minosoft.data.world.biome.accessor.BiomeAccessor
import de.bixilon.minosoft.data.world.biome.source.BiomeSource
import de.bixilon.minosoft.data.world.light.LightAccessor
import de.bixilon.minosoft.gui.rendering.util.VecUtil.chunkPosition
import de.bixilon.minosoft.gui.rendering.util.VecUtil.inChunkSectionPosition
import de.bixilon.minosoft.gui.rendering.util.VecUtil.sectionHeight
import de.bixilon.minosoft.modding.event.EventInitiators
import de.bixilon.minosoft.modding.event.events.ChunkDataChangeEvent
import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3iUtil.EMPTY
import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection
import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition
import de.bixilon.minosoft.util.KUtil.unsafeCast
import de.bixilon.minosoft.util.logging.Log
import de.bixilon.minosoft.util.logging.LogLevels
import de.bixilon.minosoft.util.logging.LogMessageType
import glm_.vec2.Vec2i
import glm_.vec3.Vec3i
@ -42,11 +38,12 @@ class Chunk(
private var sections: Array<ChunkSection?>? = null,
var biomeSource: BiomeSource? = null,
) : Iterable<ChunkSection?>, BiomeAccessor {
private val world = connection.world
var bottomLight: IntArray? = null
var topLight: IntArray? = null
val lowestSection = connection.world.dimension!!.lowestSection
val highestSection = connection.world.dimension!!.highestSection
val cacheBiomes = connection.world.cacheBiomeAccessor != null
val lowestSection = world.dimension!!.lowestSection
val highestSection = world.dimension!!.highestSection
val cacheBiomes = world.cacheBiomeAccessor != null
var blocksInitialized = false // All block data was received
var biomesInitialized = false // All biome data is initialized (aka. cache built, or similar)
@ -95,7 +92,7 @@ class Chunk(
@Synchronized
private fun initialize(): Array<ChunkSection?> {
val sections: Array<ChunkSection?> = arrayOfNulls(connection.world.dimension!!.sections)
val sections: Array<ChunkSection?> = arrayOfNulls(world.dimension!!.sections)
this.sections = sections
return sections
}
@ -141,7 +138,7 @@ class Chunk(
biomesInitialized = true
}
}
connection.world.onChunkUpdate(chunkPosition, this)
world.onChunkUpdate(chunkPosition, this)
connection.fireEvent(ChunkDataChangeEvent(connection, EventInitiators.UNKNOWN, chunkPosition, this))
}
@ -153,10 +150,10 @@ class Chunk(
var section = sections[sectionIndex]
if (section == null) {
section = ChunkSection(connection.registries)
val neighbours: Array<Chunk> = connection.world.getChunkNeighbours(chunkPosition).unsafeCast()
val cacheBiomeAccessor = connection.world.cacheBiomeAccessor
val neighbours: Array<Chunk> = world.getChunkNeighbours(chunkPosition).unsafeCast()
val cacheBiomeAccessor = world.cacheBiomeAccessor
if (cacheBiomeAccessor != null && biomesInitialized && neighboursLoaded) {
section.buildBiomeCache(chunkPosition, sectionHeight, this, neighbours, cacheBiomeAccessor)
section.buildBiomeCache(chunkPosition, sectionHeight, this, neighbours, cacheBiomeAccessor, world)
}
sections[sectionIndex] = section
}
@ -187,7 +184,6 @@ class Chunk(
}
fun buildBiomeCache() {
val start = System.nanoTime()
val cacheBiomeAccessor = connection.world.cacheBiomeAccessor ?: return
check(!biomesInitialized) { "Biome cache already initialized!" }
check(cacheBiomes) { "Cache is disabled!" }
@ -199,11 +195,9 @@ class Chunk(
for ((sectionIndex, section) in sections!!.withIndex()) {
section ?: continue
val sectionHeight = sectionIndex + lowestSection
section.buildBiomeCache(chunkPosition, sectionHeight, this, neighbours, cacheBiomeAccessor)
section.buildBiomeCache(chunkPosition, sectionHeight, this, neighbours, cacheBiomeAccessor, world)
}
biomesInitialized = true
val delta = System.nanoTime() - start
Log.log(LogMessageType.VERSION_LOADING, LogLevels.VERBOSE) { "Took ${delta}ns, ${delta / 1000}µs, ${delta / 1000_000}ms" }
}
override fun iterator(): Iterator<ChunkSection?> {
@ -213,7 +207,13 @@ class Chunk(
override fun getBiome(x: Int, y: Int, z: Int): Biome? {
if (cacheBiomes) {
val sectionHeight = y.sectionHeight
return get(sectionHeight)?.biomes?.get(x, sectionHeight, z)
val section = this[sectionHeight]
if (section == null) {
// ToDo: Faster
val chunkPosition = Vec3i(x, y, z).chunkPosition
return connection.world.cacheBiomeAccessor?.getBiome(x, y, z, chunkPosition.x, chunkPosition.y, this, null, world)
}
return section.biomes[x, y % ProtocolDefinition.SECTION_HEIGHT_Y, z]
}
return biomeSource?.getBiome(x and 0x0F, y, z and 0x0F)
}

View File

@ -89,7 +89,7 @@ class ChunkSection(
}
}
fun buildBiomeCache(chunkPosition: Vec2i, sectionHeight: Int, chunk: Chunk, neighbours: Array<Chunk>, biomeAccessor: NoiseBiomeAccessor) {
fun buildBiomeCache(chunkPosition: Vec2i, sectionHeight: Int, chunk: Chunk, neighbours: Array<Chunk>, biomeAccessor: NoiseBiomeAccessor, world: World) {
val chunkPositionX = chunkPosition.x
val chunkPositionZ = chunkPosition.y
val blockOffset = Vec3i.of(chunkPosition, sectionHeight)
@ -98,7 +98,7 @@ class ChunkSection(
val z = blockOffset.z
val biomes: Array<Biome?> = arrayOfNulls(ProtocolDefinition.BLOCKS_PER_SECTION)
for (index in 0 until ProtocolDefinition.BLOCKS_PER_SECTION) {
biomes[index] = biomeAccessor.getBiome(x + (index and 0x0F), y + ((index shr 8) and 0x0F), z + ((index shr 4) and 0x0F), chunkPositionX, chunkPositionZ, chunk, neighbours) //!!
biomes[index] = biomeAccessor.getBiome(x + (index and 0x0F), y + ((index shr 8) and 0x0F), z + ((index shr 4) and 0x0F), chunkPositionX, chunkPositionZ, chunk, neighbours, world) //!!
}
this.biomes.setData(biomes.unsafeCast())
}

View File

@ -22,7 +22,7 @@ import de.bixilon.minosoft.data.world.biome.source.SpatialBiomeArray
class NoiseBiomeAccessor(private val world: World) {
fun getBiome(x: Int, y: Int, z: Int, chunkPositionX: Int, chunkPositionZ: Int, chunk: Chunk, neighbours: Array<Chunk>): Biome? {
fun getBiome(x: Int, y: Int, z: Int, chunkPositionX: Int, chunkPositionZ: Int, chunk: Chunk, neighbours: Array<Chunk>?, world: World): Biome? {
val biomeY = if (world.dimension?.supports3DBiomes == true) {
y
} else {
@ -40,6 +40,6 @@ class NoiseBiomeAccessor(private val world: World) {
return null
}
return FuzzyNoiseBiomeCalculator.getBiome(world.hashedSeed, x, biomeY, z, chunkPositionX, chunkPositionZ, chunk, neighbours)
return FuzzyNoiseBiomeCalculator.getBiome(world.hashedSeed, x, biomeY, z, chunkPositionX, chunkPositionZ, chunk, neighbours, world)
}
}

View File

@ -2,11 +2,13 @@ package de.bixilon.minosoft.data.world.biome.noise
import de.bixilon.minosoft.data.registries.biomes.Biome
import de.bixilon.minosoft.data.world.Chunk
import de.bixilon.minosoft.data.world.World
import de.bixilon.minosoft.util.MMath.square
import glm_.vec2.Vec2i
object FuzzyNoiseBiomeCalculator {
fun getBiome(seed: Long, x: Int, y: Int, z: Int, chunkPositionX: Int, chunkPositionZ: Int, chunk: Chunk, neighbours: Array<Chunk>): Biome? {
fun getBiome(seed: Long, x: Int, y: Int, z: Int, chunkPositionX: Int, chunkPositionZ: Int, chunk: Chunk, neighbours: Array<Chunk>?, world: World): Biome? {
val m = x - 2
val n = y - 2
val o = z - 2
@ -69,6 +71,10 @@ object FuzzyNoiseBiomeCalculator {
val biomeChunkX = biomeX shr 2
val biomeChunkZ = biomeZ shr 2
if (neighbours == null) {
return world[Vec2i(biomeChunkX, biomeChunkZ)]?.biomeSource?.getBiome(biomeX, biomeY, biomeZ)
}
val deltaChunkX = biomeChunkX - chunkPositionX
val deltaChunkZ = biomeChunkZ - chunkPositionZ

View File

@ -43,6 +43,8 @@ import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection
import de.bixilon.minosoft.util.KUtil.synchronizedSetOf
import de.bixilon.minosoft.util.KUtil.toResourceLocation
import de.bixilon.minosoft.util.KUtil.unsafeCast
import de.bixilon.minosoft.util.chunk.ChunkUtil
import de.bixilon.minosoft.util.chunk.ChunkUtil.fullyLoaded
import de.bixilon.minosoft.util.logging.Log
import de.bixilon.minosoft.util.logging.LogLevels
import de.bixilon.minosoft.util.logging.LogMessageType
@ -117,7 +119,7 @@ class WorldRenderer(
if (!chunk.isFullyLoaded || it.chunkPosition in incomplete) {
return@of
}
val neighbourChunks = getChunkNeighbours(getChunkNeighbourPositions(it.chunkPosition))
val neighbourChunks = world.getChunkNeighbours(it.chunkPosition)
if (!neighbourChunks.fullyLoaded) {
return@of
}
@ -155,7 +157,7 @@ class WorldRenderer(
private fun unloadChunk(chunkPosition: Vec2i) {
incomplete -= chunkPosition
renderWindow.queue += { queue.remove(chunkPosition) }
for (neighbourPosition in getChunkNeighbourPositions(chunkPosition)) {
for (neighbourPosition in ChunkUtil.getChunkNeighbourPositions(chunkPosition)) {
renderWindow.queue += { queue.remove(neighbourPosition) }
world[neighbourPosition] ?: continue // if chunk is not loaded, we don't need to add it to incomplete
incomplete += neighbourPosition
@ -185,58 +187,6 @@ class WorldRenderer(
mesh.transparentMesh?.let { visibleTransparent += it }
}
/**
* @return All 8 fully loaded neighbour chunks or null
*/
private fun getChunkNeighbours(neighbourPositions: Array<Vec2i>): Array<Chunk?> {
val chunks: Array<Chunk?> = arrayOfNulls(neighbourPositions.size)
for ((index, neighbourPosition) in neighbourPositions.withIndex()) {
val chunk = world[neighbourPosition] ?: continue
if (!chunk.isFullyLoaded) {
continue
}
chunks[index] = chunk
}
return chunks
}
private fun getChunkNeighbourPositions(chunkPosition: Vec2i): Array<Vec2i> {
return arrayOf(
chunkPosition + Vec2i(-1, -1),
chunkPosition + Vec2i(-1, 0),
chunkPosition + Vec2i(-1, 1),
chunkPosition + Vec2i(0, -1),
chunkPosition + Vec2i(0, 1),
chunkPosition + Vec2i(1, -1),
chunkPosition + Vec2i(1, 0),
chunkPosition + Vec2i(1, 1),
)
}
/**
* @param neighbourChunks: **Fully loaded** neighbour chunks
*/
private fun getSectionNeighbours(neighbourChunks: Array<Chunk>, chunk: Chunk, sectionHeight: Int): Array<ChunkSection?> {
val sections = chunk.sections!!
return arrayOf(
sections[sectionHeight - 1],
sections[sectionHeight + 1],
neighbourChunks[3].sections!![sectionHeight],
neighbourChunks[4].sections!![sectionHeight],
neighbourChunks[1].sections!![sectionHeight],
neighbourChunks[6].sections!![sectionHeight],
)
}
private val Array<Chunk?>.fullyLoaded: Boolean
get() {
for (neighbour in this) {
if (neighbour?.isFullyLoaded != true) {
return false
}
}
return true
}
/**
* Called when chunk data changes
@ -246,8 +196,8 @@ class WorldRenderer(
if (!chunk.isFullyLoaded) {
return
}
val neighbourPositions = getChunkNeighbourPositions(chunkPosition)
val neighbourChunks = getChunkNeighbours(neighbourPositions)
val neighbourPositions = ChunkUtil.getChunkNeighbourPositions(chunkPosition)
val neighbourChunks = world.getChunkNeighbours(neighbourPositions)
if (checkQueue) {
for ((index, neighbourPosition) in neighbourPositions.withIndex()) {
@ -267,7 +217,8 @@ class WorldRenderer(
renderWindow.queue += {
val meshes = this.meshes.getOrPut(chunkPosition) { mutableMapOf() }
for (sectionHeight in chunk.sections!!.keys) {
for (sectionHeight in chunk.lowestSection until chunk.highestSection) {
chunk[sectionHeight] ?: continue
updateSection(chunkPosition, sectionHeight, chunk, neighbourChunks.unsafeCast(), meshes)
}
}
@ -277,7 +228,7 @@ class WorldRenderer(
val task = ThreadPoolRunnable(priority = LOW, interuptable = false) {
try {
updateSectionSync(chunkPosition, sectionHeight, chunk, neighbourChunks ?: getChunkNeighbours(getChunkNeighbourPositions(chunkPosition)).unsafeCast(), meshes)
updateSectionSync(chunkPosition, sectionHeight, chunk, neighbourChunks ?: world.getChunkNeighbours(chunkPosition).unsafeCast(), meshes)
} catch (exception: InterruptedException) {
Log.log(LogMessageType.RENDERING_GENERAL, LogLevels.WARN) { exception.message!! }
}
@ -291,7 +242,7 @@ class WorldRenderer(
// chunk not loaded and/or neighbours also not fully loaded
return
}
val section = chunk.sections!![sectionHeight] ?: return
val section = chunk[sectionHeight] ?: return
val visible = isChunkVisible(chunkPosition, sectionHeight, Vec3i.EMPTY, Vec3i(16, 16, 16)) // ToDo: min/maxPosition
@ -315,7 +266,7 @@ class WorldRenderer(
}
}
}
val neighbours = getSectionNeighbours(neighbourChunks, chunk, sectionHeight)
val neighbours = ChunkUtil.getSectionNeighbours(neighbourChunks, chunk, sectionHeight)
prepareSection(chunkPosition, sectionHeight, section, neighbours, meshes)
} else {
renderWindow.queue += { queue.getOrPut(chunkPosition) { mutableSetOf() } += sectionHeight }
@ -416,7 +367,7 @@ class WorldRenderer(
removeFromQueue += chunkPosition
continue
}
val neighbours = getChunkNeighbours(getChunkNeighbourPositions(chunkPosition))
val neighbours = world.getChunkNeighbours(chunkPosition)
val meshes = this.meshes.getOrPut(chunkPosition) { mutableMapOf() }
for (sectionHeight in sectionHeights) {
updateSection(chunkPosition, sectionHeight, chunk, neighbours.unsafeCast(), meshes)

View File

@ -15,7 +15,6 @@ package de.bixilon.minosoft.gui.rendering.models.baked
import de.bixilon.minosoft.data.direction.Directions
import de.bixilon.minosoft.data.registries.blocks.BlockState
import de.bixilon.minosoft.data.world.light.LightAccessor
import de.bixilon.minosoft.gui.rendering.block.mesh.ChunkSectionMeshes
import de.bixilon.minosoft.gui.rendering.models.FaceProperties
import de.bixilon.minosoft.gui.rendering.models.baked.block.BakedBlockModel
@ -31,10 +30,6 @@ class MultipartBakedModel(
return sizes[direction.ordinal]
}
override fun getLight(position: Vec3i, random: Random, side: Directions, lightAccessor: LightAccessor): Int {
return 0xFF
}
override fun singleRender(position: Vec3i, mesh: ChunkSectionMeshes, random: Random, blockState: BlockState, neighbours: Array<BlockState?>, light: Int, ambientLight: FloatArray): Boolean {
var rendered = false
for (model in models) {

View File

@ -15,7 +15,6 @@ package de.bixilon.minosoft.gui.rendering.models.baked
import de.bixilon.minosoft.data.direction.Directions
import de.bixilon.minosoft.data.registries.blocks.BlockState
import de.bixilon.minosoft.data.world.light.LightAccessor
import de.bixilon.minosoft.gui.rendering.block.mesh.ChunkSectionMeshes
import de.bixilon.minosoft.gui.rendering.models.FaceProperties
import de.bixilon.minosoft.gui.rendering.models.baked.block.BakedBlockModel
@ -56,10 +55,6 @@ class WeightedBakedModel(
throw IllegalStateException("Could not find a model: This should never happen!")
}
override fun getLight(position: Vec3i, random: Random, side: Directions, lightAccessor: LightAccessor): Int {
return getModel(random).getLight(position, random, side, lightAccessor)
}
override fun singleRender(position: Vec3i, mesh: ChunkSectionMeshes, random: Random, blockState: BlockState, neighbours: Array<BlockState?>, light: Int, ambientLight: FloatArray): Boolean {
return getModel(random).singleRender(position, mesh, random, blockState, neighbours, light, ambientLight)
}

View File

@ -15,7 +15,6 @@ package de.bixilon.minosoft.gui.rendering.models.baked.block
import de.bixilon.minosoft.data.direction.Directions
import de.bixilon.minosoft.data.registries.blocks.BlockState
import de.bixilon.minosoft.data.world.light.LightAccessor
import de.bixilon.minosoft.gui.rendering.block.mesh.ChunkSectionMeshes
import de.bixilon.minosoft.gui.rendering.models.FaceProperties
import de.bixilon.minosoft.gui.rendering.models.baked.BakedModel
@ -28,7 +27,4 @@ interface BakedBlockModel : BakedModel {
// ToDo: Tint
fun singleRender(position: Vec3i, mesh: ChunkSectionMeshes, random: Random, blockState: BlockState, neighbours: Array<BlockState?>, light: Int, ambientLight: FloatArray): Boolean
// ToDo: Get ambient light
fun getLight(position: Vec3i, random: Random, side: Directions, lightAccessor: LightAccessor): Int
}

View File

@ -15,7 +15,6 @@ package de.bixilon.minosoft.gui.rendering.models.baked.block
import de.bixilon.minosoft.data.direction.Directions
import de.bixilon.minosoft.data.registries.blocks.BlockState
import de.bixilon.minosoft.data.world.light.LightAccessor
import de.bixilon.minosoft.gui.rendering.block.mesh.ChunkSectionMesh
import de.bixilon.minosoft.gui.rendering.block.mesh.ChunkSectionMeshes
import de.bixilon.minosoft.gui.rendering.models.CullUtil.canCull
@ -73,8 +72,4 @@ class BakedBlockStateModel(
face.greedyRender(floatStart, floatEnd, side, mesh, light)
}
}
override fun getLight(position: Vec3i, random: Random, side: Directions, lightAccessor: LightAccessor): Int {
TODO("Not yet implemented")
}
}

View File

@ -18,10 +18,8 @@ import de.bixilon.minosoft.data.registries.ResourceLocation
import de.bixilon.minosoft.data.world.ChunkData
import de.bixilon.minosoft.data.world.biome.source.SpatialBiomeArray
import de.bixilon.minosoft.datafixer.BlockEntityFixer.fix
import de.bixilon.minosoft.gui.rendering.util.VecUtil.EMPTY
import de.bixilon.minosoft.gui.rendering.util.VecUtil.of
import de.bixilon.minosoft.modding.event.EventInitiators
import de.bixilon.minosoft.modding.event.events.ChunkUnloadEvent
import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3iUtil.EMPTY
import de.bixilon.minosoft.modding.event.events.ChunkDataChangeEvent
import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection
import de.bixilon.minosoft.protocol.packets.s2c.PlayS2CPacket
@ -93,7 +91,7 @@ class ChunkDataS2CP(buffer: PlayInByteBuffer) : PlayS2CPacket() {
heightMap = buffer.readNBT()?.compoundCast()
}
if (!isFullChunk) {
chunkData.biomeSource = SpatialBiomeArray(buffer.readBiomeArray())
this.chunkData.biomeSource = SpatialBiomeArray(buffer.readBiomeArray())
}
val size = buffer.readVarInt()
val lastPos = buffer.pointer
@ -121,7 +119,7 @@ class ChunkDataS2CP(buffer: PlayInByteBuffer) : PlayS2CPacket() {
entity.updateNBT(nbt)
blockEntities[position] = entity
}
chunkData.blockEntities = blockEntities
this.chunkData.blockEntities = blockEntities
}
}
}

View File

@ -262,7 +262,7 @@ object ChunkUtil {
/**
* @param neighbourChunks: **Fully loaded** neighbour chunks
*/
private fun getSectionNeighbours(neighbourChunks: Array<Chunk>, chunk: Chunk, sectionHeight: Int): Array<ChunkSection?> {
fun getSectionNeighbours(neighbourChunks: Array<Chunk>, chunk: Chunk, sectionHeight: Int): Array<ChunkSection?> {
return arrayOf(
chunk[sectionHeight - 1],
chunk[sectionHeight + 1],