Skip to main content

Unity

Multiplayer FPS is a first-person shooter built with Unity 6 and Netcode for Entities (DOTS) that demonstrates dedicated server hosting on GameFlow using a direct connection (IP and port).

Based on Unity's official template

This sample builds on Unity's official Multiplayer FPS template, adapted here to show GameFlow hosting. All Unity trademarks, assets, and template code belong to Unity Technologies. This guide only covers the GameFlow integration layer on top.

Prerequisites

  • Access to the Multiplayer FPS repository (Early Adopter access required, contact GameFlow support)
  • A GameFlow account
  • Unity 6 (6000.x) with the Linux Dedicated Server build support module

Step 1: Clone the Repository

git clone https://github.com/GameFlowGG/gameflow-unity-multiplayer-example
cd gameflow-unity-multiplayer-example

Step 2: Open the Project

  1. Open Unity Hub
  2. Click Add → Add project from disk
  3. Select the cloned gameflow-unity-multiplayer-example directory
  4. Open it with Unity 6 (6000.x); let the Package Manager resolve packages on first import

Step 3: Install the GameFlow SDK

GameFlow provides a native Unity Game Server SDK that handles server lifecycle, automatic health reporting, and player tracking. Off GameFlow (running locally), the SDK switches to local mode automatically, so the same build runs everywhere with no extra configuration.

  1. Open Window → Package Manager → + → Add package from git URL

  2. Paste:

    https://github.com/GameFlowGG/gameflow-gameserver-sdk.git?path=/sdk/unity/Packages/gg.gameflow.gameserver#sdk/unity/v0.1.0

Requires Unity 2022.3+ with API Compatibility Level .NET Standard 2.1 (the Unity default).

Step 4: GameFlow SDK Integration

The dedicated server creates one GameFlowClient for the server process and drives the lifecycle from it. The bootstrap lives in Assets/Scripts/DedicatedServer/ServerBootstrap.cs and is guarded by #if UNITY_SERVER, so it only compiles into dedicated-server builds.

Initialization

Create the client and connect. GameFlowRunner pumps SDK callbacks onto Unity's main thread and sends a clean shutdown when the process quits:

var runner = GameFlowRunner.Create();
m_GameFlow = new GameFlowClient(new GameFlowOptions
{
Logger = new UnityDebugLogger(),
Dispatcher = runner.Dispatcher,
});
runner.Bind(m_GameFlow);

await m_GameFlow.Start(); // sidecar on GameFlow, local mode off it
GameFlowServerHost.Bind(m_GameFlow);

Player Tracking

With Netcode for Entities, peers connect and disconnect inside an ECS system, not a MonoBehaviour. A small static bridge lets the Burst-compiled server system report players. This keeps the server alive (GameFlow reaps servers reporting zero players past the idle timeout) and powers the live counts in the dashboard:

// GameFlowServerHost.cs, bridge between the ECS/Burst layer and the async SDK
public static class GameFlowServerHost
{
static GameFlowClient s_GameFlow;
public static void Bind(GameFlowClient gf) => s_GameFlow = gf;
public static void Clear() => s_GameFlow = null;

public static async void PlayerConnected(int networkId) {
if (s_GameFlow == null) return;
await s_GameFlow.Players.Connect(networkId.ToString());
}
public static async void PlayerDisconnected(int networkId) {
if (s_GameFlow != null) await s_GameFlow.Players.Disconnect(networkId.ToString());
}
}

Then forward Netcode's connection events from ServerGameSystem, where they are already read from NetworkStreamDriver.ConnectionEventsForTick. Wrap the calls in [BurstDiscard] helpers so the Burst-compiled struct stays valid:

foreach (var evt in connectionEventsForTick)
{
if (evt.State == ConnectionState.State.Connected)
NotifyGameFlowPlayerConnected(evt.Id.Value); // [BurstDiscard] -> GameFlowServerHost.PlayerConnected
if (evt.State == ConnectionState.State.Disconnected)
NotifyGameFlowPlayerDisconnected(evt.Id.Value); // [BurstDiscard] -> GameFlowServerHost.PlayerDisconnected
}

The player list capacity comes from the Max Players per Server value you set on the game in GameFlow, so the server doesn't set it. The Netcode NetworkId is used as the session id. See Player Tracking for details.

Server Start

Bind the Netcode-for-Entities transport on a fixed port, then signal readiness. Health reporting starts automatically, there's no manual health loop to maintain:

const ushort ServerPort = 7979;

var gameConnection = GameConnection.GetServerConnectionSettings(ServerPort);
GameManager.SetGameConnection(gameConnection);

// server world -> NetworkStreamDriver singleton
GhostBridgeManager.Instance.SetServerNetworkStreamDriver(serverDriver);
serverDriver.Listen(gameConnection.ListenEndpoint);

await m_GameFlow.Ready();

Step 5: Build the Dedicated Server

The dedicated server must boot ServerScene (the scene holding ServerBootstrap).

  1. Open File → Build Profiles
  2. Create (or duplicate) a Dedicated Server → Linux profile
  3. In that profile, override the scene list so ServerScene is first
  4. Build (IL2CPP) into the Build/ folder

If the server logs NullReferenceException from GhostSpawner / ManagerGhostsSpawner, the build booted a client scene instead of ServerScene, fix the profile's scene list.

Step 6: Package for Upload

Unity Linux servers ship as a container image. The repo includes Build/Dockerfile, which installs the runtime libraries the Unity 6 player and Unity App UI need. GameFlow builds and runs the image for you, no local Docker step required.

Create a .zip of the Build/ folder (including the Dockerfile) for upload.

Step 7: Create a Game on GameFlow

  1. Log in to your GameFlow account
  2. Navigate to the Games section → Create New Game
  3. Set Name to Multiplayer FPS
  4. Set Game Engine / Framework to Unity

Create Game

Step 8: Configure Server Settings

  1. Set Memory to 1GB
  2. Set vCPU to 1 core
  3. Set the Port to 7979 (must match ServerPort and the Dockerfile EXPOSE)
  4. Set Max Players per Server (drives player-tracking capacity)
  5. Enable the regions you want to test

Server Settings

Step 9: Deploy and Test

  1. Upload the .zip file in the builds section
  2. Click Create Test Server, wait for the server to reach "Ready"

Test Server Ready

  1. Run the game locally in Unity, from the main menu enter the server IP and port

Multiplayer FPS Lobby

  1. Click Join

Multiplayer FPS In-Game

Running locally with no GameFlow runtime present, the SDK logs connected (local mode) and server ready. The same build connects to the GameFlow runtime automatically (sidecar mode) when deployed.