Skip to content

Commit 0ced5ce

Browse files
committed
Refactor and unify the ChangeOwnership message sending
1 parent f99e914 commit 0ced5ce

File tree

1 file changed

+74
-98
lines changed

1 file changed

+74
-98
lines changed

com.unity.netcode.gameobjects/Runtime/Spawning/NetworkSpawnManager.cs

Lines changed: 74 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using System.Collections.Generic;
33
using System.Diagnostics.CodeAnalysis;
44
using System.Linq;
5+
using System.Runtime.CompilerServices;
56
using System.Text;
67
using UnityEngine;
78

@@ -443,10 +444,12 @@ internal void ChangeOwnership(NetworkObject networkObject, ulong clientId, bool
443444
return;
444445
}
445446

447+
var distributedAuthorityMode = NetworkManager.DistributedAuthorityMode;
448+
446449
// For client-server:
447450
// If ownership changes faster than the latency between the client-server and there are NetworkVariables being updated during ownership changes,
448451
// then notify the user they could potentially lose state updates if developer logging is enabled.
449-
if (NetworkManager.LogLevel == LogLevel.Developer && !NetworkManager.DistributedAuthorityMode && m_LastChangeInOwnership.ContainsKey(networkObject.NetworkObjectId) && m_LastChangeInOwnership[networkObject.NetworkObjectId] > Time.realtimeSinceStartup)
452+
if (NetworkManager.LogLevel == LogLevel.Developer && !distributedAuthorityMode && m_LastChangeInOwnership.ContainsKey(networkObject.NetworkObjectId) && m_LastChangeInOwnership[networkObject.NetworkObjectId] > Time.realtimeSinceStartup)
450453
{
451454
for (int i = 0; i < networkObject.ChildNetworkBehaviours.Count; i++)
452455
{
@@ -458,7 +461,7 @@ internal void ChangeOwnership(NetworkObject networkObject, ulong clientId, bool
458461
}
459462
}
460463

461-
if (NetworkManager.DistributedAuthorityMode)
464+
if (distributedAuthorityMode)
462465
{
463466
// Ensure only the session owner can change ownership (i.e. acquire) and that the session owner is not trying to assign a non-session owner client
464467
// ownership of a NetworkObject with SessionOwner permissions.
@@ -523,15 +526,6 @@ internal void ChangeOwnership(NetworkObject networkObject, ulong clientId, bool
523526
throw new SpawnStateException("Object is not spawned");
524527
}
525528

526-
if (networkObject.OwnerClientId == clientId && networkObject.PreviousOwnerId == clientId)
527-
{
528-
if (NetworkManager.LogLevel == LogLevel.Developer)
529-
{
530-
NetworkLog.LogWarningServer($"[Already Owner] Unnecessary ownership change for {networkObject.name} as it is already the owned by client-{clientId}");
531-
}
532-
return;
533-
}
534-
535529
if (!networkObject.Observers.Contains(clientId))
536530
{
537531
if (NetworkManager.LogLevel == LogLevel.Developer)
@@ -560,91 +554,8 @@ internal void ChangeOwnership(NetworkObject networkObject, ulong clientId, bool
560554
networkObject.SynchronizeOwnerNetworkVariables(originalOwner, originalPreviousOwnerId);
561555
}
562556

563-
var size = 0;
564-
565-
if (NetworkManager.DistributedAuthorityMode)
566-
{
567-
var message = new ChangeOwnershipMessage
568-
{
569-
ChangeMessageType = isRequestApproval ? ChangeOwnershipMessage.ChangeType.RequestApproved : ChangeOwnershipMessage.ChangeType.OwnershipChanging,
570-
NetworkObjectId = networkObject.NetworkObjectId,
571-
OwnerClientId = networkObject.OwnerClientId,
572-
DistributedAuthorityMode = true,
573-
RequestClientId = networkObject.PreviousOwnerId,
574-
OwnershipFlags = (ushort)networkObject.Ownership,
575-
};
576-
577-
// If we are connected to the CMB service or not the DAHost (i.e. pure DA-Clients only)
578-
if (NetworkManager.CMBServiceConnection || !NetworkManager.DAHost)
579-
{
580-
// Calculate valid target client identifiers that should receive this change in ownership message.
581-
var clientIds = new List<ulong>(NetworkManager.ConnectedClientsIds.Count);
582-
foreach (var id in NetworkManager.ConnectedClientsIds)
583-
{
584-
if (id == NetworkManager.LocalClientId)
585-
{
586-
continue;
587-
}
588-
589-
if (networkObject.IsNetworkVisibleTo(id) && !IsObjectVisibilityPending(id, ref networkObject))
590-
{
591-
clientIds.Add(id);
592-
}
593-
}
594-
595-
// Don't send the message if there are no valid receivers
596-
if (clientIds.Count > 0)
597-
{
598-
message.ClientIds = clientIds.ToArray();
599-
message.ClientIdCount = clientIds.Count;
600-
601-
size = NetworkManager.ConnectionManager.SendMessage(ref message, NetworkDelivery.ReliableSequenced, NetworkManager.ServerClientId);
602-
NetworkManager.NetworkMetrics.TrackOwnershipChangeSent(NetworkManager.LocalClientId, networkObject, size);
603-
}
604-
}
605-
else // We are the DAHost so broadcast the ownership change
606-
{
607-
foreach (var client in NetworkManager.ConnectedClients)
608-
{
609-
if (client.Value.ClientId == NetworkManager.ServerClientId || IsObjectVisibilityPending(client.Key, ref networkObject))
610-
{
611-
continue;
612-
}
613-
614-
if (networkObject.IsNetworkVisibleTo(client.Value.ClientId))
615-
{
616-
size = NetworkManager.ConnectionManager.SendMessage(ref message, NetworkDelivery.ReliableSequenced, client.Value.ClientId);
617-
NetworkManager.NetworkMetrics.TrackOwnershipChangeSent(client.Key, networkObject, size);
618-
}
619-
}
620-
}
621-
}
622-
else // Normal Client-Server mode
623-
{
624-
var message = new ChangeOwnershipMessage
625-
{
626-
ChangeMessageType = ChangeOwnershipMessage.ChangeType.OwnershipChanging,
627-
NetworkObjectId = networkObject.NetworkObjectId,
628-
OwnerClientId = networkObject.OwnerClientId,
629-
};
630-
foreach (var client in NetworkManager.ConnectedClients)
631-
{
632-
if (client.Value.ClientId == NetworkManager.ServerClientId || IsObjectVisibilityPending(client.Key, ref networkObject))
633-
{
634-
continue;
635-
}
636-
if (networkObject.IsNetworkVisibleTo(client.Value.ClientId))
637-
{
638-
if (client.Key != client.Value.ClientId)
639-
{
640-
NetworkLog.LogError($"[Client-{client.Key}] Client key ({client.Key}) does not match the {nameof(NetworkClient)} client Id {client.Value.ClientId}! Client-{client.Key} will not receive ownership changed message!");
641-
continue;
642-
}
643-
size = NetworkManager.ConnectionManager.SendMessage(ref message, NetworkDelivery.ReliableSequenced, client.Value.ClientId);
644-
NetworkManager.NetworkMetrics.TrackOwnershipChangeSent(client.Key, networkObject, size);
645-
}
646-
}
647-
}
557+
// Send a message to client observers
558+
SendChangeOwnershipMessage(ref networkObject, isRequestApproval);
648559

649560
// After we have sent the change ownership message to all client observers, invoke the ownership changed notification.
650561
// !!Important!!
@@ -653,7 +564,7 @@ internal void ChangeOwnership(NetworkObject networkObject, ulong clientId, bool
653564
networkObject.InvokeOwnershipChanged(networkObject.PreviousOwnerId, clientId);
654565

655566
// Keep track of the ownership change frequency to assure a user is not exceeding changes faster than 2x the current Tick Rate.
656-
if (!NetworkManager.DistributedAuthorityMode)
567+
if (!distributedAuthorityMode)
657568
{
658569
if (!m_LastChangeInOwnership.ContainsKey(networkObject.NetworkObjectId))
659570
{
@@ -671,7 +582,7 @@ internal void ChangeOwnership(NetworkObject networkObject, ulong clientId, bool
671582
/// </summary>
672583
/// <param name="clientId">the client to check</param>
673584
/// <param name="networkObject">the <see cref="NetworkObject"/> to check if it is pending show</param>
674-
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
585+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
675586
internal bool IsObjectVisibilityPending(ulong clientId, ref NetworkObject networkObject)
676587
{
677588
if (NetworkManager.DistributedAuthorityMode && ClientsToShowObject.ContainsKey(networkObject))
@@ -685,6 +596,71 @@ internal bool IsObjectVisibilityPending(ulong clientId, ref NetworkObject networ
685596
return false;
686597
}
687598

599+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
600+
private void SendChangeOwnershipMessage(ref NetworkObject networkObject, bool isRequestApproval)
601+
{
602+
var distributedAuthorityMode = NetworkManager.DistributedAuthorityMode;
603+
var daClient = distributedAuthorityMode && !NetworkManager.DAHost;
604+
605+
int size;
606+
List<ulong> targetClientIds = null;
607+
var message = new ChangeOwnershipMessage
608+
{
609+
ChangeMessageType = ChangeOwnershipMessage.ChangeType.OwnershipChanging,
610+
NetworkObjectId = networkObject.NetworkObjectId,
611+
OwnerClientId = networkObject.OwnerClientId,
612+
};
613+
614+
if (distributedAuthorityMode)
615+
{
616+
message.DistributedAuthorityMode = true;
617+
message.RequestClientId = networkObject.PreviousOwnerId;
618+
message.OwnershipFlags = (ushort)networkObject.Ownership;
619+
620+
if (isRequestApproval)
621+
{
622+
message.ChangeMessageType = ChangeOwnershipMessage.ChangeType.RequestApproved;
623+
}
624+
625+
// Allocate our targetClientIds list
626+
if (daClient)
627+
{
628+
targetClientIds = new List<ulong>(NetworkManager.ConnectedClientsIds.Count);
629+
}
630+
}
631+
632+
foreach (var id in NetworkManager.ConnectedClientsIds)
633+
{
634+
// Don't send a message to self, or to any client that either can't see the object or visibility is pending
635+
if (id == NetworkManager.LocalClientId || !networkObject.IsNetworkVisibleTo(id) || IsObjectVisibilityPending(id, ref networkObject))
636+
{
637+
continue;
638+
}
639+
640+
// If we're a DA client, calculate valid target client identifiers that should receive this change in ownership message.
641+
if (daClient)
642+
{
643+
targetClientIds.Add(id);
644+
continue;
645+
}
646+
647+
// If we're the server or DAHost, send the message directly to the client
648+
size = NetworkManager.ConnectionManager.SendMessage(ref message, NetworkDelivery.ReliableSequenced, id);
649+
NetworkManager.NetworkMetrics.TrackOwnershipChangeSent(id, networkObject, size);
650+
}
651+
652+
// If we're a DA client, now we send the message with the collectedIds to the server.
653+
if (daClient && targetClientIds.Count > 0)
654+
{
655+
message.ClientIds = targetClientIds.ToArray();
656+
message.ClientIdCount = targetClientIds.Count;
657+
658+
size = NetworkManager.ConnectionManager.SendMessage(ref message, NetworkDelivery.ReliableSequenced, NetworkManager.ServerClientId);
659+
NetworkManager.NetworkMetrics.TrackOwnershipChangeSent(NetworkManager.ServerClientId, networkObject, size);
660+
}
661+
}
662+
663+
688664
internal bool HasPrefab(NetworkObject.SceneObject sceneObject)
689665
{
690666
if (!NetworkManager.NetworkConfig.EnableSceneManagement || !sceneObject.IsSceneObject)

0 commit comments

Comments
 (0)