#Syncing usernames
1 messages · Page 1 of 1 (latest)
Post you code here and we can see what's wrong. If you are using NGO, then NetworkVariable<FixedString32Bytes> will work
Alright, if there is anything wrong with the logic, please let me know as im really not familiar with the syntax of netcode and most of the logic behind it.
I have a script JoinMenu
I've put this on my UI menu where the player can enter a name and an ip, then he presses host or connect, These buttons call the HostLobby() or ConnectLobby() functions respectively
So far the connection part works, i can connect host and client and move around freely ( Note that i have left out the animation syncing intentionally for the moment).
I basically connect the player and then switch scenes to the game scene, then i instantiate the player prefab, which is saved in a seperate script that i've just put ontop of my network manager
JoinMenu ==>
using System.Collections;
using System.Collections.Generic;
using TMPro;
using UnityEngine;
using Unity.Netcode;
using Unity.Netcode.Transports.UTP;
using UnityEngine.SceneManagement;
using System.Net;
using System.Linq;
using UnityEditor.Experimental.GraphView;
using Telepathy;
public class JoinMenu : MonoBehaviour
{
[SerializeField] private DefaultNetworkManager networkManager = null;
[SerializeField] private GameObject PagePanel = null;
[SerializeField] private TMP_Text client_name = null;
[SerializeField] private TMP_Text ip_adress = null;
public void HostLobby()
{
string ip = System.Text.RegularExpressions.Regex.Replace(ip_adress.text, "[^0-9.]", "");
string name = client_name.text.Trim();
if (!IsValidIP(ip))
{
Debug.LogError("Invalid IP Address");
return;
}
PlayerPrefs.SetString("username", client_name.text); // set name
//networkManager.GetComponent<UnityTransport>().ConnectionData.Address = ip;
//networkManager.GetComponent<UnityTransport>().ConnectionData.Port = 6666;
Debug.Log($"IP: {ip}");
var unityTransport = networkManager.GetComponent<UnityTransport>();
unityTransport.SetConnectionData(ip,7777);
//unityTransport.name = name;// experimental
networkManager.StartHost();
SceneManager.LoadScene("NetworkTestConnect");
SceneManager.sceneLoaded += OnSceneLoaded;
}
private bool IsValidIP(string ip)
{
if (string.IsNullOrWhiteSpace(ip)) return false;
var splitValues = ip.Split('.');
if (splitValues.Length != 4) return false;
byte tempForParsing;
return splitValues.All(r => byte.TryParse(r, out tempForParsing));
}
public void ConnectLobby()
{
string ip = System.Text.RegularExpressions.Regex.Replace(ip_adress.text, "[^0-9.]", "");
string name = client_name.text;
if (!IsValidIP(ip))
{
Debug.LogError("Invalid IP Address");
return;
}
var unityTransport = networkManager.GetComponent<UnityTransport>();
unityTransport.SetConnectionData(ip, 7777);
unityTransport.name = name;
networkManager.StartClient();
SceneManager.LoadScene("NetworkTestConnect");
SceneManager.sceneLoaded += OnSceneLoaded;
}
private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
{
if (scene.name == "NetworkTestConnect")
{
SceneManager.sceneLoaded -= OnSceneLoaded;
if (NetworkManager.Singleton.IsServer)
{
if (networkManager.IsHost)
{
OnClientConnected(NetworkManager.Singleton.LocalClientId);
}
NetworkManager.Singleton.OnClientConnectedCallback += OnClientConnected;
}
}
}
private void OnClientConnected(ulong clientId)
{
if (NetworkManager.Singleton.IsServer)
{
GameObject player = Instantiate(networkManager.data.PlayerPrefab);
NetworkObject networkObject = player.GetComponent<NetworkObject>();
networkObject.SpawnAsPlayerObject(clientId);
var DisplayPlayerName = player.GetComponent<DisplayPlayerName>();
DisplayPlayerName.PlayerName.Value = new NetPlayerName() { username = client_name.text };
}
}
}
DisplayerPlayerName==> (script located on the player prefab)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Unity.Networking;
using Unity.Netcode;
using TMPro;
using UnityEditor;
using Unity.Netcode.Transports.UTP;
using Unity.Collections;
using System;
public class DisplayPlayerName : Unity.Netcode.NetworkBehaviour
{
public NetworkVariable<NetPlayerName> PlayerName = new NetworkVariable<NetPlayerName>(new NetPlayerName() { username = "" });
public override void OnNetworkSpawn()
{
base.OnNetworkSpawn();
if (IsServer)
{
PlayerName.OnValueChanged += OnPlayerNameChanged;
}
}
private void OnPlayerNameChanged(NetPlayerName previousValue, NetPlayerName newValue)
{
if (IsServer)
{
Debug.Log($"Player {OwnerClientId} changed name from {previousValue.username} to {newValue.username}");
gameObject.GetComponentInChildren<TMP_Text>().text = newValue.username;
}
}
}
public struct NetPlayerName : INetworkSerializable, System.IEquatable<NetPlayerName>
{
public string username;
public bool Equals(NetPlayerName other)
{
if (String.Equals(other.username, username, StringComparison.CurrentCultureIgnoreCase))
{
return true;
}
return false;
}
public void NetworkSerialize<T>(BufferSerializer<T> serializer) where T : IReaderWriter
{
if (serializer.IsReader)
{
var reader = serializer.GetFastBufferReader();
reader.ReadValueSafe(out username);
}
else
{
var writer = serializer.GetFastBufferWriter();
writer.WriteValueSafe(username);
}
}
}
to be fair, for the DisplayPlayerName script, i was trying to use chatgpt as a guide but it didn't really work out, lol.
Im open for criticism, Any help is appreciated. i have tried using mirror for the connection part aswell but i couldn't get it to work so i just decided i'd use the default netcode from unity, since with that i can atleast get host and client connections working lol.
Ok, since you are saving the user name to player prefs. all you need to do is retrieve it in OnNetworkSpawn() and set the network variable to it. with PlayerName.Value = PlayerPrefs.GetString("username") . The tricky part is that OnValueChanged does not get called when an object first spawns so you'll also need to set the TMP text object there as well
could you elaborate on the last part of your message? I don't quite understand.
PlayerName.OnValueChanged does not get fired when the player first spawns in. the PlayerName.Value will already be the correct value. so in the Display PlayerName OnNetworkSpawn() you'll need to call GetComponentInChildren<TMP_Text>().text = PlayerName.Value in order to set the text to the player name
@timber moss I have tried doing what you said and modified the onNetworkSpawn method as following
public override void OnNetworkSpawn()
{
base.OnNetworkSpawn();
if (IsServer)
{
PlayerName.OnValueChanged += OnPlayerNameChanged;
// get the current spawned players name from playerprefs
string username = PlayerPrefs.GetString("username");
PlayerName.Value = new NetPlayerName() { username = username };
}
GetComponentInChildren<TMP_Text>().text = PlayerName.Value.username;
}
this is the current result
now names are being set for the client
but it's all just the host's name
Ah, i forgot to set playerprefs in the Connect Method , only had it in the host method
this is the curent result
left being the host, right the client
Okay, i've tried messing around with chat gpt and it actually got it to work somehow, i still don't understand what was the issue and it'd be really interesting to know
DisplayPlayerName ==>
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Unity.Networking;
using Unity.Netcode;
using TMPro;
using UnityEditor;
using Unity.Netcode.Transports.UTP;
using Unity.Collections;
using System;
public class DisplayPlayerName : Unity.Netcode.NetworkBehaviour
{
public NetworkVariable<NetPlayerName> PlayerName = new NetworkVariable<NetPlayerName>(new NetPlayerName() { username = "" });
public override void OnNetworkSpawn()
{
base.OnNetworkSpawn();
if (IsServer)
{
PlayerName.OnValueChanged += OnPlayerNameChanged;
string username = PlayerPrefs.GetString("username");
PlayerName.Value = new NetPlayerName() { username = username };
}
UpdatePlayerNameUI(PlayerName.Value.username.ToString());
}
private void OnPlayerNameChanged(NetPlayerName previousValue, NetPlayerName newValue)
{
Debug.Log($"Player {OwnerClientId} changed name from {previousValue.username} to {newValue.username}");
UpdatePlayerNameUI(newValue.username.ToString());
}
public void SetPlayerName(string name)
{
if (IsServer)
{
PlayerName.Value = new NetPlayerName() { username = name };
}
}
private void UpdatePlayerNameUI(string name)
{
GetComponentInChildren<TMP_Text>().text = name;
}
}
public struct NetPlayerName : INetworkSerializable, System.IEquatable<NetPlayerName>
{
public FixedString64Bytes username;
public bool Equals(NetPlayerName other)
{
return username.Equals(other.username);
}
public void NetworkSerialize<T>(BufferSerializer<T> serializer) where T : IReaderWriter
{
serializer.SerializeValue(ref username);
}
}
Join Menu ==>
using System.Collections;
using System.Collections.Generic;
using TMPro;
using UnityEngine;
using Unity.Netcode;
using Unity.Netcode.Transports.UTP;
using UnityEngine.SceneManagement;
using System.Net;
using System.Linq;
using UnityEditor.Experimental.GraphView;
using Telepathy;
public class JoinMenu : MonoBehaviour
{
[SerializeField] private DefaultNetworkManager networkManager = null;
[SerializeField] private GameObject PagePanel = null;
[SerializeField] private TMP_Text client_name = null;
[SerializeField] private TMP_Text ip_adress = null;
public void HostLobby()
{
string ip = System.Text.RegularExpressions.Regex.Replace(ip_adress.text, "[^0-9.]", "");
string name = client_name.text.Trim();
if (!IsValidIP(ip))
{
Debug.LogError("Invalid IP Address");
return;
}
PlayerPrefs.SetString("username", name); // set name
var unityTransport = networkManager.GetComponent<UnityTransport>();
unityTransport.SetConnectionData(ip, 7777);
networkManager.StartHost();
SceneManager.LoadScene("NetworkTestConnect");
SceneManager.sceneLoaded += OnSceneLoaded;
}
private bool IsValidIP(string ip)
{
if (string.IsNullOrWhiteSpace(ip)) return false;
var splitValues = ip.Split('.');
if (splitValues.Length != 4) return false;
return splitValues.All(r => byte.TryParse(r, out _));
}
public void ConnectLobby()
{
string ip = System.Text.RegularExpressions.Regex.Replace(ip_adress.text, "[^0-9.]", "");
string name = client_name.text.Trim();
if (!IsValidIP(ip))
{
Debug.LogError("Invalid IP Address");
return;
}
PlayerPrefs.SetString("username", name); // set name
var unityTransport = networkManager.GetComponent<UnityTransport>();
unityTransport.SetConnectionData(ip, 7777);
networkManager.StartClient();
SceneManager.LoadScene("NetworkTestConnect");
SceneManager.sceneLoaded += OnSceneLoaded;
}
private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
{
if (scene.name == "NetworkTestConnect")
{
SceneManager.sceneLoaded -= OnSceneLoaded;
if (NetworkManager.Singleton.IsServer)
{
OnClientConnected(NetworkManager.Singleton.LocalClientId);
NetworkManager.Singleton.OnClientConnectedCallback += OnClientConnected;
}
}
}
private void OnClientConnected(ulong clientId)
{
if (NetworkManager.Singleton.IsServer)
{
GameObject player = Instantiate(networkManager.data.PlayerPrefab);
NetworkObject networkObject = player.GetComponent<NetworkObject>();
networkObject.SpawnAsPlayerObject(clientId);
var displayPlayerName = player.GetComponent<DisplayPlayerName>();
displayPlayerName.SetPlayerName(PlayerPrefs.GetString("username"));
}
}
}
this is how I do it
public class NetworkPlayer : NetworkBehaviour
{
public NetworkVariable<FixedString32Bytes> DisplayName = new();
public LocalPlayerData_SO LocalPlayer;
public override void OnNetworkSpawn()
{
DisplayName.OnValueChanged += (_, player) =>
{
UpdateName(player.ToString());
};
if (HasAuthority)
{
DisplayName.Value = LocalPlayer.Data.UserName;
}
else
{
UpdateName(DisplayName.Value.ToString());
}
}
private void UpdateName(string name)
{
GetComponentInChildren<TMP_Text>().text = name;
}
}
if i were to handle player prefabs, (which are set locally before i call startClient() or starthost(), would i need to use network variables or anything?
I tried doing it like this:
public void SetPlayerGameObject(Character prefab)
{
networkManager.data.PlayerPrefab = prefab;
}
// this method is inside the JoinMenu Script
public class CharacterButtonHandler : MonoBehaviour
{
[SerializeField]List<Button> characterButtons = new List<Button>();
[SerializeField] List<Character> Prefabs = new List<Character>();
[SerializeField] public JoinMenu joinMenu = null;
private void Start()
{
foreach (Button button in characterButtons)
{
button.onClick.AddListener(() => joinMenu.SetPlayerGameObject(Prefabs[characterButtons.IndexOf(button)]));
}
}
}
Currently it just takes the prefab selected by the host for all the clients
no matter what the client picks
Prefab is taken in the onClientConnected via networkManager.data.PlayerPrefab.characterPrefab
Yea. you would need to send the index of the Prefabs list the player chose either in an RPC or in a Network Variable