diff --git a/src/main/java/net/minestom/server/entity/Entity.java b/src/main/java/net/minestom/server/entity/Entity.java index 808396278..7a6b75d04 100644 --- a/src/main/java/net/minestom/server/entity/Entity.java +++ b/src/main/java/net/minestom/server/entity/Entity.java @@ -581,11 +581,11 @@ public class Entity implements Viewable, Tickable, Schedulable, Snapshotable, Ev // World border collision final Pos finalVelocityPosition = CollisionUtils.applyWorldBorder(instance, position, newPosition); final boolean positionChanged = !finalVelocityPosition.samePoint(position); - final boolean flying = this instanceof Player player && player.isFlying(); + final boolean isPlayer = this instanceof Player; + final boolean flying = isPlayer && ((Player) this).isFlying(); if (!positionChanged) { if (flying) { this.velocity = Vec.ZERO; - sendPacketToViewers(getVelocityPacket()); return; } else if (hasVelocity || newVelocity.isZero()) { this.velocity = noGravity ? Vec.ZERO : new Vec( @@ -593,7 +593,7 @@ public class Entity implements Viewable, Tickable, Schedulable, Snapshotable, Ev -gravityAcceleration * tps * (1 - gravityDragPerTick), 0 ); - sendPacketToViewers(getVelocityPacket()); + if (!isPlayer) sendPacketToViewers(getVelocityPacket()); return; } } @@ -620,7 +620,7 @@ public class Entity implements Viewable, Tickable, Schedulable, Snapshotable, Ev updateVelocity(wasOnGround, flying, positionBeforeMove, newVelocity); } // Verify if velocity packet has to be sent - if (!(this instanceof Player) && (hasVelocity || gravityTickCount > 0)) { + if (!isPlayer && (hasVelocity || gravityTickCount > 0)) { sendPacketToViewers(getVelocityPacket()); } } diff --git a/src/test/java/net/minestom/server/entity/EntityVelocityIntegrationTest.java b/src/test/java/net/minestom/server/entity/EntityVelocityIntegrationTest.java index 4606c9467..f175ca642 100644 --- a/src/test/java/net/minestom/server/entity/EntityVelocityIntegrationTest.java +++ b/src/test/java/net/minestom/server/entity/EntityVelocityIntegrationTest.java @@ -5,6 +5,7 @@ import net.minestom.server.api.EnvTest; import net.minestom.server.coordinate.Pos; import net.minestom.server.coordinate.Vec; import net.minestom.server.instance.Instance; +import net.minestom.server.network.packet.server.play.EntityVelocityPacket; import net.minestom.server.utils.chunk.ChunkUtils; import org.junit.jupiter.api.Test; @@ -21,16 +22,14 @@ public class EntityVelocityIntegrationTest { entity.setInstance(instance, new Pos(0, 42, 0)).join(); env.tick(); // Ensure velocity downwards is present - testMovement(env, entity, new Vec[] { - new Vec(0.0, 42.0, 0.0), + testMovement(env, entity, new Vec(0.0, 42.0, 0.0), new Vec(0.0, 41.92159999847412, 0.0), new Vec(0.0, 41.76636799395752, 0.0), new Vec(0.0, 41.53584062504456, 0.0), new Vec(0.0, 41.231523797587016, 0.0), new Vec(0.0, 40.85489329934836, 0.0), new Vec(0.0, 40.40739540236494, 0.0), - new Vec(0.0, 40.0, 0.0) - }); + new Vec(0.0, 40.0, 0.0)); } @Test @@ -44,8 +43,7 @@ public class EntityVelocityIntegrationTest { env.tick(); // Ensures the entity is onGround entity.takeKnockback(0.4f, 0, -1); - testMovement(env, entity, new Vec[] { - new Vec(0.0, 40.0, 0.0), + testMovement(env, entity, new Vec(0.0, 40.0, 0.0), new Vec(0.0, 40.360800005197525, 0.4000000059604645), new Vec(0.0, 40.63598401564693, 0.6184000345826153), new Vec(0.0, 40.827264349610196, 0.8171440663565412), @@ -62,8 +60,7 @@ public class EntityVelocityIntegrationTest { new Vec(0.0, 40.0, 1.9757875252341128), new Vec(0.0, 40.0, 1.9840936051840241), new Vec(0.0, 40.0, 1.9886287253634418), - new Vec(0.0, 40.0, 1.9886287253634418), - }); + new Vec(0.0, 40.0, 1.9886287253634418)); } @Test @@ -80,8 +77,7 @@ public class EntityVelocityIntegrationTest { assertTrue(entity.hasVelocity()); - testMovement(env, entity, new Vec[] { - new Vec(0.0, 40.0, 0.0), + testMovement(env, entity, new Vec(0.0, 40.0, 0.0), new Vec(0.0, 40.4, 0.7000000029802322), new Vec(0.0, 40.71360000610351, 1.0822000490009787), new Vec(0.0, 40.94252801654052, 1.4300021009034531), @@ -99,8 +95,7 @@ public class EntityVelocityIntegrationTest { new Vec(0.0, 40.0, 3.5916417190562298), new Vec(0.0, 40.0, 3.6048691516168874), new Vec(0.0, 40.0, 3.6120913306338815), - new Vec(0.0, 40.0, 3.616034640835186) - }); + new Vec(0.0, 40.0, 3.616034640835186)); } @Test @@ -128,6 +123,20 @@ public class EntityVelocityIntegrationTest { assertEquals(player.getVelocity().y(), 0); } + @Test + public void flyingPlayerMovement(Env env) { + // Player movement should not send velocity packets as already client predicted + var instance = env.createFlatInstance(); + var player = env.createPlayer(instance, new Pos(0, 42, 0)); + player.setFlying(true); + var witness = env.createConnection(); + witness.connect(instance, new Pos(0, 42, 0)).join(); + + var tracker = witness.trackIncoming(EntityVelocityPacket.class); + env.tick(); // Process gravity velocity + tracker.assertEmpty(); + } + @Test public void testHasVelocity(Env env) { var instance = env.createFlatInstance(); @@ -151,7 +160,7 @@ public class EntityVelocityIntegrationTest { assertFalse(entity.hasVelocity()); } - private void testMovement(Env env, Entity entity, Vec[] sample) { + private void testMovement(Env env, Entity entity, Vec... sample) { final double epsilon = 0.003; for (Vec vec : sample) { assertEquals(vec.x(), entity.getPosition().x(), epsilon); @@ -162,7 +171,7 @@ public class EntityVelocityIntegrationTest { } private void loadChunks(Instance instance) { - ChunkUtils.optionalLoadAll(instance, new long[] { + ChunkUtils.optionalLoadAll(instance, new long[]{ ChunkUtils.getChunkIndex(-1, -1), ChunkUtils.getChunkIndex(-1, 0), ChunkUtils.getChunkIndex(-1, 1),