diff --git a/com.unity.netcode.gameobjects/Runtime/Components/NetworkAnimator.cs b/com.unity.netcode.gameobjects/Runtime/Components/NetworkAnimator.cs index 2cde6a1be6..3de004b053 100644 --- a/com.unity.netcode.gameobjects/Runtime/Components/NetworkAnimator.cs +++ b/com.unity.netcode.gameobjects/Runtime/Components/NetworkAnimator.cs @@ -194,6 +194,7 @@ internal void DeregisterUpdate() internal NetworkAnimatorStateChangeHandler(NetworkAnimator networkAnimator) { m_NetworkAnimator = networkAnimator; + // TODO can we use m_LocalNetworkManager here or other cached var? m_IsServer = networkAnimator.NetworkManager.IsServer; NetworkUpdateLoop.RegisterNetworkUpdate(this, NetworkUpdateStage.PreUpdate); } @@ -1505,7 +1506,7 @@ internal void UpdateAnimationState(AnimationState animationState) } } // For reference, it is valid to have no transition information - //else if (NetworkManager.LogLevel == LogLevel.Developer) + //else if (m_LocalNetworkManager.LogLevel == LogLevel.Developer) //{ // NetworkLog.LogError($"[DestinationState To Transition Info] Layer ({animationState.Layer}) does not exist!"); //} diff --git a/com.unity.netcode.gameobjects/Runtime/Components/NetworkRigidBodyBase.cs b/com.unity.netcode.gameobjects/Runtime/Components/NetworkRigidBodyBase.cs index 9fbf8a26c9..d560b14952 100644 --- a/com.unity.netcode.gameobjects/Runtime/Components/NetworkRigidBodyBase.cs +++ b/com.unity.netcode.gameobjects/Runtime/Components/NetworkRigidBodyBase.cs @@ -971,6 +971,7 @@ protected override void OnOwnershipChanged(ulong previous, ulong current) /// internal void UpdateOwnershipAuthority() { + // TODO do we have a cached NetworkManager here? Should we create one? if (NetworkManager.DistributedAuthorityMode) { // When in distributed authority mode, always use HasAuthority @@ -980,6 +981,7 @@ internal void UpdateOwnershipAuthority() { if (NetworkTransform.IsServerAuthoritative()) { + // TODO do we have a cached NetworkManager here? Should we create one m_IsAuthority = NetworkManager.IsServer; } else @@ -997,6 +999,7 @@ internal void UpdateOwnershipAuthority() /// public override void OnNetworkSpawn() { + // TODO do we have a cached NetworkManager here? Should we create one m_TickFrequency = 1.0f / NetworkManager.NetworkConfig.TickRate; m_TickRate = NetworkManager.NetworkConfig.TickRate; UpdateOwnershipAuthority(); diff --git a/com.unity.netcode.gameobjects/Runtime/Components/NetworkTransform.cs b/com.unity.netcode.gameobjects/Runtime/Components/NetworkTransform.cs index 7c44ba13cb..e7cc2befe2 100644 --- a/com.unity.netcode.gameobjects/Runtime/Components/NetworkTransform.cs +++ b/com.unity.netcode.gameobjects/Runtime/Components/NetworkTransform.cs @@ -1619,7 +1619,7 @@ internal bool SynchronizeScale public bool CanCommitToTransform { get; protected set; } /// - /// Internally used by to keep track of the instance assigned to this + /// Internally used by to keep track of the instance assigned to /// this derived class instance. /// protected NetworkManager m_CachedNetworkManager; @@ -1850,6 +1850,7 @@ private bool ShouldSynchronizeHalfFloat(ulong targetClientId) if (!IsServerAuthoritative() && NetworkObject.OwnerClientId == targetClientId) { // In distributed authority mode we want to synchronize the half float if we are the owner. + // TODO do we have a cached NetworkManager here? Should we create one? return (!NetworkManager.DistributedAuthorityMode && NetworkObject.IsOwnedByServer) || (NetworkManager.DistributedAuthorityMode); } return true; @@ -2092,12 +2093,14 @@ internal bool ApplyTransformToNetworkState(ref NetworkTransformState networkStat return CheckForStateChange(ref networkState); } + //private int m_CachedTickRateValue; /// /// Applies the transform to the specified. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] private bool CheckForStateChange(ref NetworkTransformState networkState, bool isSynchronization = false, ulong targetClientId = 0, bool forceState = false) { + var cachedTickRateValue = (int)m_CachedNetworkManager.NetworkConfig.TickRate; var flagStates = networkState.FlagStates; // As long as we are not doing our first synchronization and we are sending unreliable deltas, each @@ -2112,9 +2115,8 @@ private bool CheckForStateChange(ref NetworkTransformState networkState, bool is // We compare against the NetworkTickSystem version since ServerTime is set when updating ticks if (UseUnreliableDeltas && !isSynchronization && m_DeltaSynch && m_NextTickSync <= CurrentTick) { - // TODO-CACHE: m_CachedNetworkManager.NetworkConfig.TickRate value // Increment to the next frame synch tick position for this instance - m_NextTickSync += (int)m_CachedNetworkManager.NetworkConfig.TickRate; + m_NextTickSync += cachedTickRateValue; // If we are teleporting, we do not need to send a frame synch for this tick slot // as a "frame synch" really is effectively just a teleport. isAxisSync = !flagStates.IsTeleportingNextFrame; @@ -3297,7 +3299,7 @@ private void OnNetworkStateChanged(NetworkTransformState oldState, NetworkTransf } // Get the time when this new state was sent - newState.SentTime = new NetworkTime(m_CachedNetworkManager.NetworkTickSystem.TickRate, newState.NetworkTick).Time; + newState.SentTime = new NetworkTime(m_CachedNetworkTickRate, newState.NetworkTick).Time; if (LogStateUpdate) { @@ -3526,7 +3528,7 @@ protected internal override void InternalOnNetworkPostSpawn() // Then we want to: // - Force the "IsSynchronizing" flag so the NetworkTransform has its state updated properly and runs through the initialization again. // - Make sure the SynchronizingState is updated to the instantiated prefab's default flags/settings. - if (NetworkManager.IsServer && !NetworkManager.DistributedAuthorityMode && !IsOwner && !OnIsServerAuthoritative() && !SynchronizeState.IsSynchronizing) + if (m_CachedNetworkManager.IsServer && !m_CachedNetworkManager.DistributedAuthorityMode && !IsOwner && !OnIsServerAuthoritative() && !SynchronizeState.IsSynchronizing) { // Handle the first/root NetworkTransform slightly differently to have a sequenced synchronization of like authority nested NetworkTransform components if (m_IsFirstNetworkTransform) @@ -3554,7 +3556,7 @@ protected internal override void InternalOnNetworkPostSpawn() } // Standard non-authority synchronization is handled here - if (!CanCommitToTransform && NetworkManager.IsConnectedClient && SynchronizeState.IsSynchronizing) + if (!CanCommitToTransform && m_CachedNetworkManager.IsConnectedClient && SynchronizeState.IsSynchronizing) { NonAuthorityFinalizeSynchronization(); } @@ -3569,6 +3571,7 @@ protected internal override void InternalOnNetworkPostSpawn() internal static InterpolationTypes DefaultInterpolationType; internal Transform CachedTransform; + private uint m_CachedNetworkTickRate; /// /// Create interpolators when first instantiated to avoid memory allocations if the @@ -3599,6 +3602,7 @@ protected virtual void Awake() internal override void InternalOnNetworkPreSpawn(ref NetworkManager networkManager) { m_CachedNetworkManager = networkManager; + m_CachedNetworkTickRate = m_CachedNetworkManager.NetworkTickSystem.TickRate; CachedTransform = transform; base.InternalOnNetworkPreSpawn(ref networkManager); } @@ -3607,7 +3611,6 @@ internal override void InternalOnNetworkPreSpawn(ref NetworkManager networkManag public override void OnNetworkSpawn() { m_ParentedChildren.Clear(); - m_CachedNetworkManager = NetworkManager; Initialize(); @@ -3625,9 +3628,9 @@ private void CleanUpOnDestroyOrDespawn() #else var forUpdate = true; #endif - if (m_CachedNetworkObject != null) + if (m_CachedNetworkObject) { - NetworkManager?.NetworkTransformRegistration(m_CachedNetworkObject, forUpdate, false); + m_CachedNetworkManager?.NetworkTransformRegistration(m_CachedNetworkObject, forUpdate, false); } DeregisterForTickUpdate(this); @@ -3673,7 +3676,7 @@ protected virtual void OnInitialize(ref NetworkVariable r /// private void ResetInterpolatedStateToCurrentAuthoritativeState() { - var serverTime = NetworkManager.ServerTime.Time; + var serverTime = m_CachedNetworkManager.ServerTime.Time; #if COM_UNITY_MODULES_PHYSICS || COM_UNITY_MODULES_PHYSICS2D var position = m_UseRigidbodyForMotion ? m_NetworkRigidbodyInternal.GetPosition() : GetSpaceRelativePosition(); var rotation = m_UseRigidbodyForMotion ? m_NetworkRigidbodyInternal.GetRotation() : GetSpaceRelativeRotation(); @@ -3695,7 +3698,7 @@ private void ResetInterpolatedStateToCurrentAuthoritativeState() } private NetworkObject m_CachedNetworkObject; /// - /// The internal initialzation method to allow for internal API adjustments + /// The internal initialization method to allow for internal API adjustments /// /// private void InternalInitialization(bool isOwnershipChange = false) @@ -3707,7 +3710,7 @@ private void InternalInitialization(bool isOwnershipChange = false) m_CachedNetworkObject = NetworkObject; // Determine if this is the first NetworkTransform in the associated NetworkObject's list - m_IsFirstNetworkTransform = NetworkObject.NetworkTransforms[0] == this; + m_IsFirstNetworkTransform = m_CachedNetworkObject.NetworkTransforms[0] == this; if (m_CachedNetworkManager && m_CachedNetworkManager.DistributedAuthorityMode) { @@ -3719,7 +3722,7 @@ private void InternalInitialization(bool isOwnershipChange = false) { if (CanCommitToTransform) { - if (NetworkObject.HasParentNetworkObject(transform)) + if (m_CachedNetworkObject.HasParentNetworkObject(transform)) { InLocalSpace = true; } @@ -3736,9 +3739,9 @@ private void InternalInitialization(bool isOwnershipChange = false) var currentPosition = GetSpaceRelativePosition(); var currentRotation = GetSpaceRelativeRotation(); - if (NetworkManager.DistributedAuthorityMode) + if (m_CachedNetworkManager.DistributedAuthorityMode) { - RegisterNetworkManagerForTickUpdate(NetworkManager); + RegisterNetworkManagerForTickUpdate(m_CachedNetworkManager); } #if COM_UNITY_MODULES_PHYSICS || COM_UNITY_MODULES_PHYSICS2D @@ -3890,7 +3893,7 @@ private void DefaultParentChanged() m_RotationInterpolator.Clear(); // Always use NetworkManager here as this can be invoked prior to spawning - var tempTime = new NetworkTime(NetworkManager.NetworkConfig.TickRate, NetworkManager.ServerTime.Tick).Time; + var tempTime = new NetworkTime(NetworkManager.NetworkConfig.TickRate, m_CachedNetworkManager.ServerTime.Tick).Time; UpdatePositionInterpolator(m_InternalCurrentPosition, tempTime, true); m_ScaleInterpolator.ResetTo(m_InternalCurrentScale, tempTime); m_RotationInterpolator.ResetTo(m_InternalCurrentRotation, tempTime); @@ -3922,7 +3925,7 @@ internal override void InternalOnNetworkObjectParentChanged(NetworkObject parent if (LastTickSync == m_LocalAuthoritativeNetworkState.GetNetworkTick()) { m_InternalCurrentPosition = m_LastStateTargetPosition = GetSpaceRelativePosition(); - m_PositionInterpolator.ResetTo(m_PositionInterpolator.Parent, m_InternalCurrentPosition, NetworkManager.ServerTime.Time); + m_PositionInterpolator.ResetTo(m_PositionInterpolator.Parent, m_InternalCurrentPosition, m_CachedNetworkManager.ServerTime.Time); if (InLocalSpace) { transform.localPosition = m_InternalCurrentPosition; @@ -3954,7 +3957,7 @@ internal override void InternalOnNetworkObjectParentChanged(NetworkObject parent { m_InternalCurrentRotation = GetSpaceRelativeRotation(); m_TargetRotation = m_InternalCurrentRotation.eulerAngles; - m_RotationInterpolator.ResetTo(m_RotationInterpolator.Parent, m_InternalCurrentRotation, NetworkManager.ServerTime.Time); + m_RotationInterpolator.ResetTo(m_RotationInterpolator.Parent, m_InternalCurrentRotation, m_CachedNetworkManager.ServerTime.Time); if (InLocalSpace) { transform.localRotation = m_InternalCurrentRotation; @@ -4577,7 +4580,7 @@ internal void TransformStateUpdate() { // TODO: Investigate where this state should be applied or just discarded. // For now, discard the state if we assumed ownership. - // Debug.Log($"[Client-{NetworkManager.LocalClientId}] Ignoring inbound update from Client-{0} and parentUpdated:{isParentingDirective}!"); + // Debug.Log($"[Client-{m_CachedNetworkManager.LocalClientId}] Ignoring inbound update from Client-{0} and parentUpdated:{isParentingDirective}!"); return; } // Store the previous/old state @@ -4638,13 +4641,13 @@ private void UpdateTransformState() { continue; } - NetworkManager.MessageManager.SendMessage(ref m_OutboundMessage, networkDelivery, clientId); + m_CachedNetworkManager.MessageManager.SendMessage(ref m_OutboundMessage, networkDelivery, clientId); } } else { // Clients (owner authoritative) send messages to the server-host - NetworkManager.MessageManager.SendMessage(ref m_OutboundMessage, networkDelivery, NetworkManager.ServerClientId); + m_CachedNetworkManager.MessageManager.SendMessage(ref m_OutboundMessage, networkDelivery, NetworkManager.ServerClientId); } m_LocalAuthoritativeNetworkState.LastSerializedSize = m_OutboundMessage.BytesWritten; } @@ -4690,6 +4693,7 @@ internal static float GetTickLatency(NetworkManager networkManager) /// Only valid on clients. /// /// Returns the tick latency and local offset in seconds and as a float value. + /// Can this be called before spawn? public static float GetTickLatency() { return GetTickLatency(NetworkManager.Singleton); @@ -4783,7 +4787,7 @@ public NetworkTransformTickRegistration(NetworkManager networkManager) internal void RegisterForTickSynchronization() { s_TickSynchPosition++; - m_NextTickSync = NetworkManager.ServerTime.Tick + (s_TickSynchPosition % (int)NetworkManager.NetworkConfig.TickRate); + m_NextTickSync = m_CachedNetworkManager.ServerTime.Tick + (s_TickSynchPosition % (int)NetworkManager.NetworkConfig.TickRate); } private static void RegisterNetworkManagerForTickUpdate(NetworkManager networkManager) @@ -4802,14 +4806,14 @@ private static void RegisterNetworkManagerForTickUpdate(NetworkManager networkMa /// private static void RegisterForTickUpdate(NetworkTransform networkTransform) { - - if (!networkTransform.NetworkManager.DistributedAuthorityMode && !s_NetworkTickRegistration.ContainsKey(networkTransform.NetworkManager)) + var networkManager = networkTransform.NetworkManager; + if (!networkManager.DistributedAuthorityMode && !s_NetworkTickRegistration.ContainsKey(networkManager)) { - s_NetworkTickRegistration.Add(networkTransform.NetworkManager, new NetworkTransformTickRegistration(networkTransform.NetworkManager)); + s_NetworkTickRegistration.Add(networkManager, new NetworkTransformTickRegistration(networkManager)); } networkTransform.RegisterForTickSynchronization(); - s_NetworkTickRegistration[networkTransform.NetworkManager].NetworkTransforms.Add(networkTransform); + s_NetworkTickRegistration[networkManager].NetworkTransforms.Add(networkTransform); } /// @@ -4819,16 +4823,17 @@ private static void RegisterForTickUpdate(NetworkTransform networkTransform) /// private static void DeregisterForTickUpdate(NetworkTransform networkTransform) { - if (networkTransform.NetworkManager == null) + var networkManager = networkTransform.NetworkManager; + if (!networkManager) { return; } - if (s_NetworkTickRegistration.ContainsKey(networkTransform.NetworkManager)) + if (s_NetworkTickRegistration.ContainsKey(networkManager)) { - s_NetworkTickRegistration[networkTransform.NetworkManager].NetworkTransforms.Remove(networkTransform); - if (!networkTransform.NetworkManager.DistributedAuthorityMode && s_NetworkTickRegistration[networkTransform.NetworkManager].NetworkTransforms.Count == 0) + s_NetworkTickRegistration[networkManager].NetworkTransforms.Remove(networkTransform); + if (!networkManager.DistributedAuthorityMode && s_NetworkTickRegistration[networkManager].NetworkTransforms.Count == 0) { - var registrationEntry = s_NetworkTickRegistration[networkTransform.NetworkManager]; + var registrationEntry = s_NetworkTickRegistration[networkManager]; registrationEntry.Remove(); } } diff --git a/com.unity.netcode.gameobjects/Runtime/Core/NetworkBehaviour.cs b/com.unity.netcode.gameobjects/Runtime/Core/NetworkBehaviour.cs index 9910668f59..aba00cddd4 100644 --- a/com.unity.netcode.gameobjects/Runtime/Core/NetworkBehaviour.cs +++ b/com.unity.netcode.gameobjects/Runtime/Core/NetworkBehaviour.cs @@ -88,6 +88,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 { + // Getting this ahead of time actually improves performance var networkManager = m_NetworkManager; var serverRpcMessage = new ServerRpcMessage { @@ -167,6 +168,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 { + // Getting this ahead of time actually improves performance var networkManager = m_NetworkManager; var clientRpcMessage = new ClientRpcMessage { @@ -215,7 +217,7 @@ internal void __endSendClientRpc(ref FastBufferWriter bufferWriter, uint rpcMeth NetworkLog.LogError(GenerateObserverErrorMessage(clientRpcParams, targetClientId)); } } - rpcWriteSize = m_NetworkManager.ConnectionManager.SendMessage(ref clientRpcMessage, networkDelivery, in clientRpcParams.Send.TargetClientIds); + rpcWriteSize = networkManager.ConnectionManager.SendMessage(ref clientRpcMessage, networkDelivery, in clientRpcParams.Send.TargetClientIds); } else if (clientRpcParams.Send.TargetClientIdsNativeArray != null) { @@ -349,6 +351,7 @@ internal FastBufferWriter __beginSendRpc(uint rpcMethodId, RpcParams rpcParams, internal void __endSendRpc(ref FastBufferWriter bufferWriter, uint rpcMethodId, RpcParams rpcParams, RpcAttribute.RpcAttributeParams attributeParams, SendTo defaultTarget, RpcDelivery rpcDelivery) #pragma warning restore IDE1006 // restore naming rule violation check { + // Sould we create a local networkManager var to improve performance instead of using 2 times m_NetworkManager? var rpcMessage = new RpcMessage { Metadata = new RpcMetadata @@ -574,7 +577,7 @@ public NetworkObject NetworkObject { get { - if (m_NetworkObject != null) + if (m_NetworkObject) { return m_NetworkObject; } @@ -594,7 +597,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 && (m_NetworkManager == null || !m_NetworkManager.ShutdownInProgress)) + if (IsSpawned && !m_NetworkObject && (!m_NetworkManager || !m_NetworkManager.ShutdownInProgress)) { if (NetworkLog.CurrentLogLevel <= LogLevel.Normal) { @@ -650,6 +653,7 @@ protected NetworkBehaviour GetNetworkBehaviour(ushort behaviourId) /// internal void UpdateNetworkProperties() { + // Getting these ahead of time actually improves performance var networkObject = m_NetworkObject; var networkManager = m_NetworkManager; diff --git a/com.unity.netcode.gameobjects/Runtime/Core/NetworkObject.cs b/com.unity.netcode.gameobjects/Runtime/Core/NetworkObject.cs index 311a3df650..98f506662e 100644 --- a/com.unity.netcode.gameobjects/Runtime/Core/NetworkObject.cs +++ b/com.unity.netcode.gameobjects/Runtime/Core/NetworkObject.cs @@ -340,31 +340,31 @@ private void CheckForInScenePlaced() internal bool HasParentNetworkObject(Transform transform) { - if (transform.parent != null) + if (m_CachedParent != null) { - var networkObject = transform.parent.GetComponent(); + var networkObject = m_CachedParent.GetComponent(); if (networkObject != null && networkObject != this) { return true; } - if (transform.parent.parent != null) + if (m_CachedParent.parent != null) { - return HasParentNetworkObject(transform.parent); + return HasParentNetworkObject(m_CachedParent); } } return false; } /// - /// Gets the NetworkManager that owns this NetworkObject instance + /// Gets the NetworkManager that owns this NetworkObject instance. /// public NetworkManager NetworkManager => NetworkManagerOwner ? NetworkManagerOwner : NetworkManager.Singleton; /// /// Useful to know if we should or should not send a message /// - internal bool HasRemoteObservers => !(Observers.Count == 0 || (Observers.Contains(NetworkManager.LocalClientId) && Observers.Count == 1)); + internal bool HasRemoteObservers => !(Observers.Count == 0 || (Observers.Contains(NetworkManagerOwner.LocalClientId) && Observers.Count == 1)); /// /// Distributed Authority Mode Only @@ -398,29 +398,29 @@ internal bool HasParentNetworkObject(Transform transform) /// Defaults to true, determines whether the will be destroyed. public void DeferDespawn(int tickOffset, bool destroy = true) { - if (!NetworkManager.DistributedAuthorityMode) + if (!IsSpawned) { - NetworkLog.LogError($"This method is only available in distributed authority mode."); + NetworkLog.LogError($"Cannot defer despawning {name} because it is not spawned!"); return; } - if (!IsSpawned) + if (!NetworkManagerOwner.DistributedAuthorityMode) { - NetworkLog.LogError($"Cannot defer despawning {name} because it is not spawned!"); + NetworkLog.LogError($"This method is only available in distributed authority mode."); return; } if (!HasAuthority) { - NetworkLog.LogError($"Only the authority can invoke {nameof(DeferDespawn)} and local Client-{NetworkManager.LocalClientId} is not the authority of {name}!"); + NetworkLog.LogError($"Only the authority can invoke {nameof(DeferDespawn)} and local Client-{NetworkManagerOwner.LocalClientId} is not the authority of {name}!"); return; } // Apply the relative tick offset for when this NetworkObject should be despawned on // non-authoritative instances. - DeferredDespawnTick = NetworkManager.ServerTime.Tick + tickOffset; + DeferredDespawnTick = NetworkManagerOwner.ServerTime.Tick + tickOffset; - var connectionManager = NetworkManager.ConnectionManager; + var connectionManager = NetworkManagerOwner.ConnectionManager; for (int i = 0; i < ChildNetworkBehaviours.Count; i++) { @@ -432,7 +432,7 @@ public void DeferDespawn(int tickOffset, bool destroy = true) } // DAHost handles sending updates to all clients - if (NetworkManager.DAHost) + if (NetworkManagerOwner.DAHost) { for (int i = 0; i < connectionManager.ConnectedClientsList.Count; i++) { @@ -601,17 +601,17 @@ internal void RemoveOwnershipExtended(OwnershipStatusExtended extended) /// true or false depending upon lock operation's success public bool SetOwnershipLock(bool lockOwnership = true) { - // If we are not in distributed autority mode, then exit early - if (!NetworkManager.DistributedAuthorityMode) + // If we don't have authority exit early + if (!HasAuthority) { - Debug.LogError($"[Feature Not Allowed In Client-Server Mode] Ownership flags are a distributed authority feature only!"); + NetworkLog.LogWarningServer($"[Attempted Lock Without Authority] Client-{NetworkManager.LocalClientId} is trying to lock ownership but does not have authority!"); return false; } - // If we don't have authority exit early - if (!HasAuthority) + // If we are not in distributed autority mode, then exit early + if (!NetworkManager.DistributedAuthorityMode) { - NetworkLog.LogWarningServer($"[Attempted Lock Without Authority] Client-{NetworkManager.LocalClientId} is trying to lock ownership but does not have authority!"); + Debug.LogError($"[Feature Not Allowed In Client-Server Mode] Ownership flags are a distributed authority feature only!"); return false; } @@ -736,6 +736,11 @@ public enum OwnershipRequestStatus /// This object is marked as SessionOwnerOnly and therefore cannot be requested /// SessionOwnerOnly, + + /// + /// The request is invalid (if not spawned for instance) + /// + Invalid, } /// @@ -754,8 +759,20 @@ public enum OwnershipRequestStatus /// public OwnershipRequestStatus RequestOwnership() { + // An ownership change request can only be made if spawned. + if (!IsSpawned) + { + + if (NetworkManagerOwner.LogLevel <= LogLevel.Normal) + { + NetworkLog.LogWarning($"[{name}] is trying to perform an ownership request but the object is not spawned!"); + } + + return OwnershipRequestStatus.Invalid; + } + // Exit early the local client is already the owner - if (OwnerClientId == NetworkManager.LocalClientId) + if (OwnerClientId == NetworkManagerOwner.LocalClientId) { return OwnershipRequestStatus.AlreadyOwner; } @@ -791,14 +808,14 @@ public OwnershipRequestStatus RequestOwnership() NetworkObjectId = NetworkObjectId, OwnerClientId = OwnerClientId, ClientIdCount = 1, - RequestClientId = NetworkManager.LocalClientId, + RequestClientId = NetworkManagerOwner.LocalClientId, ClientIds = new ulong[1] { OwnerClientId }, DistributedAuthorityMode = true, OwnershipFlags = (ushort)Ownership, }; - var sendTarget = NetworkManager.DAHost ? OwnerClientId : NetworkManager.ServerClientId; - NetworkManager.ConnectionManager.SendMessage(ref changeOwnership, MessageDeliveryType.DefaultDelivery, sendTarget); + var sendTarget = NetworkManagerOwner.DAHost ? OwnerClientId : NetworkManager.ServerClientId; + NetworkManagerOwner.ConnectionManager.SendMessage(ref changeOwnership, MessageDeliveryType.DefaultDelivery, sendTarget); return OwnershipRequestStatus.RequestSent; } @@ -861,9 +878,10 @@ internal void OwnershipRequest(ulong clientRequestingOwnership) // respond to any additional ownership request with OwnershipRequestResponseStatus.RequestInProgress. AddOwnershipExtended(OwnershipStatusExtended.Requested); + // if OwnershipRequestStatus cannot be called before spawn // This action is always authorized as long as the client still has authority. // We need to pass in that this is a request approval ownership change. - NetworkManager.SpawnManager.ChangeOwnership(this, clientRequestingOwnership, HasAuthority, true); + NetworkManagerOwner.SpawnManager.ChangeOwnership(this, clientRequestingOwnership, HasAuthority, true); } else { @@ -877,15 +895,15 @@ internal void OwnershipRequest(ulong clientRequestingOwnership) { ChangeMessageType = ChangeOwnershipMessage.ChangeType.RequestDenied, NetworkObjectId = NetworkObjectId, - OwnerClientId = NetworkManager.LocalClientId, // Always use the local clientId (see above notes) + OwnerClientId = NetworkManagerOwner.LocalClientId, // Always use the local clientId (see above notes) RequestClientId = clientRequestingOwnership, DistributedAuthorityMode = true, OwnershipRequestResponseStatus = (byte)response, OwnershipFlags = (ushort)Ownership, }; - var sendTarget = NetworkManager.DAHost ? clientRequestingOwnership : NetworkManager.ServerClientId; - NetworkManager.ConnectionManager.SendMessage(ref changeOwnership, MessageDeliveryType.DefaultDelivery, sendTarget); + var sendTarget = NetworkManagerOwner.DAHost ? clientRequestingOwnership : NetworkManager.ServerClientId; + NetworkManagerOwner.ConnectionManager.SendMessage(ref changeOwnership, MessageDeliveryType.DefaultDelivery, sendTarget); } } @@ -982,7 +1000,7 @@ public enum OwnershipLockActions /// public bool SetOwnershipStatus(OwnershipStatus status, bool clearAndSet = false, OwnershipLockActions lockAction = OwnershipLockActions.None) { - if (status.HasFlag(OwnershipStatus.SessionOwner) && !NetworkManager.LocalClient.IsSessionOwner) + if (status.HasFlag(OwnershipStatus.SessionOwner) && !NetworkManagerOwner.LocalClient.IsSessionOwner) { NetworkLog.LogWarning("Only the session owner is allowed to set the ownership status to session owner only."); return false; @@ -1072,22 +1090,22 @@ internal void SendOwnershipStatusUpdate() OwnershipFlags = (ushort)Ownership, }; - if (NetworkManager.DAHost) + if (NetworkManagerOwner.DAHost) { foreach (var clientId in Observers) { - if (clientId == NetworkManager.LocalClientId) + if (clientId == NetworkManagerOwner.LocalClientId) { continue; } - NetworkManager.ConnectionManager.SendMessage(ref changeOwnership, MessageDeliveryType.DefaultDelivery, clientId); + NetworkManagerOwner.ConnectionManager.SendMessage(ref changeOwnership, MessageDeliveryType.DefaultDelivery, clientId); } } else { changeOwnership.ClientIdCount = Observers.Count; changeOwnership.ClientIds = Observers.ToArray(); - NetworkManager.ConnectionManager.SendMessage(ref changeOwnership, MessageDeliveryType.DefaultDelivery, NetworkManager.ServerClientId); + NetworkManagerOwner.ConnectionManager.SendMessage(ref changeOwnership, MessageDeliveryType.DefaultDelivery, NetworkManager.ServerClientId); } } @@ -1114,14 +1132,17 @@ public bool HasOwnershipStatus(OwnershipStatus status) [MethodImpl(MethodImplOptions.AggressiveInlining)] private bool InternalHasAuthority() { - var networkManager = NetworkManager; - return networkManager.DistributedAuthorityMode ? OwnerClientId == networkManager.LocalClientId : networkManager.IsServer; + if (!IsSpawned) + { + return false; + } + return NetworkManagerOwner.DistributedAuthorityMode ? OwnerClientId == NetworkManagerOwner.LocalClientId : NetworkManagerOwner.IsServer; } /// /// The NetworkManager that owns this NetworkObject. /// This property controls where this NetworkObject belongs. - /// This property is null by default currently, which means that the above NetworkManager getter will return the Singleton. + /// This property will be null when the NetworkObject is not spawned. /// In the future this is the path where alternative NetworkManagers should be injected for running multi NetworkManagers /// internal NetworkManager NetworkManagerOwner; @@ -1166,17 +1187,17 @@ private bool InternalHasAuthority() /// /// Gets if the object is the personal clients player object /// - public bool IsLocalPlayer => NetworkManager != null && IsPlayerObject && OwnerClientId == NetworkManager.LocalClientId; + public bool IsLocalPlayer => IsSpawned && IsPlayerObject && OwnerClientId == NetworkManagerOwner.LocalClientId; /// /// Gets if the object is owned by the local player or if the object is the local player object /// - public bool IsOwner => NetworkManager != null && OwnerClientId == NetworkManager.LocalClientId; + public bool IsOwner => IsSpawned && OwnerClientId == NetworkManagerOwner.LocalClientId; /// - /// Gets Whether or not the object is owned by anyone + /// Gets whether or not the object is owned by anyone /// - public bool IsOwnedByServer => NetworkManager != null && OwnerClientId == NetworkManager.ServerClientId; + public bool IsOwnedByServer => IsSpawned && OwnerClientId == NetworkManager.ServerClientId; /// /// Gets if the object has yet been spawned across the network @@ -1437,7 +1458,7 @@ public void NetworkShow(ulong clientId) if (!HasAuthority) { - if (NetworkManager.DistributedAuthorityMode) + if (NetworkManagerOwner.DistributedAuthorityMode) { throw new NotServerException($"Only the owner-authority can change visibility when distributed authority mode is enabled!"); } @@ -1449,7 +1470,7 @@ public void NetworkShow(ulong clientId) if (Observers.Contains(clientId)) { - if (NetworkManager.DistributedAuthorityMode) + if (NetworkManagerOwner.DistributedAuthorityMode) { Debug.LogError($"The object {name} is already visible to Client-{clientId}!"); return; @@ -1462,13 +1483,13 @@ public void NetworkShow(ulong clientId) if (CheckObjectVisibility != null && !CheckObjectVisibility(clientId)) { - if (NetworkManager.LogLevel <= LogLevel.Normal) + if (NetworkManagerOwner.LogLevel <= LogLevel.Normal) { NetworkLog.LogWarning($"[NetworkShow] Trying to make {nameof(NetworkObject)} {gameObject.name} visible to client ({clientId}) but {nameof(CheckObjectVisibility)} returned false!"); } return; } - NetworkManager.SpawnManager.MarkObjectForShowingTo(this, clientId); + NetworkManagerOwner.SpawnManager.MarkObjectForShowingTo(this, clientId); Observers.Add(clientId); } @@ -1499,8 +1520,13 @@ public static void NetworkShow(List networkObjects, ulong clientI // Do the safety loop first to prevent putting the netcode in an invalid state. for (int i = 0; i < networkObjects.Count; i++) { + if (!networkObjects[i].IsSpawned) + { + throw new SpawnStateException("Object is not spawned"); + } + var networkObject = networkObjects[i]; - var networkManager = networkObject.NetworkManager; + var networkManager = networkObject.NetworkManagerOwner; if (networkManager.DistributedAuthorityMode && clientId == networkObject.OwnerClientId) { @@ -1516,7 +1542,7 @@ public static void NetworkShow(List networkObjects, ulong clientI // that the local instance does not own if (!networkObjects[i].HasAuthority) { - if (networkObjects[i].NetworkManager.DistributedAuthorityMode) + if (networkObjects[i].NetworkManagerOwner.DistributedAuthorityMode) { // It will log locally and to the "master-host". NetworkLog.LogErrorServer("Only the owner-authority can change visibility when distributed authority mode is enabled!"); @@ -1528,19 +1554,15 @@ public static void NetworkShow(List networkObjects, ulong clientI } } - if (!networkObjects[i].IsSpawned) - { - throw new SpawnStateException("Object is not spawned"); - } if (networkObjects[i].Observers.Contains(clientId)) { throw new VisibilityChangeException($"{nameof(NetworkObject)} with NetworkId: {networkObjects[i].NetworkObjectId} is already visible"); } - if (networkObjects[i].NetworkManager != networkManager) + if (networkObjects[i].NetworkManagerOwner != networkManager) { - throw new ArgumentNullException("All " + nameof(NetworkObject) + "s must belong to the same " + nameof(NetworkManager)); + throw new ArgumentNullException("All " + nameof(NetworkObject) + "s must belong to the same " + nameof(NetworkManagerOwner)); } } @@ -1571,9 +1593,9 @@ public void NetworkHide(ulong clientId) throw new SpawnStateException("Object is not spawned"); } - if (!HasAuthority && !NetworkManager.DAHost) + if (!HasAuthority && !NetworkManagerOwner.DAHost) { - if (NetworkManager.DistributedAuthorityMode) + if (NetworkManagerOwner.DistributedAuthorityMode) { throw new NotServerException($"Only the owner-authority can change visibility when distributed authority mode is enabled!"); } @@ -1583,11 +1605,11 @@ public void NetworkHide(ulong clientId) } } - if (!NetworkManager.SpawnManager.RemoveObjectFromShowingTo(this, clientId)) + if (!NetworkManagerOwner.SpawnManager.RemoveObjectFromShowingTo(this, clientId)) { if (!Observers.Contains(clientId)) { - if (NetworkManager.LogLevel <= LogLevel.Developer) + if (NetworkManagerOwner.LogLevel <= LogLevel.Developer) { Debug.LogWarning($"{name} is already hidden from Client-{clientId}! (ignoring)"); return; @@ -1599,41 +1621,41 @@ public void NetworkHide(ulong clientId) { NetworkObjectId = NetworkObjectId, DestroyGameObject = !IsSceneObject.Value, - IsDistributedAuthority = NetworkManager.DistributedAuthorityMode, - IsTargetedDestroy = NetworkManager.DistributedAuthorityMode, + IsDistributedAuthority = NetworkManagerOwner.DistributedAuthorityMode, + IsTargetedDestroy = NetworkManagerOwner.DistributedAuthorityMode, TargetClientId = clientId, // Just always populate this value whether we write it or not DeferredDespawnTick = DeferredDespawnTick, }; var size = 0; - if (NetworkManager.DistributedAuthorityMode) + if (NetworkManagerOwner.DistributedAuthorityMode) { - if (!NetworkManager.DAHost) + if (!NetworkManagerOwner.DAHost) { // Send destroy call to service or DAHost - size = NetworkManager.ConnectionManager.SendMessage(ref message, MessageDeliveryType.DefaultDelivery, NetworkManager.ServerClientId); + size = NetworkManagerOwner.ConnectionManager.SendMessage(ref message, MessageDeliveryType.DefaultDelivery, NetworkManager.ServerClientId); } else // DAHost mocking service { // Send destroy call - size = NetworkManager.ConnectionManager.SendMessage(ref message, MessageDeliveryType.DefaultDelivery, clientId); + size = NetworkManagerOwner.ConnectionManager.SendMessage(ref message, MessageDeliveryType.DefaultDelivery, clientId); // Broadcast the destroy to all clients so they can update their observers list - foreach (var client in NetworkManager.ConnectionManager.ConnectedClientIds) + foreach (var client in NetworkManagerOwner.ConnectionManager.ConnectedClientIds) { - if (client == clientId || client == NetworkManager.LocalClientId) + if (client == clientId || client == NetworkManagerOwner.LocalClientId) { continue; } - size += NetworkManager.ConnectionManager.SendMessage(ref message, MessageDeliveryType.DefaultDelivery, client); + size += NetworkManagerOwner.ConnectionManager.SendMessage(ref message, MessageDeliveryType.DefaultDelivery, client); } } } else { // Send destroy call - size = NetworkManager.ConnectionManager.SendMessage(ref message, MessageDeliveryType.DefaultDelivery, clientId); + size = NetworkManagerOwner.ConnectionManager.SendMessage(ref message, MessageDeliveryType.DefaultDelivery, clientId); } - NetworkManager.NetworkMetrics.TrackObjectDestroySent(clientId, this, size); + NetworkManagerOwner.NetworkMetrics.TrackObjectDestroySent(clientId, this, size); } } @@ -1664,7 +1686,7 @@ public static void NetworkHide(List networkObjects, ulong clientI for (int i = 0; i < networkObjects.Count; i++) { var networkObject = networkObjects[i]; - var networkManager = networkObject.NetworkManager; + var networkManager = networkObject.NetworkManagerOwner; if (networkManager.DistributedAuthorityMode && clientId == networkObject.OwnerClientId) { @@ -1680,7 +1702,7 @@ public static void NetworkHide(List networkObjects, ulong clientI // that the local instance does not own if (!networkObjects[i].HasAuthority) { - if (networkObjects[i].NetworkManager.DistributedAuthorityMode) + if (networkObjects[i].NetworkManagerOwner.DistributedAuthorityMode) { // It will log locally and to the "master-host". NetworkLog.LogErrorServer($"Only the owner-authority can change hide a {nameof(NetworkObject)} when distributed authority mode is enabled!"); @@ -1703,9 +1725,9 @@ public static void NetworkHide(List networkObjects, ulong clientI throw new VisibilityChangeException($"{nameof(NetworkObject)} with {nameof(NetworkObjectId)}: {networkObjects[i].NetworkObjectId} is already hidden"); } - if (networkObjects[i].NetworkManager != networkManager) + if (networkObjects[i].NetworkManagerOwner != networkManager) { - throw new ArgumentNullException("All " + nameof(NetworkObject) + "s must belong to the same " + nameof(NetworkManager)); + throw new ArgumentNullException("All " + nameof(NetworkObject) + "s must belong to the same " + nameof(NetworkManagerOwner)); } } @@ -1717,6 +1739,7 @@ public static void NetworkHide(List networkObjects, ulong clientI private void OnDestroy() { + // TODO Can we destroy an object before it is spawned? // If no NetworkManager is assigned, then just exit early if (!NetworkManager) { @@ -2160,11 +2183,11 @@ internal void SetNetworkParenting(ulong? latestParent, bool worldPositionStays) /// /// The new parent for this NetworkObject transform will be the child of. /// If true, the parent-relative position, scale and rotation are modified such that the object keeps the same world space position, rotation and scale as before. - /// Whether or not reparenting was successful. + /// Whether or not re-parenting was successful. public bool TrySetParent(Transform parent, bool worldPositionStays = true) { // If we are removing ourself from a parent - if (parent == null) + if (!parent) { return TrySetParent((NetworkObject)null, worldPositionStays); } @@ -2180,7 +2203,7 @@ public bool TrySetParent(Transform parent, bool worldPositionStays = true) /// /// The new parent for this NetworkObject transform will be the child of. /// If true, the parent-relative position, scale and rotation are modified such that the object keeps the same world space position, rotation and scale as before. - /// Whether or not reparenting was successful. + /// Whether or not re-parenting was successful. public bool TrySetParent(GameObject parent, bool worldPositionStays = true) { // If we are removing ourself from a parent @@ -2221,7 +2244,7 @@ public bool TryRemoveParent(bool worldPositionStays = true) /// /// The new parent for this NetworkObject transform will be the child of. /// If true, the parent-relative position, scale and rotation are modified such that the object keeps the same world space position, rotation and scale as before. - /// Whether or not reparenting was successful. + /// Whether or not re-parenting was successful. public bool TrySetParent(NetworkObject parent, bool worldPositionStays = true) { if (!AutoObjectParentSync) @@ -2229,7 +2252,8 @@ public bool TrySetParent(NetworkObject parent, bool worldPositionStays = true) return false; } - if (NetworkManager == null || !NetworkManager.IsListening) + var networkManager = NetworkManager; + if (!networkManager || !networkManager.IsListening) { return false; } @@ -2238,9 +2262,9 @@ public bool TrySetParent(NetworkObject parent, bool worldPositionStays = true) // It wouldn't make sense to not allow parenting, but keeping this note here as a reminder. var isAuthority = HasAuthority || (AllowOwnerToParent && IsOwner); - // If we don't have authority and we are not shutting down, then don't allow any parenting. + // If we don't have authority, and we are not shutting down, then don't allow any parenting. // If we are shutting down and don't have authority then allow it. - if (!isAuthority && !NetworkManager.ShutdownInProgress) + if (!isAuthority && !networkManager.ShutdownInProgress) { return false; } @@ -2250,7 +2274,7 @@ public bool TrySetParent(NetworkObject parent, bool worldPositionStays = true) internal bool InternalTrySetParent(NetworkObject parent, bool worldPositionStays = true) { - if (parent != null && (IsSpawned ^ parent.IsSpawned) && NetworkManager != null && !NetworkManager.ShutdownInProgress) + if (parent && (IsSpawned ^ parent.IsSpawned) && !NetworkManager.ShutdownInProgress) { if (NetworkManager.LogLevel <= LogLevel.Developer) { @@ -2262,7 +2286,7 @@ internal bool InternalTrySetParent(NetworkObject parent, bool worldPositionStays m_CachedWorldPositionStays = worldPositionStays; - if (parent == null) + if (!parent) { CurrentParent = null; transform.SetParent(null, worldPositionStays); @@ -2278,7 +2302,7 @@ internal bool InternalTrySetParent(NetworkObject parent, bool worldPositionStays private void OnTransformParentChanged() { - if (!AutoObjectParentSync || NetworkManager.ShutdownInProgress) + if (!AutoObjectParentSync) { return; } @@ -2288,8 +2312,12 @@ private void OnTransformParentChanged() return; } - if (NetworkManager == null || !NetworkManager.IsListening) + if (!IsSpawned || !NetworkManager.IsListening) { + if (NetworkManager.ShutdownInProgress) + { + return; + } // DANGO-TODO: Review as to whether we want to provide a better way to handle changing parenting of objects when the // object is not spawned. Really, we shouldn't care about these types of changes. if (NetworkManager.DistributedAuthorityMode && m_CachedParent != null && transform.parent == null) @@ -2298,30 +2326,29 @@ private void OnTransformParentChanged() return; } transform.parent = m_CachedParent; - Debug.LogException(new NotListeningException($"{nameof(NetworkManager)} is not listening, start a server or host before reparenting")); + Debug.LogException(new NotListeningException($"{nameof(NetworkManager)} is not listening, start a server or host before re-parenting")); return; } var isAuthority = false; // With distributed authority, we need to track "valid authoritative" parenting changes. // So, either the authority or AuthorityAppliedParenting is considered a "valid parenting change". isAuthority = HasAuthority || AuthorityAppliedParenting || (AllowOwnerToParent && IsOwner); - var distributedAuthority = NetworkManager.DistributedAuthorityMode; + var distributedAuthority = NetworkManagerOwner.DistributedAuthorityMode; // If we do not have authority and we are spawned if (!isAuthority && IsSpawned) { - - // If the cached parent has not already been set and we are in distributed authority mode, then log an exception and exit early as a non-authority instance + // If the cached parent has not already been set, and we are in distributed authority mode, then log an exception and exit early as a non-authority instance // is trying to set the parent. if (distributedAuthority) { transform.parent = m_CachedParent; - NetworkLog.LogError($"[Not Owner] Only the owner-authority of child {gameObject.name}'s {nameof(NetworkObject)} component can reparent it!"); + NetworkLog.LogError($"[Not Owner] Only the owner-authority of child {gameObject.name}'s {nameof(NetworkObject)} component can re-parent it!"); } else { transform.parent = m_CachedParent; - Debug.LogException(new NotServerException($"Only the server can reparent {nameof(NetworkObject)}s")); + Debug.LogException(new NotServerException($"Only the server can re-parent {nameof(NetworkObject)}s")); } return; } @@ -2339,16 +2366,15 @@ private void OnTransformParentChanged() else { transform.parent = m_CachedParent; - Debug.LogException(new SpawnStateException($"{nameof(NetworkObject)} can only be reparented after being spawned")); + Debug.LogException(new SpawnStateException($"{nameof(NetworkObject)} can only be re-parented after being spawned")); } return; } var removeParent = false; var parentTransform = transform.parent; - var parentObject = (NetworkObject)null; if (parentTransform != null) { - if (!transform.parent.TryGetComponent(out parentObject)) + if (!transform.parent.TryGetComponent(out NetworkObject parentObject)) { transform.parent = m_CachedParent; AuthorityAppliedParenting = false; @@ -2359,7 +2385,7 @@ private void OnTransformParentChanged() { transform.parent = m_CachedParent; AuthorityAppliedParenting = false; - Debug.LogException(new SpawnStateException($"{nameof(NetworkObject)} can only be reparented under another spawned {nameof(NetworkObject)}")); + Debug.LogException(new SpawnStateException($"{nameof(NetworkObject)} can only be re-parented under another spawned {nameof(NetworkObject)}")); return; } @@ -2378,7 +2404,7 @@ private void OnTransformParentChanged() var message = new ParentSyncMessage { NetworkObjectId = NetworkObjectId, - IsLatestParentSet = m_LatestParent != null && m_LatestParent.HasValue, + IsLatestParentSet = m_LatestParent is not null && m_LatestParent.HasValue, LatestParent = m_LatestParent, RemoveParent = removeParent, AuthorityApplied = authorityApplied, @@ -2455,15 +2481,15 @@ internal bool ApplyNetworkParenting(bool removeParent = false, bool ignoreNotSpa // has been set, this will not be entered into again (i.e. the later code will be invoked and // users will get notifications when the parent changes). var isInScenePlaced = IsSceneObject.HasValue && IsSceneObject.Value; - if (transform.parent != null && !removeParent && !m_LatestParent.HasValue && isInScenePlaced) + if (transform.parent && !removeParent && !m_LatestParent.HasValue && isInScenePlaced) { var parentNetworkObject = transform.parent.GetComponent(); // If parentNetworkObject is null then the parent is a GameObject without a NetworkObject component - // attached. Under this case, we preserve the hierarchy but we don't keep track of the parenting. + // attached. Under this case, we preserve the hierarchy, but we don't keep track of the parenting. // Note: We only start tracking parenting if the user removes the child from the standard GameObject // parent and then re-parents the child under a GameObject with a NetworkObject component attached. - if (parentNetworkObject == null) + if (!parentNetworkObject) { // If we are parented under a GameObject, go ahead and mark the world position stays as false // so clients synchronize their transform in local space. (only for in-scene placed NetworkObjects) @@ -2479,7 +2505,7 @@ internal bool ApplyNetworkParenting(bool removeParent = false, bool ignoreNotSpa else { // If we made it this far, go ahead and set the network parenting values - // with the WorldPoisitonSays value set to false + // with the WorldPositionSays value set to false. // Note: Since in-scene placed NetworkObjects are parented in the scene // the default "assumption" is that children are parenting local space // relative. @@ -2492,7 +2518,7 @@ internal bool ApplyNetworkParenting(bool removeParent = false, bool ignoreNotSpa } } - // If we are removing the parent or our latest parent is not set, then remove the parent + // If we are removing the parent or our latest parent is not set, then remove the parent. // removeParent is only set when: // - The server-side NetworkObject.OnTransformParentChanged is invoked and the parent is being removed // - The client-side when handling a ParentSyncMessage @@ -3173,7 +3199,7 @@ internal SceneObject GetMessageSceneObject(ulong targetClientId = NetworkManager { var obj = new SceneObject { - HasParent = transform.parent != null, + HasParent = m_CachedParent is not null, WorldPositionStays = m_CachedWorldPositionStays, NetworkObjectId = NetworkObjectId, OwnerClientId = OwnerClientId, @@ -3195,7 +3221,7 @@ internal SceneObject GetMessageSceneObject(ulong targetClientId = NetworkManager // Handle Parenting if (!AlwaysReplicateAsRoot && obj.HasParent) { - var parentNetworkObject = transform.parent.GetComponent(); + var parentNetworkObject = m_CachedParent.GetComponent(); if (parentNetworkObject) { @@ -3418,9 +3444,9 @@ internal void SubscribeToActiveSceneForSynch() /// private void CurrentlyActiveSceneChanged(Scene current, Scene next) { - // Early exit if there is no NetworkManager assigned, the NetworkManager is shutting down, the NetworkObject + // Early exit if the NetworkManager is shutting down, the NetworkObject // is not spawned, or an in-scene placed NetworkObject - if (NetworkManager == null || NetworkManager.ShutdownInProgress || !IsSpawned || IsSceneObject != false) + if (!IsSpawned || IsSceneObject != false || NetworkManager.ShutdownInProgress) { return; } @@ -3489,7 +3515,7 @@ internal void SceneChangedUpdate(Scene scene, bool notify = false) OnMigratedToNewScene?.Invoke(); // Only the authority side will notify clients of non-parented NetworkObject scene changes - if (isAuthority && notify && transform.parent == null) + if (isAuthority && notify && !m_CachedParent) { NetworkManager.SceneManager.NotifyNetworkObjectSceneChanged(this); } @@ -3519,11 +3545,11 @@ private void Awake() /// internal bool UpdateForSceneChanges() { - // Early exit if SceneMigrationSynchronization is disabled, there is no NetworkManager assigned, + // Early exit if SceneMigrationSynchronization is disabled, // the NetworkManager is shutting down, the NetworkObject is not spawned, it is an in-scene placed // NetworkObject, or the GameObject's current scene handle is the same as the SceneOriginHandle - if (!SceneMigrationSynchronization || !IsSpawned || NetworkManager == null || NetworkManager.ShutdownInProgress || - !NetworkManager.NetworkConfig.EnableSceneManagement || IsSceneObject != false || !gameObject) + if (!SceneMigrationSynchronization || !IsSpawned || NetworkManagerOwner.ShutdownInProgress || + !NetworkManagerOwner.NetworkConfig.EnableSceneManagement || IsSceneObject != false || !gameObject) { // Stop checking for a scene migration return false; diff --git a/com.unity.netcode.gameobjects/Runtime/Spawning/NetworkSpawnManager.cs b/com.unity.netcode.gameobjects/Runtime/Spawning/NetworkSpawnManager.cs index 14ea2bc41d..e91e119c17 100644 --- a/com.unity.netcode.gameobjects/Runtime/Spawning/NetworkSpawnManager.cs +++ b/com.unity.netcode.gameobjects/Runtime/Spawning/NetworkSpawnManager.cs @@ -521,6 +521,7 @@ internal void ChangeOwnership(NetworkObject networkObject, ulong clientId, bool throw new NotServerException("Only the server can change ownership"); } + //Should this go at the beginning of the function? if (!networkObject.IsSpawned) { throw new SpawnStateException("Object is not spawned");