Hi everyone!
Some time has passed since the modding update. We hope that you enjoy it in its current state. I wanted to share what we are working on and that is - Multiplayer. Because the modding update took so long and the cargo update might take even longer, we decided it makes sense to release something faster while chipping away at the cargo update. Multiplayer was always on our minds, many systems were ready and it felt like the fastest update. Together with that, we are also planning to tackle the end game issues, making it less pointless and more strategic. Cargo update needs more polished passenger gameplay. But about that later.
Deterministic Multiplayer
Worldwide Rush has many moving parts that need to be synchronized between players and doing that over the internet is just not feasible. Imagine Battlefield with 10-100k players in a single map at one time and how much bandwidth that would require. Our solution is deterministic multiplayer, which basically means players only share a minimum amount of data, and the game is simulated identically between players with that data. This is nothing new in video games and that means there is a lot of information to gather, which is great. It is my first time coding multiplayer systems.
As I discussed before, most systems are ready. The game is already running in a fixed-step loop independent from the frame rate or what is being shown on screen. Game state is changed using ordered commands instead of when the player presses something. The delay is invisible in single-player, but it is there. There was a lot of other work done in preparation, experiments and topics researched. We felt that we were ready.
First Steps
The first thing I worked on was connecting players and loading a save game. I reused my old TCP classes for LAN connection and built systems around that. Now I have a NetworkSession class that deals with what is being sent and received. Basically it is the brains for multiplayer. It uses the NetworkConnection class that deals with whatever connection system a player opted to use, like LAN or Steam. There I also store players data so that players who disconnect and connect again will continue where they left off.
Once a connection is established, a Network Session checks the greeting message, tries to find the existing player or create a new entry and either allows or disallows joining. If a player can join, then instructions on how to join will be sent. For example, if the host is in the game, instruction would mean the save file. Once the save file is downloaded, it was loaded in as any other save. At this point it was only share my savefile system.
To have a visual confirmation that the multiplayer connection is working, I made a quick chat system and to see players. Once that was done, it was all about making a clean exit. So that both host and players could exit the game, quit the multiplayer session, or just crash, informing the others. I would say these are the basics for any multiplayer system.
And this was done sometime in November 2025. When I am stressed because something does not work, I tend to switch what I am working on for a few days. It always looks like the grass is greener with a different project, or update in this case. But putting some work in makes me satisfied and realize how wrong I was. Then I can calmly go back to what I was doing and push it through.
Replay
Deterministic multiplayer means a lot of difficult to find bugs and for that I need tools to pinpoint what is going wrong. So I worked on the replay system, or fixing the old one that has existed for a year now. What I save are commands, and when you want to watch a replay, those commands are applied in the same frames. It was working before.
The problem was that, for example, a command in frame 1000 was to delete a certain vehicle, but when you load the game with commands, that vehicle does not exist, so the command is not loaded correctly. I opted for saving commands to byte data before they are applied. When the replay reaches a command frame, it would load those commands from byte data. This basically fixed invalid commands and provided me a simple way to share them between players. You will also be able to watch replays of your save games that were created with game version v.1.3.0 and above.
The replay system also saves a hash, a unique number that represents the current state in the world. It's a combination of the game time, deltas, frames, vehicle count, company values, and so on. If the replay system finds that hashes are not the same, then we have a desync - the game state is not the same as it was when the replay was made. This on its own is far from enough to catch bugs, I only needed a system to run the game without player input.
More Tools
Instead of hashes, I started saving the whole game state. A big document that records everything: where vehicles are, people, how fast something is moving, cities destinations with progress, integers in an array, companies trust - everything. This way I can know exactly what is where.
The main tool, or tools collection, is just running simulation tests. The simplest one is creating a new game from a seed and running it with bots at max speed for some time. Once the required number of frames is reached, it saves the game state and repeats this process to compare states. All values are compared, and if something is not identical, a clear error file is generated with what is different, where it is different, what commands were made, and some other basic info. Then the game is saved at a given time together with the game state, loaded, and compared again. Third is a heavy test, which compares all frames, so I could pinpoint exactly where something went wrong. For example, if the basic test was running for 10 000 frames and it found a hash difference at frame 5000, then a heavy test would repeat the test, but compare every frame from frame 4000 until a difference is found. All tests are just one button press away.
It turns out a heavy test has a limit, ~20000 frames, or something like 2 years at max speed. My 64 gigs of RAM run out, and with the current RAM prices, I fear it will be a limit for a long time.
I also made a multiplayer state comparison, either on the press of a button or when a hash difference is found, to send to the server as a bug. But that was made a bit later.
New Game
Then there is the collaborative creation of a new game. You will be able to invite players when creating a game, but only the host will be able to choose the game mode and settings. Players will be able to play in different teams or collaborate and control one team together. To help with communication, a chat system is integrated into the UI together with cursor painting. I wonder what people will paint first.
Once all players are ready, a host saves settings and shares them with players. Then everyone creates a new identical game from those settings.
Implementing this was straightforward. Every time a host does something, a new collection of settings is sent to all players. Once they get them, the UI automatically updates what is new.
Gameplay
Once everyone is in the game, only the host dictates what commands are executed and when. When players do something, instead of executing their own commands, they send them to the host and retrieve commands that the host provided for execution. Before all that, players check if the host sent commands for the next frame, otherwise simulation is paused.
When the host gets new commands, it adds them to the current list of its own commands and sends them to others before executing. The host also checks all players frames and sends missing commands, or a collection of commands to players to let them catch up. If some players are falling back too much, then everyone waits for them. I am thinking of making this as an option, because I remember people complaining when Factorio did something like that.
Currently, we can play together to around 2014 with AI before the first desync. Deterministic tests catch the same issue. I'm still figuring out how to fix it. Basically, because we prepared the game for multiplayer, there are very few bugs here and there, but all of those bugs are confusing.
The good thing now is that desync does not mean that players need to disconnect. Individual commands are checked against the simulation to avoid crashes. It's just the game itself will start to be different for players. A simple reconnect resolves the issue. Sure, the goal is to have 0 desyncs, but in case there are issues (like there always are with code), it will not be a complete dealbreaker.
On a side note, we are not planning a dedicated server or a server browser presently, but please let us know if these features are needed. Right now it feels more like an experience between friends, due to how long games can take.
Saving
Different players end the game in different places and states. This bugged me for some time, because when a host sends a save file, it sends it from the host's perspective. I wondered where I should save individual players data. Saving to the host would mean using a lot more bandwidth and storing unnecessary data. I opted for saving individual session data locally so that when players join, a game tries to find a local small save file for that unique session, and if found, applies that on top of the loaded game. It meant plenty of new checks for information that is most likely out of date, because a player can join after a big break when the world is very different.
Hopefully that sheds some light on what is being worked on. For me, it turns out multiplayer is not as scary, but it is also not easy. We estimate that the update will be ready in April.