Network connection management
Players can create and join sessions using different network connection types and configuration options.
Note: The Multiplayer Services SDK uses sessions to manage groups of players. Sessions relies internally on different combinations of Unity Gaming Services such as Relay, Distributed Authority, Lobby, Matchmaker and Multiplay Hosting, and thus contributes to the billing of those services.
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.
When a client-hosted game uses direct networking, the IP addresses of all players are visible to the host. To protect player privacy in client-hosted games, the recommended best practice is to use Relay or Distributed Authority to handle NAT, firewalls, and player IP addresses.
Not all platforms support IPv6 connections. Only use IPv6 addresses after you verify that your target platforms support it.
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)
The recommended Default protocol might vary between platforms.
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 throughIHostSession; non-host clients cannot access this interface. To obtain anIHostSession, callsession.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 theISessioninterface.
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
RelayNetworkOptionsclass configures the session to start the relay connection using the platform-suggestedDefaultprotocol with the providedregionparameter. IfPreserveRegionis 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
nullvalue 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.
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(), orWithDistributedAuthorityNetwork(), 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
OnPlayerJoinedevent 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
DirectNetworkOptionsin 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
OnNetworkStateChangedevent handler logs network state changes for debugging purposes. - The
OnNetworkStartFailedevent handler provides a place to respond to errors if starting the network fails.
- By omitting the call to
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
OnNetworkStateChangedevent handler ensures that clients get notified via console logs whenever the underlying network state changes.
- The line