Kanda Foundation 0.8.0
Loading...
Searching...
No Matches
Session Hosting Modes

There are multiple ways to play sessions in the Kanda SDK. Sessions can be joined offline, connected to a dedicated server, or hosted by clients themselves, allowing other clients to join via relay or LAN.

In this context, client refers to code that joins and participates in a session, while server refers to code that hosts a session for one or more clients.

Hosting Modes and Session Strategies

Each play mode corresponds to a specific strategy in the AppLifecycleService:

  1. Offline Mode: Uses IOfflineSessionStrategy
    • Both client and server code runs in the same application.
  2. LAN Client Hosted Mode: Uses ILanSessionStrategy
    • One client acts as both client and server, with other clients joining over LAN.
  3. Relay Client Hosted Mode: Uses IRelaySessionStrategy
    • Uses relay server for client-hosted sessions over the internet.
    • Provides NAT punchthrough and secure connections.
    • Allows clients to host and join sessions using a join code.
  4. Dedicated Server Hosted Mode:
    • For hosting: Uses IServerSessionHostingStrategy
    • For joining: Uses IServerSessionJoiningStrategy
    • Client code runs on end-user applications, server code on dedicated servers.

Choosing a Hosting Mode

When deciding which hosting mode to use, consider the following factors:

  1. Offline: Use for single-player experiences or local testing.
  2. LAN: Use for local multiplayer when all players are on the same network.
  3. Relay: Use for internet-based multiplayer when you don't have dedicated servers.
  4. Dedicated Server: Use for large-scale multiplayer or high-complexity simulations.

Each mode has its strengths and is suited for different scenarios. Choose the one that best fits your application's needs and infrastructure capabilities.

Local Ports

Local sessions (offline, LAN, or lobby) run client and server code in separate processes that communicate via localhost, making them effectively "multiplayer" sessions. This means local sessions support the full feature set of networked multiplayer, since the architecture is identical.

When hosting sessions locally, we need to select a port for network communication. This is handled through a dynamic port selection strategy.

Port Range Configuration

Configuration is managed in Kanda SDK project settings by specifying minimum and maximum port values. Default range is typically 7000-8000 and can be adjusted based on your environment's requirements.

Port Selection Process

We search the configured range sequentially and test each port for availability using UDP, then use the first available port found. If no ports are available in the selected range, the session will fail to start.

Consider adjusting the port range if conflicts occur frequently in your deployment environment.

Secure Websockets (WSS)

To establish secure connections or to enable use on restrictive firewalls for internet-based sessions, you can enable Connect Using Websockets in the Kanda SDK project settings.

When this flag is enabled, client apps establish the connection using the Secure WebSocket (WSS) protocol. In this context, connections appear as secure TLS traffic at the cost of degraded performance.

WSS in Client-Hosted Sessions

Client-hosted sessions use Unity Relay by default. When Connect Using Websockets is enabled, the relay connection is configured to use WSS for all connected clients, including the host.

How we implement this can be observed in UnityRelayClientSessionStrategy.

WSS in Server-Hosted Sessions

We host servers with Unity Multiplay Hosting by default. Multiplay machines are dynamically allocated and, at the time of writing, don't provide certificates per server.

We work around these limitations to provide WSS for servers by communicating with it via Unity Relay. The relay service supports multiple connection protocols. On startup, dedicated servers with Connect Using Websockets will allocate a Relay server, connect to it over UDP with DTLS encryption, and share the Relay join code to clients by updating its Room Server entry in Kanda Cloud.

When connecting to a Room Server, clients can obtain the relay join code and connect to it via WSS. This way, we achieve end-to-end encryption when communicating with dedicated servers.

How we implement this can be observed in KandaCloudServerSessionHostingStrategy and UnityRelayServerSessionJoiningStrategy.

Typical Session Strategy Flow

While the specific implementation details may vary, session strategies typically handle these steps:

  • Initialization:
    • Check if the application is already in a lobby or session.
    • Set up necessary services and configurations.
  • World Setup:
    • Create or configure the appropriate ECS worlds (client, server, or both).
  • Network Setup:
    • For hosting: Set up network listeners and configure the server.
    • For joining: Establish connection to the host or server.
  • Scene Loading:
    • Load the lobby or session scene.
  • Session Services:
    • Initialize and start session-specific services (e.g., voice chat, content loading).
  • Finalization:
    • Signal that the session is ready for gameplay.

Session strategies implement these steps according to their specific hosting mode requirements.

Customizing Hosting Modes

You can customize the behavior of each play mode by overriding its corresponding strategy in the AppLifecycleService. This allows you to adapt the session management to your specific needs without modifying the core SDK code.

Example of customizing the offline hosting mode:

public class CustomOfflineSessionStrategy : IOfflineSessionStrategy
{
public async Task<AppLifecycleResult> Host()
{
// Ensure not already in session
if (_standardSceneService.IsCurrentlyInSession)
{
return AppLifecycleResult.Failed(SessionStrategyConstants.AlreadyInSessionMessage);
}
// Configure networking, ECS worlds, load session scene
_connectionService.UseDefaultNetworkDriver();
_entityWorldService.SetupOfflineSessionWorlds();
await _standardSceneService.LoadSessionSceneAsync();
// Whatever else custom setup logic you need...
// Connect client and server worlds
bool wasPortAvailable = _connectionService.TryGetFirstAvailableLocalUdpPort(
_connectionSettings.LocalPortRange,
out ushort port
);
if (!wasPortAvailable)
{
return AppLifecycleResult.Failed("Could not find a local port to connect to.");
}
_connectionService.ListenForClientConnections(port);
_connectionService.ConnectToServer(NetworkEndpoint.LoopbackIpv4.WithPort(port));
return AppLifecycleResult.Success();
}
}
// In your initialization code...
var lifecycle = AppServiceLocator.Get<IAppLifecycleService>();
lifecycle.OverrideOfflineSessionStrategy(new CustomOfflineSessionStrategy());

By overriding these strategies, you can implement custom logic for network discovery, session initialization, or any other aspect of session management specific to your app requirements.

This can be useful in cases where you want to implement alternative means of hosting sessions, such as using an alternative hosting provider or integrating to custom services.