mirror of
https://github.com/GeyserMC/Geyser.git
synced 2024-08-14 23:57:35 +00:00
Movement checks (#2547)
This avoids ArrayList allocations and https://github.com/GeyserMC/Geyser/issues/2540.
This commit is contained in:
parent
6f4d433561
commit
9a8795988f
13 changed files with 199 additions and 198 deletions
|
@ -27,7 +27,6 @@ package org.geysermc.connector.entity;
|
||||||
|
|
||||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
|
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
|
||||||
import com.nukkitx.math.vector.Vector3f;
|
import com.nukkitx.math.vector.Vector3f;
|
||||||
import com.nukkitx.math.vector.Vector3i;
|
|
||||||
import com.nukkitx.protocol.bedrock.data.entity.EntityData;
|
import com.nukkitx.protocol.bedrock.data.entity.EntityData;
|
||||||
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
|
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
|
||||||
import com.nukkitx.protocol.bedrock.packet.PlaySoundPacket;
|
import com.nukkitx.protocol.bedrock.packet.PlaySoundPacket;
|
||||||
|
@ -35,13 +34,12 @@ import org.geysermc.connector.entity.player.PlayerEntity;
|
||||||
import org.geysermc.connector.entity.type.EntityType;
|
import org.geysermc.connector.entity.type.EntityType;
|
||||||
import org.geysermc.connector.network.session.GeyserSession;
|
import org.geysermc.connector.network.session.GeyserSession;
|
||||||
import org.geysermc.connector.network.translators.collision.BoundingBox;
|
import org.geysermc.connector.network.translators.collision.BoundingBox;
|
||||||
import org.geysermc.connector.network.translators.collision.CollisionManager;
|
|
||||||
import org.geysermc.connector.network.translators.collision.translators.BlockCollision;
|
import org.geysermc.connector.network.translators.collision.translators.BlockCollision;
|
||||||
import org.geysermc.connector.network.translators.world.block.BlockStateValues;
|
import org.geysermc.connector.network.translators.world.block.BlockStateValues;
|
||||||
import org.geysermc.connector.registry.BlockRegistries;
|
import org.geysermc.connector.registry.BlockRegistries;
|
||||||
|
import org.geysermc.connector.utils.BlockPositionIterator;
|
||||||
import org.geysermc.connector.utils.BlockUtils;
|
import org.geysermc.connector.utils.BlockUtils;
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.concurrent.ThreadLocalRandom;
|
import java.util.concurrent.ThreadLocalRandom;
|
||||||
|
|
||||||
public class FishingHookEntity extends ThrowableEntity {
|
public class FishingHookEntity extends ThrowableEntity {
|
||||||
|
@ -91,19 +89,16 @@ public class FishingHookEntity extends ThrowableEntity {
|
||||||
boundingBox.setMiddleY(position.getY() + boundingBox.getSizeY() / 2);
|
boundingBox.setMiddleY(position.getY() + boundingBox.getSizeY() / 2);
|
||||||
boundingBox.setMiddleZ(position.getZ());
|
boundingBox.setMiddleZ(position.getZ());
|
||||||
|
|
||||||
CollisionManager collisionManager = session.getCollisionManager();
|
|
||||||
List<Vector3i> collidableBlocks = collisionManager.getCollidableBlocks(boundingBox);
|
|
||||||
boolean touchingWater = false;
|
boolean touchingWater = false;
|
||||||
boolean collided = false;
|
boolean collided = false;
|
||||||
for (Vector3i blockPos : collidableBlocks) {
|
for (BlockPositionIterator iter = session.getCollisionManager().collidableBlocksIterator(boundingBox); iter.hasNext(); iter.next()) {
|
||||||
int blockID = session.getConnector().getWorldManager().getBlockAt(session, blockPos);
|
int blockID = session.getConnector().getWorldManager().getBlockAt(session, iter.getX(), iter.getY(), iter.getZ());
|
||||||
BlockCollision blockCollision = BlockUtils.getCollision(blockID, blockPos);
|
BlockCollision blockCollision = BlockUtils.getCollision(blockID);
|
||||||
if (blockCollision != null) {
|
if (blockCollision != null) {
|
||||||
if (blockCollision.checkIntersection(boundingBox)) {
|
if (blockCollision.checkIntersection(iter.getX(), iter.getY(), iter.getZ(), boundingBox)) {
|
||||||
// TODO Push bounding box out of collision to improve movement
|
// TODO Push bounding box out of collision to improve movement
|
||||||
collided = true;
|
collided = true;
|
||||||
}
|
}
|
||||||
blockCollision.reset();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int waterLevel = BlockStateValues.getWaterLevel(blockID);
|
int waterLevel = BlockStateValues.getWaterLevel(blockID);
|
||||||
|
@ -111,10 +106,10 @@ public class FishingHookEntity extends ThrowableEntity {
|
||||||
waterLevel = 0;
|
waterLevel = 0;
|
||||||
}
|
}
|
||||||
if (waterLevel >= 0) {
|
if (waterLevel >= 0) {
|
||||||
double waterMaxY = blockPos.getY() + 1 - (waterLevel + 1) / 9.0;
|
double waterMaxY = iter.getY() + 1 - (waterLevel + 1) / 9.0;
|
||||||
// Falling water is a full block
|
// Falling water is a full block
|
||||||
if (waterLevel >= 8) {
|
if (waterLevel >= 8) {
|
||||||
waterMaxY = blockPos.getY() + 1;
|
waterMaxY = iter.getY() + 1;
|
||||||
}
|
}
|
||||||
if (position.getY() <= waterMaxY) {
|
if (position.getY() <= waterMaxY) {
|
||||||
touchingWater = true;
|
touchingWater = true;
|
||||||
|
|
|
@ -73,7 +73,10 @@ public class BedrockMovePlayerTranslator extends PacketTranslator<MovePlayerPack
|
||||||
// Send book update before the player moves
|
// Send book update before the player moves
|
||||||
session.getBookEditCache().checkForSend();
|
session.getBookEditCache().checkForSend();
|
||||||
|
|
||||||
session.confirmTeleport(packet.getPosition().toDouble().sub(0, EntityType.PLAYER.getOffset(), 0));
|
if (!session.getTeleportMap().isEmpty()) {
|
||||||
|
session.confirmTeleport(packet.getPosition().toDouble().sub(0, EntityType.PLAYER.getOffset(), 0));
|
||||||
|
return;
|
||||||
|
}
|
||||||
// head yaw, pitch, head yaw
|
// head yaw, pitch, head yaw
|
||||||
Vector3f rotation = Vector3f.from(packet.getRotation().getY(), packet.getRotation().getX(), packet.getRotation().getY());
|
Vector3f rotation = Vector3f.from(packet.getRotation().getY(), packet.getRotation().getX(), packet.getRotation().getY());
|
||||||
|
|
||||||
|
@ -96,7 +99,7 @@ public class BedrockMovePlayerTranslator extends PacketTranslator<MovePlayerPack
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isValidMove(session, packet.getMode(), entity.getPosition(), packet.getPosition())) {
|
if (isValidMove(session, entity.getPosition(), packet.getPosition())) {
|
||||||
Vector3d position = session.getCollisionManager().adjustBedrockPosition(packet.getPosition(), packet.isOnGround(), packet.getMode() == MovePlayerPacket.Mode.TELEPORT);
|
Vector3d position = session.getCollisionManager().adjustBedrockPosition(packet.getPosition(), packet.isOnGround(), packet.getMode() == MovePlayerPacket.Mode.TELEPORT);
|
||||||
if (position != null) { // A null return value cancels the packet
|
if (position != null) { // A null return value cancels the packet
|
||||||
Packet movePacket;
|
Packet movePacket;
|
||||||
|
@ -155,22 +158,15 @@ public class BedrockMovePlayerTranslator extends PacketTranslator<MovePlayerPack
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isValidMove(GeyserSession session, MovePlayerPacket.Mode mode, Vector3f currentPosition, Vector3f newPosition) {
|
private boolean isInvalidNumber(float val) {
|
||||||
if (mode != MovePlayerPacket.Mode.NORMAL)
|
return Float.isNaN(val) || Float.isInfinite(val);
|
||||||
return true;
|
}
|
||||||
|
|
||||||
double xRange = newPosition.getX() - currentPosition.getX();
|
private boolean isValidMove(GeyserSession session, Vector3f currentPosition, Vector3f newPosition) {
|
||||||
double yRange = newPosition.getY() - currentPosition.getY();
|
if (isInvalidNumber(newPosition.getX()) || isInvalidNumber(newPosition.getY()) || isInvalidNumber(newPosition.getZ())) {
|
||||||
double zRange = newPosition.getZ() - currentPosition.getZ();
|
return false;
|
||||||
|
}
|
||||||
if (xRange < 0)
|
if (currentPosition.distanceSquared(newPosition) > 300) {
|
||||||
xRange = -xRange;
|
|
||||||
if (yRange < 0)
|
|
||||||
yRange = -yRange;
|
|
||||||
if (zRange < 0)
|
|
||||||
zRange = -zRange;
|
|
||||||
|
|
||||||
if ((xRange + yRange + zRange) > 100) {
|
|
||||||
session.getConnector().getLogger().debug(ChatColor.RED + session.getName() + " moved too quickly." +
|
session.getConnector().getLogger().debug(ChatColor.RED + session.getName() + " moved too quickly." +
|
||||||
" current position: " + currentPosition + ", new position: " + newPosition);
|
" current position: " + currentPosition + ", new position: " + newPosition);
|
||||||
|
|
||||||
|
|
|
@ -89,39 +89,41 @@ public class BoundingBox implements Cloneable {
|
||||||
return Vector3d.from(middleX, middleY - sizeY / 2, middleZ);
|
return Vector3d.from(middleX, middleY - sizeY / 2, middleZ);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean checkOverlapInAxis(Vector3d offset, BoundingBox otherBox, Axis axis) {
|
private boolean checkOverlapInAxis(double xOffset, double yOffset, double zOffset, BoundingBox otherBox, Axis axis) {
|
||||||
return switch (axis) {
|
return switch (axis) {
|
||||||
case X -> Math.abs((middleX + offset.getX()) - otherBox.getMiddleX()) * 2 < (sizeX + otherBox.getSizeX());
|
case X -> Math.abs((middleX + xOffset) - otherBox.getMiddleX()) * 2 < (sizeX + otherBox.getSizeX());
|
||||||
case Y -> Math.abs((middleY + offset.getY()) - otherBox.getMiddleY()) * 2 < (sizeY + otherBox.getSizeY());
|
case Y -> Math.abs((middleY + yOffset) - otherBox.getMiddleY()) * 2 < (sizeY + otherBox.getSizeY());
|
||||||
case Z -> Math.abs((middleZ + offset.getZ()) - otherBox.getMiddleZ()) * 2 < (sizeZ + otherBox.getSizeZ());
|
case Z -> Math.abs((middleZ + zOffset) - otherBox.getMiddleZ()) * 2 < (sizeZ + otherBox.getSizeZ());
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Find the maximum offset of another bounding box in an axis that will not collide with this bounding box
|
* Find the maximum offset of another bounding box in an axis that will not collide with this bounding box
|
||||||
*
|
*
|
||||||
* @param boxOffset The offset of this bounding box
|
* @param xOffset The x offset of this bounding box
|
||||||
|
* @param yOffset The y offset of this bounding box
|
||||||
|
* @param zOffset The z offset of this bounding box
|
||||||
* @param otherBoundingBox The bounding box that is moving
|
* @param otherBoundingBox The bounding box that is moving
|
||||||
* @param axis The axis of movement
|
* @param axis The axis of movement
|
||||||
* @param offset The current max offset
|
* @param offset The current max offset
|
||||||
* @return The new max offset
|
* @return The new max offset
|
||||||
*/
|
*/
|
||||||
public double getMaxOffset(Vector3d boxOffset, BoundingBox otherBoundingBox, Axis axis, double offset) {
|
public double getMaxOffset(double xOffset, double yOffset, double zOffset, BoundingBox otherBoundingBox, Axis axis, double offset) {
|
||||||
// Make sure that the bounding box overlaps in the other axes
|
// Make sure that the bounding box overlaps in the other axes
|
||||||
for (Axis a : Axis.VALUES) {
|
for (Axis a : Axis.VALUES) {
|
||||||
if (a != axis && !checkOverlapInAxis(boxOffset, otherBoundingBox, a)) {
|
if (a != axis && !checkOverlapInAxis(xOffset, yOffset, zOffset, otherBoundingBox, a)) {
|
||||||
return offset;
|
return offset;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (offset > 0) {
|
if (offset > 0) {
|
||||||
double min = axis.choose(getMin().add(boxOffset));
|
double min = axis.choose(getMin().add(xOffset, yOffset, zOffset));
|
||||||
double max = axis.choose(otherBoundingBox.getMax());
|
double max = axis.choose(otherBoundingBox.getMax());
|
||||||
if ((min - max) >= -2.0 * CollisionManager.COLLISION_TOLERANCE) {
|
if ((min - max) >= -2.0 * CollisionManager.COLLISION_TOLERANCE) {
|
||||||
offset = Math.min(min - max, offset);
|
offset = Math.min(min - max, offset);
|
||||||
}
|
}
|
||||||
} else if (offset < 0) {
|
} else if (offset < 0) {
|
||||||
double min = axis.choose(otherBoundingBox.getMin());
|
double min = axis.choose(otherBoundingBox.getMin());
|
||||||
double max = axis.choose(getMax().add(boxOffset));
|
double max = axis.choose(getMax().add(xOffset, yOffset, zOffset));
|
||||||
if ((min - max) >= -2.0 * CollisionManager.COLLISION_TOLERANCE) {
|
if ((min - max) >= -2.0 * CollisionManager.COLLISION_TOLERANCE) {
|
||||||
offset = Math.max(max - min, offset);
|
offset = Math.max(max - min, offset);
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,13 +42,12 @@ import org.geysermc.connector.network.session.cache.PistonCache;
|
||||||
import org.geysermc.connector.network.translators.collision.translators.BlockCollision;
|
import org.geysermc.connector.network.translators.collision.translators.BlockCollision;
|
||||||
import org.geysermc.connector.network.translators.collision.translators.ScaffoldingCollision;
|
import org.geysermc.connector.network.translators.collision.translators.ScaffoldingCollision;
|
||||||
import org.geysermc.connector.network.translators.world.block.BlockStateValues;
|
import org.geysermc.connector.network.translators.world.block.BlockStateValues;
|
||||||
|
import org.geysermc.connector.utils.BlockPositionIterator;
|
||||||
import org.geysermc.connector.utils.BlockUtils;
|
import org.geysermc.connector.utils.BlockUtils;
|
||||||
import org.geysermc.connector.utils.Axis;
|
import org.geysermc.connector.utils.Axis;
|
||||||
|
|
||||||
import java.text.DecimalFormat;
|
import java.text.DecimalFormat;
|
||||||
import java.text.DecimalFormatSymbols;
|
import java.text.DecimalFormatSymbols;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
||||||
public class CollisionManager {
|
public class CollisionManager {
|
||||||
|
@ -133,6 +132,7 @@ public class CollisionManager {
|
||||||
*
|
*
|
||||||
* @param bedrockPosition the current Bedrock position of the client
|
* @param bedrockPosition the current Bedrock position of the client
|
||||||
* @param onGround whether the Bedrock player is on the ground
|
* @param onGround whether the Bedrock player is on the ground
|
||||||
|
* @param teleported whether the Bedrock player has teleported to a new position. If true, movement correction is skipped.
|
||||||
* @return the position to send to the Java server, or null to cancel sending the packet
|
* @return the position to send to the Java server, or null to cancel sending the packet
|
||||||
*/
|
*/
|
||||||
public Vector3d adjustBedrockPosition(Vector3f bedrockPosition, boolean onGround, boolean teleported) {
|
public Vector3d adjustBedrockPosition(Vector3f bedrockPosition, boolean onGround, boolean teleported) {
|
||||||
|
@ -201,9 +201,7 @@ public class CollisionManager {
|
||||||
session.sendUpstreamPacket(movePlayerPacket);
|
session.sendUpstreamPacket(movePlayerPacket);
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Vector3i> getCollidableBlocks(BoundingBox box) {
|
public BlockPositionIterator collidableBlocksIterator(BoundingBox box) {
|
||||||
List<Vector3i> blocks = new ArrayList<>();
|
|
||||||
|
|
||||||
Vector3d position = Vector3d.from(box.getMiddleX(),
|
Vector3d position = Vector3d.from(box.getMiddleX(),
|
||||||
box.getMiddleY() - (box.getSizeY() / 2),
|
box.getMiddleY() - (box.getSizeY() / 2),
|
||||||
box.getMiddleZ());
|
box.getMiddleZ());
|
||||||
|
@ -211,42 +209,28 @@ public class CollisionManager {
|
||||||
// Expand volume by 1 in each direction to include moving blocks
|
// Expand volume by 1 in each direction to include moving blocks
|
||||||
double pistonExpand = session.getPistonCache().getPistons().isEmpty() ? 0 : 1;
|
double pistonExpand = session.getPistonCache().getPistons().isEmpty() ? 0 : 1;
|
||||||
|
|
||||||
// Ensure sizes cannot be too large - https://github.com/GeyserMC/Geyser/issues/2540
|
|
||||||
double sizeX = Math.min(box.getSizeX(), 256);
|
|
||||||
double sizeY = Math.min(box.getSizeY(), 256);
|
|
||||||
double sizeZ = Math.min(box.getSizeZ(), 256);
|
|
||||||
|
|
||||||
// Loop through all blocks that could collide
|
// Loop through all blocks that could collide
|
||||||
int minCollisionX = (int) Math.floor(position.getX() - ((sizeX / 2) + COLLISION_TOLERANCE + pistonExpand));
|
int minCollisionX = (int) Math.floor(position.getX() - ((box.getSizeX() / 2) + COLLISION_TOLERANCE + pistonExpand));
|
||||||
int maxCollisionX = (int) Math.floor(position.getX() + (sizeX / 2) + COLLISION_TOLERANCE + pistonExpand);
|
int maxCollisionX = (int) Math.floor(position.getX() + (box.getSizeX() / 2) + COLLISION_TOLERANCE + pistonExpand);
|
||||||
|
|
||||||
// Y extends 0.5 blocks down because of fence hitboxes
|
// Y extends 0.5 blocks down because of fence hitboxes
|
||||||
int minCollisionY = (int) Math.floor(position.getY() - 0.5 - COLLISION_TOLERANCE - pistonExpand / 2.0);
|
int minCollisionY = (int) Math.floor(position.getY() - 0.5 - COLLISION_TOLERANCE - pistonExpand / 2.0);
|
||||||
|
int maxCollisionY = (int) Math.floor(position.getY() + box.getSizeY() + pistonExpand);
|
||||||
|
|
||||||
int maxCollisionY = (int) Math.floor(position.getY() + sizeY + pistonExpand);
|
int minCollisionZ = (int) Math.floor(position.getZ() - ((box.getSizeZ() / 2) + COLLISION_TOLERANCE + pistonExpand));
|
||||||
|
int maxCollisionZ = (int) Math.floor(position.getZ() + (box.getSizeZ() / 2) + COLLISION_TOLERANCE + pistonExpand);
|
||||||
|
|
||||||
int minCollisionZ = (int) Math.floor(position.getZ() - ((sizeZ / 2) + COLLISION_TOLERANCE + pistonExpand));
|
return new BlockPositionIterator(minCollisionX, minCollisionY, minCollisionZ, maxCollisionX, maxCollisionY, maxCollisionZ);
|
||||||
int maxCollisionZ = (int) Math.floor(position.getZ() + (sizeZ / 2) + COLLISION_TOLERANCE + pistonExpand);
|
|
||||||
|
|
||||||
for (int y = minCollisionY; y < maxCollisionY + 1; y++) {
|
|
||||||
for (int x = minCollisionX; x < maxCollisionX + 1; x++) {
|
|
||||||
for (int z = minCollisionZ; z < maxCollisionZ + 1; z++) {
|
|
||||||
blocks.add(Vector3i.from(x, y, z));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return blocks;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Vector3i> getPlayerCollidableBlocks() {
|
public BlockPositionIterator playerCollidableBlocksIterator() {
|
||||||
return getCollidableBlocks(playerBoundingBox);
|
return collidableBlocksIterator(playerBoundingBox);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns false if the movement is invalid, and in this case it shouldn't be sent to the server and should be
|
* Returns false if the movement is invalid, and in this case it shouldn't be sent to the server and should be
|
||||||
* cancelled
|
* cancelled
|
||||||
* See {@link BlockCollision#correctPosition(GeyserSession, BoundingBox)} for more info
|
* See {@link BlockCollision#correctPosition(GeyserSession, int, int, int, BoundingBox)} for more info
|
||||||
*/
|
*/
|
||||||
public boolean correctPlayerPosition() {
|
public boolean correctPlayerPosition() {
|
||||||
|
|
||||||
|
@ -254,25 +238,22 @@ public class CollisionManager {
|
||||||
touchingScaffolding = false;
|
touchingScaffolding = false;
|
||||||
onScaffolding = false;
|
onScaffolding = false;
|
||||||
|
|
||||||
List<Vector3i> collidableBlocks = getPlayerCollidableBlocks();
|
|
||||||
|
|
||||||
// Used when correction code needs to be run before the main correction
|
// Used when correction code needs to be run before the main correction
|
||||||
for (Vector3i blockPos : collidableBlocks) {
|
BlockPositionIterator iter = session.getCollisionManager().playerCollidableBlocksIterator();
|
||||||
BlockCollision blockCollision = BlockUtils.getCollisionAt(session, blockPos);
|
for (; iter.hasNext(); iter.next()) {
|
||||||
|
BlockCollision blockCollision = BlockUtils.getCollisionAt(session, iter.getX(), iter.getY(), iter.getZ());
|
||||||
if (blockCollision != null) {
|
if (blockCollision != null) {
|
||||||
blockCollision.beforeCorrectPosition(playerBoundingBox);
|
blockCollision.beforeCorrectPosition(iter.getX(), iter.getY(), iter.getZ(), playerBoundingBox);
|
||||||
blockCollision.reset();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Main correction code
|
// Main correction code
|
||||||
for (Vector3i blockPos : collidableBlocks) {
|
for (iter.reset(); iter.hasNext(); iter.next()) {
|
||||||
BlockCollision blockCollision = BlockUtils.getCollisionAt(session, blockPos);
|
BlockCollision blockCollision = BlockUtils.getCollisionAt(session, iter.getX(), iter.getY(), iter.getZ());
|
||||||
if (blockCollision != null) {
|
if (blockCollision != null) {
|
||||||
if (!blockCollision.correctPosition(session, playerBoundingBox)) {
|
if (!blockCollision.correctPosition(session, iter.getX(), iter.getY(), iter.getZ(), playerBoundingBox)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
blockCollision.reset();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -341,24 +322,22 @@ public class CollisionManager {
|
||||||
|
|
||||||
BoundingBox movementBoundingBox = boundingBox.clone();
|
BoundingBox movementBoundingBox = boundingBox.clone();
|
||||||
movementBoundingBox.extend(movement);
|
movementBoundingBox.extend(movement);
|
||||||
|
BlockPositionIterator iter = collidableBlocksIterator(movementBoundingBox);
|
||||||
List<Vector3i> collidableBlocks = getCollidableBlocks(movementBoundingBox);
|
|
||||||
|
|
||||||
if (Math.abs(movementY) > CollisionManager.COLLISION_TOLERANCE) {
|
if (Math.abs(movementY) > CollisionManager.COLLISION_TOLERANCE) {
|
||||||
movementY = computeCollisionOffset(boundingBox, Axis.Y, movementY, collidableBlocks, checkWorld);
|
movementY = computeCollisionOffset(boundingBox, Axis.Y, movementY, iter, checkWorld);
|
||||||
boundingBox.translate(0, movementY, 0);
|
boundingBox.translate(0, movementY, 0);
|
||||||
}
|
}
|
||||||
boolean checkZFirst = Math.abs(movementZ) > Math.abs(movementX);
|
boolean checkZFirst = Math.abs(movementZ) > Math.abs(movementX);
|
||||||
if (checkZFirst && Math.abs(movementZ) > CollisionManager.COLLISION_TOLERANCE) {
|
if (checkZFirst && Math.abs(movementZ) > CollisionManager.COLLISION_TOLERANCE) {
|
||||||
movementZ = computeCollisionOffset(boundingBox, Axis.Z, movementZ, collidableBlocks, checkWorld);
|
movementZ = computeCollisionOffset(boundingBox, Axis.Z, movementZ, iter, checkWorld);
|
||||||
boundingBox.translate(0, 0, movementZ);
|
boundingBox.translate(0, 0, movementZ);
|
||||||
}
|
}
|
||||||
if (Math.abs(movementX) > CollisionManager.COLLISION_TOLERANCE) {
|
if (Math.abs(movementX) > CollisionManager.COLLISION_TOLERANCE) {
|
||||||
movementX = computeCollisionOffset(boundingBox, Axis.X, movementX, collidableBlocks, checkWorld);
|
movementX = computeCollisionOffset(boundingBox, Axis.X, movementX, iter, checkWorld);
|
||||||
boundingBox.translate(movementX, 0, 0);
|
boundingBox.translate(movementX, 0, 0);
|
||||||
}
|
}
|
||||||
if (!checkZFirst && Math.abs(movementZ) > CollisionManager.COLLISION_TOLERANCE) {
|
if (!checkZFirst && Math.abs(movementZ) > CollisionManager.COLLISION_TOLERANCE) {
|
||||||
movementZ = computeCollisionOffset(boundingBox, Axis.Z, movementZ, collidableBlocks, checkWorld);
|
movementZ = computeCollisionOffset(boundingBox, Axis.Z, movementZ, iter, checkWorld);
|
||||||
boundingBox.translate(0, 0, movementZ);
|
boundingBox.translate(0, 0, movementZ);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -366,16 +345,18 @@ public class CollisionManager {
|
||||||
return Vector3d.from(movementX, movementY, movementZ);
|
return Vector3d.from(movementX, movementY, movementZ);
|
||||||
}
|
}
|
||||||
|
|
||||||
private double computeCollisionOffset(BoundingBox boundingBox, Axis axis, double offset, List<Vector3i> collidableBlocks, boolean checkWorld) {
|
private double computeCollisionOffset(BoundingBox boundingBox, Axis axis, double offset, BlockPositionIterator iter, boolean checkWorld) {
|
||||||
for (Vector3i blockPos : collidableBlocks) {
|
for (iter.reset(); iter.hasNext(); iter.next()) {
|
||||||
|
int x = iter.getX();
|
||||||
|
int y = iter.getY();
|
||||||
|
int z = iter.getZ();
|
||||||
if (checkWorld) {
|
if (checkWorld) {
|
||||||
BlockCollision blockCollision = BlockUtils.getCollisionAt(session, blockPos);
|
BlockCollision blockCollision = BlockUtils.getCollisionAt(session, x, y, z);
|
||||||
if (blockCollision != null && !(blockCollision instanceof ScaffoldingCollision)) {
|
if (blockCollision != null && !(blockCollision instanceof ScaffoldingCollision)) {
|
||||||
offset = blockCollision.computeCollisionOffset(boundingBox, axis, offset);
|
offset = blockCollision.computeCollisionOffset(x, y, z, boundingBox, axis, offset);
|
||||||
blockCollision.reset();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
offset = session.getPistonCache().computeCollisionOffset(blockPos, boundingBox, axis, offset);
|
offset = session.getPistonCache().computeCollisionOffset(Vector3i.from(x, y, z), boundingBox, axis, offset);
|
||||||
if (Math.abs(offset) < COLLISION_TOLERANCE) {
|
if (Math.abs(offset) < COLLISION_TOLERANCE) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -399,9 +380,8 @@ public class CollisionManager {
|
||||||
|
|
||||||
playerBoundingBox.setSizeY(EntityType.PLAYER.getHeight());
|
playerBoundingBox.setSizeY(EntityType.PLAYER.getHeight());
|
||||||
playerBoundingBox.setMiddleY(standingY);
|
playerBoundingBox.setMiddleY(standingY);
|
||||||
boolean result = collision.checkIntersection(playerBoundingBox);
|
boolean result = collision.checkIntersection(position, playerBoundingBox);
|
||||||
result |= session.getPistonCache().checkCollision(position, playerBoundingBox);
|
result |= session.getPistonCache().checkCollision(position, playerBoundingBox);
|
||||||
collision.reset();
|
|
||||||
playerBoundingBox.setSizeY(originalHeight);
|
playerBoundingBox.setSizeY(originalHeight);
|
||||||
playerBoundingBox.setMiddleY(originalY);
|
playerBoundingBox.setMiddleY(originalY);
|
||||||
return result;
|
return result;
|
||||||
|
|
|
@ -40,16 +40,6 @@ public class BlockCollision {
|
||||||
@Getter
|
@Getter
|
||||||
protected final BoundingBox[] boundingBoxes;
|
protected final BoundingBox[] boundingBoxes;
|
||||||
|
|
||||||
@EqualsAndHashCode.Exclude
|
|
||||||
protected final ThreadLocal<Vector3i> position;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Store a Vector3d to allow the collision to be offset by a fractional amount
|
|
||||||
* This is used only in {@link #checkIntersection(BoundingBox)} and {@link #computeCollisionOffset(BoundingBox, Axis, double)}
|
|
||||||
*/
|
|
||||||
@EqualsAndHashCode.Exclude
|
|
||||||
protected final ThreadLocal<Vector3d> positionOffset;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is used for the step up logic.
|
* This is used for the step up logic.
|
||||||
* Usually, the player can only step up a block if they are on the same Y level as its bottom face or higher
|
* Usually, the player can only step up a block if they are on the same Y level as its bottom face or higher
|
||||||
|
@ -68,28 +58,13 @@ public class BlockCollision {
|
||||||
|
|
||||||
protected BlockCollision(BoundingBox[] boxes) {
|
protected BlockCollision(BoundingBox[] boxes) {
|
||||||
this.boundingBoxes = boxes;
|
this.boundingBoxes = boxes;
|
||||||
this.position = new ThreadLocal<>();
|
|
||||||
this.positionOffset = new ThreadLocal<>();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setPosition(Vector3i newPosition) {
|
|
||||||
this.position.set(newPosition);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setPositionOffset(Vector3d newOffset) {
|
|
||||||
this.positionOffset.set(newOffset);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void reset() {
|
|
||||||
this.position.set(null);
|
|
||||||
this.positionOffset.set(null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Overridden in classes like SnowCollision and GrassPathCollision when correction code needs to be run before the
|
* Overridden in classes like SnowCollision and GrassPathCollision when correction code needs to be run before the
|
||||||
* main correction
|
* main correction
|
||||||
*/
|
*/
|
||||||
public void beforeCorrectPosition(BoundingBox playerCollision) {}
|
public void beforeCorrectPosition(int x, int y, int z, BoundingBox playerCollision) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns false if the movement is invalid, and in this case it shouldn't be sent to the server and should be
|
* Returns false if the movement is invalid, and in this case it shouldn't be sent to the server and should be
|
||||||
|
@ -97,12 +72,7 @@ public class BlockCollision {
|
||||||
* While the Java server should do this, it could result in false flags by anticheat
|
* While the Java server should do this, it could result in false flags by anticheat
|
||||||
* This functionality is currently only used in 6 or 7 layer snow
|
* This functionality is currently only used in 6 or 7 layer snow
|
||||||
*/
|
*/
|
||||||
public boolean correctPosition(GeyserSession session, BoundingBox playerCollision) {
|
public boolean correctPosition(GeyserSession session, int x, int y, int z, BoundingBox playerCollision) {
|
||||||
Vector3i blockPos = this.position.get();
|
|
||||||
int x = blockPos.getX();
|
|
||||||
int y = blockPos.getY();
|
|
||||||
int z = blockPos.getZ();
|
|
||||||
|
|
||||||
double playerMinY = playerCollision.getMiddleY() - (playerCollision.getSizeY() / 2);
|
double playerMinY = playerCollision.getMiddleY() - (playerCollision.getSizeY() / 2);
|
||||||
for (BoundingBox b : this.boundingBoxes) {
|
for (BoundingBox b : this.boundingBoxes) {
|
||||||
double boxMinY = (b.getMiddleY() + y) - (b.getSizeY() / 2);
|
double boxMinY = (b.getMiddleY() + y) - (b.getSizeY() / 2);
|
||||||
|
@ -174,29 +144,22 @@ public class BlockCollision {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Vector3d getFullPos() {
|
public boolean checkIntersection(double x, double y, double z, BoundingBox playerCollision) {
|
||||||
Vector3i blockPos = this.position.get();
|
|
||||||
Vector3d blockOffset = this.positionOffset.get();
|
|
||||||
if (blockOffset != null && blockOffset != Vector3d.ZERO) {
|
|
||||||
return blockOffset.add(blockPos.getX(), blockPos.getY(), blockPos.getZ());
|
|
||||||
}
|
|
||||||
return blockPos.toDouble();
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean checkIntersection(BoundingBox playerCollision) {
|
|
||||||
Vector3d blockPos = getFullPos();
|
|
||||||
for (BoundingBox b : boundingBoxes) {
|
for (BoundingBox b : boundingBoxes) {
|
||||||
if (b.checkIntersection(blockPos, playerCollision)) {
|
if (b.checkIntersection(x, y, z, playerCollision)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public double computeCollisionOffset(BoundingBox boundingBox, Axis axis, double offset) {
|
public boolean checkIntersection(Vector3i position, BoundingBox playerCollision) {
|
||||||
Vector3d blockPos = getFullPos();
|
return checkIntersection(position.getX(), position.getY(), position.getZ(), playerCollision);
|
||||||
|
}
|
||||||
|
|
||||||
|
public double computeCollisionOffset(double x, double y, double z, BoundingBox boundingBox, Axis axis, double offset) {
|
||||||
for (BoundingBox b : boundingBoxes) {
|
for (BoundingBox b : boundingBoxes) {
|
||||||
offset = b.getMaxOffset(blockPos, boundingBox, axis, offset);
|
offset = b.getMaxOffset(x, y, z, boundingBox, axis, offset);
|
||||||
if (Math.abs(offset) < CollisionManager.COLLISION_TOLERANCE) {
|
if (Math.abs(offset) < CollisionManager.COLLISION_TOLERANCE) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,10 +40,10 @@ public class DirtPathCollision extends BlockCollision {
|
||||||
// Needs to run before the main correction code or it can move the player into blocks
|
// Needs to run before the main correction code or it can move the player into blocks
|
||||||
// This is counteracted by the main collision code pushing them out
|
// This is counteracted by the main collision code pushing them out
|
||||||
@Override
|
@Override
|
||||||
public void beforeCorrectPosition(BoundingBox playerCollision) {
|
public void beforeCorrectPosition(int x, int y, int z, BoundingBox playerCollision) {
|
||||||
// In Bedrock, dirt paths are solid blocks, so the player must be pushed down.
|
// In Bedrock, dirt paths are solid blocks, so the player must be pushed down.
|
||||||
double playerMinY = playerCollision.getMiddleY() - (playerCollision.getSizeY() / 2);
|
double playerMinY = playerCollision.getMiddleY() - (playerCollision.getSizeY() / 2);
|
||||||
double blockMaxY = position.get().getY() + 1;
|
double blockMaxY = y + 1;
|
||||||
if (Math.abs(blockMaxY - playerMinY) <= CollisionManager.COLLISION_TOLERANCE) {
|
if (Math.abs(blockMaxY - playerMinY) <= CollisionManager.COLLISION_TOLERANCE) {
|
||||||
playerCollision.translate(0, -0.0625, 0);
|
playerCollision.translate(0, -0.0625, 0);
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,19 +61,15 @@ public class DoorCollision extends BlockCollision {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean correctPosition(GeyserSession session, BoundingBox playerCollision) {
|
public boolean correctPosition(GeyserSession session, int x, int y, int z, BoundingBox playerCollision) {
|
||||||
boolean result = super.correctPosition(session, playerCollision);
|
boolean result = super.correctPosition(session, x, y, z, playerCollision);
|
||||||
// Hack to prevent false positives
|
// Hack to prevent false positives
|
||||||
playerCollision.setSizeX(playerCollision.getSizeX() - 0.0001);
|
playerCollision.setSizeX(playerCollision.getSizeX() - 0.0001);
|
||||||
playerCollision.setSizeY(playerCollision.getSizeY() - 0.0001);
|
playerCollision.setSizeY(playerCollision.getSizeY() - 0.0001);
|
||||||
playerCollision.setSizeZ(playerCollision.getSizeZ() - 0.0001);
|
playerCollision.setSizeZ(playerCollision.getSizeZ() - 0.0001);
|
||||||
|
|
||||||
// Check for door bug (doors are 0.1875 blocks thick on Java but 0.1825 blocks thick on Bedrock)
|
// Check for door bug (doors are 0.1875 blocks thick on Java but 0.1825 blocks thick on Bedrock)
|
||||||
if (this.checkIntersection(playerCollision)) {
|
if (this.checkIntersection(x, y, z, playerCollision)) {
|
||||||
Vector3i blockPos = this.position.get();
|
|
||||||
int x = blockPos.getX();
|
|
||||||
int z = blockPos.getZ();
|
|
||||||
|
|
||||||
switch (facing) {
|
switch (facing) {
|
||||||
case 1 -> playerCollision.setMiddleZ(z + 0.5125); // North
|
case 1 -> playerCollision.setMiddleZ(z + 0.5125); // North
|
||||||
case 2 -> playerCollision.setMiddleX(x + 0.5125); // East
|
case 2 -> playerCollision.setMiddleX(x + 0.5125); // East
|
||||||
|
|
|
@ -41,12 +41,12 @@ public class ScaffoldingCollision extends BlockCollision {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean correctPosition(GeyserSession session, BoundingBox playerCollision) {
|
public boolean correctPosition(GeyserSession session, int x, int y, int z, BoundingBox playerCollision) {
|
||||||
// Hack to not check below the player
|
// Hack to not check below the player
|
||||||
playerCollision.setSizeY(playerCollision.getSizeY() - 0.001);
|
playerCollision.setSizeY(playerCollision.getSizeY() - 0.001);
|
||||||
playerCollision.setMiddleY(playerCollision.getMiddleY() + 0.002);
|
playerCollision.setMiddleY(playerCollision.getMiddleY() + 0.002);
|
||||||
|
|
||||||
boolean intersected = this.checkIntersection(playerCollision);
|
boolean intersected = this.checkIntersection(x, y, z, playerCollision);
|
||||||
|
|
||||||
playerCollision.setSizeY(playerCollision.getSizeY() + 0.001);
|
playerCollision.setSizeY(playerCollision.getSizeY() + 0.001);
|
||||||
playerCollision.setMiddleY(playerCollision.getMiddleY() - 0.002);
|
playerCollision.setMiddleY(playerCollision.getMiddleY() - 0.002);
|
||||||
|
@ -59,7 +59,7 @@ public class ScaffoldingCollision extends BlockCollision {
|
||||||
playerCollision.setSizeY(playerCollision.getSizeY() + 0.001);
|
playerCollision.setSizeY(playerCollision.getSizeY() + 0.001);
|
||||||
playerCollision.setMiddleY(playerCollision.getMiddleY() - 0.002);
|
playerCollision.setMiddleY(playerCollision.getMiddleY() - 0.002);
|
||||||
|
|
||||||
if (this.checkIntersection(playerCollision)) {
|
if (this.checkIntersection(x, y, z, playerCollision)) {
|
||||||
session.getCollisionManager().setOnScaffolding(true);
|
session.getCollisionManager().setOnScaffolding(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -46,13 +46,13 @@ public class SnowCollision extends BlockCollision {
|
||||||
// Needs to run before the main correction code or it can move the player into blocks
|
// Needs to run before the main correction code or it can move the player into blocks
|
||||||
// This is counteracted by the main collision code pushing them out
|
// This is counteracted by the main collision code pushing them out
|
||||||
@Override
|
@Override
|
||||||
public void beforeCorrectPosition(BoundingBox playerCollision) {
|
public void beforeCorrectPosition(int x, int y, int z, BoundingBox playerCollision) {
|
||||||
// In Bedrock, snow layers round down to half blocks but you can't sink into them at all
|
// In Bedrock, snow layers round down to half blocks but you can't sink into them at all
|
||||||
// This means the collision each half block reaches above where it should be on Java so the player has to be
|
// This means the collision each half block reaches above where it should be on Java so the player has to be
|
||||||
// pushed down
|
// pushed down
|
||||||
if (layers == 4 || layers == 8) {
|
if (layers == 4 || layers == 8) {
|
||||||
double playerMinY = playerCollision.getMiddleY() - (playerCollision.getSizeY() / 2);
|
double playerMinY = playerCollision.getMiddleY() - (playerCollision.getSizeY() / 2);
|
||||||
double boxMaxY = (boundingBoxes[0].getMiddleY() + position.get().getY()) + (boundingBoxes[0].getSizeY() / 2);
|
double boxMaxY = (boundingBoxes[0].getMiddleY() + y) + (boundingBoxes[0].getSizeY() / 2);
|
||||||
// If the player is in the buggy area, push them down
|
// If the player is in the buggy area, push them down
|
||||||
if (playerMinY > boxMaxY &&
|
if (playerMinY > boxMaxY &&
|
||||||
playerMinY <= (boxMaxY + 0.125)) {
|
playerMinY <= (boxMaxY + 0.125)) {
|
||||||
|
@ -62,7 +62,7 @@ public class SnowCollision extends BlockCollision {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean correctPosition(GeyserSession session, BoundingBox playerCollision) {
|
public boolean correctPosition(GeyserSession session, int x, int y, int z, BoundingBox playerCollision) {
|
||||||
if (layers == 1) {
|
if (layers == 1) {
|
||||||
// 1 layer of snow does not have collision
|
// 1 layer of snow does not have collision
|
||||||
return true;
|
return true;
|
||||||
|
@ -72,9 +72,9 @@ public class SnowCollision extends BlockCollision {
|
||||||
playerCollision.setSizeY(playerCollision.getSizeY() - 0.0001);
|
playerCollision.setSizeY(playerCollision.getSizeY() - 0.0001);
|
||||||
playerCollision.setSizeZ(playerCollision.getSizeZ() - 0.0001);
|
playerCollision.setSizeZ(playerCollision.getSizeZ() - 0.0001);
|
||||||
|
|
||||||
if (this.checkIntersection(playerCollision)) {
|
if (this.checkIntersection(x, y, z, playerCollision)) {
|
||||||
double playerMinY = playerCollision.getMiddleY() - (playerCollision.getSizeY() / 2);
|
double playerMinY = playerCollision.getMiddleY() - (playerCollision.getSizeY() / 2);
|
||||||
double boxMaxY = (boundingBoxes[0].getMiddleY() + position.get().getY()) + (boundingBoxes[0].getSizeY() / 2);
|
double boxMaxY = (boundingBoxes[0].getMiddleY() + y) + (boundingBoxes[0].getSizeY() / 2);
|
||||||
// If the player actually can't step onto it (they can step onto it from other snow layers)
|
// If the player actually can't step onto it (they can step onto it from other snow layers)
|
||||||
if ((boxMaxY - playerMinY) > 0.5) {
|
if ((boxMaxY - playerMinY) > 0.5) {
|
||||||
// Cancel the movement
|
// Cancel the movement
|
||||||
|
@ -85,6 +85,6 @@ public class SnowCollision extends BlockCollision {
|
||||||
playerCollision.setSizeX(playerCollision.getSizeX() + 0.0001);
|
playerCollision.setSizeX(playerCollision.getSizeX() + 0.0001);
|
||||||
playerCollision.setSizeY(playerCollision.getSizeY() + 0.0001);
|
playerCollision.setSizeY(playerCollision.getSizeY() + 0.0001);
|
||||||
playerCollision.setSizeZ(playerCollision.getSizeZ() + 0.0001);
|
playerCollision.setSizeZ(playerCollision.getSizeZ() + 0.0001);
|
||||||
return super.correctPosition(session, playerCollision);
|
return super.correctPosition(session, x, y, z, playerCollision);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,7 +25,6 @@
|
||||||
|
|
||||||
package org.geysermc.connector.network.translators.collision.translators;
|
package org.geysermc.connector.network.translators.collision.translators;
|
||||||
|
|
||||||
import com.nukkitx.math.vector.Vector3i;
|
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
import org.geysermc.connector.network.session.GeyserSession;
|
import org.geysermc.connector.network.session.GeyserSession;
|
||||||
import org.geysermc.connector.network.translators.collision.BoundingBox;
|
import org.geysermc.connector.network.translators.collision.BoundingBox;
|
||||||
|
@ -69,15 +68,10 @@ public class TrapdoorCollision extends BlockCollision {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean correctPosition(GeyserSession session, BoundingBox playerCollision) {
|
public boolean correctPosition(GeyserSession session, int x, int y, int z, BoundingBox playerCollision) {
|
||||||
boolean result = super.correctPosition(session, playerCollision);
|
boolean result = super.correctPosition(session, x, y, z, playerCollision);
|
||||||
// Check for door bug (doors are 0.1875 blocks thick on Java but 0.1825 blocks thick on Bedrock)
|
// Check for door bug (doors are 0.1875 blocks thick on Java but 0.1825 blocks thick on Bedrock)
|
||||||
if (this.checkIntersection(playerCollision)) {
|
if (this.checkIntersection(x, y, z, playerCollision)) {
|
||||||
Vector3i blockPos = this.position.get();
|
|
||||||
int x = blockPos.getX();
|
|
||||||
int y = blockPos.getY();
|
|
||||||
int z = blockPos.getZ();
|
|
||||||
|
|
||||||
switch (facing) {
|
switch (facing) {
|
||||||
case 1: // North
|
case 1: // North
|
||||||
playerCollision.setMiddleZ(z + 0.5125);
|
playerCollision.setMiddleZ(z + 0.5125);
|
||||||
|
|
|
@ -526,16 +526,7 @@ public class PistonBlockEntity {
|
||||||
}
|
}
|
||||||
|
|
||||||
private BlockCollision getCollision(Vector3i blockPos) {
|
private BlockCollision getCollision(Vector3i blockPos) {
|
||||||
int blockId = getAttachedBlockId(blockPos);
|
return BlockUtils.getCollision(getAttachedBlockId(blockPos));
|
||||||
if (blockId != BlockStateValues.JAVA_AIR_ID) {
|
|
||||||
double movementProgress = progress;
|
|
||||||
if (action == PistonValueType.PULLING || action == PistonValueType.CANCELLED_MID_PUSH) {
|
|
||||||
movementProgress = 1f - progress;
|
|
||||||
}
|
|
||||||
Vector3d offset = getMovement().toDouble().mul(movementProgress);
|
|
||||||
return BlockUtils.getCollision(blockId, blockPos, offset);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -550,8 +541,15 @@ public class PistonBlockEntity {
|
||||||
public double computeCollisionOffset(Vector3i blockPos, BoundingBox boundingBox, Axis axis, double movement) {
|
public double computeCollisionOffset(Vector3i blockPos, BoundingBox boundingBox, Axis axis, double movement) {
|
||||||
BlockCollision blockCollision = getCollision(blockPos);
|
BlockCollision blockCollision = getCollision(blockPos);
|
||||||
if (blockCollision != null) {
|
if (blockCollision != null) {
|
||||||
double adjustedMovement = blockCollision.computeCollisionOffset(boundingBox, axis, movement);
|
double movementProgress = progress;
|
||||||
blockCollision.reset();
|
if (action == PistonValueType.PULLING || action == PistonValueType.CANCELLED_MID_PUSH) {
|
||||||
|
movementProgress = 1f - progress;
|
||||||
|
}
|
||||||
|
Vector3i movementVec = getMovement();
|
||||||
|
double x = blockPos.getX() + movementVec.getX() * movementProgress;
|
||||||
|
double y = blockPos.getY() + movementVec.getY() * movementProgress;
|
||||||
|
double z = blockPos.getZ() + movementVec.getZ() * movementProgress;
|
||||||
|
double adjustedMovement = blockCollision.computeCollisionOffset(x, y, z, boundingBox, axis, movement);
|
||||||
if (getAttachedBlockId(blockPos) == BlockStateValues.JAVA_SLIME_BLOCK_ID && adjustedMovement != movement) {
|
if (getAttachedBlockId(blockPos) == BlockStateValues.JAVA_SLIME_BLOCK_ID && adjustedMovement != movement) {
|
||||||
session.getPistonCache().setPlayerSlimeCollision(true);
|
session.getPistonCache().setPlayerSlimeCollision(true);
|
||||||
}
|
}
|
||||||
|
@ -563,9 +561,15 @@ public class PistonBlockEntity {
|
||||||
public boolean checkCollision(Vector3i blockPos, BoundingBox boundingBox) {
|
public boolean checkCollision(Vector3i blockPos, BoundingBox boundingBox) {
|
||||||
BlockCollision blockCollision = getCollision(blockPos);
|
BlockCollision blockCollision = getCollision(blockPos);
|
||||||
if (blockCollision != null) {
|
if (blockCollision != null) {
|
||||||
boolean result = blockCollision.checkIntersection(boundingBox);
|
double movementProgress = progress;
|
||||||
blockCollision.reset();
|
if (action == PistonValueType.PULLING || action == PistonValueType.CANCELLED_MID_PUSH) {
|
||||||
return result;
|
movementProgress = 1f - progress;
|
||||||
|
}
|
||||||
|
Vector3i movementVec = getMovement();
|
||||||
|
double x = blockPos.getX() + movementVec.getX() * movementProgress;
|
||||||
|
double y = blockPos.getY() + movementVec.getY() * movementProgress;
|
||||||
|
double z = blockPos.getZ() + movementVec.getZ() * movementProgress;
|
||||||
|
return blockCollision.checkIntersection(x, y, z, boundingBox);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,82 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*
|
||||||
|
* @author GeyserMC
|
||||||
|
* @link https://github.com/GeyserMC/Geyser
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.geysermc.connector.utils;
|
||||||
|
|
||||||
|
import com.nukkitx.network.util.Preconditions;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
|
||||||
|
public class BlockPositionIterator {
|
||||||
|
private final int minX;
|
||||||
|
private final int minY;
|
||||||
|
private final int minZ;
|
||||||
|
|
||||||
|
private final int sizeX;
|
||||||
|
private final int sizeZ;
|
||||||
|
|
||||||
|
private int i = 0;
|
||||||
|
private final int maxI;
|
||||||
|
|
||||||
|
public BlockPositionIterator(int minX, int minY, int minZ, int maxX, int maxY, int maxZ) {
|
||||||
|
Preconditions.checkArgument(maxX >= minX, "maxX is not greater than or equal to minX");
|
||||||
|
Preconditions.checkArgument(maxY >= minY, "maxY is not greater than or equal to minY");
|
||||||
|
Preconditions.checkArgument(maxZ >= minZ, "maxZ is not greater than or equal to minZ");
|
||||||
|
|
||||||
|
this.minX = minX;
|
||||||
|
this.minY = minY;
|
||||||
|
this.minZ = minZ;
|
||||||
|
|
||||||
|
this.sizeX = maxX - minX + 1;
|
||||||
|
int sizeY = maxY - minY + 1;
|
||||||
|
this.sizeZ = maxZ - minZ + 1;
|
||||||
|
this.maxI = sizeX * sizeY * sizeZ;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasNext() {
|
||||||
|
return i < maxI;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void next() {
|
||||||
|
// Iterate in zxy order
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void reset() {
|
||||||
|
i = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getX() {
|
||||||
|
return ((i / sizeZ) % sizeX) + minX;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getY() {
|
||||||
|
return (i / sizeZ / sizeX) + minY;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getZ() {
|
||||||
|
return (i % sizeZ) + minZ;
|
||||||
|
}
|
||||||
|
}
|
|
@ -27,7 +27,6 @@ package org.geysermc.connector.utils;
|
||||||
|
|
||||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position;
|
import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position;
|
||||||
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
|
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
|
||||||
import com.nukkitx.math.vector.Vector3d;
|
|
||||||
import com.nukkitx.math.vector.Vector3i;
|
import com.nukkitx.math.vector.Vector3i;
|
||||||
import org.geysermc.connector.inventory.GeyserItemStack;
|
import org.geysermc.connector.inventory.GeyserItemStack;
|
||||||
import org.geysermc.connector.inventory.PlayerInventory;
|
import org.geysermc.connector.inventory.PlayerInventory;
|
||||||
|
@ -231,25 +230,15 @@ public class BlockUtils {
|
||||||
return fullJavaIdentifier.substring(0, stateIndex);
|
return fullJavaIdentifier.substring(0, stateIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static BlockCollision getCollision(int blockId, Vector3i blockPos) {
|
public static BlockCollision getCollision(int blockId) {
|
||||||
BlockCollision collision = Registries.COLLISIONS.get(blockId);
|
return Registries.COLLISIONS.get(blockId);
|
||||||
if (collision != null) {
|
|
||||||
collision.setPosition(blockPos);
|
|
||||||
collision.setPositionOffset(null);
|
|
||||||
}
|
|
||||||
return collision;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static BlockCollision getCollision(int blockId, Vector3i blockPos, Vector3d blockOffset) {
|
|
||||||
BlockCollision collision = Registries.COLLISIONS.get(blockId);
|
|
||||||
if (collision != null) {
|
|
||||||
collision.setPosition(blockPos);
|
|
||||||
collision.setPositionOffset(blockOffset);
|
|
||||||
}
|
|
||||||
return collision;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static BlockCollision getCollisionAt(GeyserSession session, Vector3i blockPos) {
|
public static BlockCollision getCollisionAt(GeyserSession session, Vector3i blockPos) {
|
||||||
return getCollision(session.getConnector().getWorldManager().getBlockAt(session, blockPos), blockPos);
|
return getCollision(session.getConnector().getWorldManager().getBlockAt(session, blockPos));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static BlockCollision getCollisionAt(GeyserSession session, int x, int y, int z) {
|
||||||
|
return getCollision(session.getConnector().getWorldManager().getBlockAt(session, x, y, z));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue