Configuration

Construction-Time vs Runtime Settings

Configuration comes in two tiers. Settings in ClientConstructOptions are baked when the client is constructed and stay fixed for its lifetime; the network tunables additionally have setter and getter pairs on the client instance, so they can be read back and adjusted later.

Setting ClientConstructOptions Field Runtime Setter Takes Effect
App id and version AppId, AppVersion At construction.
Transport protocol Protocol At construction.
Alternative ports UseAlternativePorts At construction.
Region selection mode RegionSelection At construction.
Lobby statistics push AutoLobbyStats At construction.
Disconnect timeout DisconnectTimeoutMs SetDisconnectTimeout() Immediately, also while connected.
Ping interval PingIntervalMs SetPingInterval() Immediately, also while connected.
Sent count allowance SentCountAllowance SetSentCountAllowance() Immediately, also while connected.
Quick resend attempts QuickResendAttempts SetQuickResendAttempts() Immediately, also while connected.
CRC checksums EnableCrc SetCrcEnabled() Only while disconnected.
Unreliable command limit LimitOfUnreliableCommands SetLimitOfUnreliableCommands() Immediately, also while connected.
Auto-join lobby SetAutoJoinLobby() On the next connect.
Traffic statistics SetTrafficStatsEnabled() Immediately.

Network Tunables

Six tunables shape the transport behavior. DisconnectTimeout sets how long the connection may stay unresponsive before it counts as lost, PingInterval controls the keep-alive rate, SentCountAllowance is the resend budget for reliable commands, QuickResendAttempts accelerates early resends, CrcEnabled adds payload checksums on UDP and LimitOfUnreliableCommands caps the incoming unreliable command queue.

CRC checksums must be decided before the connection is established. Bake EnableCrc in ClientConstructOptions or call SetCrcEnabled() while disconnected; while connected the setter is rejected and the value stays unchanged.

The other five tunables — DisconnectTimeout, PingInterval, SentCountAllowance, QuickResendAttempts and LimitOfUnreliableCommands — take effect immediately, even on a live connection. The peer reads the current values on every service tick, so raising the disconnect timeout mid-session, for example, applies to the very next timeout check.

Three of the tunables are UDP-specific: SentCountAllowance, QuickResendAttempts and LimitOfUnreliableCommands have no effect on TCP or WebSocket connections. DisconnectTimeout and PingInterval apply on every transport, and QuickResendAttempts is clamped to a maximum of 4.

Bake the tunables you know upfront:

C++

ClientConstructOptions options;
options.AppId               = PHOTON_STR("your-app-id");
options.AppVersion          = PHOTON_STR("1.0");
options.DisconnectTimeoutMs = 10000;
options.PingIntervalMs      = 1000;
options.EnableCrc           = true;

RealtimeClient client(options);

Transport Protocols

ClientConstructOptions.Protocol selects the transport: UDP (the recommended default), TCP, WS or WSS. ConnectionProtocol::Default resolves per platform — WebSocket on WASM builds, where raw UDP is unavailable, and UDP everywhere else.

Two related knobs sit next to the protocol choice. UseAlternativePorts (construct-time) switches to Photon's alternative port range, which helps when restrictive firewalls block the standard ports, and ConnectOptions.TryUseDatagramEncryption enables DTLS encryption on UDP connections.

Server Time

GetServerTime() returns the synced Photon server clock in milliseconds — the value to use whenever clients need to agree on a point in time, such as round starts or ability cooldowns. It is meaningful only after a successful connect.

The value is a 32-bit millisecond counter that wraps around roughly every 24.8 days. Compare timestamps with wrap-aware arithmetic instead of a plain less-than when sessions can run long.

FetchServerTimestamp() is not a getter: it requests a fresh clock synchronization from the server, which is worth doing after a long stall before trusting GetServerTime() again. NetworkStats.ServerTimeMs is the same value as GetServerTime(), bundled into the statistics snapshot.

The master client schedules the round start a few seconds ahead and announces it, so every client counts down against the same server-time deadline:

C++

constexpr uint8_t roundStartEvent = 42;

auto subscription = client.SubscribeEvent([](uint8_t eventCode, int /*senderId*/, std::span<const uint8_t> data) {
    if (eventCode != roundStartEvent || data.size() != sizeof(int))
    {
        return;
    }

    int startTime = 0;
    std::memcpy(&startTime, data.data(), sizeof(startTime));
    // Start the round once GetServerTime() reaches startTime.
});

const int startTime = client.GetServerTime() + 5000;
client.SendEvent(roundStartEvent, startTime);

Custom Operations

SendCustomOperation(opCode, params, reliable, channel, encrypt) is the escape hatch for calling custom server-side operations — typically a Photon Server plugin — by raw operation code. The bool return only reports whether the request was queued for sending; the actual outcome arrives asynchronously.

Parameter keys are Photon parameter codes, not names: each RealtimeMap key must be a string holding the decimal form of a byte value between 0 and 255. A non-string, non-numeric or out-of-range key makes the whole call return false and nothing is sent. Values may be any type RealtimeValue carries.

The reply arrives through OnCustomOperationResponse(opCode, errorCode, errorString, data). Match responses by opCode; an errorCode of 0 means success and the response parameters come back in data with their byte codes as decimal string keys, such as "1".

Send an operation and handle its response:

C++

constexpr uint8_t leaderboardOp = 7;

auto subscription = client.OnCustomOperationResponse.Subscribe(
    [](uint8_t opCode, int errorCode, RealtimeCore::Common::StringViewType /*errorString*/, const RealtimeMap& /*data*/) {
        if (opCode != leaderboardOp)
        {
            return;
        }
        if (errorCode != 0)
        {
            // The operation failed server-side; errorString explains why.
            return;
        }
        // Success: read the results from data, keyed by decimal strings such as "1".
    });

RealtimeMap params;
params.Set(PHOTON_STR("1"), PHOTON_STR("weekly"));     // parameter code 1: board name
params.Set(PHOTON_STR("2"), static_cast<int32_t>(10)); // parameter code 2: entry count

if (!client.SendCustomOperation(leaderboardOp, params))
{
    // Rejected locally: a key was not a valid parameter code.
}
Back to top