This document is about: FUSION 2
SWITCH TO

NetworkObjectProvider

INetworkObjectProvider

When Spawned is called, the INetworkObjectProvider that was passed in StartGame() StartArgs handles getting/creating the GameObject that will be attached.

NetworkObjectProviderDefault

The default implementation of INetworkObjectProvider is NetworkObjectProviderDefault. If you do not specify a provider in the StartArgs when starting a Runner, the Runner will search the Runner game object for an INetworkObjectProvider component. If none is found there, the Runner will automatically add NetworkObjectProviderDefault.

This very basic implementation will produce Objects in response to Spawn() by instantiating a copy of a passed prefab - without any pooling. Conversely, Despawn() calls are handled with Destroy().

Pooling

The simplest way to create a INetworkObjectProvider that pools objects instead of instantiating and destroying them is to derive from NetworkObjectProviderDefalt and override the InstiatePrefab and DestroyPrefabInstance:

C#

public class PooledNetworkObjectProvider : NetworkObjectProviderDefault
{
    protected override NetworkObject InstantiatePrefab(NetworkRunner runner, NetworkObject prefab)
    {
        // Get object from pool and return it.
    }

    protected override void DestroyPrefabInstance(NetworkRunner runner, NetworkPrefabId prefabId, NetworkObject instance)
    {
        // Return the instance to the pool.
    }
}

Spawning Custom Objects

Instead of relying on remade Prefabs, it is possible to build a custom NetworkObject at runtime.

IMPORTANT: Once spawned and attached, Network Objects CANNOT have Network Behaviours added or removed. Any customization of the Network Behaviours on a Network Object must be done before spawning. It is of course still possible to add and remove any non-networked components.

C#

public class BakingObjectProvider : NetworkObjectProviderDefault
{
  // For this sample, we are using very high flag values to indicate that we need to do a custom instantiate
  // Values lower than this will fall through the default instantiation handling.
  public const int CUSTOM_PREFAB_FLAG = 100000;

  // The NetworkObjectBaker class can be reused and is Runner independent.
  private static NetworkObjectBaker _baker;
  private static NetworkObjectBaker Baker => _baker ??= new NetworkObjectBaker();

  public override NetworkObjectAcquireResult AcquirePrefabInstance(NetworkRunner runner, in NetworkPrefabAcquireContext context, out NetworkObject result) 
  {
    // Detect if this is a custom spawn by its high prefabID value we are passing.
    // The Spawn call will need to pass this value instead of a prefab.
    if (context.PrefabId.RawValue == CUSTOM_PREFAB_FLAG) 
    {
      var go = GameObject.CreatePrimitive(PrimitiveType.Cube);
      var no = go.AddComponent<NetworkObject>();
      go.AddComponent<NetworkTransform>();
      go.name = $"Custom Object"; 
    
      // Baking is required for the NetworkObject to be valid for spawning.
      Baker.Bake(go);
    
      // Move the object to the applicable Runner Scene/PhysicsScene/DontDestroyOnLoad
      // These implementations exist in the INetworkSceneManager assigned to the runner.
      if (context.DontDestroyOnLoad) 
      {
        runner.MakeDontDestroyOnLoad(go);
      }  
      else 
      {
        runner.MoveToRunnerScene(go);
      }

      // We are finished. Return the NetworkObject and report success.
      result = no;
      return NetworkObjectAcquireResult.Success;        
    }
    
    // For all other spawns, use the default spawning.
    return base.AcquirePrefabInstance(runner, context, out result);
  }
}
Back to top