Skip to content

Commit 472ed8c

Browse files
Temporarily revert #5529 (#5550)
This reverts commit 24291ab.
1 parent 24291ab commit 472ed8c

File tree

10 files changed

+99
-73
lines changed

10 files changed

+99
-73
lines changed

core/src/main/java/org/geysermc/geyser/entity/type/player/SessionPlayerEntity.java

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,6 @@
4747
import org.geysermc.geyser.level.block.type.BlockState;
4848
import org.geysermc.geyser.level.block.type.TrapDoorBlock;
4949
import org.geysermc.geyser.session.GeyserSession;
50-
import org.geysermc.geyser.session.cache.TeleportCache;
5150
import org.geysermc.geyser.session.cache.tags.BlockTag;
5251
import org.geysermc.geyser.util.AttributeUtils;
5352
import org.geysermc.geyser.util.DimensionUtils;
@@ -435,8 +434,19 @@ public void teleportVoidFloorFix(boolean up) {
435434
movePlayerPacket.setMode(MovePlayerPacket.Mode.TELEPORT);
436435
movePlayerPacket.setTeleportationCause(MovePlayerPacket.TeleportationCause.BEHAVIOR);
437436
session.sendUpstreamPacketImmediately(movePlayerPacket);
437+
}
438+
439+
/**
440+
* Used to calculate player jumping velocity for ground status calculation.
441+
*/
442+
public float getJumpVelocity() {
443+
float velocity = 0.42F;
444+
445+
if (session.getGeyser().getWorldManager().blockAt(session, this.getPosition().sub(0, EntityDefinitions.PLAYER.offset() + 0.1F, 0).toInt()).is(Blocks.HONEY_BLOCK)) {
446+
velocity *= 0.6F;
447+
}
438448

439-
session.getUnconfirmedTeleports().add(new TeleportCache(null, newPosition.down(EntityDefinitions.PLAYER.offset()), this.getPitch(), this.getYaw(), -1));
449+
return velocity + 0.1F * session.getEffectCache().getJumpPower();
440450
}
441451

