Lothsahn and I have been hard at work on the multiplayer implementation. There are a ton of challenges, but we’re inching closer. This post will dive into some of the technical nitty-gritty and the obstacles we’ve tackled in our multiplayer solution. [h3]Fixed Step[/h3] Our first hurdle is reworking Final Factory into a fixed step, deterministic simulation. Currently, FF runs with your machine’s FPS using delta time, so your framerate doesn’t affect the simulation rate. Simple, right? Well, it would have been had I built it this way in the first place! Luckily we're already pretty much done with this part. We’ve hardened up the optional fixed rate mode, which you can toggle in the dev console with the `ToggleRateLimiting` command. This makes the simulation update with the same delta time each frame, tying your updates/sec to your max framerate. So, if your framerate takes a nap, your simulation takes a nap too. [h3]The Heartbeat[/h3] Next up is ensuring that when a client joins a game, they sync perfectly with the host (the host is the authority over game state changes). We’ve added a heartbeat system that increments a ushort value indicating the current fixed step. Think of it as the game’s pulse, with each fixed update issuing a new heartbeat. This has been the main architecture we've been working on in recent weeks. When a client joins, they’re informed of the current heartbeat, allowing us to sync their fixed updates with the host. It’s like a dance, and everyone’s got to be in step! [h3]Updating the Game World via RPCs[/h3] We’re using Unity Netcode for GameObjects to send RPCs. But here’s the twist: the player controller isn’t locked to the fixed update. The baseline UPS will be around 60UPS. If your framerate is higher, you can control the player at this higher framerate for a buttery-smooth experience. Client actions can happen at any frame but sync up in a heartbeat. Here’s how it works when a player updates the game world, like placing a blueprint: [olist] [*]The client places a blueprint via a player controller action state. [*]The blueprint appears with a flag saying, “I’m not active yet!” to avoid placement lag while waiting for host confirmation. [*]A RPC notifies the host of the client’s action. [*]The “Place Blueprint” operation is queued with the necessary blueprint items. [*]During the next heartbeat, the host updates the game world by placing the blueprints. [*]The host sends a RPC confirming the blueprint placements to all clients. [*]Clients receive the RPC, queue the actions, and execute them on the next heartbeat, ensuring all updates happen at the right fixed step. [/olist] As you can see, all client-issued game state updates must go through the host. Every state change is confirmed by the host and replicated to all clients. The factory itself runs deterministically on all clients, so only player actions need replication, saving us a ton of bandwidth. [h3]What’s Left to Do?[/h3] We’ve nailed down some major multiplayer architecture items, including setting up Steam lobbies, joining saved games, and initiating a shared factory simulation in lockstep with other clients (a major recent milestone). Here’s what’s left: [list] [*]Implement RPCs for all player controller states as described. [*]Get bots using fixed point world space for off-grid movement. [*]Identify and fix any determinism bugs/issues during testing. [/list] [h3]Combat[/h3] Combat will be a bit different. Enemy ships won’t be part of the factory simulation due to challenges with ships in float3 world space while multiplayer needs fixed point space for determinism. For combat, we’ll likely use a traditional multiplayer model, sending more RPCs for ship damage and destruction. More details on this as we get closer. So there you have it! We’re making strides and can’t wait to share more progress with you soon. Stay tuned! [url=https://discord.gg/finalfactory]Discord[/url] [url=https://finalfactory.myshopify.com/]Support development by buying merch![/url] [url=https://final-factory.nolt.io/]Vote on features[/url]