mirror of https://github.com/Minestom/Minestom.git
111 lines
4.2 KiB
Java
111 lines
4.2 KiB
Java
package net.minestom.server.entity.pathfinding;
|
|
|
|
import net.minestom.server.attribute.Attribute;
|
|
import net.minestom.server.collision.CollisionUtils;
|
|
import net.minestom.server.collision.PhysicsResult;
|
|
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.LivingEntity;
|
|
import net.minestom.server.particle.Particle;
|
|
import net.minestom.server.utils.position.PositionUtils;
|
|
import org.jetbrains.annotations.ApiStatus;
|
|
import org.jetbrains.annotations.NotNull;
|
|
import org.jetbrains.annotations.Nullable;
|
|
|
|
/**
|
|
* Necessary object for all {@link NavigableEntity}.
|
|
*/
|
|
public final class Navigator {
|
|
private final Entity entity;
|
|
private final Pathfinder pathfinder;
|
|
|
|
public Navigator(@NotNull Entity entity) {
|
|
this.entity = entity;
|
|
this.pathfinder = new PathfinderImpl(entity, null, null);
|
|
}
|
|
|
|
/**
|
|
* Used to move the entity toward {@code direction} in the X and Z axis
|
|
* Gravity is still applied but the entity will not attempt to jump
|
|
* Also update the yaw/pitch of the entity to look along 'direction'
|
|
*
|
|
* @param direction the targeted position
|
|
* @param speed define how far the entity will move
|
|
*/
|
|
public void moveTowards(@NotNull Point direction, double speed) {
|
|
final Pos position = entity.getPosition();
|
|
|
|
// Find the direction
|
|
final double dx = direction.x() - position.x();
|
|
final double dy = direction.y() - position.y();
|
|
final double dz = direction.z() - position.z();
|
|
|
|
// the purpose of these few lines is to slow down entities when they reach their destination
|
|
double distSquared = dx * dx + dy * dy + dz * dz;
|
|
if (speed > distSquared) {
|
|
speed = distSquared;
|
|
}
|
|
// Find the movement speed
|
|
final double radians = Math.atan2(dz, dx);
|
|
final double speedX = Math.cos(radians) * speed;
|
|
final double speedY = dy * speed;
|
|
final double speedZ = Math.sin(radians) * speed;
|
|
|
|
// Now calculate the new yaw/pitch
|
|
final float oldYaw = position.yaw();
|
|
final float oldPitch = position.pitch();
|
|
final float newYaw = PositionUtils.getLookYaw(dx, dz);
|
|
final float newPitch = PositionUtils.getLookPitch(dx, dy, dz);
|
|
|
|
// Average the pitch and yaw to avoid jittering
|
|
final float yaw = PositionUtils.averageYaw(PositionUtils.averageYaw(oldYaw, newYaw), oldYaw);
|
|
final float pitch = PositionUtils.averagePitch(PositionUtils.averagePitch(oldPitch, newPitch), oldPitch);
|
|
|
|
// Prevent ghosting, and refresh position
|
|
final PhysicsResult physicsResult = CollisionUtils.handlePhysics(entity, new Vec(speedX, speedY, speedZ));
|
|
this.entity.refreshPosition(physicsResult.newPosition().withView(yaw, pitch));
|
|
}
|
|
|
|
public void jump(float height) {
|
|
// FIXME magic value
|
|
this.entity.setVelocity(new Vec(0, height * 2.5f, 0));
|
|
}
|
|
|
|
public void setPathTo(@Nullable Point point) {
|
|
this.pathfinder.updatePath(point);
|
|
}
|
|
|
|
@ApiStatus.Internal
|
|
public synchronized void tick() {
|
|
if (entity instanceof LivingEntity && ((LivingEntity) entity).isDead())
|
|
return; // No pathfinding tick for dead entities
|
|
final Point next = this.pathfinder.nextPoint(entity.getPosition());
|
|
if (next != null) {
|
|
moveTowards(next, getAttributeValue(Attribute.MOVEMENT_SPEED));
|
|
PathfindUtils.debugParticle(next, Particle.WHITE_ASH);
|
|
final double entityY = entity.getPosition().y();
|
|
if (entityY < next.y()) {
|
|
jump(1);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Gets the target pathfinder position.
|
|
*
|
|
* @return the target pathfinder position, null if there is no one
|
|
*/
|
|
public @Nullable Point getPathPosition() {
|
|
return this.pathfinder.nextPoint(entity.getPosition());
|
|
}
|
|
|
|
private float getAttributeValue(@NotNull Attribute attribute) {
|
|
if (entity instanceof LivingEntity) {
|
|
return ((LivingEntity) entity).getAttributeValue(attribute);
|
|
}
|
|
return attribute.defaultValue();
|
|
}
|
|
}
|