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.
This commit is contained in:
Moritz Zwerger 2025-02-06 21:37:15 +01:00
parent d2d83d85dc
commit c6892e4bd3
No known key found for this signature in database
GPG Key ID: 5CAD791931B09AC4
5 changed files with 68 additions and 23 deletions

View File

@ -1,6 +1,6 @@
/* /*
* Minosoft * 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. * 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 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.WaterTest0
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.data.world.chunk.ChunkSection
import de.bixilon.minosoft.test.ITUtil.allocate import de.bixilon.minosoft.test.ITUtil.allocate
@ -31,7 +32,7 @@ class BlockSectionDataProviderTest {
fun `initial empty`() { fun `initial empty`() {
val blocks = create() val blocks = create()
assertTrue(blocks.isEmpty) assertTrue(blocks.isEmpty)
assertEquals(blocks.fluidCount, 0) assertFalse(blocks.hasFluid)
assertEquals(blocks.count, 0) assertEquals(blocks.count, 0)
} }
@ -40,7 +41,7 @@ class BlockSectionDataProviderTest {
blocks[0] = StoneTest0.state blocks[0] = StoneTest0.state
blocks[0] = null blocks[0] = null
assertTrue(blocks.isEmpty) assertTrue(blocks.isEmpty)
assertEquals(blocks.fluidCount, 0) assertFalse(blocks.hasFluid)
assertEquals(blocks.count, 0) assertEquals(blocks.count, 0)
} }
@ -48,7 +49,15 @@ class BlockSectionDataProviderTest {
val blocks = create() val blocks = create()
blocks[0] = StoneTest0.state blocks[0] = StoneTest0.state
assertFalse(blocks.isEmpty) 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) assertEquals(blocks.count, 1)
} }
@ -91,5 +100,30 @@ class BlockSectionDataProviderTest {
assertEquals(blocks.maxPosition, Vec3i(3, 5, 12)) 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 // TODO: test initial block set
} }

View File

@ -1,6 +1,6 @@
/* /*
* Minosoft * 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. * 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 val data = this["properties"]?.toJsonObject() ?: return null
if (data.isEmpty()) return null if (data.isEmpty()) return null
val properties: MutableMap<BlockProperty<*>, Any> = HashMap() val properties: MutableMap<BlockProperty<*>, Any> = HashMap(data.size)
for ((group, json) in data) { for ((group, json) in data) {
try { try {

View File

@ -1,6 +1,6 @@
/* /*
* Minosoft * 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. * 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 { fun BlockState.isWaterlogged(): Boolean {
if (block is PixLyzerBlock && !block.waterloggable) return false if (block is PixLyzerBlock && !block.waterloggable) return false
if (this.block !is WaterloggableBlock) return false
if (this !is PropertyBlockState) 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 return properties[BlockProperties.WATERLOGGED]?.toBoolean() ?: return false
} }
} }

View File

@ -1,6 +1,6 @@
/* /*
* Minosoft * 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. * 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, val section: ChunkSection,
) : SectionDataProvider<BlockState?>(lock, true) { ) : SectionDataProvider<BlockState?>(lock, true) {
val occlusion = SectionOcclusion(this) val occlusion = SectionOcclusion(this)
var fluidCount = 0 var hasFluid = false
private set private set
init { init {
@ -37,22 +37,33 @@ class BlockSectionDataProvider(
recalculate(true) recalculate(true)
} }
fun recalculate(notify: Boolean) { private fun recalculateFluid() {
super.recalculate()
val data: Array<Any?> = data ?: return val data: Array<Any?> = data ?: return
if (isEmpty) { if (isEmpty) {
fluidCount = 0 this.hasFluid = false
occlusion.clear(notify)
return return
} }
fluidCount = 0 var hasFluid = false
for (blockState in data) { for (state in data) {
blockState as BlockState? if (state !is BlockState?) continue
if (blockState.isFluid()) { if (state.isFluid()) {
fluidCount++ hasFluid = true
break
} }
} }
this.hasFluid = hasFluid
}
fun recalculate(notify: Boolean) {
super.recalculate()
if (isEmpty) {
hasFluid = false
occlusion.clear(notify)
return
}
recalculateFluid()
occlusion.recalculate(notify) occlusion.recalculate(notify)
} }
@ -63,9 +74,9 @@ class BlockSectionDataProvider(
val valueFluid = value.isFluid() val valueFluid = value.isFluid()
if (!previousFluid && valueFluid) { if (!previousFluid && valueFluid) {
fluidCount++ hasFluid = true
} else if (previousFluid && !valueFluid) { } else if (previousFluid && !valueFluid) {
fluidCount-- recalculateFluid()
} }
return previous return previous

View File

@ -1,6 +1,6 @@
/* /*
* Minosoft * 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. * 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 { try {
solid.mesh(item.chunkPosition, item.sectionHeight, item.chunk, item.section, neighbours, sectionNeighbours, mesh) 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) fluid.mesh(item.chunkPosition, item.sectionHeight, item.chunk, item.section, neighbours, sectionNeighbours, mesh)
} }
} catch (exception: Exception) { } catch (exception: Exception) {