HOMEBLOG

AeroCEO Net Bridge

Adam C. Clifton
5 Dec 2025

While AeroCEO is primarily a single player game, I wanted to support multiplayer. It is more difficult to add multiplayer later in development, so I've been making sure it's integrated well from (almost) the start.

The first thing to do was chaning the game rules slightly to be asyncronous turn based. Instead of rotating through players taking one turn at a time, all turns happen in parallel, which makes the game run faster. In the end this does not change too much, but some things like multiple players bidding for a limited number of slots will have to resolve differently.

The second part to make multiplayer easier is that the game is always running a multiplayer game. So when running in single player, the game will still internally run a server that the client will connect to. I had thought about using a real loopback network connection for this, but that might not work on all platforms. Ie: Can you open a listen socket on Switch or iOS? And it would also be slightly slower having to throw all actions across a socket.

The alternative is what i've called a "bridge", basically it's a pretend socket. When playing in offline single player or online multiplayer, the players client will do all of its communication over the bridge. In true offline single player, the bridge will instantly pass data to the internal server via a function call. In multiplayer, the bridge will pass the data over the internet via GameStrut to be processed on a remote server.

To be a multilpayer game, we need ways to keep everyones game and the server in sync. We do that with two parts, serializable game state, and actions. Both of these can be packed or unpacked into blobs, which are a basic building block of GameStrut, like little virtual files that we can read and write to.

The game state includes the world, airports, companies, routes etc. So for AeroCEO, when a player joins a game, the server can pack the whole world stae into the blob and send it to the joining client, that can unpack it and have their game state match whatever is on the server.

Actions then make changes to this data, eg: purchsing planes, bidding on slots and creating routes. When a player makes an action, the client applies it locally, then sends the action to the server to be applied there and forwwaded to all the other players so everyone is up to date.

There is one little complication to that tho, we want to keep players actions secret from each other till the end of turn.
So for this the server will actually hold all queued actions and only finally applying and sending to others at the end of the turn.

Also, when sending the game state to a player, we only send their queued actions, not everyones. A neat feature of keeping the queued actions and applying at the end of turn, is that it's trivial to add undo functionality, we just drop the last queued action for a player.

Previous: C# On Linux ARM
© Numbat Logic Pty Ltd 2014 - 2022