|
| 1 | +# NetworkObject ownership |
| 2 | + |
| 3 | +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). |
| 4 | + |
| 5 | +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. |
| 6 | + |
| 7 | +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. |
| 8 | + |
| 9 | +> [!NOTE] |
| 10 | +> 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. |
| 11 | +
|
| 12 | +## Authority ownership |
| 13 | + |
| 14 | +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. |
| 15 | + |
| 16 | +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. |
| 17 | + |
| 18 | +```csharp |
| 19 | +GetComponent<NetworkObject>().Spawn(); |
| 20 | +``` |
| 21 | + |
| 22 | +To change ownership, the authority uses the `ChangeOwnership` method: |
| 23 | + |
| 24 | +```csharp |
| 25 | +GetComponent<NetworkObject>().ChangeOwnership(clientId); |
| 26 | +``` |
| 27 | + |
| 28 | +## Client-server ownership |
| 29 | + |
| 30 | +In a client-server game, to give ownership back to the server use the `RemoveOwnership` method: |
| 31 | + |
| 32 | +```csharp |
| 33 | +GetComponent<NetworkObject>().RemoveOwnership(); |
| 34 | +``` |
| 35 | + |
| 36 | +> [!NOTE] |
| 37 | +> `RemoveOwnership` isn't supported when using a [distributed authority network topology](../../terms-concepts/distributed-authority.md). |
| 38 | +
|
| 39 | +## Distributed authority ownership |
| 40 | + |
| 41 | +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: |
| 42 | + |
| 43 | +1. Evenly sharing the load of the game simulation via redistributing objects whenever a player joins or leaves. |
| 44 | +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. |
| 45 | +3. Controlling when and object is safe and/or valid to be transferred. |
| 46 | + |
| 47 | +The authority of any object can always change ownership as outlined in [authority ownership](#authority-ownership). |
| 48 | + |
| 49 | +### Ownership permissions settings |
| 50 | + |
| 51 | +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: |
| 52 | + |
| 53 | +| **Ownership setting** | **Description** | |
| 54 | +|-------------------|-------------| |
| 55 | +| `None` | Ownership of this NetworkObject can't be redistributed, requested, or transferred (a Player might have this, for example). | |
| 56 | +| `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. | |
| 57 | +| `Transferable` | Any client can change ownership of this NetworkObject at any time, as long as ownership is not locked or a request is pending. | |
| 58 | +| `RequestRequired` | Ownership of this NetworkObject must be requested before ownership can be changed. | |
| 59 | +| `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. | |
| 60 | + |
| 61 | +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. |
| 62 | + |
| 63 | +```csharp |
| 64 | +// To lock an object from any ownership changes |
| 65 | +GetComponent<NetworkObject>().SetOwnershipLock(true); |
| 66 | + |
| 67 | +// To unlock an object so that the underlying ownership permissions apply again |
| 68 | +GetComponent<NetworkObject>().SetOwnershipLock(false); |
| 69 | +``` |
| 70 | + |
| 71 | +### Changing ownership in distributed authority |
| 72 | + |
| 73 | +When a NetworkObject is set with `OwnershipPermissions.Transferable` any client can change ownership to any other client using the `ChangeOwnership` method: |
| 74 | + |
| 75 | +```csharp |
| 76 | +GetComponent<NetworkObject>().ChangeOwnership(clientId); |
| 77 | + |
| 78 | +// To change ownership to self |
| 79 | +GetComponent<NetworkObject>().ChangeOwnership(NetworkManager.Singleton.LocalClientId); |
| 80 | +``` |
| 81 | + |
| 82 | +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. |
| 83 | + |
| 84 | +```csharp |
| 85 | +internal class MyTransferrableBehaviour : NetworkBehaviour |
| 86 | +{ |
| 87 | + public override void OnNetworkSpawn() |
| 88 | + { |
| 89 | + NetworkObject.OnOwnershipPermissionsFailure = OnOwnershipPermissionsFailure; |
| 90 | + base.OnNetworkSpawn(); |
| 91 | + } |
| 92 | + |
| 93 | + private void OnOwnershipPermissionsFailure(NetworkObject.OwnershipPermissionsFailureStatus ownershipPermissionsFailureStatus) |
| 94 | + { |
| 95 | + // Called on the calling client when NetworkObject.ChangeOwnership() has failed |
| 96 | + } |
| 97 | + |
| 98 | + public override void OnNetworkDespawn() |
| 99 | + { |
| 100 | + NetworkObject.OnOwnershipPermissionsFailure = null; |
| 101 | + base.OnNetworkDespawn(); |
| 102 | + } |
| 103 | +} |
| 104 | +``` |
| 105 | + |
| 106 | +### Requesting ownership in distributed authority |
| 107 | + |
| 108 | +When a NetworkObject is set with `OwnershipPermissions.RequestRequired` any client can request the ownership for themselves using the `RequestOwnership` method: |
| 109 | + |
| 110 | +```csharp |
| 111 | +var requestStatus = GetComponent<NetworkObject>().RequestOwnership(); |
| 112 | +``` |
| 113 | + |
| 114 | +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). |
| 115 | + |
| 116 | +```csharp |
| 117 | +internal class MyRequestableBehaviour : NetworkBehaviour |
| 118 | +{ |
| 119 | + public override void OnNetworkSpawn() |
| 120 | + { |
| 121 | + NetworkObject.OnOwnershipRequestResponse = OnOwnershipRequestResponse; |
| 122 | + base.OnNetworkSpawn(); |
| 123 | + } |
| 124 | + |
| 125 | + private void OnOwnershipRequestResponse(NetworkObject.OwnershipRequestResponseStatus ownershipRequestResponseStatus) |
| 126 | + { |
| 127 | + // Called when the requesting client has gotten a response to their request |
| 128 | + } |
| 129 | + |
| 130 | + public override void OnNetworkDespawn() |
| 131 | + { |
| 132 | + NetworkObject.OnOwnershipRequestResponse = null; |
| 133 | + base.OnNetworkDespawn(); |
| 134 | + } |
| 135 | +} |
| 136 | +``` |
| 137 | + |
| 138 | +## Spawn with ownership |
| 139 | + |
| 140 | +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: |
| 141 | + |
| 142 | +```csharp |
| 143 | +GetComponent<NetworkObject>().SpawnWithOwnership(clientId); |
| 144 | +``` |
| 145 | + |
| 146 | +> [!NOTE] |
| 147 | +> Using `SpawnWithOwnership` can result in unexpected behaviour when the spawning game client makes any other changes on the object immediately after spawning. |
| 148 | +
|
| 149 | +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. |
| 150 | + |
| 151 | +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`. |
| 152 | + |
| 153 | +```csharp |
| 154 | +[Rpc(SendTo.Authority)] |
| 155 | +void SpawnForRequestingPlayer(RpcParams rpcParams = default) { |
| 156 | + var instance = Instantiate(myprefab).GetComponent<NetworkObject>(); |
| 157 | + instance.Spawn(); |
| 158 | + instance.transform.position = transform.position; |
| 159 | + instance.GetComponent<MyNetworkBehaviour>.MyNetworkVar.Value = initialValue; |
| 160 | + instance.ChangeOwnership(rpcParams.Receive.SenderClientId) |
| 161 | +} |
| 162 | +``` |
| 163 | + |
| 164 | +This flow allows the spawning client to completely spawn and finish initializing the object locally before transferring the ownership to another game client. |
0 commit comments