> ## Documentation Index
> Fetch the complete documentation index at: https://docs.qwacks.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Multiplayer

> Parties, matchmaking and sessions, and players connected through Flock's relay.

Flock's **multiplayer** brings players together and connects them. Friends form a
[party](/guides/parties.md), the party or a lone player [finds a match](/guides/matchmaking.md) or joins
a friend's game by code, and every game is a [session](/guides/sessions.md): one player hosts, the
others hold seats. The SDK then [connects the players](/guides/connecting-players.md) over your
game's networking: Netcode for GameObjects on Unity, the engine's own networking on Unreal.
Players on the host's network connect to it directly; everyone else goes through Flock's relay, so
nobody forwards a port, and on Unity moves to a direct path to the host when the two can reach
each other. When the host leaves, another player takes over.

> [!NOTE]
>
> **Scope:** matchmaking queues and multiplayer settings are defined per **game**; parties and seats belong to a player.

> **[Parties](/guides/parties.md)**
>
> Friends who stay together from one game to the next.

> **[Matchmaking](/guides/matchmaking.md)**
>
> Fill a game from a queue, alone or as a party.

> **[Sessions](/guides/sessions.md)**
>
> One game: a host, its players and a join code.

> **[Connecting players](/guides/connecting-players.md)**
>
> Netcode for GameObjects or Unreal's own networking, the relay, and host changes.

## Setting up

**Dashboard**

Open **Multiplayer → Sessions** and click **Multiplayer settings**. The defaults suit most games:

| Setting | Default | What it does |
| - | - | - |
| **Max players per session** | 8 | Seats in a session a player hosts or a match makes, from 2 to 16. |
| **Participant timeout (seconds)** | 90 | A player silent for longer than this loses their seat. |
| **Host timeout (seconds)** | 60 | A host silent for longer than this is replaced by the player seated longest. |
| **Session max age (seconds)** | 14400 | Every session ends after this long (4 hours), however busy it is. |
| **Create a session when a match forms** | On | Matched players get a session to play in. |
| **Hand out relay credentials** | On | Players on different networks connect through Flock's relay. When off, only players on the host's network, or on a port forwarded to it, can connect. |

Then make a queue for each mode under **Multiplayer → Matchmaking**; see
[Matchmaking](/guides/matchmaking.md).

**Unity**

1. Install **Netcode for GameObjects** 1.x or 2.x from the Package Manager. Flock's netcode
   support compiles only when it is installed. Every player of a game must use the same major
   version. Multiplayer is verified on Unity 2021.3 with Netcode 1.14 and on Unity 6000.3 with
   Netcode 2.13.
2. In **Flock → Settings**, set **Party Refresh Seconds**: how often the SDK reads the player's
   party in the background (10 by default; 0 turns it off).
3. Use one `NetworkManager` with Unity Transport, left at its default message size.
4. Sign the player in before any multiplayer call, and make every call from the main thread.
   Every multiplayer event is raised on the main thread.
5. Scripts that use multiplayer start with `using Flock;` and `using Flock.Providers;` (add
   `using Flock.Exceptions;` for `FlockErrorCode` and `using Unity.Netcode;` for `NetworkManager`).
   A script in an assembly definition of its own references `Flock.Runtime`, and
   `Flock.Multiplayer.Netcode` for `StartNetcodeAsync`.

Every call is on `FlockClient.Instance.Multiplayer`, or on an object it returns.

The package's **Samples/Multiplayer** folder has two one-screen samples:
**FlockPlayWithFriendsSample** (host, read out the code, a friend joins it) and
**FlockQuickMatchSample** (players find each other in a queue). Add either to an empty
GameObject and press Play in two copies of the game.

**Unreal**

1. Use Unreal Engine 5.4 to 5.8 and Flock Unreal SDK 1.35.0 or later. Multiplayer runs on the
   engine's own networking, so there is nothing else to install.
2. In **Project Settings → Plugins → Flock SDK Settings**, under **Multiplayer**, set **Party
   Refresh Seconds**: how often the SDK reads the player's party in the background (10 by
   default, about 6 requests a minute per player; 0 turns it off).
