|
| 1 | +--- |
| 2 | +id: playerobjects |
| 3 | +title: PlayerObjects and player prefabs |
| 4 | +--- |
| 5 | + |
| 6 | +PlayerObjects are an optional feature in Netcode for GameObjects that you can use to assign a [NetworkObject](networkobject.md) to a specific client. A client can only have one PlayerObject. |
| 7 | + |
| 8 | +PlayerObjects are instantiated by reference to a player prefab, which defines the characteristics of the PlayerObject. |
| 9 | + |
| 10 | +## Defining defaults for player prefabs |
| 11 | + |
| 12 | +If you're using `UnityEngine.InputSystem.PlayerInput` or `UnityEngine.PhysicsModule.CharacterController` components on your player prefab(s), you should disable them by default and only enable them for the local client's PlayerObject. Otherwise, you may get events from the most recently instantiated player prefab instance, even if it isn't the local client instance. |
| 13 | + |
| 14 | +You can disable these components in the **Inspector** view on the prefab itself, or disable them during `Awake` in one of your `NetworkBehaviour` components. Then you can enable the components only on the owner's instance using code like the example below: |
| 15 | + |
| 16 | +``` |
| 17 | +PlayerInput m_PlayerInput; |
| 18 | +private void Awake() |
| 19 | +{ |
| 20 | + m_PlayerInput = GetComponent<PlayerInput>(); |
| 21 | + m_PlayerInput.enabled = false; |
| 22 | +} |
| 23 | +
|
| 24 | +public override void OnNetworkSpawn() |
| 25 | +{ |
| 26 | + m_PlayerInput.enabled = IsOwner; |
| 27 | + base.OnNetworkSpawn(); |
| 28 | +} |
| 29 | +
|
| 30 | +public override void OnNetworkDespawn() |
| 31 | +{ |
| 32 | + m_PlayerInput.enabled = false; |
| 33 | + base.OnNetworkDespawn(); |
| 34 | +} |
| 35 | +``` |
| 36 | + |
| 37 | +## Spawning PlayerObjects |
| 38 | + |
| 39 | +## Session-mode agnostic methods |
| 40 | + |
| 41 | +Netcode for GameObjects can spawn a default PlayerObject for you. If you enable **Create Player Prefab** in the [NetworkManager](../components/networkmanager.md) and assign a valid prefab, then Netcode for GameObjects spawns a unique instance of the designated player prefab for each connected and approved client, referred to as the PlayerObject. |
| 42 | + |
| 43 | +To manually spawn an object as PlayerObject, use the following method: |
| 44 | + |
| 45 | +```csharp |
| 46 | +GetComponent<NetworkObject>().SpawnAsPlayerObject(clientId); |
| 47 | +``` |
| 48 | + |
| 49 | +If the player already had a prefab instance assigned, then the client owns the NetworkObject of that prefab instance unless there's additional server-side specific user code that removes or changes the ownership. |
| 50 | + |
| 51 | +Alternatively, you can choose not to spawn anything immediately after a client connects and instead use a [NetworkBehaviour component](networkbehaviour.md) to handle avatar/initial player prefab selection. This NetworkBehaviour component could be configured by the server or initiating session owner, or be associated with an [in-scene](scenemanagement/inscene-placed-networkobjects.md) or [dynamically spawned](object-spawning.md#dynamically-spawned-network-prefabs) NetworkObject, as suits the needs of your project. |
| 52 | + |
| 53 | +### Client-server contexts only |
| 54 | + |
| 55 | +In addition to the [session-mode agnostic spawning methods](#session-mode-agnostic-methods) above, you can assign a unique player prefab on a per-client connection basis using a client [connection approval process](connection-approval.md) when in [client-server contexts](../terms-concepts/client-server.md). |
| 56 | + |
| 57 | +### Distributed authority contexts only |
| 58 | + |
| 59 | +In addition to the [session-mode agnostic spawning methods](#session-mode-agnostic-methods) above, you can use the [`OnFetchLocalPlayerPrefabToSpawn`](https://docs.unity3d.com/Packages/com.unity.netcode.gameobjects@latest?subfolder=/api/Unity.Netcode.NetworkManager.html#Unity_Netcode_NetworkManager_OnFetchLocalPlayerPrefabToSpawn) method to assign a unique player prefab on a per-client basis when in [distributed authority contexts](../terms-concepts/distributed-authority.md). |
| 60 | + |
| 61 | +To use `OnFetchLocalPlayerPrefabToSpawn` in your project, assign a callback handler to `OnFetchLocalPlayerPrefabToSpawn` and whatever the client script returns is what will be spawned for that client. Ensure that the prefab being spawned is in a NetworkPrefabList [registered with the NetworkManager](object-spawning.md#registering-a-network-prefab). |
| 62 | + |
| 63 | +If you don't assign a callback handler to `OnFetchLocalPlayerPrefabToSpawn`, then the default behaviour is to return the `NetworkConfig.PlayerPrefab` (or null if neither are set). |
| 64 | + |
| 65 | +:::note `AutoSpawnPlayerPrefabClientSide` required |
| 66 | +For `OnFetchLocalPlayerPrefabToSpawn` to work, [`AutoSpawnPlayerPrefabClientSide`](https://docs.unity3d.com/Packages/com.unity.netcode.gameobjects@latest?subfolder=/api/Unity.Netcode.NetworkManager.html#Unity_Netcode_NetworkManager_AutoSpawnPlayerPrefabClientSide) must be enabled. |
| 67 | +::: |
| 68 | + |
| 69 | +## PlayerObject spawning timeline |
| 70 | + |
| 71 | +When using automatic methods of PlayerObject spawning (such as enabling **Create Player Prefab** in the [NetworkManager](../components/networkmanager.md)), PlayerObjects are spawned at different times depending on whether you have [scene management](scenemanagement/scene-management-overview.md) enabled. |
| 72 | + |
| 73 | +- When scene management is disabled, PlayerObjects are spawned when a joining client's connection is approved. |
| 74 | +- When scene management is enabled, PlayerObjects are spawned when a joining client finishes initial synchronization. |
| 75 | + |
| 76 | +If you choose not to automatically spawn a PlayerObject when a client joins, then the timing of when a PlayerObject is spawned is up to you based on your own implemented code. |
| 77 | + |
| 78 | +## Finding PlayerObjects |
| 79 | + |
| 80 | +To find a PlayerObject for a specific client ID, you can use the following methods: |
| 81 | + |
| 82 | +Within a NetworkBehaviour, you can check the local `NetworkManager.LocalClient` to get the local PlayerObjects: |
| 83 | + |
| 84 | +```csharp |
| 85 | +NetworkManager.LocalClient.PlayerObject |
| 86 | +``` |
| 87 | + |
| 88 | +Conversely, on the server-side, if you need to get the PlayerObject instance for a specific client, you can use the following: |
| 89 | + |
| 90 | +```csharp |
| 91 | +NetworkManager.Singleton.ConnectedClients[clientId].PlayerObject; |
| 92 | +``` |
| 93 | + |
| 94 | +To find your own player object just pass `NetworkManager.Singleton.LocalClientId` as the `clientId` in the sample above. |
| 95 | + |
| 96 | +## Additional resources |
| 97 | + |
| 98 | +- [NetworkObject](networkobject.md) |
| 99 | +- [NetworkManager](../components/networkmanager.md) |
| 100 | +- [Distributed authority topologies](../terms-concepts/distributed-authority.md) |
| 101 | +- [Client-server topologies](../terms-concepts/client-server.md) |
| 102 | +- [Object spawning](objectspawning.md) |
0 commit comments