Network Object
Introduction
The NetworkObject
assigns a network identity to a GameObject
so it can be shared across the network. Any GameObject
that is seen by all players and is a dynamic part of the scene should carry a NetworkObject
script.
Fusion offers two NetworkObject
base classes for deriving custom network behaviours:
SimulationBehaviour
for simulation related behaviours; and,NetworkBehaviour
for behaviours keeping or tracking a[Networked]
state.
NetworkObject
A single NetworkObject
script on the root node of a GameObject
is sufficient to control the entire hierarchy. At runtime the NetworkObject
will find all SimulationBehaviour
s and NetworkBehaviour
s in its hierarchy.
If needed, NetworkObject
s can be nested. In this case, the NetworkObject
will not search into nested children and let child NetworkObject
s track all SimulationBehaviour
s and NetworkBehaviour
s below it. A typical usecase would be a two player controlled tank made of a chassis and a turret where the driver controls the chassis' direction (movement) and the gunner controls the turret (shooting).
Prefab / Object Table
In order for the Prefab
parameter to make sense to Fusion (and to be sure that all clients agree on exactly which prefab that is), the prefab itself must be registered with Fusion. Under normal circumstances the Fusion toolset will automatically detect these prefabs and register them, but you can also manually trigger this detection by selecting the NetworkProjectConfig
and pressing Rebuild Object Table
in the Unity Inspector.
Instantiation / Spawn
The instantiation of NetworkObject
prefabs requires two steps:
- At edit-time: ensure the clients have to have identical
NetworkProjectConfig
assets which agrees on theNetworkObject
prefab identities. This is done by runningRebuild Object Table
in theNetworkProjectConfig
asset; and, - At runtime: call
Spawn()
on theNetworkRunner
with aNetworkObject
prefab as the parameter.
IMPORTANT: Calling the generic Unity Instantiate()
method will just create a broken local instance!
Destruction / Despawn
To destroy a NetworkObject
, call Runner.Despawn()
and pass the object as a parameter. This will destroy the object as well as all nested objects; to despawn only the top object, the nested objects need to be de-parented manually first.
DestroyWhenStateAuthorityLeaves
Shared Mode Only
Indicates if this NetworkObject will automatically be despawned when the StateAuthority
Player leaves the game.
HasStateAuthority Property
The HasStateAuthority
property is valid in both Shared and Server/Client modes, and will return true if:
- Server/Client Mode; Runner.IsServer
is true.
- Shared Mode; StateAuthority == Runner.LocalPlayer
.
Use this property in scripts to determine if this is the authoritative instance of this NetworkObject.
StateAuthority Property
The State Authority indicates which PlayerRef
's peer is the final authority on the NetworkObject
's state (Networked Properties), and its Networked Property values are replicated to other clients as Tick Snapshots.
NOTE: The StateAuthority
property is only applicable to Shared Mode. In Server/Client Mode this value will always be PlayerRef.None
, as the Server/Host peer will always act as State Authority.
Changing State Authority
In Server/Client Mode: State Authority always belongs to the Host/Server and cannot be transfered. StateAuthority
will always be PlayerRef.None
.
In Shared Mode: Player's have State Authority over NetworkObject
s (the Photon Shared Server MANAGES State Authority of NetworkObjects
, but does not HAVE State Authority over those objects).
Object.RequestStateAuthority()
can be called on a client to assign its PlayerRef
as the State Authority for the NetworkObject
. The Photon Shared Server will only grant the request if;
- The Object has AllowStateAuthorityOverride
enabled; or,
- The Object has no current State Authority
.
If AllowStateAuthorityOverride
is NOT enabled and there is already an assigned State Authority, the request will be ignored. The current State Authority Player must first call Object.ReleaseStateAuthority()
on its client to free the Object.
AllowStateAuthorityOverride
Only applicable to Shared Mode.
Indicates if the StateAuthority can be acquired by a Player when another player currently is the State Authority. If false, the current State Authority must first call ReleaseStateAuthority()
or disconnect. For most use cases you will want to leave AllowStateAuthorityOverride
enabled for Prefabs and Scene Objects.
This property must be set before spawning, as it cannot be changed after spawn.
HasInputAuthority Property
The HasInputAuthority
property will return true
if the Runner.LocalPlayer == Object.InputAuthority
. Use this in scripts to test if the NetworkRunner.LocalPlayer
is the Input Authority for this NetworkObject
.
NOTE: Input Authority and Fusion's INetworkInput
handling are primarily meant for Server/Client Mode, as they are fundamental to client prediction and resimulation. In Shared Mode however, user inputs are consumed immediately by the State Authority - making the INetworkStruct
input system non-essential. You may however still wish to use the Fusion input system with Shared Mode if you are considering switching to Server/Client Mode in the future, and want to avoid refactoring later.
InputAuthority Property
The InputAuthority
property indicates which PlayerRef
's input data (INetworkInput
) is returned when GetInput()
is called in any FixedUpdateNetwork
on this NetworkObject
. Player Input is only available to the client with Input Authority, and to the State Authority. All other clients (Proxies) will return false
when GetInput()
is called.
Changing Input Authority
In Shared Mode: INetworkInput
handling is optional in Shared Mode. If used however, only the current StateAuthority
may change the InputAuthority
, and can do so using the Object.AssignInputAuthority()
method.
Input Authority should match State Authority or be PlayerRef.None
. Input Authority is not automatically changed with StateAuthority
changes, so be sure to change InputAuthority
as needed in these cases.
public class StateAuthChangeExample : NetworkBehaviour, IStateAuthorityChanged
{
void IStateAuthorityChanged.StateAuthorityChanged() {
// If this object is using Fusion Inputs, the new State Authority
// should acquire Input Authority when it gets State Authority.
if (Object.HasStateAuthority) {
Object.AssignInputAuthority(Object.StateAuthority.PlayerId);
}
}
}
In Server/Client Mode: The InputAuthority
PlayerRef
can only be changed on the Server with the Object.AssignInputAuthority()
method.
SimulationBehaviour
All SimulationBehaviour
s can access their associated NetworkObject
via the Object
property.
Simulation is Fusion's way of updating the network state. Any behaviours which are part of or affect the simulation state have to derive from SimulationBehaviour
instead of MonoBehaviour
.
For example, the LevelManager
in the Tanks sample spawns powerups. Although powerups are NetworkObject
s, the LevelManager
only has to affect and know of the simulation state to execute its behaviour. Therefore, inheriting from SimulationBehaviour
is the right approach.
public class LevelManager : SimulationBehaviour
{
[SerializeField] private float _powerupDelay;
[SerializeField] private NetworkObject _powerupPrefab;
private TickTimer _powerupTimer;
public override void FixedUpdateNetwork()
{
// All of the level management logic happens server-side, so bail if we're not the server.
if (!Object.HasStateAuthority) return;
// Only active duty of the LevelManager is to spawn powerups whenever the timer expires
if (_powerupTimer.ExpiredOrNotRunning(Runner))
{
// Reset timer, and check if there is a free spot to spawn a new powerup
_powerupTimer = TickTimer.CreateFromSeconds(Runner,_powerupDelay);
SpawnPoint spawnPoint = GetSpawnPoint(SpawnPoint.Type.Powerup);
if (spawnPoint != null)
{
Debug.Log("Spawning Powerup");
NetworkObject powerupobj = Runner.Spawn(_powerupPrefab, spawnPoint.transform.position, spawnPoint.transform.rotation, PlayerRef.None);
powerupobj.GetComponent<Powerup>().Init();
}
else
{
Debug.Log("Not Spawning Powerup - no free spot");
}
}
}
}
If the behaviour requires access to [Networked]
properties, it has to derive from NetworkBehaviour
instead.
NetworkBehaviour
A NetworkBehaviour
requires a NetworkObject
on the same node or a parent node.
NetworkBehaviour
is a SimulationBehaviour
which can carry a synchronized state; this is the reason why it has to have an associated NetworkObject
.
Networked Properties
Internally Fusion stores the entire networked state for each tick as a single memory buffer, called a Snapshot
. Networked Properties define which variables in a NetworkedBehaviour
are part of that networked state.
To define a Networked Property, use the [Networked]
attribute. Fusion will automatically connect these tagged properties to its own high performance data buffers and delta compression. The property setters and getters are compile-time replaced with custom code to eliminate memory allocation overhead and provide optimal performance.
public class PlayerBehaviour : NetworkedBehaviour
{
[Networked] public float Health { get; set; }
}
At compile-time Fusion will replace the empty get/set stubs with code that accesses the actual networked state data. The direct access eliminates the memory allocation overhead and provides optimal performance. DO NOT implement them manually.
This direct property access to the state buffer means that whenever a change occurs, the state reflects that change immediately.
To write logic affecting networked state, override and implement FixedUpdateNetwork()
.
public override void FixedUpdateNetwork()
{
Health += Runner.DeltaTime * HealthRegen;
}
Allowed Types
- Primitives
- byte, sbyte
- Int16, Int32, Int64
- UInt16, UInt32, UInt64
- float
- double
- float
- double
- bool (convereted to int)
- Strings with a maximum
Length
set using the[Capacity]
attribute (defaults to 16) - Unity struct types (defined in ILWeaver.cs)
- Vector2, Vector3, Vector4
- Quaternion
- Matrix4x4
- Vector2Int, Vector3Int
- BoundingSphere
- Bounds
- Rect
- BoundsInt
- RectInt
- Color, Color32
- System.Guid
- User Defined INetworkStructs
- Fusion Defined INetworkStructs
- NetworkString<IFixedStorage>
- NetworkBool
- Ptr
- Angle
- BitSet64, BitSet128, BitSet192, BitSet256
- PlayerRefSet
- NetworkId
- NetworkButtons
- NetworkRNG
- NetworkObjectGuid
- NetworkPrefabRef
- NetworkObjectHeader
- NetworkPrefabId
- SceneRef
- TickTimer
- IFixedStorage (_2, _4, _8, _16, _32, _64, _128, _256, _512)
- Fusion Types
- NetworkObject (serialized as
NetworkId
) - NetworkBehaviour (serialized as
NetworkId
and theNetworkBehaviour
index) - PlayerRef (serialized as
PlayerRef.PlayerId
)
- NetworkObject (serialized as
- NetworkArray<T> with a maximum
Length
set using the[Capacity]
attribute (defaults to 1) - NetworkDictionary<K, V> with a maximum
Count
set using the[Capacity]
- NetworkLinkedList<T> with a maximum
Count
set using the [Capacity] attribute.
Accuracy Attribute
It is possible to control the accuracy of individual numeric type properties by using the [Accuracy]
attribute.
public class PlayerBehaviour : NetworkedBehaviour
{
[Networked, Accuracy(0.001)]
public float Health { get; set; }
}
Capacity Attribute
[Capacity]
is used to define the maximum size of NetworkArray<T>, NetworkDictionary<K, V>, NetworkLinkedList<T> and strings.
public class MyNetworkBehaviour : NetworkedBehaviour
{
[Networked, Capacity(14)]
string MyString { get; set; }
[Networked, Capacity(8)]
NetworkArray<byte> MyArray { get; }
}
React To OnChanged
Game code can to be triggered when a networked property is changed by Fusion. To write reactive code, use the (OnChanged)
parameter in the [Networked]
attribute.
public class Powerup : NetworkBehaviour
{
[Networked(OnChanged = nameof(OnTypeChanged))] public Type type { get; set; }
// Has to be public static void
public static void OnTypeChanged(Changed<Powerup> changed)
{
changed.Behaviour.OnTypeChanged();
}
private void OnTypeChanged()
{
// Some logic reacting to the value change of the "type" property
}
}
In addition to specifying the callback name, it is possible to control on which machines the callback is executed:
OnChangedLocal
(default false): set to true to also have the event hook called on the machine that changed the propertyOnChangedRemote
(default true): set to false to only have the event hook called on the machine that changed the property.
Overridable Methods
A NetworkObject
has a number of additional life-cycle methods, all of which can be overriden when implementating SimulationBehaviour
and NetworkBehaviour
.
Function | Description |
---|---|
FixedUpdateNetwork() | Fusion's fixed time step callback. Used for the core game logic. |
Spawned() | Post spawn callback. |
Despawned(bool hasState) | Called before the network object is despawned.
--- bool hasState: If the state of the behaviour is still accessible. |
Render() | Post simulation frame rendering callback. Runs after all simulations have finished. Use in place of Unity's Update when Fusion is handling Physics. |
FixedUpdateNetwork
FixedUpdateNetwork()
- abbreviated FUN()
- is called when simulating the new state from one tick to the next. FixedUpdateNetwork()
is called at fixed intervals; the time step of these intervals is defined in the NetworkProjectConfig
asset under Simulation > Tick Rate
. The time step can be accessed from any SimulationBehaviour
and NetworkBehaviour
via the Runner.DeltaTime
property.
FixedUpdateNetwork()
can be called multiple times for the same state transition to re-simulate the current predicted state based on updates (ground truth) received from the server. The re-simulation is transparent for [Networked]
properties because Fusion will reset the network state before calling FixedUpdateNetwork()
for re-simulation purposes.
IMPORTANT: Regular local non-networked state variables (e.g. class members) will not be reset and simply consider it an additional forward state progression.