3. Give the host a game mode that lets in only the session's players: a Blueprint based on
   **Flock Game Mode Base** (or **Flock Game Mode**, for match states) set in **Project Settings →
   Maps & Modes**, or a game mode of your own that calls Flock's check in `PreLoginAsync`; see
   [Who is joining](/guides/connecting-players.md#who-is-joining). A host without it lets nobody
   in (`join_check_missing`).
4. Keep the engine's IP networking. With the Steam online subsystem, set
   `bUseSteamNetworking=False` under `[OnlineSubsystemSteam]` in `Config/DefaultEngine.ini`:
   Steam's sockets cannot listen on an IP address, so Travel To Session would end
   `could_not_start`. Signing in through Steam is unaffected.
5. Sign the player in before any multiplayer call, and make every call from the game thread.
   Every multiplayer event is raised on the game thread.
6. C++ that uses multiplayer includes `FlockSubsystem.h` and `Multiplayer/FlockParty.h` or
   `Multiplayer/FlockMultiplayerSession.h`, in a module that depends on `Flock` in its
   `.Build.cs`.

Every call is on `UFlockSubsystem::GetMultiplayerProvider()`, or on an object it returns. In
Blueprint, every call is a node under **Flock | Multiplayer**.

The plugin's **Content/Samples/Multiplayer** folder (turn on **Show Plugin Content** in the
Content Browser) holds a sample made of Blueprints only, from SDK 1.36.0:
**BP\_FlockSampleGameInstance** signs in with a device name, hosts, joins by code, quick matches,
travels to the session and travels again when the host changes; **FlockMultiplayerSample** is its
level, running Flock Game Mode Base. Set **Game Instance Class** to `BP_FlockSampleGameInstance`
in **Project Settings → Maps & Modes**, open the level, and play it in two standalone games,
each signed in with its own device name.

