Added WorldBorder#isInside + physics now support world border

This commit is contained in:
Felix Cravic 2020-05-27 01:04:39 +02:00
parent 224a8a3b86
commit ef261c1792
6 changed files with 76 additions and 28 deletions

View File

@ -15,7 +15,8 @@ public class CollisionUtils {
/**
* Moves an entity with physics applied (ie checking against blocks)
* @param entity the entity to move
*
* @param entity the entity to move
* @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
@ -29,7 +30,7 @@ public class CollisionUtils {
boolean yCollision = stepAxis(instance, currentPosition.toVector(), Y_AXIS, deltaPosition.getY(),
intermediaryPosition,
deltaPosition.getY() > 0 ? boundingBox.getTopFace() : boundingBox.getBottomFace()
);
);
boolean xCollision = stepAxis(instance, intermediaryPosition, X_AXIS, deltaPosition.getX(),
intermediaryPosition,
@ -61,12 +62,13 @@ public class CollisionUtils {
/**
* Steps on a single axis. Checks against collisions for each point of 'corners'. This method assumes that startPosition is valid.
* Immediately return false if corners is of length 0.
* @param instance instance to check blocks from
*
* @param instance instance to check blocks from
* @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
* @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 iif a collision has been found
*/
private static boolean stepAxis(Instance instance, Vector startPosition, Vector axis, float stepAmount, Vector positionOut, Vector... corners) {
@ -83,21 +85,21 @@ public class CollisionUtils {
}
float sign = Math.signum(stepAmount);
int blockLength = (int)stepAmount;
float remainingLength = stepAmount-blockLength;
int blockLength = (int) stepAmount;
float 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, axis, sign, cornersCopy, cornerPositions)) {
collisionFound = true;
}
if(collisionFound) {
if (collisionFound) {
break;
}
}
// add remainingLength
if(!collisionFound) {
if (!collisionFound) {
Vector direction = new Vector();
direction.copy(axis);
collisionFound |= !stepOnce(instance, direction, remainingLength, cornersCopy, cornerPositions);
@ -113,15 +115,16 @@ public class CollisionUtils {
}
positionOut.copy(startPosition);
positionOut.add(smallestDisplacement*axis.getX()*sign, smallestDisplacement*axis.getY()*sign, smallestDisplacement*axis.getZ()*sign);
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. Returns false if this method encountered a collision
* @param instance instance to get blocks from
* @param axis the axis to move along
* @param cornersCopy the corners of the bounding box to consider (mutable)
*
* @param instance instance to get blocks from
* @param axis the axis to move along
* @param cornersCopy the corners of the bounding box to consider (mutable)
* @param cornerPositions the corners, converted to BlockPosition (mutable)
* @return
*/
@ -130,7 +133,7 @@ public class CollisionUtils {
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);
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()));
@ -140,7 +143,7 @@ public class CollisionUtils {
// 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);
corner.subtract(axis.getX() * amount, axis.getY() * amount, axis.getZ() * amount);
if (Math.abs(axis.getX()) > 10e-16) {
corner.setX(blockPos.getX() - axis.getX() * sign);

View File

@ -16,6 +16,7 @@ import net.minestom.server.event.entity.EntityVelocityEvent;
import net.minestom.server.event.handler.EventHandler;
import net.minestom.server.instance.Chunk;
import net.minestom.server.instance.Instance;
import net.minestom.server.instance.WorldBorder;
import net.minestom.server.instance.block.CustomBlock;
import net.minestom.server.network.packet.PacketWriter;
import net.minestom.server.network.packet.server.play.*;
@ -289,8 +290,8 @@ public abstract class Entity implements Viewable, EventHandler, DataContainer {
this.lastUpdate = time;
// Velocity
boolean applyVelocity = (PlayerUtils.isNettyClient(this) && hasVelocity())
|| !PlayerUtils.isNettyClient(this);
final boolean applyVelocity = !PlayerUtils.isNettyClient(this) ||
(PlayerUtils.isNettyClient(this) && hasVelocity());
if (applyVelocity) {
final float tps = MinecraftServer.TICK_PER_SECOND;
float newX = position.getX() + velocity.getX() / tps;
@ -299,11 +300,9 @@ public abstract class Entity implements Viewable, EventHandler, DataContainer {
Position newPosition = new Position(newX, newY, newZ);
//if (!PlayerUtils.isNettyClient(this) && !noGravity) { // players handle gravity by themselves
if (!noGravity) {
velocity.setY(velocity.getY() - gravityDragPerTick * tps);
}
// }
Vector newVelocityOut = new Vector();
Vector deltaPos = new Vector(
@ -313,7 +312,15 @@ public abstract class Entity implements Viewable, EventHandler, DataContainer {
);
onGround = CollisionUtils.handlePhysics(this, deltaPos, newPosition, newVelocityOut);
refreshPosition(newPosition);
WorldBorder worldBorder = instance.getWorldBorder();
if (worldBorder.isInside(newPosition)) {
// Apply velocity + gravity
refreshPosition(newPosition);
} else {
// Only apply Y velocity/gravity
refreshPosition(position.getX(), newPosition.getY(), position.getZ());
}
velocity.copy(newVelocityOut);
velocity.multiply(tps);

View File

@ -230,7 +230,7 @@ public abstract class LivingEntity extends Entity implements EquipmentHandler {
// Additional hearts support
if (this instanceof Player) {
Player player = (Player) this;
float additionalHearts = player.getAdditionalHearts();
final float additionalHearts = player.getAdditionalHearts();
if (additionalHearts > 0) {
if (damage > additionalHearts) {
damage -= additionalHearts;

View File

@ -127,7 +127,7 @@ public class Player extends LivingEntity {
private PlayerVehicleInformation vehicleInformation = new PlayerVehicleInformation();
// Tick related
private final PlayerTickEvent playerTickEvent = new PlayerTickEvent();
private final PlayerTickEvent playerTickEvent = new PlayerTickEvent(this);
public Player(UUID uuid, String username, PlayerConnection playerConnection) {
super(EntityType.PLAYER);

View File

@ -1,6 +1,17 @@
package net.minestom.server.event.player;
import net.minestom.server.entity.Player;
import net.minestom.server.event.Event;
public class PlayerTickEvent extends Event {
private Player player;
public PlayerTickEvent(Player player) {
this.player = player;
}
public Player getPlayer() {
return player;
}
}

View File

@ -1,13 +1,15 @@
package net.minestom.server.instance;
import net.minestom.server.entity.Entity;
import net.minestom.server.entity.Player;
import net.minestom.server.network.packet.server.play.WorldBorderPacket;
import net.minestom.server.utils.Position;
public class WorldBorder {
private Instance instance;
private double centerX, centerZ;
private float centerX, centerZ;
private volatile double currentDiameter;
@ -33,7 +35,7 @@ public class WorldBorder {
}
public void setCenter(double centerX, double centerZ) {
public void setCenter(float centerX, float centerZ) {
this.centerX = centerX;
this.centerZ = centerZ;
refreshCenter();
@ -43,7 +45,7 @@ public class WorldBorder {
return centerX;
}
public void setCenterX(double centerX) {
public void setCenterX(float centerX) {
this.centerX = centerX;
refreshCenter();
}
@ -52,7 +54,7 @@ public class WorldBorder {
return centerZ;
}
public void setCenterZ(double centerZ) {
public void setCenterZ(float centerZ) {
this.centerZ = centerZ;
refreshCenter();
}
@ -134,6 +136,31 @@ public class WorldBorder {
sendPacket(worldBorderPacket);
}
/**
* Used to know if a position is located inside the world border or not
*
* @param position the position to check
* @return true if {@code position} is inside the world border, false otherwise
*/
public boolean isInside(Position position) {
final double radius = getDiameter() / 2d;
final boolean checkX = position.getX() < getCenterX() + radius && position.getX() > getCenterX() - radius;
if (!checkX)
return false;
final boolean checkZ = position.getZ() < getCenterZ() + radius && position.getZ() > getCenterZ() - radius;
return checkZ;
}
/**
* Used to know if an entity is located inside the world border or not
*
* @param entity the entity to check
* @return true if {@code entity} is inside the world border, false otherwise
*/
public boolean isInside(Entity entity) {
return isInside(entity.getPosition());
}
/**
* Used to update in real-time the current diameter time
*/