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.

Back To Top

IMPORTANT!

Do NOT use Unity's built in GameObject.Instantiate() and GameObject.Destroy() methods 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.

Back To Top

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.

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.

Back To Top

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.

Back To Top

OnBeforeSpawned

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

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 initialisation 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.

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);
}

Back To Top

Spawned

When Fusion creates a new object, it will call the Spawned() method on that object. The Spawned() callback is intended for resetting non-networked variables and sub-systems. For instance if the application is using Object Pooling, Spawned() may need to reset values to their prefab defaults because the object has been recycled and no longer has its default state. All NetworkBehaviour components implement the ISpawned interface, thus every component deriving from NetworkBehaviour can simply override and implement it. SimulationBehaviour derived components, however, need to explicitly implement ISpawned and its methods to have their Spawned() method called.

Spawned() is called when Fusion first learns of the object's existence. This is not tick aligned or necessarily anywhere near the same tick in which the object was originally spawned by the authoritative peer. For this reason Networked state should not be initialized in Spawned(), nor should RPCs be sent in Spawned().

  • For spawns on a peer with State Authority, Spawned() is called immediately after Runner.Spawn().
  • For predicted spawns on a peer with Input Authority, Spawned() is called when network state is allocated (i.e. when the spawn is confirmed).
  • For proxies (i.e. object over which the peer has neither Input Authority nor State Authority), Spawned() is called when Fusion receives a network state with an object that does not exist locally. In particular a late-joiner will likely receive objects that were spawned a long time ago and the original state from their "birth tick" no longer be relevance.

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

Back To Top

Despawn

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

Back To Top

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.

Back To Top

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 existance has been confirmed as successful or failed.

Two things need to happen for this to work:

  1. A unique identifier 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 such until it is either confirmed or cancelled.

Back To Top

NetworkObjectPredictionKey

The predictionKey parameter in the Runner.Spawn() method consists 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.
var predictionKey = new NetworkObjectPredictionKey {Byte0 = (byte) Runner.Simulation.Tick, Byte1 = playerIndex};

N.B.: If multiple networked objects are predictively 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.

Back To Top

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.

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

Back To Top

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:

[Networked]
public Vector3 networkedVelocity { get; set; }
private Vector3 _predictedVelocity;
public Vector3 velocity
{
    get => Object.IsPredictedSpawn ? _predictedVelocity : networkedVelocity;
    set 
    {
      if (Object.IsPredictedSpawn) 
        _predictedVelocity = value; 
      else 
        networkedVelocity = value; 
    }    
}

Back To Top

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 prediciton 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.

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.

To Document Top