From c6892e4bd3ea70b3fb00b973e9a8703a42efc973 Mon Sep 17 00:00:00 2001 From: Moritz Zwerger Date: Thu, 6 Feb 2025 21:37:15 +0100 Subject: [PATCH] chunk section: only keep track if section has fluids and not how many, improvements A lot faster now and the count is not really needed, it will change rarely. --- .../block/BlockSectionDataProviderTest.kt | 42 +++++++++++++++++-- .../state/builder/BlockStateSettings.kt | 4 +- .../registries/fluid/fluids/WaterFluid.kt | 4 +- .../block/BlockSectionDataProvider.kt | 37 ++++++++++------ .../gui/rendering/chunk/mesher/ChunkMesher.kt | 4 +- 5 files changed, 68 insertions(+), 23 deletions(-) diff --git a/src/integration-test/kotlin/de/bixilon/minosoft/data/world/container/block/BlockSectionDataProviderTest.kt b/src/integration-test/kotlin/de/bixilon/minosoft/data/world/container/block/BlockSectionDataProviderTest.kt index 7cc3f29d2..4a03b6ac6 100644 --- a/src/integration-test/kotlin/de/bixilon/minosoft/data/world/container/block/BlockSectionDataProviderTest.kt +++ b/src/integration-test/kotlin/de/bixilon/minosoft/data/world/container/block/BlockSectionDataProviderTest.kt @@ -1,6 +1,6 @@ /* * Minosoft - * Copyright (C) 2020-2023 Moritz Zwerger + * Copyright (C) 2020-2025 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,6 +14,7 @@ package de.bixilon.minosoft.data.world.container.block import de.bixilon.kotlinglm.vec3.Vec3i +import de.bixilon.minosoft.data.registries.blocks.WaterTest0 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 @@ -31,7 +32,7 @@ class BlockSectionDataProviderTest { fun `initial empty`() { val blocks = create() assertTrue(blocks.isEmpty) - assertEquals(blocks.fluidCount, 0) + assertFalse(blocks.hasFluid) assertEquals(blocks.count, 0) } @@ -40,7 +41,7 @@ class BlockSectionDataProviderTest { blocks[0] = StoneTest0.state blocks[0] = null assertTrue(blocks.isEmpty) - assertEquals(blocks.fluidCount, 0) + assertFalse(blocks.hasFluid) assertEquals(blocks.count, 0) } @@ -48,7 +49,15 @@ class BlockSectionDataProviderTest { val blocks = create() blocks[0] = StoneTest0.state assertFalse(blocks.isEmpty) - assertEquals(blocks.fluidCount, 0) + assertFalse(blocks.hasFluid) + assertEquals(blocks.count, 1) + } + + fun `single water set`() { + val blocks = create() + blocks[0] = WaterTest0.state + assertFalse(blocks.isEmpty) + assertTrue(blocks.hasFluid) assertEquals(blocks.count, 1) } @@ -91,5 +100,30 @@ class BlockSectionDataProviderTest { assertEquals(blocks.maxPosition, Vec3i(3, 5, 12)) } + + /* + fun benchmark() { + val water = WaterTest0.state + val stone = StoneTest0.state + val random = Random(12) + + val data = create() + for (i in 0 until ProtocolDefinition.BLOCKS_PER_SECTION) { + if (random.nextBoolean()) { + data[i] = water + } else if (random.nextBoolean()) { + data[i] = stone + } + } + + val time = measureTime { + for (i in 0 until 1999_999) { + data.recalculate(false) + } + } + println("Took: ${time.inWholeNanoseconds.formatNanos()}") + } + */ + // TODO: test initial block set } diff --git a/src/main/java/de/bixilon/minosoft/data/registries/blocks/state/builder/BlockStateSettings.kt b/src/main/java/de/bixilon/minosoft/data/registries/blocks/state/builder/BlockStateSettings.kt index 3cc1a413f..729e33f0a 100644 --- a/src/main/java/de/bixilon/minosoft/data/registries/blocks/state/builder/BlockStateSettings.kt +++ b/src/main/java/de/bixilon/minosoft/data/registries/blocks/state/builder/BlockStateSettings.kt @@ -1,6 +1,6 @@ /* * Minosoft - * Copyright (C) 2020-2023 Moritz Zwerger + * Copyright (C) 2020-2025 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. * @@ -63,7 +63,7 @@ class BlockStateSettings( val data = this["properties"]?.toJsonObject() ?: return null if (data.isEmpty()) return null - val properties: MutableMap, Any> = HashMap() + val properties: MutableMap, Any> = HashMap(data.size) for ((group, json) in data) { try { diff --git a/src/main/java/de/bixilon/minosoft/data/registries/fluid/fluids/WaterFluid.kt b/src/main/java/de/bixilon/minosoft/data/registries/fluid/fluids/WaterFluid.kt index 3949eab27..4b5642017 100644 --- a/src/main/java/de/bixilon/minosoft/data/registries/fluid/fluids/WaterFluid.kt +++ b/src/main/java/de/bixilon/minosoft/data/registries/fluid/fluids/WaterFluid.kt @@ -1,6 +1,6 @@ /* * Minosoft - * Copyright (C) 2020-2024 Moritz Zwerger + * Copyright (C) 2020-2025 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. * @@ -152,8 +152,8 @@ class WaterFluid(resourceLocation: ResourceLocation = identifier) : Fluid(resour fun BlockState.isWaterlogged(): Boolean { if (block is PixLyzerBlock && !block.waterloggable) return false - if (this.block !is WaterloggableBlock) return false if (this !is PropertyBlockState) return false + if (this.block !is WaterloggableBlock) return false // check for interfaces is rather slow, so do it after class checking return properties[BlockProperties.WATERLOGGED]?.toBoolean() ?: return false } } diff --git a/src/main/java/de/bixilon/minosoft/data/world/container/block/BlockSectionDataProvider.kt b/src/main/java/de/bixilon/minosoft/data/world/container/block/BlockSectionDataProvider.kt index 27c324e41..958458465 100644 --- a/src/main/java/de/bixilon/minosoft/data/world/container/block/BlockSectionDataProvider.kt +++ b/src/main/java/de/bixilon/minosoft/data/world/container/block/BlockSectionDataProvider.kt @@ -1,6 +1,6 @@ /* * Minosoft - * Copyright (C) 2020-2023 Moritz Zwerger + * Copyright (C) 2020-2025 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. * @@ -26,7 +26,7 @@ class BlockSectionDataProvider( val section: ChunkSection, ) : SectionDataProvider(lock, true) { val occlusion = SectionOcclusion(this) - var fluidCount = 0 + var hasFluid = false private set init { @@ -37,22 +37,33 @@ class BlockSectionDataProvider( recalculate(true) } - fun recalculate(notify: Boolean) { - super.recalculate() + private fun recalculateFluid() { val data: Array = data ?: return if (isEmpty) { - fluidCount = 0 - occlusion.clear(notify) + this.hasFluid = false return } - fluidCount = 0 - for (blockState in data) { - blockState as BlockState? - if (blockState.isFluid()) { - fluidCount++ + var hasFluid = false + for (state in data) { + if (state !is BlockState?) continue + if (state.isFluid()) { + hasFluid = true + break } } + this.hasFluid = hasFluid + } + + fun recalculate(notify: Boolean) { + super.recalculate() + if (isEmpty) { + hasFluid = false + occlusion.clear(notify) + return + } + recalculateFluid() + occlusion.recalculate(notify) } @@ -63,9 +74,9 @@ class BlockSectionDataProvider( val valueFluid = value.isFluid() if (!previousFluid && valueFluid) { - fluidCount++ + hasFluid = true } else if (previousFluid && !valueFluid) { - fluidCount-- + recalculateFluid() } return previous diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/mesher/ChunkMesher.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/mesher/ChunkMesher.kt index 23ab42982..e2d718a9c 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/mesher/ChunkMesher.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/mesher/ChunkMesher.kt @@ -1,6 +1,6 @@ /* * Minosoft - * Copyright (C) 2020-2023 Moritz Zwerger + * Copyright (C) 2020-2025 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. * @@ -42,7 +42,7 @@ class ChunkMesher( try { solid.mesh(item.chunkPosition, item.sectionHeight, item.chunk, item.section, neighbours, sectionNeighbours, mesh) - if (item.section.blocks.fluidCount > 0) { + if (item.section.blocks.hasFluid) { fluid.mesh(item.chunkPosition, item.sectionHeight, item.chunk, item.section, neighbours, sectionNeighbours, mesh) } } catch (exception: Exception) {