diff --git a/src/main/java/de/bixilon/minosoft/data/world/container/block/SectionOcclusion.kt b/src/main/java/de/bixilon/minosoft/data/world/container/block/SectionOcclusion.kt index 3edbb8ae5..fd0787116 100644 --- a/src/main/java/de/bixilon/minosoft/data/world/container/block/SectionOcclusion.kt +++ b/src/main/java/de/bixilon/minosoft/data/world/container/block/SectionOcclusion.kt @@ -20,6 +20,7 @@ import de.bixilon.minosoft.data.registries.blocks.state.BlockState import de.bixilon.minosoft.data.registries.blocks.state.BlockStateFlags import de.bixilon.minosoft.data.registries.blocks.types.properties.shape.special.FullOpaqueBlock import de.bixilon.minosoft.data.registries.blocks.types.properties.shape.special.PotentialFullOpaqueBlock +import de.bixilon.minosoft.gui.rendering.util.allocator.ShortAllocator import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition import it.unimi.dsi.fastutil.ints.IntOpenHashSet import java.util.* @@ -29,7 +30,6 @@ class SectionOcclusion( ) { private var occlusion = EMPTY private var calculate = false - private val regions by lazy { ShortArray(ProtocolDefinition.BLOCKS_PER_SECTION) } fun clear(notify: Boolean) { update(EMPTY, notify) @@ -49,7 +49,13 @@ class SectionOcclusion( clear(notify) return } - update(calculateOcclusion(floodFill()), notify) + val array = ALLOCATOR.allocate(ProtocolDefinition.BLOCKS_PER_SECTION) + try { + val regions = floodFill(array) + update(calculateOcclusion(regions), notify) + } finally { + ALLOCATOR.free(array) + } } private inline fun ShortArray.updateRegion(x: Int, y: Int, z: Int, id: Short): Boolean { @@ -85,20 +91,20 @@ class SectionOcclusion( if (y < ProtocolDefinition.SECTION_MAX_Y) trace(regions, x, y + 1, z, nextId) } - private fun floodFill(): ShortArray { + private fun floodFill(array: ShortArray): ShortArray { // mark regions and check direct neighbours - Arrays.fill(regions, 0.toShort()) + Arrays.fill(array, 0.toShort()) var next: Short = 0 for (y in 0 until ProtocolDefinition.SECTION_HEIGHT_Y) { for (z in 0 until ProtocolDefinition.SECTION_WIDTH_Z) { for (x in 0 until ProtocolDefinition.SECTION_WIDTH_X) { - startTrace(regions, x, y, z, ++next) + startTrace(array, x, y, z, ++next) } } } - return regions + return array } private fun calculateOcclusion(regions: ShortArray): BooleanArray { @@ -198,6 +204,7 @@ class SectionOcclusion( companion object { private val EMPTY = BooleanArray(CubeDirections.CUBE_DIRECTION_COMBINATIONS) + private val ALLOCATOR = ShortAllocator() fun BlockState?._isFullyOpaque(): Boolean { diff --git a/src/main/java/de/bixilon/minosoft/data/world/container/palette/data/array/ArrayPaletteData.kt b/src/main/java/de/bixilon/minosoft/data/world/container/palette/data/array/ArrayPaletteData.kt index a5aec90a2..5daf4039b 100644 --- a/src/main/java/de/bixilon/minosoft/data/world/container/palette/data/array/ArrayPaletteData.kt +++ b/src/main/java/de/bixilon/minosoft/data/world/container/palette/data/array/ArrayPaletteData.kt @@ -14,6 +14,7 @@ package de.bixilon.minosoft.data.world.container.palette.data.array import de.bixilon.minosoft.data.world.container.palette.data.PaletteData +import de.bixilon.minosoft.gui.rendering.util.allocator.LongAllocator import de.bixilon.minosoft.protocol.protocol.ProtocolVersions.V_1_16 import de.bixilon.minosoft.protocol.protocol.buffers.play.PlayInByteBuffer @@ -39,7 +40,7 @@ class ArrayPaletteData( } else { (this.size + valuesPerLong - 1) / valuesPerLong } - this.data = LongArrayAllocator.claim(this.size) + this.data = ALLOCATOR.allocate(this.size) if (packetSize != size) { buffer.pointer += packetSize * Long.SIZE_BYTES // data is ignored return @@ -69,10 +70,12 @@ class ArrayPaletteData( } override fun free() { - LongArrayAllocator.free(data) + ALLOCATOR.free(data) } companion object { + private val ALLOCATOR = LongAllocator() const val LONG_BIT_SPLITTING_VERSION = V_1_16 // ToDo: When did this changed? is just a guess + } } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/util/allocator/LongAllocator.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/util/allocator/LongAllocator.kt new file mode 100644 index 000000000..94ed24064 --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/util/allocator/LongAllocator.kt @@ -0,0 +1,22 @@ +/* + * Minosoft + * 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 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.gui.rendering.util.allocator + +@Deprecated("kutil 1.27.1") +class LongAllocator : TemporaryAllocator() { + + override fun getSize(value: LongArray) = value.size + + override fun create(size: Int) = LongArray(size) +} diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/util/allocator/ShortAllocator.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/util/allocator/ShortAllocator.kt new file mode 100644 index 000000000..2d390b6da --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/util/allocator/ShortAllocator.kt @@ -0,0 +1,22 @@ +/* + * Minosoft + * 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 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.gui.rendering.util.allocator + +@Deprecated("kutil 1.27.1") +class ShortAllocator : TemporaryAllocator() { + + override fun getSize(value: ShortArray) = value.size + + override fun create(size: Int) = ShortArray(size) +} diff --git a/src/main/java/de/bixilon/minosoft/data/world/container/palette/data/array/LongArrayAllocator.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/util/allocator/TemporaryAllocator.kt similarity index 72% rename from src/main/java/de/bixilon/minosoft/data/world/container/palette/data/array/LongArrayAllocator.kt rename to src/main/java/de/bixilon/minosoft/gui/rendering/util/allocator/TemporaryAllocator.kt index 36a3fe496..2b5855c6e 100644 --- a/src/main/java/de/bixilon/minosoft/data/world/container/palette/data/array/LongArrayAllocator.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/util/allocator/TemporaryAllocator.kt @@ -11,15 +11,16 @@ * This software is not affiliated with Mojang AB, the original developer of Minecraft. */ -package de.bixilon.minosoft.data.world.container.palette.data.array +package de.bixilon.minosoft.gui.rendering.util.allocator import de.bixilon.kutil.concurrent.lock.locks.reentrant.ReentrantLock import java.lang.ref.WeakReference -object LongArrayAllocator { +@Deprecated("kutil 1.27.1") +abstract class TemporaryAllocator { private val lock = ReentrantLock() - private val list: ArrayList> = ArrayList() + private val list: ArrayList> = ArrayList() private fun cleanup() { lock.lock() @@ -33,36 +34,41 @@ object LongArrayAllocator { lock.unlock() } - fun free(array: LongArray) { + fun free(array: T) { lock.lock() cleanup() list.add(0, WeakReference(array)) lock.unlock() } - fun claim(size: Int): LongArray { + fun allocate(size: Int): T { lock.lock() - var array: LongArray? = null + var array: T? = null val iterator = list.iterator() while (iterator.hasNext()) { val reference = iterator.next() - array = reference.get() - if (array == null) { + val entry = reference.get() + if (entry == null) { iterator.remove() continue } - if (array.size >= size) { + if (getSize(entry) >= size) { + array = entry iterator.remove() break } } lock.unlock() - if (array != null && array.size >= size) return array + if (array != null) return array - // println("Allocating long array of size $size") + // println("Allocating array of size $size") - return LongArray(size) + return create(size) } + + protected abstract fun getSize(value: T): Int + + abstract fun create(size: Int): T }