This document is about: FUSION 2
SWITCH TO

Simulation Behaviour

Overview

SimulationBehaviour is the base class for NetworkBehaviour and can be used to have safe access to Fusion's update
methods like FixedUpdateNetwork, Render and such without the need for a NetworkObject.

SimulationBehaviour can not have any networked properties and are not meant to be used along with NetworkObject.
They need to be registered manually on the NetworkRunner using NetworkRunner.AddGlobal(). Registering is not needed for SimulationBehaviours that are on the same GameObject as the NetworkRunner.

Register/Unregister SimulationBehaviours

A SimulationBehavior that is not attached to the same GameObject as the NetworkRunner must be registered manually.
A safe way of doing this is to use the NetworkRunner.GetRunnerForGameObject() method to find the correct runner reference, as shown below.

C#

public void RegisterOnRunner() {
      // Find the network runner for this gameobject scene. This is useful on a scene object.
      var runner = NetworkRunner.GetRunnerForGameObject(gameObject);
      
      // Make sure the network runner is started and running.
      if (runner.IsRunning) {
        runner.AddGlobal(this);
      }
    }
    
    public void RemoveFromRunner() {
      // The same process can be done to remove the SimulationBehaviour.
      var runner = NetworkRunner.GetRunnerForGameObject(gameObject);
      if (runner.IsRunning) {
        runner.RemoveGlobal(this);
      }
    }

Example of use

A SimulationBehavior can be used to access Fusion's internal logic, but they cannot have networked properties and are
not synchronized with other peers. It is perfect for scenarios like an item or power-up spawner on an authoritative
server game where clients should not be aware of the spawn logic, but only need to replicate the spawned power-up or item itself.

Here is an example of a power up spawner using a SimulationBehaviour:

C#

public class BasicPowerUpSpawner : SimulationBehaviour {

    // Local list of prefabs for the available power ups to be spawned.
    [SerializeField] private List<NetworkPrefabRef> _availablePowerUps = new List<NetworkPrefabRef>();

    private float _spawnDelay = 3f;

    public void RegisterOnRunner() {
      // Find the network runner for this gameobject scene. This is useful on a scene object.
      var runner = NetworkRunner.GetRunnerForGameObject(gameObject);
      
      // Make sure the network runner is started and running.
      if (runner.IsRunning) {
        runner.AddGlobal(this);
      }
    }
    
    public void RemoveFromRunner() {
      // The same process can be done to remove the SimulationBehaviour.
      var runner = NetworkRunner.GetRunnerForGameObject(gameObject);
      if (runner.IsRunning) {
        runner.RemoveGlobal(this);
      }
    }

    public override void FixedUpdateNetwork() {
      if (Runner.Tick % Mathf.RoundToInt(Runner.TickRate * _spawnDelay) == 0) {
        // Generate a random index to select a power up from the list.
        int randomIndex = Random.Range(0, _availablePowerUps.Count);
        // Spawn the selected power up.
        Runner.Spawn(_availablePowerUps[randomIndex]);
      }
    }
  }

Note that this script does not register itself on the NetworkRunner, but it does have the register method that needs to be called on demand. The list of available Power Ups is a local list that is only important to the host/server instance,
but the spawned Power Ups NetworkObjects will be correctly replicated to all clients without them needing to know about the spawning logic.

Back to top