Unity 6
Netcode 2.2.0
For a little multiplayer project, i am trying to keep track of the names of players (that the clients can enter when connecting) in a static NetworkList that holds a serialized struct PlayerData:
public struct PlayerData : IEquatable<PlayerData>, INetworkSerializable
{
public ulong clientID;
public FixedString32Bytes playerName;
public bool Equals(PlayerData other)
{
return clientID == other.clientID &&
playerName == other.playerName;
}
public void NetworkSerialize<T>(BufferSerializer<T> serializer) where T : IReaderWriter
{
serializer.SerializeValue(ref clientID);
serializer.SerializeValue(ref playerName);
}
}
The NetworkList is initialized directly:
private static NetworkList<PlayerData> playerDataNetworkList = new();
And after the Host approves the client connection, a new PlayerData (name of the player is sent in ConnectionData) is created and added to the list:
private void NetworkManager_ConnectionApprovalCallback(NetworkManager.ConnectionApprovalRequest request, NetworkManager.ConnectionApprovalResponse response)
{
string requestPlayerName = Encoding.ASCII.GetString(request.Payload);
Debug.LogFormat($"{ConnectionPrefix} Server receives request of {requestPlayerName} from {request.ClientNetworkId}; isHost: {request.ClientNetworkId == NetworkManager.Singleton.LocalClientId}");
if(request.ClientNetworkId == NetworkManager.Singleton.LocalClientId) //If connection is host, always approve
{
//Host was already added to playerDataList in StartHost()
Debug.LogFormat($"{ConnectionPrefix} AUTO APPROVED Host");
response.Approved = true;
return;
}
else
{
if(playerDataNetworkList.Count >= 4)
{
response.Approved = false;
return;
}
response.Approved = true;
AddToPlayerList(requestPlayerName, request.ClientNetworkId);
}
}
The Host is adding himself to this list directly after calling StartHost on the NetworkManager.
The callback subscriptions are as follows:
Host:
public void StartHost(string playerName = "Host")
{
NetworkManager.Singleton.ConnectionApprovalCallback += NetworkManager_ConnectionApprovalCallback;
NetworkManager.Singleton.OnClientConnectedCallback += NetworkManager_OnClientConnectedCallback;
NetworkManager.Singleton.OnClientDisconnectCallback += NetworkManager_Server_OnClientDisconnectCallback;
Debug.LogFormat($"{ConnectionPrefix} Starting Host");
NetworkManager.Singleton.StartHost();
Debug.LogFormat($"{ConnectionPrefix} Adding Host to playerList");
AddToPlayerList(playerName, OwnerClientId);
}
Client
public void StartClient()
{
Debug.LogFormat($"{ConnectionPrefix} Trying to join game");
NetworkManager.Singleton.OnClientDisconnectCallback += NetworkManager_Client_OnClientDisconnectCallback;
NetworkManager.Singleton.OnClientConnectedCallback += Client_OnClientConnectedCallback;
NetworkManager.Singleton.NetworkConfig.ConnectionData = Encoding.ASCII.GetBytes("Client");
Debug.LogFormat($"{ConnectionPrefix} Starting Client");
NetworkManager.Singleton.StartClient();
}
Both OnNetworkSpawn:
public override void OnNetworkSpawn()
{
playerDataNetworkList.OnListChanged += PlayerDataNetworkList_OnListChanged;
}
Which will call PlayerDataNetworkList_OnListChanged, which i intend to fire an event to handle name changes for example. The Invoked event here is not important right now, but i added a Debug.Log to cross check the change on the Client:
private void PlayerDataNetworkList_OnListChanged(NetworkListEvent<PlayerData> changeEvent)
{
Debug.LogFormat($"{ConnectionPrefix} PLAYERLIST CHANGED {changeEvent.Type} -> Value playerName {changeEvent.Value.playerName}/Client {changeEvent.Value.clientID} -- at Index {changeEvent.Index}, count now: {playerDataNetworkList.Count}");
OnPlayerDataNetworkListChanged?.Invoke(this, EventArgs.Empty);
}
For testing i use the multiplayer playmode of Unity.
I start the host and join with the client and get the following outputs:
On the Host:
And on the Client:
Now my question is: Why does the Client have three entries in the playerDataList, while the host only has the two? Why are there two entries for clientID 1 (with name “Client”)? Shouldnt it be synched with the Host, as the Client doesnt have any write permissions to the NetworkList?
I wanted to make sure there is nothing wrong with my PlayerData, so i created another NetworkList that just holds Integers, but i get the same result in having the second entry duplicated on the Client side.
I created a repository for anyone that wants to check the project:
Am i missing something here? What should i be doing different?
Help is much appreciated