mirror of https://github.com/Minestom/Minestom.git
214 lines
8.4 KiB
Java
214 lines
8.4 KiB
Java
package net.minestom.server.entity;
|
|
|
|
import net.minestom.testing.Env;
|
|
import net.minestom.testing.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;
|
|
|
|
import java.util.concurrent.atomic.AtomicInteger;
|
|
import java.util.function.BooleanSupplier;
|
|
|
|
import static org.junit.jupiter.api.Assertions.*;
|
|
|
|
@EnvTest
|
|
public class EntityVelocityIntegrationTest {
|
|
@Test
|
|
public void gravity(Env env) {
|
|
var instance = env.createFlatInstance();
|
|
loadChunks(instance);
|
|
|
|
var entity = new Entity(EntityTypes.ZOMBIE);
|
|
entity.setInstance(instance, new Pos(0, 42, 0)).join();
|
|
env.tick(); // Ensure velocity downwards is present
|
|
|
|
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));
|
|
}
|
|
|
|
@Test
|
|
public void singleKnockback(Env env) {
|
|
var instance = env.createFlatInstance();
|
|
loadChunks(instance);
|
|
|
|
var entity = new Entity(EntityTypes.ZOMBIE);
|
|
entity.setInstance(instance, new Pos(0, 40, 0)).join();
|
|
env.tick();
|
|
env.tick(); // Ensures the entity is onGround
|
|
entity.takeKnockback(0.4f, 0, -1);
|
|
|
|
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),
|
|
new Vec(0.0, 40.9363190790167, 0.9980011404830835),
|
|
new Vec(0.0, 40.96479271438924, 1.1625810826814025),
|
|
new Vec(0.0, 40.914296876071546, 1.3123488343981535),
|
|
new Vec(0.0, 40.7864109520312, 1.4486374923882126),
|
|
new Vec(0.0, 40.58268274250654, 1.5726601747334787),
|
|
new Vec(0.0, 40.304629091760695, 1.685520818920295),
|
|
new Vec(0.0, 40.0, 1.7882240080901861),
|
|
new Vec(0.0, 40.0, 1.8816839129282854),
|
|
new Vec(0.0, 40.0, 1.9327130268970532),
|
|
new Vec(0.0, 40.0, 1.9605749263602332),
|
|
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));
|
|
}
|
|
|
|
@Test
|
|
public void doubleKnockback(Env env) {
|
|
var instance = env.createFlatInstance();
|
|
loadChunks(instance);
|
|
|
|
var entity = new Entity(EntityTypes.ZOMBIE);
|
|
entity.setInstance(instance, new Pos(0, 40, 0)).join();
|
|
env.tick();
|
|
env.tick(); // Ensures the entity is onGround
|
|
entity.takeKnockback(0.4f, 0, -1);
|
|
entity.takeKnockback(0.5f, 0, -1);
|
|
|
|
assertTrue(entity.hasVelocity());
|
|
|
|
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),
|
|
new Vec(0.0, 41.088477469609366, 1.7465019772561767),
|
|
new Vec(0.0, 41.153107934874726, 2.0345168730376946),
|
|
new Vec(0.0, 41.138045790541625, 2.2966104357523673),
|
|
new Vec(0.0, 41.04488488728202, 2.5351155846963964),
|
|
new Vec(0.0, 40.87518719878482, 2.7521552764905097),
|
|
new Vec(0.0, 40.630483459294965, 2.949661401715245),
|
|
new Vec(0.0, 40.312273788401676, 3.1293919808495585),
|
|
new Vec(0.0, 40.0, 3.292946812575406),
|
|
new Vec(0.0, 40.0, 3.441781713735323),
|
|
new Vec(0.0, 40.0, 3.523045579207649),
|
|
new Vec(0.0, 40.0, 3.56741565490924),
|
|
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));
|
|
}
|
|
|
|
@Test
|
|
public void flyingVelocity(Env env) {
|
|
var instance = env.createFlatInstance();
|
|
loadChunks(instance);
|
|
|
|
var player = env.createPlayer(instance, new Pos(0, 42, 0));
|
|
env.tick();
|
|
|
|
final double epsilon = 0.00001;
|
|
|
|
assertEquals(player.getVelocity().y(), -1.568, epsilon);
|
|
double previousVelocity = player.getVelocity().y();
|
|
|
|
player.setFlying(true);
|
|
env.tick();
|
|
|
|
// Every tick, the y velocity is multiplied by 0.6, and after 27 ticks it should be 0
|
|
for (int i = 0; i < 27; i++) {
|
|
assertEquals(player.getVelocity().y(), previousVelocity * 0.6, epsilon);
|
|
previousVelocity = player.getVelocity().y();
|
|
env.tick();
|
|
}
|
|
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();
|
|
loadChunks(instance);
|
|
|
|
var entity = new Entity(EntityType.ZOMBIE);
|
|
// Should be false because the new entity should have no velocity
|
|
assertFalse(entity.hasVelocity());
|
|
|
|
entity.setInstance(instance, new Pos(0, 41, 0)).join();
|
|
|
|
env.tick();
|
|
|
|
// Should be true: The entity is currently falling (in the air), so it does have a velocity.
|
|
// Only entities on the ground should ignore the default velocity.
|
|
assertTrue(entity.hasVelocity());
|
|
|
|
env.tick();
|
|
|
|
// Now that the entity is on the ground, it should no longer have a velocity.
|
|
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) {
|
|
assertEquals(vec.x(), entity.getPosition().x(), epsilon);
|
|
assertEquals(vec.y(), entity.getPosition().y(), epsilon);
|
|
assertEquals(vec.z(), entity.getPosition().z(), epsilon);
|
|
env.tick();
|
|
}
|
|
}
|
|
|
|
private void loadChunks(Instance instance) {
|
|
ChunkUtils.optionalLoadAll(instance, new long[]{
|
|
ChunkUtils.getChunkIndex(-1, -1),
|
|
ChunkUtils.getChunkIndex(-1, 0),
|
|
ChunkUtils.getChunkIndex(-1, 1),
|
|
ChunkUtils.getChunkIndex(0, -1),
|
|
ChunkUtils.getChunkIndex(0, 0),
|
|
ChunkUtils.getChunkIndex(0, 1),
|
|
ChunkUtils.getChunkIndex(1, -1),
|
|
ChunkUtils.getChunkIndex(1, 0),
|
|
ChunkUtils.getChunkIndex(1, 1),
|
|
}, null).join();
|
|
}
|
|
}
|