Skip to content

Commit

Permalink
fix
Browse files Browse the repository at this point in the history
This fixes most of the synchronization issues with using a distributed authority network topology and scene management is disabled.
(There still is some form of issue with changing ownership when distributing objects)
  • Loading branch information
NoelStephensUnity committed Nov 21, 2024
1 parent 90f97fd commit 311216b
Show file tree
Hide file tree
Showing 5 changed files with 69 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -1001,6 +1001,14 @@ internal NetworkClient AddClient(ulong clientId)
}

var distributedAuthority = NetworkManager.DistributedAuthorityMode;

// If not using DA return early or if using DA and scene management is disabled then exit early Since we use NetworkShow to spawn
// objects on the newly connected client side.
if (!distributedAuthority || distributedAuthority && !NetworkManager.NetworkConfig.EnableSceneManagement)
{
return networkClient;
}

var sessionOwnerId = NetworkManager.CurrentSessionOwner;
var isSessionOwner = NetworkManager.LocalClient.IsSessionOwner;
foreach (var networkObject in NetworkManager.SpawnManager.SpawnedObjectsList)
Expand Down
10 changes: 5 additions & 5 deletions com.unity.netcode.gameobjects/Runtime/Core/NetworkObject.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2894,7 +2894,7 @@ internal SceneObject GetMessageSceneObject(ulong targetClientId = NetworkManager
SyncObservers = syncObservers,
Observers = syncObservers ? Observers.ToArray() : null,
NetworkSceneHandle = NetworkSceneHandle,
Hash = HostCheckForGlobalObjectIdHashOverride(),
Hash = CheckForGlobalObjectIdHashOverride(),
OwnerObject = this,
TargetClientId = targetClientId
};
Expand Down Expand Up @@ -3246,14 +3246,14 @@ internal void UpdateForSceneChanges()
}

