Search Unity

Best way to get all connected player objects on local client

Discussion in 'Netcode for GameObjects' started by chris_webitzgames, Aug 31, 2022.

  1. chris_webitzgames

    chris_webitzgames

    Joined:
    Mar 9, 2021
    Posts:
    1
    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.
     
    Sekkizan and brainwipe like this.
  2. lavagoatGG

    lavagoatGG

    Joined:
    Apr 16, 2022
    Posts:
    229
    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:
    Code (CSharp):
    1.     public override void OnNetworkSpawn()
    2.     {
    3.         base.OnNetworkSpawn();
    4.         calltoclientconectedServerRPC(NetworkManager.Singleton.LocalClientId
    5. }
    6.  
    7.  
    8.     [ServerRpc(RequireOwnership = false)]
    9.     public void calltoclientconectedServerRPC(ulong id)
    10.     {
    11.         Gameobject playerObj = NetworkManager.Singleton.ConnectedClients[(int)id].PlayerObject
    12.         ClientConnectedClientRPC(playerObj);
    13.     }
    14.  
    15.     [ClientRpc]
    16.     private void ClientConnectedClientRPC(GameObject player)
    17.     {
    18.         //deliver the object refrence to each client
    19.     }
     
    Sekkizan likes this.
  3. CosmoM

    CosmoM

    Joined:
    Oct 31, 2015
    Posts:
    204
    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.
     
  4. lavagoatGG

    lavagoatGG

    Joined:
    Apr 16, 2022
    Posts:
    229
    Okay,
    I do it in a lobby so it's different. I didn't even know NetworkObjectReference exist
     
    Sekkizan likes this.
  5. itisMarcii_

    itisMarcii_

    Joined:
    Apr 5, 2022
    Posts:
    111
    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.
     
    lavagoatGG likes this.
  6. cerestorm

    cerestorm

    Joined:
    Apr 16, 2020
    Posts:
    664
    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:
    Code (CSharp):
    1. public class Player : NetworkBehaviour
    2. {
    3.     NetworkVariable<uint> playerId = new NetworkVariable<uint>();
    4.     NetworkVariable<int> health = new NetworkVariable<int>();
    5.  
    6.     public override void OnNetworkSpawn()
    7.     {
    8.         base.OnNetworkSpawn();
    9.  
    10.         health.OnValueChanged += OnChangeHealth;
    11.  
    12.         UiManager.Instance().AddPlayer(PlayerId);
    13.     }
    14.  
    15.     private void OnChangeHealth(int oldHealth, int newHealth)
    16.     {
    17.         UiManager.Instance().UpdateHealth(PlayerId, newHealth);
    18.     }
    19.  
    20.     public uint PlayerId { get => playerId.Value; set => playerId.Value = value; }
    21.     public int Health { get => health.Value; set => health.Value = value; }
    22. }
    If you want to keep a permanent reference for each player you could create something like this:
    Code (CSharp):
    1. public class PlayerManager : Singleton<PlayerManager>
    2. {
    3.     Dictionary<uint, Player> player;
    4.  
    5.     public Dictionary<uint, Player> Player { get => player; set => player = value; }
    6. }
    and add this to OnNetworkSpawn:
    Code (CSharp):
    1. PlayerManager.Instance().Player.Add(PlayerId, this);
     
    Sekkizan likes this.
  7. maazgamer89

    maazgamer89

    Joined:
    Mar 7, 2022
    Posts:
    1
    how do i check how many number of players are connected
     
  8. D1EG0_26

    D1EG0_26

    Joined:
    May 12, 2020
    Posts:
    2
    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

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using Unity.Netcode;
    4. using UnityEngine;
    5.  
    6. public class GameManager : NetworkBehaviour
    7. {
    8.     NetworkVariable<int> playerCount = new();
    9.     public override void OnNetworkSpawn()
    10.     {
    11.         if (IsHost)
    12.         {
    13.             NetworkManager.Singleton.OnClientConnectedCallback += OnClientConnectedCallback;
    14.             NetworkManager.Singleton.OnClientDisconnectCallback += OnClientDisconnectCallback;
    15.         }
    16.     }
    17.  
    18.     private void OnClientDisconnectCallback(ulong obj)
    19.     {
    20.         playerCount.Value--;
    21.         UIManager.Instance.UpdatePlayerCount(playerCount.Value);
    22.     }
    23.  
    24.     private void OnClientConnectedCallback(ulong obj)
    25.     {
    26.         playerCount.Value++;
    27.         UIManager.Instance.UpdatePlayerCount(playerCount.Value);
    28.     }
    29. }
    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.
     
    Last edited: Aug 3, 2023
  9. D1EG0_26

    D1EG0_26

    Joined:
    May 12, 2020
    Posts:
    2
    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;
     
  10. kJlukOo

    kJlukOo

    Joined:
    Nov 20, 2021
    Posts:
    5
    dont need delivery. u can use this in clientrpc
    Code (CSharp):
    1. NetworkManager.LocalClient.PlayerObject