Minestom/src/test/java/net/minestom/server/collision/EntityProjectileCollisionIn...

154 lines
6.4 KiB
Java

package net.minestom.server.collision;
import net.minestom.server.MinecraftServer;
import net.minestom.testing.Env;
import net.minestom.testing.EnvTest;
import net.minestom.server.coordinate.Point;
import net.minestom.server.coordinate.Pos;
import net.minestom.server.coordinate.Vec;
import net.minestom.server.entity.Entity;
import net.minestom.server.entity.EntityProjectile;
import net.minestom.server.entity.EntityType;
import net.minestom.server.entity.LivingEntity;
import net.minestom.server.event.EventNode;
import net.minestom.server.event.entity.projectile.ProjectileCollideWithBlockEvent;
import net.minestom.server.event.entity.projectile.ProjectileCollideWithEntityEvent;
import net.minestom.server.event.entity.projectile.ProjectileUncollideEvent;
import net.minestom.server.instance.Instance;
import net.minestom.server.instance.block.Block;
import net.minestom.server.utils.time.TimeUnit;
import org.junit.jupiter.api.Test;
import java.util.concurrent.atomic.AtomicReference;
import static org.junit.jupiter.api.Assertions.*;
@EnvTest
public class EntityProjectileCollisionIntegrationTest {
@Test
public void blockShootAndBlockRemoval(Env env) {
final Instance instance = env.createFlatInstance();
instance.getWorldBorder().setDiameter(1000.0);
final Entity shooter = new Entity(EntityType.SKELETON);
shooter.setInstance(instance, new Pos(0, 40, 0)).join();
final EntityProjectile projectile = new EntityProjectile(shooter, EntityType.ARROW);
projectile.setInstance(instance, shooter.getPosition().withY(y -> y + shooter.getEyeHeight())).join();
final Point blockPosition = new Vec(5, 40, 0);
final Block block = Block.GRASS_BLOCK;
instance.setBlock(blockPosition, block);
projectile.shoot(blockPosition, 1, 0);
final var eventRef = new AtomicReference<ProjectileCollideWithBlockEvent>();
MinecraftServer.getGlobalEventHandler().addListener(ProjectileCollideWithBlockEvent.class, eventRef::set);
final long tick = TimeUnit.SERVER_TICK.getDuration().toMillis();
for (int i = 0; i < MinecraftServer.TICK_PER_SECOND; ++i) {
projectile.tick(i * tick);
}
var event = eventRef.get();
assertNotNull(event);
assertEquals(blockPosition, new Vec(event.getCollisionPosition().blockX(), event.getCollisionPosition().blockY(), event.getCollisionPosition().blockZ()));
assertEquals(block, event.getBlock());
final var eventRef2 = new AtomicReference<ProjectileUncollideEvent>();
MinecraftServer.getGlobalEventHandler().addListener(ProjectileUncollideEvent.class, eventRef2::set);
eventRef.set(null);
instance.setBlock(blockPosition, Block.AIR);
for (int i = 0; i < MinecraftServer.TICK_PER_SECOND; ++i) {
projectile.tick((MinecraftServer.TICK_PER_SECOND + i) * tick);
}
event = eventRef.get();
final var event2 = eventRef2.get();
assertNotNull(event);
assertNotNull(event2);
assertEquals(blockPosition.withY(y -> y - 1), new Vec(event.getCollisionPosition().blockX(), event.getCollisionPosition().blockY(), event.getCollisionPosition().blockZ()));
}
@Test
public void entityShoot(Env env) {
final Instance instance = env.createFlatInstance();
instance.getWorldBorder().setDiameter(1000.0);
final Entity shooter = new Entity(EntityType.SKELETON);
shooter.setInstance(instance, new Pos(0, 40, 0)).join();
for (double dx = 1; dx <= 3; dx += .2) {
singleEntityShoot(instance, shooter, new Vec(dx, 40, 0));
}
}
private void singleEntityShoot(
Instance instance,
Entity shooter,
final Point targetPosition
) {
final EntityProjectile projectile = new EntityProjectile(shooter, EntityType.ARROW);
projectile.setInstance(instance, shooter.getPosition().withY(y -> y + shooter.getEyeHeight())).join();
final LivingEntity target = new LivingEntity(EntityType.RABBIT);
target.setInstance(instance, Pos.fromPoint(targetPosition)).join();
projectile.shoot(targetPosition, 1, 0);
final var eventRef = new AtomicReference<ProjectileCollideWithEntityEvent>();
final var eventNode = EventNode.all("projectile-test");
eventNode.addListener(ProjectileCollideWithEntityEvent.class, event -> {
event.getEntity().remove();
eventRef.set(event);
MinecraftServer.getGlobalEventHandler().removeChild(eventNode);
});
MinecraftServer.getGlobalEventHandler().addChild(eventNode);
final long tick = TimeUnit.SERVER_TICK.getDuration().toMillis();
for (int i = 0; i < MinecraftServer.TICK_PER_SECOND; ++i) {
if (!projectile.isRemoved()) {
projectile.tick(i * tick);
}
}
final var event = eventRef.get();
assertNotNull(event, "Could not hit entity at " + targetPosition);
assertSame(target, event.getTarget());
assertTrue(projectile.getBoundingBox().intersectEntity(event.getCollisionPosition(), target));
target.remove();
}
@Test
public void entitySelfShoot(Env env) {
final Instance instance = env.createFlatInstance();
instance.getWorldBorder().setDiameter(1000.0);
final LivingEntity shooter = new LivingEntity(EntityType.SKELETON);
shooter.setInstance(instance, new Pos(0, 40, 0)).join();
final EntityProjectile projectile = new EntityProjectile(shooter, EntityType.ARROW);
projectile.setInstance(instance, shooter.getPosition().withY(y -> y + shooter.getEyeHeight())).join();
projectile.shoot(new Vec(0, 60, 0), 1, 0);
final var eventRef = new AtomicReference<ProjectileCollideWithEntityEvent>();
MinecraftServer.getGlobalEventHandler().addListener(ProjectileCollideWithEntityEvent.class, event -> {
event.getEntity().remove();
eventRef.set(event);
});
final long tick = TimeUnit.SERVER_TICK.getDuration().toMillis();
for (int i = 0; i < MinecraftServer.TICK_PER_SECOND * 5; ++i) {
if (!projectile.isRemoved()) {
projectile.tick(i * tick);
}
}
final var event = eventRef.get();
assertNotNull(event);
assertSame(shooter, event.getTarget());
assertTrue(shooter.getBoundingBox().intersectEntity(shooter.getPosition(), projectile));
}
}