move_speed will silently desync if the player-list reset packet is ever sent #26

Closed
opened 2026-07-27 22:32:10 +00:00 by sickday · 0 comments
Owner

The client keeps a player's render speed in a per-slot byte set by the
move_speed mask, and World.Player.report_speed/2 sends it only when the value
changes. That is correct as long as the client's copy only ever changes when we
say so.

There is one packet that changes it behind our back: the one that clears the
whole player list also resets every slot's speed to 1 and re-seeds the local
player. We do not send it today — the ordinary scene rebuild leaves the array
alone, which is why change-only sending is safe right now.

The moment anything sends it — instancing, a forced world reset, a re-login path
that reuses the connection — every player's speed silently reverts to walk on
the client while the server still believes it sent 2. Nothing will change
again, so nothing will be re-sent, and running renders at walking pace until the
next time the value happens to change. That failure mode is a slow drift of the
avatar behind its true tile, not an error.

World.addition_masks/1 already handles the sibling case, restating the speed
for anyone entering a viewer's view rather than waiting for a change.

Shape of a fix

Whatever ends up sending that packet must also invalidate every player's cached
speed so the next tick restates it. Worth a note next to report_speed/2 now so
it is found when it matters.

The client keeps a player's render speed in a per-slot byte set by the `move_speed` mask, and `World.Player.report_speed/2` sends it only when the value changes. That is correct as long as the client's copy only ever changes when we say so. There is one packet that changes it behind our back: the one that clears the whole player list also resets every slot's speed to `1` and re-seeds the local player. We do not send it today — the ordinary scene rebuild leaves the array alone, which is why change-only sending is safe right now. The moment anything sends it — instancing, a forced world reset, a re-login path that reuses the connection — every player's speed silently reverts to walk on the client while the server still believes it sent `2`. Nothing will change again, so nothing will be re-sent, and running renders at walking pace until the next time the value happens to change. That failure mode is a slow drift of the avatar behind its true tile, not an error. `World.addition_masks/1` already handles the sibling case, restating the speed for anyone entering a viewer's view rather than waiting for a change. ### Shape of a fix Whatever ends up sending that packet must also invalidate every player's cached speed so the next tick restates it. Worth a note next to `report_speed/2` now so it is found when it matters.
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
Revenant/Server#26
No description provided.