Reversing on the host turned the whole set around on the client, and the
locomotive ended up looking like something derailed making its way across the
scenery. Both come from the same place: a routine correction was calling
place_on_track(), which sets the axles from scratch and works from the
vehicle's own idea of which way it faces. That is right for a peer joining with
nothing to go on, and wrong for a train that is already running - the placement
reorients it.
A correction now slides the vehicle along the track it is already on, by the
difference between the two bogie offsets, which is the same operation the
physics performs on every step. When the two sides disagree about which piece
of track the vehicle is on, it is left alone until they agree; guessing there
is what put a locomotive beside the rails. place_on_track() is kept for the one
case it suits, a peer joining the session.
Also:
- taking a seat works with the game paused. The whole thing sat inside the
"has any time passed" branch, so with the world stopped the lobby button
changed the roster and nothing else happened
- the debug panel gets a Network section, shown only in a session: role, peer,
tick, bytes and messages each way with a running rate, two charts of kB/s so
the cost of a session can be read off, how far the worst vehicle is out of
place, and whether the state digest agrees. The separate "network" overlay
window is gone - everything it said lives there now, together with the lobby
and refusal messages that had nowhere to be seen
Joining meant replaying backbuffer.bin from the very first frame of the
session, so the longer a session ran, the longer it took to get in - and the
whole history had to be kept for it.
- network/snapshot: a chunked container with a version of its own. Every
section carries its length, so a peer built before a section existed reads
a newer snapshot and simply walks past what it does not know. Version 1
carries the session (tick, clock, weather, the state of the random engine),
the vehicles (position on the track, speed, direction, controls, brake
pressures, whether the AI is driving) and the crew roster. Switches,
memcells, signals and the event queue are the next sections
- joining is now: handshake -> load the scenario -> CLIENT_READY -> the server
takes a snapshot on the spot and sends it -> the peer goes live. Because the
snapshot is taken at the moment the peer becomes active there is no backlog
to replay at all; the frame by frame catch-up is gone
- the server refuses a peer that loaded a different scenario, with a readable
reason instead of a silent desync
- reconnecting into a session that is already loaded asks for a fresh snapshot
straight away rather than waiting for a loader that will not run again
- a vehicle is only put back on the rails when it really is somewhere else; the
arithmetic that turns the recorded bogie offset back into the nose distance
place_on_track() expects mirrors what that function itself does
- the session log is still written out - it is useful when picking a desync
apart - but nothing depends on replaying it any more