diff --git a/com.unity.netcode.gameobjects/Runtime/Components/AnticipatedNetworkTransform.cs b/com.unity.netcode.gameobjects/Runtime/Components/AnticipatedNetworkTransform.cs index 9f0545fc6c..eb2abeb288 100644 --- a/com.unity.netcode.gameobjects/Runtime/Components/AnticipatedNetworkTransform.cs +++ b/com.unity.netcode.gameobjects/Runtime/Components/AnticipatedNetworkTransform.cs @@ -86,6 +86,8 @@ public struct TransformState private bool m_OutstandingAuthorityChange = false; + private NetworkManager m_NetworkManager; + #if UNITY_EDITOR private void Reset() { @@ -157,7 +159,7 @@ public bool ShouldReanticipate /// The anticipated position public void AnticipateMove(Vector3 newPosition) { - if (NetworkManager.ShutdownInProgress || !NetworkManager.IsListening) + if (m_NetworkManager == null || m_NetworkManager.ShutdownInProgress || !m_NetworkManager.IsListening) { return; } @@ -170,7 +172,7 @@ public void AnticipateMove(Vector3 newPosition) m_PreviousAnticipatedTransform = m_AnticipatedTransform; - m_LastAnticipaionCounter = NetworkManager.AnticipationSystem.AnticipationCounter; + m_LastAnticipaionCounter = m_NetworkManager.AnticipationSystem.AnticipationCounter; m_SmoothDuration = 0; m_CurrentSmoothTime = 0; @@ -183,7 +185,7 @@ public void AnticipateMove(Vector3 newPosition) /// The anticipated rotation public void AnticipateRotate(Quaternion newRotation) { - if (NetworkManager.ShutdownInProgress || !NetworkManager.IsListening) + if (m_NetworkManager == null || m_NetworkManager.ShutdownInProgress || !m_NetworkManager.IsListening) { return; } @@ -196,7 +198,7 @@ public void AnticipateRotate(Quaternion newRotation) m_PreviousAnticipatedTransform = m_AnticipatedTransform; - m_LastAnticipaionCounter = NetworkManager.AnticipationSystem.AnticipationCounter; + m_LastAnticipaionCounter = m_NetworkManager.AnticipationSystem.AnticipationCounter; m_SmoothDuration = 0; m_CurrentSmoothTime = 0; @@ -209,7 +211,7 @@ public void AnticipateRotate(Quaternion newRotation) /// The anticipated scale public void AnticipateScale(Vector3 newScale) { - if (NetworkManager.ShutdownInProgress || !NetworkManager.IsListening) + if (m_NetworkManager == null || m_NetworkManager.ShutdownInProgress || !m_NetworkManager.IsListening) { return; } @@ -222,7 +224,7 @@ public void AnticipateScale(Vector3 newScale) m_PreviousAnticipatedTransform = m_AnticipatedTransform; - m_LastAnticipaionCounter = NetworkManager.AnticipationSystem.AnticipationCounter; + m_LastAnticipaionCounter = m_NetworkManager.AnticipationSystem.AnticipationCounter; m_SmoothDuration = 0; m_CurrentSmoothTime = 0; @@ -235,7 +237,7 @@ public void AnticipateScale(Vector3 newScale) /// The anticipated transform state public void AnticipateState(TransformState newState) { - if (NetworkManager.ShutdownInProgress || !NetworkManager.IsListening) + if (m_NetworkManager == null || m_NetworkManager.ShutdownInProgress || !m_NetworkManager.IsListening) { return; } @@ -264,7 +266,7 @@ private void ProcessSmoothing() if (m_CurrentSmoothTime < m_SmoothDuration) { - m_CurrentSmoothTime += NetworkManager.RealTimeProvider.DeltaTime; + m_CurrentSmoothTime += m_NetworkManager.RealTimeProvider.DeltaTime; var transform_ = transform; var pct = math.min(m_CurrentSmoothTime / m_SmoothDuration, 1f); @@ -397,8 +399,8 @@ protected internal override void InternalOnNetworkSessionSynchronized() ResetAnticipatedState(); m_AnticipatedObject = new AnticipatedObject { Transform = this }; - NetworkManager.AnticipationSystem.RegisterForAnticipationEvents(m_AnticipatedObject); - NetworkManager.AnticipationSystem.AllAnticipatedObjects.Add(m_AnticipatedObject); + m_NetworkManager.AnticipationSystem.RegisterForAnticipationEvents(m_AnticipatedObject); + m_NetworkManager.AnticipationSystem.AllAnticipatedObjects.Add(m_AnticipatedObject); } } @@ -410,21 +412,23 @@ protected internal override void InternalOnNetworkSessionSynchronized() protected internal override void InternalOnNetworkPostSpawn() { base.InternalOnNetworkPostSpawn(); - if (!CanCommitToTransform && NetworkManager.IsConnectedClient && !SynchronizeState.IsSynchronizing) + if (!CanCommitToTransform && m_NetworkManager.IsConnectedClient && !SynchronizeState.IsSynchronizing) { m_OutstandingAuthorityChange = true; ApplyAuthoritativeState(); ResetAnticipatedState(); m_AnticipatedObject = new AnticipatedObject { Transform = this }; - NetworkManager.AnticipationSystem.RegisterForAnticipationEvents(m_AnticipatedObject); - NetworkManager.AnticipationSystem.AllAnticipatedObjects.Add(m_AnticipatedObject); + m_NetworkManager.AnticipationSystem.RegisterForAnticipationEvents(m_AnticipatedObject); + m_NetworkManager.AnticipationSystem.AllAnticipatedObjects.Add(m_AnticipatedObject); } } /// public override void OnNetworkSpawn() { - if (NetworkManager.DistributedAuthorityMode) + m_NetworkManager = NetworkManager; + + if (m_NetworkManager.DistributedAuthorityMode) { Debug.LogWarning($"This component is not currently supported in distributed authority."); } @@ -441,8 +445,8 @@ public override void OnNetworkSpawn() ResetAnticipatedState(); m_AnticipatedObject = new AnticipatedObject { Transform = this }; - NetworkManager.AnticipationSystem.RegisterForAnticipationEvents(m_AnticipatedObject); - NetworkManager.AnticipationSystem.AllAnticipatedObjects.Add(m_AnticipatedObject); + m_NetworkManager.AnticipationSystem.RegisterForAnticipationEvents(m_AnticipatedObject); + m_NetworkManager.AnticipationSystem.AllAnticipatedObjects.Add(m_AnticipatedObject); } /// @@ -450,9 +454,9 @@ public override void OnNetworkDespawn() { if (m_AnticipatedObject != null) { - NetworkManager.AnticipationSystem.DeregisterForAnticipationEvents(m_AnticipatedObject); - NetworkManager.AnticipationSystem.AllAnticipatedObjects.Remove(m_AnticipatedObject); - NetworkManager.AnticipationSystem.ObjectsToReanticipate.Remove(m_AnticipatedObject); + m_NetworkManager.AnticipationSystem.DeregisterForAnticipationEvents(m_AnticipatedObject); + m_NetworkManager.AnticipationSystem.AllAnticipatedObjects.Remove(m_AnticipatedObject); + m_NetworkManager.AnticipationSystem.ObjectsToReanticipate.Remove(m_AnticipatedObject); m_AnticipatedObject = null; } ResetAnticipatedState(); @@ -465,9 +469,9 @@ public override void OnDestroy() { if (m_AnticipatedObject != null) { - NetworkManager.AnticipationSystem.DeregisterForAnticipationEvents(m_AnticipatedObject); - NetworkManager.AnticipationSystem.AllAnticipatedObjects.Remove(m_AnticipatedObject); - NetworkManager.AnticipationSystem.ObjectsToReanticipate.Remove(m_AnticipatedObject); + m_NetworkManager.AnticipationSystem.DeregisterForAnticipationEvents(m_AnticipatedObject); + m_NetworkManager.AnticipationSystem.AllAnticipatedObjects.Remove(m_AnticipatedObject); + m_NetworkManager.AnticipationSystem.ObjectsToReanticipate.Remove(m_AnticipatedObject); m_AnticipatedObject = null; } @@ -514,7 +518,7 @@ public void Smooth(TransformState from, TransformState to, float durationSeconds protected override void OnBeforeUpdateTransformState() { // this is called when new data comes from the server - m_LastAuthorityUpdateCounter = NetworkManager.AnticipationSystem.LastAnticipationAck; + m_LastAuthorityUpdateCounter = m_NetworkManager.AnticipationSystem.LastAnticipationAck; m_OutstandingAuthorityChange = true; } @@ -567,7 +571,7 @@ protected override void OnTransformUpdated() m_AnticipatedTransform = m_AuthoritativeTransform; ShouldReanticipate = true; - NetworkManager.AnticipationSystem.ObjectsToReanticipate.Add(m_AnticipatedObject); + m_NetworkManager.AnticipationSystem.ObjectsToReanticipate.Add(m_AnticipatedObject); } } } diff --git a/com.unity.netcode.gameobjects/Runtime/Components/NetworkAnimator.cs b/com.unity.netcode.gameobjects/Runtime/Components/NetworkAnimator.cs index 2fe642162a..b4ca574471 100644 --- a/com.unity.netcode.gameobjects/Runtime/Components/NetworkAnimator.cs +++ b/com.unity.netcode.gameobjects/Runtime/Components/NetworkAnimator.cs @@ -27,7 +27,7 @@ private void FlushMessages() foreach (var animationUpdate in m_SendAnimationUpdates) { - if (m_NetworkAnimator.NetworkManager.DistributedAuthorityMode) + if (m_NetworkAnimator.DistributedAuthorityMode) { m_NetworkAnimator.SendAnimStateRpc(animationUpdate.AnimationMessage); } @@ -41,7 +41,7 @@ private void FlushMessages() foreach (var sendEntry in m_SendParameterUpdates) { - if (m_NetworkAnimator.NetworkManager.DistributedAuthorityMode) + if (m_NetworkAnimator.DistributedAuthorityMode) { m_NetworkAnimator.SendParametersUpdateRpc(sendEntry.ParametersUpdateMessage); } @@ -54,7 +54,7 @@ private void FlushMessages() foreach (var sendEntry in m_SendTriggerUpdates) { - if (m_NetworkAnimator.NetworkManager.DistributedAuthorityMode) + if (m_NetworkAnimator.DistributedAuthorityMode) { m_NetworkAnimator.SendAnimTriggerRpc(sendEntry.AnimationTriggerMessage); } @@ -213,6 +213,11 @@ internal class TransitionStateinfo // [Layer][DestinationState][TransitionStateInfo] private Dictionary> m_DestinationStateToTransitioninfo = new Dictionary>(); + // Named differently to avoid serialization conflicts with NetworkBehaviour + private NetworkManager m_LocalNetworkManager; + + internal bool DistributedAuthorityMode; + /// /// Builds the m_DestinationStateToTransitioninfo lookup table /// @@ -509,7 +514,12 @@ internal bool IsServerAuthoritative() /// protected virtual bool OnIsServerAuthoritative() { - return NetworkManager ? !NetworkManager.DistributedAuthorityMode : true; + if (!m_LocalNetworkManager) + { + return true; + } + + return !DistributedAuthorityMode; } private int[] m_TransitionHash; @@ -713,6 +723,10 @@ internal AnimationMessage GetAnimationMessage() /// public override void OnNetworkSpawn() { + // Save internal state references + m_LocalNetworkManager = NetworkManager; + DistributedAuthorityMode = m_LocalNetworkManager.DistributedAuthorityMode; + // If there is no assigned Animator then generate a server network warning (logged locally and if applicable on the server-host side as well). if (m_Animator == null) { @@ -963,7 +977,7 @@ internal void CheckForAnimatorChanges() if (m_Animator.runtimeAnimatorController == null) { - if (NetworkManager.LogLevel == LogLevel.Developer) + if (m_LocalNetworkManager.LogLevel == LogLevel.Developer) { Debug.LogError($"[{GetType().Name}] Could not find an assigned {nameof(RuntimeAnimatorController)}! Cannot check {nameof(Animator)} for changes in state!"); } @@ -985,7 +999,7 @@ internal void CheckForAnimatorChanges() // Send an AnimationMessage only if there are dirty AnimationStates to send if (m_AnimationMessage.IsDirtyCount > 0) { - if (NetworkManager.DistributedAuthorityMode) + if (DistributedAuthorityMode) { SendAnimStateRpc(m_AnimationMessage); } @@ -998,9 +1012,9 @@ internal void CheckForAnimatorChanges() { // Just notify all remote clients and not the local server m_ClientSendList.Clear(); - foreach (var clientId in NetworkManager.ConnectionManager.ConnectedClientIds) + foreach (var clientId in m_LocalNetworkManager.ConnectionManager.ConnectedClientIds) { - if (clientId == NetworkManager.LocalClientId || !NetworkObject.Observers.Contains(clientId)) + if (clientId == m_LocalNetworkManager.LocalClientId || !NetworkObject.Observers.Contains(clientId)) { continue; } @@ -1020,7 +1034,7 @@ private void SendParametersUpdate(ClientRpcParams clientRpcParams = default, boo { Parameters = m_ParameterWriter.ToArray() }; - if (NetworkManager.DistributedAuthorityMode) + if (DistributedAuthorityMode) { if (IsOwner) { @@ -1028,7 +1042,7 @@ private void SendParametersUpdate(ClientRpcParams clientRpcParams = default, boo } else { - Debug.LogError($"[{name}][Client-{NetworkManager.LocalClientId}] Attempting to send parameter updates but not the owner!"); + Debug.LogError($"[{name}][Client-{m_LocalNetworkManager.LocalClientId}] Attempting to send parameter updates but not the owner!"); } } else @@ -1266,12 +1280,12 @@ internal void UpdateAnimationState(AnimationState animationState) // Cross fade from the current to the destination state for the transitions duration while starting at the server's current normalized time of the transition m_Animator.CrossFade(transitionStateInfo.DestinationState, transitionStateInfo.TransitionDuration, transitionStateInfo.Layer, 0.0f, animationState.NormalizedTime); } - else if (NetworkManager.LogLevel == LogLevel.Developer) + else if (m_LocalNetworkManager.LogLevel == LogLevel.Developer) { NetworkLog.LogWarning($"Current State Hash ({currentState.fullPathHash}) != AnimationState.StateHash ({animationState.StateHash})"); } } - else if (NetworkManager.LogLevel == LogLevel.Developer) + else if (m_LocalNetworkManager.LogLevel == LogLevel.Developer) { NetworkLog.LogError($"[DestinationState To Transition Info] Layer ({animationState.Layer}) sub-table does not contain destination state ({animationState.DestinationStateHash})!"); } @@ -1314,21 +1328,24 @@ private unsafe void SendParametersUpdateServerRpc(ParametersUpdateMessage parame return; } UpdateParameters(ref parametersUpdate); - if (NetworkManager.ConnectedClientsIds.Count > (IsHost ? 2 : 1)) + var connectedClientIds = m_LocalNetworkManager.ConnectionManager.ConnectedClientIds; + if (connectedClientIds.Count <= (IsHost ? 2 : 1)) { - m_ClientSendList.Clear(); - foreach (var clientId in NetworkManager.ConnectionManager.ConnectedClientIds) + return; + } + + m_ClientSendList.Clear(); + foreach (var clientId in connectedClientIds) + { + if (clientId == serverRpcParams.Receive.SenderClientId || clientId == NetworkManager.ServerClientId || !NetworkObject.Observers.Contains(clientId)) { - if (clientId == serverRpcParams.Receive.SenderClientId || clientId == NetworkManager.ServerClientId || !NetworkObject.Observers.Contains(clientId)) - { - continue; - } - m_ClientSendList.Add(clientId); + continue; } - - m_ClientRpcParams.Send.TargetClientIds = m_ClientSendList; - m_NetworkAnimatorStateChangeHandler.SendParameterUpdate(parametersUpdate, m_ClientRpcParams); + m_ClientSendList.Add(clientId); } + + m_ClientRpcParams.Send.TargetClientIds = m_ClientSendList; + m_NetworkAnimatorStateChangeHandler.SendParameterUpdate(parametersUpdate, m_ClientRpcParams); } } @@ -1377,20 +1394,23 @@ private void SendAnimStateServerRpc(AnimationMessage animationMessage, ServerRpc UpdateAnimationState(animationState); } - if (NetworkManager.ConnectedClientsIds.Count > (IsHost ? 2 : 1)) + var connectedClientIds = m_LocalNetworkManager.ConnectionManager.ConnectedClientIds; + if (connectedClientIds.Count <= (IsHost ? 2 : 1)) { - m_ClientSendList.Clear(); - foreach (var clientId in NetworkManager.ConnectionManager.ConnectedClientIds) + return; + } + + m_ClientSendList.Clear(); + foreach (var clientId in connectedClientIds) + { + if (clientId == serverRpcParams.Receive.SenderClientId || clientId == NetworkManager.ServerClientId || !NetworkObject.Observers.Contains(clientId)) { - if (clientId == serverRpcParams.Receive.SenderClientId || clientId == NetworkManager.ServerClientId || !NetworkObject.Observers.Contains(clientId)) - { - continue; - } - m_ClientSendList.Add(clientId); + continue; } - m_ClientRpcParams.Send.TargetClientIds = m_ClientSendList; - m_NetworkAnimatorStateChangeHandler.SendAnimationUpdate(animationMessage, m_ClientRpcParams); + m_ClientSendList.Add(clientId); } + m_ClientRpcParams.Send.TargetClientIds = m_ClientSendList; + m_NetworkAnimatorStateChangeHandler.SendAnimationUpdate(animationMessage, m_ClientRpcParams); } } @@ -1416,10 +1436,10 @@ private void ProcessAnimStates(AnimationMessage animationMessage) { if (HasAuthority) { - if (NetworkManager.LogLevel == LogLevel.Developer) + if (m_LocalNetworkManager.LogLevel == LogLevel.Developer) { - var hostOrOwner = NetworkManager.DistributedAuthorityMode ? "Owner" : "Host"; - var clientServerOrDAMode = NetworkManager.DistributedAuthorityMode ? "distributed authority" : "client-server"; + var hostOrOwner = DistributedAuthorityMode ? "Owner" : "Host"; + var clientServerOrDAMode = DistributedAuthorityMode ? "distributed authority" : "client-server"; NetworkLog.LogWarning($"Detected the {hostOrOwner} is sending itself animation updates in {clientServerOrDAMode} mode! Please report this issue."); } return; @@ -1443,7 +1463,7 @@ internal void SendAnimTriggerServerRpc(AnimationTriggerMessage animationTriggerM // Ignore if a non-owner sent this. if (serverRpcParams.Receive.SenderClientId != OwnerClientId) { - if (NetworkManager.LogLevel == LogLevel.Developer) + if (m_LocalNetworkManager.LogLevel == LogLevel.Developer) { NetworkLog.LogWarning($"[Owner Authoritative] Detected the a non-authoritative client is sending the server animation trigger updates. If you recently changed ownership of the {name} object, then this could be the reason."); } @@ -1453,8 +1473,10 @@ internal void SendAnimTriggerServerRpc(AnimationTriggerMessage animationTriggerM // set the trigger locally on the server InternalSetTrigger(animationTriggerMessage.Hash, animationTriggerMessage.IsTriggerSet); + var connectedClientIds = m_LocalNetworkManager.ConnectionManager.ConnectedClientIds; + m_ClientSendList.Clear(); - foreach (var clientId in NetworkManager.ConnectionManager.ConnectedClientIds) + foreach (var clientId in connectedClientIds) { if (clientId == NetworkManager.ServerClientId || !NetworkObject.Observers.Contains(clientId)) { @@ -1466,7 +1488,7 @@ internal void SendAnimTriggerServerRpc(AnimationTriggerMessage animationTriggerM { m_NetworkAnimatorStateChangeHandler.QueueTriggerUpdateToClient(animationTriggerMessage, m_ClientRpcParams); } - else if (NetworkManager.ConnectedClientsIds.Count > (IsHost ? 2 : 1)) + else if (connectedClientIds.Count > (IsHost ? 2 : 1)) { m_ClientSendList.Remove(serverRpcParams.Receive.SenderClientId); m_NetworkAnimatorStateChangeHandler.QueueTriggerUpdateToClient(animationTriggerMessage, m_ClientRpcParams); @@ -1531,12 +1553,12 @@ public void SetTrigger(int hash, bool setTrigger = true) // will happen when SendAnimTriggerClientRpc is called. For a client owner, we call the // SendAnimTriggerServerRpc and then trigger locally when running in owner authority mode. var animTriggerMessage = new AnimationTriggerMessage() { Hash = hash, IsTriggerSet = setTrigger }; - if (NetworkManager.DistributedAuthorityMode && HasAuthority) + if (DistributedAuthorityMode && HasAuthority) { m_NetworkAnimatorStateChangeHandler.QueueTriggerUpdateToClient(animTriggerMessage); InternalSetTrigger(hash, setTrigger); } - else if (!NetworkManager.DistributedAuthorityMode && (IsOwner || IsServer)) + else if (!DistributedAuthorityMode && (IsOwner || IsServer)) { if (IsServer) { diff --git a/com.unity.netcode.gameobjects/Runtime/Connection/NetworkConnectionManager.cs b/com.unity.netcode.gameobjects/Runtime/Connection/NetworkConnectionManager.cs index ccaab404e4..5123c4b2c1 100644 --- a/com.unity.netcode.gameobjects/Runtime/Connection/NetworkConnectionManager.cs +++ b/com.unity.netcode.gameobjects/Runtime/Connection/NetworkConnectionManager.cs @@ -954,6 +954,7 @@ internal void CreateAndSpawnPlayer(ulong ownerId) var globalObjectIdHash = playerPrefab.GetComponent().GlobalObjectIdHash; var networkObject = NetworkManager.SpawnManager.GetNetworkObjectToSpawn(globalObjectIdHash, ownerId, playerPrefab.transform.position, playerPrefab.transform.rotation); networkObject.IsSceneObject = false; + networkObject.NetworkManagerOwner = NetworkManager; networkObject.SpawnAsPlayerObject(ownerId, networkObject.DestroyWithScene); } } diff --git a/com.unity.netcode.gameobjects/Runtime/Core/NetworkBehaviour.cs b/com.unity.netcode.gameobjects/Runtime/Core/NetworkBehaviour.cs index 332694af7d..a93164e23d 100644 --- a/com.unity.netcode.gameobjects/Runtime/Core/NetworkBehaviour.cs +++ b/com.unity.netcode.gameobjects/Runtime/Core/NetworkBehaviour.cs @@ -3,7 +3,6 @@ using Unity.Collections; using UnityEngine; - namespace Unity.Netcode { /// @@ -87,7 +86,7 @@ internal FastBufferWriter __beginSendServerRpc(uint rpcMethodId, ServerRpcParams internal void __endSendServerRpc(ref FastBufferWriter bufferWriter, uint rpcMethodId, ServerRpcParams serverRpcParams, RpcDelivery rpcDelivery) #pragma warning restore IDE1006 // restore naming rule violation check { - var networkManager = NetworkManager; + var networkManager = m_NetworkManager; var serverRpcMessage = new ServerRpcMessage { Metadata = new RpcMetadata @@ -138,14 +137,14 @@ internal void __endSendServerRpc(ref FastBufferWriter bufferWriter, uint rpcMeth } else { - rpcWriteSize = NetworkManager.ConnectionManager.SendMessage(ref serverRpcMessage, networkDelivery, NetworkManager.ServerClientId); + rpcWriteSize = networkManager.ConnectionManager.SendMessage(ref serverRpcMessage, networkDelivery, NetworkManager.ServerClientId); } bufferWriter.Dispose(); #if DEVELOPMENT_BUILD || UNITY_EDITOR || UNITY_MP_TOOLS_NET_STATS_MONITOR_ENABLED_IN_RELEASE if (__rpc_name_table[GetType()].TryGetValue(rpcMethodId, out var rpcMethodName)) { - NetworkManager.NetworkMetrics.TrackRpcSent( + networkManager.NetworkMetrics.TrackRpcSent( NetworkManager.ServerClientId, m_NetworkObject, rpcMethodName, @@ -173,7 +172,7 @@ internal FastBufferWriter __beginSendClientRpc(uint rpcMethodId, ClientRpcParams internal void __endSendClientRpc(ref FastBufferWriter bufferWriter, uint rpcMethodId, ClientRpcParams clientRpcParams, RpcDelivery rpcDelivery) #pragma warning restore IDE1006 // restore naming rule violation check { - var networkManager = NetworkManager; + var networkManager = m_NetworkManager; var clientRpcMessage = new ClientRpcMessage { Metadata = new RpcMetadata @@ -221,7 +220,7 @@ internal void __endSendClientRpc(ref FastBufferWriter bufferWriter, uint rpcMeth NetworkLog.LogError(GenerateObserverErrorMessage(clientRpcParams, targetClientId)); } } - rpcWriteSize = NetworkManager.ConnectionManager.SendMessage(ref clientRpcMessage, networkDelivery, in clientRpcParams.Send.TargetClientIds); + rpcWriteSize = m_NetworkManager.ConnectionManager.SendMessage(ref clientRpcMessage, networkDelivery, in clientRpcParams.Send.TargetClientIds); } else if (clientRpcParams.Send.TargetClientIdsNativeArray != null) { @@ -238,7 +237,7 @@ internal void __endSendClientRpc(ref FastBufferWriter bufferWriter, uint rpcMeth NetworkLog.LogError(GenerateObserverErrorMessage(clientRpcParams, targetClientId)); } } - rpcWriteSize = NetworkManager.ConnectionManager.SendMessage(ref clientRpcMessage, networkDelivery, clientRpcParams.Send.TargetClientIdsNativeArray.Value); + rpcWriteSize = networkManager.ConnectionManager.SendMessage(ref clientRpcMessage, networkDelivery, clientRpcParams.Send.TargetClientIdsNativeArray.Value); } else { @@ -246,12 +245,12 @@ internal void __endSendClientRpc(ref FastBufferWriter bufferWriter, uint rpcMeth while (observerEnumerator.MoveNext()) { // Skip over the host - if (IsHost && observerEnumerator.Current == NetworkManager.LocalClientId) + if (IsHost && observerEnumerator.Current == networkManager.LocalClientId) { shouldInvokeLocally = true; continue; } - rpcWriteSize = NetworkManager.ConnectionManager.SendMessage(ref clientRpcMessage, networkDelivery, observerEnumerator.Current); + rpcWriteSize = networkManager.ConnectionManager.SendMessage(ref clientRpcMessage, networkDelivery, observerEnumerator.Current); } } @@ -349,7 +348,7 @@ internal void __endSendRpc(ref FastBufferWriter bufferWriter, uint rpcMethodId, NetworkBehaviourId = NetworkBehaviourId, NetworkRpcMethodId = rpcMethodId, }, - SenderClientId = NetworkManager.LocalClientId, + SenderClientId = m_NetworkManager.LocalClientId, WriteBuffer = bufferWriter }; @@ -361,7 +360,7 @@ internal void __endSendRpc(ref FastBufferWriter bufferWriter, uint rpcMethodId, networkDelivery = NetworkDelivery.ReliableFragmentedSequenced; break; case RpcDelivery.Unreliable: - if (bufferWriter.Length > NetworkManager.MessageManager.NonFragmentedMessageMaxSize) + if (bufferWriter.Length > m_NetworkManager.MessageManager.NonFragmentedMessageMaxSize) { throw new OverflowException("RPC parameters are too large for unreliable delivery."); } @@ -436,6 +435,8 @@ internal string GenerateObserverErrorMessage(ClientRpcParams clientRpcParams, ul return $"Sending ClientRpc to non-observer! {containerNameHoldingId} contains clientId {targetClientId} that is not an observer!"; } + private NetworkManager m_NetworkManager; + /// /// Gets the NetworkManager that owns this NetworkBehaviour instance. /// See `NetworkObject` note for how there is a chicken/egg problem when not initialized. @@ -444,9 +445,14 @@ public NetworkManager NetworkManager { get { + if (m_NetworkManager != null) + { + return m_NetworkManager; + } + if (NetworkObject?.NetworkManager != null) { - return NetworkObject?.NetworkManager; + return NetworkObject.NetworkManager; } return NetworkManager.Singleton; @@ -469,7 +475,7 @@ public NetworkManager NetworkManager /// . /// #pragma warning restore IDE0001 - public RpcTarget RpcTarget => NetworkManager.RpcTarget; + public RpcTarget RpcTarget { get; private set; } /// /// If a NetworkObject is assigned, returns whether the NetworkObject @@ -496,23 +502,11 @@ public NetworkManager NetworkManager /// public bool HasAuthority { get; internal set; } - internal NetworkClient LocalClient { get; private set; } /// /// Gets whether the client is the distributed authority mode session owner. /// - public bool IsSessionOwner - { - get - { - if (LocalClient == null) - { - return false; - } - - return LocalClient.IsSessionOwner; - } - } + public bool IsSessionOwner { get; private set; } /// /// Gets whether the server (local or remote) is a host. @@ -543,26 +537,19 @@ public bool IsSessionOwner internal bool IsBehaviourEditable() { - if (!m_NetworkObject) + if (!m_NetworkObject || !m_NetworkManager || !m_NetworkManager.IsListening) { return true; } - if (!m_NetworkObject.NetworkManager) - { - return true; - } - - var networkManager = m_NetworkObject.NetworkManager; - // Only the authority can MODIFY. So allow modification if network is either not running or we are the authority. - return !networkManager.IsListening || - ((networkManager.DistributedAuthorityMode && m_NetworkObject.IsOwner) || (!networkManager.DistributedAuthorityMode && networkManager.IsServer)); + return HasAuthority; } - internal void SetNetworkObject(NetworkObject networkObject) + internal void SetNetworkObject(NetworkObject networkObject, ushort behaviourId) { m_NetworkObject = networkObject; + NetworkBehaviourId = behaviourId; } // TODO: this needs an overhaul. It's expensive, it's ja little naive in how it looks for networkObject in @@ -598,7 +585,7 @@ public NetworkObject NetworkObject // or NetworkBehaviour.IsSpawned (i.e. to early exit if not spawned) which, in turn, could generate several Warning messages // per spawned NetworkObject. Checking for ShutdownInProgress prevents these unnecessary LogWarning messages. // We must check IsSpawned, otherwise a warning will be logged under certain valid conditions (see OnDestroy) - if (IsSpawned && m_NetworkObject == null && (NetworkManager.Singleton == null || !NetworkManager.Singleton.ShutdownInProgress)) + if (IsSpawned && m_NetworkObject == null && (m_NetworkManager == null || !m_NetworkManager.ShutdownInProgress)) { if (NetworkLog.CurrentLogLevel <= LogLevel.Normal) { @@ -615,7 +602,7 @@ public NetworkObject NetworkObject /// public bool HasNetworkObject => NetworkObject != null; - private NetworkObject m_NetworkObject = null; + private NetworkObject m_NetworkObject; /// /// Gets the NetworkId of the NetworkObject that owns this NetworkBehaviour instance. @@ -655,17 +642,12 @@ protected NetworkBehaviour GetNetworkBehaviour(ushort behaviourId) internal void UpdateNetworkProperties() { var networkObject = m_NetworkObject; - var networkManager = NetworkManager; + var networkManager = m_NetworkManager; // Set identification related properties NetworkObjectId = networkObject.NetworkObjectId; IsLocalPlayer = networkObject.IsLocalPlayer; - // This is "OK" because GetNetworkBehaviourOrderIndex uses the order of - // NetworkObject.ChildNetworkBehaviours which is set once when first - // accessed. - NetworkBehaviourId = networkObject.GetNetworkBehaviourOrderIndex(this); - // Set ownership related properties IsOwnedByServer = networkObject.IsOwnedByServer; IsOwner = networkObject.IsOwner; @@ -677,7 +659,7 @@ internal void UpdateNetworkProperties() IsHost = networkManager.IsListening && networkManager.IsHost; IsClient = networkManager.IsListening && networkManager.IsClient; IsServer = networkManager.IsListening && networkManager.IsServer; - LocalClient = networkManager.LocalClient; + IsSessionOwner = networkManager.IsListening && networkManager.LocalClient.IsSessionOwner; HasAuthority = networkObject.HasAuthority; ServerIsHost = networkManager.IsListening && networkManager.ServerIsHost; } @@ -763,6 +745,9 @@ public virtual void OnNetworkPreDespawn() { } internal void NetworkPreSpawn(ref NetworkManager networkManager, NetworkObject networkObject) { m_NetworkObject = networkObject; + m_NetworkManager = networkManager; + RpcTarget = networkManager.RpcTarget; + UpdateNetworkProperties(); try @@ -1106,9 +1091,8 @@ internal void NetworkVariableUpdate(ulong targetClientId, bool forceSend = false } // Getting these ahead of time actually improves performance - var networkManager = NetworkManager; + var networkManager = m_NetworkManager; var networkObject = m_NetworkObject; - var behaviourIndex = networkObject.GetNetworkBehaviourOrderIndex(this); var messageManager = networkManager.MessageManager; var connectionManager = networkManager.ConnectionManager; @@ -1148,7 +1132,7 @@ internal void NetworkVariableUpdate(ulong targetClientId, bool forceSend = false var message = new NetworkVariableDeltaMessage { NetworkObjectId = NetworkObjectId, - NetworkBehaviourIndex = behaviourIndex, + NetworkBehaviourIndex = NetworkBehaviourId, NetworkBehaviour = this, TargetClientId = targetClientId, DeliveryMappedNetworkVariableIndex = m_DeliveryMappedNetworkVariableIndices[j], @@ -1193,7 +1177,7 @@ private bool CouldHaveDirtyNetworkVariables() } // If it's dirty but can't be sent yet, we have to keep monitoring it until one of the // conditions blocking its send changes. - NetworkManager.BehaviourUpdater.AddForUpdate(m_NetworkObject); + m_NetworkManager.BehaviourUpdater.AddForUpdate(m_NetworkObject); } } @@ -1259,7 +1243,7 @@ internal void MarkOwnerReadDirtyAndCheckOwnerWriteIsDirty() internal void WriteNetworkVariableData(FastBufferWriter writer, ulong targetClientId) { // Create any values that require accessing the NetworkManager locally (it is expensive to access it in NetworkBehaviour) - var networkManager = NetworkManager; + var networkManager = m_NetworkManager; var ensureLengthSafety = networkManager.NetworkConfig.EnsureNetworkVariableLengthSafety; foreach (var field in NetworkVariableFields) @@ -1313,7 +1297,7 @@ internal void WriteNetworkVariableData(FastBufferWriter writer, ulong targetClie internal void SetNetworkVariableData(FastBufferReader reader, ulong clientId) { // Stack cache any values that requires accessing the NetworkManager (it is expensive to access it in NetworkBehaviour) - var networkManager = NetworkManager; + var networkManager = m_NetworkManager; var ensureLengthSafety = networkManager.NetworkConfig.EnsureNetworkVariableLengthSafety; foreach (var field in NetworkVariableFields) @@ -1358,7 +1342,7 @@ internal void SetNetworkVariableData(FastBufferReader reader, ulong clientId) var totalBytesRead = reader.Position - readStartPos; if (totalBytesRead != expectedBytesToRead) { - if (NetworkManager.LogLevel <= LogLevel.Normal) + if (networkManager.LogLevel <= LogLevel.Normal) { NetworkLog.LogWarning($"[{name}][NetworkObjectId: {NetworkObjectId}][NetworkBehaviourId: {NetworkBehaviourId}][{field.Name}] NetworkVariable read {totalBytesRead} bytes but was expected to read {expectedBytesToRead} bytes during synchronization deserialization!"); } @@ -1375,7 +1359,7 @@ internal void SetNetworkVariableData(FastBufferReader reader, ulong clientId) /// The NetworkObject instance if found, null if no object exists with the specified networkId protected NetworkObject GetNetworkObject(ulong networkId) { - return NetworkManager.SpawnManager.SpawnedObjects.TryGetValue(networkId, out NetworkObject networkObject) ? networkObject : null; + return m_NetworkManager.SpawnManager.SpawnedObjects.GetValueOrDefault(networkId); } /// @@ -1456,10 +1440,10 @@ internal bool Synchronize(ref BufferSerializer serializer, ulong targetCli catch (Exception ex) { threwException = true; - if (NetworkManager.LogLevel <= LogLevel.Normal) + if (m_NetworkManager.LogLevel <= LogLevel.Normal) { NetworkLog.LogWarning($"{name} threw an exception during synchronization serialization, this {nameof(NetworkBehaviour)} is being skipped and will not be synchronized!"); - if (NetworkManager.LogLevel == LogLevel.Developer) + if (m_NetworkManager.LogLevel == LogLevel.Developer) { NetworkLog.LogError($"{ex.Message}\n {ex.StackTrace}"); } @@ -1503,10 +1487,10 @@ internal bool Synchronize(ref BufferSerializer serializer, ulong targetCli } catch (Exception ex) { - if (NetworkManager.LogLevel <= LogLevel.Normal) + if (m_NetworkManager.LogLevel <= LogLevel.Normal) { NetworkLog.LogWarning($"{name} threw an exception during synchronization deserialization, this {nameof(NetworkBehaviour)} is being skipped and will not be synchronized!"); - if (NetworkManager.LogLevel == LogLevel.Developer) + if (m_NetworkManager.LogLevel == LogLevel.Developer) { NetworkLog.LogError($"{ex.Message}\n {ex.StackTrace}"); } @@ -1517,7 +1501,7 @@ internal bool Synchronize(ref BufferSerializer serializer, ulong targetCli var totalBytesRead = reader.Position - positionBeforeSynchronize; if (totalBytesRead != expectedBytesToRead) { - if (NetworkManager.LogLevel <= LogLevel.Normal) + if (m_NetworkManager.LogLevel <= LogLevel.Normal) { NetworkLog.LogWarning($"{name} read {totalBytesRead} bytes but was expected to read {expectedBytesToRead} bytes during synchronization deserialization! This {nameof(NetworkBehaviour)}({GetType().Name})is being skipped and will not be synchronized!"); } @@ -1553,7 +1537,15 @@ internal virtual void InternalOnDestroy() /// public virtual void OnDestroy() { - InternalOnDestroy(); + try + { + InternalOnDestroy(); + } + catch (Exception ex) + { + Debug.LogException(ex); + } + if (m_NetworkObject != null && m_NetworkObject.IsSpawned && IsSpawned) { // If the associated NetworkObject is still spawned then this @@ -1574,12 +1566,10 @@ public virtual void OnDestroy() } - for (int i = 0; i < NetworkVariableFields.Count; i++) + foreach (var networkVar in NetworkVariableFields) { - NetworkVariableFields[i].Dispose(); + networkVar.Dispose(); } - - m_NetworkObject = null; } } } diff --git a/com.unity.netcode.gameobjects/Runtime/Core/NetworkObject.cs b/com.unity.netcode.gameobjects/Runtime/Core/NetworkObject.cs index 4c0d97c82e..5b7b8b02a7 100644 --- a/com.unity.netcode.gameobjects/Runtime/Core/NetworkObject.cs +++ b/com.unity.netcode.gameobjects/Runtime/Core/NetworkObject.cs @@ -1927,7 +1927,7 @@ public NetworkObject InstantiateAndSpawn(NetworkManager networkManager, ulong ow return null; } - return networkManager.SpawnManager.InstantiateAndSpawnNoParameterChecks(this, ownerClientId, destroyWithScene, isPlayerObject, forceOverride, position, rotation); + return networkManager.SpawnManager.InstantiateAndSpawnNoParameterChecks(this, networkManager, ownerClientId, destroyWithScene, isPlayerObject, forceOverride, position, rotation); } /// @@ -1966,6 +1966,12 @@ public void SpawnAsPlayerObject(ulong clientId, bool destroyWithScene = false) /// (true) the will be destroyed (false) the will persist after being despawned public void Despawn(bool destroy = true) { + if (!IsSpawned) + { + NetworkLog.LogErrorServer("Object is not spawned!"); + return; + } + foreach (var behavior in ChildNetworkBehaviours) { behavior.MarkVariablesDirty(false); @@ -2635,7 +2641,8 @@ internal List ChildNetworkBehaviours } // Set ourselves as the NetworkObject that this behaviour belongs to and add it to the child list - networkBehaviours[i].SetNetworkObject(this); + var nextIndex = (ushort)m_ChildNetworkBehaviours.Count; + networkBehaviours[i].SetNetworkObject(this, nextIndex); m_ChildNetworkBehaviours.Add(networkBehaviours[i]); var type = networkBehaviours[i].GetType(); @@ -3246,6 +3253,8 @@ internal static NetworkObject AddSceneObject(in SceneObject sceneObject, FastBuf return null; } + networkObject.NetworkManagerOwner = networkManager; + // 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; diff --git a/com.unity.netcode.gameobjects/Runtime/SceneManagement/SceneEventData.cs b/com.unity.netcode.gameobjects/Runtime/SceneManagement/SceneEventData.cs index b456197a47..0a91e583c7 100644 --- a/com.unity.netcode.gameobjects/Runtime/SceneManagement/SceneEventData.cs +++ b/com.unity.netcode.gameobjects/Runtime/SceneManagement/SceneEventData.cs @@ -378,6 +378,7 @@ internal void AddDespawnedInSceneNetworkObjects() { if (sobj.IsSceneObject.HasValue && sobj.IsSceneObject.Value && !sobj.IsSpawned) { + sobj.NetworkManagerOwner = m_NetworkManager; m_DespawnedInSceneObjectsSync.Add(sobj); } } @@ -1083,19 +1084,22 @@ private void DeserializeDespawnedInScenePlacedNetworkObjects() } // Now find the in-scene NetworkObject with the current GlobalObjectIdHash we are looking for - if (sceneRelativeNetworkObjects.ContainsKey(globalObjectIdHash)) + if (sceneRelativeNetworkObjects.TryGetValue(globalObjectIdHash, out var despawnedObject)) { + // Set the owner of this network object + despawnedObject.NetworkManagerOwner = m_NetworkManager; + // Since this is a NetworkObject that was never spawned, we just need to send a notification // out that it was despawned so users can make adjustments - sceneRelativeNetworkObjects[globalObjectIdHash].InvokeBehaviourNetworkDespawn(); + despawnedObject.InvokeBehaviourNetworkDespawn(); if (!m_NetworkManager.SceneManager.ScenePlacedObjects.ContainsKey(globalObjectIdHash)) { m_NetworkManager.SceneManager.ScenePlacedObjects.Add(globalObjectIdHash, new Dictionary()); } - if (!m_NetworkManager.SceneManager.ScenePlacedObjects[globalObjectIdHash].ContainsKey(sceneRelativeNetworkObjects[globalObjectIdHash].GetSceneOriginHandle())) + if (!m_NetworkManager.SceneManager.ScenePlacedObjects[globalObjectIdHash].ContainsKey(despawnedObject.GetSceneOriginHandle())) { - m_NetworkManager.SceneManager.ScenePlacedObjects[globalObjectIdHash].Add(sceneRelativeNetworkObjects[globalObjectIdHash].GetSceneOriginHandle(), sceneRelativeNetworkObjects[globalObjectIdHash]); + m_NetworkManager.SceneManager.ScenePlacedObjects[globalObjectIdHash].Add(despawnedObject.GetSceneOriginHandle(), despawnedObject); } } else diff --git a/com.unity.netcode.gameobjects/Runtime/Spawning/NetworkSpawnManager.cs b/com.unity.netcode.gameobjects/Runtime/Spawning/NetworkSpawnManager.cs index 6e4b561db6..ef6bca09ce 100644 --- a/com.unity.netcode.gameobjects/Runtime/Spawning/NetworkSpawnManager.cs +++ b/com.unity.netcode.gameobjects/Runtime/Spawning/NetworkSpawnManager.cs @@ -754,13 +754,13 @@ public NetworkObject InstantiateAndSpawn(NetworkObject networkPrefab, ulong owne return null; } - return InstantiateAndSpawnNoParameterChecks(networkPrefab, ownerClientId, destroyWithScene, isPlayerObject, forceOverride, position, rotation); + return InstantiateAndSpawnNoParameterChecks(networkPrefab, NetworkManager, ownerClientId, destroyWithScene, isPlayerObject, forceOverride, position, rotation); } /// /// !!! Does not perform any parameter checks prior to attempting to instantiate and spawn the NetworkObject !!! /// - internal NetworkObject InstantiateAndSpawnNoParameterChecks(NetworkObject networkPrefab, ulong ownerClientId = NetworkManager.ServerClientId, bool destroyWithScene = false, bool isPlayerObject = false, bool forceOverride = false, Vector3 position = default, Quaternion rotation = default) + internal NetworkObject InstantiateAndSpawnNoParameterChecks(NetworkObject networkPrefab, NetworkManager networkManager, ulong ownerClientId = NetworkManager.ServerClientId, bool destroyWithScene = false, bool isPlayerObject = false, bool forceOverride = false, Vector3 position = default, Quaternion rotation = default) { NetworkObject networkObject; // - Host and clients always instantiate the override if one exists. @@ -782,6 +782,8 @@ internal NetworkObject InstantiateAndSpawnNoParameterChecks(NetworkObject networ Debug.LogError($"Failed to instantiate and spawn {networkPrefab.name}!"); return null; } + + networkObject.NetworkManagerOwner = networkManager; networkObject.IsPlayerObject = isPlayerObject; networkObject.transform.SetPositionAndRotation(position, rotation); // If spawning as a player, then invoke SpawnAsPlayerObject @@ -807,7 +809,6 @@ internal NetworkObject GetNetworkObjectToSpawn(uint globalObjectIdHash, ulong ow { // Let the handler spawn the NetworkObject var prefabHandlerObject = NetworkManager.PrefabHandler.HandleNetworkPrefabSpawn(globalObjectIdHash, ownerId, position ?? default, rotation ?? default, instantiationData); - prefabHandlerObject.NetworkManagerOwner = NetworkManager; return prefabHandlerObject; } @@ -879,7 +880,6 @@ internal NetworkObject InstantiateNetworkPrefab(GameObject networkPrefab, uint p { var networkObject = UnityEngine.Object.Instantiate(networkPrefab).GetComponent(); networkObject.transform.SetPositionAndRotation(position ?? networkObject.transform.position, rotation ?? networkObject.transform.rotation); - networkObject.NetworkManagerOwner = NetworkManager; networkObject.PrefabGlobalObjectIdHash = prefabGlobalObjectIdHash; return networkObject; } @@ -1099,6 +1099,11 @@ internal void SpawnNetworkObjectLocally(NetworkObject networkObject, ulong netwo internal void SpawnNetworkObjectLocallyCommon(NetworkObject networkObject, ulong networkId, bool sceneObject, bool playerObject, ulong ownerClientId, bool destroyWithScene) { + if (networkObject.NetworkManagerOwner == null) + { + Debug.LogError("NetworkManagerOwner should not be null!"); + } + if (SpawnedObjects.ContainsKey(networkId)) { Debug.LogWarning($"[{NetworkManager.name}] Trying to spawn {networkObject.name} with a {nameof(NetworkObject.NetworkObjectId)} of {networkId} but it is already in the spawned list!"); @@ -1114,13 +1119,6 @@ internal void SpawnNetworkObjectLocallyCommon(NetworkObject networkObject, ulong networkObject.SceneOrigin = networkObject.gameObject.scene; } - // For integration testing, this makes sure that the appropriate NetworkManager is assigned to - // the NetworkObject since it uses the NetworkManager.Singleton when not set - if (networkObject.NetworkManagerOwner != NetworkManager) - { - networkObject.NetworkManagerOwner = NetworkManager; - } - networkObject.NetworkObjectId = networkId; networkObject.DestroyWithScene = sceneObject || destroyWithScene; @@ -1320,12 +1318,6 @@ internal void SendSpawnCallForObserverUpdate(ulong[] newObservers, NetworkObject internal void DespawnObject(NetworkObject networkObject, bool destroyObject = false, bool authorityOverride = false) { - if (!networkObject.IsSpawned) - { - NetworkLog.LogErrorServer("Object is not spawned!"); - return; - } - if (!NetworkManager.IsServer && !NetworkManager.DistributedAuthorityMode) { NetworkLog.LogErrorServer("Only server can despawn objects"); diff --git a/com.unity.netcode.gameobjects/Tests/Runtime/DistributedAuthority/DistributedAuthorityCodecTests.cs b/com.unity.netcode.gameobjects/Tests/Runtime/DistributedAuthority/DistributedAuthorityCodecTests.cs index 1f4b31affa..585c3b24d8 100644 --- a/com.unity.netcode.gameobjects/Tests/Runtime/DistributedAuthority/DistributedAuthorityCodecTests.cs +++ b/com.unity.netcode.gameobjects/Tests/Runtime/DistributedAuthority/DistributedAuthorityCodecTests.cs @@ -124,7 +124,11 @@ protected override void OnServerAndClientsCreated() m_Client.NetworkConfig.EnsureNetworkVariableLengthSafety = m_EnsureVariableLengthSafety; utpTransport.ConnectionData.Address = Dns.GetHostAddresses(m_TransportHost).First().ToString(); utpTransport.ConnectionData.Port = k_TransportPort; - m_Client.LogLevel = LogLevel.Developer; + + if (m_EnableVerboseDebug) + { + m_Client.LogLevel = LogLevel.Developer; + } // Validate we are in distributed authority mode with client side spawning and using CMB Service Assert.True(m_Client.NetworkConfig.NetworkTopology == NetworkTopologyTypes.DistributedAuthority, "Distributed authority topology is not set!"); @@ -376,6 +380,10 @@ public IEnumerator SceneEventMessageLoadWithObjects() m_Client.SceneManager.SkipSceneHandling = true; var prefabNetworkObject = m_SpawnObject.GetComponent(); + // We need to preSpawn the behaviours to set the internal data for the synchronize methods + prefabNetworkObject.NetworkManagerOwner = m_Client; + prefabNetworkObject.InvokeBehaviourNetworkPreSpawn(); + m_Client.SceneManager.ScenePlacedObjects.Add(0, new Dictionary() { { new NetworkSceneHandle(1, true), prefabNetworkObject } diff --git a/com.unity.netcode.gameobjects/Tests/Runtime/NetworkBehaviourPrePostSpawnTests.cs b/com.unity.netcode.gameobjects/Tests/Runtime/NetworkBehaviourPrePostSpawnTests.cs index a85d26dd88..06496ac129 100644 --- a/com.unity.netcode.gameobjects/Tests/Runtime/NetworkBehaviourPrePostSpawnTests.cs +++ b/com.unity.netcode.gameobjects/Tests/Runtime/NetworkBehaviourPrePostSpawnTests.cs @@ -43,6 +43,8 @@ internal class NetworkBehaviourPreSpawn : NetworkBehaviour protected override void OnNetworkPreSpawn(ref NetworkManager networkManager) { + Assert.That(NetworkObject.NetworkManagerOwner, Is.Not.Null, "NetworkManagerOwner should be set before calling OnNetworkPreSpawn"); + OnNetworkPreSpawnCalled = true; // If we are the server, then set the randomly generated value (1-200). // Otherwise, just set the value to 0. diff --git a/com.unity.netcode.gameobjects/Tests/Runtime/Prefabs/NetworkPrefabOverrideTests.cs b/com.unity.netcode.gameobjects/Tests/Runtime/Prefabs/NetworkPrefabOverrideTests.cs index cbaffa4470..502146fa24 100644 --- a/com.unity.netcode.gameobjects/Tests/Runtime/Prefabs/NetworkPrefabOverrideTests.cs +++ b/com.unity.netcode.gameobjects/Tests/Runtime/Prefabs/NetworkPrefabOverrideTests.cs @@ -135,9 +135,9 @@ protected override void OnServerAndClientsCreated() { var authorityNetworkManager = GetAuthorityNetworkManager(); // Create a NetworkPrefab with an override - var basePrefab = NetcodeIntegrationTestHelpers.CreateNetworkObject($"{k_PrefabRootName}-base", authorityNetworkManager, true); + var basePrefab = NetcodeIntegrationTestHelpers.CreateNetworkObject($"{k_PrefabRootName}-base", true); basePrefab.AddComponent(); - var targetPrefab = NetcodeIntegrationTestHelpers.CreateNetworkObject($"{k_PrefabRootName}-over", authorityNetworkManager, true); + var targetPrefab = NetcodeIntegrationTestHelpers.CreateNetworkObject($"{k_PrefabRootName}-over", true); targetPrefab.AddComponent(); m_PrefabOverride = new NetworkPrefab() { diff --git a/com.unity.netcode.gameobjects/Tests/Runtime/TestHelpers/IntegrationTestSceneHandler.cs b/com.unity.netcode.gameobjects/Tests/Runtime/TestHelpers/IntegrationTestSceneHandler.cs index 5ca6253026..7786dba6c2 100644 --- a/com.unity.netcode.gameobjects/Tests/Runtime/TestHelpers/IntegrationTestSceneHandler.cs +++ b/com.unity.netcode.gameobjects/Tests/Runtime/TestHelpers/IntegrationTestSceneHandler.cs @@ -176,10 +176,6 @@ private static void ProcessInSceneObjects(Scene scene, NetworkManager networkMan /// private static void ProcessInSceneObject(NetworkObject networkObject, NetworkManager networkManager) { - if (networkObject.NetworkManagerOwner != networkManager) - { - networkObject.NetworkManagerOwner = networkManager; - } if (networkObject.GetComponent() == null) { networkObject.gameObject.AddComponent(); diff --git a/com.unity.netcode.gameobjects/Tests/Runtime/TestHelpers/NetcodeIntegrationTest.cs b/com.unity.netcode.gameobjects/Tests/Runtime/TestHelpers/NetcodeIntegrationTest.cs index fedc6a05da..0756d94f38 100644 --- a/com.unity.netcode.gameobjects/Tests/Runtime/TestHelpers/NetcodeIntegrationTest.cs +++ b/com.unity.netcode.gameobjects/Tests/Runtime/TestHelpers/NetcodeIntegrationTest.cs @@ -576,6 +576,7 @@ private void InternalOnOneTimeSetup() IsRunning = true; m_EnableVerboseDebug = OnSetVerboseDebug(); IntegrationTestSceneHandler.VerboseDebugMode = m_EnableVerboseDebug; + NetworkManagerHelper.VerboseDebugMode = m_EnableVerboseDebug; VerboseDebug($"Entering {nameof(OneTimeSetup)}"); m_NetworkManagerInstatiationMode = OnSetIntegrationTestMode(); @@ -1735,7 +1736,6 @@ protected void DestroySceneNetworkObjects() if (CanDestroyNetworkObject(networkObject)) { - networkObject.NetworkManagerOwner = m_ServerNetworkManager; // Destroy the GameObject that holds the NetworkObject component Object.DestroyImmediate(networkObject.gameObject); } diff --git a/com.unity.netcode.gameobjects/Tests/Runtime/TestHelpers/NetcodeIntegrationTestHelpers.cs b/com.unity.netcode.gameobjects/Tests/Runtime/TestHelpers/NetcodeIntegrationTestHelpers.cs index b33f47cd01..92fb80e265 100644 --- a/com.unity.netcode.gameobjects/Tests/Runtime/TestHelpers/NetcodeIntegrationTestHelpers.cs +++ b/com.unity.netcode.gameobjects/Tests/Runtime/TestHelpers/NetcodeIntegrationTestHelpers.cs @@ -686,18 +686,16 @@ public static void MakeNetworkObjectTestPrefab(NetworkObject networkObject, uint /// /// Creates a to be used with integration testing /// - /// namr of the object - /// owner of the object + /// name of the object /// when true, the instance is automatically migrated into the DDOL /// - internal static GameObject CreateNetworkObject(string baseName, NetworkManager owner, bool moveToDDOL = false) + internal static GameObject CreateNetworkObject(string baseName, bool moveToDDOL = false) { var gameObject = new GameObject { name = baseName }; var networkObject = gameObject.AddComponent(); - networkObject.NetworkManagerOwner = owner; MakeNetworkObjectTestPrefab(networkObject); if (moveToDDOL) { @@ -724,7 +722,7 @@ public static GameObject CreateNetworkObjectPrefab(string baseName, NetworkManag Assert.IsNotNull(authorityNetworkManager, prefabCreateAssertError); Assert.IsFalse(authorityNetworkManager.IsListening, prefabCreateAssertError); - var gameObject = CreateNetworkObject(baseName, authorityNetworkManager); + var gameObject = CreateNetworkObject(baseName); var networkPrefab = new NetworkPrefab() { Prefab = gameObject }; // We could refactor this test framework to share a NetworkPrefabList instance, but at this point it's @@ -750,27 +748,6 @@ public static GameObject CreateNetworkObjectPrefab(string baseName, NetworkManag [Obsolete("This method is no longer valid or used.", false)] public static void MarkAsSceneObjectRoot(GameObject networkObjectRoot, NetworkManager server, NetworkManager[] clients) { - networkObjectRoot.name += " - Server"; - - NetworkObject[] serverNetworkObjects = networkObjectRoot.GetComponentsInChildren(); - - for (int i = 0; i < serverNetworkObjects.Length; i++) - { - serverNetworkObjects[i].NetworkManagerOwner = server; - } - - for (int i = 0; i < clients.Length; i++) - { - GameObject root = Object.Instantiate(networkObjectRoot); - root.name += " - Client - " + i; - - NetworkObject[] clientNetworkObjects = root.GetComponentsInChildren(); - - for (int j = 0; j < clientNetworkObjects.Length; j++) - { - clientNetworkObjects[j].NetworkManagerOwner = clients[i]; - } - } } /// diff --git a/com.unity.netcode.gameobjects/Tests/Runtime/TestHelpers/NetworkManagerHelper.cs b/com.unity.netcode.gameobjects/Tests/Runtime/TestHelpers/NetworkManagerHelper.cs index 7a1a4e5afa..035d11dfb5 100644 --- a/com.unity.netcode.gameobjects/Tests/Runtime/TestHelpers/NetworkManagerHelper.cs +++ b/com.unity.netcode.gameobjects/Tests/Runtime/TestHelpers/NetworkManagerHelper.cs @@ -44,6 +44,11 @@ public static class NetworkManagerHelper /// public static NetworkManagerOperatingMode CurrentNetworkManagerMode; + /// + /// When true, logs will be generated for lifecycle events. + /// + public static bool VerboseDebugMode; + /// /// This provides the ability to start NetworkManager in various modes /// @@ -97,7 +102,7 @@ public static bool StartNetworkManager(out NetworkManager networkManager, Networ return false; } - Debug.Log($"{nameof(NetworkManager)} Instantiated."); + VerboseLog($"{nameof(NetworkManager)} Instantiated."); var unityTransport = NetworkManagerGameObject.AddComponent(); if (networkConfig == null) @@ -165,10 +170,11 @@ public static T AddComponentToObject(Guid gameObjectIdentifier) where T : Net /// ID returned to reference the game object public static void SpawnNetworkObject(Guid gameObjectIdentifier) { - Assert.IsTrue(InstantiatedNetworkObjects.ContainsKey(gameObjectIdentifier)); - if (!InstantiatedNetworkObjects[gameObjectIdentifier].IsSpawned) + Assert.IsTrue(InstantiatedNetworkObjects.TryGetValue(gameObjectIdentifier, out var objToSpawn)); + if (!objToSpawn.IsSpawned) { - InstantiatedNetworkObjects[gameObjectIdentifier].Spawn(); + objToSpawn.NetworkManagerOwner = NetworkManager.Singleton; + objToSpawn.Spawn(); } } @@ -212,7 +218,7 @@ private static void StartNetworkManagerMode(NetworkManagerOperatingMode managerM } // Only log this if we started an netcode session - Debug.Log($"{CurrentNetworkManagerMode} started."); + VerboseLog($"{CurrentNetworkManagerMode} started."); } } @@ -223,7 +229,7 @@ private static void StopNetworkManagerMode() { NetworkManagerObject.Shutdown(); - Debug.Log($"{CurrentNetworkManagerMode} stopped."); + VerboseLog($"{CurrentNetworkManagerMode} stopped."); CurrentNetworkManagerMode = NetworkManagerOperatingMode.None; } @@ -243,11 +249,11 @@ public static void ShutdownNetworkManager() if (NetworkManagerGameObject != null) { - Debug.Log($"{nameof(NetworkManager)} shutdown."); + VerboseLog($"{nameof(NetworkManager)} shutdown."); StopNetworkManagerMode(); UnityEngine.Object.DestroyImmediate(NetworkManagerGameObject); - Debug.Log($"{nameof(NetworkManager)} destroyed."); + VerboseLog($"{nameof(NetworkManager)} destroyed."); } NetworkManagerGameObject = null; NetworkManagerObject = null; @@ -304,5 +310,13 @@ public static bool BuffersMatch(int indexOffset, long targetSize, byte[] sourceA } return true; } + + private static void VerboseLog(string message) + { + if (VerboseDebugMode) + { + Debug.unityLogger.Log(message); + } + } } }