Replication

In a multiplayer game, each client runs its own copy of the simulation. Replication is the mechanism that keeps these copies consistent: one client (the authority) writes the definitive values for an object's properties, the server accepts them and distributes them to every other client. Without replication, each player would see a different game.

Fusion replicates at the property level. Individual values like position, health or score are tracked independently. The server only sends properties that have changed since the last update, minimizing bandwidth.

FusionReplicator

FusionReplicator handles property sync for networked objects. Add it as a child of your networked scene's root node. The authority client writes values to the server; remote clients receive and optionally smooth them.

Root Replication Modes

The replication mode controls which properties the replicator syncs automatically based on the root node type.

  • REPLICATION_NONE - no auto-sync; add custom properties via the replicator's bottom panel
  • REPLICATION_AUTO - auto-detects root node type and syncs accordingly:
  • RigidBody2D/3D → position, rotation, linear_velocity, angular_velocity (forecast smoothing)
  • CharacterBody2D/3D → position, rotation, velocity (interpolation smoothing)
  • Other nodes → position, rotation (interpolation smoothing)

Smoothing

When root_smoothing is true (default), remote values are corrected smoothly instead of snapped. Physics bodies use velocity-based forecast; non-physics nodes use spring-damper interpolation. Set root_smoothing = false for direct value application.

Custom Properties

Custom properties are added directly via the FusionReplicator's bottom panel in the editor. Use this for game data (health, score, name) beyond what the replication mode auto-syncs. Transform and physics properties should not be added. They are handled by REPLICATION_AUTO.

Custom properties panel
Custom properties panel

Property Path Syntax

Property paths use a node:property syntax relative to the replicator's root node.

  • :property - property on the root node
  • child:property - property on a child node
  • child/grandchild:property - nested child

GDScript

":health"             # Root node
"Sprite2D:modulate"   # Child Sprite2D

Strings and Arrays

Strings use 2 words (StringHeap handle + generation). Handles are freed automatically when the value changes.

Arrays (PackedFloat32Array, PackedInt32Array, PackedVector2Array, etc.) require a fixed max_capacity set before spawning. Arrays exceeding capacity are truncated.

Node References

Properties of type Node (or Object) can reference other networked root nodes. On the wire, each reference is stored as a Fusion ObjectId (2 words: Origin + Counter).

The referenced node must be a networked root, the parent node of a FusionReplicator. This includes spawned object roots, sub-object roots, and scene object roots. Child nodes within a networked object cannot be referenced. Non-networked nodes and null both serialize as (0, 0) and resolve to null on the remote end.

GDScript

# Authority sets a reference to another networked node
partner = get_node("/root/Main/Player2")

# Remote automatically receives the resolved Node (or null)
print(partner.name) # "Player2"

Resolution rules:

  • If the referenced node is in the remote client's Area of Interest, it resolves to the local Node.
  • If the referenced node is outside AoI, destroyed, or not yet spawned, it resolves to null.
  • Setting the property to null or a non-networked node on authority sends null to all remotes.
  • Scene objects loaded via FusionClient.load_scene() work the same way. The reference resolves once the remote client has loaded the scene.

Word Count Reference

Each replicated property occupies a fixed number of 32-bit words in the sync buffer. Knowing the word count helps estimate per-object bandwidth.

Godot Type Words
bool1
int2
float1
String2
Node (Object)2
Vector22
Vector33
Vector4 / Quaternion / Color4
Transform2D6
Transform3D12

Arrays: 1 + (max_capacity × element_words). Query at runtime: $FusionReplicator.compute_word_count().

Authority and Ownership

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 authority modes that can be set on the FusionReplicator node - Transaction, Player Attached, Dynamic and Master Client.

API Quick Reference

GDScript

$FusionReplicator.has_authority()         # am I the current owner?
$FusionReplicator.get_owner_id()          # which player owns this object?
$FusionReplicator.want_authority(true)    # claim ownership
$FusionReplicator.want_authority(false)   # release ownership

The want_authority method accepts an optional second argument (update_interval) to control how often the client sends property updates (in ticks). This is mainly relevant for Dynamic mode.

Transaction (default)

Server-confirmed ownership transfers. The current owner keeps authority until it explicitly releases with want_authority(false), at which point the server marks the object as an orphan (unowned). Any other client can then claim it with want_authority(true).

