Connection and Regions
Connecting to the Cloud
Connect() establishes the connection to the Photon Cloud and returns a Task<Result<void>> that resolves once the handshake completes.
The overload Connect(ConnectOptions) additionally supplies authentication values, a display name or a custom server address.
The connection only makes progress while the client is being driven, keep calling Service() every frame, as described in Client and Service Loop.
The typical flow awaits the connect result inside a coroutine:
C++
Task<Result<void>> ConnectWithUserId(RealtimeClient& client)
{
ConnectOptions options;
options.Auth.UserId = PHOTON_STR("player-4711");
Result<void> result = co_await client.Connect(options);
if (result.IsErr())
{
// Inspect result.GetError() and back off or retry.
}
co_return result;
}
Calling Connect() while the client is already connected or connecting does not restart anything.
The returned Task fails fast with ErrorCode::InvalidState and the existing connection stays untouched.
After a successful connect the client is authenticated and ready for matchmaking.
The server assigns a random UserId when the authentication values do not supply one, and the client automatically joins the default lobby unless auto-join is disabled.
Connect Options
| Field | Type | Default | Description |
|---|---|---|---|
Auth |
AuthenticationValues |
empty | User id and authentication provider data. See Authentication. |
Username |
StringType |
empty | Display name shown to other players, independent of the user id. |
ServerAddress |
StringType |
empty | Name server address to connect to. Empty targets the Photon Cloud. |
TryUseDatagramEncryption |
bool |
false |
Encrypts UDP traffic with DTLS when the server supports it. |
UseBackgroundSendReceiveThread |
bool |
true |
Only takes effect on Nintendo Switch 1, where it moves the low-level socket send and receive onto a background thread. |
Leave ServerAddress empty to connect to the Photon Cloud.
To reach a self-hosted Photon Server, set it to the address and port of your server's name server endpoint.
Connection States
GetState() returns the current ConnectionState: one of Disconnected, Connecting, Connected, JoiningRoom, InRoom, LeavingRoom and Disconnecting.
For the common checks, the convenience queries IsConnected(), IsInRoom() and IsInLobby() answer directly without comparing enum values.
Disconnecting
Disconnect() returns a Task<Result<void>> and shuts the connection down gracefully.
If the client is in a room it leaves the room on the way out, so other players see a regular leave.
Not every disconnect is requested: timeouts, server-side kicks and network failures end the connection asynchronously.
Subscribe to OnDisconnected(DisconnectCause) to react to these, and use GetDisconnectCause() to inspect the most recent cause after the fact.
The Errors and Disconnects page lists every cause.
Reconnecting
Reconnect() is a reconnect-and-rejoin, not a plain Connect().
It re-establishes the connection using the cached session from the previous connect and rejoins the room the client was last in, restoring the same player slot.
Reconnect() is only valid while the client is in the Disconnected state.
Calling it in any other state fails fast with ErrorCode::InvalidState and leaves the existing connection untouched.
The returned Task<Result<void>> resolves when the reconnect handshake completes.
Restoring the player slot additionally requires that the room was created with a non-zero PlayerTtlMs and that the player is still marked inactive, the same rule that governs JoinRoomOptions::Rejoin, described in Rooms and Players.
A typical recovery flow watches for a timeout and issues the reconnect from the game loop:
C++
bool timedOut = false;
auto subscription = client.OnDisconnected.Subscribe([&timedOut](DisconnectCause cause) {
timedOut = (cause == DisconnectCause::TimeoutDisconnect);
});
// In the game loop:
client.Service();
if (timedOut)
{
timedOut = false;
client.Reconnect(); // Fire and forget: Service() keeps driving the reconnect.
}
Regions
The Photon Cloud is split into geographic regions, each served by its own cluster. Matchmaking is per region: only players connected to the same region can see each other's rooms and meet in matches.
Region Selection Modes
The selection mode is baked at construction time in ClientConstructOptions.RegionSelection.
RegionSelectionMode::Default connects to the first region in the region list, Select lets you choose the region during connect and Best automatically picks the lowest-latency region.
Listing Available Regions
AvailableRegions() returns a Task<Result<std::vector<RegionInfo>>> with one entry per region.
Each RegionInfo carries the region Code (such as "eu" or "us"), the Server address and a PingMs field that is -1 when no ping measurement is available.
Selecting a Region Manually
Manual selection is a coordinated flow, not a sequential one.
With RegionSelectionMode::Select, start AvailableRegions() and Connect() together, await the region list, call SelectRegion(code) and only then await the original connect Task.
The two Tasks resume each other through the name-server handshake, so neither completes without the other.
With the client constructed in Select mode, the whole flow fits in one coroutine:
C++
Task<Result<void>> ConnectToChosenRegion(RealtimeClient& client)
{
Task<Result<std::vector<RegionInfo>>> regionsTask = client.AvailableRegions();
Task<Result<void>> connectTask = client.Connect();
Result<std::vector<RegionInfo>> regions = co_await regionsTask;
if (regions.IsErr())
{
co_return Result<void>::Err(regions.GetError());
}
// Pick the region to use, for example a code saved from a previous session.
RealtimeCore::Common::StringType chosen = regions.GetValue().front().Code;
Result<void> selected = co_await client.SelectRegion(chosen);
if (selected.IsErr())
{
co_return selected;
}
co_return co_await connectTask;
}
Best Region
RegionSelectionMode::Best pings the available regions during connect and picks the lowest-latency one automatically.
It needs no extra calls and no UI, which makes it the right default for most games.
GetBestRegion() returns the region the client actually connected to.
It is populated only by a successful Connect() and returns an empty string before that, calling AvailableRegions() alone does not populate it.
Pinging every region takes time, so cache the result to make later connects faster.
Persist the code returned by GetBestRegion() after the first successful connect, then construct future clients with RegionSelectionMode::Select and pass the saved code to SelectRegion() to skip the ping pass.