diff --git a/src/integration-test/kotlin/de/bixilon/minosoft/data/world/WorldTestUtil.kt b/src/integration-test/kotlin/de/bixilon/minosoft/data/world/WorldTestUtil.kt index ceeae9aa1..edb114ae7 100644 --- a/src/integration-test/kotlin/de/bixilon/minosoft/data/world/WorldTestUtil.kt +++ b/src/integration-test/kotlin/de/bixilon/minosoft/data/world/WorldTestUtil.kt @@ -20,6 +20,8 @@ import de.bixilon.kutil.observer.DataObserver import de.bixilon.kutil.reflection.ReflectionUtil.forceSet import de.bixilon.minosoft.data.registries.blocks.state.BlockState import de.bixilon.minosoft.data.registries.dimension.DimensionProperties +import de.bixilon.minosoft.data.world.biome.WorldBiomes +import de.bixilon.minosoft.data.world.biome.source.BiomeSource import de.bixilon.minosoft.data.world.border.WorldBorder import de.bixilon.minosoft.data.world.chunk.ChunkSection.Companion.getIndex import de.bixilon.minosoft.data.world.chunk.chunk.Chunk @@ -48,14 +50,16 @@ object WorldTestUtil { world::entities.forceSet(WorldEntities()) world::view.forceSet(TEST_WORLD_VIEW) world::time.forceSet(DataObserver(WorldTime())) + world::biomes.forceSet(WorldBiomes(world)) return world } - fun World.initialize(size: Int) { + fun World.initialize(size: Int, biome: (ChunkPosition) -> BiomeSource) { for (x in -size..size) { for (z in -size..size) { - chunks.create(ChunkPosition(x, z)) + val position = ChunkPosition(x, z) + chunks.create(position, biome.invoke(position)) } } } diff --git a/src/integration-test/kotlin/de/bixilon/minosoft/data/world/biome/WorldBiomesTest.kt b/src/integration-test/kotlin/de/bixilon/minosoft/data/world/biome/WorldBiomesTest.kt new file mode 100644 index 000000000..7eb43ee23 --- /dev/null +++ b/src/integration-test/kotlin/de/bixilon/minosoft/data/world/biome/WorldBiomesTest.kt @@ -0,0 +1,149 @@ +/* + * 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 . + * + * This software is not affiliated with Mojang AB, the original developer of Minecraft. + */ + +package de.bixilon.minosoft.data.world.biome + +import de.bixilon.minosoft.data.registries.biomes.Biome +import de.bixilon.minosoft.data.registries.identified.Namespaces.minosoft +import de.bixilon.minosoft.data.world.World +import de.bixilon.minosoft.data.world.WorldTestUtil.initialize +import de.bixilon.minosoft.data.world.biome.accessor.noise.NoiseBiomeAccessor +import de.bixilon.minosoft.data.world.biome.source.BiomeSource +import de.bixilon.minosoft.data.world.biome.source.DummyBiomeSource +import de.bixilon.minosoft.data.world.chunk.chunk.Chunk +import de.bixilon.minosoft.data.world.positions.BlockPosition +import de.bixilon.minosoft.data.world.positions.ChunkPosition +import de.bixilon.minosoft.data.world.positions.InChunkPosition +import de.bixilon.minosoft.protocol.network.connection.play.ConnectionTestUtil.createConnection +import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection +import org.testng.Assert.* +import org.testng.annotations.Test + +@Test(groups = ["biomes"]) +class WorldBiomesTest { + private val b1 = Biome(minosoft("b1"), 0.0f, 0.0f) + private val b2 = Biome(minosoft("b2"), 0.0f, 0.0f) + private val b3 = Biome(minosoft("b3"), 0.0f, 0.0f) + + private fun create(noise: ((PlayConnection) -> NoiseBiomeAccessor)?, source: (ChunkPosition) -> BiomeSource): World { + val connection = createConnection(0) + connection.world.biomes.noise = noise?.invoke(connection) + connection.world.initialize(1, source) + + return connection.world + } + + fun `simple biome getting at origin chunk`() { + val world = create(null) { if (it.x == 0 && it.y == 0) PositionedSource(InChunkPosition(1, 2, 3), b1, b3) else DummyBiomeSource(b2) } + assertEquals(world.biomes[1, 2, 3], b1) + assertEquals(world.biomes[1, 2, 4], b3) + assertEquals(world.biomes[16, 2, 4], b2) + assertEquals(world.biomes[BlockPosition(1, 2, 3)], b1) + assertEquals(world.biomes[BlockPosition(1, 2, 4)], b3) + assertEquals(world.biomes[BlockPosition(16, 2, 4)], b2) + val chunk = world.chunks[0, 0]!! + assertEquals(world.biomes.getBiome(1, 2, 3, chunk), b1) + assertEquals(world.biomes.getBiome(1, 2, 4, chunk), b3) + assertEquals(chunk.getBiome(1, 2, 3), b1) + assertEquals(chunk.getBiome(1, 2, 4), b3) + } + + fun `simple biome getting at chunk -1, -1`() { + val world = create(null) { if (it.x == -1 && it.y == -1) PositionedSource(InChunkPosition(15, 2, 14), b1, b3) else DummyBiomeSource(b2) } + assertEquals(world.biomes[-1, 2, -2], b1) + assertEquals(world.biomes[-1, 2, -6], b3) + assertEquals(world.biomes[1, 2, 6], b2) + assertEquals(world.biomes[BlockPosition(-1, 2, -2)], b1) + val chunk = world.chunks[-1, -1]!! + assertEquals(world.biomes.getBiome(15, 2, 14, chunk), b1) + assertEquals(world.biomes.getBiome(15, 2, 13, chunk), b3) + assertEquals(chunk.getBiome(15, 2, 14), b1) + assertEquals(chunk.getBiome(15, 2, 13), b3) + } + + fun `ensure no caching is done without noise`() { + val source = CounterSource(b1) + val world = create(null) { source } + val chunk = world.chunks[0, 0]!! + chunk.getOrPut(0) + + assertEquals(source.counter, 0) + assertEquals(world.biomes[1, 2, 3], b1) + assertEquals(source.counter, 1) + assertFalse(chunk.cacheBiomes) + assertEquals(chunk[0]!!.biomes[1, 2, 3], null) + } + + fun `ensure caching is done with noise`() { + val source = CounterSource(b1) + val world = create({ FastNoiseAccessor(it) }) { source } + val chunk = world.chunks[0, 0]!! + chunk.getOrPut(0) + + assertEquals(source.counter, 4096) + assertEquals(world.biomes[1, 2, 3], b1) + assertEquals(source.counter, 4096) + assertTrue(chunk.cacheBiomes) + assertEquals(chunk[0]!!.biomes[1, 2, 3], b1) + } + + fun `ensure world position is converted to chunk position`() { + val source = VerifyPositionSource(b1) + val world = create(null) { source } + + assertEquals(world.biomes[1, 2, 3], b1) + assertEquals(world.biomes[16, 2, 4], b1) + assertEquals(world.biomes[-4, 2, -4], b1) + + assertEquals(world.biomes[-4, -2, -4], b1) + assertEquals(world.biomes[-4, 1024, -4], b1) + } + + + private class PositionedSource( + val position: InChunkPosition, + val biome: Biome?, + val fallback: Biome?, + ) : BiomeSource { + + override fun getBiome(x: Int, y: Int, z: Int): Biome? { + if (x != position.x || y != position.y || z != position.z) return fallback + return biome + } + } + + private class CounterSource(val biome: Biome?) : BiomeSource { + var counter = 0 + override fun getBiome(x: Int, y: Int, z: Int): Biome? { + counter++ + return biome + } + } + + private class VerifyPositionSource(val biome: Biome?) : BiomeSource { + override fun getBiome(x: Int, y: Int, z: Int): Biome? { + if (x < 0 || x > 15) throw IllegalArgumentException("Invalid x: $x") + if (y < 0 || y > 255) throw IllegalArgumentException("Invalid y: $y") + if (z < 0 || z > 15) throw IllegalArgumentException("Invalid z: $z") + + return biome + } + } + + private class FastNoiseAccessor(connection: PlayConnection) : NoiseBiomeAccessor(connection, 0L) { + + override fun get(x: Int, y: Int, z: Int, chunkPositionX: Int, chunkPositionZ: Int, chunk: Chunk, neighbours: Array?): Biome? { + return chunk.biomeSource.getBiome(x, y, z) + } + } +} diff --git a/src/integration-test/kotlin/de/bixilon/minosoft/data/world/biome/accessor/NoiseBiomeAccessorTest.kt b/src/integration-test/kotlin/de/bixilon/minosoft/data/world/biome/accessor/VoronoiBiomeAccessorTest.kt similarity index 87% rename from src/integration-test/kotlin/de/bixilon/minosoft/data/world/biome/accessor/NoiseBiomeAccessorTest.kt rename to src/integration-test/kotlin/de/bixilon/minosoft/data/world/biome/accessor/VoronoiBiomeAccessorTest.kt index 399b9cd53..3dfa9885f 100644 --- a/src/integration-test/kotlin/de/bixilon/minosoft/data/world/biome/accessor/NoiseBiomeAccessorTest.kt +++ b/src/integration-test/kotlin/de/bixilon/minosoft/data/world/biome/accessor/VoronoiBiomeAccessorTest.kt @@ -1,6 +1,6 @@ /* * Minosoft - * Copyright (C) 2020-2022 Moritz Zwerger + * 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. * @@ -14,12 +14,14 @@ package de.bixilon.minosoft.data.world.biome.accessor import de.bixilon.kotlinglm.vec3.Vec3i +import de.bixilon.minosoft.data.world.biome.accessor.noise.VoronoiBiomeAccessor +import de.bixilon.minosoft.test.ITUtil.allocate import org.objenesis.ObjenesisStd import org.testng.Assert.assertEquals import org.testng.annotations.Test @Test(groups = ["biome"]) -class NoiseBiomeAccessorTest { +class VoronoiBiomeAccessorTest { private val OBJENESIS = ObjenesisStd() fun testBiomeNoise1() { @@ -51,7 +53,7 @@ class NoiseBiomeAccessorTest { } private fun calculate(x: Int, y: Int, z: Int, seed: Long): Vec3i { - val accessor = OBJENESIS.newInstance(NoiseBiomeAccessor::class.java) + val accessor = VoronoiBiomeAccessor::class.java.allocate() return accessor.getBiomePosition(seed, x, y, z) } } diff --git a/src/integration-test/kotlin/de/bixilon/minosoft/data/world/chunk/LightTestingUtil.kt b/src/integration-test/kotlin/de/bixilon/minosoft/data/world/chunk/LightTestingUtil.kt index 4f8ec743d..997a1ae20 100644 --- a/src/integration-test/kotlin/de/bixilon/minosoft/data/world/chunk/LightTestingUtil.kt +++ b/src/integration-test/kotlin/de/bixilon/minosoft/data/world/chunk/LightTestingUtil.kt @@ -21,6 +21,7 @@ import de.bixilon.kutil.reflection.ReflectionUtil.jvmField import de.bixilon.minosoft.data.registries.blocks.state.BlockState import de.bixilon.minosoft.data.registries.dimension.DimensionProperties import de.bixilon.minosoft.data.world.World +import de.bixilon.minosoft.data.world.biome.WorldBiomes import de.bixilon.minosoft.data.world.chunk.chunk.Chunk import de.bixilon.minosoft.data.world.chunk.light.ChunkLight import de.bixilon.minosoft.data.world.chunk.neighbours.ChunkNeighbours @@ -48,6 +49,7 @@ object LightTestingUtil { val world = objenesis.newInstance(World::class.java) world::dimension.forceSet(DataObserver(DimensionProperties(skyLight = true))) world::connection.forceSet(createConnection()) + world::biomes.forceSet(WorldBiomes(world)) return world } diff --git a/src/integration-test/kotlin/de/bixilon/minosoft/data/world/chunk/manager/ChunkManagerTest.kt b/src/integration-test/kotlin/de/bixilon/minosoft/data/world/chunk/manager/ChunkManagerTest.kt index 09bf742a6..83d83cc06 100644 --- a/src/integration-test/kotlin/de/bixilon/minosoft/data/world/chunk/manager/ChunkManagerTest.kt +++ b/src/integration-test/kotlin/de/bixilon/minosoft/data/world/chunk/manager/ChunkManagerTest.kt @@ -17,7 +17,7 @@ import de.bixilon.kotlinglm.vec2.Vec2i import de.bixilon.minosoft.data.registries.biomes.Biome import de.bixilon.minosoft.data.registries.blocks.types.stone.StoneTest0 import de.bixilon.minosoft.data.registries.identified.Namespaces.minosoft -import de.bixilon.minosoft.data.world.biome.accessor.NoiseBiomeAccessor +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.DummyBiomeSource import de.bixilon.minosoft.data.world.biome.source.SpatialBiomeArray @@ -428,7 +428,7 @@ class ChunkManagerTest { fun noBiomeCache() { val manager = create() - manager.world.cacheBiomeAccessor = null + manager.world.biomes.noise = null val matrix = manager.createMatrix() val chunk = matrix[1][1] @@ -438,7 +438,7 @@ class ChunkManagerTest { fun noiseBiomeCache() { val manager = create() val biome = Biome(minosoft("test"), 0.0f, 0.0f, null, null, null, null, null) - manager.world.cacheBiomeAccessor = NoiseBiomeAccessor(manager.world.connection, 0L) + manager.world.biomes.noise = VoronoiBiomeAccessor(manager.world.connection, 0L) val source = SpatialBiomeArray(Array(1024) { biome }) val matrix = manager.createMatrix(source) @@ -446,7 +446,7 @@ class ChunkManagerTest { assertEquals(chunk.getOrPut(0)!!.biomes.count, 4096) assertEquals(chunk.getOrPut(0)!!.biomes[0], biome) - assertEquals(manager.world.getBiome(BlockPosition(5, 5, 5)), biome) + assertEquals(manager.world.biomes.getBiome(BlockPosition(5, 5, 5)), biome) assertEquals(chunk.getBiome(BlockPosition(5, 5, 5)), biome) } } diff --git a/src/integration-test/kotlin/de/bixilon/minosoft/protocol/network/connection/play/ConnectionTestUtil.kt b/src/integration-test/kotlin/de/bixilon/minosoft/protocol/network/connection/play/ConnectionTestUtil.kt index 3e53c08af..77e37d3b9 100644 --- a/src/integration-test/kotlin/de/bixilon/minosoft/protocol/network/connection/play/ConnectionTestUtil.kt +++ b/src/integration-test/kotlin/de/bixilon/minosoft/protocol/network/connection/play/ConnectionTestUtil.kt @@ -30,6 +30,7 @@ import de.bixilon.minosoft.data.language.lang.LanguageList import de.bixilon.minosoft.data.registries.registries.Registries import de.bixilon.minosoft.data.world.WorldTestUtil.createWorld import de.bixilon.minosoft.data.world.WorldTestUtil.initialize +import de.bixilon.minosoft.data.world.biome.source.DummyBiomeSource import de.bixilon.minosoft.modding.event.master.EventMaster import de.bixilon.minosoft.protocol.network.network.client.test.TestNetwork import de.bixilon.minosoft.protocol.versions.Versions @@ -93,7 +94,7 @@ object ConnectionTestUtil { CAMERA.forceSet(connection, ConnectionCamera(connection)) connection.camera.init() if (worldSize > 0) { - connection.world.initialize(worldSize) + connection.world.initialize(worldSize) { DummyBiomeSource(null) } } return connection } diff --git a/src/main/java/de/bixilon/minosoft/data/registries/blocks/types/building/plants/DoublePlant.kt b/src/main/java/de/bixilon/minosoft/data/registries/blocks/types/building/plants/DoublePlant.kt index ba33f3cab..7f2e01d91 100644 --- a/src/main/java/de/bixilon/minosoft/data/registries/blocks/types/building/plants/DoublePlant.kt +++ b/src/main/java/de/bixilon/minosoft/data/registries/blocks/types/building/plants/DoublePlant.kt @@ -120,7 +120,7 @@ abstract class DoublePlant(identifier: ResourceLocation, settings: BlockSettings override val tintProvider: TintProvider? = null override fun initTint(manager: TintManager) { - this::tintProvider.forceSet(TallGrassTintCalculator(manager.grassTintCalculator)) + this::tintProvider.forceSet(TallGrassTintCalculator(manager.grass)) } companion object : BlockFactory { @@ -135,7 +135,7 @@ abstract class DoublePlant(identifier: ResourceLocation, settings: BlockSettings override val tintProvider: TintProvider? = null override fun initTint(manager: TintManager) { - this::tintProvider.forceSet(TallGrassTintCalculator(manager.grassTintCalculator)) + this::tintProvider.forceSet(TallGrassTintCalculator(manager.grass)) } companion object : BlockFactory { @@ -173,7 +173,7 @@ abstract class DoublePlant(identifier: ResourceLocation, settings: BlockSettings } override fun initTint(manager: TintManager) { - this::tintProvider.forceSet(TallGrassTintCalculator(manager.grassTintCalculator)) // TODO: only tint if lower block is tinted + this::tintProvider.forceSet(TallGrassTintCalculator(manager.grass)) // TODO: only tint if lower block is tinted } private class Model : PickedBlockRender { diff --git a/src/main/java/de/bixilon/minosoft/data/registries/blocks/types/wood/LeavesBlock.kt b/src/main/java/de/bixilon/minosoft/data/registries/blocks/types/wood/LeavesBlock.kt index fad01a653..4b083dda5 100644 --- a/src/main/java/de/bixilon/minosoft/data/registries/blocks/types/wood/LeavesBlock.kt +++ b/src/main/java/de/bixilon/minosoft/data/registries/blocks/types/wood/LeavesBlock.kt @@ -47,7 +47,7 @@ abstract class LeavesBlock(identifier: ResourceLocation, settings: BlockSettings override val tintProvider: TintProvider? = null override fun initTint(manager: TintManager) { - this::tintProvider.forceSet(manager.foliageTintCalculator) + this::tintProvider.forceSet(manager.foliage) } override fun buildState(version: Version, settings: BlockStateSettings): BlockState { 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 06e21064f..a57bd8e52 100644 --- a/src/main/java/de/bixilon/minosoft/data/world/World.kt +++ b/src/main/java/de/bixilon/minosoft/data/world/World.kt @@ -20,7 +20,6 @@ import de.bixilon.kutil.observer.DataObserver.Companion.observed import de.bixilon.kutil.random.RandomUtil.nextInt import de.bixilon.minosoft.data.entities.block.BlockEntity import de.bixilon.minosoft.data.entities.entities.Entity -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.properties.rendering.RandomDisplayTickable import de.bixilon.minosoft.data.registries.dimension.DimensionProperties @@ -28,8 +27,7 @@ import de.bixilon.minosoft.data.registries.identified.ResourceLocation import de.bixilon.minosoft.data.registries.shapes.aabb.AABB import de.bixilon.minosoft.data.world.audio.AbstractAudioPlayer import de.bixilon.minosoft.data.world.audio.WorldAudioPlayer -import de.bixilon.minosoft.data.world.biome.accessor.BiomeAccessor -import de.bixilon.minosoft.data.world.biome.accessor.NoiseBiomeAccessor +import de.bixilon.minosoft.data.world.biome.WorldBiomes import de.bixilon.minosoft.data.world.border.WorldBorder import de.bixilon.minosoft.data.world.chunk.chunk.Chunk import de.bixilon.minosoft.data.world.chunk.light.ChunkLightUtil.hasSkyLight @@ -57,10 +55,10 @@ import java.util.* */ class World( val connection: PlayConnection, -) : BiomeAccessor, WorldAudioPlayer, WorldParticleRenderer { +) : WorldAudioPlayer, WorldParticleRenderer { val lock = SimpleLock() val random = Random() - var cacheBiomeAccessor: NoiseBiomeAccessor? = null + val biomes = WorldBiomes(this) val chunks = ChunkManager(this, 1000, 100) val entities = WorldEntities() var hardcore by observed(false) @@ -149,14 +147,6 @@ class World( chunks[position.chunkPosition]?.set(position.inChunkPosition, entity) // TODO: fire event if needed } - override fun getBiome(blockPosition: BlockPosition): Biome? { - return chunks[blockPosition.chunkPosition]?.getBiome(blockPosition.inChunkPosition) - } - - override fun getBiome(x: Int, y: Int, z: Int): Biome? { - return this.chunks[Vec2i(x shr 4, z shr 4)]?.getBiome(x and 0x0F, y, z and 0x0F) - } - fun tick() { val simulationDistance = view.simulationDistance val cameraPosition = connection.player.physics.positionInfo.chunkPosition diff --git a/src/main/java/de/bixilon/minosoft/data/world/audio/WorldAudioPlayer.kt b/src/main/java/de/bixilon/minosoft/data/world/audio/WorldAudioPlayer.kt index 0d4d093cd..b67cb06de 100644 --- a/src/main/java/de/bixilon/minosoft/data/world/audio/WorldAudioPlayer.kt +++ b/src/main/java/de/bixilon/minosoft/data/world/audio/WorldAudioPlayer.kt @@ -16,7 +16,7 @@ package de.bixilon.minosoft.data.world.audio import de.bixilon.kotlinglm.vec3.Vec3d import de.bixilon.minosoft.data.registries.identified.ResourceLocation -@Deprecated("") +@Deprecated("use world.audio") interface WorldAudioPlayer : AbstractAudioPlayer { val audioPlayer: AbstractAudioPlayer? diff --git a/src/main/java/de/bixilon/minosoft/data/world/biome/WorldBiomes.kt b/src/main/java/de/bixilon/minosoft/data/world/biome/WorldBiomes.kt new file mode 100644 index 000000000..4be7344b0 --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/data/world/biome/WorldBiomes.kt @@ -0,0 +1,52 @@ +/* + * 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 . + * + * This software is not affiliated with Mojang AB, the original developer of Minecraft. + */ + +package de.bixilon.minosoft.data.world.biome + +import de.bixilon.kotlinglm.func.common.clamp +import de.bixilon.minosoft.data.registries.biomes.Biome +import de.bixilon.minosoft.data.world.World +import de.bixilon.minosoft.data.world.biome.accessor.BiomeAccessor +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.positions.BlockPosition +import de.bixilon.minosoft.gui.rendering.util.VecUtil.sectionHeight + +class WorldBiomes(val world: World) : BiomeAccessor { + var noise: NoiseBiomeAccessor? = null + set(value) { + field = value + resetCache() + } + + operator fun get(position: BlockPosition) = getBiome(position) + override fun getBiome(position: BlockPosition) = getBiome(position.x, position.y, position.z) + + operator fun get(x: Int, y: Int, z: Int) = getBiome(x, y, z) + override fun getBiome(x: Int, y: Int, z: Int): Biome? { + val chunk = world.chunks[x shr 4, z shr 4] ?: return null + return getBiome(x and 0x0F, y.clamp(world.dimension.minY, world.dimension.maxY), z and 0x0F, chunk) + } + + fun getBiome(x: Int, y: Int, z: Int, chunk: Chunk): Biome? { + val noise = this.noise ?: return chunk.biomeSource.getBiome(x, y, z) + chunk[y.sectionHeight]?.let { return it.biomes[x, y, z] } // access cache + + return noise.get(x, y, z, chunk) + } + + + fun resetCache() { + // TODO + } +} diff --git a/src/main/java/de/bixilon/minosoft/data/world/biome/accessor/BiomeAccessor.kt b/src/main/java/de/bixilon/minosoft/data/world/biome/accessor/BiomeAccessor.kt index 3cbceeb19..e7795627c 100644 --- a/src/main/java/de/bixilon/minosoft/data/world/biome/accessor/BiomeAccessor.kt +++ b/src/main/java/de/bixilon/minosoft/data/world/biome/accessor/BiomeAccessor.kt @@ -1,6 +1,6 @@ /* * Minosoft - * Copyright (C) 2020-2022 Moritz Zwerger + * 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. * @@ -19,8 +19,8 @@ import de.bixilon.minosoft.data.registries.biomes.Biome interface BiomeAccessor { - fun getBiome(blockPosition: Vec3i): Biome? { - return getBiome(blockPosition.x, blockPosition.y, blockPosition.z) + fun getBiome(position: Vec3i): Biome? { + return getBiome(position.x, position.y, position.z) } fun getBiome(x: Int, y: Int, z: Int): Biome? diff --git a/src/main/java/de/bixilon/minosoft/data/world/biome/accessor/NullBiomeAccessor.kt b/src/main/java/de/bixilon/minosoft/data/world/biome/accessor/NullBiomeAccessor.kt index e3ac8294a..a9fd93c6c 100644 --- a/src/main/java/de/bixilon/minosoft/data/world/biome/accessor/NullBiomeAccessor.kt +++ b/src/main/java/de/bixilon/minosoft/data/world/biome/accessor/NullBiomeAccessor.kt @@ -1,6 +1,6 @@ /* * Minosoft - * Copyright (C) 2020-2022 Moritz Zwerger + * 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. * @@ -19,7 +19,7 @@ import de.bixilon.minosoft.data.registries.biomes.Biome object NullBiomeAccessor : BiomeAccessor { - override fun getBiome(blockPosition: Vec3i): Biome? { + override fun getBiome(position: Vec3i): Biome? { return null } diff --git a/src/main/java/de/bixilon/minosoft/data/world/biome/accessor/noise/NoiseBiomeAccessor.kt b/src/main/java/de/bixilon/minosoft/data/world/biome/accessor/noise/NoiseBiomeAccessor.kt new file mode 100644 index 000000000..9da4de0e1 --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/data/world/biome/accessor/noise/NoiseBiomeAccessor.kt @@ -0,0 +1,49 @@ +/* + * 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 . + * + * This software is not affiliated with Mojang AB, the original developer of Minecraft. + */ + +package de.bixilon.minosoft.data.world.biome.accessor.noise + +import de.bixilon.kutil.observer.DataObserver.Companion.observe +import de.bixilon.minosoft.data.registries.biomes.Biome +import de.bixilon.minosoft.data.world.chunk.chunk.Chunk +import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection +import de.bixilon.minosoft.protocol.protocol.ProtocolVersions.V_19W36A + +abstract class NoiseBiomeAccessor( + connection: PlayConnection, + val seed: Long = 0L, +) { + protected val world = connection.world + protected var fastNoise = false + + init { + val profile = connection.profiles.rendering + profile.performance::fastBiomeNoise.observe(this, true) { fastNoise = it } + } + + abstract fun get(x: Int, y: Int, z: Int, chunkPositionX: Int, chunkPositionZ: Int, chunk: Chunk, neighbours: Array?): Biome? + + fun get(x: Int, y: Int, z: Int, chunk: Chunk): Biome? { + val neighbours = chunk.neighbours.get() ?: return null + return get((chunk.chunkPosition.x shl 4) or x, y, (chunk.chunkPosition.y shl 4) or z, chunk.chunkPosition.x, chunk.chunkPosition.y, chunk, neighbours) + } + + + companion object { + + fun get(connection: PlayConnection, seed: Long): NoiseBiomeAccessor? = when { + connection.version < V_19W36A -> null + else -> VoronoiBiomeAccessor(connection, seed) + } + } +} diff --git a/src/main/java/de/bixilon/minosoft/data/world/biome/accessor/NoiseBiomeAccessor.kt b/src/main/java/de/bixilon/minosoft/data/world/biome/accessor/noise/VoronoiBiomeAccessor.kt similarity index 84% rename from src/main/java/de/bixilon/minosoft/data/world/biome/accessor/NoiseBiomeAccessor.kt rename to src/main/java/de/bixilon/minosoft/data/world/biome/accessor/noise/VoronoiBiomeAccessor.kt index 4e127a1d4..e18815894 100644 --- a/src/main/java/de/bixilon/minosoft/data/world/biome/accessor/NoiseBiomeAccessor.kt +++ b/src/main/java/de/bixilon/minosoft/data/world/biome/accessor/noise/VoronoiBiomeAccessor.kt @@ -11,30 +11,22 @@ * This software is not affiliated with Mojang AB, the original developer of Minecraft. */ -package de.bixilon.minosoft.data.world.biome.accessor +package de.bixilon.minosoft.data.world.biome.accessor.noise import de.bixilon.kotlinglm.vec2.Vec2i import de.bixilon.kotlinglm.vec3.Vec3i import de.bixilon.kutil.math.simple.DoubleMath.square -import de.bixilon.kutil.observer.DataObserver.Companion.observe import de.bixilon.minosoft.data.registries.biomes.Biome import de.bixilon.minosoft.data.world.biome.source.SpatialBiomeArray import de.bixilon.minosoft.data.world.chunk.chunk.Chunk import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection -class NoiseBiomeAccessor( - private val connection: PlayConnection, - var hashedSeed: Long = 0L, -) { - private val world = connection.world - private var fastNoise = false +open class VoronoiBiomeAccessor( + connection: PlayConnection, + seed: Long = 0L, +) : NoiseBiomeAccessor(connection, seed) { - init { - val profile = connection.profiles.rendering - profile.performance::fastBiomeNoise.observe(this, true) { fastNoise = it } - } - - fun getBiome(x: Int, y: Int, z: Int, chunkPositionX: Int, chunkPositionZ: Int, chunk: Chunk, neighbours: Array?): Biome? { + override fun get(x: Int, y: Int, z: Int, chunkPositionX: Int, chunkPositionZ: Int, chunk: Chunk, neighbours: Array?): Biome? { val biomeY = if (world.dimension.supports3DBiomes) y else 0 if (fastNoise) { @@ -44,7 +36,7 @@ class NoiseBiomeAccessor( return source.data[(biomeY and 0x0F) shr 2 and 0x3F shl 4 or ((z and 0x0F) shr 2 and 0x03 shl 2) or ((x and 0x0F) shr 2 and 0x03)] } - return getBiome(hashedSeed, x, biomeY, z, chunkPositionX, chunkPositionZ, chunk, neighbours) + return getBiome(seed, x, biomeY, z, chunkPositionX, chunkPositionZ, chunk, neighbours) } @@ -156,17 +148,17 @@ class NoiseBiomeAccessor( ret = next(ret, y) ret = next(ret, z) - val xFractionSalt = distribute(ret) + val xSalt = distribute(ret) ret = next(ret, seed) - val yFractionSalt = distribute(ret) + val ySalt = distribute(ret) ret = next(ret, seed) - val zFractionSalt = distribute(ret) + val zSalt = distribute(ret) - return (xFraction + xFractionSalt).square() + (yFraction + yFractionSalt).square() + (zFraction + zFractionSalt).square() + return (xFraction + xSalt).square() + (yFraction + ySalt).square() + (zFraction + zSalt).square() } private fun distribute(seed: Long): Double { diff --git a/src/main/java/de/bixilon/minosoft/data/world/chunk/ChunkSection.kt b/src/main/java/de/bixilon/minosoft/data/world/chunk/ChunkSection.kt index 5f4408c7f..8b95322d4 100644 --- a/src/main/java/de/bixilon/minosoft/data/world/chunk/ChunkSection.kt +++ b/src/main/java/de/bixilon/minosoft/data/world/chunk/ChunkSection.kt @@ -19,7 +19,7 @@ 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.registries.biomes.Biome -import de.bixilon.minosoft.data.world.biome.accessor.NoiseBiomeAccessor +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.light.SectionLight import de.bixilon.minosoft.data.world.container.SectionDataProvider @@ -67,7 +67,7 @@ class ChunkSection( } } - fun buildBiomeCache(neighbours: Array, biomeAccessor: NoiseBiomeAccessor) { + fun buildBiomeCache(neighbours: Array, noise: NoiseBiomeAccessor) { val chunkPositionX = chunk.chunkPosition.x val chunkPositionZ = chunk.chunkPosition.y val blockOffset = Vec3i.of(chunk.chunkPosition, sectionHeight) @@ -76,7 +76,7 @@ class ChunkSection( val z = blockOffset.z val biomes: Array = 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] = noise.get(x + (index and 0x0F), y + ((index shr 8) and 0x0F), z + ((index shr 4) and 0x0F), chunkPositionX, chunkPositionZ, chunk, neighbours) } this.biomes.setData(biomes.cast()) } diff --git a/src/main/java/de/bixilon/minosoft/data/world/chunk/chunk/Chunk.kt b/src/main/java/de/bixilon/minosoft/data/world/chunk/chunk/Chunk.kt index f124bc7db..291e8a8c5 100644 --- a/src/main/java/de/bixilon/minosoft/data/world/chunk/chunk/Chunk.kt +++ b/src/main/java/de/bixilon/minosoft/data/world/chunk/chunk/Chunk.kt @@ -52,7 +52,7 @@ class Chunk( val light = ChunkLight(this) val minSection = world.dimension.minSection val maxSection = world.dimension.maxSection - val cacheBiomes = world.cacheBiomeAccessor != null + val cacheBiomes = world.biomes.noise != null val neighbours = ChunkNeighbours(this) @@ -187,7 +187,7 @@ class Chunk( section.blocks.unsafeSetSection(section) val neighbours = this.neighbours.get() if (neighbours != null) { - this.neighbours.completeSection(neighbours, section, sectionHeight, world.cacheBiomeAccessor) + this.neighbours.completeSection(neighbours, section, sectionHeight, world.biomes.noise) } sections[index] = section @@ -230,11 +230,10 @@ class Chunk( override fun getBiome(x: Int, y: Int, z: Int): Biome? { val y = y.clamp(world.dimension.minY, world.dimension.maxY) - if (cacheBiomes) { - val section = this[y.sectionHeight] ?: return connection.world.cacheBiomeAccessor?.getBiome((chunkPosition.x shl 4) or x, y, (chunkPosition.y shl 4) or z, chunkPosition.x, chunkPosition.y, this, this.neighbours.get()) - return section.biomes[x, y.inSectionHeight, z] + if (!cacheBiomes) { + return biomeSource.getBiome(x, y, z) } - return biomeSource.getBiome(x and 0x0F, y, z and 0x0F) + return connection.world.biomes.getBiome(x, y, z, this) } } diff --git a/src/main/java/de/bixilon/minosoft/data/world/chunk/neighbours/ChunkNeighbours.kt b/src/main/java/de/bixilon/minosoft/data/world/chunk/neighbours/ChunkNeighbours.kt index 720c23484..1d8dcc011 100644 --- a/src/main/java/de/bixilon/minosoft/data/world/chunk/neighbours/ChunkNeighbours.kt +++ b/src/main/java/de/bixilon/minosoft/data/world/chunk/neighbours/ChunkNeighbours.kt @@ -18,7 +18,7 @@ import de.bixilon.kotlinglm.vec3.Vec3i import de.bixilon.kutil.cast.CastUtil.unsafeCast import de.bixilon.kutil.exception.Broken import de.bixilon.minosoft.data.registries.blocks.state.BlockState -import de.bixilon.minosoft.data.world.biome.accessor.NoiseBiomeAccessor +import de.bixilon.minosoft.data.world.biome.accessor.noise.NoiseBiomeAccessor import de.bixilon.minosoft.data.world.chunk.ChunkSection import de.bixilon.minosoft.data.world.chunk.chunk.Chunk import de.bixilon.minosoft.data.world.positions.ChunkPositionUtil.chunkPosition @@ -70,19 +70,19 @@ class ChunkNeighbours(val chunk: Chunk) : Iterable { remove(getIndex(offset)) } - fun completeSection(neighbours: Array, section: ChunkSection, sectionHeight: SectionHeight, biomeCacheAccessor: NoiseBiomeAccessor?) { + fun completeSection(neighbours: Array, section: ChunkSection, sectionHeight: SectionHeight, noise: NoiseBiomeAccessor?) { section.neighbours = ChunkUtil.getDirectNeighbours(neighbours, chunk, sectionHeight) - if (biomeCacheAccessor != null) { - section.buildBiomeCache(neighbours, biomeCacheAccessor) + if (noise != null) { + section.buildBiomeCache(neighbours, noise) } } private fun complete(neighbours: Array) { - val biomeCacheAccessor = chunk.world.cacheBiomeAccessor + val noise = chunk.world.biomes.noise for ((index, section) in chunk.sections.withIndex()) { if (section == null) continue val sectionHeight = index + chunk.minSection - completeSection(neighbours, section, sectionHeight, biomeCacheAccessor) + completeSection(neighbours, section, sectionHeight, noise) } chunk.light.recalculate(false) chunk.light.propagateFromNeighbours(fireEvent = false, fireSameChunkEvent = false) diff --git a/src/main/java/de/bixilon/minosoft/data/world/particle/WorldParticleRenderer.kt b/src/main/java/de/bixilon/minosoft/data/world/particle/WorldParticleRenderer.kt index b45b17414..ca61de003 100644 --- a/src/main/java/de/bixilon/minosoft/data/world/particle/WorldParticleRenderer.kt +++ b/src/main/java/de/bixilon/minosoft/data/world/particle/WorldParticleRenderer.kt @@ -15,7 +15,7 @@ package de.bixilon.minosoft.data.world.particle import de.bixilon.minosoft.gui.rendering.particle.types.Particle -@Deprecated("") +@Deprecated("use world.particle") interface WorldParticleRenderer : AbstractParticleRenderer { val particleRenderer: AbstractParticleRenderer? diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/tint/DefaultTints.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/tint/DefaultTints.kt index 1a1cf6027..a58987b9f 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/tint/DefaultTints.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/tint/DefaultTints.kt @@ -28,10 +28,10 @@ import de.bixilon.minosoft.gui.rendering.tint.tints.redstone.RedstoneWireTintCal object DefaultTints { fun init(manager: TintManager) { - manager.applyTo(setOf(MinecraftBlocks.POTTED_FERN), manager.grassTintCalculator) + manager.applyTo(setOf(MinecraftBlocks.POTTED_FERN), manager.grass) manager.applyTo(setOf(MinecraftBlocks.REDSTONE_WIRE), RedstoneWireTintCalculator) manager.applyTo(setOf(MinecraftBlocks.WATER_CAULDRON, MinecraftBlocks.CAULDRON), WaterTintProvider) - manager.applyTo(setOf(MinecraftBlocks.SUGAR_CANE), SugarCaneTintCalculator(manager.grassTintCalculator)) + manager.applyTo(setOf(MinecraftBlocks.SUGAR_CANE), SugarCaneTintCalculator(manager.grass)) manager.applyTo(setOf(MinecraftBlocks.ATTACHED_MELON_STEM, MinecraftBlocks.ATTACHED_PUMPKIN_STEM), StaticTintProvider(0xE0C71C)) manager.applyTo(setOf(MinecraftBlocks.MELON_STEM, MinecraftBlocks.PUMPKIN_STEM), StemTintCalculator) manager.applyTo(setOf(MinecraftBlocks.LILY_PAD), StaticTintProvider(block = 0x208030, item = 0x71C35C)) diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/tint/TintManager.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/tint/TintManager.kt index f77f8f24e..8d756cf39 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/tint/TintManager.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/tint/TintManager.kt @@ -28,12 +28,12 @@ import de.bixilon.minosoft.gui.rendering.tint.tints.plants.FoliageTintCalculator import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection class TintManager(val connection: PlayConnection) { - val grassTintCalculator = GrassTintCalculator() - val foliageTintCalculator = FoliageTintCalculator() + val grass = GrassTintCalculator() + val foliage = FoliageTintCalculator() fun init(assetsManager: AssetsManager) { - grassTintCalculator.init(assetsManager) - foliageTintCalculator.init(assetsManager) + grass.init(assetsManager) + foliage.init(assetsManager) for (block in connection.registries.block) { if (block !is TintedBlock) continue @@ -61,7 +61,8 @@ class TintManager(val connection: PlayConnection) { fun getParticleTint(state: BlockState, x: Int, y: Int, z: Int): Int? { if (state.block !is TintedBlock) return null val tintProvider = state.block.tintProvider ?: return null - val biome = connection.world.getBiome(x, y, z) + // TODO: cache chunk + val biome = connection.world.biomes.getBiome(x, y, z) return tintProvider.getParticleColor(state, biome, x, y, z) } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/tint/tints/grass/GrassTinted.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/tint/tints/grass/GrassTinted.kt index 480aeda42..4c00961a8 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/tint/tints/grass/GrassTinted.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/tint/tints/grass/GrassTinted.kt @@ -20,6 +20,6 @@ import de.bixilon.minosoft.gui.rendering.tint.TintedBlock interface GrassTinted : TintedBlock { override fun initTint(manager: TintManager) { - this::class.java.getDeclaredField("tintProvider").forceSet(this, manager.grassTintCalculator) + this::class.java.getDeclaredField("tintProvider").forceSet(this, manager.grass) } } diff --git a/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/InitializeS2CP.kt b/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/InitializeS2CP.kt index 9d946f23d..a1607e852 100644 --- a/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/InitializeS2CP.kt +++ b/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/InitializeS2CP.kt @@ -21,7 +21,7 @@ import de.bixilon.minosoft.data.entities.GlobalPosition import de.bixilon.minosoft.data.entities.data.types.GlobalPositionEntityDataType import de.bixilon.minosoft.data.registries.dimension.DimensionProperties import de.bixilon.minosoft.data.registries.identified.ResourceLocation -import de.bixilon.minosoft.data.world.biome.accessor.NoiseBiomeAccessor +import de.bixilon.minosoft.data.world.biome.accessor.noise.NoiseBiomeAccessor import de.bixilon.minosoft.data.world.difficulty.Difficulties import de.bixilon.minosoft.modding.event.events.DimensionChangeEvent import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection @@ -180,9 +180,7 @@ class InitializeS2CP(buffer: PlayInByteBuffer) : PlayS2CPacket { connection.world.entities.clear(connection, local = true) connection.world.entities.add(entityId, null, playerEntity) - if (connection.version.versionId >= ProtocolVersions.V_19W36A && !connection.profiles.rendering.performance.fastBiomeNoise) { - connection.world.cacheBiomeAccessor = NoiseBiomeAccessor(connection, hashedSeed) - } + connection.world.biomes.noise = NoiseBiomeAccessor.get(connection, hashedSeed) connection.world.border.reset() if (connection.version < V_1_20_2_PRE1) { diff --git a/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/RespawnS2CP.kt b/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/RespawnS2CP.kt index 2dff51217..c702f65aa 100644 --- a/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/RespawnS2CP.kt +++ b/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/RespawnS2CP.kt @@ -18,6 +18,7 @@ import de.bixilon.minosoft.data.entities.GlobalPosition import de.bixilon.minosoft.data.entities.data.types.GlobalPositionEntityDataType import de.bixilon.minosoft.data.registries.dimension.DimensionProperties import de.bixilon.minosoft.data.registries.identified.ResourceLocation +import de.bixilon.minosoft.data.world.biome.accessor.noise.NoiseBiomeAccessor import de.bixilon.minosoft.data.world.difficulty.Difficulties import de.bixilon.minosoft.modding.event.events.DimensionChangeEvent import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection @@ -114,7 +115,7 @@ class RespawnS2CP(buffer: PlayInByteBuffer) : PlayS2CPacket { } connection.world.dimension = dimension connection.world.name = world - connection.world.cacheBiomeAccessor?.hashedSeed = hashedSeed + connection.world.biomes.noise = NoiseBiomeAccessor.get(connection, hashedSeed) connection.state = PlayConnectionStates.SPAWNING if (dimensionChange) { diff --git a/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/block/chunk/ChunkBiomeS2CP.kt b/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/block/chunk/ChunkBiomeS2CP.kt index cb590143f..40f3fbc25 100644 --- a/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/block/chunk/ChunkBiomeS2CP.kt +++ b/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/block/chunk/ChunkBiomeS2CP.kt @@ -13,6 +13,7 @@ package de.bixilon.minosoft.protocol.packets.s2c.play.block.chunk import de.bixilon.kotlinglm.vec2.Vec2i +import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection import de.bixilon.minosoft.protocol.packets.s2c.PlayS2CPacket import de.bixilon.minosoft.protocol.protocol.buffers.play.PlayInByteBuffer import de.bixilon.minosoft.util.logging.Log @@ -23,7 +24,7 @@ class ChunkBiomeS2CP(buffer: PlayInByteBuffer) : PlayS2CPacket { val data = buffer.readArray { ChunkBiomeData(buffer.readLongChunkPosition(), buffer.readByteArray()) } - class ChunkBiomeData( + data class ChunkBiomeData( val position: Vec2i, val data: ByteArray, ) @@ -33,7 +34,15 @@ class ChunkBiomeS2CP(buffer: PlayInByteBuffer) : PlayS2CPacket { return Vec2i(long.toInt(), (long shr 32).toInt()) } - // TODO: handle + override fun handle(connection: PlayConnection) { + if (data.isEmpty()) return + + for ((position, data) in data) { + val chunk = connection.world.chunks[position] ?: continue + // TODO: handle + } + connection.world.biomes.resetCache() + } override fun log(reducedLog: Boolean) { Log.log(LogMessageType.NETWORK_IN, level = LogLevels.VERBOSE) { "Chunk biome (data=$data)" }