@@ -76,7 +76,7 @@ static void translate(GeyserSession session, PlayerAuthInputPacket packet) {
76
76
boolean hasVehicle = entity .getVehicle () != null ;
77
77
78
78
// shouldSendPositionReminder also increments a tick counter, so make sure it's always called unless the player is on a vehicle.
79
- boolean positionChanged = !hasVehicle && (session .getInputCache ().shouldSendPositionReminder () || actualPositionChanged );
79
+ boolean positionChangedAndShouldUpdate = !hasVehicle && (session .getInputCache ().shouldSendPositionReminder () || actualPositionChanged );
80
80
boolean rotationChanged = hasVehicle || (entity .getYaw () != yaw || entity .getPitch () != pitch || entity .getHeadYaw () != headYaw );
81
81
82
82
if (session .getLookBackScheduledFuture () != null ) {
@@ -87,87 +87,103 @@ static void translate(GeyserSession session, PlayerAuthInputPacket packet) {
87
87
}
88
88
89
89
// Client is telling us it wants to move down, but something is blocking it from doing so.
90
- boolean isOnGround = packet .getInputData ().contains (PlayerAuthInputData .VERTICAL_COLLISION ) && packet .getDelta ().getY () < 0 ;
90
+ boolean isOnGround ;
91
+ if (hasVehicle ) {
92
+ // VERTICAL_COLLISION is not accurate while in a vehicle (as of 1.21.62)
93
+ isOnGround = Math .abs (packet .getDelta ().getY ()) < 0.1 ;
94
+ } else {
95
+ isOnGround = packet .getInputData ().contains (PlayerAuthInputData .VERTICAL_COLLISION ) && packet .getDelta ().getY () < 0 ;
96
+ }
97
+
91
98
// This takes into account no movement sent from the client, but the player is trying to move anyway.
92
99
// (Press into a wall in a corner - you're trying to move but nothing actually happens)
100
+ // This isn't sent when a player is riding a vehicle (as of 1.21.62)
93
101
boolean horizontalCollision = packet .getInputData ().contains (PlayerAuthInputData .HORIZONTAL_COLLISION );
94
102
95
103
// If only the pitch and yaw changed
96
104
// This isn't needed, but it makes the packets closer to vanilla
97
105
// It also means you can't "lag back" while only looking, in theory
98
- if (!positionChanged && rotationChanged ) {
106
+ if (!positionChangedAndShouldUpdate && rotationChanged ) {
99
107
ServerboundMovePlayerRotPacket playerRotationPacket = new ServerboundMovePlayerRotPacket (isOnGround , horizontalCollision , yaw , pitch );
100
108
101
109
entity .setYaw (yaw );
102
110
entity .setPitch (pitch );
103
111
entity .setHeadYaw (headYaw );
104
112
105
113
session .sendDownstreamGamePacket (playerRotationPacket );
106
- } else if (positionChanged ) {
107
- if (isValidMove (session , entity .getPosition (), packet .getPosition ())) {
108
- CollisionResult result = session .getCollisionManager ().adjustBedrockPosition (packet .getPosition (), isOnGround , packet .getInputData ().contains (PlayerAuthInputData .HANDLE_TELEPORT ));
109
- if (result != null ) { // A null return value cancels the packet
110
- Vector3d position = result .correctedMovement ();
111
- boolean isBelowVoid = entity .isVoidPositionDesynched ();
112
-
113
- boolean teleportThroughVoidFloor , mustResyncPosition ;
114
- // Compare positions here for void floor fix below before the player's position variable is set to the packet position
115
- if (entity .getPosition ().getY () >= packet .getPosition ().getY () && !isBelowVoid ) {
116
- int floorY = position .getFloorY ();
117
- int voidFloorLocation = entity .voidFloorPosition ();
118
- teleportThroughVoidFloor = floorY <= (voidFloorLocation + 1 ) && floorY >= voidFloorLocation ;
119
- } else {
120
- teleportThroughVoidFloor = false ;
121
- }
122
114
123
- if (teleportThroughVoidFloor || isBelowVoid ) {
124
- // https://github.com/GeyserMC/Geyser/issues/3521 - no void floor in Java so we cannot be on the ground.
125
- isOnGround = false ;
126
- }
127
-
128
- if (isBelowVoid ) {
129
- int floorY = position .getFloorY ();
130
- int voidFloorLocation = entity .voidFloorPosition ();
131
- mustResyncPosition = floorY < voidFloorLocation && floorY >= voidFloorLocation - 1 ;
132
- } else {
133
- mustResyncPosition = false ;
134
- }
135
-
136
- double yPosition = position .getY ();
137
- if (entity .isVoidPositionDesynched ()) { // not using the cached variable on purpose
138
- yPosition += 4 ; // We are de-synched since we had to teleport below the void floor.
139
- }
140
-
141
- Packet movePacket ;
142
- if (rotationChanged ) {
143
- // Send rotation updates as well
144
- movePacket = new ServerboundMovePlayerPosRotPacket (
115
+ // Player position MUST be updated on our end, otherwise e.g. chunk loading breaks
116
+ if (hasVehicle ) {
117
+ entity .setPositionManual (packet .getPosition ());
118
+ session .getSkullCache ().updateVisibleSkulls ();
119
+ }
120
+ } else if (positionChangedAndShouldUpdate ) {
121
+ if (isValidMove (session , entity .getPosition (), packet .getPosition ())) {
122
+ if (!session .getWorldBorder ().isPassingIntoBorderBoundaries (entity .getPosition (), true )) {
123
+ CollisionResult result = session .getCollisionManager ().adjustBedrockPosition (packet .getPosition (), isOnGround , packet .getInputData ().contains (PlayerAuthInputData .HANDLE_TELEPORT ));
124
+ if (result != null ) { // A null return value cancels the packet
125
+ Vector3d position = result .correctedMovement ();
126
+ boolean isBelowVoid = entity .isVoidPositionDesynched ();
127
+
128
+ boolean teleportThroughVoidFloor , mustResyncPosition ;
129
+ // Compare positions here for void floor fix below before the player's position variable is set to the packet position
130
+ if (entity .getPosition ().getY () >= packet .getPosition ().getY () && !isBelowVoid ) {
131
+ int floorY = position .getFloorY ();
132
+ int voidFloorLocation = entity .voidFloorPosition ();
133
+ teleportThroughVoidFloor = floorY <= (voidFloorLocation + 1 ) && floorY >= voidFloorLocation ;
134
+ } else {
135
+ teleportThroughVoidFloor = false ;
136
+ }
137
+
138
+ if (teleportThroughVoidFloor || isBelowVoid ) {
139
+ // https://github.com/GeyserMC/Geyser/issues/3521 - no void floor in Java so we cannot be on the ground.
140
+ isOnGround = false ;
141
+ }
142
+
143
+ if (isBelowVoid ) {
144
+ int floorY = position .getFloorY ();
145
+ int voidFloorLocation = entity .voidFloorPosition ();
146
+ mustResyncPosition = floorY < voidFloorLocation && floorY >= voidFloorLocation - 1 ;
147
+ } else {
148
+ mustResyncPosition = false ;
149
+ }
150
+
151
+ double yPosition = position .getY ();
152
+ if (entity .isVoidPositionDesynched ()) { // not using the cached variable on purpose
153
+ yPosition += 4 ; // We are de-synched since we had to teleport below the void floor.
154
+ }
155
+
156
+ Packet movePacket ;
157
+ if (rotationChanged ) {
158
+ // Send rotation updates as well
159
+ movePacket = new ServerboundMovePlayerPosRotPacket (
145
160
isOnGround ,
146
161
horizontalCollision ,
147
162
position .getX (), yPosition , position .getZ (),
148
163
yaw , pitch
149
- );
150
- entity .setYaw (yaw );
151
- entity .setPitch (pitch );
152
- entity .setHeadYaw (headYaw );
153
- } else {
154
- // Rotation did not change; don't send an update with rotation
155
- movePacket = new ServerboundMovePlayerPosPacket (isOnGround , horizontalCollision , position .getX (), yPosition , position .getZ ());
156
- }
157
-
158
- entity .setPositionManual (packet .getPosition ());
159
-
160
- // Send final movement changes
161
- session .sendDownstreamGamePacket (movePacket );
162
-
163
- if (teleportThroughVoidFloor ) {
164
- entity .teleportVoidFloorFix (false );
165
- } else if (mustResyncPosition ) {
166
- entity .teleportVoidFloorFix (true );
164
+ );
165
+ entity .setYaw (yaw );
166
+ entity .setPitch (pitch );
167
+ entity .setHeadYaw (headYaw );
168
+ } else {
169
+ // Rotation did not change; don't send an update with rotation
170
+ movePacket = new ServerboundMovePlayerPosPacket (isOnGround , horizontalCollision , position .getX (), yPosition , position .getZ ());
171
+ }
172
+
173
+ entity .setPositionManual (packet .getPosition ());
174
+
175
+ // Send final movement changes
176
+ session .sendDownstreamGamePacket (movePacket );
177
+
178
+ if (teleportThroughVoidFloor ) {
179
+ entity .teleportVoidFloorFix (false );
180
+ } else if (mustResyncPosition ) {
181
+ entity .teleportVoidFloorFix (true );
182
+ }
183
+
184
+ session .getInputCache ().markPositionPacketSent ();
185
+ session .getSkullCache ().updateVisibleSkulls ();
167
186
}
168
-
169
- session .getInputCache ().markPositionPacketSent ();
170
- session .getSkullCache ().updateVisibleSkulls ();
171
187
}
172
188
} else {
173
189
// Not a valid move
0 commit comments