Skip to content

feat: AttachableBehaviour and ComponentController #3518

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 62 commits into
base: develop-2.0.0
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
62 commits
Select commit Hold shift + click to select a range
43906be
update
NoelStephensUnity May 22, 2025
6267a3e
update
NoelStephensUnity May 28, 2025
83ee650
update
NoelStephensUnity May 28, 2025
3914204
Merge branch 'develop-2.0.0' into feat/attachable-networkbehaviour-an…
NoelStephensUnity May 28, 2025
41b14b5
Merge branch 'develop-2.0.0' into feat/attachable-networkbehaviour-an…
NoelStephensUnity Jun 23, 2025
1832d21
refactor
NoelStephensUnity Jun 24, 2025
d08d496
test
NoelStephensUnity Jun 24, 2025
4a9775a
style
NoelStephensUnity Jun 24, 2025
1f81ebd
style - PVP
NoelStephensUnity Jun 24, 2025
4148bfe
style - standards
NoelStephensUnity Jun 24, 2025
2322d48
Merge branch 'develop-2.0.0' into feat/attachable-networkbehaviour-an…
NoelStephensUnity Jun 24, 2025
1fce513
refactor
NoelStephensUnity Jun 24, 2025
1ceb76c
update
NoelStephensUnity Jun 24, 2025
db05292
test
NoelStephensUnity Jun 24, 2025
2d391ed
test - update
NoelStephensUnity Jun 24, 2025
ae29873
style
NoelStephensUnity Jun 24, 2025
078bca1
Merge branch 'develop-2.0.0' into feat/attachable-networkbehaviour-an…
NoelStephensUnity Jun 24, 2025
ec59da9
Merge branch 'develop-2.0.0' into feat/attachable-networkbehaviour-an…
NoelStephensUnity Jul 10, 2025
043b0e7
update
NoelStephensUnity Jul 10, 2025
6e9530e
Merge branch 'develop-2.0.0' into feat/attachable-networkbehaviour-an…
NoelStephensUnity Jul 10, 2025
abd75d0
update
NoelStephensUnity Jul 10, 2025
e098e31
update
NoelStephensUnity Jul 13, 2025
cab1983
refactor
NoelStephensUnity Jul 13, 2025
1341aa0
style
NoelStephensUnity Jul 13, 2025
13d9a03
update & style
NoelStephensUnity Jul 13, 2025
8bd712c
refactor
NoelStephensUnity Jul 15, 2025
a63de0b
test
NoelStephensUnity Jul 15, 2025
17b769d
Merge branch 'develop-2.0.0' into feat/attachable-networkbehaviour-an…
NoelStephensUnity Jul 15, 2025
912b26f
update
NoelStephensUnity Jul 15, 2025
6d8f7a6
Merge branch 'develop-2.0.0' into feat/attachable-networkbehaviour-an…
NoelStephensUnity Jul 15, 2025
9dd32d5
update
NoelStephensUnity Jul 15, 2025
793cdb6
fix
NoelStephensUnity Jul 15, 2025
fb73b8c
style - PVP
NoelStephensUnity Jul 15, 2025
4b4c8ca
update
NoelStephensUnity Jul 18, 2025
42ac2a8
sty;e - PvP
NoelStephensUnity Jul 19, 2025
efcc404
update and test additions
NoelStephensUnity Jul 21, 2025
9b4bf43
Merge branch 'develop-2.0.0' into feat/attachable-networkbehaviour-an…
NoelStephensUnity Jul 21, 2025
741b42b
docs (update,, refactor. and fix)
NoelStephensUnity Jul 30, 2025
cc04caf
docs (style-PVP)
NoelStephensUnity Jul 30, 2025
8ad7a82
docs(style-pvp)
NoelStephensUnity Jul 30, 2025
959ccef
docs (update & add)
NoelStephensUnity Jul 30, 2025
7c95cc7
docs (style - PVP)
NoelStephensUnity Jul 30, 2025
3866464
Merge branch 'develop-2.0.0' into feat/attachable-networkbehaviour-an…
NoelStephensUnity Jul 30, 2025
fe88923
docs (style)
NoelStephensUnity Jul 30, 2025
5662003
Update com.unity.netcode.gameobjects/Runtime/Core/NetworkObject.cs
NoelStephensUnity Jul 30, 2025
93b645f
update
NoelStephensUnity Jul 30, 2025
e9eec54
style
NoelStephensUnity Jul 30, 2025
a2d8703
Merge branch 'develop-2.0.0' into feat/attachable-networkbehaviour-an…
NoelStephensUnity Jul 30, 2025
db4adab
Lorge doc review
jabbacakes Aug 1, 2025
ea66904
Merge branch 'develop-2.0.0' into feat/attachable-networkbehaviour-an…
NoelStephensUnity Aug 5, 2025
39c999c
Merge branch 'develop-2.0.0' into feat/attachable-networkbehaviour-an…
NoelStephensUnity Aug 6, 2025
dd7d4c9
Update AttachableBehaviour.cs
NoelStephensUnity Aug 6, 2025
44c5ee7
style
NoelStephensUnity Aug 6, 2025
9122d3b
Update com.unity.netcode.gameobjects/Runtime/Components/Helpers/Compo…
NoelStephensUnity Aug 7, 2025
f7a9001
Merge branch 'develop-2.0.0' into feat/attachable-networkbehaviour-an…
NoelStephensUnity Aug 7, 2025
bb04aa9
Merge branch 'develop-2.0.0' into feat/attachable-networkbehaviour-an…
NoelStephensUnity Aug 7, 2025
aa8b2f4
update
NoelStephensUnity Aug 7, 2025
48bc4c0
update
NoelStephensUnity Aug 7, 2025
9260d94
doc: update
NoelStephensUnity Aug 11, 2025
c1fd85e
Merge branch 'develop-2.0.0' into feat/attachable-networkbehaviour-an…
NoelStephensUnity Aug 14, 2025
a8b7743
Follow up docs pass
jabbacakes Aug 14, 2025
a9fb80b
Merge develop-2.0.0 into feat/attachable-networkbehaviour-and-object-…
netcode-ci-service Aug 14, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ OnNetworkSpawn | NetworkObject | During spawn initializ
OnNetworkPostSpawn | NetworkObject | Post-spawn actions | Client and server
OnNetworkSessionSynchronized | All NetworkObjects | New client finished synchronizing | Client-side only
OnInSceneObjectsSpawned | In-scene NetworkObjects | New client finished synchronizing or a scene is loaded | Client and server
OnNetworkPreDespawn | NetworkObject | Invoked before de-spawning NetworkObject | Client and server

