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