diff --git a/src/main/java/de/bixilon/minosoft/data/world/Chunk.kt b/src/main/java/de/bixilon/minosoft/data/world/Chunk.kt index 40a307997..efe4e06f5 100644 --- a/src/main/java/de/bixilon/minosoft/data/world/Chunk.kt +++ b/src/main/java/de/bixilon/minosoft/data/world/Chunk.kt @@ -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 = 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 { 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) } diff --git a/src/main/java/de/bixilon/minosoft/data/world/ChunkData.kt b/src/main/java/de/bixilon/minosoft/data/world/ChunkData.kt index 99c00cf69..984c6124e 100644 --- a/src/main/java/de/bixilon/minosoft/data/world/ChunkData.kt +++ b/src/main/java/de/bixilon/minosoft/data/world/ChunkData.kt @@ -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?>? = null, + var blockEntities: Map? = null, var biomeSource: BiomeSource? = null, var light: Array? = 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 } diff --git a/src/main/java/de/bixilon/minosoft/data/world/ChunkSection.kt b/src/main/java/de/bixilon/minosoft/data/world/ChunkSection.kt index f09ceb4fe..3f382c673 100644 --- a/src/main/java/de/bixilon/minosoft/data/world/ChunkSection.kt +++ b/src/main/java/de/bixilon/minosoft/data/world/ChunkSection.kt @@ -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() diff --git a/src/main/java/de/bixilon/minosoft/data/world/World.kt b/src/main/java/de/bixilon/minosoft/data/world/World.kt index b4b1ed703..782548a4f 100644 --- a/src/main/java/de/bixilon/minosoft/data/world/World.kt +++ b/src/main/java/de/bixilon/minosoft/data/world/World.kt @@ -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): Array { val chunks: Array = 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)) } } } diff --git a/src/main/java/de/bixilon/minosoft/data/world/container/SectionDataProvider.kt b/src/main/java/de/bixilon/minosoft/data/world/container/SectionDataProvider.kt index c96e53dc5..8c2bd00cf 100644 --- a/src/main/java/de/bixilon/minosoft/data/world/container/SectionDataProvider.kt +++ b/src/main/java/de/bixilon/minosoft/data/world/container/SectionDataProvider.kt @@ -39,6 +39,16 @@ open class SectionDataProvider( 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) { diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/gui/hud/elements/other/DebugHUDElement.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/gui/hud/elements/other/DebugHUDElement.kt index 029efbd4f..5372ae097 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/gui/hud/elements/other/DebugHUDElement.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/gui/hud/elements/other/DebugHUDElement.kt @@ -271,6 +271,7 @@ class DebugHUDElement(hudRenderer: HUDRenderer) : LayoutedHUDElement 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 } diff --git a/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/ChunkDataS2CP.kt b/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/ChunkDataS2CP.kt index bde12d07a..ffa795e77 100644 --- a/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/ChunkDataS2CP.kt +++ b/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/ChunkDataS2CP.kt @@ -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 = 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 = 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)) diff --git a/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/ChunkLightDataS2CP.kt b/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/ChunkLightDataS2CP.kt index ed783abd8..05db6d5b3 100644 --- a/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/ChunkLightDataS2CP.kt +++ b/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/ChunkLightDataS2CP.kt @@ -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)) } } diff --git a/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/JoinGameS2CP.kt b/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/JoinGameS2CP.kt index 878ed381c..8c152337f 100644 --- a/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/JoinGameS2CP.kt +++ b/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/JoinGameS2CP.kt @@ -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 diff --git a/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/MassChunkDataS2CP.kt b/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/MassChunkDataS2CP.kt index 66894cf13..30282443a 100644 --- a/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/MassChunkDataS2CP.kt +++ b/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/MassChunkDataS2CP.kt @@ -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) diff --git a/src/main/java/de/bixilon/minosoft/util/chunk/ChunkUtil.kt b/src/main/java/de/bixilon/minosoft/util/chunk/ChunkUtil.kt index 3c64d19c1..b32b59720 100644 --- a/src/main/java/de/bixilon/minosoft/util/chunk/ChunkUtil.kt +++ b/src/main/java/de/bixilon/minosoft/util/chunk/ChunkUtil.kt @@ -262,6 +262,4 @@ object ChunkUtil { neighbourChunks[6][sectionHeight], ) } - - }