From e949e114d691d6e044eabfe717ccf6f0d1f93d92 Mon Sep 17 00:00:00 2001 From: Noellie Velez Date: Fri, 12 Dec 2025 18:21:46 +0100 Subject: [PATCH 01/11] chore: start optimize work + renamed SceneObject --- .../Connection/NetworkConnectionManager.cs | 12 +- .../Runtime/Core/NetworkObject.cs | 147 +++++++++--------- .../Messages/ConnectionApprovedMessage.cs | 6 +- .../Messaging/Messages/CreateObjectMessage.cs | 34 ++-- .../SceneManagement/NetworkSceneManager.cs | 6 +- .../Runtime/SceneManagement/SceneEventData.cs | 12 +- .../Runtime/Spawning/NetworkSpawnManager.cs | 68 ++++---- 7 files changed, 143 insertions(+), 142 deletions(-) diff --git a/com.unity.netcode.gameobjects/Runtime/Connection/NetworkConnectionManager.cs b/com.unity.netcode.gameobjects/Runtime/Connection/NetworkConnectionManager.cs index eea30f54b0..f64b0b1940 100644 --- a/com.unity.netcode.gameobjects/Runtime/Connection/NetworkConnectionManager.cs +++ b/com.unity.netcode.gameobjects/Runtime/Connection/NetworkConnectionManager.cs @@ -1119,15 +1119,15 @@ internal void ApprovedPlayerSpawn(ulong clientId, uint playerPrefabHash) var message = new CreateObjectMessage { - ObjectInfo = ConnectedClients[clientId].PlayerObject.GetMessageSceneObject(clientPair.Key), + ObjectSynchronizerInfo = ConnectedClients[clientId].PlayerObject.GetMessageForSynchronization(clientPair.Key), IncludesSerializedObject = true, }; - message.ObjectInfo.Hash = playerPrefabHash; - message.ObjectInfo.IsSceneObject = false; - message.ObjectInfo.HasParent = false; - message.ObjectInfo.IsPlayerObject = true; - message.ObjectInfo.OwnerClientId = clientId; + message.ObjectSynchronizerInfo.Hash = playerPrefabHash; + message.ObjectSynchronizerInfo.IsSceneObject = false; + message.ObjectSynchronizerInfo.HasParent = false; + message.ObjectSynchronizerInfo.IsPlayerObject = true; + message.ObjectSynchronizerInfo.OwnerClientId = clientId; var size = SendMessage(ref message, MessageDeliveryType.DefaultDelivery, clientPair.Key); NetworkManager.NetworkMetrics.TrackObjectSpawnSent(clientPair.Key, ConnectedClients[clientId].PlayerObject, size); } diff --git a/com.unity.netcode.gameobjects/Runtime/Core/NetworkObject.cs b/com.unity.netcode.gameobjects/Runtime/Core/NetworkObject.cs index 953781d008..f3ea99f989 100644 --- a/com.unity.netcode.gameobjects/Runtime/Core/NetworkObject.cs +++ b/com.unity.netcode.gameobjects/Runtime/Core/NetworkObject.cs @@ -2828,7 +2828,7 @@ public NetworkBehaviour GetNetworkBehaviourAtOrderIndex(ushort index) return ChildNetworkBehaviours[index]; } - internal struct SceneObject + internal struct NetworkObjectSynchronizer { private ushort m_BitField; public uint Hash; @@ -2836,38 +2836,27 @@ internal struct SceneObject public ulong OwnerClientId; public ushort OwnershipFlags; - public bool IsPlayerObject - { - get => ByteUtility.GetBit(m_BitField, 0); - set => ByteUtility.SetBit(ref m_BitField, 0, value); - } - public bool HasParent - { - get => ByteUtility.GetBit(m_BitField, 1); - set => ByteUtility.SetBit(ref m_BitField, 1, value); - } - public bool IsSceneObject - { - get => ByteUtility.GetBit(m_BitField, 2); - set => ByteUtility.SetBit(ref m_BitField, 2, value); - } - public bool HasTransform - { - get => ByteUtility.GetBit(m_BitField, 3); - set => ByteUtility.SetBit(ref m_BitField, 3, value); - } + private const ushort k_IsPlayerObject = 0x001; + private const ushort k_HasParent = 0x002; + private const ushort k_IsSceneObject = 0x004; + private const ushort k_HasTransform = 0x008; + private const ushort k_IsLatestParentSet = 0x010; + private const ushort k_WorldPositionStays = 0x020; + private const ushort k_DestroyWithScene = 0x040; + private const ushort k_DontDestroyWithOwner = 0x080; + private const ushort k_HasOwnershipFlags = 0x100; + private const ushort k_SyncObservers = 0x200; + private const ushort k_SpawnWithObservers = 0x400; + private const ushort k_HasInstantiationData = 0x800; - public bool IsLatestParentSet - { - get => ByteUtility.GetBit(m_BitField, 4); - set => ByteUtility.SetBit(ref m_BitField, 4, value); - } + public bool IsPlayerObject; + public bool HasParent; + public bool IsSceneObject; + public bool HasTransform; - public bool WorldPositionStays - { - get => ByteUtility.GetBit(m_BitField, 5); - set => ByteUtility.SetBit(ref m_BitField, 5, value); - } + public bool IsLatestParentSet; + + public bool WorldPositionStays; /// /// Even though the server sends notifications for NetworkObjects that get @@ -2875,40 +2864,52 @@ public bool WorldPositionStays /// the client side can use it as part of a filter for automatically migrating /// to the current active scene when its scene is unloaded. (only for dynamically spawned) /// - public bool DestroyWithScene - { - get => ByteUtility.GetBit(m_BitField, 6); - set => ByteUtility.SetBit(ref m_BitField, 6, value); - } + public bool DestroyWithScene; - public bool DontDestroyWithOwner - { - get => ByteUtility.GetBit(m_BitField, 7); - set => ByteUtility.SetBit(ref m_BitField, 7, value); - } + public bool DontDestroyWithOwner; - public bool HasOwnershipFlags - { - get => ByteUtility.GetBit(m_BitField, 8); - set => ByteUtility.SetBit(ref m_BitField, 8, value); - } + public bool HasOwnershipFlags; - public bool SyncObservers - { - get => ByteUtility.GetBit(m_BitField, 9); - set => ByteUtility.SetBit(ref m_BitField, 9, value); - } + public bool SyncObservers; + + public bool SpawnWithObservers; + + public bool HasInstantiationData; - public bool SpawnWithObservers + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal ushort GetBitsetRepresentation() { - get => ByteUtility.GetBit(m_BitField, 10); - set => ByteUtility.SetBit(ref m_BitField, 10, value); + ushort bitset = 0; + if(IsPlayerObject) { bitset |= k_IsPlayerObject; }; + if(HasParent) { bitset |= k_HasParent; }; + if(IsSceneObject) { bitset |= k_IsSceneObject; }; + if(HasTransform) { bitset |= k_HasTransform; }; + if(IsLatestParentSet) { bitset |= k_IsLatestParentSet; }; + if(WorldPositionStays) { bitset |= k_WorldPositionStays; }; + if(DestroyWithScene) { bitset |= k_DestroyWithScene; }; + if(DontDestroyWithOwner) { bitset |= k_DontDestroyWithOwner; }; + if(HasOwnershipFlags) { bitset |= k_HasOwnershipFlags; }; + if(SyncObservers) { bitset |= k_SyncObservers; }; + if(SpawnWithObservers) { bitset |= k_SpawnWithObservers; }; + if(HasInstantiationData) { bitset |= k_HasInstantiationData; }; + return bitset; } - public bool HasInstantiationData + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal void SetStateFromBitset(ushort bitset) { - get => ByteUtility.GetBit(m_BitField, 11); - set => ByteUtility.SetBit(ref m_BitField, 11, value); + IsPlayerObject = (bitset & k_IsPlayerObject) != 0; + HasParent = (bitset & k_HasParent) != 0; + IsSceneObject = (bitset & k_IsSceneObject) != 0; + HasTransform = (bitset & k_HasTransform) != 0; + IsLatestParentSet = (bitset & k_IsLatestParentSet) != 0; + WorldPositionStays = (bitset & k_WorldPositionStays) != 0; + DestroyWithScene = (bitset & k_DestroyWithScene) != 0; + DontDestroyWithOwner = (bitset & k_DontDestroyWithOwner) != 0; + HasOwnershipFlags = (bitset & k_HasOwnershipFlags) != 0; + SyncObservers = (bitset & k_SyncObservers) != 0; + SpawnWithObservers = (bitset & k_SpawnWithObservers) != 0; + HasInstantiationData = (bitset & k_HasInstantiationData) != 0; } // When handling the initial synchronization of NetworkObjects, @@ -3155,9 +3156,9 @@ internal void SynchronizeNetworkBehaviours(ref BufferSerializer serializer } } - internal SceneObject GetMessageSceneObject(ulong targetClientId = NetworkManager.ServerClientId, bool syncObservers = false) + internal NetworkObjectSynchronizer GetMessageForSynchronization(ulong targetClientId = NetworkManager.ServerClientId, bool syncObservers = false) { - var obj = new SceneObject + var obj = new NetworkObjectSynchronizer { HasParent = transform.parent != null, WorldPositionStays = m_CachedWorldPositionStays, @@ -3211,7 +3212,7 @@ internal SceneObject GetMessageSceneObject(ulong targetClientId = NetworkManager syncScaleLocalSpaceRelative = obj.HasParent; } - obj.Transform = new SceneObject.TransformData + obj.Transform = new NetworkObjectSynchronizer.TransformData { // If we are parented and we have the m_CachedWorldPositionStays disabled, then use local space // values as opposed world space values. @@ -3230,27 +3231,27 @@ internal SceneObject GetMessageSceneObject(ulong targetClientId = NetworkManager } /// - /// Used to deserialize a serialized scene object which occurs + /// Used to deserialize a serialized which occurs /// when the client is approved or during a scene transition /// - /// Deserialized scene object data + /// Deserialized scene object data /// FastBufferReader for the NetworkVariable data /// NetworkManager instance /// will be true if invoked by CreateObjectMessage /// The deserialized NetworkObject or null if deserialization failed - internal static NetworkObject AddSceneObject(in SceneObject sceneObject, FastBufferReader reader, NetworkManager networkManager, bool invokedByMessage = false) + internal static NetworkObject AddClientNetworkObject(in NetworkObjectSynchronizer networkObjectSynchronizer, FastBufferReader reader, NetworkManager networkManager, bool invokedByMessage = false) { - var endOfSynchronizationData = reader.Position + sceneObject.SynchronizationDataSize; + var endOfSynchronizationData = reader.Position + networkObjectSynchronizer.SynchronizationDataSize; byte[] instantiationData = null; - if (sceneObject.HasInstantiationData) + if (networkObjectSynchronizer.HasInstantiationData) { reader.ReadValueSafe(out instantiationData); } // Attempt to create a local NetworkObject - var networkObject = networkManager.SpawnManager.CreateLocalNetworkObject(sceneObject, instantiationData); + var networkObject = networkManager.SpawnManager.CreateLocalNetworkObject(networkObjectSynchronizer, instantiationData); if (networkObject == null) @@ -3258,7 +3259,7 @@ internal static NetworkObject AddSceneObject(in SceneObject sceneObject, FastBuf // Log the error that the NetworkObject failed to construct if (networkManager.LogLevel <= LogLevel.Normal) { - NetworkLog.LogError($"Failed to spawn {nameof(NetworkObject)} for Hash {sceneObject.Hash}."); + NetworkLog.LogError($"Failed to spawn {nameof(NetworkObject)} for Hash {networkObjectSynchronizer.Hash}."); } try @@ -3279,7 +3280,7 @@ internal static NetworkObject AddSceneObject(in SceneObject sceneObject, FastBuf // This will get set again when the NetworkObject is spawned locally, but we set it here ahead of spawning // in order to be able to determine which NetworkVariables the client will be allowed to read. - networkObject.OwnerClientId = sceneObject.OwnerClientId; + networkObject.OwnerClientId = networkObjectSynchronizer.OwnerClientId; // Special Case: Invoke NetworkBehaviour.OnPreSpawn methods here before SynchronizeNetworkBehaviours networkObject.InvokeBehaviourNetworkPreSpawn(); @@ -3307,7 +3308,7 @@ internal static NetworkObject AddSceneObject(in SceneObject sceneObject, FastBuf // being told we do not have a parent, then we want to clear the latest parent so it is not automatically // "re-parented" to the original parent. This can happen if not unloading the scene and the parenting of // the in-scene placed Networkobject changes several times over different sessions. - if (sceneObject.IsSceneObject && !sceneObject.HasParent && networkObject.m_LatestParent.HasValue) + if (networkObjectSynchronizer.IsSceneObject && !networkObjectSynchronizer.HasParent && networkObject.m_LatestParent.HasValue) { networkObject.m_LatestParent = null; } @@ -3320,11 +3321,11 @@ internal static NetworkObject AddSceneObject(in SceneObject sceneObject, FastBuf // Invoke the non-authority local spawn method // (It also invokes post spawn and handles processing derferred messages) - networkManager.SpawnManager.NonAuthorityLocalSpawn(networkObject, sceneObject, sceneObject.DestroyWithScene); + networkManager.SpawnManager.NonAuthorityLocalSpawn(networkObject, networkObjectSynchronizer, networkObjectSynchronizer.DestroyWithScene); - if (sceneObject.SyncObservers) + if (networkObjectSynchronizer.SyncObservers) { - foreach (var observer in sceneObject.Observers) + foreach (var observer in networkObjectSynchronizer.Observers) { networkObject.Observers.Add(observer); } @@ -3332,7 +3333,7 @@ internal static NetworkObject AddSceneObject(in SceneObject sceneObject, FastBuf if (networkManager.DistributedAuthorityMode) { - networkObject.SpawnWithObservers = sceneObject.SpawnWithObservers; + networkObject.SpawnWithObservers = networkObjectSynchronizer.SpawnWithObservers; } // If this was not invoked by a message handler, we are in distributed authority mode, and we are spawning with observers or diff --git a/com.unity.netcode.gameobjects/Runtime/Messaging/Messages/ConnectionApprovedMessage.cs b/com.unity.netcode.gameobjects/Runtime/Messaging/Messages/ConnectionApprovedMessage.cs index b54f3f7322..d80a2d084d 100644 --- a/com.unity.netcode.gameobjects/Runtime/Messaging/Messages/ConnectionApprovedMessage.cs +++ b/com.unity.netcode.gameobjects/Runtime/Messaging/Messages/ConnectionApprovedMessage.cs @@ -160,7 +160,7 @@ public void Serialize(FastBufferWriter writer, int targetVersion) { sobj.Observers.Add(OwnerClientId); // In distributed authority mode, we send the currently known observers of each NetworkObject to the client being synchronized. - var sceneObject = sobj.GetMessageSceneObject(OwnerClientId, IsDistributedAuthority); + var sceneObject = sobj.GetMessageForSynchronization(OwnerClientId, IsDistributedAuthority); sceneObject.Serialize(writer); ++sceneObjectCount; } @@ -342,9 +342,9 @@ public void Handle(ref NetworkContext context) // to create a list to hold the data. This is a breach of convention for performance reasons. for (ushort i = 0; i < sceneObjectCount; i++) { - var sceneObject = new NetworkObject.SceneObject(); + var sceneObject = new NetworkObject.NetworkObjectSynchronizer(); sceneObject.Deserialize(m_ReceivedSceneObjectData); - NetworkObject.AddSceneObject(sceneObject, m_ReceivedSceneObjectData, networkManager); + NetworkObject.AddClientNetworkObject(sceneObject, m_ReceivedSceneObjectData, networkManager); } if (networkManager.AutoSpawnPlayerPrefabClientSide) diff --git a/com.unity.netcode.gameobjects/Runtime/Messaging/Messages/CreateObjectMessage.cs b/com.unity.netcode.gameobjects/Runtime/Messaging/Messages/CreateObjectMessage.cs index 4ced00b51c..07f4c07f02 100644 --- a/com.unity.netcode.gameobjects/Runtime/Messaging/Messages/CreateObjectMessage.cs +++ b/com.unity.netcode.gameobjects/Runtime/Messaging/Messages/CreateObjectMessage.cs @@ -9,7 +9,7 @@ internal struct CreateObjectMessage : INetworkMessage private const string k_Name = "CreateObjectMessage"; - public NetworkObject.SceneObject ObjectInfo; + public NetworkObject.NetworkObjectSynchronizer ObjectSynchronizerInfo; private FastBufferReader m_ReceivedNetworkVariableData; // DA - NGO CMB SERVICE NOTES: @@ -64,7 +64,7 @@ public void Serialize(FastBufferWriter writer, int targetVersion) if (IncludesSerializedObject) { - ObjectInfo.Serialize(writer); + ObjectSynchronizerInfo.Serialize(writer); } else { @@ -113,16 +113,16 @@ public bool Deserialize(FastBufferReader reader, ref NetworkContext context, int if (IncludesSerializedObject) { - ObjectInfo.Deserialize(reader); + ObjectSynchronizerInfo.Deserialize(reader); } else { ByteUnpacker.ReadValuePacked(reader, out NetworkObjectId); } - if (!networkManager.NetworkConfig.ForceSamePrefabs && !networkManager.SpawnManager.HasPrefab(ObjectInfo)) + if (!networkManager.NetworkConfig.ForceSamePrefabs && !networkManager.SpawnManager.HasPrefab(ObjectSynchronizerInfo)) { - networkManager.DeferredMessageManager.DeferMessage(IDeferredNetworkMessageManager.TriggerType.OnAddPrefab, ObjectInfo.Hash, reader, ref context, k_Name); + networkManager.DeferredMessageManager.DeferMessage(IDeferredNetworkMessageManager.TriggerType.OnAddPrefab, ObjectSynchronizerInfo.Hash, reader, ref context, k_Name); return false; } m_ReceivedNetworkVariableData = reader; @@ -136,18 +136,18 @@ public void Handle(ref NetworkContext context) // If a client receives a create object message and it is still synchronizing, then defer the object creation until it has finished synchronizing if (networkManager.SceneManager.ShouldDeferCreateObject()) { - networkManager.SceneManager.DeferCreateObject(context.SenderId, context.MessageSize, ObjectInfo, m_ReceivedNetworkVariableData, ObserverIds, NewObserverIds); + networkManager.SceneManager.DeferCreateObject(context.SenderId, context.MessageSize, ObjectSynchronizerInfo, m_ReceivedNetworkVariableData, ObserverIds, NewObserverIds); } else { if (networkManager.DistributedAuthorityMode && !IncludesSerializedObject && UpdateObservers) { - ObjectInfo = new NetworkObject.SceneObject() + ObjectSynchronizerInfo = new NetworkObject.NetworkObjectSynchronizer() { NetworkObjectId = NetworkObjectId, }; } - CreateObject(ref networkManager, context.SenderId, context.MessageSize, ObjectInfo, m_ReceivedNetworkVariableData, ObserverIds, NewObserverIds); + CreateObject(ref networkManager, context.SenderId, context.MessageSize, ObjectSynchronizerInfo, m_ReceivedNetworkVariableData, ObserverIds, NewObserverIds); } } @@ -158,20 +158,20 @@ internal static void CreateObject(ref NetworkManager networkManager, ref Network var observerIds = deferredObjectCreation.ObserverIds; var newObserverIds = deferredObjectCreation.NewObserverIds; var messageSize = deferredObjectCreation.MessageSize; - var sceneObject = deferredObjectCreation.SceneObject; + var sceneObject = deferredObjectCreation.NetworkObjectSynchronizer; var networkVariableData = deferredObjectCreation.FastBufferReader; CreateObject(ref networkManager, senderId, messageSize, sceneObject, networkVariableData, observerIds, newObserverIds); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static void CreateObject(ref NetworkManager networkManager, ulong senderId, uint messageSize, NetworkObject.SceneObject sceneObject, FastBufferReader networkVariableData, ulong[] observerIds, ulong[] newObserverIds) + internal static void CreateObject(ref NetworkManager networkManager, ulong senderId, uint messageSize, NetworkObject.NetworkObjectSynchronizer networkObjectSynchronizer, FastBufferReader networkVariableData, ulong[] observerIds, ulong[] newObserverIds) { var networkObject = (NetworkObject)null; try { if (!networkManager.DistributedAuthorityMode) { - networkObject = NetworkObject.AddSceneObject(sceneObject, networkVariableData, networkManager); + networkObject = NetworkObject.AddClientNetworkObject(networkObjectSynchronizer, networkVariableData, networkManager); } else { @@ -179,25 +179,25 @@ internal static void CreateObject(ref NetworkManager networkManager, ulong sende var hasNewObserverIdList = newObserverIds != null && newObserverIds.Length > 0; // Depending upon visibility of the NetworkObject and the client in question, it could be that // this client already has visibility of this NetworkObject - if (networkManager.SpawnManager.SpawnedObjects.ContainsKey(sceneObject.NetworkObjectId)) + if (networkManager.SpawnManager.SpawnedObjects.ContainsKey(networkObjectSynchronizer.NetworkObjectId)) { // If so, then just get the local instance - networkObject = networkManager.SpawnManager.SpawnedObjects[sceneObject.NetworkObjectId]; + networkObject = networkManager.SpawnManager.SpawnedObjects[networkObjectSynchronizer.NetworkObjectId]; // This should not happen, logging error just in case if (hasNewObserverIdList && newObserverIds.Contains(networkManager.LocalClientId)) { - NetworkLog.LogErrorServer($"[{nameof(CreateObjectMessage)}][Duplicate-Broadcast] Detected duplicated object creation for {sceneObject.NetworkObjectId}!"); + NetworkLog.LogErrorServer($"[{nameof(CreateObjectMessage)}][Duplicate-Broadcast] Detected duplicated object creation for {networkObjectSynchronizer.NetworkObjectId}!"); } else // Trap to make sure the owner is not receiving any messages it sent if (networkManager.CMBServiceConnection && networkManager.LocalClientId == networkObject.OwnerClientId) { - NetworkLog.LogWarning($"[{nameof(CreateObjectMessage)}][Client-{networkManager.LocalClientId}][Duplicate-CreateObjectMessage][Client Is Owner] Detected duplicated object creation for {networkObject.name}-{sceneObject.NetworkObjectId}!"); + NetworkLog.LogWarning($"[{nameof(CreateObjectMessage)}][Client-{networkManager.LocalClientId}][Duplicate-CreateObjectMessage][Client Is Owner] Detected duplicated object creation for {networkObject.name}-{networkObjectSynchronizer.NetworkObjectId}!"); } } else { - networkObject = NetworkObject.AddSceneObject(sceneObject, networkVariableData, networkManager, true); + networkObject = NetworkObject.AddClientNetworkObject(networkObjectSynchronizer, networkVariableData, networkManager, true); } // DA - NGO CMB SERVICE NOTES: @@ -229,7 +229,7 @@ internal static void CreateObject(ref NetworkManager networkManager, ulong sende var createObjectMessage = new CreateObjectMessage() { - ObjectInfo = sceneObject, + ObjectSynchronizerInfo = networkObjectSynchronizer, m_ReceivedNetworkVariableData = networkVariableData, ObserverIds = hasObserverIdList ? observerIds : null, NetworkObjectId = networkObject.NetworkObjectId, diff --git a/com.unity.netcode.gameobjects/Runtime/SceneManagement/NetworkSceneManager.cs b/com.unity.netcode.gameobjects/Runtime/SceneManagement/NetworkSceneManager.cs index 6ab3e930f2..200d5c89ce 100644 --- a/com.unity.netcode.gameobjects/Runtime/SceneManagement/NetworkSceneManager.cs +++ b/com.unity.netcode.gameobjects/Runtime/SceneManagement/NetworkSceneManager.cs @@ -3034,7 +3034,7 @@ internal struct DeferredObjectCreation // When we transfer session owner and we are using a DAHost, this will be pertinent (otherwise it is not when connected to a DA service) internal ulong[] ObserverIds; internal ulong[] NewObserverIds; - internal NetworkObject.SceneObject SceneObject; + internal NetworkObject.NetworkObjectSynchronizer NetworkObjectSynchronizer; internal FastBufferReader FastBufferReader; } @@ -3042,7 +3042,7 @@ internal struct DeferredObjectCreation internal int DeferredObjectCreationCount; // The added clientIds is specific to DAHost when session ownership changes and a normal client is controlling scene loading - internal void DeferCreateObject(ulong senderId, uint messageSize, NetworkObject.SceneObject sceneObject, FastBufferReader fastBufferReader, ulong[] observerIds, ulong[] newObserverIds) + internal void DeferCreateObject(ulong senderId, uint messageSize, NetworkObject.NetworkObjectSynchronizer networkObjectSynchronizer, FastBufferReader fastBufferReader, ulong[] observerIds, ulong[] newObserverIds) { var deferredObjectCreationEntry = new DeferredObjectCreation() { @@ -3050,7 +3050,7 @@ internal void DeferCreateObject(ulong senderId, uint messageSize, NetworkObject. MessageSize = messageSize, ObserverIds = observerIds, NewObserverIds = newObserverIds, - SceneObject = sceneObject, + NetworkObjectSynchronizer = networkObjectSynchronizer, }; unsafe diff --git a/com.unity.netcode.gameobjects/Runtime/SceneManagement/SceneEventData.cs b/com.unity.netcode.gameobjects/Runtime/SceneManagement/SceneEventData.cs index 0a91e583c7..960a62074d 100644 --- a/com.unity.netcode.gameobjects/Runtime/SceneManagement/SceneEventData.cs +++ b/com.unity.netcode.gameobjects/Runtime/SceneManagement/SceneEventData.cs @@ -625,7 +625,7 @@ internal void WriteSceneSynchronizationData(FastBufferWriter writer) var networkObject = m_NetworkObjectsSync[i]; var noStart = writer.Position; // In distributed authority mode, we send the currently known observers of each NetworkObject to the client being synchronized. - var sceneObject = m_NetworkObjectsSync[i].GetMessageSceneObject(TargetClientId, distributedAuthority); + var sceneObject = m_NetworkObjectsSync[i].GetMessageForSynchronization(TargetClientId, distributedAuthority); sceneObject.Serialize(writer); var noStop = writer.Position; @@ -705,7 +705,7 @@ internal void SerializeScenePlacedObjects(FastBufferWriter writer) foreach (var objectToSycn in m_NetworkObjectsSync) { // Serialize the NetworkObject - var sceneObject = objectToSycn.GetMessageSceneObject(TargetClientId, distributedAuthority); + var sceneObject = objectToSycn.GetMessageForSynchronization(TargetClientId, distributedAuthority); sceneObject.Serialize(writer); numberOfObjects++; } @@ -871,7 +871,7 @@ internal void DeserializeScenePlacedObjects() var sceneObjects = new List(); for (ushort i = 0; i < newObjectsCount; i++) { - var sceneObject = new NetworkObject.SceneObject(); + var sceneObject = new NetworkObject.NetworkObjectSynchronizer(); sceneObject.Deserialize(InternalBuffer); if (sceneObject.IsSceneObject) @@ -880,7 +880,7 @@ internal void DeserializeScenePlacedObjects() m_NetworkManager.SceneManager.SetTheSceneBeingSynchronized(sceneObject.NetworkSceneHandle); } - var networkObject = NetworkObject.AddSceneObject(sceneObject, InternalBuffer, m_NetworkManager); + var networkObject = NetworkObject.AddClientNetworkObject(sceneObject, InternalBuffer, m_NetworkManager); if (sceneObject.IsSceneObject) { @@ -1136,7 +1136,7 @@ internal void SynchronizeSceneNetworkObjects(NetworkManager networkManager) for (int i = 0; i < newObjectsCount; i++) { var noStart = InternalBuffer.Position; - var sceneObject = new NetworkObject.SceneObject(); + var sceneObject = new NetworkObject.NetworkObjectSynchronizer(); sceneObject.Deserialize(InternalBuffer); // If the sceneObject is in-scene placed, then set the scene being synchronized @@ -1144,7 +1144,7 @@ internal void SynchronizeSceneNetworkObjects(NetworkManager networkManager) { m_NetworkManager.SceneManager.SetTheSceneBeingSynchronized(sceneObject.NetworkSceneHandle); } - var spawnedNetworkObject = NetworkObject.AddSceneObject(sceneObject, InternalBuffer, networkManager); + var spawnedNetworkObject = NetworkObject.AddClientNetworkObject(sceneObject, InternalBuffer, networkManager); var noStop = InternalBuffer.Position; if (EnableSerializationLogs) diff --git a/com.unity.netcode.gameobjects/Runtime/Spawning/NetworkSpawnManager.cs b/com.unity.netcode.gameobjects/Runtime/Spawning/NetworkSpawnManager.cs index 14ea2bc41d..34f1796777 100644 --- a/com.unity.netcode.gameobjects/Runtime/Spawning/NetworkSpawnManager.cs +++ b/com.unity.netcode.gameobjects/Runtime/Spawning/NetworkSpawnManager.cs @@ -661,15 +661,15 @@ private void SendChangeOwnershipMessage(ref NetworkObject networkObject, bool is } - internal bool HasPrefab(NetworkObject.SceneObject sceneObject) + internal bool HasPrefab(NetworkObject.NetworkObjectSynchronizer networkObjectSynchronizer) { - if (!NetworkManager.NetworkConfig.EnableSceneManagement || !sceneObject.IsSceneObject) + if (!NetworkManager.NetworkConfig.EnableSceneManagement || !networkObjectSynchronizer.IsSceneObject) { - if (NetworkManager.PrefabHandler.ContainsHandler(sceneObject.Hash)) + if (NetworkManager.PrefabHandler.ContainsHandler(networkObjectSynchronizer.Hash)) { return true; } - if (NetworkManager.NetworkConfig.Prefabs.NetworkPrefabOverrideLinks.TryGetValue(sceneObject.Hash, out var networkPrefab)) + if (NetworkManager.NetworkConfig.Prefabs.NetworkPrefabOverrideLinks.TryGetValue(networkObjectSynchronizer.Hash, out var networkPrefab)) { switch (networkPrefab.Override) { @@ -684,7 +684,7 @@ internal bool HasPrefab(NetworkObject.SceneObject sceneObject) return false; } - var networkObject = NetworkManager.SceneManager.GetSceneRelativeInSceneNetworkObject(sceneObject.Hash, sceneObject.NetworkSceneHandle); + var networkObject = NetworkManager.SceneManager.GetSceneRelativeInSceneNetworkObject(networkObjectSynchronizer.Hash, networkObjectSynchronizer.NetworkSceneHandle); return networkObject != null; } @@ -891,24 +891,24 @@ internal NetworkObject InstantiateNetworkPrefab(GameObject networkPrefab, uint p /// For most cases this is client-side only, with the exception of when the server /// is spawning a player. /// - internal NetworkObject CreateLocalNetworkObject(NetworkObject.SceneObject sceneObject, byte[] instantiationData = null) + internal NetworkObject CreateLocalNetworkObject(NetworkObject.NetworkObjectSynchronizer networkObjectSynchronizer, byte[] instantiationData = null) { NetworkObject networkObject = null; - var globalObjectIdHash = sceneObject.Hash; - var position = sceneObject.HasTransform ? sceneObject.Transform.Position : default; - var rotation = sceneObject.HasTransform ? sceneObject.Transform.Rotation : default; - var scale = sceneObject.HasTransform ? sceneObject.Transform.Scale : default; - var parentNetworkId = sceneObject.HasParent ? sceneObject.ParentObjectId : default; - var worldPositionStays = (!sceneObject.HasParent) || sceneObject.WorldPositionStays; + var globalObjectIdHash = networkObjectSynchronizer.Hash; + var position = networkObjectSynchronizer.HasTransform ? networkObjectSynchronizer.Transform.Position : default; + var rotation = networkObjectSynchronizer.HasTransform ? networkObjectSynchronizer.Transform.Rotation : default; + var scale = networkObjectSynchronizer.HasTransform ? networkObjectSynchronizer.Transform.Scale : default; + var parentNetworkId = networkObjectSynchronizer.HasParent ? networkObjectSynchronizer.ParentObjectId : default; + var worldPositionStays = (!networkObjectSynchronizer.HasParent) || networkObjectSynchronizer.WorldPositionStays; // If scene management is disabled or the NetworkObject was dynamically spawned - if (!NetworkManager.NetworkConfig.EnableSceneManagement || !sceneObject.IsSceneObject) + if (!NetworkManager.NetworkConfig.EnableSceneManagement || !networkObjectSynchronizer.IsSceneObject) { - networkObject = GetNetworkObjectToSpawn(sceneObject.Hash, sceneObject.OwnerClientId, position, rotation, sceneObject.IsSceneObject, instantiationData); + networkObject = GetNetworkObjectToSpawn(networkObjectSynchronizer.Hash, networkObjectSynchronizer.OwnerClientId, position, rotation, networkObjectSynchronizer.IsSceneObject, instantiationData); } else // Get the in-scene placed NetworkObject { - networkObject = NetworkManager.SceneManager.GetSceneRelativeInSceneNetworkObject(globalObjectIdHash, sceneObject.NetworkSceneHandle); + networkObject = NetworkManager.SceneManager.GetSceneRelativeInSceneNetworkObject(globalObjectIdHash, networkObjectSynchronizer.NetworkSceneHandle); if (networkObject == null) { if (NetworkLog.CurrentLogLevel <= LogLevel.Error) @@ -927,10 +927,10 @@ internal NetworkObject CreateLocalNetworkObject(NetworkObject.SceneObject sceneO if (networkObject != null) { - networkObject.DestroyWithScene = sceneObject.DestroyWithScene; - networkObject.NetworkSceneHandle = sceneObject.NetworkSceneHandle; - networkObject.DontDestroyWithOwner = sceneObject.DontDestroyWithOwner; - networkObject.Ownership = (NetworkObject.OwnershipStatus)sceneObject.OwnershipFlags; + networkObject.DestroyWithScene = networkObjectSynchronizer.DestroyWithScene; + networkObject.NetworkSceneHandle = networkObjectSynchronizer.NetworkSceneHandle; + networkObject.DontDestroyWithOwner = networkObjectSynchronizer.DontDestroyWithOwner; + networkObject.Ownership = (NetworkObject.OwnershipStatus)networkObjectSynchronizer.OwnershipFlags; var nonNetworkObjectParent = false; // SPECIAL CASE FOR IN-SCENE PLACED: (only when the parent has a NetworkObject) @@ -940,12 +940,12 @@ internal NetworkObject CreateLocalNetworkObject(NetworkObject.SceneObject sceneO // the parent has changed. // For this we will want to remove the parent before spawning and setting the transform values based // on several possible scenarios. - if (sceneObject.IsSceneObject && networkObject.transform.parent != null) + if (networkObjectSynchronizer.IsSceneObject && networkObject.transform.parent != null) { var parentNetworkObject = networkObject.transform.parent.GetComponent(); // special case to handle being parented under a GameObject with no NetworkObject - nonNetworkObjectParent = !parentNetworkObject && sceneObject.HasParent; + nonNetworkObjectParent = !parentNetworkObject && networkObjectSynchronizer.HasParent; // If the in-scene placed NetworkObject has a parent NetworkObject... if (parentNetworkObject) @@ -955,18 +955,18 @@ internal NetworkObject CreateLocalNetworkObject(NetworkObject.SceneObject sceneO // - The auhtority says we have a parent but either of the two are true: // -- It isn't the same parent. // -- It was parented using world position stays. - if (!sceneObject.HasParent || (sceneObject.IsLatestParentSet - && (sceneObject.LatestParent.Value != parentNetworkObject.NetworkObjectId || sceneObject.WorldPositionStays))) + if (!networkObjectSynchronizer.HasParent || (networkObjectSynchronizer.IsLatestParentSet + && (networkObjectSynchronizer.LatestParent.Value != parentNetworkObject.NetworkObjectId || networkObjectSynchronizer.WorldPositionStays))) { // If parenting without notifications then we are temporarily removing the parent to set the transform // values before reparenting under the current parent. - networkObject.ApplyNetworkParenting(true, true, enableNotification: !sceneObject.HasParent); + networkObject.ApplyNetworkParenting(true, true, enableNotification: !networkObjectSynchronizer.HasParent); } } } // Set the transform only if the sceneObject includes transform information. - if (sceneObject.HasTransform) + if (networkObjectSynchronizer.HasTransform) { // If world position stays is true or we have auto object parent synchronization disabled // then we want to apply the position and rotation values world space relative @@ -986,7 +986,7 @@ internal NetworkObject CreateLocalNetworkObject(NetworkObject.SceneObject sceneO // the network prefab used to represent the player. // Note: not doing this would set the player's scale to zero since // that is the default value of Vector3. - if (!sceneObject.IsPlayerObject) + if (!networkObjectSynchronizer.IsPlayerObject) { // Since scale is always applied to local space scale, we do the transform // space logic during serialization such that it works out whether AutoObjectParentSync @@ -995,12 +995,12 @@ internal NetworkObject CreateLocalNetworkObject(NetworkObject.SceneObject sceneO } } - if (sceneObject.HasParent) + if (networkObjectSynchronizer.HasParent) { // Go ahead and set network parenting properties, if the latest parent is not set then pass in null // (we always want to set worldPositionStays) ulong? parentId = null; - if (sceneObject.IsLatestParentSet) + if (networkObjectSynchronizer.IsLatestParentSet) { parentId = parentNetworkId; } @@ -1009,7 +1009,7 @@ internal NetworkObject CreateLocalNetworkObject(NetworkObject.SceneObject sceneO // Dynamically spawned NetworkObjects that occur during a LoadSceneMode.Single load scene event are migrated into the DDOL // until the scene is loaded. They are then migrated back into the newly loaded and currently active scene. - if (!sceneObject.IsSceneObject && NetworkSceneManager.IsSpawnedObjectsPendingInDontDestroyOnLoad) + if (!networkObjectSynchronizer.IsSceneObject && NetworkSceneManager.IsSpawnedObjectsPendingInDontDestroyOnLoad) { UnityEngine.Object.DontDestroyOnLoad(networkObject.gameObject); } @@ -1104,9 +1104,9 @@ internal void AuthorityLocalSpawn([NotNull] NetworkObject networkObject, ulong n /// is only invoked by: /// /// - /// IMPORTANT: Pre spawn methods need to be invoked from within . + /// IMPORTANT: Pre spawn methods need to be invoked from within . /// - internal void NonAuthorityLocalSpawn([NotNull] NetworkObject networkObject, in NetworkObject.SceneObject sceneObject, bool destroyWithScene) + internal void NonAuthorityLocalSpawn([NotNull] NetworkObject networkObject, in NetworkObject.NetworkObjectSynchronizer networkObjectSynchronizer, bool destroyWithScene) { if (networkObject.IsSpawned) { @@ -1115,7 +1115,7 @@ internal void NonAuthorityLocalSpawn([NotNull] NetworkObject networkObject, in N } // Do not invoke Pre spawn here (SynchronizeNetworkBehaviours needs to be invoked prior to this) - SpawnNetworkObjectLocallyCommon(networkObject, sceneObject.NetworkObjectId, sceneObject.IsSceneObject, sceneObject.IsPlayerObject, sceneObject.OwnerClientId, destroyWithScene); + SpawnNetworkObjectLocallyCommon(networkObject, networkObjectSynchronizer.NetworkObjectId, networkObjectSynchronizer.IsSceneObject, networkObjectSynchronizer.IsPlayerObject, networkObjectSynchronizer.OwnerClientId, destroyWithScene); // It is ok to invoke NetworkBehaviour.OnPostSpawn methods networkObject.InvokeBehaviourNetworkPostSpawn(); @@ -1283,7 +1283,7 @@ internal void SendSpawnCallForObject(ulong clientId, NetworkObject networkObject } var message = new CreateObjectMessage { - ObjectInfo = networkObject.GetMessageSceneObject(clientId, NetworkManager.DistributedAuthorityMode), + ObjectSynchronizerInfo = networkObject.GetMessageForSynchronization(clientId, NetworkManager.DistributedAuthorityMode), IncludesSerializedObject = true, UpdateObservers = NetworkManager.DistributedAuthorityMode, ObserverIds = NetworkManager.DistributedAuthorityMode ? networkObject.Observers.ToArray() : null, @@ -1305,7 +1305,7 @@ internal void SendSpawnCallForObserverUpdate(ulong[] newObservers, NetworkObject var message = new CreateObjectMessage { - ObjectInfo = networkObject.GetMessageSceneObject(), + ObjectSynchronizerInfo = networkObject.GetMessageForSynchronization(), ObserverIds = networkObject.Observers.ToArray(), NewObserverIds = newObservers.ToArray(), IncludesSerializedObject = true, From f624821343c94a5be6566add853e886dbcc912fe Mon Sep 17 00:00:00 2001 From: Noellie Velez Date: Mon, 15 Dec 2025 12:14:57 +0100 Subject: [PATCH 02/11] Chore: NetworkObject optimization --- .../Runtime/Core/NetworkObject.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/com.unity.netcode.gameobjects/Runtime/Core/NetworkObject.cs b/com.unity.netcode.gameobjects/Runtime/Core/NetworkObject.cs index 6fc86a26cc..451fb64fb4 100644 --- a/com.unity.netcode.gameobjects/Runtime/Core/NetworkObject.cs +++ b/com.unity.netcode.gameobjects/Runtime/Core/NetworkObject.cs @@ -2844,7 +2844,6 @@ public NetworkBehaviour GetNetworkBehaviourAtOrderIndex(ushort index) internal struct NetworkObjectSynchronizer { - private ushort m_BitField; public uint Hash; public ulong NetworkObjectId; public ulong OwnerClientId; @@ -2962,7 +2961,8 @@ public void Serialize(FastBufferWriter writer) HasOwnershipFlags = true; SpawnWithObservers = OwnerObject.SpawnWithObservers; } - writer.WriteValueSafe(m_BitField); + + writer.WriteValueSafe(GetBitsetRepresentation()); writer.WriteValueSafe(Hash); BytePacker.WriteValueBitPacked(writer, NetworkObjectId); BytePacker.WriteValueBitPacked(writer, OwnerClientId); @@ -3042,7 +3042,8 @@ public void Serialize(FastBufferWriter writer) public void Deserialize(FastBufferReader reader) { - reader.ReadValueSafe(out m_BitField); + reader.ReadValueSafe(out ushort bitset); + SetStateFromBitset(bitset); reader.ReadValueSafe(out Hash); ByteUnpacker.ReadValueBitPacked(reader, out NetworkObjectId); ByteUnpacker.ReadValueBitPacked(reader, out OwnerClientId); From fad2fea1d53f10b823f3971c7ecd971fde69600f Mon Sep 17 00:00:00 2001 From: Noellie Velez Date: Mon, 15 Dec 2025 12:28:34 +0100 Subject: [PATCH 03/11] Rename pass SceneObject -- > SerializedObject GetMessageSceneObject --> Serialize AddSceneObject --> Deserialize --- .../Connection/NetworkConnectionManager.cs | 12 ++-- .../Runtime/Core/NetworkObject.cs | 34 +++++----- .../Messages/ConnectionApprovedMessage.cs | 6 +- .../Messaging/Messages/CreateObjectMessage.cs | 34 +++++----- .../Messaging/Messages/ParentSyncMessage.cs | 1 - .../SceneManagement/NetworkSceneManager.cs | 6 +- .../Runtime/SceneManagement/SceneEventData.cs | 12 ++-- .../Runtime/Spawning/NetworkSpawnManager.cs | 68 +++++++++---------- 8 files changed, 86 insertions(+), 87 deletions(-) diff --git a/com.unity.netcode.gameobjects/Runtime/Connection/NetworkConnectionManager.cs b/com.unity.netcode.gameobjects/Runtime/Connection/NetworkConnectionManager.cs index f64b0b1940..549cfe2059 100644 --- a/com.unity.netcode.gameobjects/Runtime/Connection/NetworkConnectionManager.cs +++ b/com.unity.netcode.gameobjects/Runtime/Connection/NetworkConnectionManager.cs @@ -1119,15 +1119,15 @@ internal void ApprovedPlayerSpawn(ulong clientId, uint playerPrefabHash) var message = new CreateObjectMessage { - ObjectSynchronizerInfo = ConnectedClients[clientId].PlayerObject.GetMessageForSynchronization(clientPair.Key), + ObjectInfo = ConnectedClients[clientId].PlayerObject.Serialize(clientPair.Key), IncludesSerializedObject = true, }; - message.ObjectSynchronizerInfo.Hash = playerPrefabHash; - message.ObjectSynchronizerInfo.IsSceneObject = false; - message.ObjectSynchronizerInfo.HasParent = false; - message.ObjectSynchronizerInfo.IsPlayerObject = true; - message.ObjectSynchronizerInfo.OwnerClientId = clientId; + message.ObjectInfo.Hash = playerPrefabHash; + message.ObjectInfo.IsSceneObject = false; + message.ObjectInfo.HasParent = false; + message.ObjectInfo.IsPlayerObject = true; + message.ObjectInfo.OwnerClientId = clientId; var size = SendMessage(ref message, MessageDeliveryType.DefaultDelivery, clientPair.Key); NetworkManager.NetworkMetrics.TrackObjectSpawnSent(clientPair.Key, ConnectedClients[clientId].PlayerObject, size); } diff --git a/com.unity.netcode.gameobjects/Runtime/Core/NetworkObject.cs b/com.unity.netcode.gameobjects/Runtime/Core/NetworkObject.cs index 451fb64fb4..08acb669e4 100644 --- a/com.unity.netcode.gameobjects/Runtime/Core/NetworkObject.cs +++ b/com.unity.netcode.gameobjects/Runtime/Core/NetworkObject.cs @@ -2842,7 +2842,7 @@ public NetworkBehaviour GetNetworkBehaviourAtOrderIndex(ushort index) return ChildNetworkBehaviours[index]; } - internal struct NetworkObjectSynchronizer + internal struct SerializedObject { public uint Hash; public ulong NetworkObjectId; @@ -3171,9 +3171,9 @@ internal void SynchronizeNetworkBehaviours(ref BufferSerializer serializer } } - internal NetworkObjectSynchronizer GetMessageForSynchronization(ulong targetClientId = NetworkManager.ServerClientId, bool syncObservers = false) + internal SerializedObject Serialize(ulong targetClientId = NetworkManager.ServerClientId, bool syncObservers = false) { - var obj = new NetworkObjectSynchronizer + var obj = new SerializedObject { HasParent = transform.parent != null, WorldPositionStays = m_CachedWorldPositionStays, @@ -3227,7 +3227,7 @@ internal NetworkObjectSynchronizer GetMessageForSynchronization(ulong targetClie syncScaleLocalSpaceRelative = obj.HasParent; } - obj.Transform = new NetworkObjectSynchronizer.TransformData + obj.Transform = new SerializedObject.TransformData { // If we are parented and we have the m_CachedWorldPositionStays disabled, then use local space // values as opposed world space values. @@ -3246,27 +3246,27 @@ internal NetworkObjectSynchronizer GetMessageForSynchronization(ulong targetClie } /// - /// Used to deserialize a serialized which occurs + /// Used to deserialize a serialized which occurs /// when the client is approved or during a scene transition /// - /// Deserialized scene object data + /// Deserialized scene object data /// FastBufferReader for the NetworkVariable data /// NetworkManager instance /// will be true if invoked by CreateObjectMessage /// The deserialized NetworkObject or null if deserialization failed - internal static NetworkObject AddClientNetworkObject(in NetworkObjectSynchronizer networkObjectSynchronizer, FastBufferReader reader, NetworkManager networkManager, bool invokedByMessage = false) + internal static NetworkObject Deserialize(in SerializedObject serializedObject, FastBufferReader reader, NetworkManager networkManager, bool invokedByMessage = false) { - var endOfSynchronizationData = reader.Position + networkObjectSynchronizer.SynchronizationDataSize; + var endOfSynchronizationData = reader.Position + serializedObject.SynchronizationDataSize; byte[] instantiationData = null; - if (networkObjectSynchronizer.HasInstantiationData) + if (serializedObject.HasInstantiationData) { reader.ReadValueSafe(out instantiationData); } // Attempt to create a local NetworkObject - var networkObject = networkManager.SpawnManager.CreateLocalNetworkObject(networkObjectSynchronizer, instantiationData); + var networkObject = networkManager.SpawnManager.CreateLocalNetworkObject(serializedObject, instantiationData); if (networkObject == null) @@ -3274,7 +3274,7 @@ internal static NetworkObject AddClientNetworkObject(in NetworkObjectSynchronize // Log the error that the NetworkObject failed to construct if (networkManager.LogLevel <= LogLevel.Normal) { - NetworkLog.LogError($"Failed to spawn {nameof(NetworkObject)} for Hash {networkObjectSynchronizer.Hash}."); + NetworkLog.LogError($"Failed to spawn {nameof(NetworkObject)} for Hash {serializedObject.Hash}."); } try @@ -3295,7 +3295,7 @@ internal static NetworkObject AddClientNetworkObject(in NetworkObjectSynchronize // This will get set again when the NetworkObject is spawned locally, but we set it here ahead of spawning // in order to be able to determine which NetworkVariables the client will be allowed to read. - networkObject.OwnerClientId = networkObjectSynchronizer.OwnerClientId; + networkObject.OwnerClientId = serializedObject.OwnerClientId; // Special Case: Invoke NetworkBehaviour.OnPreSpawn methods here before SynchronizeNetworkBehaviours networkObject.InvokeBehaviourNetworkPreSpawn(); @@ -3323,7 +3323,7 @@ internal static NetworkObject AddClientNetworkObject(in NetworkObjectSynchronize // being told we do not have a parent, then we want to clear the latest parent so it is not automatically // "re-parented" to the original parent. This can happen if not unloading the scene and the parenting of // the in-scene placed Networkobject changes several times over different sessions. - if (networkObjectSynchronizer.IsSceneObject && !networkObjectSynchronizer.HasParent && networkObject.m_LatestParent.HasValue) + if (serializedObject.IsSceneObject && !serializedObject.HasParent && networkObject.m_LatestParent.HasValue) { networkObject.m_LatestParent = null; } @@ -3336,11 +3336,11 @@ internal static NetworkObject AddClientNetworkObject(in NetworkObjectSynchronize // Invoke the non-authority local spawn method // (It also invokes post spawn and handles processing derferred messages) - networkManager.SpawnManager.NonAuthorityLocalSpawn(networkObject, networkObjectSynchronizer, networkObjectSynchronizer.DestroyWithScene); + networkManager.SpawnManager.NonAuthorityLocalSpawn(networkObject, serializedObject, serializedObject.DestroyWithScene); - if (networkObjectSynchronizer.SyncObservers) + if (serializedObject.SyncObservers) { - foreach (var observer in networkObjectSynchronizer.Observers) + foreach (var observer in serializedObject.Observers) { networkObject.Observers.Add(observer); } @@ -3348,7 +3348,7 @@ internal static NetworkObject AddClientNetworkObject(in NetworkObjectSynchronize if (networkManager.DistributedAuthorityMode) { - networkObject.SpawnWithObservers = networkObjectSynchronizer.SpawnWithObservers; + networkObject.SpawnWithObservers = serializedObject.SpawnWithObservers; } // If this was not invoked by a message handler, we are in distributed authority mode, and we are spawning with observers or diff --git a/com.unity.netcode.gameobjects/Runtime/Messaging/Messages/ConnectionApprovedMessage.cs b/com.unity.netcode.gameobjects/Runtime/Messaging/Messages/ConnectionApprovedMessage.cs index d80a2d084d..b563d439a1 100644 --- a/com.unity.netcode.gameobjects/Runtime/Messaging/Messages/ConnectionApprovedMessage.cs +++ b/com.unity.netcode.gameobjects/Runtime/Messaging/Messages/ConnectionApprovedMessage.cs @@ -160,7 +160,7 @@ public void Serialize(FastBufferWriter writer, int targetVersion) { sobj.Observers.Add(OwnerClientId); // In distributed authority mode, we send the currently known observers of each NetworkObject to the client being synchronized. - var sceneObject = sobj.GetMessageForSynchronization(OwnerClientId, IsDistributedAuthority); + var sceneObject = sobj.Serialize(OwnerClientId, IsDistributedAuthority); sceneObject.Serialize(writer); ++sceneObjectCount; } @@ -342,9 +342,9 @@ public void Handle(ref NetworkContext context) // to create a list to hold the data. This is a breach of convention for performance reasons. for (ushort i = 0; i < sceneObjectCount; i++) { - var sceneObject = new NetworkObject.NetworkObjectSynchronizer(); + var sceneObject = new NetworkObject.SerializedObject(); sceneObject.Deserialize(m_ReceivedSceneObjectData); - NetworkObject.AddClientNetworkObject(sceneObject, m_ReceivedSceneObjectData, networkManager); + NetworkObject.Deserialize(sceneObject, m_ReceivedSceneObjectData, networkManager); } if (networkManager.AutoSpawnPlayerPrefabClientSide) diff --git a/com.unity.netcode.gameobjects/Runtime/Messaging/Messages/CreateObjectMessage.cs b/com.unity.netcode.gameobjects/Runtime/Messaging/Messages/CreateObjectMessage.cs index 07f4c07f02..475ba0b171 100644 --- a/com.unity.netcode.gameobjects/Runtime/Messaging/Messages/CreateObjectMessage.cs +++ b/com.unity.netcode.gameobjects/Runtime/Messaging/Messages/CreateObjectMessage.cs @@ -9,7 +9,7 @@ internal struct CreateObjectMessage : INetworkMessage private const string k_Name = "CreateObjectMessage"; - public NetworkObject.NetworkObjectSynchronizer ObjectSynchronizerInfo; + public NetworkObject.SerializedObject ObjectInfo; private FastBufferReader m_ReceivedNetworkVariableData; // DA - NGO CMB SERVICE NOTES: @@ -64,7 +64,7 @@ public void Serialize(FastBufferWriter writer, int targetVersion) if (IncludesSerializedObject) { - ObjectSynchronizerInfo.Serialize(writer); + ObjectInfo.Serialize(writer); } else { @@ -113,16 +113,16 @@ public bool Deserialize(FastBufferReader reader, ref NetworkContext context, int if (IncludesSerializedObject) { - ObjectSynchronizerInfo.Deserialize(reader); + ObjectInfo.Deserialize(reader); } else { ByteUnpacker.ReadValuePacked(reader, out NetworkObjectId); } - if (!networkManager.NetworkConfig.ForceSamePrefabs && !networkManager.SpawnManager.HasPrefab(ObjectSynchronizerInfo)) + if (!networkManager.NetworkConfig.ForceSamePrefabs && !networkManager.SpawnManager.HasPrefab(ObjectInfo)) { - networkManager.DeferredMessageManager.DeferMessage(IDeferredNetworkMessageManager.TriggerType.OnAddPrefab, ObjectSynchronizerInfo.Hash, reader, ref context, k_Name); + networkManager.DeferredMessageManager.DeferMessage(IDeferredNetworkMessageManager.TriggerType.OnAddPrefab, ObjectInfo.Hash, reader, ref context, k_Name); return false; } m_ReceivedNetworkVariableData = reader; @@ -136,18 +136,18 @@ public void Handle(ref NetworkContext context) // If a client receives a create object message and it is still synchronizing, then defer the object creation until it has finished synchronizing if (networkManager.SceneManager.ShouldDeferCreateObject()) { - networkManager.SceneManager.DeferCreateObject(context.SenderId, context.MessageSize, ObjectSynchronizerInfo, m_ReceivedNetworkVariableData, ObserverIds, NewObserverIds); + networkManager.SceneManager.DeferCreateObject(context.SenderId, context.MessageSize, ObjectInfo, m_ReceivedNetworkVariableData, ObserverIds, NewObserverIds); } else { if (networkManager.DistributedAuthorityMode && !IncludesSerializedObject && UpdateObservers) { - ObjectSynchronizerInfo = new NetworkObject.NetworkObjectSynchronizer() + ObjectInfo = new NetworkObject.SerializedObject() { NetworkObjectId = NetworkObjectId, }; } - CreateObject(ref networkManager, context.SenderId, context.MessageSize, ObjectSynchronizerInfo, m_ReceivedNetworkVariableData, ObserverIds, NewObserverIds); + CreateObject(ref networkManager, context.SenderId, context.MessageSize, ObjectInfo, m_ReceivedNetworkVariableData, ObserverIds, NewObserverIds); } } @@ -158,20 +158,20 @@ internal static void CreateObject(ref NetworkManager networkManager, ref Network var observerIds = deferredObjectCreation.ObserverIds; var newObserverIds = deferredObjectCreation.NewObserverIds; var messageSize = deferredObjectCreation.MessageSize; - var sceneObject = deferredObjectCreation.NetworkObjectSynchronizer; + var sceneObject = deferredObjectCreation.SerializedObject; var networkVariableData = deferredObjectCreation.FastBufferReader; CreateObject(ref networkManager, senderId, messageSize, sceneObject, networkVariableData, observerIds, newObserverIds); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static void CreateObject(ref NetworkManager networkManager, ulong senderId, uint messageSize, NetworkObject.NetworkObjectSynchronizer networkObjectSynchronizer, FastBufferReader networkVariableData, ulong[] observerIds, ulong[] newObserverIds) + internal static void CreateObject(ref NetworkManager networkManager, ulong senderId, uint messageSize, NetworkObject.SerializedObject serializedObject, FastBufferReader networkVariableData, ulong[] observerIds, ulong[] newObserverIds) { var networkObject = (NetworkObject)null; try { if (!networkManager.DistributedAuthorityMode) { - networkObject = NetworkObject.AddClientNetworkObject(networkObjectSynchronizer, networkVariableData, networkManager); + networkObject = NetworkObject.Deserialize(serializedObject, networkVariableData, networkManager); } else { @@ -179,25 +179,25 @@ internal static void CreateObject(ref NetworkManager networkManager, ulong sende var hasNewObserverIdList = newObserverIds != null && newObserverIds.Length > 0; // Depending upon visibility of the NetworkObject and the client in question, it could be that // this client already has visibility of this NetworkObject - if (networkManager.SpawnManager.SpawnedObjects.ContainsKey(networkObjectSynchronizer.NetworkObjectId)) + if (networkManager.SpawnManager.SpawnedObjects.ContainsKey(serializedObject.NetworkObjectId)) { // If so, then just get the local instance - networkObject = networkManager.SpawnManager.SpawnedObjects[networkObjectSynchronizer.NetworkObjectId]; + networkObject = networkManager.SpawnManager.SpawnedObjects[serializedObject.NetworkObjectId]; // This should not happen, logging error just in case if (hasNewObserverIdList && newObserverIds.Contains(networkManager.LocalClientId)) { - NetworkLog.LogErrorServer($"[{nameof(CreateObjectMessage)}][Duplicate-Broadcast] Detected duplicated object creation for {networkObjectSynchronizer.NetworkObjectId}!"); + NetworkLog.LogErrorServer($"[{nameof(CreateObjectMessage)}][Duplicate-Broadcast] Detected duplicated object creation for {serializedObject.NetworkObjectId}!"); } else // Trap to make sure the owner is not receiving any messages it sent if (networkManager.CMBServiceConnection && networkManager.LocalClientId == networkObject.OwnerClientId) { - NetworkLog.LogWarning($"[{nameof(CreateObjectMessage)}][Client-{networkManager.LocalClientId}][Duplicate-CreateObjectMessage][Client Is Owner] Detected duplicated object creation for {networkObject.name}-{networkObjectSynchronizer.NetworkObjectId}!"); + NetworkLog.LogWarning($"[{nameof(CreateObjectMessage)}][Client-{networkManager.LocalClientId}][Duplicate-CreateObjectMessage][Client Is Owner] Detected duplicated object creation for {networkObject.name}-{serializedObject.NetworkObjectId}!"); } } else { - networkObject = NetworkObject.AddClientNetworkObject(networkObjectSynchronizer, networkVariableData, networkManager, true); + networkObject = NetworkObject.Deserialize(serializedObject, networkVariableData, networkManager, true); } // DA - NGO CMB SERVICE NOTES: @@ -229,7 +229,7 @@ internal static void CreateObject(ref NetworkManager networkManager, ulong sende var createObjectMessage = new CreateObjectMessage() { - ObjectSynchronizerInfo = networkObjectSynchronizer, + ObjectInfo = serializedObject, m_ReceivedNetworkVariableData = networkVariableData, ObserverIds = hasObserverIdList ? observerIds : null, NetworkObjectId = networkObject.NetworkObjectId, diff --git a/com.unity.netcode.gameobjects/Runtime/Messaging/Messages/ParentSyncMessage.cs b/com.unity.netcode.gameobjects/Runtime/Messaging/Messages/ParentSyncMessage.cs index 39daa80c39..844628608b 100644 --- a/com.unity.netcode.gameobjects/Runtime/Messaging/Messages/ParentSyncMessage.cs +++ b/com.unity.netcode.gameobjects/Runtime/Messaging/Messages/ParentSyncMessage.cs @@ -38,7 +38,6 @@ internal struct ParentSyncMessage : INetworkMessage public void Serialize(FastBufferWriter writer, int targetVersion) { - byte bitset = 0x00; if (WorldPositionStays) { bitset |= k_WorldPositionStays; } if (IsLatestParentSet) { bitset |= k_IsLatestParentSet; } diff --git a/com.unity.netcode.gameobjects/Runtime/SceneManagement/NetworkSceneManager.cs b/com.unity.netcode.gameobjects/Runtime/SceneManagement/NetworkSceneManager.cs index 200d5c89ce..2a57291dec 100644 --- a/com.unity.netcode.gameobjects/Runtime/SceneManagement/NetworkSceneManager.cs +++ b/com.unity.netcode.gameobjects/Runtime/SceneManagement/NetworkSceneManager.cs @@ -3034,7 +3034,7 @@ internal struct DeferredObjectCreation // When we transfer session owner and we are using a DAHost, this will be pertinent (otherwise it is not when connected to a DA service) internal ulong[] ObserverIds; internal ulong[] NewObserverIds; - internal NetworkObject.NetworkObjectSynchronizer NetworkObjectSynchronizer; + internal NetworkObject.SerializedObject SerializedObject; internal FastBufferReader FastBufferReader; } @@ -3042,7 +3042,7 @@ internal struct DeferredObjectCreation internal int DeferredObjectCreationCount; // The added clientIds is specific to DAHost when session ownership changes and a normal client is controlling scene loading - internal void DeferCreateObject(ulong senderId, uint messageSize, NetworkObject.NetworkObjectSynchronizer networkObjectSynchronizer, FastBufferReader fastBufferReader, ulong[] observerIds, ulong[] newObserverIds) + internal void DeferCreateObject(ulong senderId, uint messageSize, NetworkObject.SerializedObject serializedObject, FastBufferReader fastBufferReader, ulong[] observerIds, ulong[] newObserverIds) { var deferredObjectCreationEntry = new DeferredObjectCreation() { @@ -3050,7 +3050,7 @@ internal void DeferCreateObject(ulong senderId, uint messageSize, NetworkObject. MessageSize = messageSize, ObserverIds = observerIds, NewObserverIds = newObserverIds, - NetworkObjectSynchronizer = networkObjectSynchronizer, + SerializedObject = serializedObject, }; unsafe diff --git a/com.unity.netcode.gameobjects/Runtime/SceneManagement/SceneEventData.cs b/com.unity.netcode.gameobjects/Runtime/SceneManagement/SceneEventData.cs index 960a62074d..4f079ecfa7 100644 --- a/com.unity.netcode.gameobjects/Runtime/SceneManagement/SceneEventData.cs +++ b/com.unity.netcode.gameobjects/Runtime/SceneManagement/SceneEventData.cs @@ -625,7 +625,7 @@ internal void WriteSceneSynchronizationData(FastBufferWriter writer) var networkObject = m_NetworkObjectsSync[i]; var noStart = writer.Position; // In distributed authority mode, we send the currently known observers of each NetworkObject to the client being synchronized. - var sceneObject = m_NetworkObjectsSync[i].GetMessageForSynchronization(TargetClientId, distributedAuthority); + var sceneObject = m_NetworkObjectsSync[i].Serialize(TargetClientId, distributedAuthority); sceneObject.Serialize(writer); var noStop = writer.Position; @@ -705,7 +705,7 @@ internal void SerializeScenePlacedObjects(FastBufferWriter writer) foreach (var objectToSycn in m_NetworkObjectsSync) { // Serialize the NetworkObject - var sceneObject = objectToSycn.GetMessageForSynchronization(TargetClientId, distributedAuthority); + var sceneObject = objectToSycn.Serialize(TargetClientId, distributedAuthority); sceneObject.Serialize(writer); numberOfObjects++; } @@ -871,7 +871,7 @@ internal void DeserializeScenePlacedObjects() var sceneObjects = new List(); for (ushort i = 0; i < newObjectsCount; i++) { - var sceneObject = new NetworkObject.NetworkObjectSynchronizer(); + var sceneObject = new NetworkObject.SerializedObject(); sceneObject.Deserialize(InternalBuffer); if (sceneObject.IsSceneObject) @@ -880,7 +880,7 @@ internal void DeserializeScenePlacedObjects() m_NetworkManager.SceneManager.SetTheSceneBeingSynchronized(sceneObject.NetworkSceneHandle); } - var networkObject = NetworkObject.AddClientNetworkObject(sceneObject, InternalBuffer, m_NetworkManager); + var networkObject = NetworkObject.Deserialize(sceneObject, InternalBuffer, m_NetworkManager); if (sceneObject.IsSceneObject) { @@ -1136,7 +1136,7 @@ internal void SynchronizeSceneNetworkObjects(NetworkManager networkManager) for (int i = 0; i < newObjectsCount; i++) { var noStart = InternalBuffer.Position; - var sceneObject = new NetworkObject.NetworkObjectSynchronizer(); + var sceneObject = new NetworkObject.SerializedObject(); sceneObject.Deserialize(InternalBuffer); // If the sceneObject is in-scene placed, then set the scene being synchronized @@ -1144,7 +1144,7 @@ internal void SynchronizeSceneNetworkObjects(NetworkManager networkManager) { m_NetworkManager.SceneManager.SetTheSceneBeingSynchronized(sceneObject.NetworkSceneHandle); } - var spawnedNetworkObject = NetworkObject.AddClientNetworkObject(sceneObject, InternalBuffer, networkManager); + var spawnedNetworkObject = NetworkObject.Deserialize(sceneObject, InternalBuffer, networkManager); var noStop = InternalBuffer.Position; if (EnableSerializationLogs) diff --git a/com.unity.netcode.gameobjects/Runtime/Spawning/NetworkSpawnManager.cs b/com.unity.netcode.gameobjects/Runtime/Spawning/NetworkSpawnManager.cs index 34f1796777..75dcc83ec3 100644 --- a/com.unity.netcode.gameobjects/Runtime/Spawning/NetworkSpawnManager.cs +++ b/com.unity.netcode.gameobjects/Runtime/Spawning/NetworkSpawnManager.cs @@ -661,15 +661,15 @@ private void SendChangeOwnershipMessage(ref NetworkObject networkObject, bool is } - internal bool HasPrefab(NetworkObject.NetworkObjectSynchronizer networkObjectSynchronizer) + internal bool HasPrefab(NetworkObject.SerializedObject serializedObject) { - if (!NetworkManager.NetworkConfig.EnableSceneManagement || !networkObjectSynchronizer.IsSceneObject) + if (!NetworkManager.NetworkConfig.EnableSceneManagement || !serializedObject.IsSceneObject) { - if (NetworkManager.PrefabHandler.ContainsHandler(networkObjectSynchronizer.Hash)) + if (NetworkManager.PrefabHandler.ContainsHandler(serializedObject.Hash)) { return true; } - if (NetworkManager.NetworkConfig.Prefabs.NetworkPrefabOverrideLinks.TryGetValue(networkObjectSynchronizer.Hash, out var networkPrefab)) + if (NetworkManager.NetworkConfig.Prefabs.NetworkPrefabOverrideLinks.TryGetValue(serializedObject.Hash, out var networkPrefab)) { switch (networkPrefab.Override) { @@ -684,7 +684,7 @@ internal bool HasPrefab(NetworkObject.NetworkObjectSynchronizer networkObjectSyn return false; } - var networkObject = NetworkManager.SceneManager.GetSceneRelativeInSceneNetworkObject(networkObjectSynchronizer.Hash, networkObjectSynchronizer.NetworkSceneHandle); + var networkObject = NetworkManager.SceneManager.GetSceneRelativeInSceneNetworkObject(serializedObject.Hash, serializedObject.NetworkSceneHandle); return networkObject != null; } @@ -891,24 +891,24 @@ internal NetworkObject InstantiateNetworkPrefab(GameObject networkPrefab, uint p /// For most cases this is client-side only, with the exception of when the server /// is spawning a player. /// - internal NetworkObject CreateLocalNetworkObject(NetworkObject.NetworkObjectSynchronizer networkObjectSynchronizer, byte[] instantiationData = null) + internal NetworkObject CreateLocalNetworkObject(NetworkObject.SerializedObject serializedObject, byte[] instantiationData = null) { NetworkObject networkObject = null; - var globalObjectIdHash = networkObjectSynchronizer.Hash; - var position = networkObjectSynchronizer.HasTransform ? networkObjectSynchronizer.Transform.Position : default; - var rotation = networkObjectSynchronizer.HasTransform ? networkObjectSynchronizer.Transform.Rotation : default; - var scale = networkObjectSynchronizer.HasTransform ? networkObjectSynchronizer.Transform.Scale : default; - var parentNetworkId = networkObjectSynchronizer.HasParent ? networkObjectSynchronizer.ParentObjectId : default; - var worldPositionStays = (!networkObjectSynchronizer.HasParent) || networkObjectSynchronizer.WorldPositionStays; + var globalObjectIdHash = serializedObject.Hash; + var position = serializedObject.HasTransform ? serializedObject.Transform.Position : default; + var rotation = serializedObject.HasTransform ? serializedObject.Transform.Rotation : default; + var scale = serializedObject.HasTransform ? serializedObject.Transform.Scale : default; + var parentNetworkId = serializedObject.HasParent ? serializedObject.ParentObjectId : default; + var worldPositionStays = (!serializedObject.HasParent) || serializedObject.WorldPositionStays; // If scene management is disabled or the NetworkObject was dynamically spawned - if (!NetworkManager.NetworkConfig.EnableSceneManagement || !networkObjectSynchronizer.IsSceneObject) + if (!NetworkManager.NetworkConfig.EnableSceneManagement || !serializedObject.IsSceneObject) { - networkObject = GetNetworkObjectToSpawn(networkObjectSynchronizer.Hash, networkObjectSynchronizer.OwnerClientId, position, rotation, networkObjectSynchronizer.IsSceneObject, instantiationData); + networkObject = GetNetworkObjectToSpawn(serializedObject.Hash, serializedObject.OwnerClientId, position, rotation, serializedObject.IsSceneObject, instantiationData); } else // Get the in-scene placed NetworkObject { - networkObject = NetworkManager.SceneManager.GetSceneRelativeInSceneNetworkObject(globalObjectIdHash, networkObjectSynchronizer.NetworkSceneHandle); + networkObject = NetworkManager.SceneManager.GetSceneRelativeInSceneNetworkObject(globalObjectIdHash, serializedObject.NetworkSceneHandle); if (networkObject == null) { if (NetworkLog.CurrentLogLevel <= LogLevel.Error) @@ -927,10 +927,10 @@ internal NetworkObject CreateLocalNetworkObject(NetworkObject.NetworkObjectSynch if (networkObject != null) { - networkObject.DestroyWithScene = networkObjectSynchronizer.DestroyWithScene; - networkObject.NetworkSceneHandle = networkObjectSynchronizer.NetworkSceneHandle; - networkObject.DontDestroyWithOwner = networkObjectSynchronizer.DontDestroyWithOwner; - networkObject.Ownership = (NetworkObject.OwnershipStatus)networkObjectSynchronizer.OwnershipFlags; + networkObject.DestroyWithScene = serializedObject.DestroyWithScene; + networkObject.NetworkSceneHandle = serializedObject.NetworkSceneHandle; + networkObject.DontDestroyWithOwner = serializedObject.DontDestroyWithOwner; + networkObject.Ownership = (NetworkObject.OwnershipStatus)serializedObject.OwnershipFlags; var nonNetworkObjectParent = false; // SPECIAL CASE FOR IN-SCENE PLACED: (only when the parent has a NetworkObject) @@ -940,12 +940,12 @@ internal NetworkObject CreateLocalNetworkObject(NetworkObject.NetworkObjectSynch // the parent has changed. // For this we will want to remove the parent before spawning and setting the transform values based // on several possible scenarios. - if (networkObjectSynchronizer.IsSceneObject && networkObject.transform.parent != null) + if (serializedObject.IsSceneObject && networkObject.transform.parent != null) { var parentNetworkObject = networkObject.transform.parent.GetComponent(); // special case to handle being parented under a GameObject with no NetworkObject - nonNetworkObjectParent = !parentNetworkObject && networkObjectSynchronizer.HasParent; + nonNetworkObjectParent = !parentNetworkObject && serializedObject.HasParent; // If the in-scene placed NetworkObject has a parent NetworkObject... if (parentNetworkObject) @@ -955,18 +955,18 @@ internal NetworkObject CreateLocalNetworkObject(NetworkObject.NetworkObjectSynch // - The auhtority says we have a parent but either of the two are true: // -- It isn't the same parent. // -- It was parented using world position stays. - if (!networkObjectSynchronizer.HasParent || (networkObjectSynchronizer.IsLatestParentSet - && (networkObjectSynchronizer.LatestParent.Value != parentNetworkObject.NetworkObjectId || networkObjectSynchronizer.WorldPositionStays))) + if (!serializedObject.HasParent || (serializedObject.IsLatestParentSet + && (serializedObject.LatestParent.Value != parentNetworkObject.NetworkObjectId || serializedObject.WorldPositionStays))) { // If parenting without notifications then we are temporarily removing the parent to set the transform // values before reparenting under the current parent. - networkObject.ApplyNetworkParenting(true, true, enableNotification: !networkObjectSynchronizer.HasParent); + networkObject.ApplyNetworkParenting(true, true, enableNotification: !serializedObject.HasParent); } } } // Set the transform only if the sceneObject includes transform information. - if (networkObjectSynchronizer.HasTransform) + if (serializedObject.HasTransform) { // If world position stays is true or we have auto object parent synchronization disabled // then we want to apply the position and rotation values world space relative @@ -986,7 +986,7 @@ internal NetworkObject CreateLocalNetworkObject(NetworkObject.NetworkObjectSynch // the network prefab used to represent the player. // Note: not doing this would set the player's scale to zero since // that is the default value of Vector3. - if (!networkObjectSynchronizer.IsPlayerObject) + if (!serializedObject.IsPlayerObject) { // Since scale is always applied to local space scale, we do the transform // space logic during serialization such that it works out whether AutoObjectParentSync @@ -995,12 +995,12 @@ internal NetworkObject CreateLocalNetworkObject(NetworkObject.NetworkObjectSynch } } - if (networkObjectSynchronizer.HasParent) + if (serializedObject.HasParent) { // Go ahead and set network parenting properties, if the latest parent is not set then pass in null // (we always want to set worldPositionStays) ulong? parentId = null; - if (networkObjectSynchronizer.IsLatestParentSet) + if (serializedObject.IsLatestParentSet) { parentId = parentNetworkId; } @@ -1009,7 +1009,7 @@ internal NetworkObject CreateLocalNetworkObject(NetworkObject.NetworkObjectSynch // Dynamically spawned NetworkObjects that occur during a LoadSceneMode.Single load scene event are migrated into the DDOL // until the scene is loaded. They are then migrated back into the newly loaded and currently active scene. - if (!networkObjectSynchronizer.IsSceneObject && NetworkSceneManager.IsSpawnedObjectsPendingInDontDestroyOnLoad) + if (!serializedObject.IsSceneObject && NetworkSceneManager.IsSpawnedObjectsPendingInDontDestroyOnLoad) { UnityEngine.Object.DontDestroyOnLoad(networkObject.gameObject); } @@ -1104,9 +1104,9 @@ internal void AuthorityLocalSpawn([NotNull] NetworkObject networkObject, ulong n /// is only invoked by: /// /// - /// IMPORTANT: Pre spawn methods need to be invoked from within . + /// IMPORTANT: Pre spawn methods need to be invoked from within . /// - internal void NonAuthorityLocalSpawn([NotNull] NetworkObject networkObject, in NetworkObject.NetworkObjectSynchronizer networkObjectSynchronizer, bool destroyWithScene) + internal void NonAuthorityLocalSpawn([NotNull] NetworkObject networkObject, in NetworkObject.SerializedObject serializedObject, bool destroyWithScene) { if (networkObject.IsSpawned) { @@ -1115,7 +1115,7 @@ internal void NonAuthorityLocalSpawn([NotNull] NetworkObject networkObject, in N } // Do not invoke Pre spawn here (SynchronizeNetworkBehaviours needs to be invoked prior to this) - SpawnNetworkObjectLocallyCommon(networkObject, networkObjectSynchronizer.NetworkObjectId, networkObjectSynchronizer.IsSceneObject, networkObjectSynchronizer.IsPlayerObject, networkObjectSynchronizer.OwnerClientId, destroyWithScene); + SpawnNetworkObjectLocallyCommon(networkObject, serializedObject.NetworkObjectId, serializedObject.IsSceneObject, serializedObject.IsPlayerObject, serializedObject.OwnerClientId, destroyWithScene); // It is ok to invoke NetworkBehaviour.OnPostSpawn methods networkObject.InvokeBehaviourNetworkPostSpawn(); @@ -1283,7 +1283,7 @@ internal void SendSpawnCallForObject(ulong clientId, NetworkObject networkObject } var message = new CreateObjectMessage { - ObjectSynchronizerInfo = networkObject.GetMessageForSynchronization(clientId, NetworkManager.DistributedAuthorityMode), + ObjectInfo = networkObject.Serialize(clientId, NetworkManager.DistributedAuthorityMode), IncludesSerializedObject = true, UpdateObservers = NetworkManager.DistributedAuthorityMode, ObserverIds = NetworkManager.DistributedAuthorityMode ? networkObject.Observers.ToArray() : null, @@ -1305,7 +1305,7 @@ internal void SendSpawnCallForObserverUpdate(ulong[] newObservers, NetworkObject var message = new CreateObjectMessage { - ObjectSynchronizerInfo = networkObject.GetMessageForSynchronization(), + ObjectInfo = networkObject.Serialize(), ObserverIds = networkObject.Observers.ToArray(), NewObserverIds = newObservers.ToArray(), IncludesSerializedObject = true, From 65e7163601f780bd1879bee8d565af05500d96e3 Mon Sep 17 00:00:00 2001 From: Noellie Velez Date: Tue, 23 Dec 2025 12:32:14 +0100 Subject: [PATCH 04/11] Addressing Changeog feedback from #3810 PR --- com.unity.netcode.gameobjects/CHANGELOG.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/com.unity.netcode.gameobjects/CHANGELOG.md b/com.unity.netcode.gameobjects/CHANGELOG.md index 06109ea401..531f265494 100644 --- a/com.unity.netcode.gameobjects/CHANGELOG.md +++ b/com.unity.netcode.gameobjects/CHANGELOG.md @@ -42,7 +42,6 @@ Additional documentation and release notes are available at [Multiplayer Documen ### Changed - Improve performance of `ParentSyncMessage`. (#3814) -- If the Unity Transport Disconnect Timeout is set to 0 in the Editor, the timeout will be entirely disabeled. (#3810) - Improve performance of `DestroyObjectMessage`. (#3801) - Improve performance of `CreateObjectMessage`. (#3800) - First pass of CoreCLR engine API changes. (#3799) @@ -54,7 +53,7 @@ Additional documentation and release notes are available at [Multiplayer Documen - Ensure `NetworkBehaviour.IsSessionOwner` is correctly set when a new session owner is promoted. (#3817) - Reset extended ownership flags on `NetworkObject` despawn. (#3817) -- Fixed issue where maxCapacity calculation overflows if a developer sets a very, very high (large) m_DisconnectTimeoutMS in the Editor for Unity Transport. (#3810) +- Fixed an integer overflow that occurred when configuring a large disconnect timeout with Unity Transport. (#3810) - Fixed issues with the "Client-server quickstart for Netcode for GameObjects" script having static methods and properties. (#3787) - Fixed issue where a warning message was being logged upon a client disconnecting from a server when the log level is set to developer. (#3786) - Fixed issue where the server or host would no longer have access to the transport id to client id table when processing a transport level client disconnect event. (#3786) From df0dcad9d3935bbe2d09ba2413cde312d1fcccc1 Mon Sep 17 00:00:00 2001 From: Noellie Velez Date: Tue, 23 Dec 2025 12:39:35 +0100 Subject: [PATCH 05/11] Add changelog entry + address PR review feedback --- com.unity.netcode.gameobjects/CHANGELOG.md | 1 + com.unity.netcode.gameobjects/Runtime/Core/NetworkObject.cs | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/com.unity.netcode.gameobjects/CHANGELOG.md b/com.unity.netcode.gameobjects/CHANGELOG.md index 531f265494..09d31d3fa9 100644 --- a/com.unity.netcode.gameobjects/CHANGELOG.md +++ b/com.unity.netcode.gameobjects/CHANGELOG.md @@ -41,6 +41,7 @@ Additional documentation and release notes are available at [Multiplayer Documen ### Changed +- Improve performance of `NetworkObject`. (#3820) - Improve performance of `ParentSyncMessage`. (#3814) - Improve performance of `DestroyObjectMessage`. (#3801) - Improve performance of `CreateObjectMessage`. (#3800) diff --git a/com.unity.netcode.gameobjects/Runtime/Core/NetworkObject.cs b/com.unity.netcode.gameobjects/Runtime/Core/NetworkObject.cs index 08acb669e4..063cd62acf 100644 --- a/com.unity.netcode.gameobjects/Runtime/Core/NetworkObject.cs +++ b/com.unity.netcode.gameobjects/Runtime/Core/NetworkObject.cs @@ -2842,6 +2842,10 @@ public NetworkBehaviour GetNetworkBehaviourAtOrderIndex(ushort index) return ChildNetworkBehaviours[index]; } + /// + /// The serialized representation of a NetworkObject. + /// Used for synchronizing clients on NetworkObject spawn. + /// internal struct SerializedObject { public uint Hash; From 077150cc830406cc3b2beef855d4390d38cfb051 Mon Sep 17 00:00:00 2001 From: Noellie Velez Date: Tue, 23 Dec 2025 12:43:59 +0100 Subject: [PATCH 06/11] Changelog update --- com.unity.netcode.gameobjects/CHANGELOG.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/com.unity.netcode.gameobjects/CHANGELOG.md b/com.unity.netcode.gameobjects/CHANGELOG.md index 09d31d3fa9..2ab98767fd 100644 --- a/com.unity.netcode.gameobjects/CHANGELOG.md +++ b/com.unity.netcode.gameobjects/CHANGELOG.md @@ -13,6 +13,11 @@ Additional documentation and release notes are available at [Multiplayer Documen ### Changed +- Improve performance of `NetworkObject`. (#3820) +- Rename pass: + - SceneObject -- > SerializedObject + - GetMessageSceneObject --> Serialize + - AddSceneObject --> Deserialize (#3820) ### Deprecated @@ -41,7 +46,6 @@ Additional documentation and release notes are available at [Multiplayer Documen ### Changed -- Improve performance of `NetworkObject`. (#3820) - Improve performance of `ParentSyncMessage`. (#3814) - Improve performance of `DestroyObjectMessage`. (#3801) - Improve performance of `CreateObjectMessage`. (#3800) From 1aa7aba80a3a075c45ddcc6133e2aa5333edac3c Mon Sep 17 00:00:00 2001 From: Noellie Velez Date: Tue, 23 Dec 2025 18:56:19 +0100 Subject: [PATCH 07/11] Remove changelog trailing spaces --- com.unity.netcode.gameobjects/CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/com.unity.netcode.gameobjects/CHANGELOG.md b/com.unity.netcode.gameobjects/CHANGELOG.md index 2ab98767fd..7d0bcc8ee5 100644 --- a/com.unity.netcode.gameobjects/CHANGELOG.md +++ b/com.unity.netcode.gameobjects/CHANGELOG.md @@ -15,8 +15,8 @@ Additional documentation and release notes are available at [Multiplayer Documen - Improve performance of `NetworkObject`. (#3820) - Rename pass: - - SceneObject -- > SerializedObject - - GetMessageSceneObject --> Serialize + - SceneObject -- > SerializedObject + - GetMessageSceneObject --> Serialize - AddSceneObject --> Deserialize (#3820) ### Deprecated From 1e124df2e93018b70366551f6e0654499b6b6fa3 Mon Sep 17 00:00:00 2001 From: Noellie Velez Date: Wed, 24 Dec 2025 12:06:06 +0100 Subject: [PATCH 08/11] Fix whitespaces --- .../Runtime/Core/NetworkObject.cs | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/com.unity.netcode.gameobjects/Runtime/Core/NetworkObject.cs b/com.unity.netcode.gameobjects/Runtime/Core/NetworkObject.cs index 063cd62acf..7a37cae07a 100644 --- a/com.unity.netcode.gameobjects/Runtime/Core/NetworkObject.cs +++ b/com.unity.netcode.gameobjects/Runtime/Core/NetworkObject.cs @@ -505,7 +505,7 @@ public void DeferDespawn(int tickOffset, bool destroy = true) /// flag set and a non-owner client must have sent a request via . /// public bool IsRequestInProgress => ((OwnershipStatusExtended)Ownership).HasFlag(OwnershipStatusExtended.Requested); - + /// /// Determines whether a NetworkObject can be distributed to other clients during /// a session. @@ -515,7 +515,7 @@ public void DeferDespawn(int tickOffset, bool destroy = true) #endif [SerializeField] internal OwnershipStatus Ownership = OwnershipStatus.Distributable; - + /// /// Ownership status flags: /// : If nothing is set, then ownership is considered "static" and cannot be redistributed, requested, or transferred (i.e. a Player would have this). @@ -2897,18 +2897,18 @@ internal struct SerializedObject internal ushort GetBitsetRepresentation() { ushort bitset = 0; - if(IsPlayerObject) { bitset |= k_IsPlayerObject; }; - if(HasParent) { bitset |= k_HasParent; }; - if(IsSceneObject) { bitset |= k_IsSceneObject; }; - if(HasTransform) { bitset |= k_HasTransform; }; - if(IsLatestParentSet) { bitset |= k_IsLatestParentSet; }; - if(WorldPositionStays) { bitset |= k_WorldPositionStays; }; - if(DestroyWithScene) { bitset |= k_DestroyWithScene; }; - if(DontDestroyWithOwner) { bitset |= k_DontDestroyWithOwner; }; - if(HasOwnershipFlags) { bitset |= k_HasOwnershipFlags; }; - if(SyncObservers) { bitset |= k_SyncObservers; }; - if(SpawnWithObservers) { bitset |= k_SpawnWithObservers; }; - if(HasInstantiationData) { bitset |= k_HasInstantiationData; }; + if (IsPlayerObject) { bitset |= k_IsPlayerObject; }; + if (HasParent) { bitset |= k_HasParent; }; + if (IsSceneObject) { bitset |= k_IsSceneObject; }; + if (HasTransform) { bitset |= k_HasTransform; }; + if (IsLatestParentSet) { bitset |= k_IsLatestParentSet; }; + if (WorldPositionStays) { bitset |= k_WorldPositionStays; }; + if (DestroyWithScene) { bitset |= k_DestroyWithScene; }; + if (DontDestroyWithOwner) { bitset |= k_DontDestroyWithOwner; }; + if (HasOwnershipFlags) { bitset |= k_HasOwnershipFlags; }; + if (SyncObservers) { bitset |= k_SyncObservers; }; + if (SpawnWithObservers) { bitset |= k_SpawnWithObservers; }; + if (HasInstantiationData) { bitset |= k_HasInstantiationData; }; return bitset; } From b5a0861bfb20b1b4ada56dd559d0b341719e891c Mon Sep 17 00:00:00 2001 From: Noellie Velez Date: Wed, 24 Dec 2025 12:11:27 +0100 Subject: [PATCH 09/11] Remove tab spaces --- com.unity.netcode.gameobjects/Runtime/Core/NetworkObject.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/com.unity.netcode.gameobjects/Runtime/Core/NetworkObject.cs b/com.unity.netcode.gameobjects/Runtime/Core/NetworkObject.cs index 7a37cae07a..608d5360d3 100644 --- a/com.unity.netcode.gameobjects/Runtime/Core/NetworkObject.cs +++ b/com.unity.netcode.gameobjects/Runtime/Core/NetworkObject.cs @@ -505,7 +505,7 @@ public void DeferDespawn(int tickOffset, bool destroy = true) /// flag set and a non-owner client must have sent a request via . /// public bool IsRequestInProgress => ((OwnershipStatusExtended)Ownership).HasFlag(OwnershipStatusExtended.Requested); - + /// /// Determines whether a NetworkObject can be distributed to other clients during /// a session. @@ -515,7 +515,7 @@ public void DeferDespawn(int tickOffset, bool destroy = true) #endif [SerializeField] internal OwnershipStatus Ownership = OwnershipStatus.Distributable; - + /// /// Ownership status flags: /// : If nothing is set, then ownership is considered "static" and cannot be redistributed, requested, or transferred (i.e. a Player would have this). From bbf982623fa78648d33300eab8547226724a9079 Mon Sep 17 00:00:00 2001 From: Noellie Velez Date: Fri, 9 Jan 2026 11:10:31 +0100 Subject: [PATCH 10/11] Addressing PR feedback --- com.unity.netcode.gameobjects/CHANGELOG.md | 4 --- .../Messages/ConnectionApprovedMessage.cs | 10 +++---- .../Messaging/Messages/ParentSyncMessage.cs | 1 + .../Runtime/SceneManagement/SceneEventData.cs | 30 +++++++++---------- 4 files changed, 21 insertions(+), 24 deletions(-) diff --git a/com.unity.netcode.gameobjects/CHANGELOG.md b/com.unity.netcode.gameobjects/CHANGELOG.md index 7d0bcc8ee5..ae7999fd02 100644 --- a/com.unity.netcode.gameobjects/CHANGELOG.md +++ b/com.unity.netcode.gameobjects/CHANGELOG.md @@ -14,10 +14,6 @@ Additional documentation and release notes are available at [Multiplayer Documen ### Changed - Improve performance of `NetworkObject`. (#3820) -- Rename pass: - - SceneObject -- > SerializedObject - - GetMessageSceneObject --> Serialize - - AddSceneObject --> Deserialize (#3820) ### Deprecated diff --git a/com.unity.netcode.gameobjects/Runtime/Messaging/Messages/ConnectionApprovedMessage.cs b/com.unity.netcode.gameobjects/Runtime/Messaging/Messages/ConnectionApprovedMessage.cs index b563d439a1..5a1c5899cc 100644 --- a/com.unity.netcode.gameobjects/Runtime/Messaging/Messages/ConnectionApprovedMessage.cs +++ b/com.unity.netcode.gameobjects/Runtime/Messaging/Messages/ConnectionApprovedMessage.cs @@ -160,8 +160,8 @@ public void Serialize(FastBufferWriter writer, int targetVersion) { sobj.Observers.Add(OwnerClientId); // In distributed authority mode, we send the currently known observers of each NetworkObject to the client being synchronized. - var sceneObject = sobj.Serialize(OwnerClientId, IsDistributedAuthority); - sceneObject.Serialize(writer); + var serializedObject = sobj.Serialize(OwnerClientId, IsDistributedAuthority); + serializedObject.Serialize(writer); ++sceneObjectCount; } } @@ -342,9 +342,9 @@ public void Handle(ref NetworkContext context) // to create a list to hold the data. This is a breach of convention for performance reasons. for (ushort i = 0; i < sceneObjectCount; i++) { - var sceneObject = new NetworkObject.SerializedObject(); - sceneObject.Deserialize(m_ReceivedSceneObjectData); - NetworkObject.Deserialize(sceneObject, m_ReceivedSceneObjectData, networkManager); + var serializedObject = new NetworkObject.SerializedObject(); + serializedObject.Deserialize(m_ReceivedSceneObjectData); + NetworkObject.Deserialize(serializedObject, m_ReceivedSceneObjectData, networkManager); } if (networkManager.AutoSpawnPlayerPrefabClientSide) diff --git a/com.unity.netcode.gameobjects/Runtime/Messaging/Messages/ParentSyncMessage.cs b/com.unity.netcode.gameobjects/Runtime/Messaging/Messages/ParentSyncMessage.cs index 844628608b..39daa80c39 100644 --- a/com.unity.netcode.gameobjects/Runtime/Messaging/Messages/ParentSyncMessage.cs +++ b/com.unity.netcode.gameobjects/Runtime/Messaging/Messages/ParentSyncMessage.cs @@ -38,6 +38,7 @@ internal struct ParentSyncMessage : INetworkMessage public void Serialize(FastBufferWriter writer, int targetVersion) { + byte bitset = 0x00; if (WorldPositionStays) { bitset |= k_WorldPositionStays; } if (IsLatestParentSet) { bitset |= k_IsLatestParentSet; } diff --git a/com.unity.netcode.gameobjects/Runtime/SceneManagement/SceneEventData.cs b/com.unity.netcode.gameobjects/Runtime/SceneManagement/SceneEventData.cs index 4f079ecfa7..165a70fa33 100644 --- a/com.unity.netcode.gameobjects/Runtime/SceneManagement/SceneEventData.cs +++ b/com.unity.netcode.gameobjects/Runtime/SceneManagement/SceneEventData.cs @@ -625,9 +625,9 @@ internal void WriteSceneSynchronizationData(FastBufferWriter writer) var networkObject = m_NetworkObjectsSync[i]; var noStart = writer.Position; // In distributed authority mode, we send the currently known observers of each NetworkObject to the client being synchronized. - var sceneObject = m_NetworkObjectsSync[i].Serialize(TargetClientId, distributedAuthority); + var serializedObject = m_NetworkObjectsSync[i].Serialize(TargetClientId, distributedAuthority); - sceneObject.Serialize(writer); + serializedObject.Serialize(writer); var noStop = writer.Position; totalBytes += noStop - noStart; if (EnableSerializationLogs) @@ -705,8 +705,8 @@ internal void SerializeScenePlacedObjects(FastBufferWriter writer) foreach (var objectToSycn in m_NetworkObjectsSync) { // Serialize the NetworkObject - var sceneObject = objectToSycn.Serialize(TargetClientId, distributedAuthority); - sceneObject.Serialize(writer); + var serializedObject = objectToSycn.Serialize(TargetClientId, distributedAuthority); + serializedObject.Serialize(writer); numberOfObjects++; } @@ -871,18 +871,18 @@ internal void DeserializeScenePlacedObjects() var sceneObjects = new List(); for (ushort i = 0; i < newObjectsCount; i++) { - var sceneObject = new NetworkObject.SerializedObject(); - sceneObject.Deserialize(InternalBuffer); + var serializedObject = new NetworkObject.SerializedObject(); + serializedObject.Deserialize(InternalBuffer); - if (sceneObject.IsSceneObject) + if (serializedObject.IsSceneObject) { // Set our relative scene to the NetworkObject - m_NetworkManager.SceneManager.SetTheSceneBeingSynchronized(sceneObject.NetworkSceneHandle); + m_NetworkManager.SceneManager.SetTheSceneBeingSynchronized(serializedObject.NetworkSceneHandle); } - var networkObject = NetworkObject.Deserialize(sceneObject, InternalBuffer, m_NetworkManager); + var networkObject = NetworkObject.Deserialize(serializedObject, InternalBuffer, m_NetworkManager); - if (sceneObject.IsSceneObject) + if (serializedObject.IsSceneObject) { sceneObjects.Add(networkObject); } @@ -1136,15 +1136,15 @@ internal void SynchronizeSceneNetworkObjects(NetworkManager networkManager) for (int i = 0; i < newObjectsCount; i++) { var noStart = InternalBuffer.Position; - var sceneObject = new NetworkObject.SerializedObject(); - sceneObject.Deserialize(InternalBuffer); + var serializedObject = new NetworkObject.SerializedObject(); + serializedObject.Deserialize(InternalBuffer); // If the sceneObject is in-scene placed, then set the scene being synchronized - if (sceneObject.IsSceneObject) + if (serializedObject.IsSceneObject) { - m_NetworkManager.SceneManager.SetTheSceneBeingSynchronized(sceneObject.NetworkSceneHandle); + m_NetworkManager.SceneManager.SetTheSceneBeingSynchronized(serializedObject.NetworkSceneHandle); } - var spawnedNetworkObject = NetworkObject.Deserialize(sceneObject, InternalBuffer, networkManager); + var spawnedNetworkObject = NetworkObject.Deserialize(serializedObject, InternalBuffer, networkManager); var noStop = InternalBuffer.Position; if (EnableSerializationLogs) From e41c87758a48e71e667d0badbdc981b1f3d1e768 Mon Sep 17 00:00:00 2001 From: Emma Date: Mon, 19 Jan 2026 14:18:46 -0500 Subject: [PATCH 11/11] fix CHANGLOG merge conflict --- com.unity.netcode.gameobjects/CHANGELOG.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/com.unity.netcode.gameobjects/CHANGELOG.md b/com.unity.netcode.gameobjects/CHANGELOG.md index ea3f656e4b..30247ba839 100644 --- a/com.unity.netcode.gameobjects/CHANGELOG.md +++ b/com.unity.netcode.gameobjects/CHANGELOG.md @@ -24,7 +24,7 @@ Additional documentation and release notes are available at [Multiplayer Documen ### Fixed -- Fixed issue where maxCapacity calculation overflows if a developer sets a very, very high (large) m_DisconnectTimeoutMS in the Editor for Unity Transport. (#3810) +- Fixed an integer overflow that occurred when configuring a large disconnect timeout with Unity Transport. (#3810) ### Security @@ -57,7 +57,6 @@ Additional documentation and release notes are available at [Multiplayer Documen - Ensure `NetworkBehaviour.IsSessionOwner` is correctly set when a new session owner is promoted. (#3817) - Fixed issue where spawning a player in distributed authority mode via a client, typically session owner, other than the newly connected client and scene management is disabled then the already spawned players will not properly get synchronized by each owning client due to the newly connected client's identifier already being added prior to synchronization. (#3816) - Reset extended ownership flags on `NetworkObject` despawn. (#3817) -- Fixed an integer overflow that occurred when configuring a large disconnect timeout with Unity Transport. (#3810) - Fixed issues with the "Client-server quickstart for Netcode for GameObjects" script having static methods and properties. (#3787) - Fixed issue where a warning message was being logged upon a client disconnecting from a server when the log level is set to developer. (#3786) - Fixed issue where the server or host would no longer have access to the transport id to client id table when processing a transport level client disconnect event. (#3786)