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