When you place a block close to your bounding box when you're slowly moving backward the block gets canceled by the server.
Steps to reproduce
1. Make sure you move very slow, less than 0.03 blocks per tick. I will use cobweb and sneak for this.
2. Move backward.
3. Try to place the block as close as possible to your bounding box.
Observed results
The server thinks you're placing the block inside yourself and therefore cancels it.
Expected results
Block should be placed.
Code analysis
At net.minecraft.client.player.localplayer.sendPosition()
you can see that the client won't send its position to the server unless the player moved at least 0.03 blocks or when 20 ticks have passed.
This means that the bounding box from the server can be off by max 0.03 blocks.
final double double4 = this.getX() - this.xLast;
final double double5 = this.getY() - this.yLast1;
final double double6 = this.getZ() - this.zLast;
++this.positionReminder;
boolean boolean4 = double4 * double4 + double5 * double5 + double6 * double6 > 9.0E-4 || this.positionReminder >= 20;
There is no good reason for this, you want the server to have the same location as the client.
Suggested fix
Send the position at every move.
final double double4 = this.getX() - this.xLast;
final double double5 = this.getY() - this.yLast1;
final double double6 = this.getZ() - this.zLast;
++this.positionReminder;
boolean boolean4 = double4 * double4 + double5 * double5 + double6 * double6 > 0 || this.positionReminder >= 20;
Notes
This may have been implemented with the thought of not sending the position for very small moves (floating-point precision or very small moves <0.0001), however this already exists, if the clients motion is less than 0.003 it will be set to 0.
This isn't a duplicate of MC-95720, MC-95720 is about the inventory desync caused by an invalid block placement. This report is about why the invalid block placement happens in the first place.
Off topic
This 0.03 is also the reason why making an unbypassable anticheat movement-wise is very hard.
Linked issues
relates to 2
Attachments
Comments 4
There's a similar issue on 1.17.1 related to the same part of code with teleporting. When the client receives a teleport the last reported location in EntityPlayerSP or LocalPlayer (newer versions?) isn't updated. In a case where the player moves back to the previous reported position right after the teleport the new position will not be sent back to the server due to the movement cap. This issue is not related to the latency between the server and the client. It is important to mention that the suggested fix will not fix this issue because this issue will still be present with a movement cap of 0, therefore my suggestion is to either send a position every tick (boolean boolean4 = true; ) or to update the last reported position in EntityPlayerSP/LocalPlayer? when the player receives a teleport and, like suggested, limiting the movement limit to 0 (boolean boolean4 = double4 * double4 + double5 * double5 + double6 * double6 > 0 || this.positionReminder >= 20; ) to fix the main bug reported in this bug report.
https://www.youtube.com/watch?v=bgCvghrdmsg
Steps to reproduce
1. Create the set up shown in the video mentioned above
2. Apply speed 255
3. Set up a command block to teleport you every ~2 seconds to the same part of the setup shown in the video
4. Enter the setup and walk backwards while looking at the position at which you're teleporting yourself
5. Place a block
Note: This might take a couple of tries due to the 20 tick limit before the client sends another position packet.
I am unsure if I'm supposed to create another bug report if the issue is this closely related, therefore I have left this comment here.
Relates to MC-95720.
Here are some issues 0.03 causes with the MOJANG anticheat (vanilla)
A player is standing and starts sneaking. The player moves < 0.03 blocks and goes under a block over their head and releases shift. They have the STANDING pose on the server and the CROUCHING pose on the client, which means that the vanilla anticheat will teleport the player for phasing into a block.
A player has a high speed potion and is on the corner of an object. The player moves 0.03 blocks so they can move past this object. They then go past this object. The movement was 0.02, 0, 0. Then the next movement was 0, 0, 0.6. This causes issues because the server tries running ZX collision order (as Z > X), meaning the player tries to move 0.6 blocks in the Z direction, and then 0.02 blocks in the X direction. This also causes the vanilla anticheat to teleport the player for phasing into a block.
A player moves slightly, places a block and fails client side because they are in it because of 0.03, while server side it places. The player then runs through this block and falses phase on the vanilla anticheat once again.
Additionally, yes the client MUST send 20 movement packets a second in order to not cause desync's between the client and server, take for example.
Poses are done at the end of the tick. This means the player can sneak on the client, and not send a movement packet. They then move under a block, which the server gets the movement packet of. Client sided when they move, they have the CROUCHING pose. Server sided, they have the STANDING pose. This falses phase as the player has two different poses as there is no packet indicating that the client ticked and changed their pose.
Sending an idle packet was done in 1.8, and worked well. Both removing 0.03 and re-adding the idle movement packet is needed to fix desync's between the client and server.
I've seen the 0.03 thing cause a ton of issues such as with tridents and the status of being in water. It would be great to have the 0.03 thing removed.