mirror of
https://github.com/Minestom/Minestom.git
synced 2025-01-02 14:38:26 +01:00
Merge pull request #356 from Kebab11noel/fix/update-collision
Collision update
This commit is contained in:
commit
b00131c525
@ -2,8 +2,8 @@ package net.minestom.server.collision;
|
||||
|
||||
import net.minestom.server.entity.Entity;
|
||||
import net.minestom.server.utils.BlockPosition;
|
||||
import net.minestom.server.utils.Vector;
|
||||
import net.minestom.server.utils.coordinate.Point;
|
||||
import net.minestom.server.utils.coordinate.Vec;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
@ -199,92 +199,92 @@ public class BoundingBox {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an array of {@link Vector} representing the points at the bottom of the {@link BoundingBox}.
|
||||
* Gets an array of {@link Vec} representing the points at the bottom of the {@link BoundingBox}.
|
||||
*
|
||||
* @return the points at the bottom of the {@link BoundingBox}
|
||||
*/
|
||||
@NotNull
|
||||
public Vector[] getBottomFace() {
|
||||
return new Vector[]{
|
||||
new Vector(getMinX(), getMinY(), getMinZ()),
|
||||
new Vector(getMaxX(), getMinY(), getMinZ()),
|
||||
new Vector(getMaxX(), getMinY(), getMaxZ()),
|
||||
new Vector(getMinX(), getMinY(), getMaxZ()),
|
||||
public Vec[] getBottomFace() {
|
||||
return new Vec[]{
|
||||
new Vec(getMinX(), getMinY(), getMinZ()),
|
||||
new Vec(getMaxX(), getMinY(), getMinZ()),
|
||||
new Vec(getMaxX(), getMinY(), getMaxZ()),
|
||||
new Vec(getMinX(), getMinY(), getMaxZ()),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an array of {@link Vector} representing the points at the top of the {@link BoundingBox}.
|
||||
* Gets an array of {@link Vec} representing the points at the top of the {@link BoundingBox}.
|
||||
*
|
||||
* @return the points at the top of the {@link BoundingBox}
|
||||
*/
|
||||
@NotNull
|
||||
public Vector[] getTopFace() {
|
||||
return new Vector[]{
|
||||
new Vector(getMinX(), getMaxY(), getMinZ()),
|
||||
new Vector(getMaxX(), getMaxY(), getMinZ()),
|
||||
new Vector(getMaxX(), getMaxY(), getMaxZ()),
|
||||
new Vector(getMinX(), getMaxY(), getMaxZ()),
|
||||
public Vec[] getTopFace() {
|
||||
return new Vec[]{
|
||||
new Vec(getMinX(), getMaxY(), getMinZ()),
|
||||
new Vec(getMaxX(), getMaxY(), getMinZ()),
|
||||
new Vec(getMaxX(), getMaxY(), getMaxZ()),
|
||||
new Vec(getMinX(), getMaxY(), getMaxZ()),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an array of {@link Vector} representing the points on the left face of the {@link BoundingBox}.
|
||||
* Gets an array of {@link Vec} representing the points on the left face of the {@link BoundingBox}.
|
||||
*
|
||||
* @return the points on the left face of the {@link BoundingBox}
|
||||
*/
|
||||
@NotNull
|
||||
public Vector[] getLeftFace() {
|
||||
return new Vector[]{
|
||||
new Vector(getMinX(), getMinY(), getMinZ()),
|
||||
new Vector(getMinX(), getMaxY(), getMinZ()),
|
||||
new Vector(getMinX(), getMaxY(), getMaxZ()),
|
||||
new Vector(getMinX(), getMinY(), getMaxZ()),
|
||||
public Vec[] getLeftFace() {
|
||||
return new Vec[]{
|
||||
new Vec(getMinX(), getMinY(), getMinZ()),
|
||||
new Vec(getMinX(), getMaxY(), getMinZ()),
|
||||
new Vec(getMinX(), getMaxY(), getMaxZ()),
|
||||
new Vec(getMinX(), getMinY(), getMaxZ()),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an array of {@link Vector} representing the points on the right face of the {@link BoundingBox}.
|
||||
* Gets an array of {@link Vec} representing the points on the right face of the {@link BoundingBox}.
|
||||
*
|
||||
* @return the points on the right face of the {@link BoundingBox}
|
||||
*/
|
||||
@NotNull
|
||||
public Vector[] getRightFace() {
|
||||
return new Vector[]{
|
||||
new Vector(getMaxX(), getMinY(), getMinZ()),
|
||||
new Vector(getMaxX(), getMaxY(), getMinZ()),
|
||||
new Vector(getMaxX(), getMaxY(), getMaxZ()),
|
||||
new Vector(getMaxX(), getMinY(), getMaxZ()),
|
||||
public Vec[] getRightFace() {
|
||||
return new Vec[]{
|
||||
new Vec(getMaxX(), getMinY(), getMinZ()),
|
||||
new Vec(getMaxX(), getMaxY(), getMinZ()),
|
||||
new Vec(getMaxX(), getMaxY(), getMaxZ()),
|
||||
new Vec(getMaxX(), getMinY(), getMaxZ()),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an array of {@link Vector} representing the points at the front of the {@link BoundingBox}.
|
||||
* Gets an array of {@link Vec} representing the points at the front of the {@link BoundingBox}.
|
||||
*
|
||||
* @return the points at the front of the {@link BoundingBox}
|
||||
*/
|
||||
@NotNull
|
||||
public Vector[] getFrontFace() {
|
||||
return new Vector[]{
|
||||
new Vector(getMinX(), getMinY(), getMinZ()),
|
||||
new Vector(getMaxX(), getMinY(), getMinZ()),
|
||||
new Vector(getMaxX(), getMaxY(), getMinZ()),
|
||||
new Vector(getMinX(), getMaxY(), getMinZ()),
|
||||
public Vec[] getFrontFace() {
|
||||
return new Vec[]{
|
||||
new Vec(getMinX(), getMinY(), getMinZ()),
|
||||
new Vec(getMaxX(), getMinY(), getMinZ()),
|
||||
new Vec(getMaxX(), getMaxY(), getMinZ()),
|
||||
new Vec(getMinX(), getMaxY(), getMinZ()),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an array of {@link Vector} representing the points at the back of the {@link BoundingBox}.
|
||||
* Gets an array of {@link Vec} representing the points at the back of the {@link BoundingBox}.
|
||||
*
|
||||
* @return the points at the back of the {@link BoundingBox}
|
||||
*/
|
||||
@NotNull
|
||||
public Vector[] getBackFace() {
|
||||
return new Vector[]{
|
||||
new Vector(getMinX(), getMinY(), getMaxZ()),
|
||||
new Vector(getMaxX(), getMinY(), getMaxZ()),
|
||||
new Vector(getMaxX(), getMaxY(), getMaxZ()),
|
||||
new Vector(getMinX(), getMaxY(), getMaxZ()),
|
||||
public Vec[] getBackFace() {
|
||||
return new Vec[]{
|
||||
new Vec(getMinX(), getMinY(), getMaxZ()),
|
||||
new Vec(getMaxX(), getMinY(), getMaxZ()),
|
||||
new Vec(getMaxX(), getMaxY(), getMaxZ()),
|
||||
new Vec(getMinX(), getMaxY(), getMaxZ()),
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -5,67 +5,46 @@ import net.minestom.server.instance.Chunk;
|
||||
import net.minestom.server.instance.Instance;
|
||||
import net.minestom.server.instance.WorldBorder;
|
||||
import net.minestom.server.instance.block.Block;
|
||||
import net.minestom.server.utils.BlockPosition;
|
||||
import net.minestom.server.utils.Position;
|
||||
import net.minestom.server.utils.Vector;
|
||||
import net.minestom.server.utils.chunk.ChunkUtils;
|
||||
import net.minestom.server.utils.coordinate.Point;
|
||||
import net.minestom.server.utils.coordinate.Pos;
|
||||
import net.minestom.server.utils.coordinate.Vec;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class CollisionUtils {
|
||||
|
||||
private static final Vector Y_AXIS = new Vector(0, 1, 0);
|
||||
private static final Vector X_AXIS = new Vector(1, 0, 0);
|
||||
private static final Vector Z_AXIS = new Vector(0, 0, 1);
|
||||
private static final Vec Y_AXIS = new Vec(0, 1, 0);
|
||||
private static final Vec X_AXIS = new Vec(1, 0, 0);
|
||||
private static final Vec Z_AXIS = new Vec(0, 0, 1);
|
||||
|
||||
/**
|
||||
* Moves an entity with physics applied (ie checking against blocks)
|
||||
*
|
||||
* @param entity the entity to move
|
||||
* @param deltaPosition
|
||||
* @param positionOut the Position object in which the new position will be saved
|
||||
* @param velocityOut the Vector object in which the new velocity will be saved
|
||||
* @return whether this entity is on the ground
|
||||
* @return the result of physics simulation
|
||||
*/
|
||||
public static boolean handlePhysics(@NotNull Entity entity,
|
||||
@NotNull Vector deltaPosition,
|
||||
@NotNull Position positionOut,
|
||||
@NotNull Vector velocityOut) {
|
||||
public static PhysicsResult handlePhysics(@NotNull Entity entity, @NotNull Vec deltaPosition) {
|
||||
// TODO handle collisions with nearby entities (should it be done here?)
|
||||
final Instance instance = entity.getInstance();
|
||||
final Chunk originChunk = entity.getChunk();
|
||||
final Position currentPosition = entity.getPosition();
|
||||
final Pos currentPosition = entity.getPosition();
|
||||
final BoundingBox boundingBox = entity.getBoundingBox();
|
||||
|
||||
Vector intermediaryPosition = new Vector();
|
||||
boolean yCollision = stepAxis(instance, originChunk, currentPosition.toVector(), Y_AXIS, deltaPosition.getY(),
|
||||
intermediaryPosition,
|
||||
deltaPosition.getY() > 0 ? boundingBox.getTopFace() : boundingBox.getBottomFace());
|
||||
final StepResult yCollision = stepAxis(instance, originChunk, currentPosition.asVec(), Y_AXIS, deltaPosition.y(),
|
||||
deltaPosition.y() > 0 ? boundingBox.getTopFace() : boundingBox.getBottomFace());
|
||||
|
||||
boolean xCollision = stepAxis(instance, originChunk, intermediaryPosition, X_AXIS, deltaPosition.getX(),
|
||||
intermediaryPosition,
|
||||
deltaPosition.getX() < 0 ? boundingBox.getLeftFace() : boundingBox.getRightFace());
|
||||
final StepResult xCollision = stepAxis(instance, originChunk, yCollision.newPosition, X_AXIS, deltaPosition.x(),
|
||||
deltaPosition.x() < 0 ? boundingBox.getLeftFace() : boundingBox.getRightFace());
|
||||
|
||||
boolean zCollision = stepAxis(instance, originChunk, intermediaryPosition, Z_AXIS, deltaPosition.getZ(),
|
||||
intermediaryPosition,
|
||||
deltaPosition.getZ() > 0 ? boundingBox.getBackFace() : boundingBox.getFrontFace());
|
||||
final StepResult zCollision = stepAxis(instance, originChunk, xCollision.newPosition, Z_AXIS, deltaPosition.z(),
|
||||
deltaPosition.z() > 0 ? boundingBox.getBackFace() : boundingBox.getFrontFace());
|
||||
|
||||
positionOut.setX(intermediaryPosition.getX());
|
||||
positionOut.setY(intermediaryPosition.getY());
|
||||
positionOut.setZ(intermediaryPosition.getZ());
|
||||
velocityOut.copy(deltaPosition);
|
||||
if (xCollision) {
|
||||
velocityOut.setX(0f);
|
||||
}
|
||||
if (yCollision) {
|
||||
velocityOut.setY(0f);
|
||||
}
|
||||
if (zCollision) {
|
||||
velocityOut.setZ(0f);
|
||||
}
|
||||
|
||||
return yCollision && deltaPosition.getY() < 0;
|
||||
return new PhysicsResult(currentPosition.withCoord(zCollision.newPosition),
|
||||
deltaPosition.with(((x, y, z) -> new Vec(
|
||||
xCollision.foundCollision ? 0 : x,
|
||||
yCollision.foundCollision ? 0 : y,
|
||||
zCollision.foundCollision ? 0 : z
|
||||
))), yCollision.foundCollision && deltaPosition.y() < 0);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -76,111 +55,82 @@ public class CollisionUtils {
|
||||
* @param startPosition starting position for stepping, can be intermediary position from last step
|
||||
* @param axis step direction. Works best if unit vector and aligned to an axis
|
||||
* @param stepAmount how much to step in the direction (in blocks)
|
||||
* @param positionOut the vector in which to store the new position
|
||||
* @param corners the corners to check against
|
||||
* @return true if a collision has been found
|
||||
* @return result of the step
|
||||
*/
|
||||
private static boolean stepAxis(Instance instance,
|
||||
Chunk originChunk,
|
||||
Vector startPosition, Vector axis,
|
||||
double stepAmount, Vector positionOut,
|
||||
Vector... corners) {
|
||||
positionOut.copy(startPosition);
|
||||
private static StepResult stepAxis(Instance instance, Chunk originChunk, Vec startPosition, Vec axis, double stepAmount, Vec... corners) {
|
||||
if (corners.length == 0)
|
||||
return false; // avoid degeneracy in following computations
|
||||
// perform copies to allow in place modifications
|
||||
// prevents making a lot of new objects. Well at least it reduces the count
|
||||
BlockPosition[] cornerPositions = new BlockPosition[corners.length];
|
||||
Vector[] cornersCopy = new Vector[corners.length];
|
||||
for (int i = 0; i < corners.length; i++) {
|
||||
cornersCopy[i] = corners[i].clone();
|
||||
cornerPositions[i] = new BlockPosition(corners[i]);
|
||||
}
|
||||
return new StepResult(startPosition, false); // avoid degeneracy in following computations
|
||||
|
||||
final Vec[] originalCorners = corners.clone();
|
||||
final double sign = Math.signum(stepAmount);
|
||||
final int blockLength = (int) stepAmount;
|
||||
final double remainingLength = stepAmount - blockLength;
|
||||
// used to determine if 'remainingLength' should be used
|
||||
boolean collisionFound = false;
|
||||
for (int i = 0; i < Math.abs(blockLength); i++) {
|
||||
if (!stepOnce(instance, originChunk, axis, sign, cornersCopy, cornerPositions)) {
|
||||
collisionFound = true;
|
||||
}
|
||||
if (collisionFound) {
|
||||
break;
|
||||
}
|
||||
final OneStepResult oneStepResult = stepOnce(instance, originChunk, axis, sign, corners);
|
||||
corners = oneStepResult.newCorners;
|
||||
if (collisionFound = oneStepResult.foundCollision) break;
|
||||
}
|
||||
|
||||
// add remainingLength
|
||||
if (!collisionFound) {
|
||||
Vector direction = new Vector();
|
||||
direction.copy(axis);
|
||||
collisionFound = !stepOnce(instance, originChunk, direction, remainingLength, cornersCopy, cornerPositions);
|
||||
final OneStepResult oneStepResult = stepOnce(instance, originChunk, axis, remainingLength, corners);
|
||||
corners = oneStepResult.newCorners;
|
||||
collisionFound = oneStepResult.foundCollision;
|
||||
}
|
||||
|
||||
// find the corner which moved the least
|
||||
double smallestDisplacement = Double.POSITIVE_INFINITY;
|
||||
for (int i = 0; i < corners.length; i++) {
|
||||
final double displacement = corners[i].distance(cornersCopy[i]);
|
||||
final double displacement = originalCorners[i].distance(corners[i]);
|
||||
if (displacement < smallestDisplacement) {
|
||||
smallestDisplacement = displacement;
|
||||
}
|
||||
}
|
||||
|
||||
positionOut.copy(startPosition);
|
||||
positionOut.add(smallestDisplacement * axis.getX() * sign, smallestDisplacement * axis.getY() * sign, smallestDisplacement * axis.getZ() * sign);
|
||||
return collisionFound;
|
||||
return new StepResult(startPosition.add(new Vec(smallestDisplacement).mul(axis).mul(sign)), collisionFound);
|
||||
}
|
||||
|
||||
/**
|
||||
* Steps once (by a length of 1 block) on the given axis.
|
||||
*
|
||||
* @param instance instance to get blocks from
|
||||
* @param axis the axis to move along
|
||||
* @param amount
|
||||
* @param cornersCopy the corners of the bounding box to consider (mutable)
|
||||
* @param cornerPositions the corners, converted to BlockPosition (mutable)
|
||||
* @return false if this method encountered a collision
|
||||
* @param instance instance to get blocks from
|
||||
* @param axis the axis to move along
|
||||
* @param corners the corners of the bounding box to consider
|
||||
* @return the result of one step
|
||||
*/
|
||||
private static boolean stepOnce(Instance instance,
|
||||
Chunk originChunk,
|
||||
Vector axis, double amount, Vector[] cornersCopy, BlockPosition[] cornerPositions) {
|
||||
private static OneStepResult stepOnce(Instance instance, Chunk originChunk, Vec axis, double amount, Vec[] corners) {
|
||||
final double sign = Math.signum(amount);
|
||||
for (int cornerIndex = 0; cornerIndex < cornersCopy.length; cornerIndex++) {
|
||||
Vector corner = cornersCopy[cornerIndex];
|
||||
BlockPosition blockPos = cornerPositions[cornerIndex];
|
||||
corner.add(axis.getX() * amount, axis.getY() * amount, axis.getZ() * amount);
|
||||
blockPos.setX((int) Math.floor(corner.getX()));
|
||||
blockPos.setY((int) Math.floor(corner.getY()));
|
||||
blockPos.setZ((int) Math.floor(corner.getZ()));
|
||||
Vec[] newCorners = new Vec[corners.length];
|
||||
for (int cornerIndex = 0; cornerIndex < corners.length; cornerIndex++) {
|
||||
final Vec originalCorner = corners[cornerIndex];
|
||||
final Vec corner = originalCorner.add(axis.mul(amount));
|
||||
|
||||
Chunk chunk = ChunkUtils.retrieve(instance, originChunk, blockPos);
|
||||
Chunk chunk = ChunkUtils.retrieve(instance, originChunk, corner);
|
||||
if (!ChunkUtils.isLoaded(chunk)) {
|
||||
// Collision at chunk border
|
||||
return false;
|
||||
return new OneStepResult(corners, true);
|
||||
}
|
||||
|
||||
final Block block = chunk.getBlock(blockPos);
|
||||
final Block block = chunk.getBlock(corner);
|
||||
|
||||
// TODO: block collision boxes
|
||||
// TODO: for the moment, always consider a full block
|
||||
if (block.isSolid()) {
|
||||
corner.subtract(axis.getX() * amount, axis.getY() * amount, axis.getZ() * amount);
|
||||
newCorners[cornerIndex] = originalCorner.with(((x, y, z) -> new Vec(
|
||||
Math.abs(axis.x()) > 10e-16 ? originalCorner.blockX() - axis.x() * sign : x,
|
||||
Math.abs(axis.y()) > 10e-16 ? originalCorner.blockY() - axis.y() * sign : y,
|
||||
Math.abs(axis.z()) > 10e-16 ? originalCorner.blockZ() - axis.z() * sign : z
|
||||
)));
|
||||
|
||||
if (Math.abs(axis.getX()) > 10e-16) {
|
||||
corner.setX(blockPos.getX() - axis.getX() * sign);
|
||||
}
|
||||
if (Math.abs(axis.getY()) > 10e-16) {
|
||||
corner.setY(blockPos.getY() - axis.getY() * sign);
|
||||
}
|
||||
if (Math.abs(axis.getZ()) > 10e-16) {
|
||||
corner.setZ(blockPos.getZ() - axis.getZ() * sign);
|
||||
}
|
||||
|
||||
return false;
|
||||
return new OneStepResult(newCorners, true);
|
||||
}
|
||||
|
||||
newCorners[cornerIndex] = corner;
|
||||
}
|
||||
return true;
|
||||
return new OneStepResult(newCorners, false);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -213,4 +163,47 @@ public class CollisionUtils {
|
||||
throw new IllegalStateException("Something weird happened...");
|
||||
}
|
||||
|
||||
public static class PhysicsResult {
|
||||
private final Pos newPosition;
|
||||
private final Vec newVelocity;
|
||||
private final boolean isOnGround;
|
||||
|
||||
public PhysicsResult(Pos newPosition, Vec newVelocity, boolean isOnGround) {
|
||||
this.newPosition = newPosition;
|
||||
this.newVelocity = newVelocity;
|
||||
this.isOnGround = isOnGround;
|
||||
}
|
||||
|
||||
public Pos newPosition() {
|
||||
return newPosition;
|
||||
}
|
||||
|
||||
public Vec newVelocity() {
|
||||
return newVelocity;
|
||||
}
|
||||
|
||||
public boolean isOnGround() {
|
||||
return isOnGround;
|
||||
}
|
||||
}
|
||||
|
||||
private static class StepResult {
|
||||
private final Vec newPosition;
|
||||
private final boolean foundCollision;
|
||||
|
||||
public StepResult(Vec newPosition, boolean foundCollision) {
|
||||
this.newPosition = newPosition;
|
||||
this.foundCollision = foundCollision;
|
||||
}
|
||||
}
|
||||
|
||||
private static class OneStepResult {
|
||||
private final Vec[] newCorners;
|
||||
private final boolean foundCollision;
|
||||
|
||||
public OneStepResult(Vec[] newCorners, boolean foundCollision) {
|
||||
this.newCorners = newCorners;
|
||||
this.foundCollision = foundCollision;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -38,7 +38,6 @@ import net.minestom.server.tag.Tag;
|
||||
import net.minestom.server.tag.TagHandler;
|
||||
import net.minestom.server.thread.ThreadProvider;
|
||||
import net.minestom.server.utils.Position;
|
||||
import net.minestom.server.utils.Vector;
|
||||
import net.minestom.server.utils.callback.OptionalCallback;
|
||||
import net.minestom.server.utils.chunk.ChunkCallback;
|
||||
import net.minestom.server.utils.chunk.ChunkUtils;
|
||||
@ -508,26 +507,30 @@ public class Entity implements Viewable, Tickable, EventHandler<EntityEvent>, Da
|
||||
|
||||
if (applyVelocity) {
|
||||
final float tps = MinecraftServer.TICK_PER_SECOND;
|
||||
final double newX = position.x() + velocity.x() / tps;
|
||||
final double newY = position.y() + velocity.y() / tps;
|
||||
final double newZ = position.z() + velocity.z() / tps;
|
||||
Position newPosition = new Position(newX, newY, newZ);
|
||||
|
||||
Vector newVelocityOut = new Vector();
|
||||
final Pos newPosition;
|
||||
final Vec newVelocity;
|
||||
|
||||
// Gravity force
|
||||
final double gravityY = hasNoGravity() ? 0 : gravityAcceleration;
|
||||
|
||||
final Vector deltaPos = new Vector(
|
||||
getVelocity().getX() / tps,
|
||||
getVelocity().getY() / tps - gravityY,
|
||||
getVelocity().getZ() / tps
|
||||
final Vec deltaPos = new Vec(
|
||||
getVelocity().x() / tps,
|
||||
getVelocity().y() / tps - gravityY,
|
||||
getVelocity().z() / tps
|
||||
);
|
||||
|
||||
if (this.hasPhysics) {
|
||||
this.onGround = CollisionUtils.handlePhysics(this, deltaPos, newPosition, newVelocityOut);
|
||||
final CollisionUtils.PhysicsResult physicsResult = CollisionUtils.handlePhysics(this, deltaPos);
|
||||
this.onGround = physicsResult.isOnGround();
|
||||
newPosition = physicsResult.newPosition();
|
||||
newVelocity = physicsResult.newVelocity();
|
||||
} else {
|
||||
newVelocityOut = deltaPos;
|
||||
newVelocity = deltaPos;
|
||||
newPosition = new Pos(
|
||||
position.x() + velocity.x() / tps,
|
||||
position.y() + velocity.y() / tps,
|
||||
position.z() + velocity.z() / tps
|
||||
);
|
||||
}
|
||||
|
||||
// World border collision
|
||||
@ -545,27 +548,23 @@ public class Entity implements Viewable, Tickable, EventHandler<EntityEvent>, Da
|
||||
}
|
||||
|
||||
// Update velocity
|
||||
if (hasVelocity() || !newVelocityOut.isZero()) {
|
||||
this.velocity.copy(newVelocityOut);
|
||||
this.velocity.multiply(tps);
|
||||
if (hasVelocity() || !newVelocity.equals(Vec.ZERO)) {
|
||||
velocity = newVelocity.mul(tps); // Convert from blocks/tick to blocks/sec
|
||||
|
||||
final Block block = finalChunk.getBlock(position);
|
||||
final double drag = block.registry().friction();
|
||||
if (onGround) {
|
||||
// Stop player velocity
|
||||
if (isNettyClient) {
|
||||
this.velocity.zero();
|
||||
velocity = Vec.ZERO;
|
||||
}
|
||||
}
|
||||
|
||||
this.velocity.setX(velocity.getX() * drag);
|
||||
this.velocity.setZ(velocity.getZ() * drag);
|
||||
if (!hasNoGravity())
|
||||
this.velocity.setY(velocity.getY() * (1 - gravityDragPerTick));
|
||||
|
||||
if (velocity.equals(new Vector())) {
|
||||
this.velocity.zero();
|
||||
}
|
||||
velocity = velocity.with((x, y, z) -> new Vec(
|
||||
x * drag,
|
||||
!hasNoGravity() ? y * (1 - gravityDragPerTick) : y,
|
||||
z * drag
|
||||
)).with(Vec.Operator.EPSILON);
|
||||
}
|
||||
|
||||
// Synchronization and packets...
|
||||
|
@ -9,8 +9,6 @@ import net.minestom.server.entity.LivingEntity;
|
||||
import net.minestom.server.instance.Chunk;
|
||||
import net.minestom.server.instance.Instance;
|
||||
import net.minestom.server.instance.WorldBorder;
|
||||
import net.minestom.server.utils.Position;
|
||||
import net.minestom.server.utils.Vector;
|
||||
import net.minestom.server.utils.chunk.ChunkUtils;
|
||||
import net.minestom.server.utils.coordinate.Point;
|
||||
import net.minestom.server.utils.coordinate.Pos;
|
||||
@ -75,16 +73,11 @@ public class Navigator {
|
||||
// Update 'position' view
|
||||
PositionUtils.lookAlong(position, dx, direction.y(), dz);
|
||||
|
||||
Position newPosition = new Position();
|
||||
Vector newVelocityOut = new Vector();
|
||||
|
||||
// Prevent ghosting
|
||||
CollisionUtils.handlePhysics(entity,
|
||||
new Vector(speedX, speedY, speedZ),
|
||||
newPosition, newVelocityOut);
|
||||
final CollisionUtils.PhysicsResult physicsResult = CollisionUtils.handlePhysics(entity, new Vec(speedX, speedY, speedZ));
|
||||
|
||||
// Will move the entity during Entity#tick
|
||||
position.copyCoordinates(newPosition);
|
||||
entity.teleport(physicsResult.newPosition());
|
||||
}
|
||||
|
||||
public void jump(float height) {
|
||||
|
@ -392,6 +392,15 @@ public final class Vec implements Point {
|
||||
|
||||
@FunctionalInterface
|
||||
public interface Operator {
|
||||
/**
|
||||
* Checks each axis' value, if it's below {@code 1E-6} then it gets replaced with {@code 0}
|
||||
*/
|
||||
Operator EPSILON = (x, y, z) -> new Vec(
|
||||
Math.abs(x) < 1E-6 ? 0 : x,
|
||||
Math.abs(y) < 1E-6 ? 0 : y,
|
||||
Math.abs(z) < 1E-6 ? 0 : z
|
||||
);
|
||||
|
||||
@NotNull Vec apply(double x, double y, double z);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user