Skip to content

Commit 42002f9

Browse files
EmandMNoelStephensUnityjabbacakesmichalChrobot
authored
chore: Add documentation for NetworkPrefab InstantiateWithData (#3574)
Documentation for #3497 ## Changelog - Added: Documentation for the Network prefab handler. - Fixed: Updated the Object spawning documentation page to be DA compatible. ## Documentation - Includes documentation for previously-undocumented public API entry points. - Includes edits to existing public API documentation. ## Testing & QA [//]: # ( This section is REQUIRED and should describe how the changes were tested and how should they be tested when Playtesting for the release. It can range from "edge case covered by unit tests" to "manual testing required and new sample was added". Expectation is that PR creator does some manual testing and provides a summary of it here.) ### Functional Testing [//]: # (If checked, List manual tests that have been performed.) _Manual testing :_ - [ ] `Manual testing done` _Automated tests:_ - [ ] `Covered by existing automated tests` - [ ] `Covered by new automated tests` _Does the change require QA team to:_ - [ ] `Review automated tests`? - [ ] `Execute manual tests`? If any boxes above are checked, please add QA as a PR reviewer. ## Backport This is 2.x only documentation update and doesn't need a backport. --------- Co-authored-by: Noel Stephens <[email protected]> Co-authored-by: Amy Reeve <[email protected]> Co-authored-by: Michał Chrobot <[email protected]>
1 parent b8fa7d6 commit 42002f9

File tree

6 files changed

+365
-108
lines changed

6 files changed

+365
-108
lines changed

com.unity.netcode.gameobjects/CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ Additional documentation and release notes are available at [Multiplayer Documen
2929
- Added serializer for `Pose` (#3546)
3030
- Added methods `GetDefaultNetworkSettings` and `GetDefaultPipelineConfigurations` to `UnityTransport`. These can be used to retrieve the default settings and pipeline stages that are used by `UnityTransport`. This is useful when providing a custom driver constructor through `UnityTransport.s_DriverConstructor`, since it allows reusing or tuning the existing configuration instead of trying to recreate it. This means a transport with a custom driver can now easily benefit from most of the features of `UnityTransport`, like integration with the Network Simulator and Network Profiler from the multiplayer tools package. (#3501)
3131
- Added mappings between `ClientId` and `TransportId`. (#3516)
32-
- Added `NetworkPrefabInstanceHandlerWithData<T>`, a variant of `INetworkPrefabInstanceHandler` that provides access to custom instantiation data directly within the `Instantiate()` method. (#3430)
32+
- Added `NetworkPrefabInstanceHandlerWithData<T>`, a variant of `INetworkPrefabInstanceHandler` that provides access to custom instantiation data directly within the `Instantiate()` method. (#3497)
3333

3434
### Fixed
3535

com.unity.netcode.gameobjects/Documentation~/TableOfContents.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
* [Ownership race conditions](basics/race-conditions.md)
3535
* [Spawning and despawning](spawn-despawn.md)
3636
* [Object spawning](basics/object-spawning.md)
37+
* [Network prefab handler](advanced-topics/network-prefab-handler.md)
3738
* [Object pooling](advanced-topics/object-pooling.md)
3839
* [Object visibility](basics/object-visibility.md)
3940
* [Spawning synchronization](basics/spawning-synchronization.md)
@@ -100,4 +101,4 @@
100101
* [NetworkObject parenting](samples/bossroom/networkobject-parenting.md)
101102
* [Optimizing Boss Room](samples/bossroom/optimizing-bossroom.md)
102103
* [NetworkRigidbody](samples/bossroom/networkrigidbody.md)
103-
* [Spawn NetworkObjects](samples/bossroom/spawn-networkobjects.md)
104+
* [Spawn NetworkObjects](samples/bossroom/spawn-networkobjects.md)
Lines changed: 258 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,258 @@
1+
# Network prefab handler
2+
3+
The network prefab handler system provides advanced control over how network prefabs are instantiated and destroyed during runtime. You can use it to override the default Netcode for GameObjects [object spawning](../basics/object-spawning.md) behavior by implementing custom prefab handlers.
4+
5+
The network prefab handler system is accessible from the [NetworkManager](../components/networkmanager.md) as `NetworkManager.PrefabHandler`.
6+
7+
## When to use a prefab handler
8+
9+
For an overview of the default object spawning behavior, refer to the [object spawning page](../basics/object-spawning.md). The default spawning behavior is designed to cover the majority of use cases, however there are some scenarios where you may need more control:
10+
11+
- **Object pooling**: Reusing objects to reduce memory allocation and initialization costs.
12+
- **Performance optimization**: Using different prefab variants on different platforms (such as using a simpler object for server simulation).
13+
- **Custom initialization**: Setting up objects with game client specific data or configurations.
14+
- **Conditional spawning**: Initializing different prefab variants based on runtime conditions.
15+
16+
The prefab handler system addresses these needs through an interface-based architecture. The system relies on two key methods: `Instantiate` and `Destroy`. `Instantiate` is called on non-authority clients when an [authority](../terms-concepts/authority.md) spawns a new [NetworkObject](../basics/networkobject.md) that has a registered network prefab handler. `Destroy` is called on all game clients whenever a registered [NetworkObject](../basics/networkobject.md) is destroyed.
17+
18+
## Create a prefab handler
19+
20+
Prefab handlers are classes that implement one of the Netcode for GameObjects prefab handler descriptions. There are currently two such descriptions:
21+
22+
- [**INetworkPrefabInstanceHandler**](https://docs.unity3d.com/Packages/com.unity.netcode.gameobjects@latest?subfolder=/api/Unity.Netcode.INetworkPrefabInstanceHandler.html): This is the simplest interface for custom prefab handlers.
23+
- [**NetworkPrefabInstanceHandlerWithData**](https://docs.unity3d.com/Packages/com.unity.netcode.gameobjects@latest?subfolder=/api/Unity.Netcode.NetworkPrefabInstanceHandlerWithData.html): This specialized handler receives custom data from the authority during spawning, enabling dynamic prefab customization.
24+
25+
When using a prefab handler, Netcode for GameObjects uses the `Instantiate` and `Destroy` methods instead of default spawn handlers for the NetworkObject during spawning and despawning. The authority instance uses the traditional spawning approach where it will, via user script, instantiate and spawn a network prefab (even for those registered with a prefab handler). However, all non-authority clients will automatically use the instantiate method defined by the `INetworkPrefabInstanceHandler` implementation if the network prefab spawned has a registered `INetworkPrefabInstanceHandler` implementation with the `NetworkPrefabHandler` (`NetworkManager.PrefabHandler`).
26+
27+
### `INetworkPrefabInstanceHandler`
28+
29+
For the simple use case of overriding a network prefab, implement the `INetworkPrefabInstanceHandler` interface and register an instance of that implementation with the `NetworkPrefabHandler` (`NetworkManager.PrefabHandler`).
30+
31+
Use the `INetworkPrefabInstanceHandler` for situations where the prefab override behavior is consistent and known.
32+
33+
```csharp
34+
public interface INetworkPrefabInstanceHandler
35+
{
36+
NetworkObject Instantiate(ulong ownerClientId, Vector3 position, Quaternion rotation);
37+
void Destroy(NetworkObject networkObject);
38+
}
39+
```
40+
41+
### `NetworkPrefabInstanceHandlerWithData`
42+
43+
If you want to provide additional serialized data during the instantiation process, you can derive from the `NetworkPrefabInstanceHandlerWithData` class.
44+
45+
The `NetworkPrefabInstanceHandlerWithData` class allows you to send custom data from the authority during object spawning. This extra data can then be used to change the behavior of the `Instantiate` method. Using `NetworkPrefabInstanceHandlerWithData`, you can send any custom type that is serializable using [`INetworkSerializable`](serialization/inetworkserializable.md).
46+
47+
```csharp
48+
public abstract class NetworkPrefabInstanceHandlerWithData<T> : INetworkPrefabInstanceHandlerWithData
49+
where T : struct, INetworkSerializable
50+
{
51+
public abstract NetworkObject Instantiate(ulong ownerClientId, Vector3 position, Quaternion rotation, T instantiationData);
52+
public abstract void Destroy(NetworkObject networkObject);
53+
}
54+
```
55+
56+
## Register a prefab handler
57+
58+
Once you've [created a prefab handler](#create-a-prefab-handler), whether by implementing or deriving, you need to register any new instance of that handler with the network prefab handler system using `NetworkManager.PrefabHandler.AddHandler`. Prefab handlers are registered against a NetworkObject's [GlobalObjectIdHash](../basics/networkobject.md#using-networkobjects).
59+
60+
```csharp
61+
public class GameManager : NetworkBehaviour
62+
{
63+
[SerializeField] private GameObject prefabToSpawn;
64+
65+
void Start()
66+
{
67+
var customHandler = new MyPrefabHandler();
68+
NetworkManager.PrefabHandler.AddHandler(prefabToSpawn, customHandler);
69+
}
70+
}
71+
```
72+
73+
To un-register a prefab handler, you can [invoke the `NetworkManager.PrefabHandler.RemoveHandler` method](https://docs.unity3d.com/Packages/com.unity.netcode.gameobjects@latest?subfolder=/api/Unity.Netcode.NetworkPrefabHandler.html#Unity_Netcode_NetworkPrefabHandler_RemoveHandler_System_UInt32_). There are several override versions of this method.
74+
75+
## Object spawning with prefab handlers
76+
77+
Once a prefab handler is registered, Netcode for GameObjects automatically uses the defined `Initialize` and `Destroy` methods to manage the object lifecycle. [Spawn the network prefab as usual](../basics/object-spawning.md#spawning-a-network-prefab-overview) and the `Initialize` method will be called on whichever handler is registered with the spawned network prefab.
78+
79+
Note that the `Initialize` method is only called on non-authority clients. To customize network prefab behavior on the authority, you can use [prefab overrides](../basics/object-spawning.md#taking-prefab-overrides-into-consideration).
80+
81+
### Object spawning with custom data
82+
83+
When using a handler derived from `NetworkPrefabInstanceHandlerWithData`, you must manually set the instantiation data after instantiating the instance (but before spawning) by invoking the `NetworkPrefabInstanceHandlerWithData.SetInstantiationData` method before invoking the `NetworkObject.Spawn` method. If `SetInstantiationData` is not called, the `default` implementation will be sent to the `Instantiate` call.
84+
85+
#### Examples
86+
87+
The first example here is a pseudo-script where the `InstantiateData` structure implements the `INetworkSerializable` interface and is used to serialize instantiation data for a network prefab defined within the `SpawnPrefabWithColor` NetworkBehaviour.
88+
89+
```csharp
90+
/// <summary>
91+
/// The instantiation data that is serialized and sent with the
92+
/// spawn object message and provided prior to instantiating.
93+
/// </summary>
94+
public struct InstantiateData : INetworkSerializable
95+
{
96+
// For example purposes, the color of the material of a MeshRenderer
97+
public Color Color;
98+
99+
// Add additional pre-spawn configuration fields here:
100+
101+
public void NetworkSerialize<T>(BufferSerializer<T> serializer) where T : IReaderWriter
102+
{
103+
serializer.SerializeValue(ref Color);
104+
105+
// Add addition (field) value serialization here for each new field:
106+
}
107+
}
108+
```
109+
110+
The second example, `SpawnPrefabWithColor`, is an example of a NetworkBehavior component, to be placed on an in-scene placed NetworkObject, that handles the instantiation of a prefab handler (`SpawnWithColorHandler`) and the means to configure the network prefab to register with the handler. It also has a `SpawnWithColorSystem.SpawnObject` method that can instantiate an instance of the assigned network prefab instance that will also have instantiation data associated with it that contains the color to be applied to the instance's MeshRenderers.
111+
112+
There are easier ways to synchronize the color of MeshRenderer instances across clients, this is only for example purposes.
113+
114+
```csharp
115+
/// <summary>
116+
/// Add to an in-scene placed <see cref="NetworkObject"/>.
117+
/// </summary>
118+
public class SpawnPrefabWithColor : NetworkBehaviour
119+
{
120+
/// <summary>
121+
/// The network prefab used to register the <see cref="SpawnWithDataSystem"/> handler.
122+
/// </summary>
123+
public GameObject NetworkPrefab;
124+
125+
/// <summary>
126+
/// The <see cref="SpawnWithDataSystem"/> handler instance.
127+
/// </summary>
128+
private SpawnWithColorHandler m_SpawnWithColorHandler;
129+
130+
protected override void OnNetworkPreSpawn(ref NetworkManager networkManager)
131+
{
132+
m_SpawnWithColorHandler = new SpawnWithColorHandler(networkManager, NetworkPrefab);
133+
base.OnNetworkPreSpawn(ref networkManager);
134+
}
135+
136+
/// <summary>
137+
/// Invoked by some other component or additional script logic controls
138+
/// when an object is spawned.
139+
/// </summary>
140+
/// <param name="color">The color to apply (pseudo example purposes)</param>
141+
/// <returns>The spawned <see cref="NetworkObject"/> instance</returns>
142+
public NetworkObject SpawnObject(Vector3 position, Quaternion rotation, Color color)
143+
{
144+
if (!IsSpawned || !HasAuthority || m_SpawnWithColorHandler == null)
145+
{
146+
return null;
147+
}
148+
// Instantiate, set the instantiation data, and then spawn the network prefab.
149+
return m_SpawnWithColorHandler.InstantiateSetDataAndSpawn(position, rotation, new InstantiateData() { Color = color });
150+
}
151+
}
152+
```
153+
The `SpawnWithColorSystem` invokes the `SpawnWithColorHandler.InstantiateSetDataAndSpawn` method to create a new network prefab instance, set the instantiation data, and then spawn the network prefab instance.
154+
155+
The third example is the most complex: `SpawnWithColorHandler` with a constructor that automatically registers itself and the network prefab with the `NetworkManager.PrefabHandler`:
156+
157+
```csharp
158+
/// <summary>
159+
/// The prefab instance handler that uses instantiation data to handle updating
160+
/// the instance's <see cref="MeshRenderer"/>s material's color. (example purposes only)
161+
/// </summary>
162+
public class SpawnWithColorHandler : NetworkPrefabInstanceHandlerWithData<InstantiateData>
163+
{
164+
private GameObject m_RegisteredPrefabToSpawn;
165+
private NetworkManager m_NetworkManager;
166+
167+
/// <summary>
168+
/// Constructor
169+
/// </summary>
170+
/// <param name="registeredPrefab">The prefab used to register this handler instance.</param>
171+
/// <param name="networkPrefabGroup">The prefab group this handler will be able to spawn.</param>
172+
public SpawnWithColorSystem(NetworkManager networkManager, GameObject registeredPrefab)
173+
{
174+
m_NetworkManager = networkManager;
175+
m_RegisteredPrefabToSpawn = registeredPrefab;
176+
177+
// Register this handler with the NetworkPrefabHandler
178+
m_NetworkManager.PrefabHandler.AddHandler(m_RegisteredPrefabToSpawn, this);
179+
}
180+
181+
/// <summary>
182+
/// Used by the server or a client when using a distributed authority network topology,
183+
/// instantiate the prefab, set the instantiation data, and then spawn.
184+
/// </summary>
185+
public NetworkObject InstantiateSetDataAndSpawn(Vector3 position, Quaternion rotation, InstantiateData instantiateData)
186+
{
187+
var instance = GetPrefabInstance(position, rotation, instantiateData);
188+
189+
// Set the instantiate data before spawning
190+
m_NetworkManager.PrefabHandler.SetInstantiationData(instance, instantiateData);
191+
192+
instance.GetComponent<NetworkObject>().Spawn();
193+
return instance;
194+
}
195+
196+
/// <summary>
197+
/// Returns an instance of the registered prefab (no instantiation data set yet)
198+
/// </summary>
199+
public NetworkObject GetPrefabInstance(Vector3 position, Quaternion rotation, InstantiateData instantiateData)
200+
{
201+
// Optional to include your own position and/or rotation within the InstantiateData.
202+
var instance = Object.Instantiate(m_RegisteredPrefabToSpawn, position, rotation);
203+
var meshRenderers = instance.GetComponentsInChildren<MeshRenderer>();
204+
foreach (var renderer in meshRenderers)
205+
{
206+
// Assign the color to each MeshRenderer (just a pseudo example)
207+
renderer.material.color = instantiateData.Color;
208+
}
209+
return instance.GetComponent<NetworkObject>();
210+
}
211+
212+
/// <inheritdoc/>
213+
public override NetworkObject Instantiate(ulong ownerClientId, Vector3 position, Quaternion rotation, InstantiateData instantiateData)
214+
{
215+
// For non-authority instances, we can just get an instance based off of the passed in InstantiateData
216+
return GetPrefabInstance(position, rotation, instantiateData);
217+
}
218+
219+
/// <inheritdoc/>
220+
public override void Destroy(NetworkObject networkObject)
221+
{
222+
Object.DestroyImmediate(networkObject.gameObject);
223+
}
224+
}
225+
```
226+
When instantiating from user script for a host, server, or distributed authority client, the above `InstantiateSetDataAndSpawn` method is used. When instantiating on non-authority instances, the `GetPrefabInstance` method is used, since the authority provides the instantiation data.
227+
228+
While setting the color of a MeshRenderer doesn't really provide a broad spectrum use case scenario for `NetworkPrefabInstanceHandlerWithData`, the above example does provide you with a simple implementation to understand::
229+
230+
- Creating a serializable structure to be serialized with the spawned network prefab.
231+
- Creating a component (in this case a NetworkBehaviour) that's used to instantiate the handler and configure the network prefab to be registered.
232+
- Creating a `NetworkPrefabInstanceHandlerWithData` derived class that:
233+
- Handles instantiating and destroying instances of the registered prefab.
234+
- Provides an example of instantiating the network prefab, setting the instantiation data for the instance, and then spawning the instance.
235+
- Provides an example of taking the de-serialized instantiation data and using one (or more) fields to configure the network prefab instance prior to it being spawned.
236+
237+
### Pre-instantiation data and spawn data
238+
239+
You can use `NetworkPrefabInstanceHandlerWithData` to include pre-spawn instantiation data that you can then use to define the instance before the instance is instantiated and/or spawned. However, the are some subtle differences between pre-spawn serialized data and spawn serialized data.
240+
241+
- *Pre-spawn serialized data*:
242+
- Is included in the NetworkObject serialized data.
243+
- Is extracted and de-serialized prior to invoking the `NetworkPrefabInstanceHandlerWithData.Instantiate` method.
244+
- Can be used to identify pre-instantiated objects and/or the type of network prefab to be spawned.
245+
- Has no context for the network prefab that's going to be spawned, unless you provide that in the instantiation data.
246+
- Can include any kind of serialized data types supported by Netcode for GameObjects.
247+
- Can be used to spawn pre-determined instances that are created prior to connecting to the session or created while synchronizing with a session.
248+
- *Spawn serialized data*:
249+
- Isn't available until the network prefab is already instantiated and is in the middle of or has finished the spawn process.
250+
- Can't be used to define what network prefab to instantiate.
251+
- Typically will include other netcode related states such as NetworkVariables and RPCs.
252+
253+
When it comes to including instantiation data, you should be cautious about including data from already spawned objects. You need to ensure that the serialized information of already spawned objects, like a `NetworkBehaviourReference` or `NetworkObjectReference`, exists prior to being used.
254+
255+
## Additional resources
256+
257+
- [Object pooling](./object-pooling.md)
258+
- [Authority prefab overrides](../basics/object-spawning.md#taking-prefab-overrides-into-consideration)

0 commit comments

Comments
 (0)