![The sample's card: a device name field, Sign In and Host, a join code field and Join, a queue name field, Quick Match and Leave, and the status line In the game with its code](https://mintcdn.com/qwacks/sKCVX05gMuqzHxSa/images/guides/unreal-multiplayer-sample-in-game.png?fit=max\&auto=format\&n=sKCVX05gMuqzHxSa\&q=85\&s=663013f462f2009675ccf7458de8f357)

The Unreal sample in a game: its status line shows the join code a friend types to join.

## Which setup fits your game

| Your game | Players meet by | Relay |
| - | - | - |
| Local co-op: devices on one network (a LAN party, one Wi-Fi) | A session's join code | Only when needed (the default): players on the host's network connect directly. Or never, for no relay at all. |
| Online co-op with friends on other networks | A session's join code | Only when needed |
| Online matchmaking with strangers | A queue | Only when needed |
| Friends matched together, against or with others | A party, then a queue | Only when needed |
| Streamers and competitive play, where nobody may see another's IP address | Any of the above | Always, on every game |
| Steam, Epic Online Services or your own networking | Any of the above | Not used |

Several players on one device (split screen, shared controllers) need none of this: that is one game
with one Flock player, and Flock's multiplayer connects devices.

**Dashboard**

* **Local co-op:** nothing beyond the multiplayer settings.
* **Online co-op with friends:** leave **Hand out relay credentials** on.
* **Online matchmaking:** a queue for each mode under **Multiplayer → Matchmaking**, with its
  smallest and largest match.
* **Friends matched together:** a queue whose largest match holds the whole party.
* **Streamers and competitive play:** nothing more; the choice is made in the game.

**Unity**

**Local co-op, and online co-op with friends.** One player hosts and shares the join code (read out
in the room, or through your game's own lobby, friends list or chat); the others join with it.
Players on the host's network connect directly; with the default `WhenNeeded`, a friend on another
network comes through Flock's relay, then moves to a direct path when the two can reach each other.
Phones and PCs play together the same way. The **FlockPlayWithFriendsSample** does exactly this.

```csharp theme={null}
// The host's game.
FlockMultiplayerSession session = await FlockClient.Instance.Multiplayer.HostSessionAsync(4);
joinCodeLabel.text = session.JoinCode;
await session.StartNetcodeAsync(NetworkManager.Singleton);

// Each other player's game, with the code the host shared.
FlockMultiplayerSession joined = await FlockClient.Instance.Multiplayer.JoinSessionAsync(typedCode);
FlockNetcodeStartResult started = await joined.StartNetcodeAsync(NetworkManager.Singleton);
// started.ThroughRelay is false for a player on the host's network.
```

For a LAN-only game, pass `new FlockNetcodeOptions { Relay = FlockRelayUse.Never }` on every game; a
player elsewhere then gets `CouldNotConnect` unless a port is forwarded to the host.

**Online matchmaking.** The **FlockQuickMatchSample** does this.

```csharp theme={null}
FlockMatchmakingResult found = await FlockClient.Instance.Multiplayer.FindMatchAsync("casual-1v1");
if (found.IsMatched && found.Session != null)
    await found.Session.StartNetcodeAsync(NetworkManager.Singleton);   // the player who waited longest hosts
else
    ShowMessage("No match: " + found.Outcome);
```

**Friends matched together.** The friends form a [party](/guides/parties.md) and the leader searches for
all of them; every member's game hears the result.

```csharp theme={null}
party.SearchEnded += async result =>
{
    if (result.IsMatched && result.Session != null)
        await result.Session.StartNetcodeAsync(NetworkManager.Singleton);
};

if (party.IsLeader)
    await party.FindMatchAsync("squads");
```

**Streamers and competitive play.** Every packet goes through Flock's relay and no game learns
another's IP address; each packet takes the relay's extra hop.

```csharp theme={null}
await session.StartNetcodeAsync(NetworkManager.Singleton, new FlockNetcodeOptions { Relay = FlockRelayUse.Always });
```

**Steam, Epic Online Services or your own networking:** see
[Other networking](/guides/connecting-players.md#other-networking).

**Unreal**

The examples run in your game instance, which outlives the level changes Travel To Session
makes. `TravelOptions` is an `FFlockTravelToSessionOptions` kept there, its `HostLevel` set to
the level the host opens.

**Local co-op, and online co-op with friends.** One player hosts and shares the join code (read out
in the room, or through your game's own lobby, friends list or chat); the others join with it.
Players on the host's network connect directly; with the default `WhenNeeded`, a friend on another
network comes through Flock's relay.
The sample's **Host** and **Join** buttons do exactly this, in Blueprint.

```cpp theme={null}
FFlockMultiplayerProvider* Multiplayer = GetSubsystem<UFlockSubsystem>()->GetMultiplayerProvider();

// The host's game.
Multiplayer->HostSession(4, FFlockCommandData(), true, [this](TFlockResult<UFlockMultiplayerSession*> Hosted)
{
    if (Hosted.IsSuccess())
    {
        Session = Hosted.Value;
        ShowJoinCode(Session->GetJoinCode());
        Session->TravelToSession(this, TravelOptions, [](TFlockResult<FFlockTravelToSessionResult> Travel) {});
    }
});

// Each other player's game, with the code the host shared.
Multiplayer->JoinSession(TypedCode, [this](TFlockResult<UFlockMultiplayerSession*> Joined)
{
    if (Joined.IsSuccess())
    {
        Session = Joined.Value;
        Session->TravelToSession(this, TravelOptions, [](TFlockResult<FFlockTravelToSessionResult> Travel)
        {
            // Travel.Value.bThroughRelay is false for a player on the host's network.
        });
    }
});
```

For a LAN-only game, set `TravelOptions.Relay = EFlockRelayUse::Never` on every game; a player
elsewhere then gets `could_not_connect` unless a port is forwarded to the host.

**Online matchmaking.**
The sample's **Quick Match** button does this, in Blueprint.

```cpp theme={null}
Multiplayer->FindMatch(TEXT("casual-1v1"), FFlockMatchmakingOptions(), [this](TFlockResult<FFlockMatchmakingResult> Found)
{
    if (Found.IsSuccess() && Found.Value.IsMatched() && Found.Value.Session != nullptr)
    {
        Session = Found.Value.Session;   // the player who waited longest hosts
        Session->TravelToSession(this, TravelOptions, [](TFlockResult<FFlockTravelToSessionResult> Travel) {});
    }
    else if (Found.IsSuccess())
    {
        ShowMessage(TEXT("No match: ") + Found.Value.Outcome);
    }
});
```

**Friends matched together.** The friends form a [party](/guides/parties.md) and the leader searches for
all of them; every member's game hears the result.

```cpp theme={null}
Party->OnSearchEnded.AddDynamic(this, &UMyGameInstance::PlayMatch);

if (Party->IsLeader())
{
    Party->FindMatch(TEXT("squads"), FFlockMatchmakingOptions(), nullptr);
}

void UMyGameInstance::PlayMatch(const FFlockMatchmakingResult& Result)
{
    if (Result.IsMatched() && Result.Session != nullptr)
    {
        Session = Result.Session;
        Session->TravelToSession(this, TravelOptions, [](TFlockResult<FFlockTravelToSessionResult> Travel) {});
    }
}
```

**Streamers and competitive play.** Every packet goes through Flock's relay and no game learns
another's IP address; each packet takes the relay's extra hop. Set it on every game:

```cpp theme={null}
TravelOptions.Relay = EFlockRelayUse::Always;
```

**Steam, Epic Online Services or your own networking:** see
[Other networking](/guides/connecting-players.md#other-networking). Travel To Session needs the
engine's IP networking, so a game on Steam's sockets publishes a Steam connection of its own.

## What the SDK does for you

* **Keeps each seat.** It sends the session's heartbeat every 20 seconds while the game runs.
* **Keeps your objects current.** It reads the party, a search and the session in the background,
  and raises events when something changed: a player joined, the leader or host changed, a search
  ended, the session ended.
* **Finds the session again** after the game restarts (`GetMySessionAsync`, or `GetMySession` on
  Unreal), and the party (`GetMyPartyAsync`, or `GetMyParty`).
* **Gives the seat up when the game quits**, so the others see it at once.

## What counts as an API call

The background reads (the party, a search, the session, waiting for the host to say where it is)
and heartbeats are **not** billed as API calls. They share a limit of **120 a minute per player**;
the SDK's defaults use under 60. Actions are billed as usual: making or joining a party or session,
starting a search, leaving, the host's check of each joining player, relay logins, and a relayed
player telling the host its relay address (once for each address).

## Which games it fits

The host is one of the players, sessions hold up to 16, and matching is first come, first served.

| Fits well | Fits with care | Not a fit today |
| - | - | - |
| Co-op games for 2 to 8 players: dungeon crawlers, survival, horde shooters | Casual 1v1 and 2v2 versus, not ranked | MMOs and always-on worlds |
| Party games, brawlers, racing with friends | Fast shooters: the host has an advantage, and a player who stays on the relay plays through its extra hop | Battle royale and other games of 50 to 100 players |
| Board, card and turn-based games | 9 to 16 players: the host sends to everyone, which counts on a phone | Ranked play that needs dedicated servers and skill matching |
| Phone and PC playing together | Worlds kept by a player: save the state off the host | Browser games (a browser cannot send UDP) |

## Limits today

* **No dedicated servers.** A player hosts every session.
* **No skill or region matching yet.** Flock stores what a search sends but matches in the order
  players search. Use a queue per mode and region.
* **A host cannot remove a player, and a session's data is set once** when it is created.
* **One kind of networking per engine.** On Unity, Netcode for GameObjects 1.x and 2.x; on Unreal, the
  engine's own IP networking, not Steam's sockets. Other networking uses the session's published
  connection and join token directly; see [Connecting players](/guides/connecting-players.md).
* **On Unreal, relayed players stay on the relay.** The Unreal SDK has no direct path yet, so each
  of their packets takes the relay's extra hop.
* **Web players** can use parties, matchmaking and sessions, but not the relay: a browser cannot
  send UDP.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.