-
Notifications
You must be signed in to change notification settings - Fork 438
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
NetworkList Sometimes Goes Out of Sync in Distributed Authority Setup #3280
Comments
@nikajavakha Optionally, you might try an alternate approach like this: /// <summary>
/// Assuming this is on an in-scene placed NetworkObject
/// </summary>
public class NetworkPlayerManager : NetworkBehaviour
{
private NetworkVariable<Dictionary<ulong, PlayerConnection>> connectedPlayers = new NetworkVariable<Dictionary<ulong, PlayerConnection>>(new Dictionary<ulong, PlayerConnection>());
private ulong LastKnownSessionOwner;
public override void OnNetworkSpawn()
{
NetworkManager.OnSessionOwnerPromoted += NetworkManager_OnSessionOwnerPromoted;
LastKnownSessionOwner = NetworkManager.CurrentSessionOwner;
if (NetworkManager.LocalClient.IsSessionOwner)
{
NetworkManager.OnConnectionEvent += NetworkManager_OnConnectionEvent;
}
else
{
connectedPlayers.OnValueChanged += OnconnectedPlayersChanged;
}
}
/// <summary>
/// Upon a new session owner being promoted due to the previous one having disconnected,
/// register for connection events and take over tracking connected players.
/// </summary>
private void NetworkManager_OnSessionOwnerPromoted(ulong sessionOwnerPromoted)
{
if (NetworkManager.LocalClientId == sessionOwnerPromoted)
{
connectedPlayers.OnValueChanged -= OnconnectedPlayersChanged;
NetworkManager.OnConnectionEvent += NetworkManager_OnConnectionEvent;
// Handle removing the previous session owner
if (connectedPlayers.Value.ContainsKey(LastKnownSessionOwner))
{
connectedPlayers.Value.Remove(LastKnownSessionOwner);
connectedPlayers.CheckDirtyState();
}
}
LastKnownSessionOwner = sessionOwnerPromoted;
}
protected override void OnNetworkSessionSynchronized()
{
// Each non-sessioin owner client will log all connected players upon finishing synchronization
LogConnectedPlayers();
base.OnNetworkSessionSynchronized();
}
private void NetworkManager_OnConnectionEvent(NetworkManager networkManager, ConnectionEventData eventData)
{
switch(eventData.EventType)
{
case ConnectionEvent.PeerConnected:
{
// Add player info
connectedPlayers.Value.Add(eventData.ClientId, new PlayerConnection()
{
ClientId = eventData.ClientId,
});
connectedPlayers.CheckDirtyState();
break;
}
case ConnectionEvent.PeerDisconnected:
{
// Remove player
connectedPlayers.Value.Remove(eventData.ClientId);
connectedPlayers.CheckDirtyState();
break;
}
}
}
private void LogConnectedPlayers()
{
Debug.Log($"ConnectedPlayerClientIds: {string.Join(",", connectedPlayers.Value.Values.Select(c => c.ClientId))}");
}
private void OnconnectedPlayersChanged(Dictionary<ulong, PlayerConnection> previous, Dictionary<ulong, PlayerConnection> current)
{
LogConnectedPlayers();
}
} |
I listen for SceneEvent on the session owner's side. If the event is LoadComplete, I spawn a NetworkPlayer for the SessionOwner. If the event is SynchronizeComplete, I spawn a NetworkPlayer for the connected client. Then, each NetworkPlayer, after spawning, sends its PlayerId and PlayerName to the session owner, who adds it to the connectedPlayers list. First, I am hosting a game, so the session owner is connected and ready. Then, I open multiple game instances simultaneously to join the session. However, the network list often goes out of sync by that time (I run all instances on the same machine at the same time, and sometimes the CPU briefly reaches 100%). However, if I open the game instances with a 2–3 second delay, everything works correctly. During the mid-game, the network list also remains properly synchronized—I haven't noticed any issues. Note: NetworkManager.Singleton.ConnectedClientIds is always correct, even when I open game instances simultaneously. here is pseudo code: public class NetworkPlayerManager : NetworkBehaviour
{
private void OnSceneEvent(SceneEvent sceneEvent)
{
Debug.Log($"SceneEventType: {sceneEvent.SceneEventType} | ConnectedPlayerClientIds: {string.Join(",", connectedPlayers.ToList().Select(c => c.ClientId))}")
if (!NetworkManager.LocalClient.IsSessionOwner)
return;
switch (sceneEvent.SceneEventType)
{
case SceneEventType.LoadComplete:
// spawn session owner
if (sceneEvent.ClientId == NetworkManager.LocalClientId && !HasConnectedPlayer(sceneEvent.ClientId))
{
SpawnNetworkPlayer(sceneEvent.ClientId);
}
break;
case SceneEventType.SynchronizeComplete:
//spawn peer client
SpawnNetworkPlayer(sceneEvent.ClientId);
break;
}
}
private void SpawnNetworkPlayer(ulong clientId)
{
var networkPlayer = Instantiate(networkPlayerPrefab);
networkPlayer.NetworkObject.SpawnWithOwnership(clientId);
}
[Rpc(SendTo.Authority)]
public void RegisterPlayerAuthorityRpc(PlayerConnection playerConnection, RpcParams rpcParams = default)
{
connectedPlayers.Add(playerConnection);
}
public bool HasConnectedPlayer(ulong clientId)
{
foreach (var player in connectedPlayers)
{
if (player.ClientId == clientId)
return true;
}
return false;
}
}
public class NetworkPlayer : NetworkBehaviour
{
public override void OnNetworkSpawn(){
if (IsOwner){
var playerId = AuthenticationService.Instance.PlayerId
var playerName = AuthenticationService.Instance.Profile;
var playerConnection = new PlayerConnection(OwnerClientId, playerId, playerName, NetworkObject);
NetworkPlayerManager.Instance.RegisterPlayerAuthorityRpc(playerConnection);
}
}
} |
Description
In a distributed authority setup, I noticed that the NetworkList sometimes goes out of sync. For example, I have a private NetworkList called connectedPlayers. I built the game and ran three instances, where Client 1 was the session owner. Only the session owner is allowed to update connectedPlayers.
For each client connection, I added the new PlayerConnection from the session owner's side. Initially, it logged correctly for the first two clients as:
SceneEventType: SynchronizeComplete | ConnectedPlayerClientIds: 1,3,2
However, for the third client, the log showed:
SceneEventType: SynchronizeComplete | ConnectedPlayerClientIds: 1,3,2,3,2
indicating that some entries were duplicated. this not happens often(mostly happens when I run multiple built instances simultaneously, causing my PC's CPU usage to reach 100%.) so it's hard to reproduce but it makes me feel that NetworkList is unreliable to use. Is there any alternative of NetworkList? or if not could this be indicating bug in NGO?
Environment
The text was updated successfully, but these errors were encountered: