mirror of
https://gitlab.bixilon.de/bixilon/minosoft.git
synced 2025-09-13 01:16:46 -04:00
improve block entity handling, fix some bugs, improve performance of fast biomes
This commit is contained in:
parent
20062dc0ea
commit
ee02484494
@ -18,7 +18,6 @@ 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.gui.rendering.util.VecUtil.inChunkPosition
|
||||
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
|
||||
@ -26,6 +25,9 @@ import de.bixilon.minosoft.modding.event.events.ChunkDataChangeEvent
|
||||
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,6 +44,7 @@ class Chunk(
|
||||
var topLight: IntArray? = null
|
||||
val lowestSection = connection.world.dimension!!.lowestSection
|
||||
val highestSection = connection.world.dimension!!.highestSection
|
||||
val cacheBiomes = connection.world.cacheBiomeAccessor != null
|
||||
|
||||
var blocksInitialized = false // All block data was received
|
||||
var biomesInitialized = false // All biome data is initialized (aka. cache built, or similar)
|
||||
@ -106,6 +109,11 @@ class Chunk(
|
||||
}
|
||||
blocksInitialized = true
|
||||
}
|
||||
data.blockEntities?.let {
|
||||
for ((position, blockEntity) in it) {
|
||||
setBlockEntity(position, blockEntity)
|
||||
}
|
||||
}
|
||||
data.light?.let {
|
||||
for ((index, light) in it.withIndex()) {
|
||||
light ?: continue
|
||||
@ -124,8 +132,12 @@ class Chunk(
|
||||
}
|
||||
data.biomeSource?.let {
|
||||
this.biomeSource = it
|
||||
if (!cacheBiomes) {
|
||||
biomesInitialized = true
|
||||
}
|
||||
}
|
||||
connection.world.onChunkUpdate(chunkPosition, this)
|
||||
connection.fireEvent(ChunkDataChangeEvent(connection, EventInitiators.UNKNOWN, chunkPosition, this))
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
@ -170,11 +182,13 @@ 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!" }
|
||||
check(neighboursLoaded)
|
||||
|
||||
// isEmpty
|
||||
// ToDo: Return if isEmpty
|
||||
|
||||
val neighbours: Array<Chunk> = connection.world.getChunkNeighbours(chunkPosition).unsafeCast()
|
||||
for ((sectionIndex, section) in sections!!.withIndex()) {
|
||||
@ -183,23 +197,16 @@ class Chunk(
|
||||
section.buildBiomeCache(chunkPosition, sectionHeight, this, neighbours, cacheBiomeAccessor)
|
||||
}
|
||||
biomesInitialized = true
|
||||
connection.fireEvent(ChunkDataChangeEvent(connection, EventInitiators.UNKNOWN, chunkPosition, this))
|
||||
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?> {
|
||||
return sections!!.iterator()
|
||||
}
|
||||
|
||||
override fun getBiome(blockPosition: Vec3i): Biome? {
|
||||
if (connection.world.cacheBiomeAccessor != null) {
|
||||
val sectionHeight = blockPosition.sectionHeight
|
||||
return get(sectionHeight)?.biomes?.get(blockPosition.x, sectionHeight, blockPosition.z)
|
||||
}
|
||||
return biomeSource?.getBiome(blockPosition.inChunkPosition)
|
||||
}
|
||||
|
||||
override fun getBiome(x: Int, y: Int, z: Int): Biome? {
|
||||
if (connection.world.cacheBiomeAccessor != null) {
|
||||
if (cacheBiomes) {
|
||||
val sectionHeight = y.sectionHeight
|
||||
return get(sectionHeight)?.biomes?.get(x, sectionHeight, z)
|
||||
}
|
||||
|
@ -13,12 +13,15 @@
|
||||
|
||||
package de.bixilon.minosoft.data.world
|
||||
|
||||
import de.bixilon.minosoft.data.entities.block.BlockEntity
|
||||
import de.bixilon.minosoft.data.registries.blocks.BlockState
|
||||
import de.bixilon.minosoft.data.world.biome.source.BiomeSource
|
||||
import de.bixilon.minosoft.data.world.container.RegistrySectionDataProvider
|
||||
import glm_.vec3.Vec3i
|
||||
|
||||
class ChunkData(
|
||||
var blocks: Array<RegistrySectionDataProvider<BlockState?>?>? = null,
|
||||
var blockEntities: Map<Vec3i, BlockEntity>? = null,
|
||||
var biomeSource: BiomeSource? = null,
|
||||
var light: Array<IntArray?>? = null,
|
||||
var bottomLight: IntArray? = null,
|
||||
@ -28,6 +31,7 @@ class ChunkData(
|
||||
@Synchronized
|
||||
fun replace(data: ChunkData) {
|
||||
data.blocks?.let { this.blocks = it }
|
||||
data.blockEntities?.let { this.blockEntities = it }
|
||||
data.biomeSource?.let { this.biomeSource = it }
|
||||
data.light?.let { this.light = it }
|
||||
data.bottomLight?.let { this.bottomLight = it }
|
||||
|
@ -45,9 +45,9 @@ class ChunkSection(
|
||||
acquire()
|
||||
var blockEntity: BlockEntity?
|
||||
for (index in 0 until ProtocolDefinition.BLOCKS_PER_SECTION) {
|
||||
blockEntity = blockEntities[index] ?: continue
|
||||
blockEntity = blockEntities.unsafeGet(index) ?: continue
|
||||
val position = Vec3i.of(chunkPosition, sectionHeight, index.indexPosition)
|
||||
val blockState = blocks[index] ?: continue
|
||||
val blockState = blocks.unsafeGet(index) ?: continue
|
||||
blockEntity.tick(connection, blockState, position)
|
||||
}
|
||||
release()
|
||||
|
@ -34,6 +34,7 @@ import de.bixilon.minosoft.gui.rendering.util.VecUtil.minus
|
||||
import de.bixilon.minosoft.gui.rendering.util.VecUtil.plus
|
||||
import de.bixilon.minosoft.modding.event.EventInitiators
|
||||
import de.bixilon.minosoft.modding.event.events.BlockSetEvent
|
||||
import de.bixilon.minosoft.modding.event.events.ChunkDataChangeEvent
|
||||
import de.bixilon.minosoft.modding.event.events.ChunkUnloadEvent
|
||||
import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection
|
||||
import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition
|
||||
@ -125,8 +126,11 @@ class World(
|
||||
|
||||
fun unloadChunk(chunkPosition: Vec2i) {
|
||||
chunks.remove(chunkPosition) ?: return
|
||||
for (neighbour in getChunkNeighbours(chunkPosition)) {
|
||||
neighbour?.neighboursLoaded = false
|
||||
val neighbourPositions = ChunkUtil.getChunkNeighbourPositions(chunkPosition)
|
||||
for (neighbourPosition in neighbourPositions) {
|
||||
val neighbour = this[neighbourPosition] ?: continue
|
||||
neighbour.neighboursLoaded = false
|
||||
connection.fireEvent(ChunkDataChangeEvent(connection, EventInitiators.UNKNOWN, neighbourPosition, neighbour))
|
||||
}
|
||||
connection.fireEvent(ChunkUnloadEvent(connection, EventInitiators.UNKNOWN, chunkPosition))
|
||||
}
|
||||
@ -248,7 +252,7 @@ class World(
|
||||
|
||||
|
||||
/**
|
||||
* @return All 8 neighbour chunks
|
||||
* @return All 8 neighbour chunks
|
||||
*/
|
||||
fun getChunkNeighbours(neighbourPositions: Array<Vec2i>): Array<Chunk?> {
|
||||
val chunks: Array<Chunk?> = arrayOfNulls(neighbourPositions.size)
|
||||
@ -270,7 +274,9 @@ class World(
|
||||
}
|
||||
if (neighbours.fullyLoaded) {
|
||||
chunk.neighboursLoaded = true
|
||||
chunk.buildBiomeCache()
|
||||
if (cacheBiomeAccessor != null) {
|
||||
chunk.buildBiomeCache()
|
||||
}
|
||||
}
|
||||
for ((index, neighbourPosition) in neighbourPositions.withIndex()) {
|
||||
if (neighbourPosition == chunkPosition) {
|
||||
@ -289,8 +295,12 @@ class World(
|
||||
}
|
||||
}
|
||||
if (biomeSourceLoaded) {
|
||||
neighbourChunk.neighboursLoaded = true
|
||||
neighbourChunk.buildBiomeCache()
|
||||
neighbourChunk.neighboursLoaded = true // ToDo: only if fully loaded not just biomes
|
||||
|
||||
if (cacheBiomeAccessor != null) {
|
||||
neighbourChunk.buildBiomeCache()
|
||||
}
|
||||
connection.fireEvent(ChunkDataChangeEvent(connection, EventInitiators.UNKNOWN, neighbourPosition, neighbourChunk))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -39,6 +39,16 @@ open class SectionDataProvider<T>(
|
||||
return value
|
||||
}
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
fun unsafeGet(index: Int): T {
|
||||
return data[index] as T
|
||||
}
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
fun unsafeGet(x: Int, y: Int, z: Int): T {
|
||||
return data[y shl 8 or (z shl 4) or x] as T
|
||||
}
|
||||
|
||||
private fun recalculateCount() {
|
||||
var count = 0
|
||||
for (value in data) {
|
||||
|
@ -271,6 +271,7 @@ class DebugHUDElement(hudRenderer: HUDRenderer) : LayoutedHUDElement<GridLayout>
|
||||
this@DebugWorldInfo += AutoTextElement(hudRenderer, 1) { BaseComponent("Sky properties ", connection.world.dimension?.skyProperties) }
|
||||
this@DebugWorldInfo += AutoTextElement(hudRenderer, 1) { BaseComponent("Biome ", connection.world.getBiome(blockPosition)) }
|
||||
this@DebugWorldInfo += AutoTextElement(hudRenderer, 1) { with(connection.world.getLight(blockPosition)) { BaseComponent("Light block=", (this and 0x0F), ", sky=", (this ushr 4)) } }
|
||||
this@DebugWorldInfo += AutoTextElement(hudRenderer, 1) { BaseComponent("Fully loaded: ", chunk.isFullyLoaded) }
|
||||
|
||||
lastChunk = chunk
|
||||
}
|
||||
|
@ -21,7 +21,6 @@ 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.ChunkDataChangeEvent
|
||||
import de.bixilon.minosoft.modding.event.events.ChunkUnloadEvent
|
||||
import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection
|
||||
import de.bixilon.minosoft.protocol.packets.s2c.PlayS2CPacket
|
||||
@ -41,7 +40,6 @@ import glm_.vec3.Vec3i
|
||||
import java.util.*
|
||||
|
||||
class ChunkDataS2CP(buffer: PlayInByteBuffer) : PlayS2CPacket() {
|
||||
val blockEntities: MutableMap<Vec3i, BlockEntity> = mutableMapOf()
|
||||
val chunkPosition: Vec2i
|
||||
var chunkData: ChunkData? = ChunkData()
|
||||
private set
|
||||
@ -107,6 +105,7 @@ class ChunkDataS2CP(buffer: PlayInByteBuffer) : PlayS2CPacket() {
|
||||
buffer.pointer = size + lastPos
|
||||
}
|
||||
if (buffer.versionId >= ProtocolVersions.V_1_9_4) {
|
||||
val blockEntities: MutableMap<Vec3i, BlockEntity> = mutableMapOf()
|
||||
val positionOffset = Vec3i.of(chunkPosition, dimension.lowestSection, Vec3i.EMPTY)
|
||||
val blockEntitiesCount = buffer.readVarInt()
|
||||
for (i in 0 until blockEntitiesCount) {
|
||||
@ -121,6 +120,7 @@ class ChunkDataS2CP(buffer: PlayInByteBuffer) : PlayS2CPacket() {
|
||||
entity.updateNBT(nbt)
|
||||
blockEntities[position] = entity
|
||||
}
|
||||
chunkData!!.blockEntities = blockEntities
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -129,10 +129,6 @@ class ChunkDataS2CP(buffer: PlayInByteBuffer) : PlayS2CPacket() {
|
||||
chunkData?.let {
|
||||
val chunk = connection.world.getOrCreateChunk(chunkPosition)
|
||||
chunk.setData(chunkData!!, !isFullChunk)
|
||||
for ((position, blockEntity) in blockEntities) {
|
||||
chunk.setBlockEntity(position, blockEntity)
|
||||
}
|
||||
connection.fireEvent(ChunkDataChangeEvent(connection, this))
|
||||
} ?: let {
|
||||
connection.world.unloadChunk(chunkPosition)
|
||||
connection.fireEvent(ChunkUnloadEvent(connection, EventInitiators.SERVER, chunkPosition))
|
||||
|
@ -15,8 +15,6 @@ package de.bixilon.minosoft.protocol.packets.s2c.play
|
||||
|
||||
import de.bixilon.minosoft.Minosoft
|
||||
import de.bixilon.minosoft.data.world.ChunkData
|
||||
import de.bixilon.minosoft.modding.event.EventInitiators
|
||||
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
|
||||
import de.bixilon.minosoft.protocol.protocol.PlayInByteBuffer
|
||||
@ -68,7 +66,5 @@ class ChunkLightDataS2CP(buffer: PlayInByteBuffer) : PlayS2CPacket() {
|
||||
override fun handle(connection: PlayConnection) {
|
||||
val chunk = connection.world.getOrCreateChunk(chunkPosition)
|
||||
chunk.setData(chunkData)
|
||||
|
||||
connection.fireEvent(ChunkDataChangeEvent(connection, EventInitiators.SERVER, chunkPosition, chunk))
|
||||
}
|
||||
}
|
||||
|
@ -13,6 +13,7 @@
|
||||
package de.bixilon.minosoft.protocol.packets.s2c.play
|
||||
|
||||
import com.google.common.collect.HashBiMap
|
||||
import de.bixilon.minosoft.Minosoft
|
||||
import de.bixilon.minosoft.data.Difficulties
|
||||
import de.bixilon.minosoft.data.abilities.Gamemodes
|
||||
import de.bixilon.minosoft.data.registries.DefaultRegistries
|
||||
@ -161,7 +162,7 @@ class JoinGameS2CP(buffer: PlayInByteBuffer) : PlayS2CPacket() {
|
||||
|
||||
connection.world.entities.add(entityId, null, playerEntity)
|
||||
connection.world.hashedSeed = hashedSeed
|
||||
if (connection.version.versionId >= ProtocolVersions.V_19W36A) {
|
||||
if (connection.version.versionId >= ProtocolVersions.V_19W36A && !Minosoft.config.config.game.graphics.fastBiomeNoise) {
|
||||
connection.world.cacheBiomeAccessor = NoiseBiomeAccessor(connection.world)
|
||||
}
|
||||
TimeWorker.addTask(TimeWorkerTask(150, true) { // ToDo: Temp workaround
|
||||
|
@ -15,7 +15,6 @@ package de.bixilon.minosoft.protocol.packets.s2c.play
|
||||
import de.bixilon.minosoft.Minosoft
|
||||
import de.bixilon.minosoft.data.world.ChunkData
|
||||
import de.bixilon.minosoft.modding.event.EventInitiators
|
||||
import de.bixilon.minosoft.modding.event.events.ChunkDataChangeEvent
|
||||
import de.bixilon.minosoft.modding.event.events.ChunkUnloadEvent
|
||||
import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection
|
||||
import de.bixilon.minosoft.protocol.packets.s2c.PlayS2CPacket
|
||||
@ -74,7 +73,6 @@ class MassChunkDataS2CP() : PlayS2CPacket() {
|
||||
data?.let {
|
||||
val chunk = connection.world.getOrCreateChunk(chunkPosition)
|
||||
chunk.setData(data)
|
||||
connection.fireEvent(ChunkDataChangeEvent(connection, EventInitiators.SERVER, chunkPosition, chunk))
|
||||
} ?: let {
|
||||
// unload chunk
|
||||
connection.world.unloadChunk(chunkPosition)
|
||||
|
@ -262,6 +262,4 @@ object ChunkUtil {
|
||||
neighbourChunks[6][sectionHeight],
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user