Skip to content

Commit 1b4d257

Browse files
committed
Better onGround check
Thanks to @AJ-Ferguson for the suggestion. Includes hacks to still maintain pre-1.21.30, but that will likely lose support very soon, anyway.
1 parent aebf9d3 commit 1b4d257

File tree

3 files changed

+27
-12
lines changed

3 files changed

+27
-12
lines changed

core/src/main/java/org/geysermc/geyser/level/physics/CollisionManager.java

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -154,10 +154,11 @@ public BoundingBox getActiveBoundingBox() {
154154
* the two versions. Will also send corrected movement packets back to Bedrock if they collide with pistons.
155155
*
156156
* @param bedrockPosition the current Bedrock position of the client
157+
* @param onGround whether the Bedrock player is on the ground
157158
* @param teleported whether the Bedrock player has teleported to a new position. If true, movement correction is skipped.
158159
* @return the position to send to the Java server, or null to cancel sending the packet
159160
*/
160-
public @Nullable CollisionResult adjustBedrockPosition(Vector3f bedrockPosition, boolean teleported) {
161+
public @Nullable CollisionResult adjustBedrockPosition(Vector3f bedrockPosition, boolean onGround, boolean teleported) {
161162
PistonCache pistonCache = session.getPistonCache();
162163
// Bedrock clients tend to fall off of honey blocks, so we need to teleport them to the new position
163164
if (pistonCache.isPlayerAttachedToHoney()) {
@@ -198,17 +199,17 @@ public BoundingBox getActiveBoundingBox() {
198199

199200
position = playerBoundingBox.getBottomCenter();
200201

201-
boolean onGround = (adjustedMovement.getY() != movement.getY() && movement.getY() < 0) || isOnGround();
202+
boolean newOnGround = adjustedMovement.getY() != movement.getY() && movement.getY() < 0 || onGround;
202203
// Send corrected position to Bedrock if they differ by too much to prevent de-syncs
203-
if (movement.distanceSquared(adjustedMovement) > INCORRECT_MOVEMENT_THRESHOLD) {
204+
if (onGround != newOnGround || movement.distanceSquared(adjustedMovement) > INCORRECT_MOVEMENT_THRESHOLD) {
204205
PlayerEntity playerEntity = session.getPlayerEntity();
205206
// Client will dismount if on a vehicle
206207
if (playerEntity.getVehicle() == null && pistonCache.getPlayerMotion().equals(Vector3f.ZERO) && !pistonCache.isPlayerSlimeCollision()) {
207208
playerEntity.moveAbsolute(position.toFloat(), playerEntity.getYaw(), playerEntity.getPitch(), playerEntity.getHeadYaw(), onGround, true);
208209
}
209210
}
210211

211-
if (!onGround) {
212+
if (!newOnGround) {
212213
// Trim the position to prevent rounding errors that make Java think we are clipping into a block
213214
position = Vector3d.from(position.getX(), Double.parseDouble(DECIMAL_FORMAT.format(position.getY())), position.getZ());
214215
}
@@ -415,8 +416,8 @@ public BlockCollision getCollisionLavaWalking(int blockId, int blockY, BoundingB
415416
return BlockUtils.getCollision(blockId);
416417
}
417418

418-
private boolean isOnGround() {
419-
// Someone smarter than me at collisions plz check this.
419+
public boolean isOnGround() {
420+
// Temporary until pre-1.21.30 support is dropped.
420421
Vector3d bottomCenter = playerBoundingBox.getBottomCenter();
421422
Vector3i groundPos = Vector3i.from(bottomCenter.getX(), bottomCenter.getY() - 1, bottomCenter.getZ());
422423
BlockCollision collision = BlockUtils.getCollisionAt(session, groundPos);

core/src/main/java/org/geysermc/geyser/network/GameProtocol.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,10 @@ public static boolean isPre1_21_2(GeyserSession session) {
111111
return session.getUpstream().getProtocolVersion() < Bedrock_v686.CODEC.getProtocolVersion();
112112
}
113113

114+
public static boolean isPre1_21_30(GeyserSession session) {
115+
return session.getUpstream().getProtocolVersion() < Bedrock_v729.CODEC.getProtocolVersion();
116+
}
117+
114118
public static boolean isPre1_21_40(GeyserSession session) {
115119
return session.getUpstream().getProtocolVersion() < Bedrock_v748.CODEC.getProtocolVersion();
116120
}

core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/input/BedrockMovePlayer.java

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,15 @@
2525

2626
package org.geysermc.geyser.translator.protocol.bedrock.entity.player.input;
2727

28+
import net.kyori.adventure.util.TriState;
2829
import org.cloudburstmc.math.vector.Vector3d;
2930
import org.cloudburstmc.math.vector.Vector3f;
3031
import org.cloudburstmc.protocol.bedrock.data.PlayerAuthInputData;
3132
import org.cloudburstmc.protocol.bedrock.packet.PlayerAuthInputPacket;
3233
import org.geysermc.geyser.entity.EntityDefinitions;
3334
import org.geysermc.geyser.entity.type.player.SessionPlayerEntity;
3435
import org.geysermc.geyser.level.physics.CollisionResult;
36+
import org.geysermc.geyser.network.GameProtocol;
3537
import org.geysermc.geyser.session.GeyserSession;
3638
import org.geysermc.geyser.text.ChatColor;
3739
import org.geysermc.mcprotocollib.network.packet.Packet;
@@ -86,6 +88,14 @@ static void translate(GeyserSession session, PlayerAuthInputPacket packet) {
8688
session.setLookBackScheduledFuture(null);
8789
}
8890

91+
TriState maybeOnGround;
92+
if (GameProtocol.isPre1_21_30(session)) {
93+
// VERTICAL_COLLISION input data does not exist.
94+
maybeOnGround = TriState.NOT_SET;
95+
} else {
96+
// Client is telling us it wants to move down, but something is blocking it from doing so.
97+
maybeOnGround = TriState.byBoolean(packet.getInputData().contains(PlayerAuthInputData.VERTICAL_COLLISION) && packet.getDelta().getY() < 0);
98+
}
8999
// This takes into account no movement sent from the client, but the player is trying to move anyway.
90100
// (Press into a wall in a corner - you're trying to move but nothing actually happens)
91101
boolean horizontalCollision = packet.getInputData().contains(PlayerAuthInputData.HORIZONTAL_COLLISION);
@@ -94,7 +104,7 @@ static void translate(GeyserSession session, PlayerAuthInputPacket packet) {
94104
// This isn't needed, but it makes the packets closer to vanilla
95105
// It also means you can't "lag back" while only looking, in theory
96106
if (!positionChanged && rotationChanged) {
97-
ServerboundMovePlayerRotPacket playerRotationPacket = new ServerboundMovePlayerRotPacket(entity.isOnGround(), horizontalCollision, yaw, pitch);
107+
ServerboundMovePlayerRotPacket playerRotationPacket = new ServerboundMovePlayerRotPacket(maybeOnGround.toBooleanOrElse(entity.isOnGround()), horizontalCollision, yaw, pitch);
98108

99109
entity.setYaw(yaw);
100110
entity.setPitch(pitch);
@@ -103,10 +113,10 @@ static void translate(GeyserSession session, PlayerAuthInputPacket packet) {
103113
session.sendDownstreamGamePacket(playerRotationPacket);
104114
} else if (positionChanged) {
105115
if (isValidMove(session, entity.getPosition(), packet.getPosition())) {
106-
CollisionResult result = session.getCollisionManager().adjustBedrockPosition(packet.getPosition(), packet.getInputData().contains(PlayerAuthInputData.HANDLE_TELEPORT));
116+
CollisionResult result = session.getCollisionManager().adjustBedrockPosition(packet.getPosition(), maybeOnGround.toBooleanOrElse(false), packet.getInputData().contains(PlayerAuthInputData.HANDLE_TELEPORT));
107117
if (result != null) { // A null return value cancels the packet
108118
Vector3d position = result.correctedMovement();
109-
boolean onGround = result.onGround().toBooleanOrElse(entity.isOnGround());
119+
boolean onGround = maybeOnGround.toBooleanOrElseGet(() -> session.getCollisionManager().isOnGround());
110120
boolean isBelowVoid = entity.isVoidPositionDesynched();
111121

112122
boolean teleportThroughVoidFloor, mustResyncPosition;
@@ -155,7 +165,6 @@ static void translate(GeyserSession session, PlayerAuthInputPacket packet) {
155165
}
156166

157167
entity.setPositionManual(packet.getPosition());
158-
entity.setOnGround(onGround);
159168

160169
// Send final movement changes
161170
session.sendDownstreamGamePacket(movePacket);
@@ -174,11 +183,12 @@ static void translate(GeyserSession session, PlayerAuthInputPacket packet) {
174183
session.getGeyser().getLogger().debug("Recalculating position...");
175184
session.getCollisionManager().recalculatePosition();
176185
}
177-
} else if (horizontalCollision != session.getInputCache().lastHorizontalCollision()) {
178-
session.sendDownstreamGamePacket(new ServerboundMovePlayerStatusOnlyPacket(entity.isOnGround(), horizontalCollision));
186+
} else if (horizontalCollision != session.getInputCache().lastHorizontalCollision() || maybeOnGround.toBooleanOrElse(entity.isOnGround()) != entity.isOnGround()) {
187+
session.sendDownstreamGamePacket(new ServerboundMovePlayerStatusOnlyPacket(maybeOnGround.toBooleanOrElse(false), horizontalCollision));
179188
}
180189

181190
session.getInputCache().setLastHorizontalCollision(horizontalCollision);
191+
entity.setOnGround(maybeOnGround.toBooleanOrElse(entity.isOnGround()));
182192

183193
// Move parrots to match if applicable
184194
if (entity.getLeftParrot() != null) {

0 commit comments

Comments
 (0)