Hi,
I am trying to get the PlayerObject. It works in Server side, but in client side it returns null.
I have tried:
NetworkManager.Singleton.LocalClient.PlayerObject
NetworkManager.Singleton.SpawnManager.GetLocalPlayerObject()
with the same result.
I am using netcode for gameobjects 1.11.0
I’ve seen that this bug was reported years ago and seemed to be fixed, I don’t know if it has come back or maybe I should get the PlayerObject in other way
It supposed to be fixed here:
opened 09:27AM - 10 Mar 21 UTC
closed 02:37PM - 19 May 21 UTC
type:bug
good first issue
stat:backlog
**Describe the bug**
NetworkSpawnManager.GetLocalPlayerObject only works on hos… t. A client calling this function will always return null.
**To Reproduce**
Steps to reproduce the behavior:
1. Use a MLAPI project which uses player prefabs
2. Call NetworkSpawnManager.GetLocalPlayer as the client
**Expected behavior**
NetworkSpawnManager.GetLocalPlayer should give me my local player object as the client.
**Environment (please complete the following information):**
- MLAPI Version: release/0.1.0
**Additional context**
Code for GetLocalPlayerObject is:
```csharp
public static NetworkObject GetLocalPlayerObject()
{
if (!NetworkManager.Singleton.ConnectedClients.ContainsKey(NetworkManager.Singleton.LocalClientId)) return null;
return NetworkManager.Singleton.ConnectedClients[NetworkManager.Singleton.LocalClientId].PlayerObject;
}
```
But ConnectedClients as indicated by its XML doc is only populated on the server. I talked with Albin about this and one solution which we figured makes sense would be to polulate ConnectedClients with the own local client upon connection.
Other threads talking about the same
I haven’t been able to find anything about this that works for me, I was using
NetworkManager.Singleton.ConnectedClients.TryGetValue(NetworkManager.Singleton.LocalClientId, out var player
but it only works for the host.
Thank you
The issue may be down to when/where you’re trying to access it. If you subscribe to
NetworkManager.Singleton.OnClientConnectedCallback
it’s available on and after that call.
2 Likes
You are right, you can get the LocalClient.PlayerObject in the callback. I am not sure why is behaving differently in Server and Client, but it is.
This is the full code I’ve used to check the behaviour
using Unity.Netcode;
using UnityEngine;
public class LocalClientTest : NetworkBehaviour
{
public override void OnNetworkSpawn()
{
AssertNotNull(NetworkManager.Singleton.LocalClient.PlayerObject, "OnNetworkSpawn"); //Client => Null. Server => Not Null
AssertNotNull(NetworkManager.Singleton.SpawnManager.GetLocalPlayerObject(), "OnNetworkSpawn"); //Client => Null. Server => Not Null
}
protected override void OnNetworkPostSpawn()
{
AssertNotNull(NetworkManager.Singleton.LocalClient.PlayerObject, "OnNetworkPostSpawn");//Client => Null. Server => Not Null
AssertNotNull(NetworkManager.Singleton.SpawnManager.GetLocalPlayerObject(), "OnNetworkPostSpawn");//Client => Null. Server => Not Null
}
protected override void OnNetworkPreSpawn(ref NetworkManager networkManager)
{
AssertNotNull(NetworkManager.Singleton.LocalClient.PlayerObject, "OnNetworkPreSpawn"); //Client => Null. Server => Not Null
AssertNotNull(NetworkManager.Singleton.SpawnManager.GetLocalPlayerObject(), "OnNetworkPreSpawn"); //Client => Null. Server => Not Null
}
private void OnClientConnected(ulong obj)
{
AssertNotNull(NetworkManager.Singleton.LocalClient.PlayerObject, "OnClientConnected");//Client => Not Null. Server => Not Null
AssertNotNull(NetworkManager.Singleton.SpawnManager.GetLocalPlayerObject(), "OnClientConnected");//Client => Not Null. Server => Not Null
}
private void AssertNotNull(Object obj, string message)
{
string prefix = $"Is Server: {IsServer}";
if(obj != null)
{
Debug.Log($"{prefix} {message} is not null");
}
else
{
Debug.LogError($"{prefix} {message} is null");
}
}
private void Start() => AddNetworkManagerCallbacks();
public override void OnDestroy()
{
RemoveNetworkManagerCallbacks();
base.OnDestroy();
}
private void AddNetworkManagerCallbacks()
{
var netMan = NetworkManager.Singleton;
if (netMan != null)
{
// ensure we never register callbacks twice
RemoveNetworkManagerCallbacks();
netMan.OnClientConnectedCallback += OnClientConnected;
}
}
private void RemoveNetworkManagerCallbacks()
{
var netMan = NetworkManager.Singleton;
if (netMan != null)
{
netMan.OnClientConnectedCallback -= OnClientConnected;
}
}
}
Is LocalClientTest an in-scene object as there are timing differences between server and client. On the server Player is spawned before LocalClientTest, on the client it’s spawned afterwards (but the server’s Player is spawned before both). If you’re spawning objects yourself that order is maintained, or it was last time I checked. I don’t know where the Player and in-scene objects fit into this though.
This test was done with a in-scene object. It may be worth testing in a spawned prefab too.
I didn’t think that could be a different because the PlayerObject is your own PlayerObject, so I though that the PlayerObject instantiation would be the first in the execution order when the client connects to the server, no matter if you are host-client or simple-client