Documentation

Support

Multiplayer

Multiplayer

Network connection management

Understand different network connection types and configuration options available for multiplayer sessions.
Read time 5 minutesLast updated 12 hours ago

Players can create and join sessions using different network connection types and configuration options.

Types of network

By default, the following network connections types are available with the sessions system:
  • Direct network connection.
  • Client-hosted solutions by Unity, using Relay or Distributed Authority. This type is the recommended best practice for peer-to-peer games played over the internet.
Refer to
Class SessionOptions > Methods
for more information.
Advanced users can provide additional connection types via a custom
INetworkHandler
implementation. Refer to Using a custom network handler for an example.

Configurable network options

You can override the default network options of your sessions, including both direct and relay-based networking. If you don't specify network options when calling the
WithRelayNetwork()
,
WithDirectNetwork()
, or
WithDistributedAuthorityNetwork()
methods, the session system automatically applies its default settings to configure the requested network type. For details about default values and behaviors for these methods, refer to Class SessionOptionsExtensions.

DirectNetworkOptions

Configure direct network connections with
DirectNetworkOptions
. Use these options with
WithDirectNetwork()
when setting a
SessionOption
to override the default behavior. The following settings are available:
  • ListenIp: The IPv4 or IPv6 address that you monitor for incoming IP connections.
  • PublishIp: The IPv4 or IPv6 address to publish for other clients to connect to.
  • Port: The port number used for both listening and publishing endpoints.

RelayNetworkOptions

Configure relay protocol-based network connections with
RelayNetworkOptions
. Use it with the
WithRelayNetwork()
or
WithDistributedAuthorityNetwork()
when setting
SessionOption
to override the default behavior.
The following settings are available:
  • Protocol: Defines the network protocol that the Relay connection uses.
  • Region: Forces a specific Relay region to be used, and skips autoselection from QoS results.
  • PreserveRegion: If enabled, saves the relay region to session properties, and reuses it in case of host migration.
The following Relay protocols are supported:
  • User Datagram Protocol (UDP)
  • Datagram Transport Layer Security (DTLS)
  • Secure websocket (WSS)

Session and Netcode lifecycle separation

Starting with Multiplayer Services SDK version 1.2, you have the option to start the network connection after a session is created. The decoupled network lifecycle gives you greater flexibility and control over your game flow. After the host initiates the network connection, clients are notified and use the connection information shared by the host to start their own network connections. The connection information is shared with clients via session properties. The session's
Network
property exposes two different interfaces:
  • IHostSessionNetwork
    : Lets hosts control the network connection directly - start, stop, and manage it as needed. Available only through
    IHostSession
    ; non-host clients cannot access this interface. To obtain an
    IHostSession
    , call
    session.AsHost()
    . This may fail if the caller is not the host.
  • IClientSessionNetwork
    : Allows access only to network state and associated events. Can be accessed through the
    ISession
    interface.
This separation has the following benefits:
  • You can delay starting the network connection until certain conditions are met, for example:
    • The host manually starts the game.
    • The session reaches the maximum number of players.
    • All players mark themselves as ready.
  • As a host, you can stop the network connection at any time while keeping the session open, and restart it if needed.

Network connection management examples

The following examples demonstrate how to configure connection types, options, and lifecycle management for the networking solution tied to your session.

Example: Creating a session with a client-hosted solution with overridden default relay options

The following example demonstrates how to create a session using a Unity client-hosted solution with overridden options provided to the relay allocation:
// When the region is specified, it forces the use of a specific Relay region, and skips QoS auto-selection.async Task StartSessionAsHost(string region = null){ var options = new SessionOptions { MaxPlayers = 2 }.WithRelayNetwork(new RelayNetworkOptions(RelayProtocol.Default, region, true)); // or WithDistributedAuthorityNetwork() to use Distributed Authority instead of Relay var session = await MultiplayerService.Instance.CreateSessionAsync(options); Debug.Log($"Session {session.Id} created! Join code: {session.Code}");}
The points from Example: Creating a session with a client-hosted solution also apply to this example, along with the following information:
  • The
    RelayNetworkOptions
    class configures the session to start the relay connection using the platform-suggested
    Default
    protocol with the provided
    region
    parameter. If
    PreserveRegion
    is set to true, the newly-elected host doesn't change the relay allocation region in the event of a host migration. If set to false, the region might change.
  • If the region isn't passed as a parameter, the default
    null
    value triggers a QoS query to determine the most optimal region for the relay allocation. For the list of available regions, refer to [Relay locations and regions][RelayRegions].

