Best way to get all connected player objects on local client

Hello I’m trying to create something like a part HUD that shows the health of each other player. I want to get a reference to their player object so that I can have the UI watch their health value (which is a network variable).

The issue I am having is NetworkManager.Singleton.ConnectedClients can only be accessed from the server, but my UI component only runs on the client. I know I could just simply do FindAllObjectsofType<T> but I dont want to poll over that so I would rather have something event based. I found NetworkManager.Singleton. OnClientConnectedCallback but again that only runs on the server.

So what I really want is something where the server can notify the client that a player has connected or disconnected and pass along a reference to that player object.

2 Likes

Hello,
From what I have tried, OnClientConnectedCallback works also in the client.
Anyway, you could try making it so that every time a new cient joins, he calls a ServerRPC function that calls a ClientRPC function, and pass both function his player object refrence. Something like this:

    public override void OnNetworkSpawn()
    {
        base.OnNetworkSpawn();
        calltoclientconectedServerRPC(NetworkManager.Singleton.LocalClientId 
}


    [ServerRpc(RequireOwnership = false)]
    public void calltoclientconectedServerRPC(ulong id)
    {
        Gameobject playerObj = NetworkManager.Singleton.ConnectedClients[(int)id].PlayerObject
        ClientConnectedClientRPC(playerObj);
    }

    [ClientRpc]
    private void ClientConnectedClientRPC(GameObject player)
    {
        //deliver the object refrence to each client
    }
1 Like

I did something very similar, the only change I’d suggest is that the function argument for the ClientRpc cannot be a GameObject; it should be either a NetworkObjectReference or a NetworkBehaviourReference, that can then be cast into a GameObject client-side if needed.

Okay,
I do it in a lobby so it’s different. I didn’t even know NetworkObjectReference exist

1 Like

You could create a custom NetworkVariable that holds all the necessary information (List of clients plus their health reference). You use the OnClientConnectedCallback on the Server to fill this List (Like that all Clients will be in sync no matter if they spawn late). On the Client you read from that specific List.

I havent worked with the NetworkList yet, but that could also be an alternative.

1 Like

To give you another option, you can take advantage of the event callbacks provided with network objects. By default all player objects will spawn on all clients, so you can grab a reference to them in their OnNetworkSpawn event or just register them with the UI. You can also use the OnValueChanged event of a network variable to be informed when the health value changes.

Here’s a simple setup of the Player class:

public class Player : NetworkBehaviour
{
    NetworkVariable<uint> playerId = new NetworkVariable<uint>();
    NetworkVariable<int> health = new NetworkVariable<int>();

    public override void OnNetworkSpawn()
    {
        base.OnNetworkSpawn();

        health.OnValueChanged += OnChangeHealth;

        UiManager.Instance().AddPlayer(PlayerId);
    }

    private void OnChangeHealth(int oldHealth, int newHealth)
    {
        UiManager.Instance().UpdateHealth(PlayerId, newHealth);
    }

    public uint PlayerId { get => playerId.Value; set => playerId.Value = value; }
    public int Health { get => health.Value; set => health.Value = value; }
}

If you want to keep a permanent reference for each player you could create something like this:

public class PlayerManager : Singleton<PlayerManager>
{
    Dictionary<uint, Player> player;

    public Dictionary<uint, Player> Player { get => player; set => player = value; }
}

and add this to OnNetworkSpawn:

PlayerManager.Instance().Player.Add(PlayerId, this);
1 Like

how do i check how many number of players are connected

You can create a variable (playerCount) and each time a player joins, you do playerCount++ and each time a player leaves you substract. Use the event NetworkManager.Singleton.OnClientConnectedCallback and subscribe to it with ‘+=’. The other event is NetworkManager.Singleton.OnClientDisconnectCallback

This is my script. The player counter works fine

using System.Collections;
using System.Collections.Generic;
using Unity.Netcode;
using UnityEngine;

public class GameManager : NetworkBehaviour
{
    NetworkVariable<int> playerCount = new();
    public override void OnNetworkSpawn()
    {
        if (IsHost)
        {
            NetworkManager.Singleton.OnClientConnectedCallback += OnClientConnectedCallback;
            NetworkManager.Singleton.OnClientDisconnectCallback += OnClientDisconnectCallback;
        }
    }

    private void OnClientDisconnectCallback(ulong obj)
    {
        playerCount.Value--;
        UIManager.Instance.UpdatePlayerCount(playerCount.Value);
    }

    private void OnClientConnectedCallback(ulong obj)
    {
        playerCount.Value++;
        UIManager.Instance.UpdatePlayerCount(playerCount.Value);
    }
}

UIManager.Instance.UpdatePlayerCount() could be changed by a simple Debug.Log, it is just the function inside of another script wich changes some text on the screen.
This is my first answer, I hope it helps.

Edit: IsHost might not be the right property to use. I’m not really sure which one to use but it is just to be sure that only the server runs the script and not every client.

As I was making my game I saw a different way to do this. Also, I think this was discussed in a different thread but I dont have the link. This solution works perfectly for me:

int playerCount = NetworkManager.Singleton.ConnectedClientsList.Count;

dont need delivery. u can use this in clientrpc

NetworkManager.LocalClient.PlayerObject