Search Unity

  1. The 2022.1 beta is now available for testing. To find out what's new, have a look at our 2022.1 beta blog post.
    Dismiss Notice

Help Wanted NetworkVariable in Netcode for game objects not working

Discussion in 'Netcode for GameObjects' started by abc4c, Nov 9, 2021.

  1. abc4c

    abc4c

    Joined:
    Jan 12, 2021
    Posts:
    1
    Hi , I am new to Netcode for game objects.

    Recently, I tested NetworkVariable functionality in both MLAPI 0.1.0 and Netcode 1.0.0. In my project, I tried to create a scene "Start Point" for handling server connection. Then, I created a Lobby scene to manage the names of connected players.

    In StartPoint Scene, input field will be provided to enter text. In Lobby scene, the TextUI will be update when NetworkVariable is changed, and clients who are joining server will modify NetworkVariable<FixedString64Bytes> by their text in StartPoint scene .

    The problem is, when using Netcode 1.0.0, as mentioned in title, NetworkVariables from clients/ host does not sync together. My current solution is, I need to call ServerRpc--> ClientRpc to manage variable changes.

    Here is my setting from inspector:
    螢幕截圖 2021-11-09 下午10.20.21.png
    Here is my code:
    Code (CSharp):
    1. using UnityEngine;
    2. using Unity.Netcode;
    3. using UnityEngine.SceneManagement;
    4. using Unity.Collections;
    5. using TMPro;
    6.  
    7. public class StartPoint : NetworkBehaviour
    8. {
    9.     public TMP_InputField YourName_Field;
    10.  
    11.     [SerializeField]
    12.     public static string YourName;
    13.  
    14.     // a variable belongs to one client and can be read by all clients
    15.     public static NetworkVariable<FixedString64Bytes> PlayerName = new NetworkVariable<FixedString64Bytes>();    
    16.  
    17.     public static StartPoint singleton = null;
    18.  
    19.     public GameObject SetActivePanel;
    20.  
    21.     public void Awake()
    22.     {
    23.         DontDestroyOnLoad(this.gameObject);
    24.         if(singleton == null)
    25.         {
    26.             singleton = this;
    27.         }
    28.         else if (singleton != this)
    29.         {
    30.             Debug.Log("destroy");
    31.             Destroy(this);
    32.         }
    33.  
    34.     }
    35.  
    36.     public void StartHost()
    37.     {
    38.         NetworkManager.Singleton.StartHost();
    39.         InitPlayerName();
    40.         NetworkManager.Singleton.SceneManager.SetClientSynchronizationMode(LoadSceneMode.Single);
    41.         Debug.Log("starthost");
    42.         SetActivePanel.SetActive(false);
    43.         NetworkManager.Singleton.SceneManager.LoadScene("Lobby" , LoadSceneMode.Single);
    44.     }
    45.  
    46.  
    47.     public void StartClient()
    48.     {
    49.         NetworkManager.Singleton.StartClient();
    50.         InitPlayerName();
    51.         Debug.Log("Start Client");
    52.         SetActivePanel.SetActive(false);
    53.         NetworkManager.Singleton.SceneManager.SetClientSynchronizationMode(LoadSceneMode.Single);
    54.  
    55.     }
    56.  
    57.     [ServerRpc(RequireOwnership =false)]
    58.     public void WriteStringServerRpc(string name)          
    59.     {
    60.         PlayerName.Value = name;
    61.         PrintNetworkVariableValueClientRpc();
    62.         //WriteStringClientRpc(name);                          
    63.     }
    64.     //testing function
    65.     [ClientRpc]
    66.     public void PrintNetworkVariableValueClientRpc()
    67.     {
    68.         Debug.Log(PlayerName.Value);
    69.     }
    70.  
    71.     [ClientRpc]
    72.     public void WriteStringClientRpc(string name)
    73.     {
    74.         PlayerName.Value = name;
    75.     }
    76.  
    77.     // set your name
    78.     public void InitPlayerName()
    79.     {
    80.         YourName = YourName_Field.text;
    81.     }
    82. }
    Code (CSharp):
    1. public class LobbyStart : NetworkBehaviour
    2. {
    3.     // the text that display player name
    4.     [SerializeField]
    5.     public TextMeshProUGUI PlayerText;
    6.  
    7.     int i = 1;
    8.     private void Awake()
    9.     {
    10.         PlayerText = GameObject.Find("PlayerName").GetComponent<TextMeshProUGUI>();
    11.     }
    12.     public void Start2()
    13.     {
    14.         StartPoint.PlayerName.OnValueChanged += HandleNameChange;           // listener
    15.         StartPoint.singleton.WriteStringServerRpc(StartPoint.YourName);
    16.         Debug.Log("Current PlayerName is : " + StartPoint.PlayerName.Value);
    17.     }
    18.     public override void OnNetworkSpawn()
    19.     {
    20.         StartPoint.PlayerName.OnValueChanged += HandleNameChange;           // listener
    21.         StartPoint.singleton.WriteStringServerRpc(StartPoint.YourName);
    22.         Debug.Log("Current PlayerName is : " + StartPoint.PlayerName.Value);
    23.     }
    24.     public override void OnDestroy()
    25.     {
    26.         Debug.Log("OnDestroy");
    27.         StartPoint.PlayerName.OnValueChanged -= HandleNameChange;
    28.     }
    29.  
    30.     public void ChangeNetworkVariableButton()
    31.     {
    32.         StartPoint.singleton.WriteStringServerRpc("test" + i.ToString());         //called by client , excuted on host/server
    33.         i++;
    34.     }
    35.  
    36.     private void HandleNameChange(FixedString64Bytes previousValue, FixedString64Bytes newValue)
    37.     {
    38.        PlayerText.text = newValue.ToString();
    39.         Debug.Log("HandleName Change , " + " The Name is :" + newValue);
    40.  
    41.     }
    42. }
    Anything missing?
     
  2. keksuyt

    keksuyt

    Joined:
    Dec 10, 2021
    Posts:
    2
    For me I'm using UnityID's and I made "PlayerHUD" script and attached it to player with gameobject "PlayerInfo" as children and that gameobject had textmeshpro component.

    upload_2021-12-15_9-22-17.png

    I'm not sure how to fix you're code but this was my solution for usernames.

    Code (CSharp):
    1.  
    2. using TMPro;
    3. using Unity.Netcode;
    4. using UnityEngine;
    5. using UnityEngine.SceneManagement;
    6. using Unity.Collections;
    7. using System.Threading.Tasks;
    8. using System.Collections.Generic;
    9. using Unity.Services.Authentication;
    10. using Unity.Services.CloudSave;
    11. using Unity.Services.Core;
    12. using Unity.Services.Core.Environments;
    13.  
    14. public class PlayerHud : NetworkBehaviour
    15. {
    16.   [SerializeField]
    17.   private NetworkVariable<NetworkString> playerNetworkName = new NetworkVariable<NetworkString>();
    18.  
    19.   [SerializeField]
    20.   private bool overlaySet = false;
    21.  
    22.   [SerializeField]
    23.   private string PlayerName;
    24.  
    25.   public async override void OnNetworkSpawn()
    26.   {
    27.     Dictionary<string, string> usernameData = await SaveData.LoadAsync(new HashSet<string> {"username"});
    28.     PlayerName = usernameData["username"];
    29.     Debug.LogWarning($"Got username: {PlayerName}");
    30.  
    31.     if(!string.IsNullOrEmpty(PlayerName))
    32.     {
    33.         SetNameServerRpc(PlayerName);
    34.         Debug.LogWarning($"Sending RPC");
    35.     }
    36.       //if(IsServer)
    37.       //{
    38.         //  playerNetworkName.Value = $"Player {PlayerName}";
    39.       //    Debug.LogWarning($"Username Check as Server: {PlayerName}");
    40.       //}
    41.  
    42.   }
    43.  
    44.   public void SetOverlay()
    45.   {
    46.       var localPlayerOverlay = gameObject.GetComponentInChildren<TextMeshPro>();
    47.       localPlayerOverlay.text = $"{playerNetworkName.Value}";
    48.   }
    49.  
    50.   public void Update()
    51.   {
    52.       if(!overlaySet && !string.IsNullOrEmpty(playerNetworkName.Value))
    53.       {
    54.           SetOverlay();
    55.           overlaySet = true;
    56.       }
    57.   }
    58.  
    59.   [ServerRpc/*(RequireOwnership = false)*/]
    60.   public void SetNameServerRpc(string UserName)
    61.   {
    62.     Debug.LogWarning($"RPC reached");
    63.     Debug.LogWarning($"Username Check as Server: {UserName}");
    64.     playerNetworkName.Value = $"{UserName}";
    65.     Debug.LogWarning($"Changed NetworkVariable to {playerNetworkName.Value}");
    66.   }
    67. }
    68.  
    EDIT:
    Also I forgot about NetworkString.cs which I imported Assets/Scripts/Shared

    Code (CSharp):
    1. using Unity.Collections;
    2. using Unity.Netcode;
    3.  
    4. public struct NetworkString : INetworkSerializable
    5. {
    6.     private FixedString32Bytes info;
    7.     public void NetworkSerialize<T>(BufferSerializer<T> serializer) where T : IReaderWriter
    8.     {
    9.         serializer.SerializeValue(ref info);
    10.     }
    11.  
    12.     public override string ToString()
    13.     {
    14.         return info.ToString();
    15.     }
    16.  
    17.     public static implicit operator string(NetworkString s) => s.ToString();
    18.     public static implicit operator NetworkString(string s) => new NetworkString() { info = new FixedString32Bytes(s) };
    19. }
    20.  
    EDIT: (Again I'm sry)

    But I fixed in that code the "" marks in names so I'ma just drop the new code here
    Code (CSharp):
    1. using TMPro;
    2. using Unity.Netcode;
    3. using UnityEngine;
    4. using UnityEngine.SceneManagement;
    5. using Unity.Collections;
    6. using System.Threading.Tasks;
    7. using System.Collections.Generic;
    8. using Unity.Services.Authentication;
    9. using Unity.Services.CloudSave;
    10. using Unity.Services.Core;
    11. using Unity.Services.Core.Environments;
    12. using System;
    13.  
    14. public class PlayerHud : NetworkBehaviour
    15. {
    16.   [SerializeField]
    17.   private NetworkVariable<NetworkString> playerNetworkName = new NetworkVariable<NetworkString>();
    18.  
    19.   [SerializeField]
    20.   private bool overlaySet = false;
    21.  
    22.   [SerializeField]
    23.   private string PlayerName;
    24.  
    25.   [SerializeField]
    26.   private string playerName;
    27.  
    28.   public async override void OnNetworkSpawn()
    29.   {
    30.     Dictionary<string, string> usernameData = await SaveData.LoadAsync(new HashSet<string> {"username"});
    31.     PlayerName = usernameData["username"];
    32.     playerName = PlayerName.Trim( new Char[] {'"', '.' } );
    33.     Debug.LogWarning($"Got username: {playerName}");
    34.  
    35.     if(!string.IsNullOrEmpty(playerName))
    36.     {
    37.         SetNameServerRpc(playerName);
    38.         Debug.LogWarning($"Sending RPC");
    39.     }
    40.       //if(IsServer)
    41.       //{
    42.         //  playerNetworkName.Value = $"Player {PlayerName}";
    43.       //    Debug.LogWarning($"Username Check as Server: {PlayerName}");
    44.       //}
    45.  
    46.   }
    47.  
    48.   public void SetOverlay()
    49.   {
    50.       var localPlayerOverlay = gameObject.GetComponentInChildren<TextMeshPro>();
    51.       localPlayerOverlay.text = $"{playerNetworkName.Value}";
    52.   }
    53.  
    54.   public void Update()
    55.   {
    56.       if(!overlaySet && !string.IsNullOrEmpty(playerNetworkName.Value))
    57.       {
    58.           SetOverlay();
    59.           overlaySet = true;
    60.       }
    61.   }
    62.  
    63.   [ServerRpc/*(RequireOwnership = false)*/]
    64.   public void SetNameServerRpc(string UserName)
    65.   {
    66.     Debug.LogWarning($"RPC reached");
    67.     Debug.LogWarning($"Username Check as Server: {UserName}");
    68.     playerNetworkName.Value = $"{UserName}";
    69.     Debug.LogWarning($"Changed NetworkVariable to {playerNetworkName.Value}");
    70.   }
    71. }
    72.  
     
    Last edited: Dec 15, 2021
unityunity