In addition to the methods above, there are two special case convenience methods:

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,40 @@ Dynamically spawned | In-scene placed
`OnNetworkSpawn` | `Start`
`Start` | `OnNetworkSpawn`

For more information about NetworkBehaviour methods and when they are invoked, see the [Pre-Spawn and MonoBehaviour Methods](networkbehaviour.md#pre-spawn-and-monobehaviour-methods) section.
### Spawn process & invocation order

If you are familiar with the [event function execution order](https://docs.unity3d.com/6000.0/Documentation/Manual/execution-order.html) and/or the [script execution order](https://docs.unity3d.com/6000.0/Documentation/Manual/script-execution-order.html), then you already know that the execution order dictates the order of operations for your component scripts and you might have already had to adjust execution order of one component relative to another because your component scripts' order of operations required it. If you are not familiar with event function or script execution order, then it is recommended to read/review over the above two links.

When you make the decision to add a multiplayer element to your project, you will inevitably end up adding netcode scripts. Netcode scripts add an additional dimension to the over-all order of operations and script execution order that you need to consider prior to designing any complex netcode system comprised of several netcode scripts.

`NetworkBehaviour` includes several virtual methods that are invoked at different spawn stages of a `NetworkObject` as seen in the diagram below:

![NetwrokBehaviour Spawn Process & Method Invocation Order](../../images/NetworkBehaviour/NetworkBehaviourSpawnOrder.png)

After having looked over the diagram above, we can see that "NetworkBehaviour1" always invokes its methods before "NetworkBehaviour2". The order of `NetworkBehaviour` components is determined by their placement/position, within the inspector view of the editor, relative to the `NetworkObject`. So, it would be safe to assume that "NetworkBehaviour1" was placed somewhere above "NetworkBehaviour2". Looking at the above diagram, we can also determine that a `NetworkObject` goes through three states during the spawn process:

**Spawn states**
- Pre-Spawning: Before any netcode relative property has been set.
- Spawning: Netcode properties have been set.
- Spawned: All `NetworkBehaviour` components have run through their spawn logic.

For each spawn state there is a corresponding `NetworkBehaviour` virtual method:

**Spawn state related methods**
- Pre-Spawning --> `NetworkBehaviour.OnNetworkPreSpawn`.
- Spawning --> `NetworkBehaviour.OnNetworkSpawn`
- Spawned --> `NetworkBehaviour.OnNetworkPostSpawn`

If you read over the above diagram's notes to the right, you would notice that it provides additional information about what kind of script logic might be pertinent for each specific spawn state. The general rules of thumb for each spawn state method:

- `NetworkBehaviour.OnNetworkPreSpawn`: Used for any post serialization configuration needs that has no dependencies on any of the netcode properties. As an example, you wouldn't know the execution context since `NetworkBehaviour.IsServer` and `NetworkBehaviour.IsClient` have yet to be set (along with any other netcode related property). This is why a reference to the `NetworkManager` is passed into this virtual method.

- `NetworkBehaviour.OnNetworkSpawn`: Used to handle any `NetworkBehaviour` relative configurations based off if any serialized states that might have been passed in (or the like). Since we know each `NetworkBehaviour` component's `OnNetworkSpawn` method has a distinct order of operations relative to the other `NetworkBehaviour` components, we can look at the above diagram and come to the conclusion that trying to access some field/property of "NetworkBehavior2", if configured/set in the `OnNetworkSpawn` method, during the invocation of the `OnNetworkSpawn` method of "NetworkBehaviour1" would lead to an order of operations issue since "NetworkBehaviour2" configures the field/property during its `OnNetworkSpawn` method.

- `NetworkBehaviour.OnNetworkPostSpawn`: Any script logic added here can assume that all fields/properties configured during `OnNetworkSpawn` has completed. Accessing any field/property of "NetworkBehavior2" within `OnNetworkPostSpawn` script in "NetworkBehaviour1" would pose no order of operations issues since we know that "NetworkBehavior2" had already set those values during `OnNetworkSpawn`.


*For more information about NetworkBehaviour methods and when they are invoked, see the [Pre-Spawn and MonoBehaviour Methods](networkbehaviour.md#pre-spawn-and-monobehaviour-methods) section.*

### Disabling NetworkBehaviours when spawning

Expand All @@ -43,6 +76,34 @@ Dynamically spawned | In-scene placed (disabled NetworkBehaviour components)
> If you have child GameObjects that are not active in the hierarchy but are nested under an active GameObject with an attached NetworkObject component, then the inactive child GameObjects will not be included when the NetworkObject is spawned. This applies for the duration of the NetworkObject's spawned lifetime. If you want all child NetworkBehaviour components to be included in the spawn process, then make sure their respective GameObjects are active in the hierarchy before spawning the NetworkObject. Alternatively, you can just disable the NetworkBehaviour component(s) individually while leaving their associated GameObject active.
> It's recommended to disable a NetworkBehaviour component rather than the GameObject itself.

### Pre-spawn and MonoBehaviour methods

Since NetworkBehaviour is derived from MonoBehaviour, the `NetworkBehaviour.OnNetworkSpawn` method is treated similar to the `Awake`, `Start`, `FixedUpdate`, `Update`, and `LateUpdate` MonoBehaviour methods. Different methods are invoked depending on whether the GameObject is active in the hierarchy.

- When active: `Awake`, `Start`, `FixedUpdate`, `Update`, and `LateUpdate` are invoked.
- When not active: `Awake`, `Start`, `FixedUpdate`, `Update`, and `LateUpdate` are not invoked.

For more information about execution order, refer to [Order of execution for event functions](https://docs.unity3d.com/Manual/ExecutionOrder.html) in the main Unity Manual.

The unique behavior of `OnNetworkSpawn`, compared to the previously listed methods, is that it's not invoked until the associated GameObject is active in the hierarchy and its associated NetworkObject is spawned.

Additionally, the `FixedUpdate`, `Update`, and `LateUpdate` methods, if defined and the GameObject is active in the hierarchy, will still be invoked on NetworkBehaviours even when they're not yet spawned. If you want portions or all of your update methods to only execute when the associated NetworkObject component is spawned, you can use the `NetworkBehaviour.IsSpawned` flag to determine the spawned status like the below example:

```csharp
private void Update()
{
// If the NetworkObject is not yet spawned, exit early.
if (!IsSpawned)
{
return;
}
// Netcode specific logic executed when spawned.
}
```

Alternately, you could leverage from the [NetworkUpdateLoop](../../advanced-topics/network-update-loop-system/index.md) system by making a NetworkBehaviour implement the `INetworkUpdateSystem` interface and register each instance for a specific `NetworkUpdateStage` during the `OnNetworkSpawn` or `OnNetworkPreSpawn` invocations and then use your own script logic to determine which instance should be updating.

_This can be useful when you want only the owner, authority, or non-authority to be updating and can help to remove checks like the above. It can also reduce the performance cost of all instances that do not register for the update stage (depending upon how many instances are spawned)._

### Dynamically spawned NetworkObjects

Expand Down Expand Up @@ -79,49 +140,56 @@ public class MyNetworkBehaviour : NetworkBehaviour

For in-scene placed NetworkObjects, the `OnNetworkSpawn` method is invoked after the `Start` method, because the SceneManager scene loading process controls when NetworkObjects are instantiated. The previous code example shows how you can design a NetworkBehaviour that ensures both in-scene placed and dynamically spawned NetworkObjects will have assigned the required properties before attempting to access them. Of course, you can always make the decision to have in-scene placed `NetworkObjects` contain unique components to that of dynamically spawned `NetworkObjects`. It all depends upon what usage pattern works best for your project.

## Despawning
## De-spawning

When a NetworkObject is de-spawned, it will first iterate over and invoke `NetworkBehaviour.OnNetworkPreDespawn` and then `NetworkBehaviour.OnNetworkDespawn`for each of its assigned NetworkBehaviours.

`NetworkBehaviour.OnNetworkDespawn` is invoked on each NetworkBehaviour associated with a NetworkObject when it's despawned. This is where all netcode cleanup code should occur, but isn't to be confused with destroying ([see below](#destroying)). When a NetworkBehaviour component is destroyed, it means the associated GameObject, and all attached components, are in the middle of being destroyed. Regarding the order of operations, `NetworkBehaviour.OnNetworkDespawn` is always invoked before `NetworkBehaviour.OnDestroy`.
- `NetworkBehaviour.OnNetworkPreDespawn`: This is invoked by the associated `NetworkObject` instance at the very start of the de-spawn process. The associated `NetworkObject` is still considered "spawned" when `OnNetworkPreDespawn` is invoked.
- `NetworkBehaviour.OnNetworkDespawn`: This is invoked while the `NetworkObject` instance is in the middle of the de-spawn process. The associated `NetworkObject` should not be considered spawned and there is no guarantee that other `NetworkBehaviour` components associated with the `NetworkObject` have valid netcode related state ([see the "De-spawn process & invocation order" section for more information](#de-spawn-process--invocation-order)).

### Destroying
### De-spawning but not destroying

When de-spawned and not destroyed, the associated `GameObject` instance, and all children of that `GameObject`, will persist until it is destroyed. Under this scenario (_de-spawn but not destroy_), the would de-spawn but not destroy the `NetworkObject` instance with the intention of re-using/re-spawning the instance. In order to de-spawn and not destroy, you must invoke `NetworkObject.Despawn` while passing in `false` to not destroy the associated root `GameObject`.

### De-spawning and destroying

There are two scenarios where the object instance will be de-spawned and the GameObject destroyed:

- When invoking `NetworkObject.Despawn` and either not passing any parameters (_it defaults to destroy_) or passing in `true` for the `destroy` parameter.
- When invoking `GameObject.Destroy` on the `GameObject` that the `NetworkObject` component belongs to.
- _This will result in `NetworkObject.Despawn` to be invoked first (internally) and then `NetworkObject.OnDestroy`_ is invoked after that.

Each NetworkBehaviour has a virtual `OnDestroy` method that can be overridden to handle clean up that needs to occur when you know the NetworkBehaviour is being destroyed.

If you override the virtual `OnDestroy` method it's important to always invoke the base like such:
_NetworkBehaviour handles other internal destroy related clean up tasks and requires that you invoke the base `OnDestroy` method to operate properly._

If you override the virtual `OnDestroy` method it's important to always invoke the base `OnDestroy` method at the end of your script like such:

```csharp
public override void OnDestroy()
{
// Clean up your NetworkBehaviour
// Local NetworkBehaviour clean up script here:

// Always invoked the base
// Invoke the base after local NetworkBehaviour clean up script (last).
base.OnDestroy();
}
```

NetworkBehaviour handles other destroy clean up tasks and requires that you invoke the base `OnDestroy` method to operate properly.

## Pre-spawn and MonoBehaviour methods

Since NetworkBehaviour is derived from MonoBehaviour, the `NetworkBehaviour.OnNetworkSpawn` method is treated similar to the `Awake`, `Start`, `FixedUpdate`, `Update`, and `LateUpdate` MonoBehaviour methods. Different methods are invoked depending on whether the GameObject is active in the hierarchy.
> [!NOTE] Destroying the GameObject
> When destroying a NetworkObject from within an associated `NetworkBehaviour` component script, you always want to destroy the `NetworkObject.gameObject` and not the `NetworkBehaviour.gameObject` in the event the NetworkBehaviour is located on a child GameObject nested under the NetworkObject's GameObject.

- When active: `Awake`, `Start`, `FixedUpdate`, `Update`, and `LateUpdate` are invoked.
- When not active: `Awake`, `Start`, `FixedUpdate`, `Update`, and `LateUpdate` are not invoked.
### De-spawn process & invocation order

For more information about execution order, refer to [Order of execution for event functions](https://docs.unity3d.com/Manual/ExecutionOrder.html) in the main Unity Manual.
![NetwrokBehaviour Spawn Process & Method Invocation Order](../../images/NetworkBehaviour/NetworkBehaviourDeSpawnOrder.png)

The unique behavior of `OnNetworkSpawn`, compared to the previously listed methods, is that it's not invoked until the associated GameObject is active in the hierarchy and its associated NetworkObject is spawned.
Similar to the [spawn process & invocation order section above](#spawn-process--invocation-order), the NetworkBehaviour breaks up the de-spawn process into three states:

Additionally, the `FixedUpdate`, `Update`, and `LateUpdate` methods, if defined and the GameObject is active in the hierarchy, will still be invoked on NetworkBehaviours even when they're not yet spawned. If you want portions or all of your update methods to only execute when the associated NetworkObject component is spawned, you can use the `NetworkBehaviour.IsSpawned` flag to determine the spawned status like the below example:
**De-spawn states**
- Spawned: This state exists on the frame that the `NetworkObject` is being de-spawned, but before any internal de-spawn script has been invoked. The de-spawn is inevitable but the NetworkObject and all `NetworkBehaviour` components have their netcode related states intact.
- De-spawning: The `NetworkObject` has begun the de-spawn process. `NetworkBehaviour` components might have reset or disposed of certain fields and/or properties. Upon the last `NetworkBehaviour` component having invoked its `OnNetworkDespawn` method, the `NetworkObject` is considered de-spawned. If the `NetworkObject` was de-spawned but not destroyed then the instance would persist and if de-spawned to destroy then the `GameObject` instance and all components would be destroyed.
- De-spawned: The `NetworkObject` has finished the de-spawn process. `NetworkBehaviour` components might have reset or disposed of certain fields and/or properties. Local instance can be re-spawned if de-spawn was not while it was being destroyed.

```csharp
private void Update()
{
// If the NetworkObject is not yet spawned, exit early.
if (!IsSpawned)
{
return;
}
// Netcode specific logic executed when spawned.
}
```
**De-spawn state related methods**
- Spawned --> `NetworkBehaviour.OnNetworkPreDespawn`.
- De-spawning --> `NetworkBehaviour.OnNetworkDespawn`
- De-spawned --> *No state related method*
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.