diff --git a/src/integration-test/kotlin/de/bixilon/minosoft/gui/rendering/chunk/mesher/SolidSectionMesherTest.kt b/src/integration-test/kotlin/de/bixilon/minosoft/gui/rendering/chunk/mesher/SolidSectionMesherTest.kt
index f42af94bf..7e6abdeb6 100644
--- a/src/integration-test/kotlin/de/bixilon/minosoft/gui/rendering/chunk/mesher/SolidSectionMesherTest.kt
+++ b/src/integration-test/kotlin/de/bixilon/minosoft/gui/rendering/chunk/mesher/SolidSectionMesherTest.kt
@@ -27,6 +27,7 @@ import de.bixilon.minosoft.data.registries.dimension.DimensionProperties
import de.bixilon.minosoft.data.registries.identified.Namespaces.minosoft
import de.bixilon.minosoft.data.world.positions.BlockPosition
import de.bixilon.minosoft.data.world.positions.InSectionPosition
+import de.bixilon.minosoft.data.world.positions.SectionPosition
import de.bixilon.minosoft.gui.rendering.RenderContext
import de.bixilon.minosoft.gui.rendering.camera.Camera
import de.bixilon.minosoft.gui.rendering.chunk.entities.BlockEntityRenderer
@@ -80,9 +81,9 @@ class SolidSectionMesherTest {
val mesher = SolidSectionMesher(context)
val chunk = world.chunks[0, 0]!!
- val meshes = ChunkMeshes(context, chunk.position, 0, true)
+ val meshes = ChunkMeshes(context, SectionPosition.of(chunk.position, 0), true)
- mesher.mesh(chunk.position, 0, chunk, chunk.sections[0]!!, chunk.neighbours.neighbours, chunk.sections[0]!!.neighbours!!, meshes)
+ mesher.mesh(SectionPosition.of(chunk.position, 0), chunk, chunk.sections[0]!!, chunk.neighbours.neighbours, chunk.sections[0]!!.neighbours!!, meshes)
return meshes
}
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 0f1f68e25..97686e82c 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
@@ -23,6 +23,7 @@ import de.bixilon.minosoft.data.world.container.block.BlockSectionDataProvider
import de.bixilon.minosoft.data.world.positions.BlockPosition
import de.bixilon.minosoft.data.world.positions.ChunkPosition
import de.bixilon.minosoft.data.world.positions.InSectionPosition
+import de.bixilon.minosoft.data.world.positions.SectionHeight
import de.bixilon.minosoft.protocol.network.session.play.PlaySession
import java.util.*
@@ -30,7 +31,7 @@ import java.util.*
* Collection of 16x16x16 blocks
*/
class ChunkSection(
- val height: Int,
+ val height: SectionHeight,
val chunk: Chunk,
) {
val blocks = BlockSectionDataProvider(chunk.lock, this)
diff --git a/src/main/java/de/bixilon/minosoft/data/world/positions/BlockPosition.kt b/src/main/java/de/bixilon/minosoft/data/world/positions/BlockPosition.kt
index c92910f1d..f9e244497 100644
--- a/src/main/java/de/bixilon/minosoft/data/world/positions/BlockPosition.kt
+++ b/src/main/java/de/bixilon/minosoft/data/world/positions/BlockPosition.kt
@@ -111,6 +111,7 @@ value class BlockPosition(
inline val hash get() = generatePositionHash(x, y, z)
inline val sectionHeight get() = y.sectionHeight
inline val chunkPosition get() = ChunkPosition(x shr 4, z shr 4)
+ inline val sectionPosition get() = SectionPosition(x shr 4, y shr 4, z shr 4)
inline val inChunkPosition get() = InChunkPosition(x and 0x0F, y, this.z and 0x0F)
inline val inSectionPosition get() = InSectionPosition(x and 0x0F, y.inSectionHeight, z and 0x0F)
@@ -169,5 +170,13 @@ value class BlockPosition(
chunk.z * ProtocolDefinition.SECTION_WIDTH_Z + inSection.z
) // ToDo: Confirm
}
+
+ fun of(section: SectionPosition, inSection: InSectionPosition): BlockPosition {
+ return BlockPosition(
+ section.x * ProtocolDefinition.SECTION_WIDTH_X + inSection.x,
+ section.y * ProtocolDefinition.SECTION_HEIGHT_Y + inSection.y,
+ section.z * ProtocolDefinition.SECTION_WIDTH_Z + inSection.z
+ ) // ToDo: Confirm
+ }
}
}
diff --git a/src/main/java/de/bixilon/minosoft/data/world/positions/ChunkPosition.kt b/src/main/java/de/bixilon/minosoft/data/world/positions/ChunkPosition.kt
index 5a558d441..97c4c47a5 100644
--- a/src/main/java/de/bixilon/minosoft/data/world/positions/ChunkPosition.kt
+++ b/src/main/java/de/bixilon/minosoft/data/world/positions/ChunkPosition.kt
@@ -88,6 +88,8 @@ value class ChunkPosition(
inline operator fun component1() = x
inline operator fun component2() = z
+ fun sectionPosition(y: SectionHeight) = SectionPosition(x, y, z)
+
override fun toText() = "(${this.x.format()} ${this.z.format()})"
override fun toString() = "c($x $z)"
@@ -105,8 +107,8 @@ value class ChunkPosition(
const val Z = 1L shl SHIFT_Z
- const val MAX_X = (BlockPosition.MAX_X shr 4) + 1
- const val MAX_Z = (BlockPosition.MAX_Z shr 4) + 1
+ const val MAX_X = BlockPosition.MAX_X shr 4
+ const val MAX_Z = BlockPosition.MAX_Z shr 4
val EMPTY = ChunkPosition(0, 0)
diff --git a/src/main/java/de/bixilon/minosoft/data/world/positions/SectionPosition.kt b/src/main/java/de/bixilon/minosoft/data/world/positions/SectionPosition.kt
new file mode 100644
index 000000000..952e37c35
--- /dev/null
+++ b/src/main/java/de/bixilon/minosoft/data/world/positions/SectionPosition.kt
@@ -0,0 +1,146 @@
+/*
+ * 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.data.world.positions
+
+import de.bixilon.minosoft.data.direction.Directions
+import de.bixilon.minosoft.data.text.formatting.TextFormattable
+import de.bixilon.minosoft.data.world.positions.BlockPositionUtil.assertPosition
+import de.bixilon.minosoft.util.KUtil.format
+
+@JvmInline
+value class SectionPosition(
+ inline val raw: Long,
+) : TextFormattable {
+
+ constructor() : this(0, 0, 0)
+
+ constructor(x: Int, y: SectionHeight, z: Int) : this(((y and MASK_Y).toLong() shl SHIFT_Y) or ((z and MASK_Z).toLong() shl SHIFT_Z) or ((x and MASK_X).toLong() shl SHIFT_X)) {
+ assertPosition(x, -MAX_X, MAX_X)
+ assertPosition(y, MIN_Y, MAX_Y)
+ assertPosition(z, -MAX_Z, MAX_Z)
+ }
+
+ inline val x: Int get() = (((raw ushr SHIFT_X).toInt() and MASK_X) shl (Int.SIZE_BITS - BITS_X)) shr (Int.SIZE_BITS - BITS_X)
+ inline val y: SectionHeight get() = (((raw ushr SHIFT_Y).toInt() and MASK_Y) shl (Int.SIZE_BITS - BITS_Y)) shr (Int.SIZE_BITS - BITS_Y)
+ inline val z: Int get() = (((raw ushr SHIFT_Z).toInt() and MASK_Z) shl (Int.SIZE_BITS - BITS_Z)) shr (Int.SIZE_BITS - BITS_Z)
+
+ inline fun plusX(): SectionPosition {
+ assertPosition(this.x < MAX_X)
+ return SectionPosition(raw + X * 1)
+ }
+
+ inline fun plusX(x: Int): SectionPosition {
+ assertPosition(this.x + x, -MAX_X, MAX_X)
+ return SectionPosition(raw + X * x)
+ }
+
+ inline fun minusX(): SectionPosition {
+ assert(this.x > -MAX_X)
+ return SectionPosition(raw - X * 1)
+ }
+
+ inline fun plusY(): SectionPosition {
+ assertPosition(this.y < MAX_Y)
+ return SectionPosition(raw + Y * 1)
+ }
+
+ inline fun plusY(y: Int): SectionPosition {
+ assertPosition(this.y + y, MIN_Y, MAX_Y)
+ return SectionPosition(raw + Y * y)
+ }
+
+ inline fun minusY(): SectionPosition {
+ assert(this.y > MIN_Y)
+ return SectionPosition(raw - Y * 1)
+ }
+
+ inline fun plusZ(): SectionPosition {
+ assert(this.z < MAX_Z)
+ return SectionPosition(raw + Z * 1)
+ }
+
+ inline fun plusZ(z: Int): SectionPosition {
+ assertPosition(this.z + z, -MAX_Z, MAX_Z)
+ return SectionPosition(raw + Z * z)
+ }
+
+ inline fun minusZ(): SectionPosition {
+ assert(this.z > -MAX_Z)
+ return SectionPosition(raw - Z * 1)
+ }
+
+ inline fun with(x: Int = this.x, y: Int = this.y, z: Int = this.z) = SectionPosition(x, y, z)
+
+ inline operator fun plus(value: Int) = SectionPosition(this.x + value, this.y + value, this.z + value)
+ inline operator fun minus(value: Int) = SectionPosition(this.x - value, this.y - value, this.z - value)
+ inline operator fun times(value: Int) = SectionPosition(this.x * value, this.y * value, this.z * value)
+ inline operator fun div(value: Int) = SectionPosition(this.x / value, this.y * value, this.z / value)
+
+ inline operator fun plus(position: SectionPosition) = SectionPosition(this.x + position.x, this.y + position.y, this.z + position.z)
+ inline operator fun minus(position: SectionPosition) = SectionPosition(this.x - position.x, this.y - position.y, this.z - position.z)
+
+ inline operator fun plus(position: ChunkPosition) = SectionPosition(this.x + position.x, this.y, this.z + position.z)
+ inline operator fun minus(position: ChunkPosition) = SectionPosition(this.x - position.x, this.y, this.z - position.z)
+
+ inline operator fun plus(direction: Directions) = SectionPosition(this.x + direction.vector.x, this.y + direction.vector.y, this.z + direction.vector.z)
+ inline operator fun minus(direction: Directions) = SectionPosition(this.x - direction.vector.x, this.y - direction.vector.y, this.z - direction.vector.z)
+
+ inline operator fun unaryMinus() = SectionPosition(-this.x, -this.y, -this.z)
+ inline operator fun unaryPlus() = this
+
+
+ inline operator fun component1() = x
+ inline operator fun component2() = y
+ inline operator fun component3() = z
+
+ inline fun length2() = (x * x + y * y + z * z)
+
+ inline fun sectionIndex(minSection: SectionHeight): SectionIndex = this.y - minSection
+ inline val chunkPosition get() = ChunkPosition(x, z)
+
+ override fun toText() = "(${this.x.format()} ${this.y.format()} ${this.z.format()})"
+ override fun toString() = "c($x $y $z)"
+
+
+ companion object {
+ const val BITS_X = 22
+ const val MASK_X = (1 shl BITS_X) - 1
+ const val SHIFT_X = 0
+
+ const val BITS_Z = 22
+ const val MASK_Z = (1 shl BITS_Z) - 1
+ const val SHIFT_Z = BITS_X
+
+ const val BITS_Y = 8
+ const val MASK_Y = (1 shl BITS_Y) - 1
+ const val SHIFT_Y = BITS_X + BITS_Z
+
+ const val X = 1L shl SHIFT_X
+ const val Z = 1L shl SHIFT_Z
+ const val Y = 1L shl SHIFT_Y
+
+
+ const val MAX_X = BlockPosition.MAX_X shr 4
+ const val MIN_Y = BlockPosition.MIN_Y shr 4
+ const val MAX_Y = BlockPosition.MAX_Y shr 4
+ const val MAX_Z = BlockPosition.MAX_Z shr 4
+
+
+ fun of(chunkPosition: ChunkPosition, sectionHeight: Int) = SectionPosition(chunkPosition.x, sectionHeight, chunkPosition.z)
+ fun of(chunkPosition: ChunkPosition, sectionIndex: SectionIndex, minSection: SectionHeight) = SectionPosition(chunkPosition.x, sectionIndex + minSection, chunkPosition.z)
+
+
+ val EMPTY = SectionPosition(0, 0, 0)
+ }
+}
diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/camera/MatrixHandler.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/camera/MatrixHandler.kt
index e259b08af..29b0bef0b 100644
--- a/src/main/java/de/bixilon/minosoft/gui/rendering/camera/MatrixHandler.kt
+++ b/src/main/java/de/bixilon/minosoft/gui/rendering/camera/MatrixHandler.kt
@@ -138,7 +138,7 @@ class MatrixHandler(
if (view.updateFrustum) {
frustum.recalculate()
- camera.visibilityGraph.updateCamera(cameraBlockPosition.chunkPosition, cameraBlockPosition.sectionHeight)
+ camera.visibilityGraph.updateCamera(cameraBlockPosition.sectionPosition)
}
session.events.fire(CameraPositionChangeEvent(context, useEyePosition))
diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/ChunkRenderer.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/ChunkRenderer.kt
index ba5562d9b..11f9a4f95 100644
--- a/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/ChunkRenderer.kt
+++ b/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/ChunkRenderer.kt
@@ -23,6 +23,7 @@ import de.bixilon.minosoft.config.key.KeyCodes
import de.bixilon.minosoft.data.registries.identified.Namespaces.minosoft
import de.bixilon.minosoft.data.world.World
import de.bixilon.minosoft.data.world.positions.ChunkPosition
+import de.bixilon.minosoft.data.world.positions.SectionPosition
import de.bixilon.minosoft.gui.rendering.RenderContext
import de.bixilon.minosoft.gui.rendering.RenderingStates
import de.bixilon.minosoft.gui.rendering.chunk.mesh.VisibleMeshes
@@ -86,8 +87,7 @@ class ChunkRenderer(
private var previousViewDistance = session.world.view.viewDistance
private var cameraPosition = Vec3.EMPTY
- var cameraChunkPosition = ChunkPosition.EMPTY
- var cameraSectionHeight = 0
+ var cameraSectionPosition = SectionPosition.EMPTY
var limitChunkTransferTime = true
@@ -198,15 +198,15 @@ class ChunkRenderer(
}
- fun unload(item: WorldQueueItem) = unload(QueuePosition(item.chunkPosition, item.sectionHeight))
+ fun unload(item: WorldQueueItem) = unload(QueuePosition(item.position))
fun unload(position: QueuePosition) {
lock.lock()
- loaded.unload(position.position, position.sectionHeight, false)
- culledQueue.remove(position.position, position.sectionHeight, false)
+ loaded.unload(position.position, false)
+ culledQueue.remove(position.position.chunkPosition, false)
meshingQueue.remove(position, false)
loadingQueue.abort(position, false)
- meshingQueue.tasks.interrupt(position.position, position.sectionHeight)
+ meshingQueue.tasks.interrupt(position.position.chunkPosition)
lock.unlock()
}
@@ -252,15 +252,10 @@ class ChunkRenderer(
private fun onFrustumChange() {
var sortQueue = false
val cameraPosition = Vec3(session.player.renderInfo.eyePosition - context.camera.offset.offset)
- val cameraChunkPosition = cameraPosition.blockPosition.chunkPosition
- val cameraSectionHeight = this.cameraSectionHeight
+ val sectionPosition = cameraPosition.blockPosition.sectionPosition
if (this.cameraPosition != cameraPosition) {
- if (this.cameraChunkPosition != cameraChunkPosition) {
- this.cameraChunkPosition = cameraChunkPosition
- sortQueue = true
- }
- if (this.cameraSectionHeight != cameraSectionHeight) {
- this.cameraSectionHeight = cameraSectionHeight
+ if (this.cameraSectionPosition != sectionPosition) {
+ this.cameraSectionPosition = sectionPosition
sortQueue = true
}
this.cameraPosition = cameraPosition
diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/LoadedMeshes.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/LoadedMeshes.kt
index 88c2d996b..eef4622a4 100644
--- a/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/LoadedMeshes.kt
+++ b/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/LoadedMeshes.kt
@@ -15,6 +15,7 @@ package de.bixilon.minosoft.gui.rendering.chunk
import de.bixilon.kutil.concurrent.lock.RWLock
import de.bixilon.minosoft.data.world.positions.ChunkPosition
+import de.bixilon.minosoft.data.world.positions.SectionPosition
import de.bixilon.minosoft.gui.rendering.chunk.mesh.ChunkMeshes
import de.bixilon.minosoft.gui.rendering.chunk.mesh.VisibleMeshes
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap
@@ -67,17 +68,17 @@ class LoadedMeshes(
if (lock) unlock()
}
- fun unload(position: ChunkPosition, sectionHeight: Int, lock: Boolean) {
+ fun unload(position: SectionPosition, lock: Boolean) {
if (lock) lock()
- val meshes = this.meshes[position]
+ val meshes = this.meshes[position.chunkPosition]
if (meshes != null) {
- meshes.remove(sectionHeight)?.let {
+ meshes.remove(position.y)?.let {
renderer.unloadingQueue.forceQueue(it, lock)
if (meshes.isEmpty()) {
- this.meshes.remove(position)
+ this.meshes.remove(position.chunkPosition)
}
}
}
@@ -106,7 +107,7 @@ class LoadedMeshes(
for (entry in meshes.int2ObjectEntrySet()) {
val mesh = entry.value
- if (!renderer.visibilityGraph.isSectionVisible(chunkPosition, entry.intKey, mesh.minPosition, mesh.maxPosition, false)) {
+ if (!renderer.visibilityGraph.isSectionVisible(SectionPosition.of(chunkPosition, entry.intKey), mesh.minPosition, mesh.maxPosition, false)) {
continue
}
visible.addMesh(mesh)
diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/WorldQueueItem.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/WorldQueueItem.kt
index fa59cb89b..82352dbc8 100644
--- a/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/WorldQueueItem.kt
+++ b/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/WorldQueueItem.kt
@@ -14,22 +14,18 @@
package de.bixilon.minosoft.gui.rendering.chunk
import de.bixilon.kotlinglm.vec3.Vec3
-import de.bixilon.kotlinglm.vec3.Vec3i
import de.bixilon.minosoft.data.world.chunk.ChunkSection
import de.bixilon.minosoft.data.world.chunk.chunk.Chunk
-import de.bixilon.minosoft.data.world.positions.ChunkPosition
+import de.bixilon.minosoft.data.world.positions.SectionPosition
import de.bixilon.minosoft.gui.rendering.chunk.mesh.ChunkMeshes
import de.bixilon.minosoft.gui.rendering.chunk.queue.QueuePosition
-import java.util.*
class WorldQueueItem(
- val chunkPosition: ChunkPosition,
- val sectionHeight: Int,
+ val position: SectionPosition,
val chunk: Chunk,
val section: ChunkSection,
val center: Vec3,
) {
- val sectionPosition = Vec3i(chunkPosition.x, sectionHeight, chunkPosition.z)
var mesh: ChunkMeshes? = null
var distance = 0
@@ -37,15 +33,15 @@ class WorldQueueItem(
override fun equals(other: Any?): Boolean {
if (other is WorldQueueItem) {
- return chunkPosition == other.chunkPosition && sectionHeight == other.sectionHeight
+ return position == other.position
}
if (other is QueuePosition) {
- return chunkPosition == other.position && sectionHeight == other.sectionHeight
+ return position == other.position
}
return false
}
override fun hashCode(): Int {
- return Objects.hash(chunkPosition, sectionHeight)
+ return position.hashCode()
}
}
diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/mesh/ChunkMeshes.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/mesh/ChunkMeshes.kt
index e9e8ce79c..3002750ac 100644
--- a/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/mesh/ChunkMeshes.kt
+++ b/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/mesh/ChunkMeshes.kt
@@ -17,8 +17,8 @@ import de.bixilon.kotlinglm.vec2.Vec2
import de.bixilon.kotlinglm.vec3.Vec3
import de.bixilon.kutil.exception.Broken
import de.bixilon.minosoft.data.world.positions.BlockPosition
-import de.bixilon.minosoft.data.world.positions.ChunkPosition
import de.bixilon.minosoft.data.world.positions.InSectionPosition
+import de.bixilon.minosoft.data.world.positions.SectionPosition
import de.bixilon.minosoft.gui.rendering.RenderContext
import de.bixilon.minosoft.gui.rendering.chunk.entities.BlockEntityRenderer
import de.bixilon.minosoft.gui.rendering.system.base.texture.TextureTransparencies
@@ -29,11 +29,10 @@ import de.bixilon.minosoft.util.collections.floats.DirectArrayFloatList
class ChunkMeshes(
context: RenderContext,
- val chunkPosition: ChunkPosition,
- val sectionHeight: Int,
+ val position: SectionPosition,
smallMesh: Boolean = false,
) : BlockVertexConsumer {
- val center: Vec3 = Vec3(BlockPosition.of(chunkPosition, sectionHeight, InSectionPosition(8, 8, 8)))
+ val center: Vec3 = Vec3(BlockPosition.of(position, InSectionPosition(8, 8, 8)))
var opaqueMesh: ChunkMesh? = ChunkMesh(context, if (smallMesh) 8192 else 65536)
var translucentMesh: ChunkMesh? = ChunkMesh(context, if (smallMesh) 4096 else 16384)
var textMesh: ChunkMesh? = ChunkMesh(context, if (smallMesh) 1024 else 4096)
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 30ee1886a..4c50d2c39 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
@@ -38,12 +38,12 @@ class ChunkMesher(
return null
}
val sectionNeighbours = ChunkUtil.getDirectNeighbours(neighbours.neighbours, item.chunk, item.section.height)
- val mesh = ChunkMeshes(renderer.context, item.chunkPosition, item.sectionHeight, item.section.smallMesh)
+ val mesh = ChunkMeshes(renderer.context, item.position, item.section.smallMesh)
try {
- solid.mesh(item.chunkPosition, item.sectionHeight, item.chunk, item.section, neighbours.neighbours, sectionNeighbours, mesh)
+ solid.mesh(item.position, item.chunk, item.section, neighbours.neighbours, sectionNeighbours, mesh)
if (item.section.blocks.hasFluid) {
- fluid.mesh(item.chunkPosition, item.sectionHeight, item.chunk, item.section, mesh)
+ fluid.mesh(item.position, item.chunk, item.section, mesh)
}
} catch (exception: Exception) {
mesh.unload()
diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/mesher/FluidSectionMesher.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/mesher/FluidSectionMesher.kt
index cfb66729e..7bc8bde54 100644
--- a/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/mesher/FluidSectionMesher.kt
+++ b/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/mesher/FluidSectionMesher.kt
@@ -30,9 +30,9 @@ import de.bixilon.minosoft.data.text.formatting.color.Colors
import de.bixilon.minosoft.data.world.chunk.ChunkSection
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.data.world.positions.InSectionPosition
+import de.bixilon.minosoft.data.world.positions.SectionPosition
import de.bixilon.minosoft.gui.rendering.RenderContext
import de.bixilon.minosoft.gui.rendering.chunk.mesh.ChunkMesh
import de.bixilon.minosoft.gui.rendering.chunk.mesh.ChunkMeshes
@@ -62,7 +62,7 @@ class FluidSectionMesher(
// ToDo: Should this be combined with the solid renderer (but we'd need to render faces twice, because of cullface)
- fun mesh(chunkPosition: ChunkPosition, sectionHeight: Int, chunk: Chunk, section: ChunkSection, mesh: ChunkMeshes) {
+ fun mesh(sectionPosition: SectionPosition, chunk: Chunk, section: ChunkSection, mesh: ChunkMeshes) {
val blocks = section.blocks
var position = BlockPosition()
@@ -70,9 +70,9 @@ class FluidSectionMesher(
val cameraOffset = context.camera.offset.offset
- val offsetX = chunkPosition.x * ProtocolDefinition.SECTION_WIDTH_X
- val offsetY = sectionHeight * ProtocolDefinition.SECTION_HEIGHT_Y
- val offsetZ = chunkPosition.z * ProtocolDefinition.SECTION_WIDTH_Z
+ val offsetX = sectionPosition.x * ProtocolDefinition.SECTION_WIDTH_X
+ val offsetY = sectionPosition.y * ProtocolDefinition.SECTION_HEIGHT_Y
+ val offsetZ = sectionPosition.z * ProtocolDefinition.SECTION_WIDTH_Z
for (y in blocks.minPosition.y..blocks.maxPosition.y) {
for (z in blocks.minPosition.z..blocks.maxPosition.z) {
diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/mesher/SolidSectionMesher.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/mesher/SolidSectionMesher.kt
index 7cf00306f..a434d5623 100644
--- a/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/mesher/SolidSectionMesher.kt
+++ b/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/mesher/SolidSectionMesher.kt
@@ -32,9 +32,9 @@ import de.bixilon.minosoft.data.world.chunk.chunk.Chunk
import de.bixilon.minosoft.data.world.chunk.light.SectionLight
import de.bixilon.minosoft.data.world.chunk.neighbours.ChunkNeighbourArray
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.data.world.positions.InSectionPosition
+import de.bixilon.minosoft.data.world.positions.SectionPosition
import de.bixilon.minosoft.gui.rendering.RenderContext
import de.bixilon.minosoft.gui.rendering.chunk.entities.BlockEntityRenderer
import de.bixilon.minosoft.gui.rendering.chunk.entities.renderer.RenderedBlockEntity
@@ -59,12 +59,12 @@ class SolidSectionMesher(
profile.light::ambientOcclusion.observe(this, true) { this.ambientOcclusion = it }
}
- fun mesh(chunkPosition: ChunkPosition, sectionHeight: Int, chunk: Chunk, section: ChunkSection, neighbourChunks: ChunkNeighbourArray, neighbours: Array, mesh: ChunkMeshes) {
+ fun mesh(sectionPosition: SectionPosition, chunk: Chunk, section: ChunkSection, neighbourChunks: ChunkNeighbourArray, neighbours: Array, mesh: ChunkMeshes) {
val random = if (profile.antiMoirePattern) Random(0L) else null
- val isLowestSection = sectionHeight == chunk.minSection
- val isHighestSection = sectionHeight == chunk.maxSection
+ val isLowestSection = sectionPosition.y == chunk.minSection
+ val isHighestSection = sectionPosition.y == chunk.maxSection
val blocks = section.blocks
val entities: ArrayList> = ArrayList(section.blockEntities.count)
@@ -76,9 +76,9 @@ class SolidSectionMesher(
val cameraOffset = context.camera.offset.offset
- val offsetX = chunkPosition.x * ProtocolDefinition.SECTION_WIDTH_X
- val offsetY = sectionHeight * ProtocolDefinition.SECTION_HEIGHT_Y
- val offsetZ = chunkPosition.z * ProtocolDefinition.SECTION_WIDTH_Z
+ val offsetX = sectionPosition.x * ProtocolDefinition.SECTION_WIDTH_X
+ val offsetY = sectionPosition.y * ProtocolDefinition.SECTION_HEIGHT_Y
+ val offsetZ = sectionPosition.z * ProtocolDefinition.SECTION_WIDTH_Z
val floatOffset = FloatArray(3)
diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/queue/CulledQueue.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/queue/CulledQueue.kt
index ddbb342c8..819b17a6a 100644
--- a/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/queue/CulledQueue.kt
+++ b/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/queue/CulledQueue.kt
@@ -17,6 +17,7 @@ import de.bixilon.kutil.concurrent.lock.RWLock
import de.bixilon.minosoft.data.world.chunk.chunk.Chunk
import de.bixilon.minosoft.data.world.positions.ChunkPosition
import de.bixilon.minosoft.data.world.positions.SectionHeight
+import de.bixilon.minosoft.data.world.positions.SectionPosition
import de.bixilon.minosoft.gui.rendering.chunk.ChunkRenderer
import it.unimi.dsi.fastutil.ints.IntOpenHashSet
@@ -99,7 +100,7 @@ class CulledQueue(
val heightIterator = sectionHeights.intIterator()
for (sectionHeight in heightIterator) {
val section = chunk[sectionHeight] ?: continue
- if (!renderer.visibilityGraph.isSectionVisible(chunkPosition, sectionHeight, section.blocks.minPosition, section.blocks.maxPosition, false)) {
+ if (!renderer.visibilityGraph.isSectionVisible(SectionPosition.Companion.of(chunkPosition, sectionHeight), section.blocks.minPosition, section.blocks.maxPosition, false)) {
continue
}
list += Pair(chunk, sectionHeight)
diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/queue/QueuePosition.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/queue/QueuePosition.kt
index 72009c201..8bc366cb9 100644
--- a/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/queue/QueuePosition.kt
+++ b/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/queue/QueuePosition.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.
*
@@ -13,30 +13,28 @@
package de.bixilon.minosoft.gui.rendering.chunk.queue
-import de.bixilon.minosoft.data.world.positions.ChunkPosition
+import de.bixilon.minosoft.data.world.positions.SectionPosition
import de.bixilon.minosoft.gui.rendering.chunk.WorldQueueItem
import de.bixilon.minosoft.gui.rendering.chunk.mesh.ChunkMeshes
-import java.util.*
class QueuePosition(
- val position: ChunkPosition,
- val sectionHeight: Int,
+ val position: SectionPosition,
) {
- constructor(mesh: ChunkMeshes) : this(mesh.chunkPosition, mesh.sectionHeight)
+ constructor(mesh: ChunkMeshes) : this(mesh.position)
override fun equals(other: Any?): Boolean {
if (other is WorldQueueItem) {
- return position == other.chunkPosition && sectionHeight == other.sectionHeight
+ return position == other.position
}
if (other is QueuePosition) {
- return position == other.position && sectionHeight == other.sectionHeight
+ return position == other.position
}
return false
}
override fun hashCode(): Int {
- return Objects.hash(position, sectionHeight)
+ return position.hashCode()
}
}
diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/queue/loading/MeshLoadingQueue.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/queue/loading/MeshLoadingQueue.kt
index b3b29023a..502c5536a 100644
--- a/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/queue/loading/MeshLoadingQueue.kt
+++ b/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/queue/loading/MeshLoadingQueue.kt
@@ -58,18 +58,18 @@ class MeshLoadingQueue(
mesh.load()
- if (position != mesh.chunkPosition) {
- meshes = renderer.loaded.meshes.getOrPut(mesh.chunkPosition) { Int2ObjectOpenHashMap() }
- position = mesh.chunkPosition
+ if (position != mesh.position.chunkPosition) {
+ meshes = renderer.loaded.meshes.getOrPut(mesh.position.chunkPosition) { Int2ObjectOpenHashMap() }
+ position = mesh.position.chunkPosition
}
- meshes.put(mesh.sectionHeight, mesh)?.let {
+ meshes.put(mesh.position.y, mesh)?.let {
renderer.visible.removeMesh(it)
it.unload()
}
- val visible = renderer.visibilityGraph.isSectionVisible(mesh.chunkPosition, mesh.sectionHeight, mesh.minPosition, mesh.maxPosition, true)
+ val visible = renderer.visibilityGraph.isSectionVisible(mesh.position, mesh.minPosition, mesh.maxPosition, true)
if (visible) {
count++
renderer.visible.addMesh(mesh)
@@ -91,7 +91,7 @@ class MeshLoadingQueue(
// already inside, remove
meshes.remove(mesh)
}
- if (mesh.chunkPosition == renderer.cameraChunkPosition) {
+ if (mesh.position.chunkPosition == renderer.cameraSectionPosition.chunkPosition) {
// still higher priority
meshes.add(0, mesh)
} else {
@@ -104,20 +104,20 @@ class MeshLoadingQueue(
if (lock) lock()
val positions: MutableSet = mutableSetOf()
this.positions.removeAll {
- if (it.position != position) {
+ if (it.position.chunkPosition != position) {
return@removeAll false
}
positions += it
return@removeAll true
}
- this.meshes.removeAll { QueuePosition(it.chunkPosition, it.sectionHeight) in positions }
+ this.meshes.removeAll { QueuePosition(it.position) in positions }
if (lock) unlock()
}
fun abort(position: QueuePosition, lock: Boolean = true) {
if (lock) lock()
if (this.positions.remove(position)) {
- this.meshes.removeAll { it.chunkPosition == position.position && it.sectionHeight == position.sectionHeight }
+ this.meshes.removeAll { it.position == position.position }
}
if (lock) unlock()
}
@@ -128,7 +128,7 @@ class MeshLoadingQueue(
if (lock) lock()
this.positions.removeAll {
- if (renderer.visibilityGraph.isChunkVisible(it.position)) {
+ if (renderer.visibilityGraph.isChunkVisible(it.position.chunkPosition)) {
return@removeAll false
}
remove += it
diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/queue/loading/MeshUnloadingQueue.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/queue/loading/MeshUnloadingQueue.kt
index ef3ef4383..ef66fafa2 100644
--- a/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/queue/loading/MeshUnloadingQueue.kt
+++ b/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/queue/loading/MeshUnloadingQueue.kt
@@ -60,7 +60,7 @@ class MeshUnloadingQueue(
fun forceQueue(mesh: ChunkMeshes, lock: Boolean = true) {
if (lock) lock()
- if (mesh.chunkPosition == renderer.session.camera.entity.physics.positionInfo.chunkPosition) {
+ if (mesh.position.chunkPosition == renderer.session.camera.entity.physics.positionInfo.chunkPosition) {
this.meshes.add(0, mesh)
} else {
this.meshes += mesh
diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/queue/meshing/ChunkMeshingQueue.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/queue/meshing/ChunkMeshingQueue.kt
index ef046ba9c..bc83905ba 100644
--- a/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/queue/meshing/ChunkMeshingQueue.kt
+++ b/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/queue/meshing/ChunkMeshingQueue.kt
@@ -72,11 +72,11 @@ class ChunkMeshingQueue(
items += item
}
unlock()
- val camera = renderer.cameraChunkPosition
+ val camera = renderer.cameraSectionPosition
for (item in items) {
- val distance = abs(item.chunkPosition.x - camera.x) + abs(item.chunkPosition.z - camera.z)
+ val distance = abs(item.position.x - camera.x) + abs(item.position.z - camera.z) // TODO: Check y?
val runnable = HeavyPoolRunnable(if (distance < 1) ThreadPool.HIGH else ThreadPool.LOW, interruptable = true)
- val task = MeshPrepareTask(item.chunkPosition, item.sectionHeight, runnable)
+ val task = MeshPrepareTask(item.position, runnable)
task.runnable.runnable = Runnable { renderer.mesher.tryMesh(item, task, task.runnable) }
tasks += task
}
@@ -87,7 +87,7 @@ class ChunkMeshingQueue(
fun remove(chunkPosition: ChunkPosition) {
val remove: MutableSet = mutableSetOf()
queue.removeAll {
- if (it.chunkPosition != chunkPosition) {
+ if (it.position.chunkPosition != chunkPosition) {
return@removeAll false
}
remove += it
@@ -100,7 +100,7 @@ class ChunkMeshingQueue(
if (lock) lock()
val remove: MutableSet = mutableSetOf()
queue.removeAll {
- if (renderer.visibilityGraph.isChunkVisible(it.chunkPosition)) {
+ if (renderer.visibilityGraph.isChunkVisible(it.position.chunkPosition)) {
return@removeAll false
}
remove += it
@@ -153,7 +153,7 @@ class ChunkMeshingQueue(
if (set.remove(item)) {
queue -= item
}
- if (item.chunkPosition == renderer.cameraChunkPosition) {
+ if (item.position.chunkPosition == renderer.cameraSectionPosition.chunkPosition) {
queue.add(0, item)
} else {
queue += item
diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/queue/meshing/ChunkQueueComparator.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/queue/meshing/ChunkQueueComparator.kt
index e20bc7a1f..e90ad8970 100644
--- a/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/queue/meshing/ChunkQueueComparator.kt
+++ b/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/queue/meshing/ChunkQueueComparator.kt
@@ -13,31 +13,26 @@
package de.bixilon.minosoft.gui.rendering.chunk.queue.meshing
-import de.bixilon.minosoft.data.world.positions.ChunkPosition
+import de.bixilon.minosoft.data.world.positions.SectionPosition
import de.bixilon.minosoft.gui.rendering.chunk.ChunkRenderer
import de.bixilon.minosoft.gui.rendering.chunk.WorldQueueItem
class ChunkQueueComparator : Comparator {
private var sort = 1
- private var position: ChunkPosition = ChunkPosition.EMPTY
- private var height = 0
+ private var position = SectionPosition()
fun update(renderer: ChunkRenderer) {
- if (this.position == renderer.cameraChunkPosition && this.height == renderer.cameraSectionHeight) return
- this.position = renderer.cameraChunkPosition
- this.height = renderer.cameraSectionHeight
+ if (this.position == renderer.cameraSectionPosition) return
+ this.position = renderer.cameraSectionPosition
sort++
}
private fun getDistance(item: WorldQueueItem): Int {
if (item.sort == this.sort) return item.distance
- val array = item.sectionPosition.array
- val x = array[0] - position.x
- val y = array[1] - height
- val z = array[2] - position.z
- val distance = (x * x + y * y + z * z)
+ val position = item.position
+ val distance = (position - this.position).length2()
item.distance = distance
item.sort = sort
diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/queue/meshing/tasks/MeshPrepareTask.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/queue/meshing/tasks/MeshPrepareTask.kt
index 85df1b22c..4ea66b634 100644
--- a/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/queue/meshing/tasks/MeshPrepareTask.kt
+++ b/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/queue/meshing/tasks/MeshPrepareTask.kt
@@ -14,10 +14,9 @@
package de.bixilon.minosoft.gui.rendering.chunk.queue.meshing.tasks
import de.bixilon.kutil.concurrent.pool.runnable.HeavyPoolRunnable
-import de.bixilon.minosoft.data.world.positions.ChunkPosition
+import de.bixilon.minosoft.data.world.positions.SectionPosition
class MeshPrepareTask(
- val chunkPosition: ChunkPosition,
- val sectionHeight: Int,
+ val position: SectionPosition,
val runnable: HeavyPoolRunnable,
)
diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/queue/meshing/tasks/MeshPrepareTaskManager.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/queue/meshing/tasks/MeshPrepareTaskManager.kt
index 5e50a9bd2..1ab340f1f 100644
--- a/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/queue/meshing/tasks/MeshPrepareTaskManager.kt
+++ b/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/queue/meshing/tasks/MeshPrepareTaskManager.kt
@@ -16,7 +16,7 @@ package de.bixilon.minosoft.gui.rendering.chunk.queue.meshing.tasks
import de.bixilon.kutil.concurrent.lock.RWLock
import de.bixilon.kutil.concurrent.pool.DefaultThreadPool
import de.bixilon.minosoft.data.world.positions.ChunkPosition
-import de.bixilon.minosoft.data.world.positions.SectionHeight
+import de.bixilon.minosoft.data.world.positions.SectionPosition
import de.bixilon.minosoft.gui.rendering.chunk.ChunkRenderer
class MeshPrepareTaskManager(
@@ -58,17 +58,17 @@ class MeshPrepareTaskManager(
fun interrupt(position: ChunkPosition) {
lock.acquire()
for (task in tasks) {
- if (task.chunkPosition == position) {
+ if (task.position.chunkPosition == position) {
task.runnable.interrupt()
}
}
lock.release()
}
- fun interrupt(position: ChunkPosition, height: SectionHeight) {
+ fun interrupt(position: SectionPosition) {
lock.acquire()
for (task in tasks) {
- if (task.chunkPosition == position && task.sectionHeight == height) {
+ if (task.position == position) {
task.runnable.interrupt()
}
}
@@ -79,7 +79,7 @@ class MeshPrepareTaskManager(
fun cleanup() {
lock.acquire()
for (task in tasks) {
- if (!renderer.visibilityGraph.isChunkVisible(task.chunkPosition)) {
+ if (!renderer.visibilityGraph.isChunkVisible(task.position.chunkPosition)) {
task.runnable.interrupt()
}
}
diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/queue/queue/ChunkQueueMaster.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/queue/queue/ChunkQueueMaster.kt
index a3303e5bd..31f7ca231 100644
--- a/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/queue/queue/ChunkQueueMaster.kt
+++ b/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/queue/queue/ChunkQueueMaster.kt
@@ -20,6 +20,7 @@ import de.bixilon.minosoft.data.world.chunk.ChunkSection
import de.bixilon.minosoft.data.world.chunk.chunk.Chunk
import de.bixilon.minosoft.data.world.positions.BlockPosition
import de.bixilon.minosoft.data.world.positions.SectionHeight
+import de.bixilon.minosoft.data.world.positions.SectionPosition
import de.bixilon.minosoft.gui.rendering.RenderingStates
import de.bixilon.minosoft.gui.rendering.chunk.ChunkRenderer
import de.bixilon.minosoft.gui.rendering.chunk.WorldQueueItem
@@ -32,15 +33,16 @@ class ChunkQueueMaster(
) {
private fun queue(section: ChunkSection, chunk: Chunk, force: Boolean): Boolean {
+ val position = SectionPosition.of(chunk.position, section.height)
if (section.blocks.isEmpty) {
- renderer.unload(QueuePosition(chunk.position, section.height))
+ renderer.unload(QueuePosition(position))
return false
}
- val visible = force || renderer.visibilityGraph.isSectionVisible(chunk.position, section.height, section.blocks.minPosition, section.blocks.maxPosition, true)
+ val visible = force || renderer.visibilityGraph.isSectionVisible(position, section.blocks.minPosition, section.blocks.maxPosition, true)
if (visible) {
val center = CHUNK_CENTER + BlockPosition.of(chunk.position, section.height)
- val item = WorldQueueItem(chunk.position, section.height, chunk, section, center)
+ val item = WorldQueueItem(position, chunk, section, center)
renderer.meshingQueue.queue(item)
return true
}
diff --git a/src/test/java/de/bixilon/minosoft/data/world/positions/BlockPositionTest.kt b/src/test/java/de/bixilon/minosoft/data/world/positions/BlockPositionTest.kt
index e65040c0a..cff3bdd9f 100644
--- a/src/test/java/de/bixilon/minosoft/data/world/positions/BlockPositionTest.kt
+++ b/src/test/java/de/bixilon/minosoft/data/world/positions/BlockPositionTest.kt
@@ -84,8 +84,8 @@ class BlockPositionTest {
@Test
fun `correct negative y large`() {
- val position = BlockPosition(-2048, 0xF, 0xF)
- assertEquals(position.x, -2048)
+ val position = BlockPosition(1234, -2048, 0xF)
+ assertEquals(position.y, -2048)
}
@Test
diff --git a/src/test/java/de/bixilon/minosoft/data/world/positions/SectionPositionTest.kt b/src/test/java/de/bixilon/minosoft/data/world/positions/SectionPositionTest.kt
new file mode 100644
index 000000000..d896ececc
--- /dev/null
+++ b/src/test/java/de/bixilon/minosoft/data/world/positions/SectionPositionTest.kt
@@ -0,0 +1,179 @@
+/*
+ * 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.data.world.positions
+
+import org.junit.jupiter.api.Test
+import org.junit.jupiter.api.assertThrows
+import kotlin.test.assertEquals
+
+class SectionPositionTest {
+
+ @Test
+ fun `init correct min`() {
+ val position = SectionPosition(-1875000, -128, -1875000)
+ }
+
+ @Test
+ fun `init correct max`() {
+ val position = SectionPosition(1875000, 127, 1875000)
+ }
+
+ @Test
+ fun `init badly`() {
+ assertThrows { SectionPosition(-1875001, 128, -1875001) }
+ }
+
+ @Test
+ fun `correct positive x`() {
+ val position = SectionPosition(2, 0xF, 0xF)
+ assertEquals(position.x, 2)
+ }
+
+ @Test
+ fun `correct positive x large`() {
+ val position = SectionPosition(1875000, 0xF, 0xF)
+ assertEquals(position.x, 1875000)
+ }
+
+ @Test
+ fun `correct negative x`() {
+ val position = SectionPosition(-2, 0xF, 0xF)
+ assertEquals(position.x, -2)
+ }
+
+ @Test
+ fun `correct negative x large`() {
+ val position = SectionPosition(-1875000, 0xF, 0xF)
+ assertEquals(position.x, -1875000)
+ }
+
+ @Test
+ fun `correct plus x`() {
+ val position = SectionPosition(2, 0xF, 0xF)
+ assertEquals(position.plusX().x, 3)
+ }
+
+ @Test
+ fun `correct plus 2 x`() {
+ val position = SectionPosition(2, 0xF, 0xF)
+ assertEquals(position.plusX(2).x, 4)
+ }
+
+ @Test
+ fun `correct minus x`() {
+ val position = SectionPosition(2, 0xF, 0xF)
+ assertEquals(position.minusX().x, 1)
+ }
+
+ @Test
+ fun `correct negative y`() {
+ val position = SectionPosition(0xF, -4, 0xF)
+ assertEquals(position.y, -4)
+ }
+
+ @Test
+ fun `correct negative y large`() {
+ val position = SectionPosition(123, -128, 0xF)
+ assertEquals(position.y, -128)
+ }
+
+ @Test
+ fun `correct positive y`() {
+ val position = SectionPosition(0xF, 100, 0xF)
+ assertEquals(position.y, 100)
+ }
+
+ @Test
+ fun `correct positive y large`() {
+ val position = SectionPosition(0xF, 127, 0xF)
+ assertEquals(position.y, 127)
+ }
+
+ @Test
+ fun `correct plus y`() {
+ val position = SectionPosition(0xF, 2, 0xF)
+ assertEquals(position.plusY().y, 3)
+ }
+
+ @Test
+ fun `correct plus 2 y`() {
+ val position = SectionPosition(0xF, 2, 0xF)
+ assertEquals(position.plusY(2).y, 4)
+ }
+
+ @Test
+ fun `correct minus y`() {
+ val position = SectionPosition(0xF, 2, 0xF)
+ assertEquals(position.minusY().y, 1)
+ }
+
+ @Test
+ fun `correct positive z`() {
+ val position = SectionPosition(0xF, 0xF, 4)
+ assertEquals(position.z, 4)
+ }
+
+ @Test
+ fun `correct positive z large`() {
+ val position = SectionPosition(0, 0, 1875000)
+ assertEquals(position.z, 1875000)
+ }
+
+ @Test
+ fun `correct negative z`() {
+ val position = SectionPosition(0xF, 0xF, -4)
+ assertEquals(position.z, -4)
+ }
+
+ @Test
+ fun `correct negative z large`() {
+ val position = SectionPosition(0, 0, -1875000)
+ assertEquals(position.z, -1875000)
+ }
+
+
+ @Test
+ fun `correct plus z`() {
+ val position = SectionPosition(0xF, 0xF, 2)
+ assertEquals(position.plusZ().z, 3)
+ }
+
+ @Test
+ fun `correct plus 2 z`() {
+ val position = SectionPosition(0xF, 0xF, 2)
+ assertEquals(position.plusZ(2).z, 4)
+ }
+
+ @Test
+ fun `correct minus z`() {
+ val position = SectionPosition(0xF, 0xF, 2)
+ assertEquals(position.minusZ().z, 1)
+ }
+
+ @Test
+ fun `unary minus`() {
+ val position = -SectionPosition(2, 2, 2)
+ assertEquals(position.x, -2)
+ assertEquals(position.y, -2)
+ assertEquals(position.z, -2)
+ }
+
+ @Test
+ fun `unary plus`() {
+ val position = +SectionPosition(2, 2, 2)
+ assertEquals(position.x, 2)
+ assertEquals(position.y, 2)
+ assertEquals(position.z, 2)
+ }
+}