This document is about: FUSION 1
SWITCH TO

This page is a work in progress and could be pending updates.

Spawning

Introduction

For a GameObject to exist across the network, it has to:

  1. have a NetworkObject component; and,
  2. be created using the Runner.Spawn() method.

The NetworkObject is used by Fusion to assign a network-wide unique identifier so all clients can agree on which instance is which and correctly synchronize each networked object's state. The Runner.Spawn() method tells Fusion when and how to add a new object instance to the collective network state.

IMPORTANT!

Do NOT use Unity's built in GameObject.Instantiate() method for networked object , this will just create a local game object which is completely detached from the Fusion simulation loop with a broken network state.

Runner.Spawn

The Runner.Spawn() method on the Fusion NetworkRunner instance mimics the GameObject.Instantiate() method in Unity. The parameters that can be provided to the method are:

  1. a prefab of type NetworkObject.
  2. a position
  3. a rotation
  4. a PlayerRef to identify the client with input authority over the object.
  5. a delegate of type NetworkRunner.OnBeforeSpawned to run before replicating the object on the other instances
  6. a prediction key of type NetworkObjectPredictionKey in case this is a predicted spawn.

Only the prefab is a mandatory parameter, all others are optional.

C#

var obj = Runner.Spawn(prefab, Vector3.zero, Quaternion.identity, Runner.LocalPlayer, MyOnBeforeSpawnDelegate, key);

Although any client can call Runner.Spawn(), the results will differ depending on the network topology.

  • On the server, in hosted or client/server mode, ownership (State Authority) of the spawned object is assigned to the server, and the object is created and returned immediately. Clients will receive the object as part of the next snapshot.
  • On a client in hosted or client/server mode, the default action is that nothing will happen and that the call will return null. However, Fusion supports creation of a temporary local object for instant feedback - this is referred to as "Predictive Spawning".
  • In shared mode, State Authority is always assigned to the caller and, again, the instance is returned immediately. Other clients will receive the object eventually.

In either case, Spawn should be called from FixedUpdateNetwork and it is ok to call during both Forward and Re-simulation stages. Fusion will correctly return the same object during re-simulation of predicted local spawns (assuming the prediction key matches), while authoritative spawns only happen in shared mode or on the Host, neither of which does re-simulation.

Input Authority

The input authority is assigned to a particular client by passing in their PlayerRef to the method; this is optional. The client to whom input authority was given will be able to provide input data for the object and (in addition to the Host or Server) is allowed to query that input structure in GetInput().

If the object does not require input or no client has input authority over it, null can be passed instead.

OnBeforeSpawned

The NetworkRunner.OnBeforeSpawned parameter can take a method or lambda expression matching the delegate signature.

C#

public delegate void OnBeforeSpawned(NetworkRunner runner, NetworkObject obj);

This delegate is invoked after the object is created but before it gets synchronized across all instances. This allows the caller to perform additional custom initialization of the object before any other part of the system is able to access it. This is a good place to initialize custom network properties.

C#

private void MySpawnFunction(){
    Runner.Spawn(
        _objPrefab, 
        Vector3.zero, 
        Quaternion.identity, 
        inputAuthority: null, 
        InitializeObjBeforeSpawn,
        predictionKey: null
        );
}

private void InitializeObjBeforeSpawn(NetworkRunner runner, NetworkObject obj)
{
    var objSB = obj.GetComponent<ObjSimulationBehaviour>();
    objSB.InitializeObjSettings(_currentExplosionForce);
}

It is also possible to use a lambda expression to have the possibility to pass more parameters.

C#

private void MySpawnFunction(){
  Runner.Spawn(
    _objPrefab,
    Vector3.zero,
    Quaternion.identity,
    inputAuthority: null,
    (Runner, NO) => NO.GetComponent<MyCustomBehaviour>().Init(myInt, myParameter)
    predictionKey: null
    );
}

Spawned

ISpawned.Spawned() is called immediately after the NetworkRunner attaches a NetworkObject (either as a result of a NetworkRunner.Spawn() call, or loading a Scene which contained a NetworkObject). The Spawned() callback can be considered Fusion's alternative to Awake(), and is called AFTER the object has been attached and is valid.

NetworkBehaviour implements the ISpawned interface with an empty virtual Spawned() method. To implement Spawned() for a custom NetworkBehaviour, simply override Spawned(). SimulationBehaviour derived components, however, need to explicitly implement ISpawned.Spawned().

Any Networked Property values changes made on the State Authority in Spawned() will be the initial values for all spawned instances of that NetworkObject on all other peers. HOWEVER, remote peers may not always spawn objects on the same tick as the State Authority (due to Area of Interest, Interest Management, late joining, and Prioritization). When a NetworkObject spawns remotely on a later tick than the State Authority, it will spawn with the values that the State Authority had for that later tick.

  • For spawns on a peer with State Authority, Spawned() is called immediately after Runner.Spawn().
  • For non-State Authority peers, The NetworkObject is spawned when the NetworkRunner receives a network state for an NetworkObject that does not exist locally. This also applies to Predictive Spawning.

