mirror of
https://gitlab.bixilon.de/bixilon/minosoft.git
synced 2025-09-13 09:26:11 -04:00
calculate biome cache on demand, refactor chunk section constructor
This makes things way faster and uses less memory. Biome is just needed for tinted blocks (and maybe sky color), most blocks don't require it. Calculating the biome is expensive (at least when joining).
This commit is contained in:
parent
c4cd6c4856
commit
7f32520f6e
@ -90,9 +90,11 @@ class WorldBiomesTest {
|
|||||||
val chunk = world.chunks[0, 0]!!
|
val chunk = world.chunks[0, 0]!!
|
||||||
chunk.getOrPut(0)
|
chunk.getOrPut(0)
|
||||||
|
|
||||||
assertEquals(source.counter, 4096)
|
assertEquals(source.counter, 0) // biomes ore on demand
|
||||||
assertEquals(world.biomes[1, 2, 3], b1)
|
assertEquals(world.biomes[1, 2, 3], b1)
|
||||||
assertEquals(source.counter, 4096)
|
assertEquals(source.counter, 1)
|
||||||
|
assertEquals(world.biomes[1, 2, 3], b1)
|
||||||
|
assertEquals(source.counter, 1) // don't query again
|
||||||
assertTrue(chunk.cacheBiomes)
|
assertTrue(chunk.cacheBiomes)
|
||||||
assertEquals(chunk[0]!!.biomes[1, 2, 3], b1)
|
assertEquals(chunk[0]!!.biomes[1, 2, 3], b1)
|
||||||
}
|
}
|
||||||
|
@ -15,12 +15,14 @@ package de.bixilon.minosoft.data.world.chunk.manager
|
|||||||
|
|
||||||
import de.bixilon.kotlinglm.vec2.Vec2i
|
import de.bixilon.kotlinglm.vec2.Vec2i
|
||||||
import de.bixilon.minosoft.data.registries.biomes.Biome
|
import de.bixilon.minosoft.data.registries.biomes.Biome
|
||||||
|
import de.bixilon.minosoft.data.registries.blocks.state.BlockState
|
||||||
import de.bixilon.minosoft.data.registries.blocks.types.stone.StoneTest0
|
import de.bixilon.minosoft.data.registries.blocks.types.stone.StoneTest0
|
||||||
import de.bixilon.minosoft.data.registries.identified.Namespaces.minosoft
|
import de.bixilon.minosoft.data.registries.identified.Namespaces.minosoft
|
||||||
import de.bixilon.minosoft.data.world.biome.accessor.noise.VoronoiBiomeAccessor
|
import de.bixilon.minosoft.data.world.biome.accessor.noise.VoronoiBiomeAccessor
|
||||||
import de.bixilon.minosoft.data.world.biome.source.BiomeSource
|
import de.bixilon.minosoft.data.world.biome.source.BiomeSource
|
||||||
import de.bixilon.minosoft.data.world.biome.source.DummyBiomeSource
|
import de.bixilon.minosoft.data.world.biome.source.DummyBiomeSource
|
||||||
import de.bixilon.minosoft.data.world.biome.source.SpatialBiomeArray
|
import de.bixilon.minosoft.data.world.biome.source.SpatialBiomeArray
|
||||||
|
import de.bixilon.minosoft.data.world.chunk.ChunkSection.Companion.getIndex
|
||||||
import de.bixilon.minosoft.data.world.chunk.chunk.Chunk
|
import de.bixilon.minosoft.data.world.chunk.chunk.Chunk
|
||||||
import de.bixilon.minosoft.data.world.chunk.chunk.ChunkPrototype
|
import de.bixilon.minosoft.data.world.chunk.chunk.ChunkPrototype
|
||||||
import de.bixilon.minosoft.data.world.chunk.neighbours.ChunkNeighbours
|
import de.bixilon.minosoft.data.world.chunk.neighbours.ChunkNeighbours
|
||||||
@ -31,13 +33,13 @@ import de.bixilon.minosoft.data.world.chunk.update.chunk.ChunkCreateUpdate
|
|||||||
import de.bixilon.minosoft.data.world.chunk.update.chunk.ChunkUnloadUpdate
|
import de.bixilon.minosoft.data.world.chunk.update.chunk.ChunkUnloadUpdate
|
||||||
import de.bixilon.minosoft.data.world.chunk.update.chunk.NeighbourChangeUpdate
|
import de.bixilon.minosoft.data.world.chunk.update.chunk.NeighbourChangeUpdate
|
||||||
import de.bixilon.minosoft.data.world.chunk.update.chunk.prototype.PrototypeChangeUpdate
|
import de.bixilon.minosoft.data.world.chunk.update.chunk.prototype.PrototypeChangeUpdate
|
||||||
import de.bixilon.minosoft.data.world.container.block.BlockSectionDataProvider
|
|
||||||
import de.bixilon.minosoft.data.world.positions.BlockPosition
|
import de.bixilon.minosoft.data.world.positions.BlockPosition
|
||||||
import de.bixilon.minosoft.data.world.positions.ChunkPosition
|
import de.bixilon.minosoft.data.world.positions.ChunkPosition
|
||||||
import de.bixilon.minosoft.data.world.positions.InChunkPosition
|
import de.bixilon.minosoft.data.world.positions.InChunkPosition
|
||||||
import de.bixilon.minosoft.gui.rendering.util.vec.vec2.Vec2iUtil.EMPTY
|
import de.bixilon.minosoft.gui.rendering.util.vec.vec2.Vec2iUtil.EMPTY
|
||||||
import de.bixilon.minosoft.modding.event.listener.CallbackEventListener.Companion.listen
|
import de.bixilon.minosoft.modding.event.listener.CallbackEventListener.Companion.listen
|
||||||
import de.bixilon.minosoft.protocol.network.connection.play.ConnectionTestUtil.createConnection
|
import de.bixilon.minosoft.protocol.network.connection.play.ConnectionTestUtil.createConnection
|
||||||
|
import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition
|
||||||
import org.testng.Assert.*
|
import org.testng.Assert.*
|
||||||
import org.testng.annotations.Test
|
import org.testng.annotations.Test
|
||||||
|
|
||||||
@ -191,9 +193,9 @@ class ChunkManagerTest {
|
|||||||
manager[ChunkPosition(0, 1)]!![3, 16, 3] = StoneTest0.state
|
manager[ChunkPosition(0, 1)]!![3, 16, 3] = StoneTest0.state
|
||||||
|
|
||||||
manager[ChunkPosition(0, 0)] = ChunkPrototype(blocks = arrayOf(
|
manager[ChunkPosition(0, 0)] = ChunkPrototype(blocks = arrayOf(
|
||||||
BlockSectionDataProvider(null).apply { this[3, 3, 3] = StoneTest0.state },
|
arrayOfNulls<BlockState>(ProtocolDefinition.BLOCKS_PER_SECTION).apply { this[getIndex(3, 3, 3)] = StoneTest0.state },
|
||||||
BlockSectionDataProvider(null).apply { this[3, 3, 3] = StoneTest0.state },
|
arrayOfNulls<BlockState>(ProtocolDefinition.BLOCKS_PER_SECTION).apply { this[getIndex(3, 3, 3)] = StoneTest0.state },
|
||||||
BlockSectionDataProvider(null).apply { this[3, 3, 3] = StoneTest0.state },
|
arrayOfNulls<BlockState>(ProtocolDefinition.BLOCKS_PER_SECTION).apply { this[getIndex(3, 3, 3)] = StoneTest0.state },
|
||||||
null, null, null,
|
null, null, null,
|
||||||
),
|
),
|
||||||
blockEntities = emptyMap(),
|
blockEntities = emptyMap(),
|
||||||
@ -399,7 +401,7 @@ class ChunkManagerTest {
|
|||||||
fired++
|
fired++
|
||||||
}
|
}
|
||||||
|
|
||||||
manager.set(ChunkPosition(1, 1), ChunkPrototype(blocks = Array(16) { if (it == 0) BlockSectionDataProvider(null) else null }), false)
|
manager.set(ChunkPosition(1, 1), ChunkPrototype(blocks = Array(16) { if (it == 0) arrayOfNulls(ProtocolDefinition.BLOCKS_PER_SECTION) else null }), false)
|
||||||
|
|
||||||
assertNotNull(manager[ChunkPosition(1, 1)])
|
assertNotNull(manager[ChunkPosition(1, 1)])
|
||||||
|
|
||||||
@ -443,8 +445,10 @@ class ChunkManagerTest {
|
|||||||
val matrix = manager.createMatrix(source)
|
val matrix = manager.createMatrix(source)
|
||||||
|
|
||||||
val chunk = matrix[1][1]
|
val chunk = matrix[1][1]
|
||||||
assertEquals(chunk.getOrPut(0)!!.biomes.count, 4096)
|
val section = chunk.getOrPut(0)!!.biomes
|
||||||
assertEquals(chunk.getOrPut(0)!!.biomes[0], biome)
|
assertEquals(section[3, 3, 3], biome)
|
||||||
|
assertEquals(section[3, 3, 3], biome)
|
||||||
|
assertEquals(section[0], biome)
|
||||||
|
|
||||||
assertEquals(manager.world.biomes.getBiome(BlockPosition(5, 5, 5)), biome)
|
assertEquals(manager.world.biomes.getBiome(BlockPosition(5, 5, 5)), biome)
|
||||||
assertEquals(chunk.getBiome(BlockPosition(5, 5, 5)), biome)
|
assertEquals(chunk.getBiome(BlockPosition(5, 5, 5)), biome)
|
||||||
|
@ -1,7 +1,22 @@
|
|||||||
|
/*
|
||||||
|
* Minosoft
|
||||||
|
* Copyright (C) 2020-2023 Moritz Zwerger
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
|
||||||
|
*/
|
||||||
|
|
||||||
package de.bixilon.minosoft.data.world.container.block
|
package de.bixilon.minosoft.data.world.container.block
|
||||||
|
|
||||||
import de.bixilon.kotlinglm.vec3.Vec3i
|
import de.bixilon.kotlinglm.vec3.Vec3i
|
||||||
import de.bixilon.minosoft.data.registries.blocks.types.stone.StoneTest0
|
import de.bixilon.minosoft.data.registries.blocks.types.stone.StoneTest0
|
||||||
|
import de.bixilon.minosoft.data.world.chunk.ChunkSection
|
||||||
|
import de.bixilon.minosoft.test.ITUtil.allocate
|
||||||
import org.testng.Assert.*
|
import org.testng.Assert.*
|
||||||
import org.testng.annotations.Test
|
import org.testng.annotations.Test
|
||||||
|
|
||||||
@ -9,7 +24,8 @@ import org.testng.annotations.Test
|
|||||||
class BlockSectionDataProviderTest {
|
class BlockSectionDataProviderTest {
|
||||||
|
|
||||||
private fun create(): BlockSectionDataProvider {
|
private fun create(): BlockSectionDataProvider {
|
||||||
return BlockSectionDataProvider(null)
|
val section = ChunkSection::class.java.allocate()
|
||||||
|
return BlockSectionDataProvider(null, section)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun `initial empty`() {
|
fun `initial empty`() {
|
||||||
|
@ -19,8 +19,10 @@ import de.bixilon.kutil.observer.DataObserver
|
|||||||
import de.bixilon.kutil.reflection.ReflectionUtil.forceSet
|
import de.bixilon.kutil.reflection.ReflectionUtil.forceSet
|
||||||
import de.bixilon.mbf.MBFBinaryReader
|
import de.bixilon.mbf.MBFBinaryReader
|
||||||
import de.bixilon.minosoft.data.registries.blocks.MinecraftBlocks
|
import de.bixilon.minosoft.data.registries.blocks.MinecraftBlocks
|
||||||
|
import de.bixilon.minosoft.data.registries.blocks.state.BlockState
|
||||||
import de.bixilon.minosoft.data.registries.blocks.types.building.stone.StoneBlock
|
import de.bixilon.minosoft.data.registries.blocks.types.building.stone.StoneBlock
|
||||||
import de.bixilon.minosoft.data.registries.dimension.DimensionProperties
|
import de.bixilon.minosoft.data.registries.dimension.DimensionProperties
|
||||||
|
import de.bixilon.minosoft.data.world.chunk.ChunkSection.Companion.getIndex
|
||||||
import de.bixilon.minosoft.protocol.network.connection.play.ConnectionTestUtil.createConnection
|
import de.bixilon.minosoft.protocol.network.connection.play.ConnectionTestUtil.createConnection
|
||||||
import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection
|
import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection
|
||||||
import de.bixilon.minosoft.protocol.packets.s2c.play.block.chunk.ChunkS2CP
|
import de.bixilon.minosoft.protocol.packets.s2c.play.block.chunk.ChunkS2CP
|
||||||
@ -37,6 +39,10 @@ class ChunkS2CPTest {
|
|||||||
registries.update(version, mbf.data.unsafeCast())
|
registries.update(version, mbf.data.unsafeCast())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private operator fun Array<BlockState?>.get(x: Int, y: Int, z: Int): BlockState? {
|
||||||
|
return this[getIndex(x, y, z)]
|
||||||
|
}
|
||||||
|
|
||||||
private fun read(name: String, version: String, connection: PlayConnection = createConnection(version = version), dimension: DimensionProperties): ChunkS2CP {
|
private fun read(name: String, version: String, connection: PlayConnection = createConnection(version = version), dimension: DimensionProperties): ChunkS2CP {
|
||||||
val data = ChunkS2CPTest::class.java.getResourceAsStream("/packets/chunk/$name.bin")!!.readAllBytes()
|
val data = ChunkS2CPTest::class.java.getResourceAsStream("/packets/chunk/$name.bin")!!.readAllBytes()
|
||||||
connection.world::dimension.forceSet(DataObserver(dimension))
|
connection.world::dimension.forceSet(DataObserver(dimension))
|
||||||
|
@ -14,19 +14,14 @@ package de.bixilon.minosoft.data.world.chunk
|
|||||||
|
|
||||||
import de.bixilon.kotlinglm.vec2.Vec2i
|
import de.bixilon.kotlinglm.vec2.Vec2i
|
||||||
import de.bixilon.kotlinglm.vec3.Vec3i
|
import de.bixilon.kotlinglm.vec3.Vec3i
|
||||||
import de.bixilon.kutil.array.ArrayUtil.cast
|
|
||||||
import de.bixilon.kutil.cast.CastUtil.unsafeNull
|
|
||||||
import de.bixilon.kutil.reflection.ReflectionUtil.jvmField
|
|
||||||
import de.bixilon.minosoft.data.entities.block.BlockEntity
|
import de.bixilon.minosoft.data.entities.block.BlockEntity
|
||||||
import de.bixilon.minosoft.data.registries.biomes.Biome
|
|
||||||
import de.bixilon.minosoft.data.world.biome.accessor.noise.NoiseBiomeAccessor
|
|
||||||
import de.bixilon.minosoft.data.world.chunk.chunk.Chunk
|
import de.bixilon.minosoft.data.world.chunk.chunk.Chunk
|
||||||
import de.bixilon.minosoft.data.world.chunk.light.SectionLight
|
import de.bixilon.minosoft.data.world.chunk.light.SectionLight
|
||||||
import de.bixilon.minosoft.data.world.container.SectionDataProvider
|
import de.bixilon.minosoft.data.world.container.SectionDataProvider
|
||||||
|
import de.bixilon.minosoft.data.world.container.biome.BiomeSectionDataProvider
|
||||||
import de.bixilon.minosoft.data.world.container.block.BlockSectionDataProvider
|
import de.bixilon.minosoft.data.world.container.block.BlockSectionDataProvider
|
||||||
import de.bixilon.minosoft.gui.rendering.util.VecUtil.of
|
import de.bixilon.minosoft.gui.rendering.util.VecUtil.of
|
||||||
import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection
|
import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection
|
||||||
import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition
|
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -34,12 +29,12 @@ import java.util.*
|
|||||||
*/
|
*/
|
||||||
class ChunkSection(
|
class ChunkSection(
|
||||||
val sectionHeight: Int,
|
val sectionHeight: Int,
|
||||||
chunk: Chunk? = null,
|
val chunk: Chunk,
|
||||||
var blocks: BlockSectionDataProvider = BlockSectionDataProvider(chunk?.lock),
|
|
||||||
var biomes: SectionDataProvider<Biome> = SectionDataProvider(chunk?.lock, checkSize = false),
|
|
||||||
var blockEntities: SectionDataProvider<BlockEntity?> = SectionDataProvider(chunk?.lock, checkSize = true),
|
|
||||||
) {
|
) {
|
||||||
val chunk: Chunk = chunk ?: unsafeNull()
|
var blocks = BlockSectionDataProvider(chunk.lock, this)
|
||||||
|
var biomes = BiomeSectionDataProvider(chunk.lock, this)
|
||||||
|
var blockEntities: SectionDataProvider<BlockEntity?> = SectionDataProvider(chunk.lock, checkSize = true)
|
||||||
|
|
||||||
var light = SectionLight(this)
|
var light = SectionLight(this)
|
||||||
var neighbours: Array<ChunkSection?>? = null
|
var neighbours: Array<ChunkSection?>? = null
|
||||||
|
|
||||||
@ -66,14 +61,6 @@ class ChunkSection(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun buildBiomeCache(noise: NoiseBiomeAccessor) {
|
|
||||||
val biomes: Array<Biome?> = arrayOfNulls(ProtocolDefinition.BLOCKS_PER_SECTION)
|
|
||||||
for (index in 0 until ProtocolDefinition.BLOCKS_PER_SECTION) {
|
|
||||||
biomes[index] = noise.get(index and 0x0F, (index shr 8) and 0x0F, (index shr 4) and 0x0F, chunk)
|
|
||||||
}
|
|
||||||
this.biomes.setData(biomes.cast())
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
fun clear() {
|
fun clear() {
|
||||||
blocks.clear()
|
blocks.clear()
|
||||||
@ -81,16 +68,7 @@ class ChunkSection(
|
|||||||
blockEntities.clear()
|
blockEntities.clear()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun updateChunk(chunk: Chunk) {
|
|
||||||
CHUNK[this] = chunk
|
|
||||||
blocks.lock = chunk.lock
|
|
||||||
// biomes?
|
|
||||||
blockEntities.lock = chunk.lock
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private val CHUNK = ChunkSection::chunk.jvmField
|
|
||||||
|
|
||||||
inline val Vec3i.index: Int
|
inline val Vec3i.index: Int
|
||||||
get() = getIndex(x, y, z)
|
get() = getIndex(x, y, z)
|
||||||
|
|
||||||
|
@ -28,7 +28,6 @@ import de.bixilon.minosoft.data.world.chunk.light.ChunkLight
|
|||||||
import de.bixilon.minosoft.data.world.chunk.neighbours.ChunkNeighbours
|
import de.bixilon.minosoft.data.world.chunk.neighbours.ChunkNeighbours
|
||||||
import de.bixilon.minosoft.data.world.chunk.update.block.ChunkLocalBlockUpdate
|
import de.bixilon.minosoft.data.world.chunk.update.block.ChunkLocalBlockUpdate
|
||||||
import de.bixilon.minosoft.data.world.chunk.update.block.SingleBlockUpdate
|
import de.bixilon.minosoft.data.world.chunk.update.block.SingleBlockUpdate
|
||||||
import de.bixilon.minosoft.data.world.container.block.BlockSectionDataProvider.Companion.unsafeSetSection
|
|
||||||
import de.bixilon.minosoft.data.world.positions.ChunkPosition
|
import de.bixilon.minosoft.data.world.positions.ChunkPosition
|
||||||
import de.bixilon.minosoft.data.world.positions.InChunkPosition
|
import de.bixilon.minosoft.data.world.positions.InChunkPosition
|
||||||
import de.bixilon.minosoft.data.world.positions.SectionHeight
|
import de.bixilon.minosoft.data.world.positions.SectionHeight
|
||||||
@ -44,7 +43,6 @@ import java.util.*
|
|||||||
class Chunk(
|
class Chunk(
|
||||||
val connection: PlayConnection,
|
val connection: PlayConnection,
|
||||||
val chunkPosition: ChunkPosition,
|
val chunkPosition: ChunkPosition,
|
||||||
var sections: Array<ChunkSection?>,
|
|
||||||
var biomeSource: BiomeSource,
|
var biomeSource: BiomeSource,
|
||||||
) : Iterable<ChunkSection?>, BiomeAccessor {
|
) : Iterable<ChunkSection?>, BiomeAccessor {
|
||||||
val lock = ThreadLock()
|
val lock = ThreadLock()
|
||||||
@ -53,6 +51,7 @@ class Chunk(
|
|||||||
val minSection = world.dimension.minSection
|
val minSection = world.dimension.minSection
|
||||||
val maxSection = world.dimension.maxSection
|
val maxSection = world.dimension.maxSection
|
||||||
val cacheBiomes = world.biomes.noise != null
|
val cacheBiomes = world.biomes.noise != null
|
||||||
|
var sections: Array<ChunkSection?> = arrayOfNulls(world.dimension.sections)
|
||||||
|
|
||||||
val neighbours = ChunkNeighbours(this)
|
val neighbours = ChunkNeighbours(this)
|
||||||
|
|
||||||
@ -184,7 +183,6 @@ class Chunk(
|
|||||||
var section = sections[index] // get another time, it might have changed already
|
var section = sections[index] // get another time, it might have changed already
|
||||||
if (section == null) {
|
if (section == null) {
|
||||||
section = ChunkSection(sectionHeight, chunk = this)
|
section = ChunkSection(sectionHeight, chunk = this)
|
||||||
section.blocks.unsafeSetSection(section)
|
|
||||||
val neighbours = this.neighbours.get()
|
val neighbours = this.neighbours.get()
|
||||||
if (neighbours != null) {
|
if (neighbours != null) {
|
||||||
this.neighbours.completeSection(neighbours, section, sectionHeight, world.biomes.noise)
|
this.neighbours.completeSection(neighbours, section, sectionHeight, world.biomes.noise)
|
||||||
|
@ -15,20 +15,18 @@ package de.bixilon.minosoft.data.world.chunk.chunk
|
|||||||
|
|
||||||
import de.bixilon.kotlinglm.vec3.Vec3i
|
import de.bixilon.kotlinglm.vec3.Vec3i
|
||||||
import de.bixilon.kutil.json.JsonObject
|
import de.bixilon.kutil.json.JsonObject
|
||||||
import de.bixilon.kutil.reflection.ReflectionUtil.forceSet
|
|
||||||
import de.bixilon.kutil.reflection.ReflectionUtil.jvmField
|
|
||||||
import de.bixilon.minosoft.config.StaticConfiguration
|
import de.bixilon.minosoft.config.StaticConfiguration
|
||||||
|
import de.bixilon.minosoft.data.registries.blocks.state.BlockState
|
||||||
import de.bixilon.minosoft.data.registries.blocks.types.entity.BlockWithEntity
|
import de.bixilon.minosoft.data.registries.blocks.types.entity.BlockWithEntity
|
||||||
import de.bixilon.minosoft.data.world.biome.source.BiomeSource
|
import de.bixilon.minosoft.data.world.biome.source.BiomeSource
|
||||||
import de.bixilon.minosoft.data.world.chunk.ChunkSection
|
import de.bixilon.minosoft.data.world.chunk.ChunkSection
|
||||||
import de.bixilon.minosoft.data.world.container.block.BlockSectionDataProvider
|
|
||||||
import de.bixilon.minosoft.data.world.positions.ChunkPosition
|
import de.bixilon.minosoft.data.world.positions.ChunkPosition
|
||||||
import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection
|
import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection
|
||||||
import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition
|
import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition
|
||||||
import it.unimi.dsi.fastutil.ints.IntOpenHashSet
|
import it.unimi.dsi.fastutil.ints.IntOpenHashSet
|
||||||
|
|
||||||
class ChunkPrototype(
|
class ChunkPrototype(
|
||||||
var blocks: Array<BlockSectionDataProvider?>? = null,
|
var blocks: Array<Array<BlockState?>?>? = null,
|
||||||
var blockEntities: Map<Vec3i, JsonObject>? = null,
|
var blockEntities: Map<Vec3i, JsonObject>? = null,
|
||||||
var biomeSource: BiomeSource? = null,
|
var biomeSource: BiomeSource? = null,
|
||||||
var light: Array<ByteArray?>? = null,
|
var light: Array<ByteArray?>? = null,
|
||||||
@ -53,28 +51,23 @@ class ChunkPrototype(
|
|||||||
|
|
||||||
val dimension = connection.world.dimension
|
val dimension = connection.world.dimension
|
||||||
|
|
||||||
val sections: Array<ChunkSection?> = arrayOfNulls(dimension.sections)
|
|
||||||
|
|
||||||
val light = this.light
|
val light = this.light
|
||||||
for ((index, provider) in blocks.withIndex()) {
|
val chunk = Chunk(connection, position, biomeSource)
|
||||||
if (provider == null) continue
|
|
||||||
val section = ChunkSection(index + dimension.minSection, null, provider)
|
for ((index, blockData) in blocks.withIndex()) {
|
||||||
SECTION[provider] = section
|
if (blockData == null) continue
|
||||||
|
val section = ChunkSection(index + dimension.minSection, chunk)
|
||||||
|
section.blocks.setData(blockData)
|
||||||
|
|
||||||
if (!StaticConfiguration.IGNORE_SERVER_LIGHT) {
|
if (!StaticConfiguration.IGNORE_SERVER_LIGHT) {
|
||||||
light?.get(index)?.let { section.light.light = it }
|
light?.get(index)?.let { section.light.light = it }
|
||||||
}
|
}
|
||||||
|
|
||||||
sections[index] = section
|
chunk.sections[index] = section
|
||||||
}
|
}
|
||||||
this.blockEntities.update(dimension.minSection, sections, null, connection)
|
this.blockEntities.update(dimension.minSection, chunk, null, connection)
|
||||||
|
|
||||||
val chunk = Chunk(connection, position, sections, biomeSource)
|
|
||||||
|
|
||||||
for (section in sections) {
|
|
||||||
if (section == null) continue
|
|
||||||
section.updateChunk(chunk)
|
|
||||||
}
|
|
||||||
if (!StaticConfiguration.IGNORE_SERVER_LIGHT) {
|
if (!StaticConfiguration.IGNORE_SERVER_LIGHT) {
|
||||||
this.topLight?.let { chunk.light.top.update(it) }
|
this.topLight?.let { chunk.light.top.update(it) }
|
||||||
this.bottomLight?.let { chunk.light.bottom.update(it) }
|
this.bottomLight?.let { chunk.light.bottom.update(it) }
|
||||||
@ -84,7 +77,7 @@ class ChunkPrototype(
|
|||||||
return chunk
|
return chunk
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun Array<BlockSectionDataProvider?>.update(chunk: Chunk, replace: Boolean, affected: IntOpenHashSet) {
|
private fun Array<Array<BlockState?>?>.update(chunk: Chunk, replace: Boolean, affected: IntOpenHashSet) {
|
||||||
for ((index, provider) in this.withIndex()) {
|
for ((index, provider) in this.withIndex()) {
|
||||||
var section = chunk.sections[index]
|
var section = chunk.sections[index]
|
||||||
val sectionHeight = index - chunk.minSection
|
val sectionHeight = index - chunk.minSection
|
||||||
@ -101,16 +94,15 @@ class ChunkPrototype(
|
|||||||
} else {
|
} else {
|
||||||
section.blockEntities.clear()
|
section.blockEntities.clear()
|
||||||
}
|
}
|
||||||
SECTION.forceSet(provider, section)
|
|
||||||
|
|
||||||
section.blocks = provider
|
section.blocks.setData(provider)
|
||||||
affected += sectionHeight
|
affected += sectionHeight
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun Map<Vec3i, JsonObject>?.update(minSection: Int, sections: Array<ChunkSection?>, affected: IntOpenHashSet?, connection: PlayConnection) {
|
private fun Map<Vec3i, JsonObject>?.update(minSection: Int, chunk: Chunk, affected: IntOpenHashSet?, connection: PlayConnection) {
|
||||||
val position = Vec3i()
|
val position = Vec3i()
|
||||||
for ((index, section) in sections.withIndex()) {
|
for ((index, section) in chunk.sections.withIndex()) {
|
||||||
if (section == null || section.blocks.isEmpty) continue
|
if (section == null || section.blocks.isEmpty) continue
|
||||||
val blocks = section.blocks
|
val blocks = section.blocks
|
||||||
val sectionHeight = (index + minSection)
|
val sectionHeight = (index + minSection)
|
||||||
@ -142,7 +134,7 @@ class ChunkPrototype(
|
|||||||
fun updateChunk(chunk: Chunk, replace: Boolean): IntOpenHashSet? {
|
fun updateChunk(chunk: Chunk, replace: Boolean): IntOpenHashSet? {
|
||||||
val affected = IntOpenHashSet()
|
val affected = IntOpenHashSet()
|
||||||
this.blocks?.update(chunk, replace, affected)
|
this.blocks?.update(chunk, replace, affected)
|
||||||
this.blockEntities?.update(chunk.minSection, chunk.sections, affected, chunk.connection)
|
this.blockEntities?.update(chunk.minSection, chunk, affected, chunk.connection)
|
||||||
|
|
||||||
this.biomeSource?.let { chunk.biomeSource = it } // TODO: invalidate cache
|
this.biomeSource?.let { chunk.biomeSource = it } // TODO: invalidate cache
|
||||||
|
|
||||||
@ -155,8 +147,4 @@ class ChunkPrototype(
|
|||||||
if (affected.isEmpty()) return null
|
if (affected.isEmpty()) return null
|
||||||
return affected
|
return affected
|
||||||
}
|
}
|
||||||
|
|
||||||
private companion object {
|
|
||||||
private val SECTION = BlockSectionDataProvider::section.jvmField
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -161,7 +161,7 @@ class ChunkManager(val world: World, chunkCapacity: Int = 0, prototypeCapacity:
|
|||||||
fun create(position: ChunkPosition, biome: BiomeSource = DummyBiomeSource(null)): Chunk {
|
fun create(position: ChunkPosition, biome: BiomeSource = DummyBiomeSource(null)): Chunk {
|
||||||
if (!world.isValidPosition(position)) throw IllegalArgumentException("Chunk position $position is not valid!")
|
if (!world.isValidPosition(position)) throw IllegalArgumentException("Chunk position $position is not valid!")
|
||||||
chunks.lock.lock()
|
chunks.lock.lock()
|
||||||
val chunk = chunks.unsafe.getOrPut(position) { Chunk(world.connection, position, arrayOfNulls(world.dimension.sections), biome) }
|
val chunk = chunks.unsafe.getOrPut(position) { Chunk(world.connection, position, biome) }
|
||||||
val updates = onChunkCreate(chunk)
|
val updates = onChunkCreate(chunk)
|
||||||
chunks.lock.unlock()
|
chunks.lock.unlock()
|
||||||
|
|
||||||
|
@ -72,9 +72,6 @@ class ChunkNeighbours(val chunk: Chunk) : Iterable<Chunk?> {
|
|||||||
|
|
||||||
fun completeSection(neighbours: Array<Chunk>, section: ChunkSection, sectionHeight: SectionHeight, noise: NoiseBiomeAccessor?) {
|
fun completeSection(neighbours: Array<Chunk>, section: ChunkSection, sectionHeight: SectionHeight, noise: NoiseBiomeAccessor?) {
|
||||||
section.neighbours = ChunkUtil.getDirectNeighbours(neighbours, chunk, sectionHeight)
|
section.neighbours = ChunkUtil.getDirectNeighbours(neighbours, chunk, sectionHeight)
|
||||||
if (noise != null) {
|
|
||||||
section.buildBiomeCache(noise)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun complete(neighbours: Array<Chunk>) {
|
private fun complete(neighbours: Array<Chunk>) {
|
||||||
|
@ -23,36 +23,25 @@ import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition
|
|||||||
|
|
||||||
open class SectionDataProvider<T>(
|
open class SectionDataProvider<T>(
|
||||||
var lock: Lock?,
|
var lock: Lock?,
|
||||||
data: Array<T>? = null,
|
|
||||||
val checkSize: Boolean = false,
|
val checkSize: Boolean = false,
|
||||||
calculateInitial: Boolean = true,
|
|
||||||
) : Iterable<T> {
|
) : Iterable<T> {
|
||||||
protected var data: Array<Any?>? = data?.unsafeCast()
|
protected var data: Array<Any?>? = null
|
||||||
private set
|
private set
|
||||||
var count: Int = 0
|
var count: Int = 0
|
||||||
private set
|
private set
|
||||||
val isEmpty: Boolean
|
val isEmpty: Boolean
|
||||||
get() = count == 0
|
get() = count == 0
|
||||||
lateinit var minPosition: Vec3i
|
var minPosition = Vec3i(ProtocolDefinition.CHUNK_SECTION_SIZE)
|
||||||
private set
|
private set
|
||||||
lateinit var maxPosition: Vec3i
|
var maxPosition = Vec3i.EMPTY
|
||||||
private set
|
private set
|
||||||
|
|
||||||
init {
|
|
||||||
if (data != null && calculateInitial) {
|
|
||||||
recalculate()
|
|
||||||
} else {
|
|
||||||
minPosition = Vec3i(ProtocolDefinition.CHUNK_SECTION_SIZE)
|
|
||||||
maxPosition = Vec3i.EMPTY
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
operator fun get(index: Int): T {
|
open operator fun get(index: Int): T {
|
||||||
return data?.get(index) as T
|
return data?.get(index) as T
|
||||||
}
|
}
|
||||||
|
|
||||||
operator fun get(x: Int, y: Int, z: Int): T {
|
open operator fun get(x: Int, y: Int, z: Int): T {
|
||||||
return get(ChunkSection.getIndex(x, y, z))
|
return get(ChunkSection.getIndex(x, y, z))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -193,13 +182,6 @@ open class SectionDataProvider<T>(
|
|||||||
lock?.unlock()
|
lock?.unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun copy(): SectionDataProvider<T> {
|
|
||||||
lock?.acquire()
|
|
||||||
val clone = SectionDataProvider<T>(null, data?.clone()?.unsafeCast())
|
|
||||||
lock?.release()
|
|
||||||
|
|
||||||
return clone
|
|
||||||
}
|
|
||||||
|
|
||||||
fun clear() {
|
fun clear() {
|
||||||
lock?.lock()
|
lock?.lock()
|
||||||
|
@ -0,0 +1,41 @@
|
|||||||
|
/*
|
||||||
|
* Minosoft
|
||||||
|
* Copyright (C) 2020-2023 Moritz Zwerger
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package de.bixilon.minosoft.data.world.container.biome
|
||||||
|
|
||||||
|
import de.bixilon.kutil.concurrent.lock.Lock
|
||||||
|
import de.bixilon.minosoft.data.registries.biomes.Biome
|
||||||
|
import de.bixilon.minosoft.data.world.chunk.ChunkSection
|
||||||
|
import de.bixilon.minosoft.data.world.container.SectionDataProvider
|
||||||
|
|
||||||
|
class BiomeSectionDataProvider(
|
||||||
|
lock: Lock? = null,
|
||||||
|
val section: ChunkSection,
|
||||||
|
) : SectionDataProvider<Biome?>(lock, false) {
|
||||||
|
|
||||||
|
override fun get(index: Int): Biome? {
|
||||||
|
var biome = super.get(index)
|
||||||
|
if (biome != null) return biome
|
||||||
|
biome = section.chunk.world.biomes.noise?.get(index and 0x0F, (index shr 8) and 0x0F, (index shr 4) and 0x0F, section.chunk)
|
||||||
|
unsafeSet(index, biome)
|
||||||
|
return biome
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun get(x: Int, y: Int, z: Int): Biome? {
|
||||||
|
var biome = super.get(x, y, z)
|
||||||
|
if (biome != null) return biome
|
||||||
|
biome = section.chunk.world.biomes.noise?.get(x, y, z, section.chunk)
|
||||||
|
unsafeSet(x, y, z, biome)
|
||||||
|
return biome
|
||||||
|
}
|
||||||
|
}
|
@ -13,9 +13,7 @@
|
|||||||
|
|
||||||
package de.bixilon.minosoft.data.world.container.block
|
package de.bixilon.minosoft.data.world.container.block
|
||||||
|
|
||||||
import de.bixilon.kutil.cast.CastUtil.unsafeNull
|
|
||||||
import de.bixilon.kutil.concurrent.lock.Lock
|
import de.bixilon.kutil.concurrent.lock.Lock
|
||||||
import de.bixilon.kutil.reflection.ReflectionUtil.jvmField
|
|
||||||
import de.bixilon.minosoft.data.registries.blocks.state.BlockState
|
import de.bixilon.minosoft.data.registries.blocks.state.BlockState
|
||||||
import de.bixilon.minosoft.data.registries.blocks.types.fluid.FluidHolder
|
import de.bixilon.minosoft.data.registries.blocks.types.fluid.FluidHolder
|
||||||
import de.bixilon.minosoft.data.registries.fluid.fluids.WaterFluid.Companion.isWaterlogged
|
import de.bixilon.minosoft.data.registries.fluid.fluids.WaterFluid.Companion.isWaterlogged
|
||||||
@ -25,9 +23,8 @@ import de.bixilon.minosoft.data.world.container.SectionDataProvider
|
|||||||
|
|
||||||
class BlockSectionDataProvider(
|
class BlockSectionDataProvider(
|
||||||
lock: Lock? = null,
|
lock: Lock? = null,
|
||||||
data: Array<BlockState?>? = null,
|
val section: ChunkSection,
|
||||||
) : SectionDataProvider<BlockState?>(lock, data, true, false) {
|
) : SectionDataProvider<BlockState?>(lock, true) {
|
||||||
val section: ChunkSection = unsafeNull()
|
|
||||||
val occlusion = SectionOcclusion(this)
|
val occlusion = SectionOcclusion(this)
|
||||||
var fluidCount = 0
|
var fluidCount = 0
|
||||||
private set
|
private set
|
||||||
@ -89,13 +86,4 @@ class BlockSectionDataProvider(
|
|||||||
}
|
}
|
||||||
return this.isWaterlogged()
|
return this.isWaterlogged()
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
|
||||||
private val sections = BlockSectionDataProvider::section.jvmField
|
|
||||||
|
|
||||||
@Deprecated("properly integrate in constructor")
|
|
||||||
fun BlockSectionDataProvider.unsafeSetSection(section: ChunkSection) {
|
|
||||||
this@Companion.sections[this] = section
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -131,7 +131,7 @@ class SolidSectionMesher(
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
val tints = tints.getBlockTint(state, chunk.getBiome(position.x and 0x0F, y, position.z and 0x0F), x, y, z)
|
val tints = tints.getBlockTint(state, chunk, x, position.y, z)
|
||||||
var rendered = false
|
var rendered = false
|
||||||
model?.render(position, floatOffset, mesh, random, state, neighbourBlocks, light, tints, blockEntity.unsafeCast())?.let { if (it) rendered = true }
|
model?.render(position, floatOffset, mesh, random, state, neighbourBlocks, light, tints, blockEntity.unsafeCast())?.let { if (it) rendered = true }
|
||||||
|
|
||||||
|
@ -17,7 +17,6 @@ import de.bixilon.kotlinglm.vec3.Vec3i
|
|||||||
import de.bixilon.kutil.primitive.IntUtil.toInt
|
import de.bixilon.kutil.primitive.IntUtil.toInt
|
||||||
import de.bixilon.minosoft.assets.AssetsManager
|
import de.bixilon.minosoft.assets.AssetsManager
|
||||||
import de.bixilon.minosoft.data.container.stack.ItemStack
|
import de.bixilon.minosoft.data.container.stack.ItemStack
|
||||||
import de.bixilon.minosoft.data.registries.biomes.Biome
|
|
||||||
import de.bixilon.minosoft.data.registries.blocks.state.BlockState
|
import de.bixilon.minosoft.data.registries.blocks.state.BlockState
|
||||||
import de.bixilon.minosoft.data.registries.fluid.Fluid
|
import de.bixilon.minosoft.data.registries.fluid.Fluid
|
||||||
import de.bixilon.minosoft.data.text.formatting.color.RGBColor
|
import de.bixilon.minosoft.data.text.formatting.color.RGBColor
|
||||||
@ -47,10 +46,11 @@ class TintManager(val connection: PlayConnection) {
|
|||||||
DefaultTints.init(this)
|
DefaultTints.init(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getBlockTint(state: BlockState, biome: Biome?, x: Int, y: Int, z: Int): IntArray? {
|
fun getBlockTint(state: BlockState, chunk: Chunk?, x: Int, y: Int, z: Int): IntArray? {
|
||||||
if (state.block !is TintedBlock) return null
|
if (state.block !is TintedBlock) return null
|
||||||
val tintProvider = state.block.tintProvider ?: return null
|
val tintProvider = state.block.tintProvider ?: return null
|
||||||
val tints = IntArray(if (tintProvider is MultiTintProvider) tintProvider.tints else 1)
|
val tints = IntArray(if (tintProvider is MultiTintProvider) tintProvider.tints else 1)
|
||||||
|
val biome = chunk?.getBiome(x, y, z)
|
||||||
|
|
||||||
for (tintIndex in tints.indices) {
|
for (tintIndex in tints.indices) {
|
||||||
tints[tintIndex] = tintProvider.getBlockColor(state, biome, x, y, z, tintIndex)
|
tints[tintIndex] = tintProvider.getBlockColor(state, biome, x, y, z, tintIndex)
|
||||||
@ -70,10 +70,6 @@ class TintManager(val connection: PlayConnection) {
|
|||||||
return getParticleTint(blockState, position.x, position.y, position.z)
|
return getParticleTint(blockState, position.x, position.y, position.z)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getBlockTint(blockState: BlockState, biome: Biome? = null, blockPosition: Vec3i): IntArray? {
|
|
||||||
return getBlockTint(blockState, biome, blockPosition.x, blockPosition.y, blockPosition.z)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getFluidTint(chunk: Chunk, fluid: Fluid, height: Float, x: Int, y: Int, z: Int): Int? {
|
fun getFluidTint(chunk: Chunk, fluid: Fluid, height: Float, x: Int, y: Int, z: Int): Int? {
|
||||||
val biome = chunk.getBiome(x and 0x0F, y, z and 0x0F)
|
val biome = chunk.getBiome(x and 0x0F, y, z and 0x0F)
|
||||||
return fluid.model?.tint?.getFluidTint(fluid, biome, height, x, y, z)
|
return fluid.model?.tint?.getFluidTint(fluid, biome, height, x, y, z)
|
||||||
|
@ -24,7 +24,6 @@ import de.bixilon.minosoft.data.world.chunk.ChunkSection
|
|||||||
import de.bixilon.minosoft.data.world.chunk.chunk.Chunk
|
import de.bixilon.minosoft.data.world.chunk.chunk.Chunk
|
||||||
import de.bixilon.minosoft.data.world.chunk.chunk.ChunkPrototype
|
import de.bixilon.minosoft.data.world.chunk.chunk.ChunkPrototype
|
||||||
import de.bixilon.minosoft.data.world.chunk.neighbours.ChunkNeighbours
|
import de.bixilon.minosoft.data.world.chunk.neighbours.ChunkNeighbours
|
||||||
import de.bixilon.minosoft.data.world.container.block.BlockSectionDataProvider
|
|
||||||
import de.bixilon.minosoft.data.world.container.palette.PalettedContainer
|
import de.bixilon.minosoft.data.world.container.palette.PalettedContainer
|
||||||
import de.bixilon.minosoft.data.world.container.palette.PalettedContainerReader
|
import de.bixilon.minosoft.data.world.container.palette.PalettedContainerReader
|
||||||
import de.bixilon.minosoft.data.world.container.palette.palettes.BiomePaletteFactory
|
import de.bixilon.minosoft.data.world.container.palette.palettes.BiomePaletteFactory
|
||||||
@ -74,7 +73,7 @@ object ChunkUtil {
|
|||||||
|
|
||||||
// parse data
|
// parse data
|
||||||
var index = 0
|
var index = 0
|
||||||
val sections: Array<BlockSectionDataProvider?> = arrayOfNulls(dimension.sections)
|
val sections: Array<Array<BlockState?>?> = arrayOfNulls(dimension.sections)
|
||||||
for ((sectionIndex, sectionHeight) in (dimension.minSection..dimension.maxSection).withIndex()) {
|
for ((sectionIndex, sectionHeight) in (dimension.minSection..dimension.maxSection).withIndex()) {
|
||||||
if (!sectionBitMask[sectionIndex]) {
|
if (!sectionBitMask[sectionIndex]) {
|
||||||
continue
|
continue
|
||||||
@ -106,7 +105,7 @@ object ChunkUtil {
|
|||||||
|
|
||||||
blocks[yzx] = buffer.connection.registries.blockState.getOrNull(blockId) ?: continue
|
blocks[yzx] = buffer.connection.registries.blockState.getOrNull(blockId) ?: continue
|
||||||
}
|
}
|
||||||
sections[sectionHeight] = BlockSectionDataProvider(data = blocks)
|
sections[sectionHeight] = blocks
|
||||||
}
|
}
|
||||||
chunkData.blocks = sections
|
chunkData.blocks = sections
|
||||||
return chunkData
|
return chunkData
|
||||||
@ -139,7 +138,7 @@ object ChunkUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var index = 0
|
var index = 0
|
||||||
val sections: Array<BlockSectionDataProvider?> = arrayOfNulls(dimension.sections)
|
val sections: Array<Array<BlockState?>?> = arrayOfNulls(dimension.sections)
|
||||||
for ((sectionIndex, sectionHeight) in (dimension.minSection..dimension.maxSection).withIndex()) { // max sections per chunks in chunk column
|
for ((sectionIndex, sectionHeight) in (dimension.minSection..dimension.maxSection).withIndex()) { // max sections per chunks in chunk column
|
||||||
if (!sectionBitMask[sectionIndex]) {
|
if (!sectionBitMask[sectionIndex]) {
|
||||||
continue
|
continue
|
||||||
@ -150,7 +149,7 @@ object ChunkUtil {
|
|||||||
val block = buffer.connection.registries.blockState.getOrNull(blockId) ?: continue
|
val block = buffer.connection.registries.blockState.getOrNull(blockId) ?: continue
|
||||||
blocks[yzx] = block
|
blocks[yzx] = block
|
||||||
}
|
}
|
||||||
sections[sectionHeight] = BlockSectionDataProvider(data = blocks)
|
sections[sectionHeight] = blocks
|
||||||
}
|
}
|
||||||
chunkData.blocks = sections
|
chunkData.blocks = sections
|
||||||
return chunkData
|
return chunkData
|
||||||
@ -158,7 +157,7 @@ object ChunkUtil {
|
|||||||
|
|
||||||
fun readPaletteChunk(buffer: PlayInByteBuffer, dimension: DimensionProperties, sectionBitMask: BitSet?, complete: Boolean, skylight: Boolean = false): ChunkPrototype {
|
fun readPaletteChunk(buffer: PlayInByteBuffer, dimension: DimensionProperties, sectionBitMask: BitSet?, complete: Boolean, skylight: Boolean = false): ChunkPrototype {
|
||||||
val chunkData = ChunkPrototype()
|
val chunkData = ChunkPrototype()
|
||||||
val sectionBlocks: Array<BlockSectionDataProvider?> = arrayOfNulls(dimension.sections)
|
val sectionBlocks: Array<Array<BlockState?>?> = arrayOfNulls(dimension.sections)
|
||||||
val light: Array<ByteArray?> = arrayOfNulls(dimension.sections)
|
val light: Array<ByteArray?> = arrayOfNulls(dimension.sections)
|
||||||
var lightReceived = 0
|
var lightReceived = 0
|
||||||
val biomes: Array<Array<Biome?>?> = arrayOfNulls(dimension.sections)
|
val biomes: Array<Array<Biome?>?> = arrayOfNulls(dimension.sections)
|
||||||
@ -176,8 +175,8 @@ object ChunkUtil {
|
|||||||
val blockContainer: PalettedContainer<BlockState?> = PalettedContainerReader.read(buffer, buffer.connection.registries.blockState, paletteFactory = BlockStatePaletteFactory)
|
val blockContainer: PalettedContainer<BlockState?> = PalettedContainerReader.read(buffer, buffer.connection.registries.blockState, paletteFactory = BlockStatePaletteFactory)
|
||||||
|
|
||||||
if (!blockContainer.isEmpty) {
|
if (!blockContainer.isEmpty) {
|
||||||
val unpacked = BlockSectionDataProvider(data = blockContainer.unpack())
|
val unpacked = blockContainer.unpack<BlockState?>()
|
||||||
if (!unpacked.isEmpty) {
|
if (!unpacked.isEmpty()) {
|
||||||
sectionBlocks[sectionHeight - dimension.minSection] = unpacked
|
sectionBlocks[sectionHeight - dimension.minSection] = unpacked
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -311,4 +310,12 @@ object ChunkUtil {
|
|||||||
fun ChunkPosition.isInViewDistance(viewDistance: Int, cameraPosition: ChunkPosition): Boolean {
|
fun ChunkPosition.isInViewDistance(viewDistance: Int, cameraPosition: ChunkPosition): Boolean {
|
||||||
return abs(this.x - cameraPosition.x) <= viewDistance && abs(this.y - cameraPosition.y) <= viewDistance
|
return abs(this.x - cameraPosition.x) <= viewDistance && abs(this.y - cameraPosition.y) <= viewDistance
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun Array<BlockState?>.isEmpty(): Boolean {
|
||||||
|
for (entry in this) {
|
||||||
|
if (entry == null) continue
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user