/// <summary>
/// Only applies to Host mode.
/// Only applies to Hosts or session owners (for now)
/// Will return the registered source NetworkPrefab's GlobalObjectIdHash if one exists.
/// Server and Clients will always return the NetworkObject's GlobalObjectIdHash.
/// </summary>
/// <returns></returns>
internal uint HostCheckForGlobalObjectIdHashOverride()
/// <returns>appropriate hash value</returns>
internal uint CheckForGlobalObjectIdHashOverride()
{
if (NetworkManager.IsServer)
if (NetworkManager.IsServer || (NetworkManager.DistributedAuthorityMode && NetworkManager.LocalClient.IsSessionOwner))
{
if (NetworkManager.PrefabHandler.ContainsHandler(this))
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -332,7 +332,7 @@ private void HandleOwnershipChange(ref NetworkContext context)
// Sanity check that we are not sending duplicated change ownership messages
if (networkObject.OwnerClientId == OwnerClientId)
{
UnityEngine.Debug.LogError($"Unnecessary ownership changed message for {NetworkObjectId}.");
UnityEngine.Debug.LogError($"Client-{context.SenderId} sent unnecessary ownership changed message for {NetworkObjectId}.");
// Ignore the message
return;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,19 +55,23 @@ public void Handle(ref NetworkContext context)
// Don't redistribute for the local instance
if (ClientId != networkManager.LocalClientId)
{
// Synchronize the client with spawned objects (relative to each client)
networkManager.SpawnManager.SynchronizeObjectsToNewlyJoinedClient(ClientId);

// Keeping for reference in case the above doesn't resolve for hidden objects (theoretically it should)
// Show any NetworkObjects that are:
// - Hidden from the session owner
// - Owned by this client
// - Has NetworkObject.SpawnWithObservers set to true (the default)
if (!networkManager.LocalClient.IsSessionOwner)
{
networkManager.SpawnManager.ShowHiddenObjectsToNewlyJoinedClient(ClientId);
}
//if (!networkManager.LocalClient.IsSessionOwner)
//{
// networkManager.SpawnManager.ShowHiddenObjectsToNewlyJoinedClient(ClientId);
//}

// We defer redistribution to the end of the NetworkUpdateStage.PostLateUpdate
networkManager.RedistributeToClient = true;
networkManager.ClientToRedistribute = ClientId;
networkManager.TickToRedistribute = networkManager.ServerTime.Tick + 20;
networkManager.TickToRedistribute = networkManager.ServerTime.Tick + (int)(0.5f * networkManager.NetworkConfig.TickRate);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -580,7 +580,6 @@ internal void ChangeOwnership(NetworkObject networkObject, ulong clientId, bool
{
networkObject.ChildNetworkBehaviours[i].UpdateNetworkProperties();
}

size = NetworkManager.ConnectionManager.SendMessage(ref message, NetworkDelivery.ReliableSequenced, NetworkManager.ServerClientId);
NetworkManager.NetworkMetrics.TrackOwnershipChangeSent(NetworkManager.LocalClientId, networkObject, size);
}
Expand Down Expand Up @@ -1976,14 +1975,14 @@ internal void NotifyNetworkObjectsSynchronized()
/// synchronizing in order to "show" (spawn) anything that might be currently hidden from
/// the session owner.
/// </summary>
/// <remarks>
/// Replacement is: SynchronizeObjectsToNewlyJoinedClient
/// </remarks>
internal void ShowHiddenObjectsToNewlyJoinedClient(ulong newClientId)
{
if (!NetworkManager.DistributedAuthorityMode)
if (NetworkManager == null || NetworkManager.ShutdownInProgress && NetworkManager.LogLevel <= LogLevel.Developer)
{
if (NetworkManager == null || !NetworkManager.ShutdownInProgress && NetworkManager.LogLevel <= LogLevel.Developer)
{
Debug.LogWarning($"[Internal Error] {nameof(ShowHiddenObjectsToNewlyJoinedClient)} invoked while !");
}
Debug.LogWarning($"[Internal Error] {nameof(ShowHiddenObjectsToNewlyJoinedClient)} invoked while shutdown is in progress!");
return;
}

Expand Down Expand Up @@ -2019,5 +2018,46 @@ internal void ShowHiddenObjectsToNewlyJoinedClient(ulong newClientId)
}
}
}

internal void SynchronizeObjectsToNewlyJoinedClient(ulong newClientId)
{
if (NetworkManager == null || NetworkManager.ShutdownInProgress && NetworkManager.LogLevel <= LogLevel.Developer)
{
Debug.LogWarning($"[Internal Error] {nameof(SynchronizeObjectsToNewlyJoinedClient)} invoked while shutdown is in progress!");
return;
}

if (!NetworkManager.DistributedAuthorityMode)
{
Debug.LogError($"[Internal Error] {nameof(SynchronizeObjectsToNewlyJoinedClient)} should only be invoked when using a distributed authority network topology!");
return;
}

if (NetworkManager.NetworkConfig.EnableSceneManagement)
{
Debug.LogError($"[Internal Error] {nameof(SynchronizeObjectsToNewlyJoinedClient)} should only be invoked when scene management is disabled!");
return;
}

var localClientId = NetworkManager.LocalClient.ClientId;
foreach (var networkObject in SpawnedObjectsList)
{
if (networkObject.SpawnWithObservers && networkObject.OwnerClientId == localClientId)
{
if (networkObject.Observers.Contains(newClientId))
{
if (NetworkManager.LogLevel <= LogLevel.Developer)
{
// Temporary tracking to make sure we are not showing something already visibile (should never be the case for this)
Debug.LogWarning($"[{nameof(SynchronizeObjectsToNewlyJoinedClient)}][{networkObject.name}] New client as already an observer!");
}
// For now, remove the client (impossible for the new client to have an instance since the session owner doesn't) to make sure newly added
// code to handle this edge case works.
networkObject.Observers.Remove(newClientId);
}
networkObject.NetworkShow(newClientId);
}
}
}
}
}

0 comments on commit 311216b

Please sign in to comment.