Not sent small player position changes makes validation hard on servers
The bug
The client does have a too large threshold for not sending position changes to the server.
What this small inaccuracy in player position causes, is:
- Pressing forward while looking mostly against a wall causes the player to not move smoothly, but just one every second (due to forced position send every 20 ticks)
- In edge cases: Clipping through block edges from server's view
- Third-party extensions to server software which try to detect cheating have huge problems to validate movement in water with the client's movement algorithm, because multiple of such small movements following each other, trying all combinations of multiple small movements has expotential complexity.
- During a jump with just slight horizontal motion, the horizontal motion at the peak of a jump is not sent to the server.
* Jump once and building a block below you while inair, then stop moving - For the server, you will not be marked onGround on the server and float slightly above the block you just build (until the forced position send every 20 ticks).
Not as important reasons to change this:
- Various command block possibilities and testfor might want to check various things exactly but they can't
- inability of always correctly checking whether a player collided with a wall: if the move the player did was just very near a wall, the next move might be less than the minimum movement change to send a position update so he did not collide server-side only
- whether a player moved onto a pressure plate or stopped just before can't be really decided
- whether the player is moving slightly while collided with a wall, some puzzle adventures maybe want to check whether the player is moving at all or not
Suggested fix:
Affected method: net.minecraft.client.player.LocalPlayer.sendPosition()
Code snippet (this one from 21w39a):
if (this.isControlledCamera()) {
double $$4 = this.getX() - this.xLast;
double $$5 = this.getY() - this.yLast1;
double $$6 = this.getZ() - this.zLast;
double $$7 = (double)(this.getYRot() - this.yRotLast);
double $$8 = (double)(this.getXRot() - this.xRotLast);
++this.positionReminder;
boolean $$9 = $$4 * $$4 + $$5 * $$5 + $$6 * $$6 > 9.0E-4D || this.positionReminder >= 20;
boolean $$10 = $$7 != 0.0D || $$8 != 0.0D;
if (this.isPassenger()) {
Suggested change:
- boolean $$9 = $$4 * $$4 + $$5 * $$5 + $$6 * $$6 > 9.0E-4D || this.positionReminder >= 20;
+ boolean $$9 = $$4 * $$4 + $$5 * $$5 + $$6 * $$6 > 4.0E-8D || this.positionReminder >= 20;
Because of the squared distance context:
9.0E-4D refers to the distance 0.03
4.0E-8D refers to the distance 0.0002
This suggested new "small movement threshold" is still far below any double-precision floating point inaccuracy.
Other technical reason to implement this change
The code review from @Pokechu22 (first comment) does show that the constant 9.0E-4 is outdated.
Minecraft 1.9 increased the "relative movement" server->client packets from 1/32 = 0.03125 to 1/128. 0.03125 which is very similar to the the 0.03 distance.
It can be expected that the constant 9.0E-4 aka 0.03 was chosen in relation to te accuracy of the "relative movement" packet. So as you increased its accuracy, it is more than neccessary to follow up on this change with the suggested fix in this issue.
Downsides of the fix
None. There is no performance impact of this code change. The network usage at most increases to that of a player sprinting, which already happens often during the game.
2018-03-04, 04:39 AM
2022-03-05, 02:05 AM
2022-02-21, 02:00 PM
3
4
NetworkPacket, accuracy, cheats, movement, multiplayer, networking, packets
Minecraft 1.12.2 - 1.18.1
Minecraft 1.12.2, Minecraft 18w09a, Minecraft 18w10c, Minecraft 18w10d, Minecraft 18w11a, Minecraft 18w14a, Minecraft 18w14b, Minecraft 18w15a, Minecraft 18w16a, Minecraft 18w19a, Minecraft 18w19b, Minecraft 18w20b, Minecraft 18w20c, Minecraft 18w21b, Minecraft 18w22b, Minecraft 18w22c, Minecraft 1.13-pre1, Minecraft 1.13-pre2, Minecraft 1.13-pre3, Minecraft 1.13-pre5, Minecraft 1.13-pre6, Minecraft 1.13-pre7, Minecraft 1.13-pre8, Minecraft 1.13-pre9, Minecraft 1.13-pre10, Minecraft 1.13, Minecraft 18w30a, Minecraft 18w30b, Minecraft 18w31a, Minecraft 18w32a, Minecraft 18w33a, Minecraft 1.13.1-pre1, Minecraft 1.13.1-pre2, Minecraft 1.13.1, Minecraft 1.13.2-pre1, Minecraft 1.13.2-pre2, Minecraft 1.13.2, Minecraft 18w43a, Minecraft 18w43b, Minecraft 18w43c, Minecraft 18w44a, Minecraft 18w45a, Minecraft 18w46a, Minecraft 18w47a, Minecraft 18w47b, Minecraft 18w48a, Minecraft 18w48b, Minecraft 18w49a, Minecraft 18w50a, Minecraft 19w02a, Minecraft 19w03b, Minecraft 19w03c, Minecraft 19w04b, Minecraft 19w05a, Minecraft 19w06a, Minecraft 19w07a, Minecraft 19w08b, Minecraft 19w09a, Minecraft 19w11a, Minecraft 19w11b, Minecraft 19w12b, Minecraft 19w13b, Minecraft 19w14a, Minecraft 19w14b, Minecraft 1.14 Pre-Release 2, Minecraft 1.14 Pre-Release 3, Minecraft 1.14 Pre-Release 4, Minecraft 1.14 Pre-Release 5, Minecraft 1.14, Minecraft 1.14.1 Pre-Release 1, Minecraft 1.14.1 Pre-Release 2, Minecraft 1.14.1, Minecraft 1.14.2 Pre-Release 1, Minecraft 1.14.2 Pre-Release 2, Minecraft 1.14.2 Pre-Release 3, Minecraft 1.14.2 Pre-Release 4, Minecraft 1.14.2, Minecraft 1.14.3 Pre-Release 1, Minecraft 1.14.3 Pre-Release 2, Minecraft 1.14.3 Pre-Release 3, Minecraft 1.14.3 Pre-Release 4, Minecraft 1.14.3, 1.14.4, 19w34a, 19w35a, 19w36a, 19w37a, 19w39a, 19w42a, 19w44a, 19w45b, 19w46b, 1.15 Pre-release 3, 1.15, 1.15.1, 1.15.1 Pre-release 1, 1.15.2 Pre-release 2, 1.15.2, 20w10a, 20w15a, 1.16 Pre-release 1, 1.16 Pre-release 3, 1.16.3, 1.16.4 Pre-release 1, 1.16.5, 21w11a, 21w16a, 1.17 Pre-release 3, 1.17 Release Candidate 2, 1.17, 1.17.1 Pre-release 1, 1.17.1 Pre-release 2, 1.17.1 Pre-release 3, 1.17.1 Release Candidate 1, 1.17.1, 21w37a, 21w38a, 21w39a, 1.18 Pre-release 1, 1.18 Pre-release 4, 1.18 Pre-release 5, 1.18 Release Candidate 1, 1.18, 1.18.1 Pre-release 1, 1.18.1