From 2766038db92d2d171d914d2c95c6c37ee933ccb9 Mon Sep 17 00:00:00 2001 From: David Choo Date: Sun, 18 Jul 2021 10:58:08 -0400 Subject: [PATCH] Update player bounding box in more scenarios (#2377) Co-authored-by: Camotoy <20743703+Camotoy@users.noreply.github.com> --- .../connector/entity/player/PlayerEntity.java | 17 +-- .../entity/player/SessionPlayerEntity.java | 17 ++- .../network/session/GeyserSession.java | 6 +- .../player/BedrockMovePlayerTranslator.java | 123 +++++++++--------- .../collision/CollisionManager.java | 36 +++-- .../JavaPlayerPositionRotationTranslator.java | 12 +- 6 files changed, 105 insertions(+), 106 deletions(-) diff --git a/connector/src/main/java/org/geysermc/connector/entity/player/PlayerEntity.java b/connector/src/main/java/org/geysermc/connector/entity/player/PlayerEntity.java index 7b182da38..7c32fa191 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/player/PlayerEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/player/PlayerEntity.java @@ -155,10 +155,6 @@ public class PlayerEntity extends LivingEntity { setRotation(rotation); this.position = Vector3f.from(position.getX() + relX, position.getY() + relY, position.getZ() + relZ); - // If this is the player logged in through this Geyser session - if (geyserId == 1) { - session.getCollisionManager().updatePlayerBoundingBox(position); - } setOnGround(isOnGround); MovePlayerPacket movePlayerPacket = new MovePlayerPacket(); @@ -230,18 +226,7 @@ public class PlayerEntity extends LivingEntity { @Override public void setPosition(Vector3f position) { - setPosition(position, true); - } - - /** - * Set the player position and specify if the entity type's offset should be added. Set to false when the player - * sends us a move packet where the offset is already added - * - * @param position the new position of the Bedrock player - * @param includeOffset whether to include the offset - */ - public void setPosition(Vector3f position, boolean includeOffset) { - this.position = includeOffset ? position.add(0, entityType.getOffset(), 0) : position; + super.setPosition(position.add(0, entityType.getOffset(), 0)); } @Override diff --git a/connector/src/main/java/org/geysermc/connector/entity/player/SessionPlayerEntity.java b/connector/src/main/java/org/geysermc/connector/entity/player/SessionPlayerEntity.java index 65f2baa66..baf07b55d 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/player/SessionPlayerEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/player/SessionPlayerEntity.java @@ -74,9 +74,9 @@ public class SessionPlayerEntity extends PlayerEntity { } @Override - public void moveAbsolute(GeyserSession session, Vector3f position, Vector3f rotation, boolean isOnGround, boolean teleported) { - session.getCollisionManager().updatePlayerBoundingBox(position); - super.moveAbsolute(session, position, rotation, isOnGround, teleported); + public void moveRelative(GeyserSession session, double relX, double relY, double relZ, Vector3f rotation, boolean isOnGround) { + super.moveRelative(session, relX, relY, relZ, rotation, isOnGround); + session.getCollisionManager().updatePlayerBoundingBox(this.position.down(entityType.getOffset())); } @Override @@ -87,6 +87,17 @@ public class SessionPlayerEntity extends PlayerEntity { super.setPosition(position); } + /** + * Set the player's position without applying an offset or moving the bounding box + * This is used in BedrockMovePlayerTranslator which receives the player's position + * with the offset pre-applied + * + * @param position the new position of the Bedrock player + */ + public void setPositionManual(Vector3f position) { + this.position = position; + } + @Override public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) { super.updateBedrockMetadata(entityMetadata, session); diff --git a/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java b/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java index 23f36b5f8..ad2e6d6c6 100644 --- a/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java +++ b/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java @@ -1132,9 +1132,9 @@ public class GeyserSession implements CommandSender { } } - public boolean confirmTeleport(Vector3d position) { + public void confirmTeleport(Vector3d position) { if (teleportMap.size() == 0) { - return true; + return; } int teleportID = -1; @@ -1185,8 +1185,6 @@ public class GeyserSession implements CommandSender { teleport.getYaw(), teleport.getPitch(), playerEntity.isOnGround(), true); } } - - return true; } /** diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/entity/player/BedrockMovePlayerTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/entity/player/BedrockMovePlayerTranslator.java index 45e35a39c..7970dbd16 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/entity/player/BedrockMovePlayerTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/entity/player/BedrockMovePlayerTranslator.java @@ -35,7 +35,7 @@ import com.nukkitx.protocol.bedrock.packet.MoveEntityAbsolutePacket; import com.nukkitx.protocol.bedrock.packet.MovePlayerPacket; import org.geysermc.connector.GeyserConnector; import org.geysermc.connector.common.ChatColor; -import org.geysermc.connector.entity.player.PlayerEntity; +import org.geysermc.connector.entity.player.SessionPlayerEntity; import org.geysermc.connector.entity.type.EntityType; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.PacketTranslator; @@ -54,7 +54,7 @@ public class BedrockMovePlayerTranslator extends PacketTranslator= packet.getPosition().getY(); - - entity.setPosition(packet.getPosition(), false); - entity.setOnGround(packet.isOnGround()); - - // Send final movement changes - session.sendDownstreamPacket(movePacket); - - if (notMovingUp) { - int floorY = position.getFloorY(); - // If the client believes the world has extended height, then it also believes the void floor - // still exists, just at a lower spot - boolean extendedWorld = session.getChunkCache().isExtendedHeight(); - if (floorY <= (extendedWorld ? BEDROCK_OVERWORLD_VOID_FLOOR_LOWER_Y : -38) - && floorY >= (extendedWorld ? BEDROCK_OVERWORLD_VOID_FLOOR_UPPER_Y : -40)) { - // Work around there being a floor at the bottom of the world and teleport the player below it - // Moving from below to above the void floor works fine - entity.setPosition(entity.getPosition().sub(0, 4f, 0)); - MovePlayerPacket movePlayerPacket = new MovePlayerPacket(); - movePlayerPacket.setRuntimeEntityId(entity.getGeyserId()); - movePlayerPacket.setPosition(entity.getPosition()); - movePlayerPacket.setRotation(entity.getBedrockRotation()); - movePlayerPacket.setMode(MovePlayerPacket.Mode.TELEPORT); - movePlayerPacket.setTeleportationCause(MovePlayerPacket.TeleportationCause.BEHAVIOR); - session.sendUpstreamPacket(movePlayerPacket); - } - } + session.sendDownstreamPacket(playerRotationPacket); + } else { + Vector3d position = session.getCollisionManager().adjustBedrockPosition(packet.getPosition(), packet.isOnGround()); + if (position != null) { // A null return value cancels the packet + if (isValidMove(session, packet.getMode(), entity.getPosition(), packet.getPosition())) { + Packet movePacket; + if (rotationChanged) { + // Send rotation updates as well + movePacket = new ClientPlayerPositionRotationPacket(packet.isOnGround(), position.getX(), position.getY(), position.getZ(), + packet.getRotation().getY(), packet.getRotation().getX()); + entity.setRotation(rotation); } else { - // Not a valid move - session.getConnector().getLogger().debug("Recalculating position..."); - session.getCollisionManager().recalculatePosition(); + // Rotation did not change; don't send an update with rotation + movePacket = new ClientPlayerPositionPacket(packet.isOnGround(), position.getX(), position.getY(), position.getZ()); } + + // Compare positions here for void floor fix below before the player's position variable is set to the packet position + boolean notMovingUp = entity.getPosition().getY() >= packet.getPosition().getY(); + + entity.setPositionManual(packet.getPosition()); + entity.setOnGround(packet.isOnGround()); + + // Send final movement changes + session.sendDownstreamPacket(movePacket); + + if (notMovingUp) { + int floorY = position.getFloorY(); + // If the client believes the world has extended height, then it also believes the void floor + // still exists, just at a lower spot + boolean extendedWorld = session.getChunkCache().isExtendedHeight(); + if (floorY <= (extendedWorld ? BEDROCK_OVERWORLD_VOID_FLOOR_LOWER_Y : -38) + && floorY >= (extendedWorld ? BEDROCK_OVERWORLD_VOID_FLOOR_UPPER_Y : -40)) { + // Work around there being a floor at the bottom of the world and teleport the player below it + // Moving from below to above the void floor works fine + entity.setPosition(entity.getPosition().sub(0, 4f, 0)); + MovePlayerPacket movePlayerPacket = new MovePlayerPacket(); + movePlayerPacket.setRuntimeEntityId(entity.getGeyserId()); + movePlayerPacket.setPosition(entity.getPosition()); + movePlayerPacket.setRotation(entity.getBedrockRotation()); + movePlayerPacket.setMode(MovePlayerPacket.Mode.TELEPORT); + movePlayerPacket.setTeleportationCause(MovePlayerPacket.TeleportationCause.BEHAVIOR); + session.sendUpstreamPacket(movePlayerPacket); + } + } + } else { + // Not a valid move + session.getConnector().getLogger().debug("Recalculating position..."); + session.getCollisionManager().recalculatePosition(); } } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/collision/CollisionManager.java b/connector/src/main/java/org/geysermc/connector/network/translators/collision/CollisionManager.java index e59c33520..a28a39271 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/collision/CollisionManager.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/collision/CollisionManager.java @@ -54,7 +54,7 @@ public class CollisionManager { private final GeyserSession session; @Getter - private BoundingBox playerBoundingBox; + private final BoundingBox playerBoundingBox; /** * Whether the player is inside scaffolding @@ -105,26 +105,16 @@ public class CollisionManager { } /** - * Updates the stored bounding box without passing a position, which currently just changes the height depending on if the player is sneaking. + * Updates the height of the stored bounding box */ public void updatePlayerBoundingBox() { - if (playerBoundingBox == null) { - Vector3f playerPosition; - if (session.getPlayerEntity() == null) { - // Temporary position to prevent NullPointerException - playerPosition = Vector3f.ZERO; - } else { - playerPosition = session.getPlayerEntity().getPosition(); - } - playerBoundingBox = new BoundingBox(playerPosition.getX(), playerPosition.getY() + 0.9, playerPosition.getZ(), - EntityType.PLAYER.getWidth(), EntityType.PLAYER.getHeight(), EntityType.PLAYER.getLength()); - } else { - // According to the Minecraft Wiki, when sneaking: - // - In Bedrock Edition, the height becomes 1.65 blocks, allowing movement through spaces as small as 1.75 (2 - 1⁄4) blocks high. - // - In Java Edition, the height becomes 1.5 blocks. - // Other instances have the player's bounding box become as small as 0.6 or 0.2. - playerBoundingBox.setSizeY(session.getPlayerEntity().getMetadata().getFloat(EntityData.BOUNDING_BOX_HEIGHT)); - } + // According to the Minecraft Wiki, when sneaking: + // - In Bedrock Edition, the height becomes 1.65 blocks, allowing movement through spaces as small as 1.75 (2 - 1⁄4) blocks high. + // - In Java Edition, the height becomes 1.5 blocks. + // Other instances have the player's bounding box become as small as 0.6 or 0.2. + double playerHeight = session.getPlayerEntity().getMetadata().getFloat(EntityData.BOUNDING_BOX_HEIGHT); + playerBoundingBox.setMiddleY(playerBoundingBox.getMiddleY() - (playerBoundingBox.getSizeY() / 2.0) + (playerHeight / 2.0)); + playerBoundingBox.setSizeY(playerHeight); } /** @@ -265,9 +255,15 @@ public class CollisionManager { if (collision != null) { // Determine, if the player's bounding box *were* at full height, if it would intersect with the block // at the current location. + double originalY = playerBoundingBox.getMiddleY(); + double originalHeight = playerBoundingBox.getSizeY(); + double standingY = originalY - (originalHeight / 2.0) + (EntityType.PLAYER.getHeight() / 2.0); + playerBoundingBox.setSizeY(EntityType.PLAYER.getHeight()); + playerBoundingBox.setMiddleY(standingY); boolean result = collision.checkIntersection(playerBoundingBox); - playerBoundingBox.setSizeY(session.getPlayerEntity().getMetadata().getFloat(EntityData.BOUNDING_BOX_HEIGHT)); + playerBoundingBox.setSizeY(originalHeight); + playerBoundingBox.setMiddleY(originalY); return result; } return false; diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/player/JavaPlayerPositionRotationTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/player/JavaPlayerPositionRotationTranslator.java index 3865ef64b..454d23d69 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/player/JavaPlayerPositionRotationTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/player/JavaPlayerPositionRotationTranslator.java @@ -124,8 +124,18 @@ public class JavaPlayerPositionRotationTranslator extends PacketTranslator