mirror of
https://gitlab.bixilon.de/bixilon/minosoft.git
synced 2025-09-15 10:25:06 -04:00
physics: reduce memory allocations a lot
This should improve performance of physics when exploding millions of tnt. Memory is being reused with the temporary allocator. Shapes are extracted initially, which is still bad, because most of them are empty.
This commit is contained in:
parent
2340fc1a3d
commit
728ca1ce2f
@ -82,4 +82,32 @@ class CollisionIT {
|
|||||||
player.assertPosition(0.0, 1.5, 0.0)
|
player.assertPosition(0.0, 1.5, 0.0)
|
||||||
player.assertVelocity(0.0, -0.0784000015258789, 0.0)
|
player.assertVelocity(0.0, -0.0784000015258789, 0.0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun `not crashing when already exceeding negative y`() {
|
||||||
|
val player = createPlayer(createSession(2))
|
||||||
|
player.forceTeleport(Vec3d(0.0, -3000, 0.0))
|
||||||
|
player.physics.velocity = Vec3d(0.0, -150.0, 0.0)
|
||||||
|
player.runTicks(10)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun `not crashing when exceeding negative y`() {
|
||||||
|
val player = createPlayer(createSession(2))
|
||||||
|
player.forceTeleport(Vec3d(0.0, -2040, 0.0))
|
||||||
|
player.physics.velocity = Vec3d(0.0, -150.0, 0.0)
|
||||||
|
player.runTicks(10)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun `not crashing when already exceeding positive y`() {
|
||||||
|
val player = createPlayer(createSession(2))
|
||||||
|
player.forceTeleport(Vec3d(0.0, 3000, 0.0))
|
||||||
|
player.physics.velocity = Vec3d(0.0, 150.0, 0.0)
|
||||||
|
player.runTicks(10)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun `not crashing when exceeding positive y`() {
|
||||||
|
val player = createPlayer(createSession(2))
|
||||||
|
player.forceTeleport(Vec3d(0.0, 2040, 0.0))
|
||||||
|
player.physics.velocity = Vec3d(0.0, 150.0, 0.0)
|
||||||
|
player.runTicks(10)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,6 @@ import de.bixilon.kotlinglm.func.common.clamp
|
|||||||
import de.bixilon.kotlinglm.vec3.Vec3
|
import de.bixilon.kotlinglm.vec3.Vec3
|
||||||
import de.bixilon.kotlinglm.vec3.Vec3d
|
import de.bixilon.kotlinglm.vec3.Vec3d
|
||||||
import de.bixilon.kotlinglm.vec3.Vec3i
|
import de.bixilon.kotlinglm.vec3.Vec3i
|
||||||
import de.bixilon.kotlinglm.vec3.Vec3t
|
|
||||||
import de.bixilon.kutil.math.simple.DoubleMath.ceil
|
import de.bixilon.kutil.math.simple.DoubleMath.ceil
|
||||||
import de.bixilon.kutil.math.simple.DoubleMath.floor
|
import de.bixilon.kutil.math.simple.DoubleMath.floor
|
||||||
import de.bixilon.minosoft.data.Axes
|
import de.bixilon.minosoft.data.Axes
|
||||||
@ -59,12 +58,13 @@ class AABB {
|
|||||||
this.max = max
|
this.max = max
|
||||||
}
|
}
|
||||||
|
|
||||||
fun intersect(other: AABB): Boolean {
|
fun intersects(other: AABB): Boolean {
|
||||||
return (min.x < other.max.x && max.x > other.min.x) && (min.y < other.max.y && max.y > other.min.y) && (min.z < other.max.z && max.z > other.min.z)
|
return (min.x < other.max.x && max.x > other.min.x) && (min.y < other.max.y && max.y > other.min.y) && (min.z < other.max.z && max.z > other.min.z)
|
||||||
}
|
}
|
||||||
|
|
||||||
operator fun plus(other: Vec3t<out Number>): AABB = offset(other)
|
fun intersects(other: AABB, offset: BlockPosition): Boolean {
|
||||||
fun offset(other: Vec3t<out Number>) = AABB(true, min + other, max + other)
|
return (min.x < (other.max.x + offset.x) && max.x > (other.min.x + offset.x)) && (min.y < (other.max.y + offset.y) && max.y > (other.min.y + offset.y)) && (min.z < (other.max.z + offset.z) && max.z > (other.min.z + offset.z))
|
||||||
|
}
|
||||||
|
|
||||||
operator fun plus(other: Vec3d): AABB = offset(other)
|
operator fun plus(other: Vec3d): AABB = offset(other)
|
||||||
fun offset(other: Vec3d) = AABB(true, min + other, max + other)
|
fun offset(other: Vec3d) = AABB(true, min + other, max + other)
|
||||||
@ -128,15 +128,10 @@ class AABB {
|
|||||||
return AABB(true, newMin, newMax)
|
return AABB(true, newMin, newMax)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun extend(vec3i: Vec3i): AABB {
|
|
||||||
return this.extend(Vec3d(vec3i))
|
|
||||||
}
|
|
||||||
|
|
||||||
fun extend(direction: Directions): AABB {
|
fun extend(direction: Directions): AABB {
|
||||||
return this.extend(direction.vectord)
|
return this.extend(direction.vectord)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fun grow(size: Double = 1.0E-7): AABB {
|
fun grow(size: Double = 1.0E-7): AABB {
|
||||||
return AABB(min - size, max + size)
|
return AABB(min - size, max + size)
|
||||||
}
|
}
|
||||||
@ -149,37 +144,38 @@ class AABB {
|
|||||||
return this > min && this < max
|
return this > min && this < max
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun intersects(axis: Axes, other: AABB): Boolean {
|
private fun intersects(axis: Axes, other: AABB, offset: BlockPosition): Boolean {
|
||||||
val min = min[axis]
|
val min = min[axis]
|
||||||
val max = max[axis]
|
val max = max[axis]
|
||||||
|
|
||||||
val otherMin = other.min[axis]
|
val otherMin = other.min[axis] + offset[axis]
|
||||||
val otherMax = other.max[axis]
|
val otherMax = other.max[axis] + offset[axis]
|
||||||
|
|
||||||
return min.isIn(otherMin, otherMax)
|
return min.isIn(otherMin, otherMax)
|
||||||
|| max.isIn(otherMin, otherMax)
|
|| max.isIn(otherMin, otherMax)
|
||||||
|| otherMin.isIn(min, max)
|
|| otherMin.isIn(min, max)
|
||||||
|| otherMax.isIn(min, max)
|
|| otherMax.isIn(min, max)
|
||||||
|| (min == otherMin && max == otherMax)
|
|| (min == otherMin && max == otherMax)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun calculateMaxOffset(other: AABB, offset: Double, axis: Axes): Double {
|
fun calculateMaxDistance(other: AABB, maxDistance: Double, axis: Axes) = calculateMaxDistance(other, BlockPosition(), maxDistance, axis)
|
||||||
if (!intersects(axis.next(), other) || !intersects(axis.previous(), other)) {
|
fun calculateMaxDistance(other: AABB, offset: BlockPosition, maxDistance: Double, axis: Axes): Double {
|
||||||
return offset
|
if (!intersects(axis.next(), other, offset) || !intersects(axis.previous(), other, offset)) {
|
||||||
|
return maxDistance
|
||||||
}
|
}
|
||||||
val min = min[axis]
|
val min = min[axis]
|
||||||
val max = max[axis]
|
val max = max[axis]
|
||||||
val otherMin = other.min[axis]
|
val otherMin = other.min[axis] + offset[axis]
|
||||||
val otherMax = other.max[axis]
|
val otherMax = other.max[axis] + offset[axis]
|
||||||
|
|
||||||
if (offset > 0 && otherMax <= min && otherMax + offset > min) {
|
if (maxDistance > 0 && otherMax <= min && otherMax + maxDistance > min) {
|
||||||
return (min - otherMax).clamp(0.0, offset)
|
return (min - otherMax).clamp(0.0, maxDistance)
|
||||||
}
|
}
|
||||||
if (offset < 0 && max <= otherMin && otherMin + offset < max) {
|
if (maxDistance < 0 && max <= otherMin && otherMin + maxDistance < max) {
|
||||||
return (max - otherMin).clamp(offset, 0.0)
|
return (max - otherMin).clamp(maxDistance, 0.0)
|
||||||
}
|
}
|
||||||
|
|
||||||
return offset
|
return maxDistance
|
||||||
}
|
}
|
||||||
|
|
||||||
@Deprecated("mutable")
|
@Deprecated("mutable")
|
||||||
@ -188,12 +184,10 @@ class AABB {
|
|||||||
max.array[axis.ordinal] += value
|
max.array[axis.ordinal] += value
|
||||||
}
|
}
|
||||||
|
|
||||||
fun offset(axis: Axes, offset: Double): AABB {
|
fun offset(axis: Axes, offset: Double) = when (axis) {
|
||||||
return when (axis) {
|
Axes.X -> this + Vec3d(-offset, 0.0, 0.0)
|
||||||
Axes.X -> this + Vec3d(-offset, 0.0, 0.0)
|
Axes.Y -> this + Vec3d(0.0, -offset, 0.0)
|
||||||
Axes.Y -> this + Vec3d(0.0, -offset, 0.0)
|
Axes.Z -> this + Vec3d(0.0, 0.0, -offset)
|
||||||
Axes.Z -> this + Vec3d(0.0, 0.0, -offset)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -296,19 +290,19 @@ class AABB {
|
|||||||
|
|
||||||
fun checkSide(x: Double): Boolean {
|
fun checkSide(x: Double): Boolean {
|
||||||
return (this.min == Vec3d(x, min.y, min.z) && this.max == Vec3d(x, max.y, min.z))
|
return (this.min == Vec3d(x, min.y, min.z) && this.max == Vec3d(x, max.y, min.z))
|
||||||
|| (this.min == Vec3d(x, min.y, min.z) && this.max == Vec3d(x, min.y, max.z))
|
|| (this.min == Vec3d(x, min.y, min.z) && this.max == Vec3d(x, min.y, max.z))
|
||||||
|| (this.min == Vec3d(x, max.y, min.z) && this.max == Vec3d(x, max.y, max.z))
|
|| (this.min == Vec3d(x, max.y, min.z) && this.max == Vec3d(x, max.y, max.z))
|
||||||
|| (this.min == Vec3d(x, min.y, max.z) && this.max == Vec3d(x, max.y, max.z))
|
|| (this.min == Vec3d(x, min.y, max.z) && this.max == Vec3d(x, max.y, max.z))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return checkSide(min.x) // left quad
|
return checkSide(min.x) // left quad
|
||||||
|| checkSide(max.x) // right quad
|
|| checkSide(max.x) // right quad
|
||||||
// connections between 2 quads
|
// connections between 2 quads
|
||||||
|| (this.min == min && this.max == Vec3d(max.x, min.y, min.z))
|
|| (this.min == min && this.max == Vec3d(max.x, min.y, min.z))
|
||||||
|| (this.min == Vec3d(min.x, max.y, min.z) && this.max == Vec3d(max.x, max.y, min.z))
|
|| (this.min == Vec3d(min.x, max.y, min.z) && this.max == Vec3d(max.x, max.y, min.z))
|
||||||
|| (this.min == Vec3d(min.x, max.y, max.z) && this.max == max)
|
|| (this.min == Vec3d(min.x, max.y, max.z) && this.max == max)
|
||||||
|| (this.min == Vec3d(min.x, min.y, max.z) && this.max == Vec3d(max.x, min.y, max.z))
|
|| (this.min == Vec3d(min.x, min.y, max.z) && this.max == Vec3d(max.x, min.y, max.z))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun toString(): String {
|
override fun toString(): String {
|
||||||
|
@ -0,0 +1,125 @@
|
|||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package de.bixilon.minosoft.data.registries.shapes.collision
|
||||||
|
|
||||||
|
import de.bixilon.kotlinglm.vec3.Vec3d
|
||||||
|
import de.bixilon.kutil.array.ArrayUtil.cast
|
||||||
|
import de.bixilon.kutil.cast.CastUtil.unsafeCast
|
||||||
|
import de.bixilon.minosoft.data.Axes
|
||||||
|
import de.bixilon.minosoft.data.registries.blocks.shapes.collision.CollisionPredicate
|
||||||
|
import de.bixilon.minosoft.data.registries.blocks.shapes.collision.context.CollisionContext
|
||||||
|
import de.bixilon.minosoft.data.registries.blocks.types.entity.BlockWithEntity
|
||||||
|
import de.bixilon.minosoft.data.registries.blocks.types.properties.shape.collision.CollidableBlock
|
||||||
|
import de.bixilon.minosoft.data.registries.blocks.types.properties.shape.collision.fixed.FixedCollidable
|
||||||
|
import de.bixilon.minosoft.data.registries.shapes.aabb.AABB
|
||||||
|
import de.bixilon.minosoft.data.registries.shapes.voxel.AbstractVoxelShape
|
||||||
|
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.allocator.LongAllocator
|
||||||
|
import de.bixilon.minosoft.gui.rendering.util.allocator.TemporaryAllocator
|
||||||
|
|
||||||
|
class CollisionShape(
|
||||||
|
val world: World,
|
||||||
|
context: CollisionContext,
|
||||||
|
aabb: AABB,
|
||||||
|
movement: Vec3d,
|
||||||
|
chunk: Chunk?,
|
||||||
|
predicate: CollisionPredicate? = null,
|
||||||
|
) : AbstractVoxelShape {
|
||||||
|
override val aabbs: Int
|
||||||
|
|
||||||
|
private var total: Int
|
||||||
|
private val positions: LongArray
|
||||||
|
private val shapes: Array<AbstractVoxelShape>
|
||||||
|
|
||||||
|
|
||||||
|
init {
|
||||||
|
val aabbs = aabb.extend(movement).grow(1.0).positions()
|
||||||
|
val positions = POSITIONS.allocate(aabbs.size)
|
||||||
|
val shapes: Array<AbstractVoxelShape?> = SHAPES.allocate(aabbs.size)
|
||||||
|
|
||||||
|
var index = 0
|
||||||
|
var total = 0
|
||||||
|
|
||||||
|
// TODO: add entity collisions (boat, shulker)
|
||||||
|
// TODO: add world border collision shape
|
||||||
|
|
||||||
|
for ((position, state, chunk) in WorldIterator(aabbs, world, chunk)) {
|
||||||
|
if (state.block !is CollidableBlock) continue
|
||||||
|
if (predicate != null && !predicate.invoke(state)) continue
|
||||||
|
// TODO: filter blocks (e.g. moving piston), whatever that means
|
||||||
|
|
||||||
|
val shape = when (state.block) {
|
||||||
|
is FixedCollidable -> state.block.getCollisionShape(state)
|
||||||
|
is BlockWithEntity<*> -> state.block.getCollisionShape(world.session, context, position, state, chunk.getBlockEntity(position.inChunkPosition))
|
||||||
|
else -> state.block.getCollisionShape(world.session, context, position, state, null)
|
||||||
|
} ?: continue
|
||||||
|
|
||||||
|
if (position in aabb && shape.intersects(aabb, -position)) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
positions[index] = position.raw
|
||||||
|
shapes[index] = shape
|
||||||
|
index++
|
||||||
|
total += shape.aabbs
|
||||||
|
}
|
||||||
|
this.shapes = shapes.cast()
|
||||||
|
this.total = index
|
||||||
|
this.positions = positions
|
||||||
|
this.aabbs = total
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun iterator(): Iterator<AABB> {
|
||||||
|
TODO("Not yet implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun intersects(other: AABB): Boolean {
|
||||||
|
for (index in 0 until total) {
|
||||||
|
val position = BlockPosition(this.positions[index])
|
||||||
|
val shape = this.shapes[index]
|
||||||
|
|
||||||
|
if (shape.intersects(other, -position)) return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun calculateMaxDistance(other: AABB, maxDistance: Double, axis: Axes): Double {
|
||||||
|
var distance = maxDistance
|
||||||
|
|
||||||
|
for (index in 0 until total) {
|
||||||
|
val position = BlockPosition(this.positions[index])
|
||||||
|
val shape = this.shapes[index]
|
||||||
|
|
||||||
|
distance = shape.calculateMaxDistance(other, -position, distance, axis)
|
||||||
|
}
|
||||||
|
|
||||||
|
return distance
|
||||||
|
}
|
||||||
|
|
||||||
|
fun free() {
|
||||||
|
POSITIONS.free(this.positions)
|
||||||
|
SHAPES.free(this.shapes.unsafeCast())
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val POSITIONS = LongAllocator()
|
||||||
|
private val SHAPES = object : TemporaryAllocator<Array<AbstractVoxelShape?>>() {
|
||||||
|
override fun getSize(value: Array<AbstractVoxelShape?>) = value.size
|
||||||
|
override fun create(size: Int): Array<AbstractVoxelShape?> = arrayOfNulls(size)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -16,7 +16,6 @@ package de.bixilon.minosoft.data.registries.shapes.voxel
|
|||||||
import de.bixilon.kotlinglm.vec3.Vec3
|
import de.bixilon.kotlinglm.vec3.Vec3
|
||||||
import de.bixilon.kotlinglm.vec3.Vec3d
|
import de.bixilon.kotlinglm.vec3.Vec3d
|
||||||
import de.bixilon.kotlinglm.vec3.Vec3i
|
import de.bixilon.kotlinglm.vec3.Vec3i
|
||||||
import de.bixilon.kotlinglm.vec3.Vec3t
|
|
||||||
import de.bixilon.kutil.primitive.IntUtil.toInt
|
import de.bixilon.kutil.primitive.IntUtil.toInt
|
||||||
import de.bixilon.minosoft.data.Axes
|
import de.bixilon.minosoft.data.Axes
|
||||||
import de.bixilon.minosoft.data.registries.shapes.ShapeRegistry
|
import de.bixilon.minosoft.data.registries.shapes.ShapeRegistry
|
||||||
@ -30,14 +29,20 @@ import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3dUtil.max
|
|||||||
import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3dUtil.min
|
import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3dUtil.min
|
||||||
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet
|
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet
|
||||||
|
|
||||||
abstract class AbstractVoxelShape : Iterable<AABB> {
|
interface AbstractVoxelShape : Iterable<AABB> {
|
||||||
abstract val aabbs: Int
|
val aabbs: Int
|
||||||
|
|
||||||
fun intersect(other: AABB): Boolean {
|
fun intersects(other: AABB): Boolean {
|
||||||
for (aabb in this) {
|
for (aabb in this) {
|
||||||
if (!aabb.intersect(other)) {
|
if (!aabb.intersects(other)) continue
|
||||||
continue
|
return true
|
||||||
}
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
fun intersects(other: AABB, offset: BlockPosition): Boolean {
|
||||||
|
for (aabb in this) {
|
||||||
|
if (!aabb.intersects(other, offset)) continue
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
@ -51,18 +56,14 @@ abstract class AbstractVoxelShape : Iterable<AABB> {
|
|||||||
return VoxelShape(result)
|
return VoxelShape(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
operator fun plus(offset: Vec3t<out Number>) = modify { it + offset }
|
|
||||||
operator fun plus(offset: Vec3d) = modify { it + offset }
|
operator fun plus(offset: Vec3d) = modify { it + offset }
|
||||||
operator fun plus(offset: Vec3) = modify { it + offset }
|
operator fun plus(offset: Vec3) = modify { it + offset }
|
||||||
operator fun plus(offset: Vec3i) = modify { it + offset }
|
operator fun plus(offset: Vec3i) = modify { it + offset }
|
||||||
|
|
||||||
@JvmName("plusBlockPosition")
|
|
||||||
operator fun plus(offset: BlockPosition) = modify { it + offset }
|
operator fun plus(offset: BlockPosition) = modify { it + offset }
|
||||||
|
|
||||||
@JvmName("plusInChunkPosition")
|
|
||||||
operator fun plus(offset: InChunkPosition) = modify { it + offset }
|
operator fun plus(offset: InChunkPosition) = modify { it + offset }
|
||||||
|
|
||||||
@JvmName("plusInSectionPosition")
|
|
||||||
operator fun plus(offset: InSectionPosition) = modify { it + offset }
|
operator fun plus(offset: InSectionPosition) = modify { it + offset }
|
||||||
|
|
||||||
fun add(other: AbstractVoxelShape): AbstractVoxelShape {
|
fun add(other: AbstractVoxelShape): AbstractVoxelShape {
|
||||||
@ -75,7 +76,15 @@ abstract class AbstractVoxelShape : Iterable<AABB> {
|
|||||||
fun calculateMaxDistance(other: AABB, maxDistance: Double, axis: Axes): Double {
|
fun calculateMaxDistance(other: AABB, maxDistance: Double, axis: Axes): Double {
|
||||||
var distance = maxDistance
|
var distance = maxDistance
|
||||||
for (aabb in this) {
|
for (aabb in this) {
|
||||||
distance = aabb.calculateMaxOffset(other, distance, axis)
|
distance = aabb.calculateMaxDistance(other, distance, axis)
|
||||||
|
}
|
||||||
|
return distance
|
||||||
|
}
|
||||||
|
|
||||||
|
fun calculateMaxDistance(other: AABB, offset: BlockPosition, maxDistance: Double, axis: Axes): Double {
|
||||||
|
var distance = maxDistance
|
||||||
|
for (aabb in this) {
|
||||||
|
distance = aabb.calculateMaxDistance(other, offset, distance, axis)
|
||||||
}
|
}
|
||||||
return distance
|
return distance
|
||||||
}
|
}
|
||||||
@ -110,7 +119,6 @@ abstract class AbstractVoxelShape : Iterable<AABB> {
|
|||||||
return shouldDrawLine(start.toVec3d, end.toVec3d)
|
return shouldDrawLine(start.toVec3d, end.toVec3d)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fun getMax(axis: Axes): Double {
|
fun getMax(axis: Axes): Double {
|
||||||
if (aabbs == 0) return Double.NaN
|
if (aabbs == 0) return Double.NaN
|
||||||
|
|
||||||
|
@ -1,57 +0,0 @@
|
|||||||
/*
|
|
||||||
* Minosoft
|
|
||||||
* Copyright (C) 2020-2023 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 <https://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package de.bixilon.minosoft.data.registries.shapes.voxel
|
|
||||||
|
|
||||||
import de.bixilon.minosoft.data.registries.shapes.aabb.AABB
|
|
||||||
|
|
||||||
class MutableVoxelShape(
|
|
||||||
val aabb: MutableSet<AABB>,
|
|
||||||
) : AbstractVoxelShape() {
|
|
||||||
override val aabbs: Int = aabb.size
|
|
||||||
|
|
||||||
constructor(vararg aabbs: AABB) : this(aabbs.toMutableSet())
|
|
||||||
constructor(shape: AbstractVoxelShape) : this(shape.toMutableSet())
|
|
||||||
|
|
||||||
operator fun plusAssign(aabb: AABB) {
|
|
||||||
this.aabb += aabb
|
|
||||||
}
|
|
||||||
|
|
||||||
operator fun plusAssign(shape: AbstractVoxelShape) {
|
|
||||||
this.aabb += shape
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun iterator(): Iterator<AABB> {
|
|
||||||
return aabb.iterator()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun toString(): String {
|
|
||||||
if (aabbs == 0) {
|
|
||||||
return "VoxelShape{EMPTY}"
|
|
||||||
}
|
|
||||||
return "VoxelShape{$aabb}"
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun hashCode(): Int {
|
|
||||||
return aabb.hashCode()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun equals(other: Any?): Boolean {
|
|
||||||
if (this === other) return true
|
|
||||||
if (other == null && aabbs == 0) return true
|
|
||||||
if (other !is AbstractVoxelShape) return false
|
|
||||||
if (other is VoxelShape) return aabb == other.aabb
|
|
||||||
if (other is MutableVoxelShape) return aabb == other.aabb
|
|
||||||
TODO("Can not compare $this with $other")
|
|
||||||
}
|
|
||||||
}
|
|
@ -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.
|
||||||
*
|
*
|
||||||
@ -19,7 +19,7 @@ import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet
|
|||||||
|
|
||||||
class VoxelShape(
|
class VoxelShape(
|
||||||
val aabb: Collection<AABB>,
|
val aabb: Collection<AABB>,
|
||||||
) : AbstractVoxelShape() {
|
) : AbstractVoxelShape {
|
||||||
override val aabbs: Int = aabb.size
|
override val aabbs: Int = aabb.size
|
||||||
|
|
||||||
constructor(vararg aabbs: AABB) : this(ObjectOpenHashSet(aabbs))
|
constructor(vararg aabbs: AABB) : this(ObjectOpenHashSet(aabbs))
|
||||||
@ -47,7 +47,6 @@ class VoxelShape(
|
|||||||
if (other == null && aabbs == 0) return true
|
if (other == null && aabbs == 0) return true
|
||||||
if (other !is AbstractVoxelShape) return false
|
if (other !is AbstractVoxelShape) return false
|
||||||
if (other is VoxelShape) return aabb == other.aabb
|
if (other is VoxelShape) return aabb == other.aabb
|
||||||
if (other is MutableVoxelShape) return aabb == other.aabb
|
|
||||||
TODO("Can not compare $this with $other")
|
TODO("Can not compare $this with $other")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -177,7 +177,7 @@ class WorldEntities : Iterable<Entity> {
|
|||||||
}
|
}
|
||||||
val aabb = entity.physics.aabb
|
val aabb = entity.physics.aabb
|
||||||
|
|
||||||
if (shape.intersect(aabb)) {
|
if (shape.intersects(aabb)) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -60,6 +60,7 @@ class WorldIterator(
|
|||||||
if (this.chunk !== chunk) {
|
if (this.chunk !== chunk) {
|
||||||
this.chunk = chunk
|
this.chunk = chunk
|
||||||
}
|
}
|
||||||
|
// TODO: some fast skip? (if section is empty, can not be in section or chunk is null)
|
||||||
|
|
||||||
val state = chunk[position.inChunkPosition] ?: continue
|
val state = chunk[position.inChunkPosition] ?: continue
|
||||||
|
|
||||||
@ -116,7 +117,7 @@ class WorldIterator(
|
|||||||
if (predicate != null && !predicate.invoke(state)) continue
|
if (predicate != null && !predicate.invoke(state)) continue
|
||||||
|
|
||||||
val shape = state.block.getCollisionShape(world.session, context, position, state, null) ?: continue
|
val shape = state.block.getCollisionShape(world.session, context, position, state, null) ?: continue
|
||||||
if ((shape + position).intersect(aabb)) {
|
if ((shape + position).intersects(aabb)) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
|
|
||||||
package de.bixilon.minosoft.data.world.positions
|
package de.bixilon.minosoft.data.world.positions
|
||||||
|
|
||||||
|
import de.bixilon.minosoft.data.Axes
|
||||||
import de.bixilon.minosoft.data.direction.Directions
|
import de.bixilon.minosoft.data.direction.Directions
|
||||||
import de.bixilon.minosoft.data.text.formatting.TextFormattable
|
import de.bixilon.minosoft.data.text.formatting.TextFormattable
|
||||||
import de.bixilon.minosoft.data.world.positions.BlockPositionUtil.assertPosition
|
import de.bixilon.minosoft.data.world.positions.BlockPositionUtil.assertPosition
|
||||||
@ -102,6 +103,12 @@ value class BlockPosition(
|
|||||||
return modifyZ(-Z * 1)
|
return modifyZ(-Z * 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
operator fun get(axis: Axes) = when (axis) {
|
||||||
|
Axes.X -> x
|
||||||
|
Axes.Y -> y
|
||||||
|
Axes.Z -> z
|
||||||
|
}
|
||||||
|
|
||||||
inline fun with(x: Int = this.x, y: Int = this.y, z: Int = this.z) = BlockPosition(x, y, z)
|
inline fun with(x: Int = this.x, y: Int = this.y, z: Int = this.z) = BlockPosition(x, y, z)
|
||||||
|
|
||||||
inline operator fun plus(value: Int) = BlockPosition(this.x + value, this.y + value, this.z + value)
|
inline operator fun plus(value: Int) = BlockPosition(this.x + value, this.y + value, this.z + value)
|
||||||
|
@ -44,7 +44,7 @@ class WallOverlay(context: RenderContext) : SimpleOverlay(context) {
|
|||||||
}
|
}
|
||||||
val camera = context.session.camera.entity
|
val camera = context.session.camera.entity
|
||||||
val shape = blockState.block.getCollisionShape(context.session, EntityCollisionContext(camera), position, blockState, null) ?: return false // TODO: block entity
|
val shape = blockState.block.getCollisionShape(context.session, EntityCollisionContext(camera), position, blockState, null) ?: return false // TODO: block entity
|
||||||
if (!shape.intersect(player.physics.aabb)) {
|
if (!shape.intersects(player.physics.aabb)) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
|
@ -20,6 +20,7 @@ import de.bixilon.minosoft.data.physics.PhysicsEntity
|
|||||||
import de.bixilon.minosoft.data.registries.blocks.shapes.collision.context.ParticleCollisionContext
|
import de.bixilon.minosoft.data.registries.blocks.shapes.collision.context.ParticleCollisionContext
|
||||||
import de.bixilon.minosoft.data.registries.particle.data.ParticleData
|
import de.bixilon.minosoft.data.registries.particle.data.ParticleData
|
||||||
import de.bixilon.minosoft.data.registries.shapes.aabb.AABB
|
import de.bixilon.minosoft.data.registries.shapes.aabb.AABB
|
||||||
|
import de.bixilon.minosoft.data.registries.shapes.collision.CollisionShape
|
||||||
import de.bixilon.minosoft.data.world.chunk.chunk.Chunk
|
import de.bixilon.minosoft.data.world.chunk.chunk.Chunk
|
||||||
import de.bixilon.minosoft.gui.rendering.particle.ParticleFactory
|
import de.bixilon.minosoft.gui.rendering.particle.ParticleFactory
|
||||||
import de.bixilon.minosoft.gui.rendering.particle.ParticleMesh
|
import de.bixilon.minosoft.gui.rendering.particle.ParticleMesh
|
||||||
@ -28,7 +29,6 @@ import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3Util.EMPTY
|
|||||||
import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3dUtil.EMPTY
|
import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3dUtil.EMPTY
|
||||||
import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3dUtil.blockPosition
|
import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3dUtil.blockPosition
|
||||||
import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3dUtil.interpolateLinear
|
import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3dUtil.interpolateLinear
|
||||||
import de.bixilon.minosoft.physics.parts.CollisionMovementPhysics.collectCollisions
|
|
||||||
import de.bixilon.minosoft.physics.parts.CollisionMovementPhysics.collide
|
import de.bixilon.minosoft.physics.parts.CollisionMovementPhysics.collide
|
||||||
import de.bixilon.minosoft.protocol.network.session.play.PlaySession
|
import de.bixilon.minosoft.protocol.network.session.play.PlaySession
|
||||||
import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition
|
import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition
|
||||||
@ -138,7 +138,7 @@ abstract class Particle(
|
|||||||
private fun collide(movement: Vec3d): Vec3d {
|
private fun collide(movement: Vec3d): Vec3d {
|
||||||
val aabb = aabb + movement
|
val aabb = aabb + movement
|
||||||
val context = ParticleCollisionContext(this)
|
val context = ParticleCollisionContext(this)
|
||||||
val collisions = session.world.collectCollisions(context, movement, aabb, getChunk())
|
val collisions = CollisionShape(session.world, context, aabb, movement, getChunk())
|
||||||
val adjusted = collide(movement, aabb, collisions)
|
val adjusted = collide(movement, aabb, collisions)
|
||||||
if (adjusted.y != movement.y) {
|
if (adjusted.y != movement.y) {
|
||||||
onGround = true
|
onGround = true
|
||||||
|
@ -108,7 +108,9 @@ class LocalPlayerPhysics(entity: LocalPlayerEntity) : PlayerPhysics<LocalPlayerE
|
|||||||
val aabb = aabb
|
val aabb = aabb
|
||||||
val offset = AABB(position.x + 0.0, aabb.min.y, position.z + 0.0, position.x + 1.0, aabb.max.y, position.z + 1.0).shrink(1.0E-7)
|
val offset = AABB(position.x + 0.0, aabb.min.y, position.z + 0.0, position.x + 1.0, aabb.max.y, position.z + 1.0).shrink(1.0E-7)
|
||||||
val collisions = collectCollisions(Vec3d.EMPTY, offset, predicate = predicate)
|
val collisions = collectCollisions(Vec3d.EMPTY, offset, predicate = predicate)
|
||||||
return collisions.intersect(aabb)
|
val intersects = collisions.intersects(aabb)
|
||||||
|
collisions.free()
|
||||||
|
return intersects
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun shouldSprint(): Boolean {
|
private fun shouldSprint(): Boolean {
|
||||||
|
@ -17,59 +17,19 @@ import de.bixilon.kotlinglm.vec3.Vec3d
|
|||||||
import de.bixilon.kotlinglm.vec3.swizzle.xz
|
import de.bixilon.kotlinglm.vec3.swizzle.xz
|
||||||
import de.bixilon.minosoft.data.Axes
|
import de.bixilon.minosoft.data.Axes
|
||||||
import de.bixilon.minosoft.data.registries.blocks.shapes.collision.CollisionPredicate
|
import de.bixilon.minosoft.data.registries.blocks.shapes.collision.CollisionPredicate
|
||||||
import de.bixilon.minosoft.data.registries.blocks.shapes.collision.context.CollisionContext
|
|
||||||
import de.bixilon.minosoft.data.registries.blocks.shapes.collision.context.EntityCollisionContext
|
import de.bixilon.minosoft.data.registries.blocks.shapes.collision.context.EntityCollisionContext
|
||||||
import de.bixilon.minosoft.data.registries.blocks.types.entity.BlockWithEntity
|
|
||||||
import de.bixilon.minosoft.data.registries.blocks.types.properties.shape.collision.CollidableBlock
|
|
||||||
import de.bixilon.minosoft.data.registries.blocks.types.properties.shape.collision.fixed.FixedCollidable
|
|
||||||
import de.bixilon.minosoft.data.registries.shapes.aabb.AABB
|
import de.bixilon.minosoft.data.registries.shapes.aabb.AABB
|
||||||
|
import de.bixilon.minosoft.data.registries.shapes.collision.CollisionShape
|
||||||
import de.bixilon.minosoft.data.registries.shapes.voxel.AbstractVoxelShape
|
import de.bixilon.minosoft.data.registries.shapes.voxel.AbstractVoxelShape
|
||||||
import de.bixilon.minosoft.data.registries.shapes.voxel.VoxelShape
|
import de.bixilon.minosoft.data.world.positions.BlockPosition
|
||||||
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.gui.rendering.util.vec.vec3.Vec3dUtil.EMPTY
|
import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3dUtil.EMPTY
|
||||||
import de.bixilon.minosoft.physics.entities.EntityPhysics
|
import de.bixilon.minosoft.physics.entities.EntityPhysics
|
||||||
import kotlin.math.abs
|
import kotlin.math.abs
|
||||||
|
|
||||||
object CollisionMovementPhysics {
|
object CollisionMovementPhysics {
|
||||||
|
|
||||||
fun World.collectCollisions(context: CollisionContext, movement: Vec3d, aabb: AABB, chunk: Chunk?, predicate: CollisionPredicate? = null): VoxelShape {
|
fun EntityPhysics<*>.collectCollisions(movement: Vec3d, aabb: AABB, predicate: CollisionPredicate? = null): CollisionShape {
|
||||||
val shapes: ArrayList<AABB> = ArrayList()
|
return CollisionShape(this.entity.session.world, EntityCollisionContext(entity, this, aabb), aabb, movement, positionInfo.chunk, predicate)
|
||||||
// TODO: add entity collisions (boat, shulker)
|
|
||||||
// TODO: add world border collision shape
|
|
||||||
|
|
||||||
|
|
||||||
for ((position, state, chunk) in WorldIterator(aabb.extend(movement).grow(1.0).positions(), this, chunk)) {
|
|
||||||
if (state.block !is CollidableBlock) continue
|
|
||||||
|
|
||||||
if (predicate != null && !predicate.invoke(state)) continue
|
|
||||||
// TODO: filter blocks (e.g. moving piston), whatever that means
|
|
||||||
|
|
||||||
var shape = when (state.block) {
|
|
||||||
is FixedCollidable -> state.block.getCollisionShape(state)
|
|
||||||
is BlockWithEntity<*> -> {
|
|
||||||
|
|
||||||
state.block.getCollisionShape(session, context, position, state, chunk.getBlockEntity(position.inChunkPosition))
|
|
||||||
}
|
|
||||||
|
|
||||||
else -> {
|
|
||||||
state.block.getCollisionShape(session, context, position, state, null)
|
|
||||||
}
|
|
||||||
} ?: continue
|
|
||||||
shape += position
|
|
||||||
|
|
||||||
if (position in aabb && shape.intersect(aabb)) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
shapes += shape
|
|
||||||
}
|
|
||||||
|
|
||||||
return VoxelShape(shapes)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun EntityPhysics<*>.collectCollisions(movement: Vec3d, aabb: AABB, predicate: CollisionPredicate? = null): VoxelShape {
|
|
||||||
return this.entity.session.world.collectCollisions(EntityCollisionContext(entity, this, aabb), movement, aabb, positionInfo.chunk, predicate)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun checkMovement(axis: Axes, originalValue: Double, offsetAABB: Boolean, aabb: AABB, collisions: AbstractVoxelShape): Double {
|
private fun checkMovement(axis: Axes, originalValue: Double, offsetAABB: Boolean, aabb: AABB, collisions: AbstractVoxelShape): Double {
|
||||||
@ -114,13 +74,19 @@ object CollisionMovementPhysics {
|
|||||||
|
|
||||||
fun EntityPhysics<*>.collide(movement: Vec3d): Vec3d {
|
fun EntityPhysics<*>.collide(movement: Vec3d): Vec3d {
|
||||||
val aabb = aabb
|
val aabb = aabb
|
||||||
val collisions = collectCollisions(movement, aabb)
|
if (aabb.min.y <= BlockPosition.MIN_Y || aabb.max.y >= BlockPosition.MAX_Y) return movement // TODO: also check movement
|
||||||
val collision = collide(movement, aabb, collisions)
|
|
||||||
if (stepHeight <= 0.0) {
|
|
||||||
return collision
|
|
||||||
}
|
|
||||||
|
|
||||||
return collideStepping(movement, collision, collisions)
|
val collisions = collectCollisions(movement, aabb)
|
||||||
|
try {
|
||||||
|
val collision = collide(movement, aabb, collisions)
|
||||||
|
if (stepHeight <= 0.0) {
|
||||||
|
return collision
|
||||||
|
}
|
||||||
|
|
||||||
|
return collideStepping(movement, collision, collisions)
|
||||||
|
} finally {
|
||||||
|
collisions.free()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun EntityPhysics<*>.collideStepping(movement: Vec3d, collision: Vec3d, collisions: AbstractVoxelShape): Vec3d {
|
private fun EntityPhysics<*>.collideStepping(movement: Vec3d, collision: Vec3d, collisions: AbstractVoxelShape): Vec3d {
|
||||||
|
@ -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.
|
||||||
*
|
*
|
||||||
@ -33,7 +33,7 @@ internal class AABBTest {
|
|||||||
val a = AABB(Vec3d(5.0, 0.0, 7.0), Vec3d(6.0, 1.0, 8.0))
|
val a = AABB(Vec3d(5.0, 0.0, 7.0), Vec3d(6.0, 1.0, 8.0))
|
||||||
val b = AABB(Vec3d(5.7, 1.0, 6.3), Vec3d(6.3, 3, 6.9))
|
val b = AABB(Vec3d(5.7, 1.0, 6.3), Vec3d(6.3, 3, 6.9))
|
||||||
|
|
||||||
assertEquals(1239312.0, a.calculateMaxOffset(b, 1239312.0, Axes.Z))
|
assertEquals(1239312.0, a.calculateMaxDistance(b, 1239312.0, Axes.Z))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -41,7 +41,7 @@ internal class AABBTest {
|
|||||||
val a = AABB(Vec3d(5.0, 0.0, 7.0), Vec3d(6.0, 1.0, 8.0))
|
val a = AABB(Vec3d(5.0, 0.0, 7.0), Vec3d(6.0, 1.0, 8.0))
|
||||||
val b = AABB(Vec3d(5.699999988079071, 0.5358406250445555, 6.373910529638632), Vec3d(6.300000011920929, 2.3358405773608397, 6.97391055348049))
|
val b = AABB(Vec3d(5.699999988079071, 0.5358406250445555, 6.373910529638632), Vec3d(6.300000011920929, 2.3358405773608397, 6.97391055348049))
|
||||||
|
|
||||||
assertNotEquals(0.1, a.calculateMaxOffset(b, 0.1, Axes.Z))
|
assertNotEquals(0.1, a.calculateMaxDistance(b, 0.1, Axes.Z))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -49,7 +49,7 @@ internal class AABBTest {
|
|||||||
val a = AABB(Vec3d(5.0, 0.0, 6.0), Vec3d(5.8, 1.0, 7.0))
|
val a = AABB(Vec3d(5.0, 0.0, 6.0), Vec3d(5.8, 1.0, 7.0))
|
||||||
val b = AABB(Vec3d(5.7, 1.0, 6.0), Vec3d(6.3, 2.8, 6.6))
|
val b = AABB(Vec3d(5.7, 1.0, 6.0), Vec3d(6.3, 2.8, 6.6))
|
||||||
|
|
||||||
assertEquals(0.0, a.calculateMaxOffset(b, -0.0784000015258789, Axes.Y))
|
assertEquals(0.0, a.calculateMaxDistance(b, -0.0784000015258789, Axes.Y))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -57,7 +57,7 @@ internal class AABBTest {
|
|||||||
val a = AABB(Vec3d(5.0, 0.0, 6.0), Vec3d(5.8, 1.0, 7.0))
|
val a = AABB(Vec3d(5.0, 0.0, 6.0), Vec3d(5.8, 1.0, 7.0))
|
||||||
val b = AABB(Vec3d(5.0, 1.0, 6.0), Vec3d(5.8, 2.8, 6.6))
|
val b = AABB(Vec3d(5.0, 1.0, 6.0), Vec3d(5.8, 2.8, 6.6))
|
||||||
|
|
||||||
assertEquals(0.0, a.calculateMaxOffset(b, -0.0784000015258789, Axes.Y))
|
assertEquals(0.0, a.calculateMaxDistance(b, -0.0784000015258789, Axes.Y))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -65,7 +65,7 @@ internal class AABBTest {
|
|||||||
val a = AABB(Vec3d(5.0, 0.0, 6.0), Vec3d(5.8, 1.0, 7.0))
|
val a = AABB(Vec3d(5.0, 0.0, 6.0), Vec3d(5.8, 1.0, 7.0))
|
||||||
val b = AABB(Vec3d(5.1, 1.0, 5.9), Vec3d(5.5, 2.8, 7.1))
|
val b = AABB(Vec3d(5.1, 1.0, 5.9), Vec3d(5.5, 2.8, 7.1))
|
||||||
|
|
||||||
assertEquals(0.0, a.calculateMaxOffset(b, -0.0784000015258789, Axes.Y))
|
assertEquals(0.0, a.calculateMaxDistance(b, -0.0784000015258789, Axes.Y))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user