aabb iterator: don't use IntRange, reduce more allocations

This commit is contained in:
Moritz Zwerger 2025-03-31 15:10:25 +02:00
parent d711e077b7
commit a21b1ea4c9
No known key found for this signature in database
GPG Key ID: 5CAD791931B09AC4
5 changed files with 72 additions and 31 deletions

View File

@ -17,44 +17,44 @@ import de.bixilon.minosoft.data.world.World
import de.bixilon.minosoft.data.world.chunk.chunk.Chunk
import de.bixilon.minosoft.data.world.iterator.WorldIterator
import de.bixilon.minosoft.data.world.positions.BlockPosition
import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3dUtil.ceil
import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3dUtil.floor
class AABBIterator(
private val rangeX: IntRange,
private val rangeY: IntRange,
private val rangeZ: IntRange,
val min: BlockPosition,
val max: BlockPosition,
) : Iterator<BlockPosition> {
private var count = 0
private var x = rangeX.first
private var y = rangeY.first
private var z = rangeZ.first
private var current = min
val size = maxOf(0, max.x - min.x + 1) * maxOf(0, max.y - min.y + 1) * maxOf(0, max.z - min.z + 1)
val size: Int = maxOf(0, rangeX.last - rangeX.first + 1) * maxOf(0, rangeY.last - rangeY.first + 1) * maxOf(0, rangeZ.last - rangeZ.first + 1)
constructor(aabb: AABB) : this(AABB.getRange(aabb.min.x, aabb.max.x), AABB.getRange(aabb.min.y, aabb.max.y), AABB.getRange(aabb.min.z, aabb.max.z))
constructor(min: BlockPosition, max: BlockPosition) : this(min.x..max.x, min.y..max.y, min.z..max.z)
constructor(minX: Int, minY: Int, minZ: Int, maxX: Int, maxY: Int, maxZ: Int) : this(minX..maxX, minY..maxY, minZ..maxZ)
constructor(aabb: AABB) : this(aabb.min.floor, aabb.max.ceil - 1)
constructor(minX: Int, minY: Int, minZ: Int, maxX: Int, maxY: Int, maxZ: Int) : this(BlockPosition(minX, minY, minZ), BlockPosition(maxX, maxY, maxZ))
override fun hasNext(): Boolean {
return count < size
}
override fun next(): BlockPosition {
if (count >= size) throw IllegalStateException("No positions available anymore!")
if (!hasNext()) throw IllegalStateException("No positions available anymore!")
val current = current
var next = current
val position = BlockPosition(x, y, z)
if (z < rangeZ.last) z++ else {
z = rangeZ.first
if (y < rangeY.last) y++ else {
y = rangeY.first
if (x < rangeX.last) x++
if (next.x < max.x) next = next.plusX() else {
next = next.with(x = min.x)
if (next.z < max.z) next = next.plusZ() else {
next = next.with(z = min.z)
if (next.y < max.y) next = next.plusY()
}
}
this.current = next
count++
return position
return current
}
fun blocks(world: World, chunk: Chunk? = null): WorldIterator {

View File

@ -159,14 +159,17 @@ object VecUtil {
return (((axisHash and 0xF) / 15.0f) - 0.5f) / 2.0f
}
return Vec3(
val offset = Vec3(
x = horizontal(positionHash),
y = if (offsetType === RandomOffsetTypes.XYZ) {
(((positionHash shr 4 and 0xF) / 15.0f) - 1.0f) / 5.0f
} else {
0.0f
},
z = horizontal(positionHash shr 8)).clamp(-maxModelOffset, maxModelOffset)
z = horizontal(positionHash shr 8))
offset.clampAssign(-maxModelOffset, maxModelOffset)
return offset
}
fun Vec3.clampAssign(min: Float, max: Float) {
@ -174,6 +177,7 @@ object VecUtil {
this.y = y.clamp(min, max)
this.z = z.clamp(min, max)
}
fun Vec3.clamp(min: Float, max: Float): Vec3 {
return Vec3(
x = x.clamp(min, max),

View File

@ -45,8 +45,11 @@ object Vec3dUtil {
val Vec3d.Companion.MAX: Vec3d
get() = Vec3d(Double.MAX_VALUE, Double.MAX_VALUE, Double.MAX_VALUE)
val Vec3d.floor: Vec3i
get() = Vec3i(this.x.floor, this.y.floor, this.z.floor)
val Vec3d.floor: BlockPosition
get() = BlockPosition(this.x.floor, this.y.floor, this.z.floor)
val Vec3d.ceil: BlockPosition
get() = BlockPosition(this.x.ceil, this.y.ceil, this.z.ceil)
val Vec3d.blockPosition: BlockPosition
get() = BlockPosition(this.x.floor, this.y.floor, this.z.floor)

View File

@ -41,6 +41,7 @@ import de.bixilon.minosoft.protocol.PlayerPublicKey
import de.bixilon.minosoft.protocol.network.session.play.PlaySession
import de.bixilon.minosoft.protocol.packets.s2c.play.sound.PlayedSound
import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition
import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition.VELOCITY_NETWORK_DIVIDER
import de.bixilon.minosoft.protocol.protocol.ProtocolVersions
import de.bixilon.minosoft.protocol.protocol.ProtocolVersions.V_14W04A
import de.bixilon.minosoft.protocol.protocol.ProtocolVersions.V_14W21A
@ -378,7 +379,7 @@ class PlayInByteBuffer : InByteBuffer {
}
fun readVelocity(): Vec3d {
return Vec3d(readShort(), readShort(), readShort()) * (1.0f / ProtocolDefinition.VELOCITY_NETWORK_DIVIDER)
return Vec3d(readShort() * (1.0 / VELOCITY_NETWORK_DIVIDER), readShort() * (1.0 / VELOCITY_NETWORK_DIVIDER), readShort() * (1.0 / VELOCITY_NETWORK_DIVIDER))
}
fun readVibrationSource(): VibrationSource {

View File

@ -27,7 +27,39 @@ class AABBIteratorTest {
}
@Test
fun singleBlock() {
fun `correct min and max`() {
val iterator = AABBIterator(1, 2, 3, 4, 5, 6)
assertEquals(iterator.min, BlockPosition(1, 2, 3))
assertEquals(iterator.max, BlockPosition(4, 5, 6))
}
@Test
fun `correct floor and ceil not`() {
val iterator = AABB(1.0, 2.0, 3.0, 4.0, 5.0, 6.0).positions()
assertEquals(iterator.min, BlockPosition(1, 2, 3))
assertEquals(iterator.max, BlockPosition(3, 4, 5))
}
@Test
fun `correct floor and ceil`() {
val iterator = AABB(1.2, 2.2, 3.3, 4.5, 5.7, 6.4).positions()
assertEquals(iterator.min, BlockPosition(1, 2, 3))
assertEquals(iterator.max, BlockPosition(4, 5, 6))
}
@Test
fun `less than single block`() {
val aabb = AABB(0.0, 0.0, 0.0, 0.1, 0.1, 0.1)
val positions = aabb.positions()
assertEquals(1, positions.size)
assertTrue(positions.hasNext())
assertEquals(BlockPosition(0, 0, 0), positions.next())
assertFalse(positions.hasNext())
}
@Test
fun `exactly one block`() {
val aabb = AABB(0.0, 0.0, 0.0, 1.0, 1.0, 1.0)
val positions = aabb.positions()
@ -43,14 +75,14 @@ class AABBIteratorTest {
val positions = aabb.positions()
assertEquals(24, positions.size)
val set: MutableSet<BlockPosition> = mutableSetOf()
val set: MutableSet<BlockPosition> = hashSetOf()
for (position in positions) {
set += position
}
assertEquals(24, set.size)
assertEquals(setOf(
assertEquals(hashSetOf(
BlockPosition(0, 0, 0),
BlockPosition(0, 0, 1),
BlockPosition(0, 0, 2),
@ -108,9 +140,10 @@ class AABBIteratorTest {
val positions = aabb.positions()
assertEquals(64, positions.size)
for (x in -2 until 2) {
for (y in -2 until 2) {
for (z in -2 until 2) {
for (y in -2 until 2) {
for (z in -2 until 2) {
for (x in -2 until 2) {
assertEquals(BlockPosition(x, y, z), positions.next())
}
}