442452
public boolean isOnClimbableBlock() {

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

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -155,9 +155,10 @@ public BoundingBox getActiveBoundingBox() {
155155
*
156156
* @param bedrockPosition the current Bedrock position of the client
157157
* @param onGround whether the Bedrock player is on the ground
158+
* @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 onGround) {
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()) {
@@ -181,7 +182,7 @@ public BoundingBox getActiveBoundingBox() {
181182

182183
Vector3d startingPos = playerBoundingBox.getBottomCenter();
183184
Vector3d movement = position.sub(startingPos);
184-
Vector3d adjustedMovement = correctPlayerMovement(movement, false);
185+
Vector3d adjustedMovement = correctPlayerMovement(movement, false, teleported);
185186
playerBoundingBox.translate(adjustedMovement.getX(), adjustedMovement.getY(), adjustedMovement.getZ());
186187
playerBoundingBox.translate(pistonCache.getPlayerMotion().getX(), pistonCache.getPlayerMotion().getY(), pistonCache.getPlayerMotion().getZ());
187188
// Correct player position
@@ -292,8 +293,10 @@ public boolean correctPlayerPosition() {
292293
return true;
293294
}
294295

295-
public Vector3d correctPlayerMovement(Vector3d movement, boolean checkWorld) {
296-
if ((!checkWorld && session.getPistonCache().getPistons().isEmpty())) { // There is nothing to check
296+
public Vector3d correctPlayerMovement(Vector3d movement, boolean checkWorld, boolean teleported) {
297+
// On the teleported check: see https://github.com/GeyserMC/Geyser/issues/2540
298+
// As of this commit we don't know how it happens but we don't need to check movement here anyway in that case
299+
if (teleported || (!checkWorld && session.getPistonCache().getPistons().isEmpty())) { // There is nothing to check
297300
return movement;
298301
}
299302
return correctMovement(movement, playerBoundingBox, session.getPlayerEntity().isOnGround(), PLAYER_STEP_UP, checkWorld, false);

core/src/main/java/org/geysermc/geyser/session/GeyserSession.java

Lines changed: 15 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
import org.checkerframework.common.value.qual.IntRange;
5353
import org.cloudburstmc.math.vector.Vector2f;
5454
import org.cloudburstmc.math.vector.Vector2i;
55+
import org.cloudburstmc.math.vector.Vector3d;
5556
import org.cloudburstmc.math.vector.Vector3f;
5657
import org.cloudburstmc.math.vector.Vector3i;
5758
import org.cloudburstmc.nbt.NbtMap;
@@ -209,8 +210,6 @@
209210
import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.ServerboundChatCommandSignedPacket;
210211
import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.ServerboundChatPacket;
211212
import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.ServerboundClientTickEndPacket;
212-
import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.level.ServerboundAcceptTeleportationPacket;
213-
import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundMovePlayerPosRotPacket;
214213
import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundPlayerAbilitiesPacket;
215214
import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundPlayerActionPacket;
216215
import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundUseItemPacket;
@@ -286,7 +285,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
286285
private final WorldCache worldCache;
287286

288287
@Setter
289-
private Queue<TeleportCache> unconfirmedTeleports = new ConcurrentLinkedQueue<>();
288+
private TeleportCache unconfirmedTeleport;
290289

291290
private final WorldBorder worldBorder;
292291
/**
@@ -1649,28 +1648,23 @@ public int getNextItemNetId() {
16491648
return itemNetId.getAndIncrement();
16501649
}
16511650

1652-
public void confirmTeleport(Vector3f position, boolean teleport) {
1653-
if (this.unconfirmedTeleports.isEmpty() || !teleport) {
1651+
public void confirmTeleport(Vector3d position) {
1652+
if (unconfirmedTeleport == null) {
16541653
return;
16551654
}
16561655

1657-
final List<TeleportCache> caches = new ArrayList<>();
1658-
while (!this.unconfirmedTeleports.isEmpty()) {
1659-
TeleportCache cache = this.unconfirmedTeleports.poll();
1660-
if (cache.getJavaPosition() != null) {
1661-
caches.add(cache);
1662-
}
1663-
1664-
if (cache.canConfirm(position)) {
1665-
break;
1666-
}
1656+
if (unconfirmedTeleport.canConfirm(position)) {
1657+
unconfirmedTeleport = null;
1658+
return;
1659+
}
16671660

1668-
// Player claimed that they have already accepted the teleport but none of the cached position match, resending teleport...
1669-
if (this.unconfirmedTeleports.isEmpty()) {
1670-
geyser.getLogger().debug("Resending teleport " + cache.getTeleportConfirmId());
1671-
getPlayerEntity().moveAbsolute(cache.getBedrockPosition(), cache.getYaw(), cache.getPitch(), playerEntity.isOnGround(), true);
1672-
this.unconfirmedTeleports.add(new TeleportCache(null, cache.getBedrockPosition(), cache.getPitch(), cache.getYaw(), -1));
1673-
}
1661+
// Resend the teleport every few packets until Bedrock responds
1662+
unconfirmedTeleport.incrementUnconfirmedFor();
1663+
if (unconfirmedTeleport.shouldResend()) {
1664+
unconfirmedTeleport.resetUnconfirmedFor();
1665+
geyser.getLogger().debug("Resending teleport " + unconfirmedTeleport.getTeleportConfirmId());
1666+
getPlayerEntity().moveAbsolute(Vector3f.from(unconfirmedTeleport.getX(), unconfirmedTeleport.getY(), unconfirmedTeleport.getZ()),
1667+
unconfirmedTeleport.getYaw(), unconfirmedTeleport.getPitch(), playerEntity.isOnGround(), true);
16741668
}
16751669
}
16761670

core/src/main/java/org/geysermc/geyser/session/cache/EntityEffectCache.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,11 +46,16 @@ public class EntityEffectCache {
4646
@Getter
4747
private int miningFatigue;
4848

49+
/* Used to calculate jumping velocity */
50+
@Getter
51+
private int jumpPower;
52+
4953
public void setEffect(Effect effect, int effectAmplifier) {
5054
switch (effect) {
5155
case CONDUIT_POWER -> conduitPower = effectAmplifier + 1;
5256
case HASTE -> haste = effectAmplifier + 1;
5357
case MINING_FATIGUE -> miningFatigue = effectAmplifier + 1;
58+
case JUMP_BOOST -> jumpPower = effectAmplifier + 1;
5459
}
5560
entityEffects.add(effect);
5661
}
@@ -60,6 +65,7 @@ public void removeEffect(Effect effect) {
6065
case CONDUIT_POWER -> conduitPower = 0;
6166
case HASTE -> haste = 0;
6267
case MINING_FATIGUE -> miningFatigue = 0;
68+
case JUMP_BOOST -> jumpPower = 0;
6369
}
6470
entityEffects.remove(effect);
6571
}

core/src/main/java/org/geysermc/geyser/session/cache/PistonCache.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,7 @@ public void displacePlayer(Vector3d displacement) {
170170
delta = clientVehicle.getVehicleComponent().correctMovement(delta);
171171
clientVehicle.getVehicleComponent().moveRelative(delta);
172172
} else {
173-
delta = session.getCollisionManager().correctPlayerMovement(delta, true);
173+
delta = session.getCollisionManager().correctPlayerMovement(delta, true, false);
174174
session.getCollisionManager().getPlayerBoundingBox().translate(delta.getX(), delta.getY(), delta.getZ());
175175
}
176176

core/src/main/java/org/geysermc/geyser/session/cache/TeleportCache.java

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,9 @@
2525

2626
package org.geysermc.geyser.session.cache;
2727

28+
import org.cloudburstmc.math.vector.Vector3d;
2829
import lombok.Data;
2930
import lombok.RequiredArgsConstructor;
30-
import org.cloudburstmc.math.vector.Vector3d;
31-
import org.cloudburstmc.math.vector.Vector3f;
3231

3332
/**
3433
* Represents a teleport ID and corresponding coordinates that need to be confirmed. <br>
@@ -42,17 +41,36 @@
4241
@RequiredArgsConstructor
4342
@Data
4443
public class TeleportCache {
44+
4545
private static final double ERROR_X_AND_Z = 0.1;
4646
private static final double ERROR_Y = 0.1;
4747

48-
private final Vector3d javaPosition;
49-
private final Vector3f bedrockPosition;
48+
/**
49+
* How many move packets the teleport can be unconfirmed for before it gets resent to the client
50+
*/
51+
private static final int RESEND_THRESHOLD = 20; // Make it one full second with auth input
52+
53+
private final double x, y, z;
5054
private final float pitch, yaw;
5155
private final int teleportConfirmId;
5256

53-
public boolean canConfirm(Vector3f position) {
54-
return Math.abs(this.bedrockPosition.getX() - position.getX()) < ERROR_X_AND_Z &&
55-
Math.abs(this.bedrockPosition.getY() - position.getY()) < ERROR_Y &&
56-
Math.abs(this.bedrockPosition.getZ() - position.getZ()) < ERROR_X_AND_Z;
57+
private int unconfirmedFor = 0;
58+
59+
public boolean canConfirm(Vector3d position) {
60+
return (Math.abs(this.x - position.getX()) < ERROR_X_AND_Z &&
61+
Math.abs(this.y - position.getY()) < ERROR_Y &&
62+
Math.abs(this.z - position.getZ()) < ERROR_X_AND_Z);
63+
}
64+
65+
public void incrementUnconfirmedFor() {
66+
unconfirmedFor++;
67+
}
68+
69+
public void resetUnconfirmedFor() {
70+
unconfirmedFor = 0;
71+
}
72+
73+
public boolean shouldResend() {
74+
return unconfirmedFor >= RESEND_THRESHOLD;
5775
}
5876
}

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

Lines changed: 15 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,8 @@ static void translate(GeyserSession session, PlayerAuthInputPacket packet) {
5050
if (!session.isSpawned()) return;
5151

5252
// Ignore movement packets until Bedrock's position matches the teleported position
53-
if (!session.getUnconfirmedTeleports().isEmpty()) {
54-
session.confirmTeleport(packet.getPosition().down(EntityDefinitions.PLAYER.offset()), packet.getInputData().contains(PlayerAuthInputData.HANDLE_TELEPORT));
53+
if (session.getUnconfirmedTeleport() != null) {
54+
session.confirmTeleport(packet.getPosition().toDouble().sub(0, EntityDefinitions.PLAYER.offset(), 0));
5555
return;
5656
}
5757

@@ -86,29 +86,25 @@ static void translate(GeyserSession session, PlayerAuthInputPacket packet) {
8686
session.setLookBackScheduledFuture(null);
8787
}
8888

89-
boolean verticalCollision = packet.getInputData().contains(PlayerAuthInputData.VERTICAL_COLLISION);
89+
// Simulate jumping since it happened this tick, not from the last tick end.
90+
if (entity.isOnGround() && packet.getInputData().contains(PlayerAuthInputData.START_JUMPING)) {
91+
entity.setLastTickEndVelocity(Vector3f.from(entity.getLastTickEndVelocity().getX(), Math.max(entity.getLastTickEndVelocity().getY(), entity.getJumpVelocity()), entity.getLastTickEndVelocity().getZ()));
92+
}
93+
94+
// Due to how ladder works on Bedrock, we won't get climbing velocity from tick end unless if you're colliding horizontally. So we account for it ourselves.
95+
boolean onClimbableBlock = entity.isOnClimbableBlock();
96+
if (onClimbableBlock && packet.getInputData().contains(PlayerAuthInputData.JUMPING)) {
97+
entity.setLastTickEndVelocity(Vector3f.from(entity.getLastTickEndVelocity().getX(), 0.2F, entity.getLastTickEndVelocity().getZ()));
98+
}
9099

100+
// Client is telling us it wants to move down, but something is blocking it from doing so.
91101
boolean isOnGround;
92102
if (hasVehicle) {
93103
// VERTICAL_COLLISION is not accurate while in a vehicle (as of 1.21.62)
94104
// If the player is riding a vehicle or is in spectator mode, onGround is always set to false for the player
95105
isOnGround = false;
96106
} else {
97-
// Client is telling us it wants to move down, but something is blocking it from doing so.
98-
isOnGround = verticalCollision && entity.getLastTickEndVelocity().getY() < 0;
99-
100-
// We only have to check for these cases if player is having vertical collision else the onGround status will always be false.
101-
// These cases will always (I think so?) have upwards motion so don't even bother checking what the actual tick end y, the status is going to be false.
102-
if (verticalCollision) {
103-
if (entity.isOnGround() && packet.getInputData().contains(PlayerAuthInputData.START_JUMPING)) {
104-
isOnGround = false;
105-
}
106-
107-
// Due to how ladder works on Bedrock, we won't get climbing velocity from tick end unless if you're colliding horizontally. So we account for it ourselves.
108-
if (session.getPlayerEntity().isOnClimbableBlock() && (packet.getInputData().contains(PlayerAuthInputData.JUMPING) || packet.getInputData().contains(PlayerAuthInputData.ASCEND_BLOCK))) {
109-
isOnGround = false;
110-
}
111-
}
107+
isOnGround = packet.getInputData().contains(PlayerAuthInputData.VERTICAL_COLLISION) && entity.getLastTickEndVelocity().getY() < 0;
112108
}
113109

114110
entity.setLastTickEndVelocity(packet.getDelta());
@@ -138,7 +134,7 @@ static void translate(GeyserSession session, PlayerAuthInputPacket packet) {
138134
} else if (positionChangedAndShouldUpdate) {
139135
if (isValidMove(session, entity.getPosition(), packet.getPosition())) {
140136
if (!session.getWorldBorder().isPassingIntoBorderBoundaries(entity.getPosition(), true)) {
141-
CollisionResult result = session.getCollisionManager().adjustBedrockPosition(packet.getPosition(), isOnGround);
137+
CollisionResult result = session.getCollisionManager().adjustBedrockPosition(packet.getPosition(), isOnGround, packet.getInputData().contains(PlayerAuthInputData.HANDLE_TELEPORT));
142138
if (result != null) { // A null return value cancels the packet
143139
Vector3d position = result.correctedMovement();
144140
boolean isBelowVoid = entity.isVoidPositionDesynched();

core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaSetPassengersTranslator.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ public void translate(GeyserSession session, ClientboundSetPassengersPacket pack
5555
if (passenger == session.getPlayerEntity()) {
5656
session.getPlayerEntity().setVehicle(entity);
5757
// We need to confirm teleports before entering a vehicle, or else we will likely exit right out
58-
session.confirmTeleport(passenger.getPosition().down(EntityDefinitions.PLAYER.offset()), true);
58+
session.confirmTeleport(passenger.getPosition().down(EntityDefinitions.PLAYER.offset()).toDouble());
5959

6060
if (entity instanceof ClientVehicle clientVehicle) {
6161
clientVehicle.getVehicleComponent().onMount();

core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaPlayerPositionTranslator.java

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
import org.cloudburstmc.protocol.bedrock.packet.RespawnPacket;
3333
import org.geysermc.geyser.entity.EntityDefinitions;
3434
import org.geysermc.geyser.entity.type.player.SessionPlayerEntity;
35+
import org.geysermc.geyser.item.hashing.DataComponentHashers;
3536
import org.geysermc.geyser.session.GeyserSession;
3637
import org.geysermc.geyser.session.cache.TeleportCache;
3738
import org.geysermc.geyser.translator.protocol.PacketTranslator;
@@ -86,7 +87,8 @@ public void translate(GeyserSession session, ClientboundPlayerPositionPacket pac
8687
// DataComponentHashers.testHashing(session); // TODO remove me
8788

8889
// Make sure the player moves away from (0, 32767, 0) before accepting movement packets
89-
session.getUnconfirmedTeleports().add(new TeleportCache(pos, entity.position(), packet.getXRot(), packet.getYRot(), packet.getId()));
90+
session.setUnconfirmedTeleport(new TeleportCache(packet.getPosition().getX(), packet.getPosition().getY(), packet.getPosition().getZ(), packet.getXRot(), packet.getYRot(), packet.getId())); // TODO
91+
9092
acceptTeleport(session, packet.getPosition().getX(), packet.getPosition().getY(), packet.getPosition().getZ(), packet.getYRot(), packet.getXRot(), packet.getId());
9193

9294
if (session.getServerRenderDistance() > 32 && !session.isEmulatePost1_13Logic()) {
@@ -121,28 +123,29 @@ public void translate(GeyserSession session, ClientboundPlayerPositionPacket pac
121123

122124
session.getGeyser().getLogger().debug("Teleport (" + id + ") from " + entity.getPosition().getX() + " " + (entity.getPosition().getY() - EntityDefinitions.PLAYER.offset()) + " " + entity.getPosition().getZ());
123125

124-
Vector3f teleportDestination = Vector3f.from(newX, newY, newZ);
125-
Vector3f lastPlayerPosition = entity.position();
126+
Vector3f lastPlayerPosition = entity.getPosition().down(EntityDefinitions.PLAYER.offset());
126127
float lastPlayerPitch = entity.getPitch();
127-
// Bedrock ignores teleports that are extremely close to the player's original position and orientation
128-
// so we simply ignore if the teleport is close enough.
129-
if (lastPlayerPosition.distanceSquared(teleportDestination) < 0.001 && Math.abs(newPitch - lastPlayerPitch) < 5) {
130-
acceptTeleport(session, newX, newY, newZ, newYaw, newPitch, id);
131-
return;
132-
}
133-
128+
Vector3f teleportDestination = Vector3f.from(newX, newY, newZ);
134129
entity.moveAbsolute(teleportDestination, newYaw, newPitch, false, true);
130+
135131
session.getGeyser().getLogger().debug("to " + entity.getPosition().getX() + " " + (entity.getPosition().getY() - EntityDefinitions.PLAYER.offset()) + " " + entity.getPosition().getZ());
136132

137-
session.getUnconfirmedTeleports().add(new TeleportCache(Vector3d.from(newX, newY, newZ), teleportDestination, newPitch, newYaw, id));
133+
// Bedrock ignores teleports that are extremely close to the player's original position and orientation,
134+
// so check if we need to cache the teleport
135+
if (lastPlayerPosition.distanceSquared(teleportDestination) < 0.001 && Math.abs(newPitch - lastPlayerPitch) < 5) {
136+
session.setUnconfirmedTeleport(null);
137+
} else {
138+
session.setUnconfirmedTeleport(new TeleportCache(newX, newY, newZ, newPitch, newYaw, id));
139+
}
140+
138141
acceptTeleport(session, newX, newY, newZ, newYaw, newPitch, id);
139142
}
140143

141144
private void acceptTeleport(GeyserSession session, double x, double y, double z, float yaw, float pitch, int id) {
142-
// Confirm the teleport when we receive it to match Java edition behaviour.
145+
// Confirm the teleport when we receive it to match Java edition
143146
ServerboundAcceptTeleportationPacket teleportConfirmPacket = new ServerboundAcceptTeleportationPacket(id);
144147
session.sendDownstreamGamePacket(teleportConfirmPacket);
145-
// Most servers expect exact coordinates given back to them.
148+
// Servers (especially ones like Hypixel) expect exact coordinates given back to them.
146149
ServerboundMovePlayerPosRotPacket positionPacket = new ServerboundMovePlayerPosRotPacket(false, false, x, y, z, yaw, pitch);
147150
session.sendDownstreamGamePacket(positionPacket);
148151
}

0 commit comments

Comments
 (0)