ECS multiplayer game networking initialization

Hey!

I was tinkering with the structure of our game and I have a question about when and how to initialize the connection between clients and host in netcode for entities.

What I would like to do is something like this:

  1. Main menu (Mono)
    • Player clicks on join or host button, loads the lobby scene in
  2. Lobby (Mono)
    • Lobby is created or joined depending on whether the player wanted to host or join a lobby
    • Game is started once everyone is ready, players start to load the game scene
  3. Game (ECS)
    • Creates the ECS worlds and connects them to the current game session using unity relay
    • everyone is connected and happy

It is important to note that the MainMenu, Lobby and Game are all separate scenes in this case.

Is there anything in this flow that would catch me off guard and rid me of all my programmer joy? I am asking because we’ve encountered many party crashers when thinking about netcode architecture.

Thank you!

You could unify them. You only need an “empty shell” scene that contains the bootstrap objects, ie all global singletons.

The rest of the scenes you load and unload additively as needed. This lends itself particularly well to networking, but also resource management as loading a scene in single-mode is much heavier (destroy and likely re-instantiate the same things) than additive loads (load/unload only what changes).

Consider this one particular case:

  • Lobby is created or joined depending on whether the player wanted to host or join a lobby

With single-loaded scenes this means you have to somehow “record” the choice whether to create or join a lobby. Most commonly you’ll use a DontDestroyOnLoad object for this.

Then after the Lobby scene loaded, you’ll need to request the data from the DDOL object to update the Lobby state accordingly. This means that any Lobby scripts dependent on the Lobby state will need to either wait for the Lobby initialization to complete (separate event) or access the same DDOL object (more dependencies).

If this were done with an additively loaded scene, it changes the process entirely:

  • Clicking the Join / Create button instantly issues a Lobby creation or join event
  • Next the Lobby scene is loaded additively in the background, but waits for activation
  • The Lobby creation process when completed then activates the Lobby scene, at which point the Lobby scripts run their Awake and can 100% rely on the Lobby’s connection already being valid
  • If an error occurs or the user presses “Cancel” the scene load is aborted respectively the scene never gets activated.

Result: by the time the Lobby scene loaded chances are the Lobby connection has already been established and the whole menu flow is much snappier.

To be honest, the process you describe is eerily oversimplified.

What happens if Lobby creation fails?

What happens if a client drops between Lobby and the game start?

What if a player drops mid-session - return to Lobby? Can the player reconnect mid-session?

Those events are super important to consider and get right from the start because these situations occur in the real world and can easily lead to negative user reviews (ie “game stuck on the loading screen”) if your game won’t properly respond to failure states.

Specifically for establishing the connection to the game session I would do so in the Lobby screen to ensure all clients are properly connected. Then issue the load. This has benefits:

  • Initializing the session is quick, the Lobby confirms everyone being connected respectively if not, none of the players are force-loaded into a game that they didn’t intend to start without their friend and now have to back out again.
  • Game scene loads with an active connection ie no scenario where you load the game scene, fully set it up for singleplayer, then in the midst of it realize “oh there’s a networking connection now” and shuffle a number of things around => this is what bugs thrive on.
  • Returning to the Lobby with an active session is “normal”
  • No code duplication between Lobby and ingame, ie if players are allowed to select an Avatar you don’t have to synchronize their appearance both via the Lobby and via the session netcode - it all happens with a session already established, using the same Player entities rather than Lobby duplicates.