mojira.dev
MC-252140

Side crossing causing inconsistent knockback behaviour between single player and servers

I had always been wondering why taking fall damage on servers causes your movement to stall in midair, so I did some investigating, as it turns out, when the server is managing the player's movement, there would be a difference in behavior between local server and remote servers.

Facts

1. Player receives knockback from server via `ClientboundSetEntityMotionPacket`

2. When the client receives the packet for the local player, it sets the player's motion/delta movement to the Vec3 in the packet

3. The Vec3 in the packet is determined by the motion/delta movement the server has of that player.

Issue:

The server code crossed sides to access the LocalPlayer's motion on singleplayer, while it can't on multiplayer.

Ramification:

On single player, any knockback is added to the player's original motion(Only the host if it's opened to LAN), but on multiplayer, the knockback replaces the player's original motion.

 

Proposed solution:

  1. Add a different packet for player knockbacks

Not recommended solutions:

  1. Make the client report motion data to server (But it could open up new a creative uses)

  2. Change how ClientboundSetEntityMotionPacket is handled and add the motion instead of setting.

also you should fix the side crossing

Linked issues

Comments 4

Can you clarify how to reproduce this bug, and summarize what its gameplay impact is? Thank you.

Hello!

  1. You can reproduce this bug by taking knockback from poison midair in singleplayer and then multiplayer, on singleplayer you would keep your momentum and on multiplayer you would lose all your momentum.

  2. It's an inconsistency between single and multiplayer, which should not exist.

⚠️ Please do not mark Unreleased Versions as affected. You don't have access to them yet.

-- I am a bot. This action was performed automatically! If you think it was incorrect, please notify us on Discord or Reddit

Alright, I did not do a good job at presenting this.

Reproduction

A situation where the bug can happen is if you connect any server that is not hosted on the exact same minecraft process(i.e. anything other than singleplayer), and you take any form of knockback.

Gameplay effect

The gameplay effect is that

  • This is an inconsistency between singleplayer and multiplayer caused by side crossing[1].

  • Small things can kill a player's momentum making movement act weirdly

For example, if you are in a fight with someone and they knocked you back, but you are also on fire. This will make it so that the preview knockback is replaced with the (should be zero but not due to another bug) new knockback.

Or if you are doing a parkour and you had the momentum and were, again, on fire. If the fire ticks mid-jump, it will kill the momentum and you will just fall down.

On a higher ping situation, you may fall down and start sprinting, but when the fall damage('s velocity) is applied, your speed will (effectively) be reset

  • And anything else related to KB and player motion

[1] The velocity packet is absolute, not additive. And the server decides what value to put in the packet by adding the stored velocity of the entity and the knockback that was applied. As in `player.setVelocity(player.velocity + knockback)`, here it accessed the player's velocity, which is different between an integrated server(which would return the player's actual velocity), while on a remote server, this would almost always return (0, -0.81, 0) (don't remember specifically), because the server does not have the player's motion, and the small negative on y is from gravity(which probably shouldn't be calculated on players either).

Conclusion?

The velocity part of the code is a bit of a mess honestly and there are several problems 😛

  • The server calculates player's gravity even though it shouldn't

  • Velocity is absolute but the server adds to the player's original velocity(almost like `client_velo = server_velo + kb` instead of `client_velo += kb`), which it does not have(or rather, has a mistaken value of)

  • The solution for the velocity packet works in singleplayer because it crossed sides and client_velo is server_velo in that case

Fix?

Based on the implementation, I would have to guess that the intention is that velocity packet should add to the player's motion, so things like fire giving a (0,0,0) kb would leave the player's velocity unchanged instead of setting it to zero. And the dev accidentally crossed sides and used the client's player velo on the server, which happened to work in their singleplayer testing. But it is actually broken on multiplayer.

Hopefully that was a bit more useful

shuaiouke

(Unassigned)

Plausible

Platform

Normal

Player

1.18.2, 1.19, 1.19.1 Pre-release 1

Retrieved