diff --git a/src/main/java/net/minestom/server/collision/RayUtils.java b/src/main/java/net/minestom/server/collision/RayUtils.java index 3388d13a2..812a76128 100644 --- a/src/main/java/net/minestom/server/collision/RayUtils.java +++ b/src/main/java/net/minestom/server/collision/RayUtils.java @@ -15,7 +15,7 @@ final class RayUtils { * @return true if an intersection between the ray and the bounding box was found */ public static boolean BoundingBoxIntersectionCheck(BoundingBox moving, Point rayStart, Point rayDirection, BoundingBox collidableStatic, Point staticCollidableOffset, SweepResult finalResult) { - Point bbCentre = new Vec(moving.minX() + moving.width() / 2, moving.minY() + moving.height() / 2 + Vec.EPSILON, moving.minZ() + moving.depth() / 2); + Point bbCentre = new Vec(moving.minX() + moving.width() / 2, moving.minY() + moving.height() / 2, moving.minZ() + moving.depth() / 2); Point rayCentre = rayStart.add(bbCentre); // Translate bounding box @@ -36,7 +36,7 @@ final class RayUtils { // Intersect X // Left side of bounding box if (rayDirection.x() > 0) { - double xFac = bbOffMin.x() / rayDirection.x(); + double xFac = epsilon(bbOffMin.x() / rayDirection.x()); if (xFac < percentage) { double yix = rayDirection.y() * xFac + rayCentre.y(); double zix = rayDirection.z() * xFac + rayCentre.z(); @@ -56,7 +56,7 @@ final class RayUtils { } // Right side of bounding box if (rayDirection.x() < 0) { - double xFac = bbOffMax.x() / rayDirection.x(); + double xFac = epsilon(bbOffMax.x() / rayDirection.x()); if (xFac < percentage) { double yix = rayDirection.y() * xFac + rayCentre.y(); double zix = rayDirection.z() * xFac + rayCentre.z(); @@ -76,7 +76,7 @@ final class RayUtils { // Intersect Z if (rayDirection.z() > 0) { - double zFac = bbOffMin.z() / rayDirection.z(); + double zFac = epsilon(bbOffMin.z() / rayDirection.z()); if (zFac < percentage) { double xiz = rayDirection.x() * zFac + rayCentre.x(); double yiz = rayDirection.y() * zFac + rayCentre.y(); @@ -94,7 +94,7 @@ final class RayUtils { } } if (rayDirection.z() < 0) { - double zFac = bbOffMax.z() / rayDirection.z(); + double zFac = epsilon(bbOffMax.z() / rayDirection.z()); if (zFac < percentage) { double xiz = rayDirection.x() * zFac + rayCentre.x(); double yiz = rayDirection.y() * zFac + rayCentre.y(); @@ -114,7 +114,7 @@ final class RayUtils { // Intersect Y if (rayDirection.y() > 0) { - double yFac = bbOffMin.y() / rayDirection.y(); + double yFac = epsilon(bbOffMin.y() / rayDirection.y()); if (yFac < percentage) { double xiy = rayDirection.x() * yFac + rayCentre.x(); double ziy = rayDirection.z() * yFac + rayCentre.z(); @@ -133,7 +133,7 @@ final class RayUtils { } if (rayDirection.y() < 0) { - double yFac = bbOffMax.y() / rayDirection.y(); + double yFac = epsilon(bbOffMax.y() / rayDirection.y()); if (yFac < percentage) { double xiy = rayDirection.x() * yFac + rayCentre.x(); double ziy = rayDirection.z() * yFac + rayCentre.z(); @@ -167,6 +167,10 @@ final class RayUtils { return isHit; } + private static double epsilon(double value) { + return Math.abs(value) < Vec.EPSILON ? 0 : value; + } + public static boolean BoundingBoxRayIntersectionCheck(Vec start, Vec direction, BoundingBox boundingBox, Pos position) { return BoundingBoxIntersectionCheck(BoundingBox.ZERO, start, direction, boundingBox, position, new SweepResult(Double.MAX_VALUE, 0, 0, 0, null)); } diff --git a/src/test/java/net/minestom/server/collision/EntityBlockPhysicsIntegrationTest.java b/src/test/java/net/minestom/server/collision/EntityBlockPhysicsIntegrationTest.java index 394b5b945..01d51040a 100644 --- a/src/test/java/net/minestom/server/collision/EntityBlockPhysicsIntegrationTest.java +++ b/src/test/java/net/minestom/server/collision/EntityBlockPhysicsIntegrationTest.java @@ -1029,4 +1029,34 @@ public class EntityBlockPhysicsIntegrationTest { assertEqualsPoint(new Pos(0, 40, 0.7), res.newPosition()); } + + @Test + public void entityBlockPositionTestSlightlyAbove(Env env) { + var instance = env.createFlatInstance(); + instance.setBlock(0, 42, 0, Block.STONE); + + var entity = new Entity(EntityType.ZOMBIE); + entity.setInstance(instance, new Pos(0, 43.00001, 0)); + + var deltaPos = new Vec(0.0, -10, 0.0); + var physicsResult = CollisionUtils.handlePhysics(entity, deltaPos, null); + + var newPos = physicsResult.newPosition(); + assertEquals(43, newPos.blockY()); + } + + @Test + public void entityBlockPositionTestFarAbove(Env env) { + var instance = env.createFlatInstance(); + instance.setBlock(0, 42, 0, Block.STONE); + + var entity = new Entity(EntityType.ZOMBIE); + entity.setInstance(instance, new Pos(0, 43.5, 0)); + + var deltaPos = new Vec(0.0, -10, 0.0); + var physicsResult = CollisionUtils.handlePhysics(entity, deltaPos, null); + + var newPos = physicsResult.newPosition(); + assertEquals(43, newPos.blockY()); + } } \ No newline at end of file