diff --git a/src/main/java/net/minestom/server/entity/EntityProjectile.java b/src/main/java/net/minestom/server/entity/EntityProjectile.java index 65fcbca59..82685ae08 100644 --- a/src/main/java/net/minestom/server/entity/EntityProjectile.java +++ b/src/main/java/net/minestom/server/entity/EntityProjectile.java @@ -63,8 +63,10 @@ public class EntityProjectile extends Entity { double dx = to.x() - from.x(); double dy = to.y() - from.y(); double dz = to.z() - from.z(); - final double xzLength = Math.sqrt(dx * dx + dz * dz); - dy += xzLength * 0.20000000298023224D; + if (!hasNoGravity()) { + final double xzLength = Math.sqrt(dx * dx + dz * dz); + dy += xzLength * 0.20000000298023224D; + } final double length = Math.sqrt(dx * dx + dy * dy + dz * dz); dx /= length; diff --git a/src/test/java/net/minestom/server/entity/EntityProjectileIntegrationTest.java b/src/test/java/net/minestom/server/entity/EntityProjectileIntegrationTest.java new file mode 100644 index 000000000..fc6454d77 --- /dev/null +++ b/src/test/java/net/minestom/server/entity/EntityProjectileIntegrationTest.java @@ -0,0 +1,74 @@ +package net.minestom.server.entity; + +import net.minestom.server.api.Env; +import net.minestom.server.api.EnvTest; +import net.minestom.server.coordinate.Pos; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +@EnvTest +public class EntityProjectileIntegrationTest { + @Test + public void gravityVelocity(Env env) { + var instance = env.createFlatInstance(); + var shooter = new EntityCreature(EntityType.SKELETON); + shooter.setInstance(instance, new Pos(0, 42, 0)).join(); + var projectile = new EntityProjectile(shooter, EntityType.ARROW); + var from = new Pos(0, 42, 0).add(0, + shooter.getEyeHeight(), shooter.getPosition().direction().z()); + var target = from.add(0, 0, 10); + projectile.setInstance(instance, from).join(); + projectile.shoot(target, 1, 0); + + var before = projectile.getPosition(); // at start + var after = projectile.getPosition(); // now - 1 tick, closest to target + var smallestDistance = 1e6; + while (true) { + final var distance = projectile.getPosition().distanceSquared(target); + if (distance <= smallestDistance) smallestDistance = distance; + else break; + + after = projectile.getPosition(); + env.tick(); + } + + // Ensure the position is correct. + // x doesn't change + // Big delta because ticks aren't very accurate + assertEquals(before.x(), after.x()); + assertEquals(target.y(), after.y(), 0.6); + assertEquals(target.z(), after.z(), 0.6); + } + + @Test + public void noGravityVelocity(Env env) { + var instance = env.createFlatInstance(); + var shooter = new EntityCreature(EntityType.SKELETON); + shooter.setInstance(instance, new Pos(0, 42, 0)).join(); + var projectile = new EntityProjectile(shooter, EntityType.ARROW); + var from = new Pos(0, 42, 0).add(0, + shooter.getEyeHeight(), shooter.getPosition().direction().z()); + var target = from.add(0, 0, 10); + projectile.setNoGravity(true); + projectile.setInstance(instance, from).join(); + projectile.shoot(target, 1, 0); + + var before = projectile.getPosition(); // at start + var after = projectile.getPosition(); // now - 1 tick, closest to target + var smallestDistance = 1e6; + while (true) { + final var distance = projectile.getPosition().distanceSquared(target); + if (distance <= smallestDistance) smallestDistance = distance; + else break; + + after = projectile.getPosition(); + env.tick(); + } + + // x and y don't change (no gravity) and z changes by Σz velocity. + assertEquals(before.x(), after.x()); + assertEquals(before.y(), after.y()); + assertEquals(target.z(), after.z(), 0.05); + } +}