prevent crash when entity position is out of bounds (of block position)

This is not done well, clamping the position will introduce weird bugs in full height dimensions, because minosoft assumes that the position is still in the world.
This commit is contained in:
Moritz Zwerger 2025-04-11 14:42:04 +02:00
parent f96047dbfe
commit 941b8c9f9c
No known key found for this signature in database
GPG Key ID: 5CAD791931B09AC4
10 changed files with 46 additions and 17 deletions

View File

@ -90,9 +90,9 @@ enum class Directions(
@Deprecated("outsource")
fun byDirection(direction: Vec3): Directions {
var minDirection = VALUES[0]
var minError = 2.0f
var minError = 2.0f * 2.0f
for (testDirection in VALUES) {
val error = (testDirection.vectorf - direction).length()
val error = (testDirection.vectorf - direction).length2()
if (error < MIN_ERROR) {
return testDirection
} else if (error < minError) {

View File

@ -204,8 +204,6 @@ abstract class Entity(
preTick()
tick()
postTick()
} catch (error: Throwable) {
error.printStackTrace()
} finally {
lastTickTime = time
lock.unlock()

View File

@ -28,6 +28,7 @@ import de.bixilon.minosoft.data.world.positions.InSectionPosition
import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3Util.EMPTY
import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3Util.ONE
import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3Util.toVec3
import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3dUtil.clampBlockPosition
import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3dUtil.get
import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3dUtil.max
import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3dUtil.min
@ -100,7 +101,7 @@ class AABB {
}
fun positions(order: AABBIterator.IterationOrder = AABBIterator.IterationOrder.OPTIMIZED): AABBIterator {
return AABBIterator(this, order)
return AABBIterator(min.clampBlockPosition(), max.clampBlockPosition(), order)
}
fun extend(vec3: Vec3d): AABB {

View File

@ -13,6 +13,7 @@
package de.bixilon.minosoft.data.registries.shapes.aabb
import de.bixilon.kotlinglm.vec3.Vec3d
import de.bixilon.minosoft.data.world.World
import de.bixilon.minosoft.data.world.chunk.chunk.Chunk
import de.bixilon.minosoft.data.world.iterator.WorldIterator
@ -30,8 +31,7 @@ class AABBIterator(
val size = maxOf(0, max.x - min.x + 1) * maxOf(0, max.y - min.y + 1) * maxOf(0, max.z - min.z + 1)
constructor(aabb: AABB) : this(aabb.min.floor, aabb.max.ceil - 1)
constructor(aabb: AABB, order: IterationOrder) : this(aabb.min.floor, aabb.max.ceil - 1, order)
constructor(min: Vec3d, max: Vec3d, order: IterationOrder) : this(min.floor, max.ceil - 1, order)
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 {

View File

@ -16,12 +16,13 @@ package de.bixilon.minosoft.data.world.vec
import de.bixilon.minosoft.data.Axes
import de.bixilon.minosoft.data.direction.DirectionVector
import de.bixilon.minosoft.data.direction.Directions
import de.bixilon.minosoft.data.text.BaseComponent
import de.bixilon.minosoft.data.text.formatting.TextFormattable
import de.bixilon.minosoft.data.world.vec.VecUtil.assertVec
import de.bixilon.minosoft.util.KUtil.format
@JvmInline
value class SVec3(val raw: Int) {
value class SVec3(val raw: Int) : TextFormattable {
constructor() : this(0, 0, 0)
constructor(x: Int, y: Int, z: Int) : this(((y and MASK_Y) shl SHIFT_Y) or ((z and MASK_Z) shl SHIFT_Z) or ((x and MASK_X) shl SHIFT_X)) {
@ -103,7 +104,16 @@ value class SVec3(val raw: Int) {
Axes.Z -> z
}
override fun toString() = "(${this.x.format()} ${this.y.format()} ${this.z.format()})"
override fun toString() = "(${this.x} ${this.y} ${this.z})"
override fun toText() = BaseComponent().apply {
this += "("
this += x.format()
this += " "
this += y.format()
this += " "
this += z.format()
this += ")"
}
companion object {

View File

@ -47,7 +47,11 @@ class Camera(
fun draw() {
val entity = context.session.camera.entity
(entity.attachment.getRootVehicle() ?: entity).tryTick() // TODO
try {
(entity.attachment.getRootVehicle() ?: entity).tryTick() // TODO
} catch (error: Throwable) {
error.printStackTrace()
}
if (entity is LocalPlayerEntity) {
entity._draw(millis())
}

View File

@ -13,6 +13,7 @@
package de.bixilon.minosoft.gui.rendering.util.vec.vec3
import de.bixilon.kotlinglm.func.common.clamp
import de.bixilon.kotlinglm.vec3.Vec3
import de.bixilon.kotlinglm.vec3.Vec3d
import de.bixilon.kotlinglm.vec3.Vec3i
@ -59,6 +60,19 @@ object Vec3dUtil {
return Vec3(floatArrayOf(array[0].toFloat(), array[1].toFloat(), array[2].toFloat()))
}
private fun Double.clamp(min: Int, max: Int) = clamp(min.toDouble(), max.toDouble())
fun Vec3d.clampBlockPosition(): Vec3d { // TODO: remove +1/-1. AABBIterator otherwise crashes when subtracting one
val x = x.clamp(-BlockPosition.MAX_X + 1, BlockPosition.MAX_X - 1)
val y = y.clamp(+BlockPosition.MIN_Y + 1, BlockPosition.MAX_Y - 1)
val z = z.clamp(-BlockPosition.MAX_Z + 1, BlockPosition.MAX_Z - 1)
if (x != this.x || y != this.y || this.z != z) {
return Vec3d(x, y, z)
}
return this
}
fun interpolateLinear(delta: Double, start: Vec3d, end: Vec3d): Vec3d {
if (delta <= 0.0) {

View File

@ -14,6 +14,7 @@
package de.bixilon.minosoft.physics.entities
import de.bixilon.kotlinglm.vec3.Vec3d
import de.bixilon.kutil.math.simple.IntMath.clamp
import de.bixilon.kutil.primitive.DoubleUtil
import de.bixilon.minosoft.data.direction.Directions
import de.bixilon.minosoft.data.entities.EntityRotation
@ -104,10 +105,10 @@ open class EntityPhysics<E : Entity>(val entity: E) : BasicPhysicsEntity(), Abst
fun getLandingPosition(): BlockPosition {
val info = this.positionInfo
val position = BlockPosition(info.position.x, (position.y - 0.2).toInt(), info.position.z) // TODO: can y get below 0?
val position = BlockPosition(info.position.x, (position.y - 0.2).toInt().clamp(BlockPosition.MIN_Y, BlockPosition.MAX_Y), info.position.z) // TODO: can y get below 0?
val inChunk = position.inChunkPosition
val state = positionInfo.chunk?.get(inChunk)
if (state == null) {
if (state == null && inChunk.y > BlockPosition.MIN_Y) {
val down = positionInfo.chunk?.get(inChunk + Directions.DOWN)
// TODO: check if block is fence, fence gate or wall
// return down

View File

@ -16,11 +16,11 @@ package de.bixilon.minosoft.physics.parts
import de.bixilon.kotlinglm.vec2.Vec2d
import de.bixilon.kotlinglm.vec3.Vec3d
import de.bixilon.kutil.math.simple.DoubleMath.floor
import de.bixilon.kutil.math.simple.IntMath.clamp
import de.bixilon.minosoft.data.Axes
import de.bixilon.minosoft.data.abilities.Gamemodes
import de.bixilon.minosoft.data.direction.Directions
import de.bixilon.minosoft.data.world.positions.BlockPosition
import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3iUtil.get
import de.bixilon.minosoft.physics.entities.living.player.local.LocalPlayerPhysics
object OutOfBlockPusher {
@ -31,7 +31,7 @@ object OutOfBlockPusher {
}
private fun LocalPlayerPhysics.pushOutOfBlocks(x: Double, z: Double) {
val position = BlockPosition(x.floor, this.position.y.floor, z.floor)
val position = BlockPosition(x.floor, this.position.y.floor.clamp(BlockPosition.MIN_Y, BlockPosition.MAX_Y), z.floor)
if (!wouldCollidePushable(position)) {
return
}

View File

@ -13,6 +13,7 @@
package de.bixilon.minosoft.physics.submersion
import de.bixilon.kotlinglm.func.common.clamp
import de.bixilon.kotlinglm.vec3.Vec3d
import de.bixilon.kutil.math.simple.DoubleMath.floor
import de.bixilon.minosoft.data.Tickable
@ -67,7 +68,7 @@ class SubmersionState(private val physics: EntityPhysics<*>) : Tickable {
val totalVelocity = Vec3d.EMPTY
var count = 0
for ((position, state, chunk) in WorldIterator(aabb.positions(), world, physics.positionInfo.chunk)) {
for ((position, state, chunk) in WorldIterator(aabb, world, physics.positionInfo.chunk)) {
if (!fluid.matches(state)) continue // TODO: tags?
val height = position.y + if (fluid.matches(chunk[position.inChunkPosition + Directions.UP])) 1.0f else fluid.getHeight(state)
@ -147,7 +148,7 @@ class SubmersionState(private val physics: EntityPhysics<*>) : Tickable {
// TODO
}
val position = physics.position
val eyePosition = BlockPosition(position.x.floor, eyeHeight.floor, position.z.floor)
val eyePosition = BlockPosition(position.x.floor, eyeHeight.floor.clamp(BlockPosition.MIN_Y, BlockPosition.MAX_Y), position.z.floor)
val block = physics.positionInfo.chunk?.get(eyePosition.inChunkPosition) ?: return
if (block.block !is FluidHolder) {