Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Join us on Dec 8, 2022, between 7 am & 7 pm EST, in the DOTS Dev Blitz Day 2022 - Q&A forum, Discord, and Unity3D Subreddit to learn more about DOTS directly from the Unity Developers.
    Dismiss Notice
  3. Have a look at our Games Focus blog post series which will show what Unity is doing for all game developers – now, next year, and in the future.
    Dismiss Notice

Question Simple example for a updating player list inGame

Discussion in 'Netcode for GameObjects' started by Andreas12345, Oct 31, 2022.

  1. Andreas12345

    Andreas12345

    Joined:
    Oct 17, 2013
    Posts:
    521
    I try to create a list and update it, but i didnt get it managed.

    Solution in:
    https://forum.unity.com/threads/sim...ting-player-list-ingame.1355462/#post-8554556

    I have a
    Code (CSharp):
    1. public GameObject nameTag;  // try to add to a list
    i use a
    Code (CSharp):
    1. private NetworkVariable<FixedString32Bytes> playerName = new NetworkVariable<FixedString32Bytes>();
    The name Tag i show over the player with another value:
    Code (CSharp):
    1. public override void OnNetworkSpawn()
    2.     {
    3.         playerName.OnValueChanged += OnPlayerNameChanged;
    4.         if (IsOwner)
    5.         {
    6.             SetPlayerNameServerRpc(PlayerPrefs.GetString("BikerName", "Unnamed Player"));
    7.             SetPlayerLobbyIdServerRpc(LobbyManager.singleton.GetCurPlayerId());
    8.          
    9.  
    10.         } else {
    11.             SetNameTag(playerName.Value.ToString());
    12.             SetWattKG(playerWKG.Value.ToString());
    13.    
    14.         }
    15.     }
    I want the nameTag stored in a list and update the UI, but also removed if player leaves.
    My idea was to call a PlayerlistUpdate() function with a ServerRPC when a client joins the session.

    In
    Code (CSharp):
    1. public override void OnNetworkSpawn()
    But how do i call a function on the client?
    How do i have not double entries, and how do i remove the entry that leaves the session?

    Call a function on the clients would be a good start.
     
    Last edited: Nov 1, 2022
  2. cerestorm

    cerestorm

    Joined:
    Apr 16, 2020
    Posts:
    402
    The above won't work as playerName is updated after the player is spawned. What you can do is to make use of OnPlayerNameChanged.

    For OnNetworkSpawn have:
    Code (CSharp):
    1.     public override void OnNetworkSpawn()
    2.     {
    3.         playerName.OnValueChanged += OnPlayerNameChanged;
    4.         if (IsLocalPlayer)
    5.         {
    6.             SetPlayerNameServerRpc(PlayerPrefs.GetString("BikerName", "Unnamed Player"));
    7.             SetPlayerLobbyIdServerRpc(LobbyManager.singleton.GetCurPlayerId());
    8.         }
    9.     }
    for OnPlayerNameChanged:

    Code (CSharp):
    1.     private void OnPlayerNameChanged(FixedString32Bytes previousValue, FixedString32Bytes newValue)
    2.     {
    3.         Debug.Log("Player OnPlayerNameChanged playerName: " + newValue);
    4.  
    5.         // add player to list
    6.         // display tag on UI
    7.     }
    For adding the player you could keep it simple and have a GameManager with a dictionary and use a playerId of some sort as the key:
    Code (CSharp):
    1. public class GameManager : Singleton<GameManager>
    2. {
    3.     Dictionary<uint, Player> players = new Dictionary<uint, Player>();
    4.  
    5.     public Dictionary<uint, Player> Players { get => players; }
    6. }
    For updating the UI it depends on how you're set up to access it, I have a class that holds all the UI elements and another for updating it but that might be more complicated a setup than you have in mind.

    For removing the player you can use OnNetworkDespawn:
    Code (CSharp):
    1.     public override void OnNetworkDespawn()
    2.     {
    3.         GameManager.Instance().Players.Remove(playerId);
    4.  
    5.         // remove player from UI
    6.     }
    If you're only maintaining the player list for UI updates you can always have the list and UI update handling in the same class.
     
    Andreas12345 likes this.
  3. Andreas12345

    Andreas12345

    Joined:
    Oct 17, 2013
    Posts:
    521
    I created my NetPlayerlist you suggest here with:
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using System.Linq;
    5. using Unity.Services.Lobbies.Models;
    6.  
    7. public class NetPlayerList : MonoBehaviour
    8. {
    9.     public static NetPlayerList singleton;
    10.  
    11.     Dictionary<uint, Player> players = new Dictionary<uint, Player>();
    12.  
    13.     public Dictionary<uint, Player> Players { get => players; }
    14.  
    15.  
    16. }
    in My NetworkBicyleScript i have:
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using Unity.Netcode;
    5. using Unity.Collections;
    6. using Unity.Services.Lobbies;
    7. using Unity.Services.Lobbies.Models;
    8. using Unity.Services.Relay;
    9. using TMPro;
    10.  
    11. //Handles network specific functions for multiplayer bicycles
    12. public class NetworkBicycle : NetworkBehaviour {
    13.  
    14.     public GameObject nameTag;  // try to add to a list
    15.     public GameObject wkg;
    16.  
    17.  
    18.  
    19.     //Network variables can not be nullable, so we have to use a fixed string
    20.     private NetworkVariable<FixedString32Bytes> playerName = new NetworkVariable<FixedString32Bytes>();
    21.     private NetworkVariable<FixedString128Bytes> playerLobbyId = new NetworkVariable<FixedString128Bytes>();
    22.     private NetworkVariable<FixedString32Bytes> playerWKG = new NetworkVariable<FixedString32Bytes>();
    23.  
    24.  
    25.     public override void OnNetworkSpawn()
    26.     {
    27.         playerName.OnValueChanged += OnPlayerNameChanged;
    28.         if (IsOwner)
    29.         {
    30.             SetPlayerNameServerRpc(PlayerPrefs.GetString("BikerName", "Unnamed Player"));
    31.             SetPlayerLobbyIdServerRpc(LobbyManager.singleton.GetCurPlayerId());
    32.         if (IsLocalPlayer)
    33.         {
    34.             SetPlayerNameServerRpc(PlayerPrefs.GetString("BikerName", "Unnamed Player"));
    35.             SetPlayerLobbyIdServerRpc(LobbyManager.singleton.GetCurPlayerId());
    36.         }
    37.  
    38.         } else {
    39.             SetNameTag(playerName.Value.ToString());
    40.             SetWattKG(playerWKG.Value.ToString());
    41.  
    42.         }
    43.     }
    44.  
    45.     [ServerRpc]
    46.     public void SetPlayerNameServerRpc(string name)
    47.     {
    48.         playerName.Value = name;
    49.     }
    50.  
    51.     [ServerRpc]
    52.     public void SetPlayerLobbyIdServerRpc(string id)
    53.     {
    54.         playerLobbyId.Value = id;
    55.     }
    56.  
    57.  
    58.     private void OnPlayerNameChanged(FixedString32Bytes previousValue, FixedString32Bytes newValue)
    59.     {
    60.         Debug.Log("Player OnPlayerNameChanged playerName: " + newValue);
    61.  
    62.         // add player to list
    63.         // display tag on UI
    64.     }
    65.  
    66.     private void SetNameTag(string name)
    67.     {
    68.         if (nameTag == null) {
    69.             return;
    70.         }
    71.         nameTag.GetComponent<TextMeshPro>().text = name;
    72.      
    73.     }
    74.  
    75.     public void SetWattKG(string _wkg)
    76.     {
    77.         if (wkg == null)
    78.         {
    79.             return;
    80.         }
    81.         wkg.GetComponent<TextMeshPro>().text = playerWKG.Value.ToString();
    82.         //Debug.Log("MoreValue" + playerWKG.Value.ToString());
    83.     }
    84.  
    85.     private void Update()
    86.     {
    87.         if (IsOwner)
    88.         {
    89.             var bikeUI = GameObject.FindGameObjectWithTag("BikeComputer").GetComponent<BikeComputerUI>();
    90.             SetWattKGServerRpc(bikeUI.wkg.text);
    91.            // Debug.Log("UpdatedValue" + playerWKG.Value.ToString());
    92.          
    93.         }
    94.         SetWattKG(playerWKG.Value.ToString());
    95.     }
    96.  
    97.  
    98.     [ServerRpc]
    99.     public void SetWattKGServerRpc(string _wkg)
    100.     {
    101.         playerWKG.Value = _wkg;
    102.       //  Debug.Log("We ve got value" + _wkg);
    103.     }
    104.  
    105.     public override void OnNetworkDespawn()
    106.     {
    107.         string playerId =
    108.         NetPlayerList.Instance().Players.Remove(playerId);
    109.         // remove player from UI
    110.     }
    111.  
    112.     private void OnDestroy() {
    113.         if (IsServer) {
    114.             LobbyService.Instance.RemovePlayerAsync(LobbyManager.singleton.GetCurLobby().Id, playerLobbyId.Value.ToString());
    115.         }
    116.         if (IsOwner) {
    117.             LobbyManager.singleton.Shutdown(true);
    118.         }
    119.     }
    120. }
    121.  
    changes like you suggested. but gives me a "no defination" for
    Code (CSharp):
    1. NetPlayerList.Instance().Players.Remove(playerId);
    I have also my LobbyManager posted here:
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using Unity.Netcode;
    5. using Unity.Netcode.Transports.UTP;
    6. using Unity.Services;
    7. using Unity.Services.Authentication;
    8. using Unity.Services.Core;
    9. using Unity.Services.Relay;
    10. using Unity.Services.Relay.Models;
    11. using Unity.Services.Lobbies;
    12. using Unity.Services.Lobbies.Models;
    13. using ParrelSync;  ///Needs to be Disabled when you build
    14. using System.Threading.Tasks;
    15. using UnityEngine.SceneManagement;
    16.  
    17. [RequireComponent(typeof(NetworkManager))]
    18. public class LobbyManager : MonoBehaviour {
    19.     public static LobbyManager singleton;
    20.     private string playerId;
    21.     private UnityTransport transport;
    22.     public const string joinCodeKey = "jc";
    23.     public const string sceneNameKey = "scnm";
    24.     public const string hostNameKey = "hname";
    25.  
    26.     private Lobby curLobby;
    27.  
    28.     private void Awake() {
    29.         LobbyManager.singleton = this;
    30.         transport = FindObjectOfType<UnityTransport>();
    31.     }
    32.  
    33.     private void Start() {
    34.         Authenticate();
    35.     }
    36.  
    37.     private async Task Authenticate() {
    38.         if (UnityServices.State == ServicesInitializationState.Uninitialized) {
    39.             var options = new InitializationOptions();
    40.         //Needs to be Disabled when you build
    41.      
    42.             #if UNITY_EDITOR
    43.                         //Used to differentiate clients when using ParrelSync
    44.                         options.SetProfile(ClonesManager.IsClone() ? ClonesManager.GetArgument() : "Primary");
    45.          #endif
    46.    
    47.             await UnityServices.InitializeAsync(options);
    48.         }
    49.         if (!AuthenticationService.Instance.IsSignedIn) {
    50.             await AuthenticationService.Instance.SignInAnonymouslyAsync();
    51.         }
    52.         playerId = AuthenticationService.Instance.PlayerId;
    53.     }
    54.  
    55.     private static IEnumerator HeartbeatLobbyCoroutine(string lobbyId, float waitTimeSeconds) {
    56.         var delay = new WaitForSecondsRealtime(waitTimeSeconds);
    57.         while (true) {
    58.             LobbyService.Instance.SendHeartbeatPingAsync(lobbyId);
    59.             yield return delay;
    60.         }
    61.     }
    62.  
    63.     public async Task<List<Lobby>> GatherLobbies() {
    64.         var options = new QueryLobbiesOptions { Count = 15, };
    65.         var allLobbies = await LobbyService.Instance.QueryLobbiesAsync(options);
    66.         return allLobbies.Results;
    67.     }
    68.  
    69.     public async Task<Lobby> CreateLobby(string hostName) {
    70.         try {
    71.             string joinCode = await RelayManager.singleton.CreateGame();
    72.             var options = new CreateLobbyOptions {
    73.                 Data = new Dictionary<string, DataObject> {
    74.                     { joinCodeKey, new DataObject(DataObject.VisibilityOptions.Public, joinCode) },
    75.                     { sceneNameKey, new DataObject(DataObject.VisibilityOptions.Public, SceneManager.GetActiveScene().name) },
    76.                     { hostNameKey, new DataObject(DataObject.VisibilityOptions.Public, hostName)}
    77.                 }
    78.             };
    79.             var lobby = await LobbyService.Instance.CreateLobbyAsync("Lobby Name", RelayManager.singleton.maxPlayerCount, options);
    80.             curLobby = lobby;
    81.             StartCoroutine(HeartbeatLobbyCoroutine(lobby.Id, 15));
    82.             return lobby;
    83.         } catch (System.Exception e) {
    84.             Debug.LogError("Failed to create lobby");
    85.             Debug.LogError(e);
    86.             throw;
    87.         }
    88.     }
    89.  
    90.     public async Task<Lobby> CreateLobbyDedServer(string hostName)
    91.     {
    92.         try
    93.         {
    94.             string joinCode = await RelayManager.singleton.CreateDedicatedServer();
    95.             var options = new CreateLobbyOptions
    96.             {
    97.                 Data = new Dictionary<string, DataObject> {
    98.                     { joinCodeKey, new DataObject(DataObject.VisibilityOptions.Public, joinCode) },
    99.                     { sceneNameKey, new DataObject(DataObject.VisibilityOptions.Public, SceneManager.GetActiveScene().name) },
    100.                     { hostNameKey, new DataObject(DataObject.VisibilityOptions.Public, hostName)}
    101.                 }
    102.             };
    103.             var lobby = await LobbyService.Instance.CreateLobbyAsync("Lobby Name", RelayManager.singleton.maxPlayerCount, options);
    104.             curLobby = lobby;
    105.             StartCoroutine(HeartbeatLobbyCoroutine(lobby.Id, 15));
    106.             //NetworkManager.Singleton.
    107.             return lobby;
    108.         }
    109.         catch (System.Exception e)
    110.         {
    111.             Debug.LogError("Failed to create lobby");
    112.             Debug.LogError(e);
    113.             throw;
    114.         }
    115.     }
    116.  
    117.     public async Task JoinLobby(string lobbyId) {
    118.         try {
    119.             curLobby = await LobbyService.Instance.JoinLobbyByIdAsync(lobbyId);
    120.             await RelayManager.singleton.JoinGame(curLobby.Data[LobbyManager.joinCodeKey].Value);
    121.         } catch (System.Exception e) {
    122.             Debug.LogError("Failed to join lobby");
    123.             Debug.LogError(e);
    124.             throw;
    125.         }
    126.     }
    127.  
    128.     //To be called by other scripts to shut down network services and optionally to return to menu
    129.     public void Shutdown(bool returnToMenu) {
    130.         if (GlobalValues.GetGameMode() == GlobalValues.GameMode.Single || curLobby == null) {
    131.             return;
    132.         }
    133.        // Destroy(NetworkManager.Singleton.gameObject);
    134.         NetworkManager.Singleton.Shutdown();
    135.         if (returnToMenu) {
    136.             ReturnToMenu();
    137.         }
    138.      
    139.     }
    140.  
    141.     //Returns to menu
    142.     private void ReturnToMenu() {
    143.         Destroy(NetworkManager.Singleton.gameObject);
    144.        // SceneManager.LoadScene(0);
    145.     }
    146.  
    147.     public Lobby GetCurLobby() {
    148.         return curLobby;
    149.     }
    150.  
    151.     public string GetCurPlayerId() {
    152.         return playerId;
    153.     }
    154. }
    155.  
    I am still struggle and i think i mix to much different places :(
    The complete day i am busy with that :(

    The playerId i grab now with:
    Code (CSharp):
    1. string playerId = LobbyManager.singleton.GetCurPlayerId();
     
    Last edited: Oct 31, 2022
  4. cerestorm

    cerestorm

    Joined:
    Apr 16, 2020
    Posts:
    402
    You'll need to remove this from OnNetworkSpawn:
    Code (CSharp):
    1.         } else {
    2.             SetNameTag(playerName.Value.ToString());
    3.             SetWattKG(playerWKG.Value.ToString());
    4.  
    5.         }
    at least the SetNameTag call as playerName won't have a value at this point.
    I see the Remove but don't see you adding to the player dictionary. I can't say exactly what you want but OnPlayerNameChanged will need to look something like this:
    Code (CSharp):
    1.     private void OnPlayerNameChanged(FixedString32Bytes previousValue, FixedString32Bytes newValue)
    2.     {
    3.         Debug.Log("Player OnPlayerNameChanged playerName: " + newValue);
    4.  
    5.         NetPlayerList.Instance().Players.Add(playerId, this);
    6.         SetNameTag(playerName.Value.ToString());
    7.     }
    You'll need to find or create a playerId to use as the key.
     
    Andreas12345 likes this.
  5. Andreas12345

    Andreas12345

    Joined:
    Oct 17, 2013
    Posts:
    521
    Ok then i am more on it:
    Code (CSharp):
    1. private void OnPlayerNameChanged(FixedString32Bytes previousValue, FixedString32Bytes newValue)
    2.     {
    3.         Debug.Log("Player OnPlayerNameChanged playerName: " + newValue);
    4.  
    5.         uint playerId = Convert.ToUInt32(LobbyManager.singleton.GetCurPlayerId());
    6.         NetPlayerList.singleton.Players.Add(playerId, this);
    7.         SetNameTag(playerName.Value.ToString());
    8.     }
    I need to convert, but how ever this
    Code (CSharp):
    1. NetPlayerList.singleton.Players.Add(playerId, this);
    2.  
    brings me:
    Code (CSharp):
    1. Assets\Scripts\Multiplayer\NetworkBicycle.cs(71,55): error CS1503: Argument 2: cannot convert from 'NetworkBicycle' to 'Unity.Services.Lobbies.Models.Player'
     
  6. cerestorm

    cerestorm

    Joined:
    Apr 16, 2020
    Posts:
    402
    If NetworkBicycle is the class you're using to represent the player change the dictionary definition to this:
    Code (csharp):
    1. Dictionary<uint, NetworkBicycle> players = Dictionary<uint, NetworkBicycle>();
    'this' is just a way of getting the current object.
     
    Andreas12345 likes this.
  7. Andreas12345

    Andreas12345

    Joined:
    Oct 17, 2013
    Posts:
    521
    Ok but i needed to replace uint to string, and i am here now:
    My Future NetPlayerList:
    Code (CSharp):
    1. public class NetPlayerList : MonoBehaviour
    2. {
    3.     public static NetPlayerList Instance { get; private set; }
    4.     public Dictionary<string, NetworkBicycle> players = new Dictionary<string, NetworkBicycle>();
    5.  
    6.     private void Awake()
    7.     {
    8.         // If there is an instance, and it's not me, delete myself.
    9.         if (Instance != null && Instance != this)
    10.         {
    11.             Destroy(this);
    12.         }
    13.         else
    14.         {
    15.             Instance = this;
    16.         }
    17.     }
    18. }
    And in my NetworkBicycle ia have now:
    Code (CSharp):
    1. private void OnPlayerNameChanged(FixedString32Bytes previousValue, FixedString32Bytes newValue)
    2.     {
    3.        // Debug.Log("Player OnPlayerNameChanged playerName: " + newValue);
    4.        // Debug.Log("Player OnPlayerNameChanged playerId: " + LobbyManager.singleton.GetCurPlayerId());
    5.         var playerId = LobbyManager.singleton.GetCurPlayerId();
    6.         NetPlayerList.Instance.players.Add(playerId, this );
    7.         Debug.Log("Added: "+playerId, this);
    8.         SetNameTag(playerName.Value.ToString());
    9.         Debug.Log("Values =" + NetPlayerList.Instance.players.Keys + NetPlayerList.Instance.players.Values);
    10.     }
    Code (CSharp):
    1. void ShowDict()
    2.     {
    3.         foreach (KeyValuePair<string, NetworkBicycle> player in NetPlayerList.Instance.players)
    4.         {
    5.             Debug.Log("Key"+ player.Key);
    6.             Debug.Log("Value"+ player.Value);
    7.         }
    8.     }
    This dont look correct!?
    And i am right, i need to read out the dictionary and then add the values to my wanted PlayerList?

    My debugLog:
    Code (CSharp):
    1. Key = XCYqLi55AtTxVr823viSjZbWasKa
    2. Value = ValueBiycycle StandardYellow(Clone) (NetworkBicycle)
     
    Last edited: Nov 1, 2022
  8. Andreas12345

    Andreas12345

    Joined:
    Oct 17, 2013
    Posts:
    521
    So after reading and not understanding i have:
    Code (CSharp):
    1. using System;
    2. using System.Collections.Generic;
    3. using TMPro;
    4. using Unity.Netcode;
    5. using UnityEngine;
    6. using UnityEngine.UI;
    7.  
    8. public class NetPlayerList : NetworkBehaviour
    9. {
    10.  
    11.     public TMP_Text LobbyText;
    12.  
    13.     private Dictionary<ulong, bool> m_ClientsInLobby;
    14.     private string m_UserLobbyStatusText;
    15.  
    16.     public override void OnNetworkSpawn()
    17.     {
    18.         m_ClientsInLobby = new Dictionary<ulong, bool>();
    19.  
    20.         //Always add ourselves to the list at first
    21.         m_ClientsInLobby.Add(NetworkManager.LocalClientId, false);
    22.  
    23.         //If we are hosting, then handle the server side for detecting when clients have connected
    24.         //and when their lobby scenes are finished loading.
    25.         if (IsServer)
    26.         {
    27.             //  m_AllPlayersInLobby = false;
    28.  
    29.             //Server will be notified when a client connects
    30.             NetworkManager.OnClientConnectedCallback += OnClientConnectedCallback;
    31.             UpdateAndCheckPlayersInLobby();
    32.    
    33.         }
    34.  
    35.         //Update our lobby
    36.         GenerateUserStatsForLobby();
    37.  
    38.     }
    39.     /
    40.     private void OnGUI()
    41.     {
    42.         if (LobbyText != null) LobbyText.text = m_UserLobbyStatusText;
    43.     }
    44.  
    45.    
    46.     private void GenerateUserStatsForLobby()
    47.     {
    48.         m_UserLobbyStatusText = string.Empty;
    49.         foreach (var clientLobbyStatus in m_ClientsInLobby)
    50.         {
    51.             m_UserLobbyStatusText += PlayerPrefs.GetString("BikerName") + "\n";// + clientLobbyStatus.Key + "          \n";
    52.          
    53.             /
    54.         }
    55.     }
    56.    
    57.     private void UpdateAndCheckPlayersInLobby()
    58.     {
    59.        
    60.  
    61.         foreach (var clientLobbyStatus in m_ClientsInLobby)
    62.         {
    63.             SendClientReadyStatusUpdatesClientRpc(clientLobbyStatus.Key, clientLobbyStatus.Value);
    64.            
    65.         }
    66.      
    67.     }
    68.  
    69.      /// <summary>
    70.     ///     OnClientConnectedCallback
    71.     ///     Since we are entering a lobby and Netcode's NetworkManager is spawning the player,
    72.     ///     the server can be configured to only listen for connected clients at this stage.
    73.     /// </summary>
    74.     /// <param name="clientId">client that connected</param>
    75.     private void OnClientConnectedCallback(ulong clientId)
    76.     {
    77.         if (IsServer)
    78.         {
    79.             if (!m_ClientsInLobby.ContainsKey(clientId)) m_ClientsInLobby.Add(clientId, false);
    80.             GenerateUserStatsForLobby();
    81.  
    82.             UpdateAndCheckPlayersInLobby();
    83.         }
    84.     }
    85.  
    86.     /// <summary>
    87.     ///     SendClientReadyStatusUpdatesClientRpc
    88.     ///     Sent from the server to the client when a player's status is updated.
    89.     ///     This also populates the connected clients' (excluding host) player state in the lobby
    90.     /// </summary>
    91.     /// <param name="clientId"></param>
    92.     /// <param name="isReady"></param>
    93.     [ClientRpc]
    94.     private void SendClientReadyStatusUpdatesClientRpc(ulong clientId, bool isReady)
    95.     {
    96.         if (!IsServer)
    97.         {
    98.             if (!m_ClientsInLobby.ContainsKey(clientId))
    99.                 m_ClientsInLobby.Add(clientId, isReady);
    100.             else
    101.                 m_ClientsInLobby[clientId] = isReady;
    102.             GenerateUserStatsForLobby();
    103.         }
    104.     }
    105.  
    106.    
    107. }
    108.  
    Not perfect yet, and i need to remove the player when he/she despawns:
    But works in a way.
    I have *COPIED* and fit to my needs from:
    https://github.com/Unity-Technologies/com.unity.multiplayer.samples.bitesize/tree/main/Basic

    The Invaders example
    I still dont understand not all, but i will when time is come. :)
     
  9. cerestorm

    cerestorm

    Joined:
    Apr 16, 2020
    Posts:
    402
    You didn't mention what the list was going to be used for so I only gave you a general example. Actually looking at it again it's not quite right but anyway. I've not used Lobby but if there's something you're stuck with I'll see if I can help.
     
    Andreas12345 likes this.
  10. Andreas12345

    Andreas12345

    Joined:
    Oct 17, 2013
    Posts:
    521
    I am always happy for any help :)
    upload_2022-11-1_11-19-53.png

    The adding works great.
    Now i like to create a callBack what removes the player from the List when leave with :
    Code (CSharp):
    1. public override void OnNetworkDespawn()
    2.     {
    3.  
    4.         NetworkManager.OnClientDisconnectCallback += OnClientDisconnectCallback;
    5.         GenerateUserStatsForLobby();
    6.         UpdateAndCheckPlayersInLobby();
    7.     }
    Code (CSharp):
    1. private void OnClientDisconnectCallback(ulong clientId)
    2.     {
    3.         if (!IsServer)
    4.         {
    5.             if (!m_ClientsInLobby.ContainsKey(clientId)) m_ClientsInLobby.Remove(clientId);
    6.  
    7.             GenerateUserStatsForLobby();
    8.             UpdateAndCheckPlayersInLobby();
    9.         }
    10.     }
    But the Player is still in List

    many Thanks for your great help by the way! :)
     
  11. cerestorm

    cerestorm

    Joined:
    Apr 16, 2020
    Posts:
    402
    You'll want NetworkManager.OnClientDisconnectCallback += OnClientDisconnectCallback; to be in OnNetworkSpawn.

    One thing I would suggest is debug log everything, all method calls and relevant values so you have eyes on what's going on when the application is running.
     
    Andreas12345 likes this.
  12. Andreas12345

    Andreas12345

    Joined:
    Oct 17, 2013
    Posts:
    521
    The debug says:
    Code (CSharp):
    1.  Debug.Log("Removed: " + clientId);
    [Netcode] Disconnect Event From 1

    MayBe its disconnect from Dictionary, but dont removed from the list.

    But when i leave and rejoin the Session, i have 3 entries, so the entry is probably not really removed with all the data?
     
  13. cerestorm

    cerestorm

    Joined:
    Apr 16, 2020
    Posts:
    402
    I can't really say, if you need to have a dictionary and a list then you need to keep them in sync, I can't see enough to understand what's going on. You'll want to make sure everything is correct at each step, so start when a client connects check that all values are correct and when they disconnect you're effectively reversing what you did on connection.
     
    Andreas12345 likes this.
  14. Andreas12345

    Andreas12345

    Joined:
    Oct 17, 2013
    Posts:
    521
    I understand:
    My idea was to just remove all entries in the text:
    https://github.com/Landixus/ToolsForUnity/blob/master/NetPlayerList.cs#L92

    I pushed my file to github, because i think its easier to read:

    And after cleared the List i just generate them new, so i dont need to reverse it.
     
  15. Andreas12345

    Andreas12345

    Joined:
    Oct 17, 2013
    Posts:
    521
    Got it:
    Code (CSharp):
    1.  private void OnClientDisconnectCallback(ulong clientId)
    2.     {
    3.         if (IsServer)
    4.         {
    5.             if (m_ClientsInLobby.ContainsKey(clientId)) m_ClientsInLobby.Remove(clientId);
    6.             Debug.Log("Removed: " + clientId);
    7.             m_UserLobbyStatusText = "";
    8.             GenerateUserStatsForLobby();
    9.             UpdateAndCheckPlayersInLobby();
    10.         }
    11.     }
    The ! was to much.
    It works now, if anybody surf here:
    Code (CSharp):
    1. using System;
    2. using System.Collections.Generic;
    3. using TMPro;
    4. using Unity.Netcode;
    5. using UnityEngine;
    6. using UnityEngine.UI;
    7.  
    8. public class NetPlayerList : NetworkBehaviour
    9. {
    10.  
    11.     [SerializeField]
    12.     public TMP_Text LobbyText;
    13.  
    14.     private Dictionary<ulong, bool> m_ClientsInLobby;
    15.  
    16.     private string m_UserLobbyStatusText;
    17.  
    18.     public override void OnNetworkSpawn()
    19.     {
    20.         m_ClientsInLobby = new Dictionary<ulong, bool>();
    21.  
    22.         //Always add ourselves to the list at first
    23.         m_ClientsInLobby.Add(NetworkManager.LocalClientId, false);
    24.  
    25.         //If we are hosting, then handle the server side for detecting when clients have connected
    26.         //and when their lobby scenes are finished loading.
    27.         if (IsServer)
    28.         {
    29.             //Server will be notified when a client connects
    30.             NetworkManager.OnClientConnectedCallback += OnClientConnectedCallback;
    31.             NetworkManager.OnClientDisconnectCallback += OnClientDisconnectCallback;
    32.             UpdateAndCheckPlayersInLobby();
    33.         }
    34.         //Update our lobby
    35.         GenerateUserStatsForLobby();
    36.     }
    37.     private void OnGUI()
    38.     {
    39.         if (LobbyText != null) LobbyText.text = m_UserLobbyStatusText;
    40.     }
    41.     private void GenerateUserStatsForLobby()
    42.     {
    43.         m_UserLobbyStatusText = string.Empty;
    44.         foreach (var clientLobbyStatus in m_ClientsInLobby)
    45.         {
    46.             m_UserLobbyStatusText += PlayerPrefs.GetString("BikerName") + "\n";
    47.  
    48.         }
    49.     }
    50.     /// <summary>
    51.     ///     UpdateAndCheckPlayersInLobby
    52.     ///     Checks to see if we have at least 2 or more people to start
    53.     /// </summary>
    54.     private void UpdateAndCheckPlayersInLobby()
    55.     {
    56.         foreach (var clientLobbyStatus in m_ClientsInLobby)
    57.         {
    58.             SendClientReadyStatusUpdatesClientRpc(clientLobbyStatus.Key); // clientLobbyStatus.Value);
    59.         }
    60.     }
    61.  
    62.     /// <summary>
    63.     ///     OnClientConnectedCallback
    64.     ///     Since we are entering a lobby and Netcode's NetworkManager is spawning the player,
    65.     ///     the server can be configured to only listen for connected clients at this stage.
    66.     /// </summary>
    67.     private void OnClientConnectedCallback(ulong clientId)
    68.     {
    69.         if (IsServer)
    70.         {
    71.             if (!m_ClientsInLobby.ContainsKey(clientId)) m_ClientsInLobby.Add(clientId, false);
    72.  
    73.             GenerateUserStatsForLobby();
    74.             UpdateAndCheckPlayersInLobby();
    75.         }
    76.     }
    77.  
    78.     private void OnClientDisconnectCallback(ulong clientId)
    79.     {
    80.         if (IsServer)
    81.         {
    82.             if (m_ClientsInLobby.ContainsKey(clientId)) m_ClientsInLobby.Remove(clientId);
    83.             Debug.Log("Removed: " + clientId);
    84.             m_UserLobbyStatusText = "";
    85.             GenerateUserStatsForLobby();
    86.             UpdateAndCheckPlayersInLobby();
    87.         }
    88.     }
    89.  
    90.     /// <summary>
    91.     ///     SendClientReadyStatusUpdatesClientRpc
    92.     ///     Sent from the server to the client when a player's status is updated.
    93.     ///     This also populates the connected clients' (excluding host) player state in the lobby
    94.     /// </summary>
    95.     /// <param name="clientId"></param>
    96.     [ClientRpc]
    97.   //  private void SendClientReadyStatusUpdatesClientRpc(ulong clientId, bool isReady)
    98.     private void SendClientReadyStatusUpdatesClientRpc(ulong clientId)
    99.     {
    100.         if (!IsServer)
    101.         {
    102.             if (!m_ClientsInLobby.ContainsKey(clientId))
    103.                 m_ClientsInLobby.Add(clientId, false);
    104.                 GenerateUserStatsForLobby();
    105.         }
    106.     }
    107.  
    108. }
    109.  
     
    cerestorm likes this.
  16. Andreas12345

    Andreas12345

    Joined:
    Oct 17, 2013
    Posts:
    521
    I was totally wrong, i store always the same name in the list of the client on the side of the client.
    I need to marry the client ID with the PlayerName:
    This brings me the client ID to List with 0, false.... 1,false....:
    Code (CSharp):
    1. m_UserLobbyStatusText += $"{clientLobbyStatus.Key}: {clientLobbyStatus.Value}\n"
    but no name :(
    https://github.com/Landixus/ToolsForUnity/blob/master/NetworkBicycle.cs#L169

    I am lost here. :(
    My solution is not working.
    I tried to get a more experienced coder and attract with some pocket money ends in zero success :(
    Player List with name must be a secret feature of netcode.
     
  17. cerestorm

    cerestorm

    Joined:
    Apr 16, 2020
    Posts:
    402
    I have to go back to bit to understand what you actually need and correct something I said previously.

    Have a collection for connected players:
    Code (CSharp):
    1. public class NetPlayerList : NetworkBehaviour
    2. {
    3.     private Dictionary<ulong, NetworkBicycle> players;
    4. }
    Add to the player collection on spawn:
    Code (CSharp):
    1. public class NetworkBicycle : NetworkBehaviour {
    2.     public override void OnNetworkSpawn()
    3.     {
    4.         NetPlayerList.instance.Players.Add(this.OwnerClientId, this);
    5.  
    6.         playerName.OnValueChanged += OnPlayerNameChanged;
    7.     }
    8. }
    Add player name to UI:
    Code (CSharp):
    1. private void OnPlayerNameChanged(FixedString32Bytes previousValue, FixedString32Bytes newValue)
    2.     {
    3.         SetNameTag(playerName.Value.ToString());
    4.     }
    Remove player from collection on despawn:
    Code (CSharp):
    1. public class NetworkBicycle : NetworkBehaviour {  
    2.     public override void OnNetworkDespawn()
    3.     {
    4.         NetPlayerList.instance.Players.Remove(this.OwnerClientId);
    5.  
    6.         playerName.OnValueChanged -= OnPlayerNameChanged;
    7.     }
    8. }
    Is this essentially what you're after, as I'm a bit confused on how you're using the dictionaries at the moment.
     
    Andreas12345 likes this.
  18. Andreas12345

    Andreas12345

    Joined:
    Oct 17, 2013
    Posts:
    521
    Thank you i try this when i am back at home and report back.
     
  19. Andreas12345

    Andreas12345

    Joined:
    Oct 17, 2013
    Posts:
    521
    I tried but i get the Singleton not referenced:

    I am here:
    Code (CSharp):
    1. using System;
    2. using System.Collections.Generic;
    3. using TMPro;
    4. using Unity.Netcode;
    5. using UnityEngine;
    6. using UnityEngine.UI;
    7.  
    8. public class NetPlayerList : NetworkBehaviour
    9. {
    10.     public static NetPlayerList instance { get; private set; }
    11.  
    12.     [SerializeField]
    13.     public TMP_Text LobbyText;
    14.  
    15.     private Dictionary<ulong, bool> m_ClientsInLobby;
    16.     private string m_UserLobbyStatusText;
    17.  
    18.     public Dictionary<ulong, NetworkBicycle> players;
    19.  
    20.  
    21.     private void Awake()
    22.     {
    23.         // If there is an instance, and it's not me, delete myself.
    24.  
    25.         if (instance != null && instance != this)
    26.         {
    27.             Destroy(this);
    28.         }
    29.         else
    30.         {
    31.             instance = this;
    32.         }
    33.     }
    34.  
    35.     public override void OnNetworkSpawn()
    36.     {
    37.         m_ClientsInLobby = new Dictionary<ulong, bool>();
    38.  
    39.  
    40.         //Always add ourselves to the list at first
    41.         m_ClientsInLobby.Add(NetworkManager.LocalClientId, false);
    42.  
    43.         //If we are hosting, then handle the server side for detecting when clients have connected
    44.         //and when their lobby scenes are finished loading.
    45.         if (IsServer)
    46.         {
    47.             //Server will be notified when a client connects
    48.             NetworkManager.OnClientConnectedCallback += OnClientConnectedCallback;
    49.             NetworkManager.OnClientDisconnectCallback += OnClientDisconnectCallback;
    50.             UpdateAndCheckPlayersInLobby();
    51.         }
    52.         //Update our lobby
    53.         GenerateUserStatsForLobby();
    54.     }
    55.     private void OnGUI()
    56.     {
    57.         if (LobbyText != null) LobbyText.text = m_UserLobbyStatusText;
    58.     }
    59.     private void GenerateUserStatsForLobby()
    60.     {
    61.         m_UserLobbyStatusText = string.Empty;
    62.  
    63.         foreach (var clientLobbyStatus in m_ClientsInLobby)
    64.         {
    65.  
    66.             m_UserLobbyStatusText += $"{clientLobbyStatus.Key}: {clientLobbyStatus.Value}\n" + players.Values;
    67.             /*
    68.             if (IsLocalPlayer)
    69.             {
    70.                  m_UserLobbyStatusText += PlayerPrefs.GetString("BikerName") + "\n";
    71.             }*/
    72.  
    73.             //  m_UserLobbyStatusText += networkBicyle.nameTag.GetComponent<TextMeshPro>().text;
    74.  
    75.         }
    76.     }
    77.     /// <summary>
    78.     ///     UpdateAndCheckPlayersInLobby
    79.     ///     Checks to see if we have at least 2 or more people to start
    80.     /// </summary>
    81.     private void UpdateAndCheckPlayersInLobby()
    82.     {
    83.         foreach (var clientLobbyStatus in m_ClientsInLobby)
    84.         {
    85.             SendClientReadyStatusUpdatesClientRpc(clientLobbyStatus.Key); // clientLobbyStatus.Value);
    86.         }
    87.     }
    88.  
    89.     /// <summary>
    90.     ///     OnClientConnectedCallback
    91.     ///     Since we are entering a lobby and Netcode's NetworkManager is spawning the player,
    92.     ///     the server can be configured to only listen for connected clients at this stage.
    93.     /// </summary>
    94.     private void OnClientConnectedCallback(ulong clientId)
    95.     {
    96.         if (IsServer)
    97.         {
    98.             if (!m_ClientsInLobby.ContainsKey(clientId)) m_ClientsInLobby.Add(clientId, false);
    99.  
    100.             GenerateUserStatsForLobby();
    101.             UpdateAndCheckPlayersInLobby();
    102.         }
    103.     }
    104.  
    105.     private void OnClientDisconnectCallback(ulong clientId)
    106.     {
    107.         if (IsServer)
    108.         {
    109.             if (m_ClientsInLobby.ContainsKey(clientId)) m_ClientsInLobby.Remove(clientId);
    110.             Debug.Log("Removed: " + clientId);
    111.             m_UserLobbyStatusText = "";
    112.             GenerateUserStatsForLobby();
    113.             UpdateAndCheckPlayersInLobby();
    114.         }
    115.     }
    116.  
    117.     /// <summary>
    118.     ///     SendClientReadyStatusUpdatesClientRpc
    119.     ///     Sent from the server to the client when a player's status is updated.
    120.     ///     This also populates the connected clients' (excluding host) player state in the lobby
    121.     /// </summary>
    122.     /// <param name="clientId"></param>
    123.     [ClientRpc]
    124.   //  private void SendClientReadyStatusUpdatesClientRpc(ulong clientId, bool isReady)
    125.     private void SendClientReadyStatusUpdatesClientRpc(ulong clientId)
    126.     {
    127.         if (!IsServer)
    128.         {
    129.             if (!m_ClientsInLobby.ContainsKey(clientId))
    130.                 m_ClientsInLobby.Add(clientId, false);
    131.                 GenerateUserStatsForLobby();
    132.         }
    133.     }
    134.  
    135. }
    And my Bicycle:
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using System;
    4. using UnityEngine;
    5. using Unity.Netcode;
    6. using Unity.Collections;
    7. using Unity.Services.Lobbies;
    8. using Unity.Services.Lobbies.Models;
    9. using Unity.Services.Relay;
    10. using TMPro;
    11.  
    12. //Handles network specific functions for multiplayer bicycles
    13. public class NetworkBicycle : NetworkBehaviour {
    14.  
    15.     public GameObject nameTag;  // try to add to a list
    16.     public GameObject wkg;
    17.     //Network variables can not be nullable, so we have to use a fixed string
    18.     private NetworkVariable<FixedString32Bytes> playerName = new NetworkVariable<FixedString32Bytes>();
    19.     private NetworkVariable<FixedString128Bytes> playerLobbyId = new NetworkVariable<FixedString128Bytes>();
    20.     private NetworkVariable<FixedString32Bytes> playerWKG = new NetworkVariable<FixedString32Bytes>();
    21.  
    22.  
    23.     private void Start()
    24.     {
    25.    //     LobbyText = GameObject.FindGameObjectWithTag("PLStart").GetComponent<TMP_Text>();
    26.     }
    27.  
    28.     public override void OnNetworkSpawn()
    29.     {
    30.         playerName.OnValueChanged += OnPlayerNameChanged;
    31.         if (IsOwner)
    32.         {
    33.             SetPlayerNameServerRpc(PlayerPrefs.GetString("BikerName", "Unnamed Player"));
    34.             SetPlayerLobbyIdServerRpc(LobbyManager.singleton.GetCurPlayerId());
    35.            //   Debug.Log("We ve got listname" + _listname);
    36.  
    37.             /*  if (IsLocalPlayer)
    38.               {
    39.                   SetPlayerNameServerRpc(PlayerPrefs.GetString("BikerName", "Unnamed Player"));
    40.                   SetPlayerLobbyIdServerRpc(LobbyManager.singleton.GetCurPlayerId());
    41.               }*/
    42.  
    43.         } else
    44.         {
    45.             SetNameTag(playerName.Value.ToString());
    46.             SetWattKG(playerWKG.Value.ToString());
    47.         }
    48.  
    49.         NetPlayerList.instance.players.Add(this.OwnerClientId, this);
    50.  
    51.         playerName.OnValueChanged += OnPlayerNameChanged;
    52.  
    53.     }
    54.  
    55.     public override void OnNetworkDespawn()
    56.     {
    57.  
    58.         NetPlayerList.instance.players.Remove(this.OwnerClientId);
    59.  
    60.         playerName.OnValueChanged -= OnPlayerNameChanged;
    61.         //  var playerId = LobbyManager.singleton.GetCurPlayerId();
    62.         //  NetPlayerList.Instance.players.Remove(playerId);
    63.         // remove player from UI
    64.           Debug.Log("Removed: " + this.OwnerClientId);
    65.     }
    66.  
    67.     [ServerRpc]
    68.     public void SetPlayerNameServerRpc(string name)
    69.     {
    70.         playerName.Value = name;
    71.     }
    72.  
    73.     [ServerRpc]
    74.     public void SetPlayerLobbyIdServerRpc(string id)
    75.     {
    76.         playerLobbyId.Value = id;
    77.     }
    78.  
    79.  
    80.     private void OnPlayerNameChanged(FixedString32Bytes previousValue, FixedString32Bytes newValue)
    81.     {
    82.  
    83.       SetNameTag(playerName.Value.ToString());
    84.  
    85.     }
    86.  
    87.     private void SetNameTag(string name)
    88.     {
    89.         if (nameTag == null) {
    90.             return;
    91.         }
    92.         nameTag.GetComponent<TextMeshPro>().text = name;
    93.        
    94.     }
    95.  
    96.     public void SetWattKG(string _wkg)
    97.     {
    98.         if (wkg == null)
    99.         {
    100.             return;
    101.         }
    102.         wkg.GetComponent<TextMeshPro>().text = playerWKG.Value.ToString();
    103.         //Debug.Log("MoreValue" + playerWKG.Value.ToString());
    104.     }
    105.  
    106.  
    107.  
    108.     private void Update()
    109.     {  
    110.         if (IsOwner)
    111.         {
    112.             var bikeUI = GameObject.FindGameObjectWithTag("BikeComputer").GetComponent<BikeComputerUI>();
    113.             SetWattKGServerRpc(bikeUI.wkg.text);
    114.            // Debug.Log("UpdatedValue" + playerWKG.Value.ToString());
    115.            
    116.         }
    117.         SetWattKG(playerWKG.Value.ToString());
    118.     }
    119.  
    120.  
    121.     [ServerRpc]
    122.     public void SetWattKGServerRpc(string _wkg)
    123.     {
    124.         playerWKG.Value = _wkg;
    125.       //  Debug.Log("We ve got value" + _wkg);
    126.     }
    127.  
    128.  
    129.  
    130.        private void OnDestroy() {
    131.         if (IsServer) {
    132.             LobbyService.Instance.RemovePlayerAsync(LobbyManager.singleton.GetCurLobby().Id, playerLobbyId.Value.ToString());
    133.         }
    134.         if (IsOwner) {
    135.             LobbyManager.singleton.Shutdown(true);
    136.         }
    137.     }
    138. }
    139.  
    Gives me currently:
    NullReferenceException: Object reference not set to an instance of an object at 49:
    NetPlayerList.instance.players.Add(this.OwnerClientId, this);

    But i thought a Singleton is always project wide active when awaked!?
     
  20. cerestorm

    cerestorm

    Joined:
    Apr 16, 2020
    Posts:
    402
    Bit short on time but does NetPlayerList need to be a NetworkBehaviour, are you spawning it?
     
  21. Andreas12345

    Andreas12345

    Joined:
    Oct 17, 2013
    Posts:
    521
    No, but then the functions are missing: upload_2022-11-8_20-1-55.png
     
  22. cerestorm

    cerestorm

    Joined:
    Apr 16, 2020
    Posts:
    402
    It may not be necessary for it to be a network object, because if it is you have to spawn it and if you spawn it you have to make sure it's spawned before the host player object. The error suggests it's not actually being spawned or spawned first.
     
  23. Andreas12345

    Andreas12345

    Joined:
    Oct 17, 2013
    Posts:
    521
    The NetPlayerList Object is always in the scene. Its a part of the UI
     
  24. cerestorm

    cerestorm

    Joined:
    Apr 16, 2020
    Posts:
    402
    As an in-scene network object? Anyway, are you actually instantiating the dictionary?
     
  25. Andreas12345

    Andreas12345

    Joined:
    Oct 17, 2013
    Posts:
    521
  26. cerestorm

    cerestorm

    Joined:
    Apr 16, 2020
    Posts:
    402
    Log NetPlayerList.instance and NetPlayerLisr.instance.players and see which one is null.
     
    Andreas12345 likes this.
  27. Andreas12345

    Andreas12345

    Joined:
    Oct 17, 2013
    Posts:
    521
    I try when i am back from work.
    Thanks for your patience. :)

    BTW the null Reference is gone.
     
    Last edited: Nov 9, 2022
  28. Andreas12345

    Andreas12345

    Joined:
    Oct 17, 2013
    Posts:
    521
  29. cerestorm

    cerestorm

    Joined:
    Apr 16, 2020
    Posts:
    402
    It looks like it's kinda working, you might want to log the clientId as well in SetNameTag(). Do both host and client have the same name?

    For public GameObject nameTag in NetworkBicycle, how are you setting this value with the correct TextMeshPro game object?
     
    Andreas12345 likes this.
  30. Andreas12345

    Andreas12345

    Joined:
    Oct 17, 2013
    Posts:
    521
    I use parallel Sync thats why the have the same name.
    the nameTag TextMeshPro game object is on the PlayerPrefab
     
  31. cerestorm

    cerestorm

    Joined:
    Apr 16, 2020
    Posts:
    402
    Having the same name makes it harder to understand the logs, unique names would be better, you could just use the clientId for now. The SetNameTag() call in OnNetworkSpawn isn't needed and the logs will be clearer without it.

    I can't see what's wrong, try hard coding the names in SetNameTag() to make sure they're displayed properly.
     
    Andreas12345 likes this.
  32. Andreas12345

    Andreas12345

    Joined:
    Oct 17, 2013
    Posts:
    521
    I create a build and patch to check with different machines:
    What happens is this:
    upload_2022-11-10_16-54-15.png
    When 3rd player joins

    When 4th player join:
    upload_2022-11-10_16-54-49.png

    i think i am at 99.5% success
    Its only always the last player who joins that gets no attention

    Funny sidekick happening when Server leaves the session:
    upload_2022-11-10_16-58-16.png
    4th Player will be then added :)
     
  33. cerestorm

    cerestorm

    Joined:
    Apr 16, 2020
    Posts:
    402
    Good stuff, all I can suggest is log everything and see where differences show up along the line.
     
    RikuTheFuffs-U likes this.
  34. Andreas12345

    Andreas12345

    Joined:
    Oct 17, 2013
    Posts:
    521
    No way, it just not work
    I tried to change IsServer to IsHost, because i start as non Dedicated, but brings nothing in change.
     
  35. cerestorm

    cerestorm

    Joined:
    Apr 16, 2020
    Posts:
    402
    What are you logs telling you, as they're there to guide you towards understanding the problem.

    It looks like you have two separate issues, getting the player name and displaying it correctly. Just focus on getting the name for now and afterwards look into correctly showing it on the UI.
     
  36. Andreas12345

    Andreas12345

    Joined:
    Oct 17, 2013
    Posts:
    521
    I stop with that, for me its unity buggy netcode.
    the forum is full of issues, also the github.

    I think its easier to have a online player list, and make them public to all players.
    I ask 3 coders, and they all said my code is correct, and that netcode of unity is full of problems.

    But i like to thank you with your assist and patience
    @cerestorm