From 17ef1c2f57d558b46fa8257bf386f4f4faba240e Mon Sep 17 00:00:00 2001 From: Arektor Date: Fri, 7 Oct 2022 17:19:29 +0200 Subject: [PATCH] Reduce velocity update rate (#1426) --- .../net/minestom/server/entity/Entity.java | 17 +++++++++--- .../entity/EntityVelocityIntegrationTest.java | 27 +++++++++++++++++++ 2 files changed, 41 insertions(+), 3 deletions(-) diff --git a/src/main/java/net/minestom/server/entity/Entity.java b/src/main/java/net/minestom/server/entity/Entity.java index 61959a508..91fab8c45 100644 --- a/src/main/java/net/minestom/server/entity/Entity.java +++ b/src/main/java/net/minestom/server/entity/Entity.java @@ -86,6 +86,8 @@ import java.util.function.UnaryOperator; public class Entity implements Viewable, Tickable, Schedulable, Snapshotable, EventHandler, Taggable, PermissionHandler, HoverEventSource, Sound.Emitter { + private static final int VELOCITY_UPDATE_INTERVAL = 1; + private static final Int2ObjectSyncMap ENTITY_BY_ID = Int2ObjectSyncMap.hashmap(); private static final Map ENTITY_BY_UUID = new ConcurrentHashMap<>(); private static final AtomicInteger LAST_ENTITY_ID = new AtomicInteger(); @@ -106,6 +108,7 @@ public class Entity implements Viewable, Tickable, Schedulable, Snapshotable, Ev // Velocity protected Vec velocity = Vec.ZERO; // Movement in block per second + protected boolean lastVelocityWasZero = true; protected boolean hasPhysics = true; /** @@ -593,7 +596,12 @@ public class Entity implements Viewable, Tickable, Schedulable, Snapshotable, Ev -gravityAcceleration * tps * (1 - gravityDragPerTick), 0 ); - if (!isPlayer) sendPacketToViewers(getVelocityPacket()); + if (this.ticks % VELOCITY_UPDATE_INTERVAL == 0) { + if (!isPlayer && !this.lastVelocityWasZero) { + sendPacketToViewers(getVelocityPacket()); + this.lastVelocityWasZero = !hasVelocity; + } + } return; } } @@ -620,8 +628,11 @@ public class Entity implements Viewable, Tickable, Schedulable, Snapshotable, Ev updateVelocity(wasOnGround, flying, positionBeforeMove, newVelocity); } // Verify if velocity packet has to be sent - if (!isPlayer && (hasVelocity || gravityTickCount > 0)) { - sendPacketToViewers(getVelocityPacket()); + if (this.ticks % VELOCITY_UPDATE_INTERVAL == 0) { + if (!isPlayer && (hasVelocity || !lastVelocityWasZero)) { + sendPacketToViewers(getVelocityPacket()); + this.lastVelocityWasZero = !hasVelocity; + } } } diff --git a/src/test/java/net/minestom/server/entity/EntityVelocityIntegrationTest.java b/src/test/java/net/minestom/server/entity/EntityVelocityIntegrationTest.java index b68bf6b29..3d7c2eb77 100644 --- a/src/test/java/net/minestom/server/entity/EntityVelocityIntegrationTest.java +++ b/src/test/java/net/minestom/server/entity/EntityVelocityIntegrationTest.java @@ -9,6 +9,9 @@ import net.minestom.server.network.packet.server.play.EntityVelocityPacket; import net.minestom.server.utils.chunk.ChunkUtils; import org.junit.jupiter.api.Test; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.BooleanSupplier; + import static org.junit.jupiter.api.Assertions.*; @EnvTest @@ -160,6 +163,30 @@ public class EntityVelocityIntegrationTest { assertFalse(entity.hasVelocity()); } + @Test + public void countVelocityPackets(Env env) { + final int VELOCITY_UPDATE_INTERVAL = 1; + + var instance = env.createFlatInstance(); + var viewerConnection = env.createConnection(); + viewerConnection.connect(instance, new Pos(1, 40, 1)).join(); + var entity = new Entity(EntityType.ZOMBIE); + entity.setInstance(instance, new Pos(0,40,0)).join(); + + AtomicInteger i = new AtomicInteger(); + BooleanSupplier tickLoopCondition = () -> i.getAndIncrement() < Math.max(VELOCITY_UPDATE_INTERVAL, 1); + + var tracker = viewerConnection.trackIncoming(EntityVelocityPacket.class); + env.tickWhile(tickLoopCondition, null); + tracker.assertEmpty(); // Verify no updates are sent while the entity is not moving + + entity.setVelocity(new Vec(0, 5, 0)); + tracker = viewerConnection.trackIncoming(EntityVelocityPacket.class); + i.set(0); + env.tickWhile(tickLoopCondition, null); + tracker.assertCount(1); // Verify the update is only sent once + } + private void testMovement(Env env, Entity entity, Vec... sample) { final double epsilon = 0.003; for (Vec vec : sample) {