Connection

App ID and Fusion Settings

Project-wide Fusion configuration can be found in Project Settings > Fusion Settings in the Unreal editor. The most important fields are AppId and AppVersion. The App ID identifies the project on the Photon Cloud and AppVersion segments players by client build so incompatible versions cannot share rooms.

Get an App ID for the project from the Photon Dashboard and paste it into the App ID field as shown in the Quick Start Guide.

Connecting to Photon

Every connection and room operation goes through UFusionOnlineSubsystem, a UGameInstanceSubsystem reached the standard Unreal way: GameInstance->GetSubsystem<UFusionOnlineSubsystem>(). The subsystem owns the underlying UFusionClient, the PhotonMatchmaking::RealtimeClient, and the lifecycle of the Fusion session.

In Blueprints, the entry point is the latent node "Connect To Photon", which maps to ConnectToPhoton(FFusionConnectOptions, WorldContextObject) and returns a UFusionConnectToPhotonAsync with OnSuccess and OnFailure multicast pins. That node is a convenience wrapper built for Blueprint use; under the hood it drives PhotonMatchmaking::RealtimeClient::Connect. From C++ you call that matchmaking API directly and skip the latent node entirely.

C++

// Create a standalone matchmaking client. AppId / AppVersion / region mode come
// from Fusion Settings. It is NOT on the subsystem yet.
FFusionConnectOptions ConnectOpts;
ConnectOpts.RegionSelectionMode = EFusionRegionSelectionMode::Best;
UFusionRealtimeClient* RealtimeClient = UFusionRealtimeClient::CreateRealtimeClient(ConnectOpts);

PhotonMatchmaking::RealtimeClient* Client = RealtimeClient->GetClient();

PhotonMatchmaking::ConnectOptions RtOpts;
RtOpts.auth.userId = reinterpret_cast<const PhotonCommon::CharType*>(
    StringCast<UTF8CHAR>(*FGuid::NewGuid().ToString()).Get());
// Leave RtOpts.serverAddress empty for the Photon Cloud NameServer.

Client->Connect(RtOpts); // returns a Task; you can discard it (see below)

// Pump the client every tick until it reports connected — nothing else drives
// the connection while the client is standalone:
//   RealtimeClient->Service();
//   if (RealtimeClient->IsConnected()) { /* connected */ }

The one hard requirement is that something calls Service() on the client every tick, that is what advances the connection and dispatches incoming events. While the client is standalone you pump it yourself, once you hand it to the subsystem UFusionOnlineSubsystem::WorldTick does it for you.

For Blueprint projects, wire the "Connect To Photon" latent node's OnSuccess pin into "Join Or Create Room" with a Make FFusionRoomOptions literal feeding the room options.

Joining or Creating a Room

Once connected, the subsystem exposes five room entry points. CreateRoom, JoinOrCreateRoom, and JoinOrCreateRandomRoom all take an FFusionRoomOptions struct describing the room to create. JoinRoom(RoomName) and JoinRandomRoom join an existing room without creating one, the by-name variant requires the exact room name, the random variant picks any open and visible room.

C++

PhotonMatchmaking::CreateRoomOptions RoomOpts;
RoomOpts.maxPlayers = 8;

const auto RoomName = StringCast<UTF8CHAR>(TEXT("Match-42"));
Client->JoinOrCreateRoom(
    reinterpret_cast<const PhotonCommon::CharType*>(RoomName.Get()), RoomOpts);

// Keep calling RealtimeClient->Service() each tick. Once the client is in the
// room (RealtimeClient->IsInRoom(), or the OnRoomJoined broadcaster fires),
// hand it to the subsystem and start the Fusion session. The subsystem now
// owns the client, so WorldTick takes over servicing it.
OnlineSubsystem->RealtimeClient = RealtimeClient;
OnlineSubsystem->StartFusionSession(); // constructs the UFusionClient, begins replication

If you would rather not call Service() yourself, the inverse also works: assign the client to OnlineSubsystem->RealtimeClient up front so WorldTick services it from the start, and simply defer StartFusionSession() until the room is joined.

The room entry points map one-to-one onto RealtimeClient methods: JoinOrCreateRoom, JoinRandomOrCreateRoom, CreateRoom, JoinRoom(name), and JoinRandomRoom. The FFusionRoomOptions struct used by the Blueprint nodes is just a wrapper, FFusionRoomOptions::ToCreateRoomOptions() converts it to the PhotonMatchmaking::CreateRoomOptions these methods take, so C++ code can build either one.

For Blueprints, the convenience node "Connect And Join Room" (ConnectAndJoinRoom) chains connect, join, and Fusion start in a single action. The C++ equivalent is the two snippets above: connect (servicing the client), join, then assign the in-room client to the subsystem and call StartFusionSession().