Example: Using a custom network handler

Advanced users can specify a custom network handler by implementing INetworkHandler, which overrides the default integration with Netcode for GameObjects and Netcode for Entities. You can provide integration with any third-party networking solutions when implementing the
INetworkHandler
interface.
var options = new SessionOptions { MaxPlayers = 2 }.WithRelayNetwork().WithNetworkHandler(new CustomEntitiesNetworkHandler());

Example: Starting Netcode at a later time

In some games, you might want to delay starting the network connection and gameplay until certain conditions are met, for example, until all players have joined and are ready. The following example demonstrates how to delay the connection using the Session API.
async Task StartSessionAsHost(){ var options = new SessionOptions { MaxPlayers = 4 }; // note the omitted `With<X>Network() call. var session = await MultiplayerService.Instance.CreateSessionAsync(options); session.PlayerJoined += OnPlayerJoined; session.Network.StartFailed += OnNetworkStartFailed; session.Network.StateChanged += OnNetworkStateChanged; Debug.Log($"Session {session.Id} created! Join code: {session.Code}"); void OnPlayerJoined(string playerId) { // verify if we have reached the max player count if (session.PlayerCount == session.MaxPlayers) { var networkOptions = new DirectNetworkOptions(ListenIPAddress.AnyIpv4, PublishIPAddress.LoopbackIpv4, 7777); // start the network once max player count have been reached _ = session.Network.StartDirectNetworkAsync(networkOptions); } } void OnNetworkStateChanged(NetworkState state) { switch (state) { case NetworkState.Starting: Debug.Log("Starting network..."); break; case NetworkState.Started: Debug.Log($"Network has started, listening on: {session.Network.NetworkInfo.ListenAddress}, " + $"and publishing on: {session.Network.NetworkInfo.PublishAddress} created!"); break; default: Debug.Log($"[{nameof(StartSessionAsHost)}] Network state has changed! New State:{state:G}"); break; } } void OnNetworkStartFailed(SessionError error) { // handle the error Debug.LogError($"Network start failed: {error:G}"); }}async Task JoinSessionAsClient(string sessionJoinCode){ // Join the session var session = await MultiplayerService.Instance.JoinSessionByCodeAsync(sessionJoinCode); Debug.Log($"Network state at the time of connection was: {session.Network.State:G}."); session.Network.StateChanged += OnNetworkStateChanged; void OnNetworkStateChanged(NetworkState state) { Debug.Log($"[{nameof(JoinSessionAsClient)}] Network state has changed! New State:{state:G}"); }}
Consider the following details about how this example works:
  • Host(
    StartSessionAsHost
    ):
    • By omitting the call to
      WithDirectNetwork()
      ,
      WithRelayNetwork()
      , or
      WithDistributedAuthorityNetwork()
      , the session is created without starting a netcode connection right away.
    • The line
      var session = await MultiplayerService.Instance.CreateSessionAsync(options);
      creates the session, and makes the player the host.
    • The next three lines subscribe to session lifecycle events: player joining, network state changes, and network start failures.
    • The
      OnPlayerJoined
      event handler checks if the maximum number of players is reached. In this example, the maximum number is four.
    • After the required number of players has joined the session,
      session.Network.StartDirectNetworkAsync(networkOptions)
      is called to start the network connection.
    • The
      DirectNetworkOptions
      in this example are configured to listen on any IPv4 addresses (0.0.0.0), publish on 127.0.0.1 and use port 7777.
    • The
      OnNetworkStateChanged
      event handler logs network state changes for debugging purposes.
    • The
      OnNetworkStartFailed
      event handler provides a place to respond to errors if starting the network fails.
  • Client(
    JoinSessionAsClient
    ):
    • The line
      var session = await MultiplayerService.Instance.JoinSessionByCodeAsync(sessionJoinCode);
      joins the session using the provided join code.
    • After joining, the current network state is logged.
    • The
      OnNetworkStateChanged
      event handler ensures that clients get notified via console logs whenever the underlying network state changes.