If a NetworkObject should be initialized at prior to being attached to the NetworkRunner, use a pre-spawn OnBeforeSpawned callback supplied to Runner.Spawn().

IAfterSpawned

IAfterSpawned.AfterSpawned() is called after a batch of NetworkObjects have spawned and have all ISpawned.Spawned() callbacks have finished. This can be thought of as Fusion's alternative to Start(). Use this callback when a NetworkBehaviour needs to get or set values in another NetworkBehaviour after spawning, without concerns about execution order.

Despawn

To remove a network object, the peer with State Authority over the object may call Runner.Despawn().

Despawned

Similar to how Runner.Spawn() triggers the Spawned() method call for classes implementing ISpawned, Despawn() will result in the Despawned() method to be called for classes implementing IDespawned.

All NetworkBehaviours imlement IDespawned, whereas SimulationBehaviours have to add it explicitly.

Spawn Prediction

Spawn Prediction is only available in Host / Server Mode

Predictive Spawning is named as such because it lets a non-authoritative client predict the future existence of an object and allows it to simulate a local placeholder until the proper networked object's existence has been confirmed as successful or failed.

Two things need to happen for this to work:

  1. A unique identifier, called Prediction Key, must be created to allow the client to match its temporary local object against a future "actual" instance. This will enable it to upgrade the local object to a first class network object when the spawn is confirmed.
  2. The client must handle the local object as a non-networked object (= not accessing the object's network state) until it is either confirmed or canceled.

NetworkObjectPredictionKey

The predictionKey parameter being passed to the Runner.Spawn() method consists of 4 bytes. The application is free to invent its own keys as long as it considers the following:

  1. The key must be the same on the client and the authoritative host/server, therefore it cannot be random or based on local data.
  2. It must be unique for the player and the current tick. It is sensible to include the tick (or some lower end portion of it) as well as the players id in the key.

C#

var predictionKey = new NetworkObjectPredictionKey {Byte0 = (byte) Runner.Simulation.Tick, Byte1 = playerIndex};

N.B.: If multiple networked objects are predicatively spawned by a client during the same tick, additional information is need (e.g. a shared counter) to tell the various spawned NetworkObjects apart from each other.

IPredictedSpawnBehaviour

While the spawned game object is in its predicted state, it will not be part of the Fusion simulation and its networked properties will not work since there is not yet any state for them to access. In order for the predicted object to behave like a real object, some additional logic is needed. This logic has to be implemented using the IPredictedSpawnBehaviour interface.

C#

public interface IPredictedSpawnBehaviour {
    void PredictedSpawnSpawned();
    void PredictedSpawnUpdate();
    void PredictedSpawnRender();
    void PredictedSpawnFailed();
    void PredictedSpawnSuccess();
  }

Spawned, Update, Render

The three first methods match the Spawned(), FixedUpdateNetwork() and Render() methods found in functional SimulationBehaviour and NetworkBehaviour components. They are called under the same conditions as those methods with the difference that these are exclusively and explicitly called when the object is in its "predicted" state.

In fact, one possible implementation of those methods is to simply call Spawned(), FixedUpdateNetwork() and Render(), respectively, though the application needs to consider that network properties are not available. One solution to that is to wrap the networked properties with a check for predictive spawning and maintain two sets of variables, like this:

C#

[Networked] private Vector3 _networkedVelocity { get; set; }
private Vector3 _predictedVelocity;
public Vector3 Velocity
{
    get => Object.IsPredictedSpawn ? _predictedVelocity : _networkedVelocity;
    set 
    {
      if (Object.IsPredictedSpawn) 
        _predictedVelocity = value; 
      else 
        _networkedVelocity = value; 
    }    
}
Failed and Success

PredictedSpawnFailed() and PredictedSpawnSuccess are specific to prediction and triggered when the Server / Host confirms the success or failure of the spawn action. If it prediction was successful PredictedSpawnSuccess() is called, otherwise PredictedSpawnFailed() is triggered.

The application rarely needs to handle successful spawns, since the temporary object is simply promoted to a fully networked object and continues to exist as if nothing had changed; however, prediction failures do need to be handled - the simplest implementation is to just destroy the object.

When using Runner.Despawn() on a predicted object, it requires an additional boolean parameter to indicate the object in question was in a predicted state.

C#

public void PredictedSpawnFailed()
{
    Runner.Despawn(Object, true);
}

Runner.Despawn() has to be used because Runner.Spawn() obtained the temporary object through the Fusion Object Pool and thus needs to return it to the pool again.

Back to top