diff --git a/src/main/java/net/minestom/server/coordinate/Pos.java b/src/main/java/net/minestom/server/coordinate/Pos.java index 27e43b1e7..7d1c39556 100644 --- a/src/main/java/net/minestom/server/coordinate/Pos.java +++ b/src/main/java/net/minestom/server/coordinate/Pos.java @@ -2,6 +2,7 @@ package net.minestom.server.coordinate; import net.minestom.server.instance.block.BlockFace; import net.minestom.server.utils.MathUtils; +import net.minestom.server.utils.position.PositionUtils; import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; @@ -112,6 +113,14 @@ public record Pos(double x, double y, double z, float yaw, float pitch) implemen return new Pos(x, y, z, yaw, pitch); } + @Contract(pure = true) + public @NotNull Pos withLookAt(@NotNull Point point) { + if (samePoint(point)) return this; + final Vec delta = Vec.fromPoint(point.sub(this)).normalize(); + return withView(PositionUtils.getLookYaw(delta.x(), delta.z()), + PositionUtils.getLookPitch(delta.x(), delta.y(), delta.z())); + } + @Contract(pure = true) public @NotNull Pos withPitch(@NotNull DoubleUnaryOperator operator) { return withPitch((float) operator.applyAsDouble(pitch)); diff --git a/src/main/java/net/minestom/server/entity/Entity.java b/src/main/java/net/minestom/server/entity/Entity.java index 3a6bd4a2e..7645733ba 100644 --- a/src/main/java/net/minestom/server/entity/Entity.java +++ b/src/main/java/net/minestom/server/entity/Entity.java @@ -56,7 +56,6 @@ import net.minestom.server.utils.chunk.ChunkCache; import net.minestom.server.utils.chunk.ChunkUtils; import net.minestom.server.utils.entity.EntityUtils; import net.minestom.server.utils.player.PlayerUtils; -import net.minestom.server.utils.position.PositionUtils; import net.minestom.server.utils.time.Cooldown; import net.minestom.server.utils.time.TimeUnit; import net.minestom.server.utils.validate.Check; @@ -336,15 +335,8 @@ public class Entity implements Viewable, Tickable, Schedulable, Snapshotable, Ev * @param position the position to look at. */ public void lookAt(@NotNull Pos position) { - if (this.position.samePoint(position)) { - return; - } - - Vec delta = position.sub(getPosition()).asVec().normalize(); - setView( - PositionUtils.getLookYaw(delta.x(), delta.z()), - PositionUtils.getLookPitch(delta.x(), delta.y(), delta.z()) - ); + final Pos newPosition = this.position.withLookAt(position); + if (!newPosition.sameView(this.position)) setView(newPosition.yaw(), newPosition.pitch()); } /** diff --git a/src/test/java/net/minestom/server/coordinate/PosViewDirectionTest.java b/src/test/java/net/minestom/server/coordinate/PosViewDirectionTest.java new file mode 100644 index 000000000..e0ae029f6 --- /dev/null +++ b/src/test/java/net/minestom/server/coordinate/PosViewDirectionTest.java @@ -0,0 +1,45 @@ +package net.minestom.server.coordinate; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class PosViewDirectionTest { + private static final float EPSILON = 0.01f; + + @Test + public void withLookAtPos() { + Pos initialPosition = new Pos(0, 40, 0); + Pos position; + + // look at itself, direction should not change + position = initialPosition.withLookAt(initialPosition); + assertEquals(initialPosition.yaw(), position.yaw()); + assertEquals(initialPosition.pitch(), position.pitch()); + + position = initialPosition.withLookAt(new Pos(16, 40, 16)); + assertEquals(-45f, position.yaw()); + assertEquals(0f, position.pitch(), EPSILON); + + position = initialPosition.withLookAt(new Pos(-16, 40, 56)); + assertEquals(15.94f, position.yaw(), EPSILON); + assertEquals(0f, position.pitch(), EPSILON); + + position = initialPosition.withLookAt(new Pos(48, 36, 48)); + assertEquals(-45f, position.yaw(), EPSILON); + assertEquals(4.76f, position.pitch(), EPSILON); + + position = initialPosition.withLookAt(new Pos(48, 36, -17)); + assertEquals(-109.50f, position.yaw(), EPSILON); + // should have the same pitch as the previous position + assertEquals(4.76f, position.pitch(), EPSILON); + + position = initialPosition.withLookAt(new Pos(0, 87, 0)); + // looking from below, not checking the yaw + assertEquals(-90f, position.pitch(), EPSILON); + + position = initialPosition.withLookAt(new Pos(-25, 42, 4)); + assertEquals(80.90f, position.yaw(), EPSILON); + assertEquals(-4.57f, position.pitch(), EPSILON); + } +}