Skip to content
This repository was archived by the owner on Jul 23, 2025. It is now read-only.

Commit 3dc48bc

Browse files
jabbacakesr-machVic-CooperLagowiecDevamanda-butler-unity
authored
Develop into main (#1239)
Co-authored-by: Rémi MACH <[email protected]> Co-authored-by: Vic Cooper <[email protected]> Co-authored-by: LagowiecDev <[email protected]> Co-authored-by: amanda-butler-unity <[email protected]> Co-authored-by: Noel Stephens <[email protected]> Co-authored-by: Griffin of Innatical <[email protected]> Co-authored-by: Christopher Pope <[email protected]> Co-authored-by: Steve Diniro <[email protected]> Co-authored-by: s-omeilia-unity <[email protected]> Co-authored-by: Alex Martin <[email protected]> Co-authored-by: Monaxys <[email protected]> Co-authored-by: Flap27 <[email protected]> Co-authored-by: NRTnarathip <[email protected]>
1 parent 2181fb6 commit 3dc48bc

File tree

19 files changed

+313
-41
lines changed

19 files changed

+313
-41
lines changed

docs/advanced-topics/networkobject-parenting.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ If you only plan on making a one time change to the child NetworkObject componen
102102

103103
### Network prefabs, parenting, and NetworkTransform components
104104

105-
Because the NetworkTransform component synchronizes the transform of a GameObject component (with a NetworkObject component attached to it), it can become tricky to understand the parent-child transform relationship and how that translates when synchronizing late joining clients. Currently, a network prefab can only have one NetworkObject component within the root GameObject component of the prefab. However, you can have a complex hierarchy of GameObject components nested under the root GameObjet component and each child GameObject component can have a NetworkBehaviour component attached to it. Because a NetworkTransform component synchronizes the transform of the GameObject component it's attached to, you might be tempted to setup a network prefab like this:
105+
Because the NetworkTransform component synchronizes the transform of a GameObject component (with a NetworkObject component attached to it), it can become tricky to understand the parent-child transform relationship and how that translates when synchronizing late joining clients. Currently, a network prefab can only have one NetworkObject component within the root GameObject component of the prefab. However, you can have a complex hierarchy of GameObject components nested under the root GameObject component and each child GameObject component can have a NetworkBehaviour component attached to it. Because a NetworkTransform component synchronizes the transform of the GameObject component it's attached to, you might be tempted to setup a network prefab like this:
106106

107107
```
108108
Network Prefab Root (GameObject with NetworkObject and NetworkTransform components attached to it)

docs/advanced-topics/physics.md

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ title: Physics
44
Description: Brief explanation on using Physics in Netcode for GameObjects
55
---
66

7-
There are many different ways to do physics in multiplayer games. Netcode for GameObjects (Netcode) has a built in approach which allows for server-authoritative physics where the physics simulation only runs on the server. To enable network physics, add a `NetworkRigidbody` component to your object.
7+
There are many different ways to manage physics simulation in multiplayer games. Netcode for GameObjects (Netcode) has a built in approach which allows for server-authoritative physics where the physics simulation only runs on the server. To enable network physics, add a `NetworkRigidbody` component to your object.
88

99
## NetworkRigidbody
1010

@@ -26,7 +26,7 @@ If there is a need for a gameplay event to happen on a collision, you can listen
2626

2727
`NetworkRigidbody2D` works in the same way as NetworkRigidbody but for 2D physics (`Rigidbody2D`) instead.
2828

29-
## NetworkRigidbody & ClientNetworkTransform
29+
## NetworkRigidbody and ClientNetworkTransform
3030

3131
You can use NetworkRigidbody with the [`ClientNetworkTransform`](../components/networktransform.md#clientnetworktransform) package sample to allow the owner client of a NetworkObject to move it authoritatively. In this mode, collisions only result in realistic dynamic collisions if the object is colliding with other NetworkObjects (owned by the same client).
3232

@@ -40,6 +40,29 @@ Add the ClientNetworkTransform component to your GameObject first. Otherwise the
4040

4141
A common issue with physics in multiplayer games is lag and how objects update on basically different timelines. For example, a player would be on a timeline that’s offset by the network latency relative to your server’s objects. One way to prepare for this is to test your game with artificial lag. You might catch some weird delayed collisions that would otherwise make it into production.
4242

43-
The ClientDriven [bitesize sample](../learn/bitesize/bitesize-clientdriven.md) addresses this by manually adding forces server-side to offer a buffer before an actual collision, but it still feels wobbly at times. However, this isn't really a solution.
43+
The ClientDriven [bitesize sample](../learn/bitesize/bitesize-clientdriven.md) addresses this by manually adding forces server-side to offer a buffer before an actual collision, but it still feels wobbly at times. However, this isn't really a solution.
4444

45-
The best way to address the issue of physics latency is to create a custom `NetworkTransform` with a custom physics-based interpolator. You can also use the [Network Simulator tool](../../tools/network-simulator.md) to spot issues with latency.
45+
The best way to address the issue of physics latency is to create a custom `NetworkTransform` with a custom physics-based interpolator. You can also use the [Network Simulator tool](../../tools/network-simulator.md) to spot issues with latency.
46+
47+
## Message processing vs. applying changes to state (timing considerations)
48+
49+
When handling the synchronization of changes to certain physics properties, it's important to understand the order of operations involved in message processing relative to the update stages that occur within a single frame. The stages occur in this order:
50+
51+
- Initialization _(Awake and Start are invoked here)_
52+
- EarlyUpdate _(Inbound messages are processed here)_
53+
- FixedUpdate _(Physics simulation is run and results)_
54+
- PreUpdate _(NetworkTime and Tick is updated)_
55+
- Update _(NetworkBehaviours/Components are updated)_
56+
- PreLateUpdate: _(Useful for handling post-update tasks prior to processing and sending pending outbound messages)_
57+
- LateUpdate: _(Useful for changes to camera, detecting input, and handling other post-update tasks)_
58+
- PostLateUpdate: _(Dirty NetworkVariables processed and pending outbound messages are sent)_
59+
60+
From this list of update stages, the `EarlyUpdate` and `FixedUpdate` stages have the most impact on NetworkVariableDeltaMessage and RpcMessages processing. Inbound messages are processed during the `EarlyUpdate` stage, which means that Rpc methods and NetworkVariable.OnValueChanged callbacks are invoked at that point in time during any given frame. Taking this into consideration, there are certain scenarios where making changes to a Rigidbody could yield undesirable results.
61+
62+
### Rigidbody interpolation example
63+
64+
While `NetworkTransform` offers interpolation as a way to smooth between delta state updates, it doesn't get applied to the authoritative instance. You can use `Rigidbody.interpolation` for your authoritative instance while maintaining a strict server-authoritative motion model.
65+
66+
To have a client control their owned objects, you can use either [RPCs](message-system/rpc.md) or [NetworkVariables](../basics/networkvariables.md) on the client-side. However, this often results in the host-client's updates working as expected, but with slight jitter when a client sends updates. You might be scanning for key or device input during the `Update` to `LateUpdate` stages. Any input from the host player is applied after the `FixedUpdate` stage (i.e. physics simulation for the frame has already run), but input from client players is sent via a message and processed, with a half RTT delay, on the host side (or processed 1 network tick + half RTT if using NetworkVariables). Because of when messages are processed, client input updates run the risk of being processed during the `EarlyUpdate` stage which occurs just before the current frame's `FixedUpdate` stage.
67+
68+
To avoid this kind of scenario, it's recommended that you apply any changes received via messages to a Rigidbody _after_ the FixedUpdate has run for the current frame. If you [look at how `NetworkTransform` handles its changes to transform state](https://github.com/Unity-Technologies/com.unity.netcode.gameobjects/blob/a2c6f7da5be5af077427eef9c1598fa741585b82/com.unity.netcode.gameobjects/Components/NetworkTransform.cs#L3028), you can see that state updates are applied during the `Update` stage, but are received during the `EarlyUpdate` stage. Following this kind of pattern when synchronizing changes to a Rigidbody via messages will help you to avoid unexpected results in your Netcode for GameObjects project.

docs/basics/networkobject.md

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -117,9 +117,9 @@ NetworkManager.Singleton.ConnectedClients[clientId].PlayerObject;
117117

118118
To find your own player object just pass `NetworkManager.Singleton.LocalClientId` as the `clientId` in the sample above.
119119

120-
### Network Prefabs
120+
## Network prefabs
121121

122-
Network Prefabs are registered to a `NetworkPrefabsList` object (a type of `ScriptableObject`). By default, a Default Prefabs List containing every Network Prefab in your project.
122+
Network prefabs are registered to a `NetworkPrefabsList` object (a type of `ScriptableObject`). By default, a default prefabs List containing every network prefab in your project.
123123

124124
However, when you want to limit which prefabs are available (for example, to reduce memory usage), you can disable this behavior in **Project Settings** > **Netcode For GameObjects** > **Project Settings**. You can also manually create a `NetworkPrefabsList` by right-clicking in the assets view and selecting **Create** > **Netcode** > **Network Prefabs List** and adding your prefabs to it. That prefab list can then be assigned to a `NetworkManager` to allow that `NetworkManager` to create those prefabs.
125125

@@ -129,13 +129,37 @@ You can only have one `NetworkObject` at the root of a Prefab. Don't create Pref
129129

130130
:::
131131

132-
### Spawning with (or without) Observers
132+
### Creating a network prefab
133+
134+
You can create a network prefab the [same way you create normal prefabs](https://docs.unity3d.com/Manual/CreatingPrefabs.html). The only difference is that the root GameObject of the prefab should have a `NetworkObject` component added to it:
135+
136+
![image](/img/createnetworkprefab.png)
137+
138+
### Converting a prefab to a network prefab
139+
140+
Sometimes you might run into a scenario where you created a prefab and already have several in-scene placed instances of that prefab within one or more already existing scenes. In this scenario, you can:
141+
142+
- Navigate to your source network prefab.
143+
- Select it so its properties show up in the inspector view.
144+
- Find the `NetworkObject` component and right click on it.
145+
- At the bottom of the context menu, select the **Refresh In-Scene Prefab Instances** menu item.
146+
147+
![image](/img/RefresInScenePrefabInstances.png)
148+
149+
This will:
150+
- Open each scene, individually, within the **Build Settings** > **Scenes in Build** list
151+
- Automatically update each prefab instance with the correct `GlobalObjectIdHash` value and then save and close each scene.
152+
153+
This will process the currently opened scene as well.
154+
155+
## Spawning with (or without) observers
156+
133157
![image](/img/SpawnWithObservers.png)
134158

135159
The `NetworkObject.SpawnWithObservers` property (default is true) provides you with the ability to spawn a `NetworkObject` with no initial observers. This is the recommended alternative to using `NetworkObject.CheckObjectVisibility` when you just want it to be applied globally to all clients (only when spawning an instance of the `NetworkObject` in question). If you want more precise per-client control then `NetworkObject.CheckObjectVisibility` is recommended. `NetworkObject.SpawnWithObservers` is only applied upon the initial server-side spawning and once spawned it has no impact on object visibility.
136160

161+
## Transform synchronization
137162

138-
### Transform Synchronization
139163
![image](/img/NetworkObject-TransformSynchronization.png)
140164

141165
There are times when you want to use a NetworkObject for something that does not require the synchronization of its transform. You might have an [In-Scene placed NetworkObject](./scenemanagement/inscene-placed-networkobjects.md) that is purely used to manage game state (or the like) and it doesn't make sense to incur the initial client synchronization cost of synchronizing its transform. To prevent a NetworkObject from initially synchronizing its transform when spawned, un-check the Synchronize Transform property. This property is enabled/checked by default.
@@ -144,14 +168,15 @@ There are times when you want to use a NetworkObject for something that does not
144168
If you are planning to use a NetworkTransform then you always want to make sure the Synchronize Transform property is enabled/checked.
145169
:::
146170

147-
### Active Scene Synchronization
171+
## Active scene synchronization
172+
148173
![image](/img/ActiveSceneMigration.png)
149174

150175
When a GameObject is instantiated it gets instantiated in the current active scene. However, sometimes you might find that you want to change the currently active scene and would like specific NetworkObject instances to automatically migrate to the newly assigned active scene. While you could keep a list or table of the NetworkObject instances and write the code/logic to migrate them into a newly assigned active scene, this can be time consuming an become complicated depending upon project size and complexity. The alternate way (and recommended) to handle this is by enabling/checking the Active Scene Synchronization property of each NetworkObject you want to automatically migrate into any newly assigned scene. This property defaults to disabled/un-checked.
151176

152177
See Also: [NetworkSceneManager Active Scene Synchronization](../basics/scenemanagement/using-networkscenemanager#active-scene-synchronization)
153178

154-
### Scene Migration Synchronization
179+
## Scene migration synchronization
155180

156181
![image](/img/SceneMigrationSynchronization.png)
157182

docs/basics/networkvariable.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -482,7 +482,7 @@ public struct AreaWeaponBooster : INetworkSerializable, System.IEquatable<AreaWe
482482

483483
public bool Equals(AreaWeaponBooster other)
484484
{
485-
return other.Equals(this) && Radius == other.Radius && Location == other.Location;
485+
return ApplyWeaponBooster.Equals(other.ApplyWeaponBooster) && Radius == other.Radius && Location == other.Location;
486486
}
487487
}
488488
```

docs/basics/object-spawning.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ var instance = Instantiate(NetworkManager.GetNetworkPrefabOverride(myPrefab));
7171
var instanceNetworkObject = instance.GetComponent<NetworkObject>();
7272
instanceNetworkObject.Spawn();
7373
```
74-
In the above script, we get the prefab override using the `NetworkManager.GetNetworkPrefabOverride` method. Then we then create an instance of the network prefab override, and finally we spawn the network prefab override instance's `NetworkObject`.
74+
In the above script, we get the prefab override using the `NetworkManager.GetNetworkPrefabOverride` method. Then we create an instance of the network prefab override, and finally we spawn the network prefab override instance's `NetworkObject`.
7575

7676
#### Using InstantiateAndSpawn
7777
The second option is to leverage the `NetworkSpawnManager.InstantiateAndSpawn` method that handles whether or not to spawn an override for you. The below script is written as if it's being invoked within a `NetworkBehaviour`.
@@ -178,14 +178,14 @@ While the NonPooledDynamicSpawner example is one of the simplest ways to spawn a
178178
:::
179179

180180
:::note
181-
Really, the when we use the term "non-pooled" more often than not we are referring to the concept that a `GameObject` will be instantiated on both the server and the clients each time an instance is spawned.
181+
Really, when we use the term "non-pooled" more often than not we are referring to the concept that a `GameObject` will be instantiated on both the server and the clients each time an instance is spawned.
182182
:::
183183

184184
### Pooled Dynamic Spawning
185185

186186
Pooled dynamic spawning is when netcode objects (`GameObject` with one `NetworkObject` component) aren't destroyed on the server or the client when despawned. Instead, specific components are just disabled (or the `GameObject` itself) when a netcode object is despawned. A pooled dynamically spawned netcode object is typically instantiated during an already memory allocation heavy period of time (like when a scene is loaded or even at the start of your application before even establishing a network connection). Pooled dynamically spawned netcode objects are more commonly thought of as more than one netcode object that can be re-used without incurring the memory allocation and initialization costs. However, you might also run into scenarios where you need just one dynamically spawned netcode object to be treated like a pooled dynmically spawned netcode object.
187187

188-
Fortunately, Netcode for GameObjects provides you with a way to be in control over the instatiation and destruction process for one or many netcode objects by via the `INetworkPrefabInstanceHandler` interface. Any `INetworkPrefabInstanceHandler`implementation should be registered with the `NetworkPrefabHandler`(for multiple netcode objects see [Object Pooling](../advanced-topics/object-pooling)) to accomplish this.
188+
Fortunately, Netcode for GameObjects provides you with a way to be in control over the instatiation and destruction process for one or many netcode objects by via the `INetworkPrefabInstanceHandler` interface. Any `INetworkPrefabInstanceHandler`implementation should be registered with the `NetworkPrefabHandler`(for multiple netcode objects see [Object Pooling](../advanced-topics/object-pooling.md)) to accomplish this.
189189

190190
The easiest way to not destroy a network Prefab instance is to have something, other than the instance itself, keeping a reference to the instance. This way you can simply set the root `GameObject` to be inactive when it's despawned while still being able to set it active when the same network Prefab type needs to be respawned. Below is one example of how you can accomplish this for a single netcode object instance:
191191

0 commit comments

Comments
 (0)