mirror of
https://github.com/Minestom/Minestom.git
synced 2025-01-07 17:08:30 +01:00
Added WorldBorder#isInside + physics now support world border
This commit is contained in:
parent
224a8a3b86
commit
ef261c1792
@ -15,7 +15,8 @@ public class CollisionUtils {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 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 positionOut the Position object in which the new position will be saved
|
* @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
|
* @param velocityOut the Vector object in which the new velocity will be saved
|
||||||
* @return whether this entity is on the ground
|
* @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(),
|
boolean yCollision = stepAxis(instance, currentPosition.toVector(), Y_AXIS, deltaPosition.getY(),
|
||||||
intermediaryPosition,
|
intermediaryPosition,
|
||||||
deltaPosition.getY() > 0 ? boundingBox.getTopFace() : boundingBox.getBottomFace()
|
deltaPosition.getY() > 0 ? boundingBox.getTopFace() : boundingBox.getBottomFace()
|
||||||
);
|
);
|
||||||
|
|
||||||
boolean xCollision = stepAxis(instance, intermediaryPosition, X_AXIS, deltaPosition.getX(),
|
boolean xCollision = stepAxis(instance, intermediaryPosition, X_AXIS, deltaPosition.getX(),
|
||||||
intermediaryPosition,
|
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.
|
* 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.
|
* 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 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 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 iif a collision has been found
|
* @return true iif a collision has been found
|
||||||
*/
|
*/
|
||||||
private static boolean stepAxis(Instance instance, Vector startPosition, Vector axis, float stepAmount, Vector positionOut, Vector... corners) {
|
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);
|
float sign = Math.signum(stepAmount);
|
||||||
int blockLength = (int)stepAmount;
|
int blockLength = (int) stepAmount;
|
||||||
float remainingLength = stepAmount-blockLength;
|
float 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, axis, sign, cornersCopy, cornerPositions)) {
|
if (!stepOnce(instance, axis, sign, cornersCopy, cornerPositions)) {
|
||||||
collisionFound = true;
|
collisionFound = true;
|
||||||
}
|
}
|
||||||
if(collisionFound) {
|
if (collisionFound) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// add remainingLength
|
// add remainingLength
|
||||||
if(!collisionFound) {
|
if (!collisionFound) {
|
||||||
Vector direction = new Vector();
|
Vector direction = new Vector();
|
||||||
direction.copy(axis);
|
direction.copy(axis);
|
||||||
collisionFound |= !stepOnce(instance, direction, remainingLength, cornersCopy, cornerPositions);
|
collisionFound |= !stepOnce(instance, direction, remainingLength, cornersCopy, cornerPositions);
|
||||||
@ -113,15 +115,16 @@ public class CollisionUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
positionOut.copy(startPosition);
|
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;
|
return collisionFound;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Steps once (by a length of 1 block) on the given axis. Returns false if this method encountered a collision
|
* 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 instance instance to get blocks from
|
||||||
* @param cornersCopy the corners of the bounding box to consider (mutable)
|
* @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)
|
* @param cornerPositions the corners, converted to BlockPosition (mutable)
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@ -130,7 +133,7 @@ public class CollisionUtils {
|
|||||||
for (int cornerIndex = 0; cornerIndex < cornersCopy.length; cornerIndex++) {
|
for (int cornerIndex = 0; cornerIndex < cornersCopy.length; cornerIndex++) {
|
||||||
Vector corner = cornersCopy[cornerIndex];
|
Vector corner = cornersCopy[cornerIndex];
|
||||||
BlockPosition blockPos = cornerPositions[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.setX((int) Math.floor(corner.getX()));
|
||||||
blockPos.setY((int) Math.floor(corner.getY()));
|
blockPos.setY((int) Math.floor(corner.getY()));
|
||||||
blockPos.setZ((int) Math.floor(corner.getZ()));
|
blockPos.setZ((int) Math.floor(corner.getZ()));
|
||||||
@ -140,7 +143,7 @@ public class CollisionUtils {
|
|||||||
// 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);
|
corner.subtract(axis.getX() * amount, axis.getY() * amount, axis.getZ() * amount);
|
||||||
|
|
||||||
if (Math.abs(axis.getX()) > 10e-16) {
|
if (Math.abs(axis.getX()) > 10e-16) {
|
||||||
corner.setX(blockPos.getX() - axis.getX() * sign);
|
corner.setX(blockPos.getX() - axis.getX() * sign);
|
||||||
|
@ -16,6 +16,7 @@ import net.minestom.server.event.entity.EntityVelocityEvent;
|
|||||||
import net.minestom.server.event.handler.EventHandler;
|
import net.minestom.server.event.handler.EventHandler;
|
||||||
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.block.CustomBlock;
|
import net.minestom.server.instance.block.CustomBlock;
|
||||||
import net.minestom.server.network.packet.PacketWriter;
|
import net.minestom.server.network.packet.PacketWriter;
|
||||||
import net.minestom.server.network.packet.server.play.*;
|
import net.minestom.server.network.packet.server.play.*;
|
||||||
@ -289,8 +290,8 @@ public abstract class Entity implements Viewable, EventHandler, DataContainer {
|
|||||||
this.lastUpdate = time;
|
this.lastUpdate = time;
|
||||||
|
|
||||||
// Velocity
|
// Velocity
|
||||||
boolean applyVelocity = (PlayerUtils.isNettyClient(this) && hasVelocity())
|
final boolean applyVelocity = !PlayerUtils.isNettyClient(this) ||
|
||||||
|| !PlayerUtils.isNettyClient(this);
|
(PlayerUtils.isNettyClient(this) && hasVelocity());
|
||||||
if (applyVelocity) {
|
if (applyVelocity) {
|
||||||
final float tps = MinecraftServer.TICK_PER_SECOND;
|
final float tps = MinecraftServer.TICK_PER_SECOND;
|
||||||
float newX = position.getX() + velocity.getX() / tps;
|
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);
|
Position newPosition = new Position(newX, newY, newZ);
|
||||||
|
|
||||||
//if (!PlayerUtils.isNettyClient(this) && !noGravity) { // players handle gravity by themselves
|
|
||||||
if (!noGravity) {
|
if (!noGravity) {
|
||||||
velocity.setY(velocity.getY() - gravityDragPerTick * tps);
|
velocity.setY(velocity.getY() - gravityDragPerTick * tps);
|
||||||
}
|
}
|
||||||
// }
|
|
||||||
|
|
||||||
Vector newVelocityOut = new Vector();
|
Vector newVelocityOut = new Vector();
|
||||||
Vector deltaPos = 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);
|
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.copy(newVelocityOut);
|
||||||
velocity.multiply(tps);
|
velocity.multiply(tps);
|
||||||
|
|
||||||
|
@ -230,7 +230,7 @@ public abstract class LivingEntity extends Entity implements EquipmentHandler {
|
|||||||
// Additional hearts support
|
// Additional hearts support
|
||||||
if (this instanceof Player) {
|
if (this instanceof Player) {
|
||||||
Player player = (Player) this;
|
Player player = (Player) this;
|
||||||
float additionalHearts = player.getAdditionalHearts();
|
final float additionalHearts = player.getAdditionalHearts();
|
||||||
if (additionalHearts > 0) {
|
if (additionalHearts > 0) {
|
||||||
if (damage > additionalHearts) {
|
if (damage > additionalHearts) {
|
||||||
damage -= additionalHearts;
|
damage -= additionalHearts;
|
||||||
|
@ -127,7 +127,7 @@ public class Player extends LivingEntity {
|
|||||||
private PlayerVehicleInformation vehicleInformation = new PlayerVehicleInformation();
|
private PlayerVehicleInformation vehicleInformation = new PlayerVehicleInformation();
|
||||||
|
|
||||||
// Tick related
|
// Tick related
|
||||||
private final PlayerTickEvent playerTickEvent = new PlayerTickEvent();
|
private final PlayerTickEvent playerTickEvent = new PlayerTickEvent(this);
|
||||||
|
|
||||||
public Player(UUID uuid, String username, PlayerConnection playerConnection) {
|
public Player(UUID uuid, String username, PlayerConnection playerConnection) {
|
||||||
super(EntityType.PLAYER);
|
super(EntityType.PLAYER);
|
||||||
|
@ -1,6 +1,17 @@
|
|||||||
package net.minestom.server.event.player;
|
package net.minestom.server.event.player;
|
||||||
|
|
||||||
|
import net.minestom.server.entity.Player;
|
||||||
import net.minestom.server.event.Event;
|
import net.minestom.server.event.Event;
|
||||||
|
|
||||||
public class PlayerTickEvent extends Event {
|
public class PlayerTickEvent extends Event {
|
||||||
|
|
||||||
|
private Player player;
|
||||||
|
|
||||||
|
public PlayerTickEvent(Player player) {
|
||||||
|
this.player = player;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Player getPlayer() {
|
||||||
|
return player;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,15 @@
|
|||||||
package net.minestom.server.instance;
|
package net.minestom.server.instance;
|
||||||
|
|
||||||
|
import net.minestom.server.entity.Entity;
|
||||||
import net.minestom.server.entity.Player;
|
import net.minestom.server.entity.Player;
|
||||||
import net.minestom.server.network.packet.server.play.WorldBorderPacket;
|
import net.minestom.server.network.packet.server.play.WorldBorderPacket;
|
||||||
|
import net.minestom.server.utils.Position;
|
||||||
|
|
||||||
public class WorldBorder {
|
public class WorldBorder {
|
||||||
|
|
||||||
private Instance instance;
|
private Instance instance;
|
||||||
|
|
||||||
private double centerX, centerZ;
|
private float centerX, centerZ;
|
||||||
|
|
||||||
private volatile double currentDiameter;
|
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.centerX = centerX;
|
||||||
this.centerZ = centerZ;
|
this.centerZ = centerZ;
|
||||||
refreshCenter();
|
refreshCenter();
|
||||||
@ -43,7 +45,7 @@ public class WorldBorder {
|
|||||||
return centerX;
|
return centerX;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setCenterX(double centerX) {
|
public void setCenterX(float centerX) {
|
||||||
this.centerX = centerX;
|
this.centerX = centerX;
|
||||||
refreshCenter();
|
refreshCenter();
|
||||||
}
|
}
|
||||||
@ -52,7 +54,7 @@ public class WorldBorder {
|
|||||||
return centerZ;
|
return centerZ;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setCenterZ(double centerZ) {
|
public void setCenterZ(float centerZ) {
|
||||||
this.centerZ = centerZ;
|
this.centerZ = centerZ;
|
||||||
refreshCenter();
|
refreshCenter();
|
||||||
}
|
}
|
||||||
@ -134,6 +136,31 @@ public class WorldBorder {
|
|||||||
sendPacket(worldBorderPacket);
|
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
|
* Used to update in real-time the current diameter time
|
||||||
*/
|
*/
|
||||||
|
Loading…
Reference in New Issue
Block a user