Async Actions

Every connect and room call returns a UFusionRoomActionBase subclass, a Blueprint latent action that exposes OnSuccess and OnFailure multicast delegates as exec pins in BP and as FMulticastDynamicDelegate members in C++. OnFailure carries an EFusionActionFailureCodes value describing the reason. These actions exist for Blueprint use, C++ code that wants to avoid them uses the PhotonMatchmaking::RealtimeClient directly, as shown in Connecting to Photon above.

Async class Subsystem method Wraps
UFusionConnectToPhotonAsync ConnectToPhoton Initial cloud connection
UFusionDisconnectFromPhotonAsync DisconnectFromPhoton Full disconnect from the cloud
UFusionJoinOrCreateRoomAsync JoinOrCreateRoom, JoinOrCreateRandomRoom Join a matching room or create one
UFusionCreateRoomAsync CreateRoom Create a new room unconditionally
UFusionJoinRoomAsync JoinRoom, JoinRandomRoom Join an existing room
UFusionLeaveRoomAsync LeaveRoom Leave the current room, stay connected
UFusionConnectAndJoinRoomAsync ConnectAndJoinRoom Connect plus join in one action

EFusionActionFailureCodes covers the practical failure cases: TimeOut, InvalidRegion, ClientAlreadyExists, Disconnected, and the already-in-that-state codes Connecting, JoiningRoom, and InRoom which fire when the requested action is redundant because the client has already reached that state (for example, calling connect while already connected, or join/create while already in a room).

Connection Options and Regions

FFusionConnectOptions carries two fields. Region is a region code string such as "us" or "eu", see Regions for the full list. RegionSelectionMode is an EFusionRegionSelectionMode enum that decides how the Region field is interpreted.

Mode Behavior
Default Use the first available region. The Region string is ignored.
Select Connect to the region named in the Region string.
Best Ping every available region, pick the lowest-RTT one, and cache the result.

C++

FFusionConnectOptions ConnectOpts;
ConnectOpts.Region = TEXT("us");
ConnectOpts.RegionSelectionMode = EFusionRegionSelectionMode::Select;

For production, ship with Best on first launch so the player lands on the lowest-RTT region without any UI. Persist the chosen region and switch to Select with that value on subsequent launches to skip the ping pass.

Room Options

FFusionRoomOptions describes the room being created or joined.

Field Type Effect
RoomName FString Unique name within the App ID. Required for invite-style flows; auto-generated when joining randomly.
MaxPlayers uint8 Maximum concurrent players in the room.
bIsOpen bool If false, the room rejects new joins. Set false to seal a match in progress.
bIsVisible bool If false, the room does not appear in random-join results. Invite-only rooms set this false.
EmptyTTL uint8 (seconds) How long the room survives after the last player leaves. Converted to ms internally.
InitialWorld TSoftObjectPtr<UWorld> World to load when the local player joins. Skips a separate ChangeWorld call on the Master Client.

C++

FFusionRoomOptions RoomOpts;
RoomOpts.RoomName = TEXT("Match-42");
RoomOpts.MaxPlayers = 8;
RoomOpts.EmptyTTL = 0;
RoomOpts.InitialWorld = LobbyWorldPtr;

Set InitialWorld whenever the room creator already knows the starting map. The local client loads that world automatically as it joins, and the Master Client does not need to issue a separate ChangeWorld call after OnSuccess.

Leaving the Room and Reconnecting

LeaveRoom(WorldContextObject) returns a UFusionLeaveRoomAsync and after OnSuccess the client is back in EFusionStatus::Connected. It can call JoinOrCreateRoom again without re-running ConnectToPhoton. For a full teardown of the Photon connection, use DisconnectFromPhoton, which returns the client to EFusionStatus::None.

Connection Status and Events

Status() returns the current EFusionStatus. The normal lifecycle traces NoneConnectingConnectedJoiningRoomInRoomLeavingRoom, with Disconnected and Error reachable from any non-terminal state. The transitions are introduced in Concepts.

Query Returns
IsConnected() True when the client has reached at least Connected.
IsInRoom() True when the client is fully in a room (InRoom).
IsJoiningOrInRoom() True for both JoiningRoom and InRoom — useful for "session is forming or formed" gates.
IsMasterClient() True when this client is the elected Master Client of the current room.
PlayerCount() Current number of players in the room.
GetLocalPlayerId() Stable int32 id of the local player for this session.
GetRtt() Round-trip time to the Photon relay, in milliseconds.
CurrentRoomInfo(Name, Players) Room name and current player count as out params.
Back to top