17
0
mirror of https://github.com/MaSzyna-EU07/maszyna.git synced 2026-10-28 14:37:29 +01:00

multiplayer: whoever drives a train runs it, and their ride is the smooth one

Until now the server ran the physics of everything and a client re-ran it from
the server's frame times, corrected a few times a second. That is the worst of
both: the client's own train never moved smoothly, its controls answered a
round trip late, and the two copies still sat metres apart between corrections.

Simulation authority now follows the train:

- the first person aboard a train runs its physics on their own machine, and
  what they produce is what the rest of the session is told about it. A train
  with nobody in it belongs to the host. Every peer works the owner out the
  same way, from the crew of its lowest numbered car, so nobody has to be told
- a peer never applies corrections to a train it runs itself. Its own physics
  is the authority on it, and overwriting that is precisely what made the
  owner's ride stutter
- a client publishes the state of its own trains upstream, ten times a second.
  The server takes it, filtered so a peer can only move the trains it is
  entitled to move, and passes it on to everybody else in its own stream
- so the picture is: your train is smooth for you and may stutter for the
  others; their trains may stutter for you and are smooth for them

Two things follow from it:

- commands for the train you run take effect the moment you press the key
  instead of after a trip to the server and back. They are still sent, so
  everybody else sees them, and the echo is dropped when it returns
- the client no longer replays the server's frame times out of a jitter buffer.
  It runs on its own clock, like the host does, and simply carries out the
  commands as they arrive. Playing back somebody else's frame times meant the
  world ran at the wrong speed whenever the two machines drew at different
  rates, and every buffered frame sat between the player and their controls

Also: the server only sends a frame when it has commands in it, or every tenth
one to carry the tick, instead of one per rendered frame.
This commit is contained in:
2026-09-07 00:19:40 +00:00
parent 0b75e701fc
commit c0dbf99f1a
10 changed files with 230 additions and 130 deletions

View File

@@ -148,6 +148,19 @@ command_verdict validate_command(PeerId Peer, user_command Command, uint32_t Rec
// set they are sitting in, which is what makes the cab switches of a multiple unit work
bool may_control(PeerId Peer, NetworkEntityId Entity);
// whose machine actually runs the physics of a given train. the first person aboard does,
// so their own train moves smoothly for them and only its result travels to the others;
// a train with nobody in it is run by the host
PeerId simulation_owner(NetworkEntityId Entity);
// true when this peer is the one running it, and therefore must not have it corrected
bool is_locally_simulated(NetworkEntityId Entity);
// true for a command this peer may carry out at once instead of waiting for the round
// trip: it addresses a train this peer both runs and is allowed to work
bool is_predictable(uint32_t Recipient);
// copies out of Commands everything that qualifies, leaving the original alone - it still
// has to reach the server so that everybody else sees it
void collect_predictable(command_queue::commands_map const &Commands, command_queue::commands_map &Predicted);
// walking into a cab with the in-game key is the same request as pressing the button in
// the lobby, so it goes through the crew registry rather than being treated as a command
// that reaches the whole world. returns the vehicle it resolved to, if any