-
Notifications
You must be signed in to change notification settings - Fork 462
chore: Add NetworkObject ownership docs and update related docs #3879
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
base: develop-2.0.0
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,164 @@ | ||
| # NetworkObject ownership | ||
|
|
||
| Before reading these docs, familiarize yourself with the concepts of [ownership](../terms-concepts/ownership.md) and [authority](../terms-concepts/authority.md) within Netcode for GameObjects. It's also recommended to read the documentation on the [NetworkObject](../components/core/networkobject.md). | ||
|
|
||
| To see if the local client is the owner of a NetworkObject, you can check the[`NetworkObject.IsOwner`](https://docs.unity3d.com/Packages/com.unity.netcode.gameobjects@latest?subfolder=/api/Unity.Netcode.NetworkObject.IsOwner.html) or the [`NetworkBehaviour.IsOwner`](https://docs.unity3d.com/Packages/com.unity.netcode.gameobjects@latest?subfolder=/api/Unity.Netcode.NetworkBehaviour.IsOwner.html) property. | ||
|
|
||
| To see if the server owns a NetworkObject, you can check the [`NetworkObject.IsOwnedByServer`](https://docs.unity3d.com/Packages/com.unity.netcode.gameobjects@latest?subfolder=/api/Unity.Netcode.NetworkObject.IsOwnedByServer.html) or the [`NetworkBehaviour.IsOwnedByServer`](https://docs.unity3d.com/Packages/com.unity.netcode.gameobjects@latest?subfolder=/api/Unity.Netcode.NetworkBehaviour.IsOwnedByServer.html) property. | ||
|
|
||
| > [!NOTE] | ||
| > When you want a specific NetworkObject to keep existing after the owner leaves the session, you can set the `NetworkObject.DontDestroyWithOwner` property to `true`. This ensures that the owned NetworkObject isn't destroyed as the owner leaves. | ||
|
|
||
| ## Authority ownership | ||
|
|
||
| If you're creating a client-server game and you want a client to control more than one NetworkObject, or if you're creating a distributed authority game and the authority/current owner of the object would like to change ownership, use the following ownership methods. | ||
|
Comment on lines
+12
to
+14
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ownership vs authorityThe client-server and distributed authority network topologies have slight differences when it comes to ownership and authority.
The following methods change their behavior based on the network topology being used: |
||
|
|
||
| The default `NetworkObject.Spawn` method will set server-side ownership when using a client-server topology. When using a distributed authority topology, this method will set the client who calls the method as the owner. | ||
|
|
||
| ```csharp | ||
| GetComponent<NetworkObject>().Spawn(); | ||
| ``` | ||
|
Comment on lines
+16
to
+20
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. NetworkObject.Spawn
|
||
|
|
||
| To change ownership, the authority uses the `ChangeOwnership` method: | ||
|
|
||
| ```csharp | ||
| GetComponent<NetworkObject>().ChangeOwnership(clientId); | ||
EmandM marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| ``` | ||
|
|
||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. NetworkObject.SpawnWithOwnership
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I moved SpawnWithOwnership to the bottom of the page. That way ChangeOwnership has a higher prominence than SpawnWithOwnership, hopefully leading to fewer SpawnAuthority issues. |
||
| ## Client-server ownership | ||
|
|
||
| In a client-server game, to give ownership back to the server use the `RemoveOwnership` method: | ||
|
|
||
| ```csharp | ||
| GetComponent<NetworkObject>().RemoveOwnership(); | ||
| ``` | ||
|
|
||
| > [!NOTE] | ||
| > `RemoveOwnership` isn't supported when using a [distributed authority network topology](../../terms-concepts/distributed-authority.md). | ||
|
|
||
| ## Distributed authority ownership | ||
|
|
||
| When building a distributed authority game, it is important to remember that owner of an object is always the authority for that object. As the simulation is shared between clients, it is important that ownership can be easily passed between game clients. This enables: | ||
|
|
||
| 1. Evenly sharing the load of the game simulation via redistributing objects whenever a player joins or leaves. | ||
| 2. Allowing ownership to be transferred immediately to a client in situations where a client is interacting with that object and so wants to remove lag from those interactions. | ||
| 3. Controlling when and object is safe and/or valid to be transferred. | ||
|
|
||
| The authority of any object can always change ownership as outlined in [authority ownership](#authority-ownership). | ||
|
|
||
| ### Ownership permissions settings | ||
|
|
||
| The following ownership permission settings, defined by [`NetworkObject.OwnershipStatus`](https://docs.unity3d.com/Packages/com.unity.netcode.gameobjects@latest?subfolder=/api/Unity.Netcode.NetworkObject.OwnershipStatus.html), control how ownership of objects can be changed during a distributed authority session: | ||
|
|
||
| | **Ownership setting** | **Description** | | ||
| |-------------------|-------------| | ||
| | `None` | Ownership of this NetworkObject can't be redistributed, requested, or transferred (a Player might have this, for example). | | ||
| | `Distributable` | Ownership of this NetworkObject is automatically redistributed when a client joins or leaves, as long as ownership is not locked or a request is pending. | | ||
| | `Transferable` | Any client can change ownership of this NetworkObject at any time, as long as ownership is not locked or a request is pending. | | ||
| | `RequestRequired` | Ownership of this NetworkObject must be requested before ownership can be changed. | | ||
| | `SessionOwner` | This NetworkObject is always owned by the [session owner](distributed-authority.md#session-ownership) and can't be transferred or distributed. If the session owner changes, this NetworkObject is automatically transferred to the new session owner. | | ||
|
|
||
| You can also use `NetworkObject.SetOwnershipLock` to lock and unlock the permission settings of a NetworkObject for a period of time, preventing ownership changes on a temporary basis. | ||
|
|
||
| ```csharp | ||
| // To lock an object from any ownership changes | ||
| GetComponent<NetworkObject>().SetOwnershipLock(true); | ||
EmandM marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| // To unlock an object so that the underlying ownership permissions apply again | ||
| GetComponent<NetworkObject>().SetOwnershipLock(false); | ||
EmandM marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| ``` | ||
|
|
||
| ### Changing ownership in distributed authority | ||
|
|
||
| When a NetworkObject is set with `OwnershipPermissions.Transferable` any client can change ownership to any other client using the `ChangeOwnership` method: | ||
|
|
||
| ```csharp | ||
| GetComponent<NetworkObject>().ChangeOwnership(clientId); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. NetworkObject.ChangeOwnership(clientId); |
||
|
|
||
| // To change ownership to self | ||
| GetComponent<NetworkObject>().ChangeOwnership(NetworkManager.Singleton.LocalClientId); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. NetworkObject.ChangeOwnership(NetworkManager.LocalClientId); |
||
| ``` | ||
|
|
||
| When a non-authoritative game client calls `ChangeOwnership`, the ownership change can fail. On a failed attempt to change ownership, the `OnOwnershipPermissionsFailure` callback will be invoked with a [`NetworkObject.OwnershipPermissionsFailureStatus`](https://docs.unity3d.com/Packages/com.unity.netcode.gameobjects@latest?subfolder=/api/Unity.Netcode.NetworkObject.OwnershipPermissionsFailureStatus.html) to give information on the failure. | ||
|
|
||
| ```csharp | ||
| internal class MyTransferrableBehaviour : NetworkBehaviour | ||
| { | ||
| public override void OnNetworkSpawn() | ||
| { | ||
| NetworkObject.OnOwnershipPermissionsFailure = OnOwnershipPermissionsFailure; | ||
| base.OnNetworkSpawn(); | ||
| } | ||
|
|
||
| private void OnOwnershipPermissionsFailure(NetworkObject.OwnershipPermissionsFailureStatus ownershipPermissionsFailureStatus) | ||
| { | ||
| // Called on the calling client when NetworkObject.ChangeOwnership() has failed | ||
| } | ||
|
|
||
| public override void OnNetworkDespawn() | ||
| { | ||
| NetworkObject.OnOwnershipPermissionsFailure = null; | ||
| base.OnNetworkDespawn(); | ||
| } | ||
| } | ||
|
Comment on lines
+85
to
+103
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. public class ChangeOwnershipBehaviour : NetworkBehaviour }
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Are we sure we want all this detailed code here? Maybe it'd be more useful to have the most simple example here and a more fully featured "putting it all together" section at the end? |
||
| ``` | ||
|
|
||
| ### Requesting ownership in distributed authority | ||
|
|
||
| When a NetworkObject is set with `OwnershipPermissions.RequestRequired` any client can request the ownership for themselves using the `RequestOwnership` method: | ||
|
|
||
| ```csharp | ||
| var requestStatus = GetComponent<NetworkObject>().RequestOwnership(); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. var requestStatus = NetworkObject.RequestOwnership(); |
||
| ``` | ||
|
|
||
| The `RequestOwnership` will return an [`OwnershipRequestStatus`](https://docs.unity3d.com/Packages/com.unity.netcode.gameobjects@latest?subfolder=/api/Unity.Netcode.NetworkObject.OwnershipRequestStatus.html) to indicate the initial status of the request. To view the result of the request, `OnOwnershipRequestResponse` callback will be invoked with a [`NetworkObject.OwnershipRequestResponseStatus`](https://docs.unity3d.com/Packages/com.unity.netcode.gameobjects@latest?subfolder=/api/Unity.Netcode.NetworkObject.OwnershipRequestResponseStatus.html). | ||
|
|
||
| ```csharp | ||
| internal class MyRequestableBehaviour : NetworkBehaviour | ||
| { | ||
| public override void OnNetworkSpawn() | ||
| { | ||
| NetworkObject.OnOwnershipRequestResponse = OnOwnershipRequestResponse; | ||
| base.OnNetworkSpawn(); | ||
| } | ||
|
|
||
| private void OnOwnershipRequestResponse(NetworkObject.OwnershipRequestResponseStatus ownershipRequestResponseStatus) | ||
| { | ||
| // Called when the requesting client has gotten a response to their request | ||
| } | ||
|
|
||
| public override void OnNetworkDespawn() | ||
| { | ||
| NetworkObject.OnOwnershipRequestResponse = null; | ||
| base.OnNetworkDespawn(); | ||
| } | ||
| } | ||
|
Comment on lines
+117
to
+135
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ///
|
||
| ``` | ||
|
|
||
| ## Spawn with ownership | ||
|
|
||
| To spawn a `NetworkObject` that is [owned](../../terms-concepts/ownership.md) by a different game client than the one doing the spawning, use the following: | ||
|
|
||
| ```csharp | ||
| GetComponent<NetworkObject>().SpawnWithOwnership(clientId); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. NetworkObject.SpawnWithOwnership(clientId); |
||
| ``` | ||
|
|
||
| > [!NOTE] | ||
| > Using `SpawnWithOwnership` can result in unexpected behaviour when the spawning game client makes any other changes on the object immediately after spawning. | ||
|
|
||
| Using `SpawnWithOwnership` and then editing the object locally will mean the client doing the spawning will behave as the "spawn authority". The spawn authority will have limited local [authority](../terms-concepts/authority.md) over the object, but will not have [ownership](../terms-concepts/ownership.md) of the object that is spawned. This means any owner-specific checks during the spawn sequence will not be invoked on the spawn authority side. | ||
|
|
||
| Any time you would like to spawn an object for another client and then immediately make adjustments on that object, it's instead recommended to use `Spawn`. After adjusting, the spawn authority can immediately follow with a call to `ChangeOwnership`. | ||
|
|
||
| ```csharp | ||
| [Rpc(SendTo.Authority)] | ||
| void SpawnForRequestingPlayer(RpcParams rpcParams = default) { | ||
| var instance = Instantiate(myprefab).GetComponent<NetworkObject>(); | ||
| instance.Spawn(); | ||
| instance.transform.position = transform.position; | ||
| instance.GetComponent<MyNetworkBehaviour>.MyNetworkVar.Value = initialValue; | ||
| instance.ChangeOwnership(rpcParams.Receive.SenderClientId) | ||
| } | ||
| ``` | ||
|
|
||
| This flow allows the spawning client to completely spawn and finish initializing the object locally before transferring the ownership to another game client. | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,15 +1,15 @@ | ||
| # NetworkObject parenting | ||
|
|
||
| ### Overview | ||
| ## Overview | ||
|
|
||
| If you aren't completely familiar with transform parenting in Unity, then it's highly recommended to [review over the existing Unity documentation](https://docs.unity3d.com/Manual/class-Transform.html) before reading further to properly synchronize all connected clients with any change in a GameObject component's transform parented status, Netcode for GameObjects requires that the parent and child GameObject components have NetworkObject components attached to them. | ||
| If you aren't completely familiar with transform parenting in Unity, then it's highly recommended to [review over the existing Unity documentation](https://docs.unity3d.com/Manual/class-Transform.html) before reading further. To properly synchronize all connected clients with any change in a GameObject component's transform parented status, Netcode for GameObjects requires that the parent and child GameObject components have NetworkObject components attached to them. Otherwise, you can use the [AttachableBehaviour](../components/helper/attachablebehaviour.md) and [AttachableNode](../components/helper/attachablenode.md) helper components to synchronize other types of parenting. | ||
|
|
||
| ### Parenting rules | ||
| ## Parenting rules | ||
|
|
||
| - Setting the parent of a child's `Transform` directly (that is, `transform.parent = childTransform;`) always uses the default `WorldPositionStays` value of `true`. | ||
| - It's recommended to always use the `NetworkObject.TrySetParent` method when parenting if you plan on changing the `WorldPositionStays` default value. | ||
| - Likewise, it's also recommended to use the `NetworkObject.TryRemoveParent` method to remove a parent from a child. | ||
| - When a server parents a spawned NetworkObject component under another spawned NetworkObject component during a Netcode game session this parent child relationship replicates across the network to all connected and future late joining clients. | ||
| - When an [authority](../terms-concepts/authority.md) parents a spawned NetworkObject component under another spawned NetworkObject component during a Netcode game session this parent child relationship replicates across the network to all connected and future late joining clients. | ||
| - If, while editing a scene, you place an in-scene placed NetworkObject component under a GameObject component that doesn't have a NetworkObject component attached to it, Netcode for GameObjects preserves that parenting relationship. | ||
| - During runtime, this parent-child hierarchy remains true unless the user code removes the GameObject parent from the child NetworkObject component. | ||
| - **Note**: Once removed, Netcode for GameObjects won't allow you to re-parent the NetworkObject component back under the same or another GameObject component that with no NetworkObject component attached to it. | ||
|
|
@@ -38,12 +38,16 @@ virtual void OnNetworkObjectParentChanged(NetworkObject parentNetworkObject) { } | |
| > [!NOTE] Multi-generation children and scale | ||
| > If you are dealing with more than one generation of nested children where each parent and child have scale values other than `Vector3.one`, then mixing the `WorldPositionStays` value when parenting and removing a parent will impact how the final scale is calculated! If you want to keep the same values before parenting when removing a parent from a child, then you need to use the same `WorldPositionStays` value used when the child was parented. | ||
|
|
||
| ### Only a server (or a host) can parent NetworkObjects | ||
| ### Who can parent NetworkObjects | ||
|
|
||
| Similar to [Ownership](../basics/networkobject#ownership), only the server (or host) can control NetworkObject component parenting. | ||
| By default, only the [authority](../terms-concepts/authority.md) of an object can change the parenting of the object. This means in a client-server game, only the server (or host) can control NetworkObject component parenting. In a distributed authority game the owner of the object can always parent the object. | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. owner of the object can always parent the object under any other spawned NetworkObject (owned or not). |
||
|
|
||
| To allow the [owner](../terms-concepts/ownership.md) to parent their owned object in a client-server game, use the [`NetworkObject.AllowOwnerToParent`](https://docs.unity3d.com/Packages/com.unity.netcode.gameobjects@latest?subfolder=/api/Unity.Netcode.NetworkObject.html#Unity_Netcode_NetworkObject_AllowOwnerToParent) property. | ||
|
|
||
|  | ||
|
|
||
| > [!NOTE] | ||
| > If you run into a situation where your client must trigger parenting a NetworkObject component, one solution is for the client to send an RPC to the server. Upon receiving the RPC message, the server then handles parenting the NetworkObject component. | ||
| > If you run into a situation where your client must trigger parenting a NetworkObject component, one solution is for the client to send an RPC to the authority. Upon receiving the RPC message, the authority then handles parenting the NetworkObject component. | ||
|
|
||
| ### Only parent under a NetworkObject Or nothing (root or null) | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here are some suggested adjustments:
To assure a spawned NetworkObject persists after the owner leaves a session, set the
NetworkObject.DontDestroyWithOwnerproperty totrue. This assures the client-owned NetworkObject doesn't get destroyed when the owning client leaves.