Hi I’m working on a remote replica of traintastic simulator to enable multiplayer.
The idea is to reuse my UDP duscovery and existing traintastic protocol.
The replica is quite dumb, it will drive trains according to their speed but it will not track sensor occupation and all other things done in updateVehiclePosition().
So master instance will do all the logic and send sensor state changes to replicas plus a periodical state refresh.
Now the challenge is to sync trains, when they are added/removed and when they change vehicles by coupling/splitting.
Just a check, to see if I understand it correctly.
there is one “server/master” simulator
there are zero or more “client/slave” simulators
clients do their own train position calculations/frame rate updates
every N ms theu receive a full state, this might cause a small train jump due to synchronization
If the clients are allowed to perform some actions, I suggest to send the command to the server, then the server can perform the action, then send a state update to all clients. The server must be the synchronization point, there must be a single source of truth.
This is how Traintastic-server and client work together too, all client actions are sent to the server, the server executes it, changes are sent back to the client. It is basically model-view, where the server is the model and the client the view.
When you drive a train from replica/slave simulator it will just send command to master simulator without acting on Train object.
Train object will get updated by state refresh received by master.
Basically all commands are proxied to master instance.
Train refresh is a variable size message, i tried boost:::serialization but didn’t like it. The API forces to do copy of the buffer multiple times, at least the way I understood it, and it also adds structure info in the message so it wastes extra bytes because receive side already knows structure to deserialize.
Now I’m using QDataStream, unfortunately this adds QtCore dependency to simulator file…
Since train refresh is big I split it into 2 types:
Only state refresh, so TrainState + VehicleState
Full refresh sent less often with train length, vehicle properties etc
I’ve increased connection buffers because messages can be 300 bytes for long train.
But code in my fork really needs a cleanup if you want to use it as a base for new simulator versions.
Awesome, that should work very well. On a local network the delay is usually very low so people won’t notice.
The Traintastic client/server protocol had a similar challenge, for that I wrote shared/src/traintastic/network/message.hpp it contains simple serialize/deserialize logic which assumes both side do exactly the same, it works very well, it also supports sub blocks of data. Maybe that can be reused. Many of the Command numbers are still free, so using a few for the simulator multiplayer is fine by me