Ownership

Ownership Modes

Authority determines which client is allowed to write a networked object's properties.
Only the authority client's values are accepted by the server, all other clients receive read-only copies.
Fusion has several ownership modes that the Ownership value can be set to on the UFusionActorComponent to control how authority is assigned and transferred.

Each mode is a different rule for who can own the object and what happens to it when the owner disconnects.
Pick it at design time.

Mode Behavior When the owner leaves
Transaction Take-and-release transaction semantics: a client requests ownership via SetWantsOwner(true) and the current owner grants or denies it. See [[#granting-and-denying-ownership-requests]]. Becomes unowned.
PlayerAttached Same request handshake as Transaction. Destroyed.
Dynamic Any client can claim ownership optimistically, without owner approval. Suited to objects that change ownership frequently (e.g. physics objects). See [[#dynamic-ownership-and-send-rate]]. Becomes unowned.
MasterClient Always owned by the current Master Client. See [[#master-client-mode-and-auto-promotion]]. Re-targets the new Master Client.

Example mapping: PlayerAttached for player avatars and per-player inventory, Transaction for shared pickups the player explicitly picks up and drops, Dynamic for physics objects and projectiles that change ownership frequently, MasterClient for singletons and room-wide systems.

Setting Ownership Mode

The Ownership UPROPERTY on UFusionActorComponent is read once, when the actor is attached as a Fusion source. Set it in the C++ constructor or the BP defaults. It is not designed to flip at runtime.

C++

AInteractablePickup::AInteractablePickup()
{
    FusionActorComponent = CreateDefaultSubobject<UFusionActorComponent>(TEXT("Fusion"));
    FusionActorComponent->Ownership = EFusionObjectOwnerFlags::Transaction;
}

Requesting Ownership

UFusionOnlineSubsystem::SetWantsOwner(Actor, bWantsOwner) is the runtime entry point.
Call it with bWantsOwner = true to claim ownership of an actor, or false to release.
The call is BP-callable.

What the claim does depends on the ownership mode.
For Transaction and PlayerAttached, it raises a request the current owner must grant or deny (see [[#granting-and-denying-ownership-requests]]).
For Dynamic, it sets a persistent intent the client claims by sending, with no owner approval (see [[#dynamic-ownership-and-send-rate]]).
For MasterClient and GameGlobal the claim has no effect.

C++

OnlineSubsystem->SetWantsOwner(Actor, true);  // claim
OnlineSubsystem->SetWantsOwner(Actor, false); // release

The BP-pure inspectors on UFusionOnlineSubsystem answer the runtime "who owns this and can I write to it?" question: HasOwner(Actor), GetOwner(Actor), IsOwner(Actor), and CanModify(Actor).
Use IsOwner and CanModify as the predicates for gating writes to replicated state.
AActor::HasAuthority() works equally well for that gate.
It is equivalent to CanModify(Actor) (see [[#ownership-and-hasauthority]]).

Ownership Modes

Transaction

Transaction ownership transfers go through a request that the current owner answers.
When a non-owner calls SetWantsOwner(Actor, true), the current owner's OnOwnershipRequested event fires with the requesting player id.

OnOwnershipRequested is a BlueprintAssignable multicast on UFusionActorComponent.
It passes the requesting player id as an int32.

Requests are denied by default.
To grant one, bind OnOwnershipRequested and call RespondToOwnershipRequest(RequesterPlayerId, true) from inside the handler.
The response must be made synchronously inside the handler: the component issues an automatic denial the instant your handler returns, so a grant made anywhere else is too late.

RespondToOwnershipRequest(int32 RequesterPlayerId, bool bGranted) is the BlueprintCallable answer on UFusionActorComponent.
Pass true to grant the request or false to deny it.

C++

void AInteractablePickup::BeginPlay()
{
    Super::BeginPlay();
    FusionActorComponent->OnOwnershipRequested.AddDynamic(this, &AInteractablePickup::HandleOwnershipRequested);
}

void AInteractablePickup::HandleOwnershipRequested(int32 RequesterPlayerId)
{
    // Respond synchronously here. Do nothing to let the default denial stand.
    const bool bGrant = CanYieldTo(RequesterPlayerId);
    FusionActorComponent->RespondToOwnershipRequest(RequesterPlayerId, bGrant);
}

The requester learns the outcome through events, not a return value.
A granted request arrives as OnOwnerChanged followed by OnOwnerWasGiven.
There is no positive "request granted" event.
A denied request arrives as OnOwnershipDenied.

Leaving OnOwnershipRequested unbound denies every request automatically.
That is the default for any actor that does not opt in to granting.

PlayerAttached

Same transfer mechanics as Transaction, but with one key difference: when the owning player disconnects, the server automatically destroys the object. Use this for player avatars, player-owned inventory, or anything that should not outlive its owner.

Dynamic

Dynamic ownership does not use the request handshake.
SetWantsOwner(Actor, true) sets an intent on the object.
You do not need to re-assert it every frame to keep holding one you own.
But the intent is cleared when you lose the object to another client (see below), so a client that keeps losing a contested object must re-assert it to stay in the running.

A client that wants a Dynamic object claims it when the object next sends an update, once a short per-object cooldown has elapsed.
No current-owner approval is involved.
The claim is optimistic.

Because the claim rides on the object's next send, how often this client sends the object governs how aggressively it takes ownership.
UFusionActorComponent::SetLocalSendRate(int32) sets that rate for this client, and ResetLocalSendRate() restores the default.

SetLocalSendRate takes a send interval, not a frequency.
A value of 1 sends every tick and claims fastest, 16 sends every sixteenth tick and claims slowly, and 0 (or ResetLocalSendRate) restores the default.

The common pattern is to drop the local send rate to 1 while contesting a Dynamic object for a fast takeover, then raise it (for example 16) once you own it to save bandwidth while passively holding.

C++

// Contest: want ownership and send every tick for a fast claim.
OnlineSubsystem->SetWantsOwner(Actor, true);
FusionActorComponent->SetLocalSendRate(1);

// If another client wins the contest your intent is cleared (see below),
// so call SetWantsOwner(Actor, true) again to keep contesting.

// Once owned, relax to save bandwidth while holding.
FusionActorComponent->SetLocalSendRate(16);

If another client wins ownership of a Dynamic object you are contesting (even one you only claimed optimistically and never actually held), your want intent is automatically cleared.
This stops two clients from fighting over the object indefinitely.
With manual SetWantsOwner, the intent is one-shot per lost contest: call SetWantsOwner(Actor, true) again to re-contest.
The AutoDynamicOwnershipRange helper re-asserts the intent each tick, so it recovers on its own.

ClearOwnerCooldown() is a BlueprintCallable on UFusionActorComponent.
It clears the per-object cooldown so the next eligible send can re-claim immediately.

Master Client

Setting the Ownership value to MasterClient binds the object's owner to whichever player is the current Master Client.
The resolved owner is recomputed on every master change, so IsOwner(Actor) and IsMasterClient() always agree for these actors.

When the current Master Client leaves the room, Photon promotes a new master automatically. Every MasterClient-owned object re-targets the new master in the same tick, and the OnOwnerChanged event fires on each affected UFusionActorComponent. No application code is required.

Do not call SetWantsOwner on MasterClient-owned objects. The ownership rule for MasterClient is "whoever is master right now", not "whoever asked". Claim requests do not change the resolved owner. If the project needs ownership that any client can request and release, use Transaction or Dynamic instead.

Ownership and HasAuthority

Fusion sets each networked actor's ENetRole every tick, so AActor::HasAuthority() is a supported way to gate writes to Fusion-replicated state.
It reads true on the client that may currently modify the object and false everywhere else, matching CanModify(Actor).

In Dynamic mode HasAuthority() is optimistic: it turns true the moment you claim, before the server confirms, and reverts within a tick if you lose the contest (see [[#dynamic-ownership-and-send-rate]]).
Read it after OnObjectReady, not in BeginPlay, where the role is not yet set.

C++

if (Actor->HasAuthority())
{
    // We hold write authority over this Fusion object, so it's safe to drive.
}

Auto Dynamic Ownership Range

AutoDynamicOwnershipRange on UFusionActorComponent is an optional helper that automates SetWantsOwner calls based on distance. It is a separate feature from the Dynamic ownership mode.

While enabled, the actor requests ownership whenever the local player is within AutoDynamicOwnershipRange and releases it again once the player moves beyond that distance.

C++

FusionActorComponent->Ownership = EFusionObjectOwnerFlags::Dynamic;
FusionActorComponent->AutoDynamicOwnershipRange = 500.0; // cm

The helper calls SetWantsOwner on whatever ownership mode the actor uses, and the mode decides what happens. A value of 0 disables the helper, leaving ownership transfer under explicit gameplay control through direct SetWantsOwner calls.

Ownership-Change Events

OnOwnerChanged is a BlueprintAssignable multicast on UFusionActorComponent. It fires whenever the resolved owner of the actor changes, including the local-to-remote and remote-to-local transitions.

OnOwnerWasGiven is the narrower companion event. It fires only when the local client has just become the owner. Use it as the hook for "I just took authority, start driving this actor".

C++

void AMyActor::BeginPlay()
{
    Super::BeginPlay();
    FusionActorComponent->OnOwnerChanged.AddDynamic(this, &AMyActor::HandleOwnerChanged);
    FusionActorComponent->OnOwnerWasGiven.AddDynamic(this, &AMyActor::HandleBecameOwner);
}
Back to top