On disconnect, the object stays alive as an orphan and other clients can claim it.

GDScript

# Pickup / vehicle pattern
func _on_interact(player):
    $FusionReplicator.want_authority(true)   # claim when interacting

func _on_exit(player):
    $FusionReplicator.want_authority(false)  # release when done

Player Attached

Same request/release mechanics as Transaction, but with one key difference: when the owning player disconnects, the server automatically despawns the object.

Use this for player avatars, player-owned inventory, or anything that should not outlive its owner.

GDScript

# Spawner creates a player avatar with PLAYER_ATTACHED owner mode.
# Authority is implicitly assigned to the spawning player.
func _on_player_joined(player_id: int):
    var avatar = preload("res://player.tscn").instantiate()
    $FusionClient.spawn(avatar)  # owner_mode set on the FusionReplicator node

Dynamic

Predictive authority is designed for fast-paced ownership transfers where waiting for server confirmation would feel sluggish.

want_authority(true) immediately assigns ownership locally and the client starts sending data at full rate. If the server agrees, nothing further happens, the client simply continues as authority. If the server rejects the claim (because another client's data arrived first), authority reverts.

want_authority(false) lowers the send rate, signalling that this client is willing to give up ownership. The server can then accept another client's predictive claim. The client will not re-claim automatically once the server confirms someone else took over.

Automatic send-rate management:

Callupdate_interval
want_authority(true)1 (every tick)
want_authority(false)16 (low rate)

The low send rate for the authority is the way to allow the server to accept a dynamic request (gives enough slack for a new client to send a new version first). It's possible to override the default permissive interval by passing a second argument: want_authority(false, 12).

GDScript

# Physics ball — transfer ownership at midline (pong demo pattern)
func _physics_process(delta):
    if not $FusionReplicator.has_authority():
        if ball_crossed_my_half():
            $FusionReplicator.want_authority(true)   # predictive claim
    else:
        if ball_left_my_half():
            $FusionReplicator.want_authority(false)  # yield ownership
        else:
            apply_physics(delta)

Master Client

Always owned by the current master client. Calls to want_authority() are ignored.

If the master client disconnects, Photon assigns a new master and ownership transfers automatically - no application code required.

Use this for shared singleton state: scoreboards, match timers, game-manager objects.

authority_changed Signal

The authority_changed signal fires on the FusionReplicator node whenever ownership resolves, regardless of mode. Connect to it to react to authority transitions:

GDScript

func _ready():
    $FusionReplicator.authority_changed.connect(_on_authority_changed)

func _on_authority_changed():
    if $FusionReplicator.has_authority():
        print("I now own this object")

Interest Management (AOI)

Interest management controls which objects each client receives updates for, reducing bandwidth in large worlds. Objects publish an interest key via interest_mode on FusionReplicator; clients subscribe to keys via FusionClient.

  • INTEREST_GLOBAL (default) - visible to all clients
  • INTEREST_AREA - spatial grid key auto-computed from position (cell size in Project Settings fusion/interest_management/area_of_interest_cell_size)
  • INTEREST_USER - custom group key via interest_key
Project Settings - Interest Modes
Project Settings - Interest Modes

Subscribe with one or more FusionInterestArea nodes (auto-manages grid subscriptions, tipically following camera or player node) or manually:

FusionInterestArea - Node Inspector Settings
FusionInterestArea - Node Inspector Settings

GDScript

FusionClient.set_area_keys([[cell_key, 0]])   # area keys (refresh each frame)
FusionClient.add_user_key(42)                  # user keys (persistent)

Enter/exit signals: FusionClient.interest_enter / interest_exit.

Key Properties

These inspector properties control replication behavior on each FusionReplicator instance.

  • root_path (NodePath, "..") - node whose properties are synced
  • root_replication_mode - NONE or AUTO
  • root_smoothing (bool, true)
  • update_interval (int, 1) - server send interval in ticks
  • root_teleport_threshold (float, 100.0) - snap if error exceeds this
  • root_spring_stiffness (float, 50.0) / root_spring_damping (float, 10.0)
FusionReplicator inspector
FusionReplicator inspector

Signals

FusionReplicator emits signals when authority changes or a sync cycle completes.

  • authority_changed(has_authority: bool) - ownership changed
  • synchronized - inbound sync cycle completed
Back to top