diff --git a/com.unity.netcode.gameobjects/CHANGELOG.md b/com.unity.netcode.gameobjects/CHANGELOG.md index ba73356e80..ff9f37f6a8 100644 --- a/com.unity.netcode.gameobjects/CHANGELOG.md +++ b/com.unity.netcode.gameobjects/CHANGELOG.md @@ -22,12 +22,14 @@ Additional documentation and release notes are available at [Multiplayer Documen ### Fixed -- Fixed AnticipatedNetworkTransform not respecting the InLocalSpace flag (#3995) +- Issue where scene migration in a distributed authority session would throw an exception on clients migrating their owned `NetworkObject` instances to a different scene.(#4086) +- Issue where migrating a dynamically spawned or in-scene placed `NetworkObject` into a different scene during awake could result in that spawned instance to not be synchronized. (#4086) - Issue where a NullReferenceException was thrown when a non-authority failed to spawn a NetworkObject. (#4067) - Issue where the active scene was not being serialized as the 1st scene which could result in various errors including a soft synchronization error if, on the client-side, other synchronized scenes had already been loaded prior to the active scene, which is always loaded as `LoadSceneMode.SingleMode` when client synchronization is set to `LoadSceneMode.SingleMode`, resulting in the previously loaded scene(s) to be unloaded. (#4065) - Issue when FastBufferReader is attempting to read a string and all or a portion of the character count has already been read by user script, it could read a character length that results in a negative byte length which could result in an editor crash. (#4052) - Issue where NetworkRigidbodyBase was not applying rotation correctly when using Rigidbody2D. (#4012) - Issue where NetworkRigidbodyBase was always checking the 3D rigid body's interpolation mode when determining if it is kinematic and needs to put the rigid body to sleep and then switch to interpolation. (#4012) +- Fixed AnticipatedNetworkTransform not respecting the InLocalSpace flag. (#3995) ### Security diff --git a/com.unity.netcode.gameobjects/Editor/InScenePlacedProcessor.cs b/com.unity.netcode.gameobjects/Editor/InScenePlacedProcessor.cs index 423ff4a65c..f7529de12c 100644 --- a/com.unity.netcode.gameobjects/Editor/InScenePlacedProcessor.cs +++ b/com.unity.netcode.gameobjects/Editor/InScenePlacedProcessor.cs @@ -1,3 +1,4 @@ +using Unity.Netcode.Logging; using UnityEditor; using UnityEditor.Build; using UnityEditor.Build.Reporting; @@ -19,8 +20,22 @@ internal class SetInScenePlaced : IProcessSceneWithReport public int callbackOrder => 0; public void OnProcessScene(Scene scene, BuildReport report) { + var log = new ContextualLogger(); + log.AddInfo(scene.name, scene.handle); foreach (var networkObject in FindObjects.FromSceneByType(scene, true)) { + if (networkObject.SceneOrigin.IsValid() && networkObject.SceneOrigin.handle != scene.handle) + { + log.Warning(new Context(LogLevel.Developer, $"{nameof(NetworkObject)}'s SceneOrigin doesn't match current scene being processed! Skipping processing.").AddInfo("SceneOrigin", networkObject.SceneOriginHandle).AddNetworkObject(networkObject)); + continue; + } + + if (networkObject.HasBeenSpawned) + { + log.Error(new Context(LogLevel.Normal, $"Processing {nameof(NetworkObject)} that has already been spawned! This should not be possible. Skipping processing.").AddNetworkObject(networkObject)); + continue; + } + networkObject.InScenePlaced = true; } } diff --git a/com.unity.netcode.gameobjects/Editor/NetworkManagerHelper.cs b/com.unity.netcode.gameobjects/Editor/NetworkManagerHelper.cs index a3224e6471..66ddb2b6f0 100644 --- a/com.unity.netcode.gameobjects/Editor/NetworkManagerHelper.cs +++ b/com.unity.netcode.gameobjects/Editor/NetworkManagerHelper.cs @@ -195,11 +195,11 @@ public bool NotifyUserOfNestedNetworkManager(NetworkManager networkManager, bool { return isParented; } - else // If we are no longer a child, then we can remove ourself from this list - if (transform.root == gameObject.transform) - { - s_LastKnownNetworkManagerParents.Remove(networkManager); - } + else if (transform.root == gameObject.transform) + { + // If we are no longer a child, then we can remove ourself from this list + s_LastKnownNetworkManagerParents.Remove(networkManager); + } } if (!EditorApplication.isUpdating && isParented) { diff --git a/com.unity.netcode.gameobjects/Runtime/Components/Interpolator/BufferedLinearInterpolator.cs b/com.unity.netcode.gameobjects/Runtime/Components/Interpolator/BufferedLinearInterpolator.cs index 294cd9989f..8ee288b02f 100644 --- a/com.unity.netcode.gameobjects/Runtime/Components/Interpolator/BufferedLinearInterpolator.cs +++ b/com.unity.netcode.gameobjects/Runtime/Components/Interpolator/BufferedLinearInterpolator.cs @@ -467,20 +467,20 @@ internal T Update(float deltaTime, double tickLatencyAsTime, double minDeltaTime InterpolateState.CurrentValue = InterpolateState.NextValue; } } - else // If the target is reached and we have no more state updates, we want to check to see if we need to reset. - if (m_BufferQueue.Count == 0) + // If the target is reached and we have no more state updates, we want to check to see if we need to reset. + else if (m_BufferQueue.Count == 0) + { + // When the delta between the time sent and the current tick latency time-window is greater than the max delta time + // plus the minimum delta time (a rough estimate of time to wait before we consider rate of change equal to zero), + // we will want to reset the interpolator with the current known value. This prevents the next received state update's + // time to be calculated against the last calculated time which if there is an extended period of time between the two + // it would cause a large delta time period between the two states (i.e. it stops moving for a second or two and then + // starts moving again). + if ((tickLatencyAsTime - InterpolateState.Target.Value.TimeSent) > InterpolateState.MaxDeltaTime + minDeltaTime) { - // When the delta between the time sent and the current tick latency time-window is greater than the max delta time - // plus the minimum delta time (a rough estimate of time to wait before we consider rate of change equal to zero), - // we will want to reset the interpolator with the current known value. This prevents the next received state update's - // time to be calculated against the last calculated time which if there is an extended period of time between the two - // it would cause a large delta time period between the two states (i.e. it stops moving for a second or two and then - // starts moving again). - if ((tickLatencyAsTime - InterpolateState.Target.Value.TimeSent) > InterpolateState.MaxDeltaTime + minDeltaTime) - { - InterpolateState.Reset(InterpolateState.CurrentValue); - } + InterpolateState.Reset(InterpolateState.CurrentValue); } + } } m_NbItemsReceivedThisFrame = 0; return InterpolateState.CurrentValue; @@ -593,20 +593,20 @@ public T Update(float deltaTime, double renderTime, double serverTime) // Determine if we have reached our target InterpolateState.TargetReached = IsApproximately(InterpolateState.CurrentValue, InterpolateState.Target.Value.Item, GetPrecision()); } - else // If the target is reached and we have no more state updates, we want to check to see if we need to reset. - if (InterpolateState.TargetReached && m_BufferQueue.Count == 0) + // If the target is reached and we have no more state updates, we want to check to see if we need to reset. + else if (InterpolateState.TargetReached && m_BufferQueue.Count == 0) + { + // When the delta between the time sent and the current tick latency time-window is greater than the max delta time + // plus the minimum delta time (a rough estimate of time to wait before we consider rate of change equal to zero), + // we will want to reset the interpolator with the current known value. This prevents the next received state update's + // time to be calculated against the last calculated time which if there is an extended period of time between the two + // it would cause a large delta time period between the two states (i.e. it stops moving for a second or two and then + // starts moving again). + if ((renderTime - InterpolateState.Target.Value.TimeSent) > 0.3f) // If we haven't recevied anything within 300ms, assume we stopped motion. { - // When the delta between the time sent and the current tick latency time-window is greater than the max delta time - // plus the minimum delta time (a rough estimate of time to wait before we consider rate of change equal to zero), - // we will want to reset the interpolator with the current known value. This prevents the next received state update's - // time to be calculated against the last calculated time which if there is an extended period of time between the two - // it would cause a large delta time period between the two states (i.e. it stops moving for a second or two and then - // starts moving again). - if ((renderTime - InterpolateState.Target.Value.TimeSent) > 0.3f) // If we haven't recevied anything within 300ms, assume we stopped motion. - { - InterpolateState.Reset(InterpolateState.CurrentValue); - } + InterpolateState.Reset(InterpolateState.CurrentValue); } + } m_NbItemsReceivedThisFrame = 0; return InterpolateState.CurrentValue; } diff --git a/com.unity.netcode.gameobjects/Runtime/Components/NetworkAnimator.cs b/com.unity.netcode.gameobjects/Runtime/Components/NetworkAnimator.cs index f87eee73ab..cdb25aa598 100644 --- a/com.unity.netcode.gameobjects/Runtime/Components/NetworkAnimator.cs +++ b/com.unity.netcode.gameobjects/Runtime/Components/NetworkAnimator.cs @@ -1180,26 +1180,25 @@ internal void CheckForAnimatorChanges() { SendAnimStateRpc(m_AnimationMessage); } + else if (!IsServer && IsOwner) + { + SendServerAnimStateRpc(m_AnimationMessage); + } else - if (!IsServer && IsOwner) - { - SendServerAnimStateRpc(m_AnimationMessage); - } - else + { + // Just notify all remote clients and not the local server + m_TargetGroup.Clear(); + foreach (var clientId in LocalNetworkManager.ConnectionManager.ConnectedClientIds) { - // Just notify all remote clients and not the local server - m_TargetGroup.Clear(); - foreach (var clientId in LocalNetworkManager.ConnectionManager.ConnectedClientIds) + if (clientId == LocalNetworkManager.LocalClientId || !NetworkObject.Observers.Contains(clientId)) { - if (clientId == LocalNetworkManager.LocalClientId || !NetworkObject.Observers.Contains(clientId)) - { - continue; - } - m_TargetGroup.Add(clientId); + continue; } - m_RpcParams.Send.Target = m_TargetGroup.Target; - SendClientAnimStateRpc(m_AnimationMessage, m_RpcParams); + m_TargetGroup.Add(clientId); } + m_RpcParams.Send.Target = m_TargetGroup.Target; + SendClientAnimStateRpc(m_AnimationMessage, m_RpcParams); + } } } @@ -1346,25 +1345,24 @@ private unsafe void WriteParameters(ref FastBufferWriter writer) BytePacker.WriteValuePacked(writer, (uint)valueInt); } } - else - if (cacheValue.Type == AnimationParamEnumWrapper.AnimatorControllerParameterBool) + else if (cacheValue.Type == AnimationParamEnumWrapper.AnimatorControllerParameterBool) + { + var valueBool = m_Animator.GetBool(hash); + fixed (void* value = cacheValue.Value) { - var valueBool = m_Animator.GetBool(hash); - fixed (void* value = cacheValue.Value) - { - UnsafeUtility.WriteArrayElement(value, 0, valueBool); - BytePacker.WriteValuePacked(writer, valueBool); - } + UnsafeUtility.WriteArrayElement(value, 0, valueBool); + BytePacker.WriteValuePacked(writer, valueBool); } - else if (cacheValue.Type == AnimationParamEnumWrapper.AnimatorControllerParameterFloat) + } + else if (cacheValue.Type == AnimationParamEnumWrapper.AnimatorControllerParameterFloat) + { + var valueFloat = m_Animator.GetFloat(hash); + fixed (void* value = cacheValue.Value) { - var valueFloat = m_Animator.GetFloat(hash); - fixed (void* value = cacheValue.Value) - { - UnsafeUtility.WriteArrayElement(value, 0, valueFloat); - BytePacker.WriteValuePacked(writer, valueFloat); - } + UnsafeUtility.WriteArrayElement(value, 0, valueFloat); + BytePacker.WriteValuePacked(writer, valueFloat); } + } } } diff --git a/com.unity.netcode.gameobjects/Runtime/Components/NetworkTransform.cs b/com.unity.netcode.gameobjects/Runtime/Components/NetworkTransform.cs index 63b43544bd..152cea793b 100644 --- a/com.unity.netcode.gameobjects/Runtime/Components/NetworkTransform.cs +++ b/com.unity.netcode.gameobjects/Runtime/Components/NetworkTransform.cs @@ -2515,24 +2515,24 @@ private bool CheckForStateChange(ref NetworkTransformState networkState, bool is } } } - else // Just apply the full local scale when synchronizing - if (SynchronizeScale) + // Just apply the full local scale when synchronizing + else if (SynchronizeScale) + { + var localScale = CachedTransform.localScale; + if (!UseHalfFloatPrecision) { - var localScale = CachedTransform.localScale; - if (!UseHalfFloatPrecision) - { - networkState.ScaleX = localScale.x; - networkState.ScaleY = localScale.y; - networkState.ScaleZ = localScale.z; - } - else - { - networkState.Scale = localScale; - } - flagStates.MarkChanged(AxialType.Scale, true); - isScaleDirty = true; + networkState.ScaleX = localScale.x; + networkState.ScaleY = localScale.y; + networkState.ScaleZ = localScale.z; } + else + { + networkState.Scale = localScale; + } + flagStates.MarkChanged(AxialType.Scale, true); + isScaleDirty = true; + } isDirty |= isPositionDirty || isRotationDirty || isScaleDirty; if (isDirty) @@ -3488,12 +3488,12 @@ private void NonAuthorityFinalizeSynchronization() child.InternalInitialization(); } } - else // Otherwise, just run through standard synchronization of this instance - if (!CanCommitToTransform) - { - ApplySynchronization(); - InternalInitialization(); - } + // Otherwise, just run through standard synchronization of this instance + else if (!CanCommitToTransform) + { + ApplySynchronization(); + InternalInitialization(); + } } } diff --git a/com.unity.netcode.gameobjects/Runtime/Configuration/NetworkPrefab.cs b/com.unity.netcode.gameobjects/Runtime/Configuration/NetworkPrefab.cs index c6f30d2835..b1c071e705 100644 --- a/com.unity.netcode.gameobjects/Runtime/Configuration/NetworkPrefab.cs +++ b/com.unity.netcode.gameobjects/Runtime/Configuration/NetworkPrefab.cs @@ -166,6 +166,22 @@ public bool Validate(int index = -1) return false; } + if (networkObject.InScenePlaced) + { + if (NetworkLog.CurrentLogLevel <= LogLevel.Developer) + { + NetworkLog.LogWarning($"{NetworkPrefabHandler.PrefabDebugHelper(this)} InScenePlaced {nameof(NetworkObject)} is being registered as a Prefab. This can cause issues!"); + } + } + + if (networkObject.IsSpawned) + { + if (NetworkLog.CurrentLogLevel <= LogLevel.Developer) + { + NetworkLog.LogWarning($"{NetworkPrefabHandler.PrefabDebugHelper(this)} Currently spawned {nameof(NetworkObject)} is being registered as a Prefab. This can cause issues!"); + } + } + return true; } diff --git a/com.unity.netcode.gameobjects/Runtime/Connection/NetworkConnectionManager.cs b/com.unity.netcode.gameobjects/Runtime/Connection/NetworkConnectionManager.cs index dd22801412..3ff131131f 100644 --- a/com.unity.netcode.gameobjects/Runtime/Connection/NetworkConnectionManager.cs +++ b/com.unity.netcode.gameobjects/Runtime/Connection/NetworkConnectionManager.cs @@ -967,19 +967,18 @@ internal void ProcessClientsToDisconnect() { return (true, playerPrefabHash.Value); } - else - if (NetworkManager.NetworkConfig.PlayerPrefab != null) + else if (NetworkManager.NetworkConfig.PlayerPrefab != null) + { + var networkObject = NetworkManager.NetworkConfig.PlayerPrefab.GetComponent(); + if (networkObject != null) { - var networkObject = NetworkManager.NetworkConfig.PlayerPrefab.GetComponent(); - if (networkObject != null) - { - return (true, networkObject.GlobalObjectIdHash); - } - else - { - NetworkManager.Log.Error(new Logging.Context(LogLevel.Error, $"Player prefab {NetworkManager.NetworkConfig.PlayerPrefab.name} has no {nameof(NetworkObject)}!")); - } + return (true, networkObject.GlobalObjectIdHash); } + else + { + NetworkManager.Log.Error(new Logging.Context(LogLevel.Error, $"Player prefab {NetworkManager.NetworkConfig.PlayerPrefab.name} has no {nameof(NetworkObject)}!")); + } + } return (false, 0); } diff --git a/com.unity.netcode.gameobjects/Runtime/Core/NetworkObject.cs b/com.unity.netcode.gameobjects/Runtime/Core/NetworkObject.cs index 6a9397e48e..52e4dad4f1 100644 --- a/com.unity.netcode.gameobjects/Runtime/Core/NetworkObject.cs +++ b/com.unity.netcode.gameobjects/Runtime/Core/NetworkObject.cs @@ -5,14 +5,11 @@ using System.Runtime.CompilerServices; using System.Text; using Unity.Netcode.Components; +using Unity.Netcode.Logging; using Unity.Netcode.Runtime; #if UNITY_EDITOR using UnityEditor; -#if UNITY_2021_2_OR_NEWER using UnityEditor.SceneManagement; -#else -using UnityEditor.Experimental.SceneManagement; -#endif #endif using UnityEngine; using UnityEngine.SceneManagement; @@ -106,6 +103,9 @@ public uint PrefabIdHash /// public NetworkObject CurrentParent { get; private set; } + private int m_SpawnCount; + internal bool HasBeenSpawned => m_SpawnCount > 0; + #if UNITY_EDITOR private const string k_GlobalIdTemplate = "GlobalObjectId_V1-{0}-{1}-{2}-{3}"; @@ -129,9 +129,6 @@ public uint PrefabIdHash // The InContext or InIsolation edit mode network prefab scene instance of the prefab asset (s_PrefabAsset). private static NetworkObject s_PrefabInstance; - private static bool s_DebugPrefabIdGeneration; - - [ContextMenu("Refresh In-Scene Prefab Instances")] internal void RefreshAllPrefabInstances() { @@ -328,7 +325,7 @@ internal void OnValidate() /// private void CheckForInScenePlaced() { - if (gameObject.scene.IsValid() && gameObject.scene.isLoaded && gameObject.scene.buildIndex >= 0) + if (gameObject.scene.IsValid() && gameObject.scene.buildIndex >= 0) { if (PrefabUtility.IsPartOfAnyPrefab(this)) { @@ -348,6 +345,9 @@ private void CheckForInScenePlaced() SetSceneObjectStatus(true); #pragma warning restore CS0618 // Type or member is obsolete + // We go ahead and set this for "typical in-scene placed" usage patterns so this is serialized + InScenePlaced = true; + // Default scene migration synchronization to false for in-scene placed NetworkObjects SceneMigrationSynchronization = false; } @@ -1228,15 +1228,35 @@ public bool HasOwnershipStatus(OwnershipStatus status) /// /// Gets if the object is a SceneObject. /// + /// + /// This method is marked for deprecation.
+ /// Use instead. + ///
[Obsolete("Use InScenePlaced instead")] public bool? IsSceneObject { get; internal set; } + /// - /// True if this object is placed in a scene; false otherwise. + /// The serialized value. /// [field: HideInInspector] [field: SerializeField] - public bool InScenePlaced { get; internal set; } + private bool m_InScenePlaced; + + /// + /// True if this object is placed in a scene; false otherwise. + /// + public bool InScenePlaced + { + get + { + return m_InScenePlaced; + } + internal set + { + m_InScenePlaced = value; + } + } /// /// Sets whether this NetworkObject was instantiated as part of a scene @@ -1448,12 +1468,16 @@ internal Scene SceneOrigin set { + if (SceneOriginHandle.IsEmpty() && value.IsValid() && value.isLoaded) + { + SceneOriginHandle = value.handle; + } + // The scene origin should only be set once. // Once set, it should never change. - if (SceneOriginHandle.IsEmpty() && value.IsValid() && value.isLoaded) + if (!m_SceneOrigin.IsValid()) { m_SceneOrigin = value; - SceneOriginHandle = value.handle; } } } @@ -1782,7 +1806,7 @@ private void OnDestroy() } [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void SpawnInternal(bool destroyWithScene, ulong ownerClientId, bool playerObject) + private void SpawnInternal(bool destroyWithScene, ulong ownerClientId, bool playerObject) { if (NetworkManagerOwner == null) { @@ -1853,7 +1877,28 @@ internal void SpawnInternal(bool destroyWithScene, ulong ownerClientId, bool pla } } - if (!NetworkManagerOwner.SpawnManager.AuthorityLocalSpawn(this, NetworkManagerOwner.SpawnManager.GetNetworkObjectId(), InScenePlaced, playerObject, ownerClientId, destroyWithScene)) + + // Calculate the legacy IsSceneObject value as the public field is obsolete with warning + // We can't break the public behavior of the field. +#pragma warning disable CS0618 // Type or member is obsolete + var legacyIsSceneObject = IsSceneObject.HasValue && IsSceneObject.Value; +#pragma warning restore CS0618 // Type or member is obsolete + + // If SpawnInternal is being called on an object that is marked as InScenePlaced, + // The scene object was never automatically spawned when the scene was loaded. + // Count this object as a dynamically spawned object. + // TODO-[MTT-15388]: Actually support disabled/not spawned InScenePlaced NetworkObjects + if (InScenePlaced && !HasBeenSpawned) + { + if (NetworkManagerOwner.NetworkConfig.EnableSceneManagement && NetworkManagerOwner.LogLevel <= LogLevel.Developer) + { + Debug.LogWarning($"[{name}][SceneOrigin={SceneOriginHandle}] Dynamically spawning InScenePlaced network object. This can cause issues!", this); + } + + InScenePlaced = false; + } + + if (!NetworkManagerOwner.SpawnManager.AuthorityLocalSpawn(this, NetworkManagerOwner.SpawnManager.GetNetworkObjectId(), legacyIsSceneObject, playerObject, ownerClientId, destroyWithScene)) { if (NetworkManagerOwner.LogLevel <= LogLevel.Normal) { @@ -2053,6 +2098,7 @@ internal void SetupOnSpawn(ulong networkId, bool isPlayerObject, ulong ownerClie // When spawned, previous owner is always the first assigned owner PreviousOwnerId = ownerClientId; m_HasAuthority = NetworkManagerOwner.DistributedAuthorityMode ? OwnerClientId == NetworkManagerOwner.LocalClientId : NetworkManagerOwner.IsServer; + m_SpawnCount++; IsSpawned = true; // If this is the player, and the client is the owner, then lock ownership by default @@ -2094,6 +2140,17 @@ internal void SetupOnSpawn(ulong networkId, bool isPlayerObject, ulong ownerClie } } + /// + /// Resets this NetworkObject at the end of a session. + /// Ensures scene objects are ready to be reused + /// + internal void ResetOnShutdown() + { + NetworkLog.InternalAssert(NetworkManager.ShutdownInProgress, "This method should only be called while the NetworkManager is shutting down"); + m_SpawnCount = 0; + ResetOnDespawn(); + } + internal void ResetOnDespawn() { // Always clear out the observers list when despawned @@ -2654,26 +2711,26 @@ internal bool ApplyNetworkParenting(bool removeParent = false, bool ignoreNotSpa m_CachedWorldPositionStays = false; return true; } - else // If the parent still isn't spawned add this to the orphaned children and return false - if (!parentNetworkObject.IsSpawned) - { - OrphanChildren.Add(this); - return false; - } - else - { - // If we made it this far, go ahead and set the network parenting values - // with the WorldPoisitonSays 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. - SetNetworkParenting(parentNetworkObject.NetworkObjectId, false); + // If the parent still isn't spawned add this to the orphaned children and return false + else if (!parentNetworkObject.IsSpawned) + { + OrphanChildren.Add(this); + return false; + } + else + { + // If we made it this far, go ahead and set the network parenting values + // with the WorldPoisitonSays 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. + SetNetworkParenting(parentNetworkObject.NetworkObjectId, false); - // Set the cached parent - SetCachedParent(parentNetworkObject.transform); + // Set the cached parent + SetCachedParent(parentNetworkObject.transform); - return true; - } + return true; + } } // If we are removing the parent or our latest parent is not set, then remove the parent. @@ -3466,11 +3523,7 @@ internal static NetworkObject DeserializeAndSpawnObject(in SerializedObject seri if (serializedObject.NetworkObjectId == default) { - if (networkManager.LogLevel <= LogLevel.Error) - { - NetworkLog.LogErrorServer($"[{nameof(GlobalObjectIdHash)}={serializedObject.Hash}] Received spawn request with invalid {nameof(NetworkObjectId)} {serializedObject.NetworkObjectId}. This should not happen!"); - } - + NetworkLog.LogErrorServer(new Context(LogLevel.Error, $"Received spawn request with invalid {nameof(NetworkObjectId)}. This should not happen!").AddInfo(nameof(NetworkObjectId), serializedObject.NetworkObjectId).AddInfo(nameof(GlobalObjectIdHash), serializedObject.Hash)); reader.Seek(endOfSynchronizationData); return null; } @@ -3602,6 +3655,7 @@ internal void SceneChangedUpdate(Scene scene, bool notify = false) return; } + // Don't create notification if there is a scene event in progress. if (NetworkManagerOwner.SceneManager.IsSceneEventInProgress()) { return; @@ -3627,17 +3681,17 @@ internal void SceneChangedUpdate(Scene scene, bool notify = false) NetworkSceneHandle = SceneOriginHandle; } } - else // Otherwise, the client did not find the client to server scene handle - if (NetworkManagerOwner.LogLevel <= LogLevel.Developer) - { - // There could be a scenario where a user has some client-local scene loaded that they migrate the NetworkObject - // into, but that scenario seemed very edge case and under most instances a user should be notified that this - // server - client scene handle mismatch has occurred. It also seemed pertinent to make the message replicate to - // the server-side too. - NetworkLog.LogWarningServer($"[Client-{NetworkManagerOwner.LocalClientId}][{name}] Server - " + - $"client scene mismatch detected! Client-side scene handle ({SceneOriginHandle}) for scene ({gameObject.scene.name})" + - $"has no associated server side (network) scene handle!"); - } + // Otherwise, the client did not find the client to server scene handle + else if (NetworkManagerOwner.LogLevel <= LogLevel.Developer) + { + // There could be a scenario where a user has some client-local scene loaded that they migrate the NetworkObject + // into, but that scenario seemed very edge case and under most instances a user should be notified that this + // server - client scene handle mismatch has occurred. It also seemed pertinent to make the message replicate to + // the server-side too. + NetworkLog.LogWarningServer($"[Client-{NetworkManagerOwner.LocalClientId}][{name}] Server - " + + $"client scene mismatch detected! Client-side scene handle ({SceneOriginHandle}) for scene ({gameObject.scene.name})" + + $"has no associated server side (network) scene handle!"); + } OnMigratedToNewScene?.Invoke(); // Only the authority side will notify clients of non-parented NetworkObject scene changes diff --git a/com.unity.netcode.gameobjects/Runtime/Logging/NetworkLog.cs b/com.unity.netcode.gameobjects/Runtime/Logging/NetworkLog.cs index df08bee61f..66a7df1f96 100644 --- a/com.unity.netcode.gameobjects/Runtime/Logging/NetworkLog.cs +++ b/com.unity.netcode.gameobjects/Runtime/Logging/NetworkLog.cs @@ -103,6 +103,8 @@ internal static void ConfigureIntegrationTestLogging(NetworkManager networkManag /// The message to log [HideInCallstack] public static void LogErrorServer(string message) => s_Log.ErrorServer(new Context(LogLevel.Error, message, true)); + [HideInCallstack] + internal static void LogErrorServer(Context context) => s_Log.ErrorServer(context); internal static LogType GetMessageLogType(UnityEngine.LogType engineLogType) { @@ -115,14 +117,14 @@ internal static LogType GetMessageLogType(UnityEngine.LogType engineLogType) }; } - private const string k_SenderId = "SenderId"; internal static Context BuildContextForServerMessage([NotNull] NetworkManager networkManager, LogLevel level, ulong senderId, string message) { - var ctx = new Context(level, message, true).AddInfo(k_SenderId, senderId); - if (TryGetNetworkObjectName(networkManager, message, out var name)) + var ctx = new Context(level, message, true).AddTag("Received log from client").AddInfo(k_SenderId, senderId); + var networkObject = TryGetNetworkObject(networkManager, message); + if (networkObject != null) { - ctx.AddTag(name); + ctx.AddNetworkObject(networkObject); } return ctx; } @@ -135,29 +137,41 @@ internal enum LogType : byte None } - private static readonly Regex k_GlobalObjectIdHash = new($@"\[{nameof(NetworkObject.GlobalObjectIdHash)}=(\d+)\]", RegexOptions.Compiled); + private static readonly Regex k_NetworkObjectId = new($@"\[{nameof(NetworkObject.NetworkObjectId)}:(\d+)\]", RegexOptions.Compiled); + private static readonly Regex k_GlobalObjectIdHash = new($@"\[{nameof(NetworkObject.GlobalObjectIdHash)}:(\d+)\]", RegexOptions.Compiled); [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static bool TryGetNetworkObjectName([NotNull] NetworkManager networkManager, string message, out string name) + private static NetworkObject TryGetNetworkObject([NotNull] NetworkManager networkManager, string message) { - name = null; + if (k_NetworkObjectId.IsMatch(message)) + { + var stringId = k_NetworkObjectId.Match(message).Groups[1].Value; + if (ulong.TryParse(stringId, out var networkObjectId) && networkObjectId > 0 && networkManager.SpawnManager.SpawnedObjects.TryGetValue(networkObjectId, out var networkObject)) + { + return networkObject; + } + } + if (!k_GlobalObjectIdHash.IsMatch(message)) { - return false; + return null; } var stringHash = k_GlobalObjectIdHash.Match(message).Groups[1].Value; if (!ulong.TryParse(stringHash, out var globalObjectIdHash)) { - return false; + return null; } - if (!networkManager.SpawnManager.SpawnedObjects.TryGetValue(globalObjectIdHash, out var networkObject)) + NetworkObject matchingObject = null; + foreach (var networkObject in networkManager.SpawnManager.SpawnedObjectsList) { - return false; + if (networkObject.GlobalObjectIdHash == globalObjectIdHash) + { + matchingObject = networkObject; + } } - name = networkObject.name; - return true; + return matchingObject; } [HideInCallstack] diff --git a/com.unity.netcode.gameobjects/Runtime/SceneManagement/DefaultSceneManagerHandler.cs b/com.unity.netcode.gameobjects/Runtime/SceneManagement/DefaultSceneManagerHandler.cs index dba918a679..f7ce87d521 100644 --- a/com.unity.netcode.gameobjects/Runtime/SceneManagement/DefaultSceneManagerHandler.cs +++ b/com.unity.netcode.gameobjects/Runtime/SceneManagement/DefaultSceneManagerHandler.cs @@ -359,14 +359,14 @@ public void SetClientSynchronizationMode(ref NetworkManager networkManager, Load } return; } - else // Warn users if they are changing this after there are clients already connected and synchronized - if (!networkManager.DistributedAuthorityMode && networkManager.ConnectedClientsIds.Count > (networkManager.IsHost ? 1 : 0) && sceneManager.ClientSynchronizationMode != mode) + // Warn users if they are changing this after there are clients already connected and synchronized + else if (!networkManager.DistributedAuthorityMode && networkManager.ConnectedClientsIds.Count > (networkManager.IsHost ? 1 : 0) && sceneManager.ClientSynchronizationMode != mode) + { + if (NetworkLog.CurrentLogLevel <= LogLevel.Normal) { - if (NetworkLog.CurrentLogLevel <= LogLevel.Normal) - { - NetworkLog.LogWarning("Server is changing client synchronization mode after clients have been synchronized! It is recommended to do this before clients are connected!"); - } + NetworkLog.LogWarning("Server is changing client synchronization mode after clients have been synchronized! It is recommended to do this before clients are connected!"); } + } // For additive client synchronization, we take into consideration scenes // already loaded. diff --git a/com.unity.netcode.gameobjects/Runtime/SceneManagement/NetworkSceneManager.cs b/com.unity.netcode.gameobjects/Runtime/SceneManagement/NetworkSceneManager.cs index c0d4b44aee..e3a5d2cfe4 100644 --- a/com.unity.netcode.gameobjects/Runtime/SceneManagement/NetworkSceneManager.cs +++ b/com.unity.netcode.gameobjects/Runtime/SceneManagement/NetworkSceneManager.cs @@ -1034,7 +1034,7 @@ internal void SetTheSceneBeingSynchronized(NetworkSceneHandle serverSceneHandle) // Most common scenario for DontDestroyOnLoad is when NetworkManager is set to not be destroyed if (serverSceneHandle == DontDestroyOnLoadScene.handle) { - SceneBeingSynchronized = NetworkManager.gameObject.scene; + SceneBeingSynchronized = DontDestroyOnLoadScene; return; } else @@ -2260,8 +2260,6 @@ private void SynchronizeNetworkObjectScene() { networkObject.SceneOriginHandle = ServerSceneHandleToClientSceneHandle[networkObject.NetworkSceneHandle]; - - // If the NetworkObject does not have a parent and is not in the same scene as it is on the server side, then find the right scene // and move it to that scene. if (networkObject.gameObject.scene.handle != networkObject.SceneOriginHandle && networkObject.transform.parent == null) @@ -2269,11 +2267,6 @@ private void SynchronizeNetworkObjectScene() if (ScenesLoaded.ContainsKey(networkObject.SceneOriginHandle)) { var scene = ScenesLoaded[networkObject.SceneOriginHandle]; - if (scene == DontDestroyOnLoadScene) - { - Debug.Log($"{networkObject.gameObject.name} migrating into DDOL!"); - } - SceneManager.MoveGameObjectToScene(networkObject.gameObject, scene); } else if (NetworkManager.LogLevel <= LogLevel.Normal) @@ -2897,6 +2890,12 @@ internal bool IsSceneUnloading(NetworkObject networkObject) /// internal void NotifyNetworkObjectSceneChanged(NetworkObject networkObject) { + if (networkObject.NetworkManagerOwner != NetworkManager) + { + Debug.Log($"!!!!!!!!!!!!! Integration test is registering for scene migration for instances outside of the bounds of this NetworkManager context !!!!!!!!!!!!!"); + return; + } + // Really, this should never happen but in case it does if (!networkObject.HasAuthority) { @@ -2920,7 +2919,7 @@ internal void NotifyNetworkObjectSceneChanged(NetworkObject networkObject) // Ignore if the scene is the currently active scene and the NetworkObject is auto synchronizing/migrating // to the currently active scene. - if (networkObject.gameObject.scene == SceneManager.GetActiveScene() && networkObject.ActiveSceneSynchronization) + if (networkObject.gameObject.scene.name == SceneManager.GetActiveScene().name && networkObject.ActiveSceneSynchronization) { return; } @@ -2929,6 +2928,13 @@ internal void NotifyNetworkObjectSceneChanged(NetworkObject networkObject) // Note: This does not apply to SceneEventType.Synchronize since synchronization isn't a global connected client event. if (IsSceneEventInProgress()) { + Debug.Log($"{networkObject.name} scene event in progress -- ignoring!"); + return; + } + + if (IsSceneUnloading(networkObject)) + { + Debug.Log($"{networkObject.name} scene unloading in progress -- ignoring!"); return; } @@ -3053,7 +3059,15 @@ internal void CheckForAndSendNetworkObjectSceneChanged() // Some NetworkObjects still exist, send the message var sceneEvent = BeginSceneEvent(); sceneEvent.SceneEventType = SceneEventType.ObjectSceneChanged; - SendSceneEventData(sceneEvent.SceneEventId, NetworkManager.ConnectedClientsIds.Where(c => c != NetworkManager.LocalClientId).ToArray()); + // SendSceneEventData can throw an exception. We need to wrap this and recover from the exception gracefully. + try + { + SendSceneEventData(sceneEvent.SceneEventId, NetworkManager.ConnectedClientsIds.Where(c => c != NetworkManager.LocalClientId).ToArray()); + } + catch (Exception ex) + { + Debug.LogException(ex); + } ObjectsMigratedIntoNewScene.Clear(); EndSceneEvent(sceneEvent.SceneEventId); } diff --git a/com.unity.netcode.gameobjects/Runtime/SceneManagement/SceneEventData.cs b/com.unity.netcode.gameobjects/Runtime/SceneManagement/SceneEventData.cs index 2575bd6bfd..6195fa2335 100644 --- a/com.unity.netcode.gameobjects/Runtime/SceneManagement/SceneEventData.cs +++ b/com.unity.netcode.gameobjects/Runtime/SceneManagement/SceneEventData.cs @@ -1204,31 +1204,51 @@ private void ReadSceneEventProgressDone(FastBufferReader reader) private void SerializeObjectsMovedIntoNewScene(FastBufferWriter writer) { var sceneManager = m_NetworkManager.SceneManager; - var ownerId = m_NetworkManager.LocalClientId; + var networkManagerClientId = m_NetworkManager.LocalClientId; if (IsForwarding) { - ownerId = m_OwnerId; + networkManagerClientId = m_OwnerId; } // Write the owner identifier - writer.WriteValueSafe(ownerId); + writer.WriteValueSafe(networkManagerClientId); - // Write the number of scene handles - writer.WriteValueSafe(sceneManager.ObjectsMigratedIntoNewScene.Count); + // Create a place holder for the number of entries written. + // Distributed authority this could end up being just a single entry for + // one of several scenes loaded. As such, we need to count how many entries + // are actually written. + var countPosition = writer.Position; + writer.WriteValueSafe(0); + var entriesWritten = 0; foreach (var sceneHandleObjects in sceneManager.ObjectsMigratedIntoNewScene) { - if (!sceneHandleObjects.Value.ContainsKey(ownerId)) + // Since these are separated by scene then owner, there could be scenes that have + // no changes. + if (!sceneHandleObjects.Value.ContainsKey(networkManagerClientId)) { - throw new Exception($"Trying to send object scene migration for Client-{ownerId} but the client has no entries to send!"); + continue; } // Write the scene handle writer.WriteValueSafe(sceneHandleObjects.Key); // Write the number of NetworkObjectIds to expect - writer.WriteValueSafe(sceneHandleObjects.Value[ownerId].Count); - foreach (var networkObject in sceneHandleObjects.Value[ownerId]) + writer.WriteValueSafe(sceneHandleObjects.Value[networkManagerClientId].Count); + foreach (var networkObject in sceneHandleObjects.Value[networkManagerClientId]) { writer.WriteValueSafe(networkObject.NetworkObjectId); } + entriesWritten++; + } + if (entriesWritten == 0) + { + throw new Exception($"Trying to send object scene migration for Client-{networkManagerClientId} but the client has no entries to send!"); + } + else + { + // Write the number of entries written + var endPosition = writer.Position; + writer.Seek(countPosition); + writer.WriteValueSafe(entriesWritten); + writer.Seek(endPosition); } } diff --git a/com.unity.netcode.gameobjects/Runtime/Spawning/NetworkPrefabHandler.cs b/com.unity.netcode.gameobjects/Runtime/Spawning/NetworkPrefabHandler.cs index ece7561161..19444a4ddb 100644 --- a/com.unity.netcode.gameobjects/Runtime/Spawning/NetworkPrefabHandler.cs +++ b/com.unity.netcode.gameobjects/Runtime/Spawning/NetworkPrefabHandler.cs @@ -341,11 +341,11 @@ internal void HandleNetworkPrefabDestroy(NetworkObject networkObjectInstance) prefabInstanceHandler.Destroy(networkObjectInstance); } } - else // Otherwise the NetworkObject is the source NetworkPrefab - if (m_PrefabAssetToPrefabHandler.TryGetValue(networkObjectInstanceHash, out var prefabInstanceHandler)) - { - prefabInstanceHandler.Destroy(networkObjectInstance); - } + // Otherwise the NetworkObject is the source NetworkPrefab + else if (m_PrefabAssetToPrefabHandler.TryGetValue(networkObjectInstanceHash, out var prefabInstanceHandler)) + { + prefabInstanceHandler.Destroy(networkObjectInstance); + } } /// diff --git a/com.unity.netcode.gameobjects/Runtime/Spawning/NetworkSpawnManager.cs b/com.unity.netcode.gameobjects/Runtime/Spawning/NetworkSpawnManager.cs index 2f8ae30d03..74d0ee121e 100644 --- a/com.unity.netcode.gameobjects/Runtime/Spawning/NetworkSpawnManager.cs +++ b/com.unity.netcode.gameobjects/Runtime/Spawning/NetworkSpawnManager.cs @@ -907,10 +907,7 @@ internal NetworkObject GetNetworkObjectToSpawn(uint globalObjectIdHash, ulong ow // If not, then there is an issue (user possibly didn't register the prefab properly?) if (networkPrefabReference == null) { - if (NetworkLog.CurrentLogLevel <= LogLevel.Error) - { - NetworkLog.LogErrorServer($"[{nameof(globalObjectIdHash)}={globalObjectIdHash}] Failed to create object locally. {nameof(NetworkPrefab)} could not be found. Is the prefab registered with {NetworkManager.name}?"); - } + NetworkManager.Log.ErrorServer(new Context(LogLevel.Error, $"Failed to create object locally. {nameof(NetworkPrefab)} could not be found. Is the prefab registered with this {nameof(NetworkManager)}").AddInfo(nameof(NetworkObject.GlobalObjectIdHash), globalObjectIdHash).AddTag(NetworkManager.name)); return null; } @@ -957,6 +954,7 @@ internal NetworkObject InstantiateNetworkPrefab([NotNull] GameObject networkPref /// /// For most cases this is client-side only, except when the server is spawning a player. /// + [return: MaybeNull] internal NetworkObject CreateLocalNetworkObject(NetworkObject.SerializedObject serializedObject, byte[] instantiationData = null) { NetworkObject networkObject = null; @@ -977,11 +975,7 @@ internal NetworkObject CreateLocalNetworkObject(NetworkObject.SerializedObject s networkObject = NetworkManager.SceneManager.GetSceneRelativeInSceneNetworkObject(globalObjectIdHash, serializedObject.NetworkSceneHandle); if (networkObject == null) { - if (NetworkLog.CurrentLogLevel <= LogLevel.Error) - { - NetworkLog.LogError($"{nameof(NetworkPrefab)} hash was not found! In-Scene placed {nameof(NetworkObject)} soft synchronization failure for Hash: {globalObjectIdHash}!"); - } - + NetworkLog.LogErrorServer(new Context(LogLevel.Error, $"{nameof(NetworkPrefab)} hash was not found! In-Scene placed {nameof(NetworkObject)} soft synchronization failure!").AddInfo(nameof(NetworkObject.GlobalObjectIdHash), globalObjectIdHash)); return null; } @@ -1122,7 +1116,14 @@ internal bool AuthorityLocalSpawn([NotNull] NetworkObject networkObject, ulong n return false; } - if (!sceneObject && NetworkManager.LogLevel <= LogLevel.Error) + if (playerObject && networkObject.InScenePlaced) + { + NetworkLog.LogError(new Context(LogLevel.Developer, "Player prefab is marked as belonging to a scene. This may cause issues.").AddNetworkObject(networkObject).AddInfo("SceneName", networkObject.SceneOrigin.name)); + networkObject.InScenePlaced = false; + } + NetworkLog.InternalAssert(sceneObject == networkObject.InScenePlaced, "Legacy sceneObject value should match calculated InScenePlaced value."); + + if (!networkObject.InScenePlaced && NetworkManager.LogLevel <= LogLevel.Error) { var networkObjectChildren = networkObject.GetComponentsInChildren(); if (networkObjectChildren.Length > 1) @@ -1137,7 +1138,7 @@ internal bool AuthorityLocalSpawn([NotNull] NetworkObject networkObject, ulong n networkObject.NetworkManagerOwner = NetworkManager; networkObject.InvokeBehaviourNetworkPreSpawn(); - if (NetworkManager.DistributedAuthorityMode && NetworkManager.NetworkConfig.EnableSceneManagement && sceneObject) + if (NetworkManager.DistributedAuthorityMode && NetworkManager.NetworkConfig.EnableSceneManagement && networkObject.InScenePlaced) { networkObject.SceneOriginHandle = networkObject.gameObject.scene.handle; networkObject.NetworkSceneHandle = NetworkManager.SceneManager.ClientSceneHandleToServerSceneHandle[networkObject.gameObject.scene.handle]; @@ -1175,10 +1176,7 @@ internal bool NonAuthorityLocalSpawn(in NetworkObject.SerializedObject serialize { if (SpawnedObjects.ContainsKey(serializedObject.NetworkObjectId)) { - if (NetworkManager.LogLevel <= LogLevel.Error) - { - NetworkLog.LogWarning($"Trying to spawn a {nameof(NetworkObject)} with a {nameof(NetworkObject.NetworkObjectId)} of {serializedObject.NetworkObjectId} but an object with that id is already in the spawned list. This should not happen!"); - } + NetworkManager.Log.Warning(new Context(LogLevel.Error, $"Trying to spawn a {nameof(NetworkObject)} but an object with that {nameof(NetworkObject.NetworkObjectId)} is already in the spawned list. This should not happen!")); networkObject = null; return false; } @@ -1195,14 +1193,11 @@ internal bool NonAuthorityLocalSpawn(in NetworkObject.SerializedObject serialize // Log the error that the NetworkObject failed to construct if (networkObject == null) { - if (NetworkManager.LogLevel <= LogLevel.Normal) - { - NetworkLog.LogError($"[{nameof(NetworkObject.GlobalObjectIdHash)}={serializedObject.Hash}] Failed to spawn {nameof(NetworkObject)}!"); - } - + NetworkManager.Log.ErrorServer(new Context(LogLevel.Normal, $"Failed to spawn {nameof(NetworkObject)}!").AddInfo(nameof(NetworkObject.GlobalObjectIdHash), serializedObject.Hash)); return false; } + networkObject.InScenePlaced = serializedObject.IsSceneObject; networkObject.NetworkManagerOwner = NetworkManager; // This will get set again when the NetworkObject is spawned locally, but we set it here ahead of spawning @@ -1227,11 +1222,7 @@ internal bool NonAuthorityLocalSpawn(in NetworkObject.SerializedObject serialize if (networkObject.IsSpawned) { - if (NetworkManager.LogLevel <= LogLevel.Error) - { - NetworkLog.LogErrorServer($"[{networkObject.name}] Object-{networkObject.NetworkObjectId} is already spawned!"); - } - + NetworkManager.Log.ErrorServer(new Context(LogLevel.Normal, $"{nameof(NetworkObject)} is already spawned!").AddNetworkObject(networkObject)); // Mark the spawn as a success if the object is already spawned return true; } @@ -1455,13 +1446,13 @@ internal void DespawnObject(NetworkObject networkObject, bool destroyObject = fa internal void ServerResetShutdownStateForSceneObjects() { var networkObjects = FindObjects.ByType(orderByIdentifier: true, includeInactive: true); - foreach (var sobj in networkObjects) + foreach (var obj in networkObjects) { - if (!sobj.InScenePlaced) + // Only reset things that have been spawned are in-scene placed, and is assigned to the relative NetworkManager (for integration testing purposes) + if (obj.HasBeenSpawned && obj.InScenePlaced && obj.NetworkManagerOwner == NetworkManager) { - continue; + obj.ResetOnShutdown(); } - sobj.ResetOnDespawn(); } } @@ -1725,11 +1716,10 @@ internal void OnDespawnObject([NotNull] NetworkObject networkObject, bool destro NetworkLog.LogError($"{nameof(NetworkObject)} #{spawnedNetObj.NetworkObjectId} could not be moved to the root when its parent {nameof(NetworkObject)} #{networkObject.NetworkObjectId} was being destroyed"); } } - else - if (NetworkLog.CurrentLogLevel <= LogLevel.Developer) - { - NetworkLog.LogWarning($"{nameof(NetworkObject)} #{spawnedNetObj.NetworkObjectId} moved to the root because its parent {nameof(NetworkObject)} #{networkObject.NetworkObjectId} is destroyed"); - } + else if (NetworkLog.CurrentLogLevel <= LogLevel.Developer) + { + NetworkLog.LogWarning($"{nameof(NetworkObject)} #{spawnedNetObj.NetworkObjectId} moved to the root because its parent {nameof(NetworkObject)} #{networkObject.NetworkObjectId} is destroyed"); + } } } diff --git a/com.unity.netcode.gameobjects/Tests/Runtime/DistributedAuthority/NetworkClientAndPlayerObjectTests.cs b/com.unity.netcode.gameobjects/Tests/Runtime/DistributedAuthority/NetworkClientAndPlayerObjectTests.cs index 461d85a757..929592a9b0 100644 --- a/com.unity.netcode.gameobjects/Tests/Runtime/DistributedAuthority/NetworkClientAndPlayerObjectTests.cs +++ b/com.unity.netcode.gameobjects/Tests/Runtime/DistributedAuthority/NetworkClientAndPlayerObjectTests.cs @@ -246,12 +246,11 @@ private bool ValidateAllPlayerObjects() m_ErrorLogLevel1.AppendLine($"[Client-{client.LocalClientId}] Local {nameof(NetworkClient.PlayerObject)} is null!"); success = false; } - else - if (!client.SpawnManager.PlayerObjects.Contains(client.LocalClient.PlayerObject)) - { - m_ErrorLogLevel1.AppendLine($"[Client-{client.LocalClientId}] Local {nameof(NetworkSpawnManager.PlayerObjects)} does not contain {client.LocalClient.PlayerObject.name}!"); - success = false; - } + else if (!client.SpawnManager.PlayerObjects.Contains(client.LocalClient.PlayerObject)) + { + m_ErrorLogLevel1.AppendLine($"[Client-{client.LocalClientId}] Local {nameof(NetworkSpawnManager.PlayerObjects)} does not contain {client.LocalClient.PlayerObject.name}!"); + success = false; + } } return success; diff --git a/com.unity.netcode.gameobjects/Tests/Runtime/NetworkObject/NetworkObjectDestroyTests.cs b/com.unity.netcode.gameobjects/Tests/Runtime/NetworkObject/NetworkObjectDestroyTests.cs index 0e226ec115..f27f28d53f 100644 --- a/com.unity.netcode.gameobjects/Tests/Runtime/NetworkObject/NetworkObjectDestroyTests.cs +++ b/com.unity.netcode.gameobjects/Tests/Runtime/NetworkObject/NetworkObjectDestroyTests.cs @@ -1,5 +1,6 @@ using System.Collections; using System.Collections.Generic; +using System.Text.RegularExpressions; using NUnit.Framework; using Unity.Netcode.TestHelpers.Runtime; using UnityEngine; @@ -193,7 +194,7 @@ private bool HaveLogsBeenReceived() return false; } - if (!NetcodeLogAssert.HasLogBeenReceived(LogType.Error, $"[Netcode] [SenderId:{m_ClientNetworkManagers[0].LocalClientId}] [Invalid Destroy][{m_ClientPlayerName}][NetworkObjectId:{m_ClientNetworkObjectId}] Destroy a spawned {nameof(NetworkObject)} on a non-host client is not valid. Call Destroy or Despawn on the server/host instead.")) + if (!NetcodeLogAssert.HasLogBeenReceived(LogType.Error, new Regex($"SenderId:{m_ClientNetworkManagers[0].LocalClientId}]"))) { return false; } diff --git a/com.unity.netcode.gameobjects/Tests/Runtime/NetworkShowHideTests.cs b/com.unity.netcode.gameobjects/Tests/Runtime/NetworkShowHideTests.cs index 43f6eac7de..1ef0a13eb4 100644 --- a/com.unity.netcode.gameobjects/Tests/Runtime/NetworkShowHideTests.cs +++ b/com.unity.netcode.gameobjects/Tests/Runtime/NetworkShowHideTests.cs @@ -488,11 +488,10 @@ private bool Object1IsNotVisibileToClient() m_ErrorLog.AppendLine($"{m_NetSpawnedObject1.name} is still visible to Client-{m_ClientWithoutVisibility}!"); } } - else - if (client.SpawnManager.SpawnedObjects[m_NetSpawnedObject1.NetworkObjectId].IsNetworkVisibleTo(m_ClientWithoutVisibility)) - { - m_ErrorLog.AppendLine($"Local instance of {m_NetSpawnedObject1.name} on Client-{client.LocalClientId} thinks Client-{m_ClientWithoutVisibility} still has visibility!"); - } + else if (client.SpawnManager.SpawnedObjects[m_NetSpawnedObject1.NetworkObjectId].IsNetworkVisibleTo(m_ClientWithoutVisibility)) + { + m_ErrorLog.AppendLine($"Local instance of {m_NetSpawnedObject1.name} on Client-{client.LocalClientId} thinks Client-{m_ClientWithoutVisibility} still has visibility!"); + } } return m_ErrorLog.Length == 0; } diff --git a/com.unity.netcode.gameobjects/Tests/Runtime/NetworkTransform/NetworkTransformNonAuthorityTests.cs b/com.unity.netcode.gameobjects/Tests/Runtime/NetworkTransform/NetworkTransformNonAuthorityTests.cs index 5705d21942..350f312973 100644 --- a/com.unity.netcode.gameobjects/Tests/Runtime/NetworkTransform/NetworkTransformNonAuthorityTests.cs +++ b/com.unity.netcode.gameobjects/Tests/Runtime/NetworkTransform/NetworkTransformNonAuthorityTests.cs @@ -418,13 +418,12 @@ private bool ShouldSyncAxis(bool first, bool second, bool lastValue) // make the last one disabled. return false; } - else - if (!first && !second) - { - // If both are disabled, then make the - // last one enabled. - return true; - } + else if (!first && !second) + { + // If both are disabled, then make the + // last one enabled. + return true; + } } return Random.Range(start, 100) >= 50 ? false : true; } diff --git a/com.unity.netcode.gameobjects/Tests/Runtime/Prefabs/NetworkPrefabHandlerSynchronizationTests.cs b/com.unity.netcode.gameobjects/Tests/Runtime/Prefabs/NetworkPrefabHandlerSynchronizationTests.cs index d135f29b91..3124dec5f7 100644 --- a/com.unity.netcode.gameobjects/Tests/Runtime/Prefabs/NetworkPrefabHandlerSynchronizationTests.cs +++ b/com.unity.netcode.gameobjects/Tests/Runtime/Prefabs/NetworkPrefabHandlerSynchronizationTests.cs @@ -1,4 +1,5 @@ using System.Collections; +using System.Text.RegularExpressions; using NUnit.Framework; using Unity.Netcode.TestHelpers.Runtime; using UnityEngine; @@ -42,7 +43,10 @@ public IEnumerator NetworkPrefabHandlerSpawnAndSynchronizeTests() // Check the invalid object spawns on the authority, expect an error from non-authority. LogAssert.Expect(LogType.Exception, "Exception: exception while instantiating"); - LogAssert.Expect(LogType.Error, $"[Netcode] [GlobalObjectIdHash={exceptionObject.GlobalObjectIdHash}] Failed to spawn NetworkObject!"); + LogAssert.Expect(LogType.Error, new Regex("Failed to spawn NetworkObject!")); + // Authority should receive an error from non-authority and should use the globalObjectIdHash to find the failing object + LogAssert.Expect(LogType.Error, new Regex($@"SenderId:{nonAuthority.LocalClientId}\]\[{Regex.Escape(exceptionObject.name)}")); + yield return WaitForConditionOrTimeOut(() => exceptionObject.IsSpawned); AssertOnTimeout("Failed to spawn object on authority!"); @@ -58,9 +62,13 @@ public IEnumerator NetworkPrefabHandlerSpawnAndSynchronizeTests() newClient.PrefabHandler.AddHandler(m_ClientSideExceptionPrefab, new NetworkPrefabExceptionThrower()); newClient.PrefabHandler.AddHandler(m_ValidPrefab, new NetworkPrefabInstanceHandler(networkObjectToSpawnOnClient)); - // Expect assertions fromt the new client + // Expect assertions from the new client LogAssert.Expect(LogType.Exception, "Exception: exception while instantiating"); - LogAssert.Expect(LogType.Error, $"[Netcode] [GlobalObjectIdHash={exceptionObject.GlobalObjectIdHash}] Failed to spawn NetworkObject!"); + LogAssert.Expect(LogType.Error, new Regex("Failed to spawn NetworkObject!")); + + // Authority will receive an error from new client and should use the globalObjectIdHash to find the failing object + var expectedNewClientId = nonAuthority.LocalClientId + 1; + LogAssert.Expect(LogType.Error, new Regex($@"SenderId:{expectedNewClientId}\]\[{Regex.Escape(exceptionObject.name)}")); // Start and synchronize the new client yield return StartClient(newClient); diff --git a/com.unity.netcode.gameobjects/Tests/Runtime/TestHelpers/NetcodeLogAssert.cs b/com.unity.netcode.gameobjects/Tests/Runtime/TestHelpers/NetcodeLogAssert.cs index 72f9753ee1..e2c95d7450 100644 --- a/com.unity.netcode.gameobjects/Tests/Runtime/TestHelpers/NetcodeLogAssert.cs +++ b/com.unity.netcode.gameobjects/Tests/Runtime/TestHelpers/NetcodeLogAssert.cs @@ -222,6 +222,30 @@ public bool HasLogBeenReceived(LogType type, string message) return found; } + /// + /// Determines if a log message was logged or not. + /// + /// to check for. + /// containing the message to search for. + /// or + public bool HasLogBeenReceived(LogType type, Regex message) + { + var found = false; + lock (m_Lock) + { + foreach (var logEvent in AllLogs) + { + if (logEvent.LogType == type && message.IsMatch(logEvent.Message)) + { + found = true; + break; + } + } + } + return found; + } + + /// /// Clears out the log history that is searched. /// diff --git a/testproject/Assets/AddressableAssetsData/AddressableAssetSettings.asset b/testproject/Assets/AddressableAssetsData/AddressableAssetSettings.asset index 6a1c39a006..69bec9b722 100644 --- a/testproject/Assets/AddressableAssetsData/AddressableAssetSettings.asset +++ b/testproject/Assets/AddressableAssetsData/AddressableAssetSettings.asset @@ -15,7 +15,8 @@ MonoBehaviour: m_DefaultGroup: 93aa504d1b753cb41a8a779ae63f5795 m_currentHash: serializedVersion: 2 - Hash: c105cac3e36a87a6dabc4f3755bc1fd9 + Hash: 00000000000000000000000000000000 + m_ExtractTypeTreeData: 0 m_OptimizeCatalogSize: 0 m_BuildRemoteCatalog: 0 m_CatalogRequestsTimeout: 0 @@ -33,6 +34,7 @@ MonoBehaviour: m_UniqueBundleIds: 0 m_EnableJsonCatalog: 0 m_NonRecursiveBuilding: 1 + m_AllowNestedBundleFolders: 0 m_CCDEnabled: 0 m_maxConcurrentWebRequests: 500 m_UseUWRForLocalBundles: 0 @@ -41,6 +43,7 @@ MonoBehaviour: m_BundleRedirectLimit: -1 m_SharedBundleSettings: 0 m_SharedBundleSettingsCustomGroupIndex: 0 + m_simulatedLoadDelay: 0.1 m_ContiguousBundles: 0 m_StripUnityVersionFromBundleBuild: 0 m_DisableVisibleSubAssetRepresentations: 0 @@ -70,32 +73,32 @@ MonoBehaviour: m_Id: b7ba5fc73af2a49449023b732cdf652d m_ProfileName: Default m_Values: - - m_Id: a2553e7788fb43741926b3128a0aa641 - m_Value: '[UnityEditor.EditorUserBuildSettings.activeBuildTarget]' - - m_Id: 8bc200e556c0a2f4daf1a4696958eaa6 - m_Value: '[UnityEngine.AddressableAssets.Addressables.BuildPath]/[BuildTarget]' + - m_Id: 2a3d80e942fdbfe49a979d4a22bbe893 + m_Value: 'http://localhost/[BuildTarget]' - m_Id: 80085c797452bb94ca0bf0a4b2ec258c m_Value: '{UnityEngine.AddressableAssets.Addressables.RuntimePath}/[BuildTarget]' + - m_Id: 8bc200e556c0a2f4daf1a4696958eaa6 + m_Value: '[UnityEngine.AddressableAssets.Addressables.BuildPath]/[BuildTarget]' + - m_Id: a2553e7788fb43741926b3128a0aa641 + m_Value: '[UnityEditor.EditorUserBuildSettings.activeBuildTarget]' - m_Id: eaae5cc67c56cfe4299363a742a284b3 m_Value: 'ServerData/[BuildTarget]' - - m_Id: 2a3d80e942fdbfe49a979d4a22bbe893 - m_Value: 'http://localhost/[BuildTarget]' m_ProfileEntryNames: - - m_Id: a2553e7788fb43741926b3128a0aa641 - m_Name: BuildTarget + - m_Id: 2a3d80e942fdbfe49a979d4a22bbe893 + m_Name: Remote.LoadPath + m_InlineUsage: 0 + - m_Id: 80085c797452bb94ca0bf0a4b2ec258c + m_Name: Local.LoadPath m_InlineUsage: 0 - m_Id: 8bc200e556c0a2f4daf1a4696958eaa6 m_Name: Local.BuildPath m_InlineUsage: 0 - - m_Id: 80085c797452bb94ca0bf0a4b2ec258c - m_Name: Local.LoadPath + - m_Id: a2553e7788fb43741926b3128a0aa641 + m_Name: BuildTarget m_InlineUsage: 0 - m_Id: eaae5cc67c56cfe4299363a742a284b3 m_Name: Remote.BuildPath m_InlineUsage: 0 - - m_Id: 2a3d80e942fdbfe49a979d4a22bbe893 - m_Name: Remote.LoadPath - m_InlineUsage: 0 m_ProfileVersion: 1 m_LabelTable: m_LabelNames: diff --git a/testproject/Assets/AddressableAssetsData/AssetGroups/Default Local Group.asset b/testproject/Assets/AddressableAssetsData/AssetGroups/Default Local Group.asset index 5d957b4c4e..36d70b4b1c 100644 --- a/testproject/Assets/AddressableAssetsData/AssetGroups/Default Local Group.asset +++ b/testproject/Assets/AddressableAssetsData/AssetGroups/Default Local Group.asset @@ -13,19 +13,16 @@ MonoBehaviour: m_Name: Default Local Group m_EditorClassIdentifier: m_GroupName: Default Local Group - m_Data: - m_SerializedData: [] m_GUID: 93aa504d1b753cb41a8a779ae63f5795 m_SerializeEntries: - m_GUID: ffa1ab8ed58b72343ad93116ded1700a m_Address: AddressableTestObject.prefab m_ReadOnly: 0 m_SerializedLabels: [] - m_MainAsset: {fileID: 0} - m_TargetAsset: {fileID: 0} + FlaggedDuringContentUpdateRestriction: 0 m_ReadOnly: 0 m_Settings: {fileID: 11400000, guid: 75e5cd8b6bfca5d49a5818e70d71b64d, type: 2} m_SchemaSet: m_Schemas: - - {fileID: 11400000, guid: 6b8a226e7c996ad4b841b997672f866c, type: 2} - {fileID: 11400000, guid: 07e6ff907f5779a42b6e632340d10c58, type: 2} + - {fileID: 11400000, guid: 6b8a226e7c996ad4b841b997672f866c, type: 2} diff --git a/testproject/Assets/Prefabs/AddressableTestObject.prefab b/testproject/Assets/Prefabs/AddressableTestObject.prefab index 473b199037..2930d6b0f3 100644 --- a/testproject/Assets/Prefabs/AddressableTestObject.prefab +++ b/testproject/Assets/Prefabs/AddressableTestObject.prefab @@ -9,8 +9,8 @@ GameObject: serializedVersion: 6 m_Component: - component: {fileID: 6175900562428407388} - - component: {fileID: 6175900562428407389} - component: {fileID: 6175900562428407386} + - component: {fileID: 6175900562428407389} m_Layer: 0 m_Name: AddressableTestObject m_TagString: Untagged @@ -25,14 +25,15 @@ Transform: m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 6175900562428407387} + serializedVersion: 2 m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} m_LocalPosition: {x: 0, y: 0, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 0} - m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !u!114 &6175900562428407389 +--- !u!114 &6175900562428407386 MonoBehaviour: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} @@ -41,12 +42,24 @@ MonoBehaviour: m_GameObject: {fileID: 6175900562428407387} m_Enabled: 1 m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 6c8e5a8a448245769b69af7de9c47b21, type: 3} + m_Script: {fileID: 11500000, guid: d5a57f767e5e46a458fc5d3c628d0cbb, type: 3} m_Name: m_EditorClassIdentifier: - AnIntVal: 1234567 - AStringVal: 1234567 ---- !u!114 &6175900562428407386 + GlobalObjectIdHash: 4054942115 + InScenePlacedSourceGlobalObjectIdHash: 0 + DeferredDespawnTick: 0 + Ownership: 1 + AlwaysReplicateAsRoot: 0 + SynchronizeTransform: 1 + k__BackingField: 0 + ActiveSceneSynchronization: 0 + SceneMigrationSynchronization: 1 + SpawnWithObservers: 1 + DontDestroyWithOwner: 0 + AutoObjectParentSync: 1 + SyncOwnerTransformWhenParented: 1 + AllowOwnerToParent: 0 +--- !u!114 &6175900562428407389 MonoBehaviour: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} @@ -55,10 +68,9 @@ MonoBehaviour: m_GameObject: {fileID: 6175900562428407387} m_Enabled: 1 m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: d5a57f767e5e46a458fc5d3c628d0cbb, type: 3} + m_Script: {fileID: 11500000, guid: 6c8e5a8a448245769b69af7de9c47b21, type: 3} m_Name: m_EditorClassIdentifier: - GlobalObjectIdHash: 951099334 - AlwaysReplicateAsRoot: 0 - DontDestroyWithOwner: 0 - AutoObjectParentSync: 1 + ShowTopMostFoldoutHeaderGroup: 1 + AnIntVal: 1234567 + AStringVal: 1234567 diff --git a/testproject/Assets/Scenes/AddressableInSceneObject.unity b/testproject/Assets/Scenes/AddressableInSceneObject.unity new file mode 100644 index 0000000000..e9fea46774 --- /dev/null +++ b/testproject/Assets/Scenes/AddressableInSceneObject.unity @@ -0,0 +1,199 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!29 &1 +OcclusionCullingSettings: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_OcclusionBakeSettings: + smallestOccluder: 5 + smallestHole: 0.25 + backfaceThreshold: 100 + m_SceneGUID: 00000000000000000000000000000000 + m_OcclusionCullingData: {fileID: 0} +--- !u!104 &2 +RenderSettings: + m_ObjectHideFlags: 0 + serializedVersion: 10 + m_Fog: 0 + m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} + m_FogMode: 3 + m_FogDensity: 0.01 + m_LinearFogStart: 0 + m_LinearFogEnd: 300 + m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1} + m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1} + m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1} + m_AmbientIntensity: 1 + m_AmbientMode: 0 + m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1} + m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0} + m_HaloStrength: 0.5 + m_FlareStrength: 1 + m_FlareFadeSpeed: 3 + m_HaloTexture: {fileID: 0} + m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0} + m_DefaultReflectionMode: 0 + m_DefaultReflectionResolution: 128 + m_ReflectionBounces: 1 + m_ReflectionIntensity: 1 + m_CustomReflection: {fileID: 0} + m_Sun: {fileID: 0} + m_UseRadianceAmbientProbe: 0 +--- !u!157 &3 +LightmapSettings: + m_ObjectHideFlags: 0 + serializedVersion: 13 + m_BakeOnSceneLoad: 0 + m_GISettings: + serializedVersion: 2 + m_BounceScale: 1 + m_IndirectOutputScale: 1 + m_AlbedoBoost: 1 + m_EnvironmentLightingMode: 0 + m_EnableBakedLightmaps: 1 + m_EnableRealtimeLightmaps: 0 + m_LightmapEditorSettings: + serializedVersion: 12 + m_Resolution: 2 + m_BakeResolution: 40 + m_AtlasSize: 1024 + m_AO: 0 + m_AOMaxDistance: 1 + m_CompAOExponent: 1 + m_CompAOExponentDirect: 0 + m_ExtractAmbientOcclusion: 0 + m_Padding: 2 + m_LightmapParameters: {fileID: 0} + m_LightmapsBakeMode: 1 + m_TextureCompression: 1 + m_ReflectionCompression: 2 + m_MixedBakeMode: 2 + m_BakeBackend: 1 + m_PVRSampling: 1 + m_PVRDirectSampleCount: 32 + m_PVRSampleCount: 512 + m_PVRBounces: 2 + m_PVREnvironmentSampleCount: 256 + m_PVREnvironmentReferencePointCount: 2048 + m_PVRFilteringMode: 1 + m_PVRDenoiserTypeDirect: 1 + m_PVRDenoiserTypeIndirect: 1 + m_PVRDenoiserTypeAO: 1 + m_PVRFilterTypeDirect: 0 + m_PVRFilterTypeIndirect: 0 + m_PVRFilterTypeAO: 0 + m_PVREnvironmentMIS: 1 + m_PVRCulling: 1 + m_PVRFilteringGaussRadiusDirect: 1 + m_PVRFilteringGaussRadiusIndirect: 5 + m_PVRFilteringGaussRadiusAO: 2 + m_PVRFilteringAtrousPositionSigmaDirect: 0.5 + m_PVRFilteringAtrousPositionSigmaIndirect: 2 + m_PVRFilteringAtrousPositionSigmaAO: 1 + m_ExportTrainingData: 0 + m_TrainingDataDestination: TrainingData + m_LightProbeSampleCountMultiplier: 4 + m_LightingDataAsset: {fileID: 0} + m_LightingSettings: {fileID: 0} +--- !u!196 &4 +NavMeshSettings: + serializedVersion: 2 + m_ObjectHideFlags: 0 + m_BuildSettings: + serializedVersion: 3 + agentTypeID: 0 + agentRadius: 0.5 + agentHeight: 2 + agentSlope: 45 + agentClimb: 0.4 + ledgeDropHeight: 0 + maxJumpAcrossDistance: 0 + minRegionArea: 2 + manualCellSize: 0 + cellSize: 0.16666667 + manualTileSize: 0 + tileSize: 256 + buildHeightMesh: 0 + maxJobWorkers: 0 + preserveTilesOutsideBounds: 0 + debug: + m_Flags: 0 + m_NavMeshData: {fileID: 0} +--- !u!1001 &1879396995 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + serializedVersion: 3 + m_TransformParent: {fileID: 0} + m_Modifications: + - target: {fileID: 6175900562428407386, guid: ffa1ab8ed58b72343ad93116ded1700a, + type: 3} + propertyPath: GlobalObjectIdHash + value: 1346653293 + objectReference: {fileID: 0} + - target: {fileID: 6175900562428407387, guid: ffa1ab8ed58b72343ad93116ded1700a, + type: 3} + propertyPath: m_Name + value: AddressableTestObject + objectReference: {fileID: 0} + - target: {fileID: 6175900562428407388, guid: ffa1ab8ed58b72343ad93116ded1700a, + type: 3} + propertyPath: m_LocalPosition.x + value: 1.09747 + objectReference: {fileID: 0} + - target: {fileID: 6175900562428407388, guid: ffa1ab8ed58b72343ad93116ded1700a, + type: 3} + propertyPath: m_LocalPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 6175900562428407388, guid: ffa1ab8ed58b72343ad93116ded1700a, + type: 3} + propertyPath: m_LocalPosition.z + value: 1.59747 + objectReference: {fileID: 0} + - target: {fileID: 6175900562428407388, guid: ffa1ab8ed58b72343ad93116ded1700a, + type: 3} + propertyPath: m_LocalRotation.w + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 6175900562428407388, guid: ffa1ab8ed58b72343ad93116ded1700a, + type: 3} + propertyPath: m_LocalRotation.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 6175900562428407388, guid: ffa1ab8ed58b72343ad93116ded1700a, + type: 3} + propertyPath: m_LocalRotation.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 6175900562428407388, guid: ffa1ab8ed58b72343ad93116ded1700a, + type: 3} + propertyPath: m_LocalRotation.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 6175900562428407388, guid: ffa1ab8ed58b72343ad93116ded1700a, + type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 6175900562428407388, guid: ffa1ab8ed58b72343ad93116ded1700a, + type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 6175900562428407388, guid: ffa1ab8ed58b72343ad93116ded1700a, + type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_RemovedGameObjects: [] + m_AddedGameObjects: [] + m_AddedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: ffa1ab8ed58b72343ad93116ded1700a, type: 3} +--- !u!1660057539 &9223372036854775807 +SceneRoots: + m_ObjectHideFlags: 0 + m_Roots: + - {fileID: 1879396995} diff --git a/testproject/Assets/Scenes/AddressableInSceneObject.unity.meta b/testproject/Assets/Scenes/AddressableInSceneObject.unity.meta new file mode 100644 index 0000000000..dbdfd8aca5 --- /dev/null +++ b/testproject/Assets/Scenes/AddressableInSceneObject.unity.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 68d21678646384e6291bb2b568b5d95c +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: addressablebundle + assetBundleVariant: diff --git a/testproject/Assets/Scenes/MultiprocessTestScene.unity b/testproject/Assets/Scenes/MultiprocessTestScene.unity deleted file mode 100644 index f67263407e..0000000000 --- a/testproject/Assets/Scenes/MultiprocessTestScene.unity +++ /dev/null @@ -1,1062 +0,0 @@ -%YAML 1.1 -%TAG !u! tag:unity3d.com,2011: ---- !u!29 &1 -OcclusionCullingSettings: - m_ObjectHideFlags: 0 - serializedVersion: 2 - m_OcclusionBakeSettings: - smallestOccluder: 5 - smallestHole: 0.25 - backfaceThreshold: 100 - m_SceneGUID: 00000000000000000000000000000000 - m_OcclusionCullingData: {fileID: 0} ---- !u!104 &2 -RenderSettings: - m_ObjectHideFlags: 0 - serializedVersion: 10 - m_Fog: 0 - m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} - m_FogMode: 3 - m_FogDensity: 0.01 - m_LinearFogStart: 0 - m_LinearFogEnd: 300 - m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1} - m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1} - m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1} - m_AmbientIntensity: 1 - m_AmbientMode: 0 - m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1} - m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0} - m_HaloStrength: 0.5 - m_FlareStrength: 1 - m_FlareFadeSpeed: 3 - m_HaloTexture: {fileID: 0} - m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0} - m_DefaultReflectionMode: 0 - m_DefaultReflectionResolution: 128 - m_ReflectionBounces: 1 - m_ReflectionIntensity: 1 - m_CustomReflection: {fileID: 0} - m_Sun: {fileID: 0} - m_UseRadianceAmbientProbe: 0 ---- !u!157 &3 -LightmapSettings: - m_ObjectHideFlags: 0 - serializedVersion: 13 - m_BakeOnSceneLoad: 0 - m_GISettings: - serializedVersion: 2 - m_BounceScale: 1 - m_IndirectOutputScale: 1 - m_AlbedoBoost: 1 - m_EnvironmentLightingMode: 0 - m_EnableBakedLightmaps: 1 - m_EnableRealtimeLightmaps: 0 - m_LightmapEditorSettings: - serializedVersion: 12 - m_Resolution: 2 - m_BakeResolution: 40 - m_AtlasSize: 1024 - m_AO: 0 - m_AOMaxDistance: 1 - m_CompAOExponent: 1 - m_CompAOExponentDirect: 0 - m_ExtractAmbientOcclusion: 0 - m_Padding: 2 - m_LightmapParameters: {fileID: 0} - m_LightmapsBakeMode: 1 - m_TextureCompression: 1 - m_ReflectionCompression: 2 - m_MixedBakeMode: 2 - m_BakeBackend: 1 - m_PVRSampling: 1 - m_PVRDirectSampleCount: 32 - m_PVRSampleCount: 512 - m_PVRBounces: 2 - m_PVREnvironmentSampleCount: 256 - m_PVREnvironmentReferencePointCount: 2048 - m_PVRFilteringMode: 1 - m_PVRDenoiserTypeDirect: 1 - m_PVRDenoiserTypeIndirect: 1 - m_PVRDenoiserTypeAO: 1 - m_PVRFilterTypeDirect: 0 - m_PVRFilterTypeIndirect: 0 - m_PVRFilterTypeAO: 0 - m_PVREnvironmentMIS: 1 - m_PVRCulling: 1 - m_PVRFilteringGaussRadiusDirect: 1 - m_PVRFilteringGaussRadiusIndirect: 5 - m_PVRFilteringGaussRadiusAO: 2 - m_PVRFilteringAtrousPositionSigmaDirect: 0.5 - m_PVRFilteringAtrousPositionSigmaIndirect: 2 - m_PVRFilteringAtrousPositionSigmaAO: 1 - m_ExportTrainingData: 0 - m_TrainingDataDestination: TrainingData - m_LightProbeSampleCountMultiplier: 4 - m_LightingDataAsset: {fileID: 0} - m_LightingSettings: {fileID: 130932425} ---- !u!196 &4 -NavMeshSettings: - serializedVersion: 2 - m_ObjectHideFlags: 0 - m_BuildSettings: - serializedVersion: 3 - agentTypeID: 0 - agentRadius: 0.5 - agentHeight: 2 - agentSlope: 45 - agentClimb: 0.4 - ledgeDropHeight: 0 - maxJumpAcrossDistance: 0 - minRegionArea: 2 - manualCellSize: 0 - cellSize: 0.16666667 - manualTileSize: 0 - tileSize: 256 - buildHeightMesh: 0 - maxJobWorkers: 0 - preserveTilesOutsideBounds: 0 - debug: - m_Flags: 0 - m_NavMeshData: {fileID: 0} ---- !u!1 &127222500 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 127222502} - - component: {fileID: 127222501} - m_Layer: 0 - m_Name: Directional Light - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!108 &127222501 -Light: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 127222500} - m_Enabled: 1 - serializedVersion: 11 - m_Type: 1 - m_Color: {r: 1, g: 0.95686275, b: 0.8392157, a: 1} - m_Intensity: 1 - m_Range: 10 - m_SpotAngle: 30 - m_InnerSpotAngle: 21.80208 - m_CookieSize: 10 - m_Shadows: - m_Type: 2 - m_Resolution: -1 - m_CustomResolution: -1 - m_Strength: 1 - m_Bias: 0.05 - m_NormalBias: 0.4 - m_NearPlane: 0.2 - m_CullingMatrixOverride: - e00: 1 - e01: 0 - e02: 0 - e03: 0 - e10: 0 - e11: 1 - e12: 0 - e13: 0 - e20: 0 - e21: 0 - e22: 1 - e23: 0 - e30: 0 - e31: 0 - e32: 0 - e33: 1 - m_UseCullingMatrixOverride: 0 - m_Cookie: {fileID: 0} - m_DrawHalo: 0 - m_Flare: {fileID: 0} - m_RenderMode: 0 - m_CullingMask: - serializedVersion: 2 - m_Bits: 4294967295 - m_RenderingLayerMask: 1 - m_Lightmapping: 4 - m_LightShadowCasterMode: 0 - m_AreaSize: {x: 1, y: 1} - m_BounceIntensity: 1 - m_ColorTemperature: 6570 - m_UseColorTemperature: 0 - m_BoundingSphereOverride: {x: 0, y: 0, z: 0, w: 0} - m_UseBoundingSphereOverride: 0 - m_UseViewFrustumForShadowCasterCull: 1 - m_ForceVisible: 0 - m_ShadowRadius: 0 - m_ShadowAngle: 0 - m_LightUnit: 1 - m_LuxAtDistance: 1 - m_EnableSpotReflector: 1 ---- !u!4 &127222502 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 127222500} - serializedVersion: 2 - m_LocalRotation: {x: 0.40821788, y: -0.23456968, z: 0.10938163, w: 0.8754261} - m_LocalPosition: {x: 0, y: 3, z: 0} - m_LocalScale: {x: 1, y: 1, z: 1} - m_ConstrainProportionsScale: 0 - m_Children: [] - m_Father: {fileID: 0} - m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0} ---- !u!850595691 &130932425 -LightingSettings: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_Name: - serializedVersion: 9 - m_EnableBakedLightmaps: 0 - m_EnableRealtimeLightmaps: 0 - m_RealtimeEnvironmentLighting: 1 - m_BounceScale: 1 - m_AlbedoBoost: 1 - m_IndirectOutputScale: 1 - m_UsingShadowmask: 1 - m_BakeBackend: 1 - m_LightmapMaxSize: 1024 - m_LightmapSizeFixed: 0 - m_UseMipmapLimits: 1 - m_BakeResolution: 40 - m_Padding: 2 - m_LightmapCompression: 3 - m_AO: 0 - m_AOMaxDistance: 1 - m_CompAOExponent: 1 - m_CompAOExponentDirect: 0 - m_ExtractAO: 0 - m_MixedBakeMode: 2 - m_LightmapsBakeMode: 1 - m_FilterMode: 1 - m_LightmapParameters: {fileID: 15204, guid: 0000000000000000f000000000000000, type: 0} - m_ExportTrainingData: 0 - m_EnableWorkerProcessBaking: 1 - m_TrainingDataDestination: TrainingData - m_RealtimeResolution: 2 - m_ForceWhiteAlbedo: 0 - m_ForceUpdates: 0 - m_PVRCulling: 1 - m_PVRSampling: 1 - m_PVRDirectSampleCount: 32 - m_PVRSampleCount: 512 - m_PVREnvironmentSampleCount: 256 - m_PVREnvironmentReferencePointCount: 2048 - m_LightProbeSampleCountMultiplier: 4 - m_PVRBounces: 2 - m_PVRMinBounces: 2 - m_PVREnvironmentImportanceSampling: 1 - m_PVRFilteringMode: 1 - m_PVRDenoiserTypeDirect: 1 - m_PVRDenoiserTypeIndirect: 1 - m_PVRDenoiserTypeAO: 1 - m_PVRFilterTypeDirect: 0 - m_PVRFilterTypeIndirect: 0 - m_PVRFilterTypeAO: 0 - m_PVRFilteringGaussRadiusDirect: 1 - m_PVRFilteringGaussRadiusIndirect: 5 - m_PVRFilteringGaussRadiusAO: 2 - m_PVRFilteringAtrousPositionSigmaDirect: 0.5 - m_PVRFilteringAtrousPositionSigmaIndirect: 2 - m_PVRFilteringAtrousPositionSigmaAO: 1 - m_RespectSceneVisibilityWhenBakingGI: 0 ---- !u!1 &160940364 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 160940368} - - component: {fileID: 160940367} - - component: {fileID: 160940366} - - component: {fileID: 160940365} - m_Layer: 0 - m_Name: Boundary bottom left - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!135 &160940365 -SphereCollider: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 160940364} - m_Material: {fileID: 0} - m_IncludeLayers: - serializedVersion: 2 - m_Bits: 0 - m_ExcludeLayers: - serializedVersion: 2 - m_Bits: 0 - m_LayerOverridePriority: 0 - m_IsTrigger: 0 - m_ProvidesContacts: 0 - m_Enabled: 1 - serializedVersion: 3 - m_Radius: 0.5 - m_Center: {x: 0, y: 0, z: 0} ---- !u!23 &160940366 -MeshRenderer: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 160940364} - m_Enabled: 1 - m_CastShadows: 1 - m_ReceiveShadows: 1 - m_DynamicOccludee: 1 - m_StaticShadowCaster: 0 - m_MotionVectors: 1 - m_LightProbeUsage: 1 - m_ReflectionProbeUsage: 1 - m_RayTracingMode: 2 - m_RayTraceProcedural: 0 - m_RayTracingAccelStructBuildFlagsOverride: 0 - m_RayTracingAccelStructBuildFlags: 1 - m_SmallMeshCulling: 1 - m_RenderingLayerMask: 1 - m_RendererPriority: 0 - m_Materials: - - {fileID: 10303, guid: 0000000000000000f000000000000000, type: 0} - m_StaticBatchInfo: - firstSubMesh: 0 - subMeshCount: 0 - m_StaticBatchRoot: {fileID: 0} - m_ProbeAnchor: {fileID: 0} - m_LightProbeVolumeOverride: {fileID: 0} - m_ScaleInLightmap: 1 - m_ReceiveGI: 1 - m_PreserveUVs: 0 - m_IgnoreNormalsForChartDetection: 0 - m_ImportantGI: 0 - m_StitchLightmapSeams: 1 - m_SelectedEditorRenderState: 3 - m_MinimumChartSize: 4 - m_AutoUVMaxDistance: 0.5 - m_AutoUVMaxAngle: 89 - m_LightmapParameters: {fileID: 0} - m_SortingLayerID: 0 - m_SortingLayer: 0 - m_SortingOrder: 0 - m_AdditionalVertexStreams: {fileID: 0} ---- !u!33 &160940367 -MeshFilter: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 160940364} - m_Mesh: {fileID: 10207, guid: 0000000000000000e000000000000000, type: 0} ---- !u!4 &160940368 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 160940364} - serializedVersion: 2 - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: -10, y: -10, z: -10} - m_LocalScale: {x: 1, y: 1, z: 1} - m_ConstrainProportionsScale: 0 - m_Children: [] - m_Father: {fileID: 0} - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !u!1 &430011403 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 430011407} - - component: {fileID: 430011406} - - component: {fileID: 430011405} - - component: {fileID: 430011404} - m_Layer: 0 - m_Name: ThreeDText - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!114 &430011404 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 430011403} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 04cf3cc1396054b009a1ed283aa50021, type: 3} - m_Name: - m_EditorClassIdentifier: - IsTestCoordinatorActiveAndEnabled: 0 - CommandLineArguments: ---- !u!102 &430011405 -TextMesh: - serializedVersion: 3 - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 430011403} - m_Text: Hello World - m_OffsetZ: 0 - m_CharacterSize: 1 - m_LineSpacing: 1 - m_Anchor: 0 - m_Alignment: 0 - m_TabSize: 4 - m_FontSize: 0 - m_FontStyle: 0 - m_RichText: 1 - m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} - m_Color: - serializedVersion: 2 - rgba: 4294967295 ---- !u!23 &430011406 -MeshRenderer: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 430011403} - m_Enabled: 1 - m_CastShadows: 1 - m_ReceiveShadows: 1 - m_DynamicOccludee: 1 - m_StaticShadowCaster: 0 - m_MotionVectors: 1 - m_LightProbeUsage: 1 - m_ReflectionProbeUsage: 1 - m_RayTracingMode: 2 - m_RayTraceProcedural: 0 - m_RayTracingAccelStructBuildFlagsOverride: 0 - m_RayTracingAccelStructBuildFlags: 1 - m_SmallMeshCulling: 1 - m_RenderingLayerMask: 1 - m_RendererPriority: 0 - m_Materials: - - {fileID: 10100, guid: 0000000000000000e000000000000000, type: 0} - m_StaticBatchInfo: - firstSubMesh: 0 - subMeshCount: 0 - m_StaticBatchRoot: {fileID: 0} - m_ProbeAnchor: {fileID: 0} - m_LightProbeVolumeOverride: {fileID: 0} - m_ScaleInLightmap: 1 - m_ReceiveGI: 1 - m_PreserveUVs: 0 - m_IgnoreNormalsForChartDetection: 0 - m_ImportantGI: 0 - m_StitchLightmapSeams: 1 - m_SelectedEditorRenderState: 3 - m_MinimumChartSize: 4 - m_AutoUVMaxDistance: 0.5 - m_AutoUVMaxAngle: 89 - m_LightmapParameters: {fileID: 0} - m_SortingLayerID: 0 - m_SortingLayer: 0 - m_SortingOrder: 0 - m_AdditionalVertexStreams: {fileID: 0} ---- !u!4 &430011407 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 430011403} - serializedVersion: 2 - m_LocalRotation: {x: 0.2164396, y: 0, z: 0, w: 0.97629607} - m_LocalPosition: {x: -45, y: 10, z: 10} - m_LocalScale: {x: 1, y: 1, z: 1} - m_ConstrainProportionsScale: 0 - m_Children: [] - m_Father: {fileID: 0} - m_LocalEulerAnglesHint: {x: 25, y: 0, z: 0} ---- !u!1 &941021721 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 941021724} - - component: {fileID: 941021723} - - component: {fileID: 941021722} - m_Layer: 0 - m_Name: Main Camera - m_TagString: MainCamera - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!81 &941021722 -AudioListener: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 941021721} - m_Enabled: 1 ---- !u!20 &941021723 -Camera: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 941021721} - m_Enabled: 1 - serializedVersion: 2 - m_ClearFlags: 1 - m_BackGroundColor: {r: 0.19215687, g: 0.3019608, b: 0.4745098, a: 0} - m_projectionMatrixMode: 1 - m_GateFitMode: 2 - m_FOVAxisMode: 0 - m_Iso: 200 - m_ShutterSpeed: 0.005 - m_Aperture: 16 - m_FocusDistance: 10 - m_FocalLength: 50 - m_BladeCount: 5 - m_Curvature: {x: 2, y: 11} - m_BarrelClipping: 0.25 - m_Anamorphism: 0 - m_SensorSize: {x: 36, y: 24} - m_LensShift: {x: 0, y: 0} - m_NormalizedViewPortRect: - serializedVersion: 2 - x: 0 - y: 0 - width: 1 - height: 1 - near clip plane: 0.3 - far clip plane: 1000 - field of view: 60 - orthographic: 0 - orthographic size: 5 - m_Depth: -1 - m_CullingMask: - serializedVersion: 2 - m_Bits: 4294967295 - m_RenderingPath: -1 - m_TargetTexture: {fileID: 0} - m_TargetDisplay: 0 - m_TargetEye: 3 - m_HDR: 1 - m_AllowMSAA: 1 - m_AllowDynamicResolution: 0 - m_ForceIntoRT: 0 - m_OcclusionCulling: 1 - m_StereoConvergence: 10 - m_StereoSeparation: 0.022 ---- !u!4 &941021724 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 941021721} - serializedVersion: 2 - m_LocalRotation: {x: 0.21736304, y: -0, z: -0, w: 0.97609085} - m_LocalPosition: {x: 0, y: 9.15, z: -27.5} - m_LocalScale: {x: 1, y: 1, z: 1} - m_ConstrainProportionsScale: 0 - m_Children: [] - m_Father: {fileID: 0} - m_LocalEulerAnglesHint: {x: 25.108, y: 0, z: 0} ---- !u!1 &996484657 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 996484661} - - component: {fileID: 996484660} - - component: {fileID: 996484659} - - component: {fileID: 996484658} - m_Layer: 0 - m_Name: Boundary center - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!135 &996484658 -SphereCollider: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 996484657} - m_Material: {fileID: 0} - m_IncludeLayers: - serializedVersion: 2 - m_Bits: 0 - m_ExcludeLayers: - serializedVersion: 2 - m_Bits: 0 - m_LayerOverridePriority: 0 - m_IsTrigger: 0 - m_ProvidesContacts: 0 - m_Enabled: 1 - serializedVersion: 3 - m_Radius: 0.5 - m_Center: {x: 0, y: 0, z: 0} ---- !u!23 &996484659 -MeshRenderer: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 996484657} - m_Enabled: 1 - m_CastShadows: 1 - m_ReceiveShadows: 1 - m_DynamicOccludee: 1 - m_StaticShadowCaster: 0 - m_MotionVectors: 1 - m_LightProbeUsage: 1 - m_ReflectionProbeUsage: 1 - m_RayTracingMode: 2 - m_RayTraceProcedural: 0 - m_RayTracingAccelStructBuildFlagsOverride: 0 - m_RayTracingAccelStructBuildFlags: 1 - m_SmallMeshCulling: 1 - m_RenderingLayerMask: 1 - m_RendererPriority: 0 - m_Materials: - - {fileID: 10303, guid: 0000000000000000f000000000000000, type: 0} - m_StaticBatchInfo: - firstSubMesh: 0 - subMeshCount: 0 - m_StaticBatchRoot: {fileID: 0} - m_ProbeAnchor: {fileID: 0} - m_LightProbeVolumeOverride: {fileID: 0} - m_ScaleInLightmap: 1 - m_ReceiveGI: 1 - m_PreserveUVs: 0 - m_IgnoreNormalsForChartDetection: 0 - m_ImportantGI: 0 - m_StitchLightmapSeams: 1 - m_SelectedEditorRenderState: 3 - m_MinimumChartSize: 4 - m_AutoUVMaxDistance: 0.5 - m_AutoUVMaxAngle: 89 - m_LightmapParameters: {fileID: 0} - m_SortingLayerID: 0 - m_SortingLayer: 0 - m_SortingOrder: 0 - m_AdditionalVertexStreams: {fileID: 0} ---- !u!33 &996484660 -MeshFilter: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 996484657} - m_Mesh: {fileID: 10207, guid: 0000000000000000e000000000000000, type: 0} ---- !u!4 &996484661 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 996484657} - serializedVersion: 2 - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: 0, y: 0, z: 0} - m_LocalScale: {x: 1, y: 1, z: 1} - m_ConstrainProportionsScale: 0 - m_Children: [] - m_Father: {fileID: 0} - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !u!1 &1206022453 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 1206022457} - - component: {fileID: 1206022456} - - component: {fileID: 1206022455} - - component: {fileID: 1206022454} - m_Layer: 0 - m_Name: Boundary top right - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!135 &1206022454 -SphereCollider: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1206022453} - m_Material: {fileID: 0} - m_IncludeLayers: - serializedVersion: 2 - m_Bits: 0 - m_ExcludeLayers: - serializedVersion: 2 - m_Bits: 0 - m_LayerOverridePriority: 0 - m_IsTrigger: 0 - m_ProvidesContacts: 0 - m_Enabled: 1 - serializedVersion: 3 - m_Radius: 0.5 - m_Center: {x: 0, y: 0, z: 0} ---- !u!23 &1206022455 -MeshRenderer: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1206022453} - m_Enabled: 1 - m_CastShadows: 1 - m_ReceiveShadows: 1 - m_DynamicOccludee: 1 - m_StaticShadowCaster: 0 - m_MotionVectors: 1 - m_LightProbeUsage: 1 - m_ReflectionProbeUsage: 1 - m_RayTracingMode: 2 - m_RayTraceProcedural: 0 - m_RayTracingAccelStructBuildFlagsOverride: 0 - m_RayTracingAccelStructBuildFlags: 1 - m_SmallMeshCulling: 1 - m_RenderingLayerMask: 1 - m_RendererPriority: 0 - m_Materials: - - {fileID: 10303, guid: 0000000000000000f000000000000000, type: 0} - m_StaticBatchInfo: - firstSubMesh: 0 - subMeshCount: 0 - m_StaticBatchRoot: {fileID: 0} - m_ProbeAnchor: {fileID: 0} - m_LightProbeVolumeOverride: {fileID: 0} - m_ScaleInLightmap: 1 - m_ReceiveGI: 1 - m_PreserveUVs: 0 - m_IgnoreNormalsForChartDetection: 0 - m_ImportantGI: 0 - m_StitchLightmapSeams: 1 - m_SelectedEditorRenderState: 3 - m_MinimumChartSize: 4 - m_AutoUVMaxDistance: 0.5 - m_AutoUVMaxAngle: 89 - m_LightmapParameters: {fileID: 0} - m_SortingLayerID: 0 - m_SortingLayer: 0 - m_SortingOrder: 0 - m_AdditionalVertexStreams: {fileID: 0} ---- !u!33 &1206022456 -MeshFilter: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1206022453} - m_Mesh: {fileID: 10207, guid: 0000000000000000e000000000000000, type: 0} ---- !u!4 &1206022457 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1206022453} - serializedVersion: 2 - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: 10, y: 10, z: 10} - m_LocalScale: {x: 1, y: 1, z: 1} - m_ConstrainProportionsScale: 0 - m_Children: [] - m_Father: {fileID: 0} - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !u!1 &1211923374 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 1211923376} - - component: {fileID: 1211923375} - - component: {fileID: 1211923378} - - component: {fileID: 1211923377} - m_Layer: 0 - m_Name: '[NetworkManager] (Multiprocess)' - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!114 &1211923375 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1211923374} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 593a2fe42fa9d37498c96f9a383b6521, type: 3} - m_Name: - m_EditorClassIdentifier: - NetworkManagerExpanded: 0 - NetworkConfig: - ProtocolVersion: 0 - NetworkTransport: {fileID: 2027640073} - PlayerPrefab: {fileID: 4700706668509470175, guid: 7eeaaf9e50c0afc4dab93584a54fb0d6, - type: 3} - Prefabs: - NetworkPrefabsLists: [] - TickRate: 30 - ClientConnectionBufferTimeout: 10 - ConnectionApproval: 0 - ConnectionData: - EnableTimeResync: 0 - TimeResyncInterval: 30 - EnsureNetworkVariableLengthSafety: 0 - EnableSceneManagement: 1 - ForceSamePrefabs: 1 - RecycleNetworkIds: 1 - NetworkIdRecycleDelay: 120 - RpcHashSize: 0 - LoadSceneTimeOut: 120 - SpawnTimeout: 10 - EnableNetworkLogs: 1 - NetworkTopology: 0 - UseCMBService: 0 - AutoSpawnPlayerPrefabClientSide: 1 - NetworkProfilingMetrics: 1 - OldPrefabList: - - Override: 0 - Prefab: {fileID: 9115731988109684252, guid: c2851feb7276442cc86a6f2d1d69ea11, - type: 3} - SourcePrefabToOverride: {fileID: 0} - SourceHashToOverride: 0 - OverridingTargetPrefab: {fileID: 0} - RunInBackground: 1 - LogLevel: 1 ---- !u!4 &1211923376 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1211923374} - serializedVersion: 2 - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: 0, y: 0, z: 0} - m_LocalScale: {x: 1, y: 1, z: 1} - m_ConstrainProportionsScale: 0 - m_Children: - - {fileID: 2027640072} - m_Father: {fileID: 0} - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !u!114 &1211923377 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1211923374} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 068bf11ceb1344667af4cc40950f44f4, type: 3} - m_Name: - m_EditorClassIdentifier: - ReferencedPrefab: {fileID: 9115731988109684252, guid: c2851feb7276442cc86a6f2d1d69ea11, - type: 3} ---- !u!114 &1211923378 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1211923374} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 55d1c75ce242745ac98f7e7aca6d2d19, type: 3} - m_Name: - m_EditorClassIdentifier: ---- !u!1 &1274245423 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 1274245425} - - component: {fileID: 1274245424} - - component: {fileID: 1274245426} - m_Layer: 0 - m_Name: TestCoordinator - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!114 &1274245424 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1274245423} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: d5a57f767e5e46a458fc5d3c628d0cbb, type: 3} - m_Name: - m_EditorClassIdentifier: - GlobalObjectIdHash: 2217825759 - InScenePlacedSourceGlobalObjectIdHash: 0 - DeferredDespawnTick: 0 - Ownership: 1 - AlwaysReplicateAsRoot: 0 - SynchronizeTransform: 1 - ActiveSceneSynchronization: 0 - SceneMigrationSynchronization: 1 - SpawnWithObservers: 1 - DontDestroyWithOwner: 0 - AutoObjectParentSync: 1 - SyncOwnerTransformWhenParented: 1 - AllowOwnerToParent: 0 ---- !u!4 &1274245425 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1274245423} - serializedVersion: 2 - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: 10, y: 10, z: 10} - m_LocalScale: {x: 1, y: 1, z: 1} - m_ConstrainProportionsScale: 0 - m_Children: [] - m_Father: {fileID: 0} - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !u!114 &1274245426 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1274245423} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: ef1240e0784f84eadb77fe822e2e03c7, type: 3} - m_Name: - m_EditorClassIdentifier: ---- !u!1 &2027640071 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 2027640072} - - component: {fileID: 2027640073} - m_Layer: 0 - m_Name: UTP - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!4 &2027640072 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 2027640071} - serializedVersion: 2 - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: 0, y: 0, z: 0} - m_LocalScale: {x: 1, y: 1, z: 1} - m_ConstrainProportionsScale: 0 - m_Children: [] - m_Father: {fileID: 1211923376} - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !u!114 &2027640073 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 2027640071} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 6960e84d07fb87f47956e7a81d71c4e6, type: 3} - m_Name: - m_EditorClassIdentifier: - m_ProtocolType: 0 - m_UseWebSockets: 0 - m_UseEncryption: 0 - m_MaxPacketQueueSize: 128 - m_MaxPayloadSize: 4096 - m_HeartbeatTimeoutMS: 500 - m_ConnectTimeoutMS: 1000 - m_MaxConnectAttempts: 60 - m_DisconnectTimeoutMS: 30000 - ConnectionData: - Address: 127.0.0.1 - Port: 7777 - ServerListenAddress: 127.0.0.1 - DebugSimulator: - PacketDelayMS: 0 - PacketJitterMS: 0 - PacketDropRate: 0 ---- !u!1660057539 &9223372036854775807 -SceneRoots: - m_ObjectHideFlags: 0 - m_Roots: - - {fileID: 941021724} - - {fileID: 127222502} - - {fileID: 1211923376} - - {fileID: 1206022457} - - {fileID: 996484661} - - {fileID: 160940368} - - {fileID: 1274245425} - - {fileID: 430011407} diff --git a/testproject/Assets/Scripts/MoveDynamicSpawnInAwake.cs b/testproject/Assets/Scripts/MoveDynamicSpawnInAwake.cs new file mode 100644 index 0000000000..23b1b909a8 --- /dev/null +++ b/testproject/Assets/Scripts/MoveDynamicSpawnInAwake.cs @@ -0,0 +1,38 @@ +using System.Collections.Generic; +using Unity.Netcode; +using UnityEngine; +using UnityEngine.SceneManagement; + +#if UNITY_6000_6_OR_NEWER && UNITY_EDITOR + [Unity.Scripting.LifecycleManagement.AutoStaticsCleanup] +#endif +public partial class MoveDynamicSpawnInAwake : MonoBehaviour +{ + public NetworkObject MovedObject { get; private set; } + private static readonly HashSet k_AlreadyMovedObjects = new(); + private void Awake() + { + var networkManager = NetworkManager.Singleton; + if (networkManager == null || !networkManager.IsListening) + { + return; + } + + foreach (var spawnedObject in networkManager.SpawnManager.SpawnedObjects.Values) + { + if (spawnedObject == null || !spawnedObject.IsSpawned || !spawnedObject.HasAuthority || spawnedObject.IsPlayerObject || spawnedObject.InScenePlaced) + { + continue; + } + + if (!k_AlreadyMovedObjects.Add(spawnedObject)) + { + continue; + } + + MovedObject = spawnedObject; + SceneManager.MoveGameObjectToScene(spawnedObject.gameObject, gameObject.scene); + return; + } + } +} diff --git a/testproject/Assets/Scripts/MoveDynamicSpawnInAwake.cs.meta b/testproject/Assets/Scripts/MoveDynamicSpawnInAwake.cs.meta new file mode 100644 index 0000000000..053fb00eb0 --- /dev/null +++ b/testproject/Assets/Scripts/MoveDynamicSpawnInAwake.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 566f22ce0b192499d8728df60af83423 \ No newline at end of file diff --git a/testproject/Assets/Tests/Manual/IntegrationTestScenes/EmptyScene3.unity.meta b/testproject/Assets/Tests/Manual/IntegrationTestScenes/EmptyScene3.unity.meta index 46669dd13d..88bb22b242 100644 --- a/testproject/Assets/Tests/Manual/IntegrationTestScenes/EmptyScene3.unity.meta +++ b/testproject/Assets/Tests/Manual/IntegrationTestScenes/EmptyScene3.unity.meta @@ -1,7 +1,7 @@ fileFormatVersion: 2 -guid: abd4c8b51c445d54faa16c67ac973f1b +guid: bfb4addb64cf6455a88668eba2f759ba DefaultImporter: externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: + userData: + assetBundleName: + assetBundleVariant: diff --git a/testproject/Assets/Tests/Manual/IntegrationTestScenes/InSceneNetworkObjectMovesToDDOL.unity b/testproject/Assets/Tests/Manual/IntegrationTestScenes/InSceneNetworkObjectMovesToDDOL.unity new file mode 100644 index 0000000000..1cfda7fc2d --- /dev/null +++ b/testproject/Assets/Tests/Manual/IntegrationTestScenes/InSceneNetworkObjectMovesToDDOL.unity @@ -0,0 +1,198 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!29 &1 +OcclusionCullingSettings: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_OcclusionBakeSettings: + smallestOccluder: 5 + smallestHole: 0.25 + backfaceThreshold: 100 + m_SceneGUID: 00000000000000000000000000000000 + m_OcclusionCullingData: {fileID: 0} +--- !u!104 &2 +RenderSettings: + m_ObjectHideFlags: 0 + serializedVersion: 10 + m_Fog: 0 + m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} + m_FogMode: 3 + m_FogDensity: 0.01 + m_LinearFogStart: 0 + m_LinearFogEnd: 300 + m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1} + m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1} + m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1} + m_AmbientIntensity: 1 + m_AmbientMode: 0 + m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1} + m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0} + m_HaloStrength: 0.5 + m_FlareStrength: 1 + m_FlareFadeSpeed: 3 + m_HaloTexture: {fileID: 0} + m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0} + m_DefaultReflectionMode: 0 + m_DefaultReflectionResolution: 128 + m_ReflectionBounces: 1 + m_ReflectionIntensity: 1 + m_CustomReflection: {fileID: 0} + m_Sun: {fileID: 0} + m_UseRadianceAmbientProbe: 0 +--- !u!157 &3 +LightmapSettings: + m_ObjectHideFlags: 0 + serializedVersion: 13 + m_BakeOnSceneLoad: 0 + m_GISettings: + serializedVersion: 2 + m_BounceScale: 1 + m_IndirectOutputScale: 1 + m_AlbedoBoost: 1 + m_EnvironmentLightingMode: 0 + m_EnableBakedLightmaps: 1 + m_EnableRealtimeLightmaps: 0 + m_LightmapEditorSettings: + serializedVersion: 12 + m_Resolution: 2 + m_BakeResolution: 40 + m_AtlasSize: 1024 + m_AO: 0 + m_AOMaxDistance: 1 + m_CompAOExponent: 1 + m_CompAOExponentDirect: 0 + m_ExtractAmbientOcclusion: 0 + m_Padding: 2 + m_LightmapParameters: {fileID: 0} + m_LightmapsBakeMode: 1 + m_TextureCompression: 1 + m_ReflectionCompression: 2 + m_MixedBakeMode: 2 + m_BakeBackend: 1 + m_PVRSampling: 1 + m_PVRDirectSampleCount: 32 + m_PVRSampleCount: 512 + m_PVRBounces: 2 + m_PVREnvironmentSampleCount: 256 + m_PVREnvironmentReferencePointCount: 2048 + m_PVRFilteringMode: 1 + m_PVRDenoiserTypeDirect: 1 + m_PVRDenoiserTypeIndirect: 1 + m_PVRDenoiserTypeAO: 1 + m_PVRFilterTypeDirect: 0 + m_PVRFilterTypeIndirect: 0 + m_PVRFilterTypeAO: 0 + m_PVREnvironmentMIS: 1 + m_PVRCulling: 1 + m_PVRFilteringGaussRadiusDirect: 1 + m_PVRFilteringGaussRadiusIndirect: 5 + m_PVRFilteringGaussRadiusAO: 2 + m_PVRFilteringAtrousPositionSigmaDirect: 0.5 + m_PVRFilteringAtrousPositionSigmaIndirect: 2 + m_PVRFilteringAtrousPositionSigmaAO: 1 + m_ExportTrainingData: 0 + m_TrainingDataDestination: TrainingData + m_LightProbeSampleCountMultiplier: 4 + m_LightingDataAsset: {fileID: 0} + m_LightingSettings: {fileID: 0} +--- !u!196 &4 +NavMeshSettings: + serializedVersion: 2 + m_ObjectHideFlags: 0 + m_BuildSettings: + serializedVersion: 3 + agentTypeID: 0 + agentRadius: 0.5 + agentHeight: 2 + agentSlope: 45 + agentClimb: 0.4 + ledgeDropHeight: 0 + maxJumpAcrossDistance: 0 + minRegionArea: 2 + manualCellSize: 0 + cellSize: 0.16666667 + manualTileSize: 0 + tileSize: 256 + buildHeightMesh: 0 + maxJobWorkers: 0 + preserveTilesOutsideBounds: 0 + debug: + m_Flags: 0 + m_NavMeshData: {fileID: 0} +--- !u!1 &1633685737 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1633685739} + - component: {fileID: 1633685738} + - component: {fileID: 1633685740} + m_Layer: 0 + m_Name: InSceneObject + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &1633685738 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1633685737} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d5a57f767e5e46a458fc5d3c628d0cbb, type: 3} + m_Name: + m_EditorClassIdentifier: + GlobalObjectIdHash: 974939462 + InScenePlacedSourceGlobalObjectIdHash: 0 + DeferredDespawnTick: 0 + Ownership: 1 + AlwaysReplicateAsRoot: 0 + SynchronizeTransform: 1 + m_InScenePlaced: 1 + ActiveSceneSynchronization: 0 + SceneMigrationSynchronization: 0 + SpawnWithObservers: 1 + DontDestroyWithOwner: 0 + AutoObjectParentSync: 1 + SyncOwnerTransformWhenParented: 1 + AllowOwnerToParent: 0 +--- !u!4 &1633685739 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1633685737} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &1633685740 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1633685737} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 112072ebb4fab6341bfee4bd9d7e58da, type: 3} + m_Name: + m_EditorClassIdentifier: TestProject.ManualTests::TestProject.ManualTests.MoveInScenePlacedToDDOL + ShowTopMostFoldoutHeaderGroup: 1 +--- !u!1660057539 &9223372036854775807 +SceneRoots: + m_ObjectHideFlags: 0 + m_Roots: + - {fileID: 1633685739} diff --git a/testproject/Assets/Scenes/MultiprocessTestScene.unity.meta b/testproject/Assets/Tests/Manual/IntegrationTestScenes/InSceneNetworkObjectMovesToDDOL.unity.meta similarity index 74% rename from testproject/Assets/Scenes/MultiprocessTestScene.unity.meta rename to testproject/Assets/Tests/Manual/IntegrationTestScenes/InSceneNetworkObjectMovesToDDOL.unity.meta index 5a9d45d780..dfa51863fd 100644 --- a/testproject/Assets/Scenes/MultiprocessTestScene.unity.meta +++ b/testproject/Assets/Tests/Manual/IntegrationTestScenes/InSceneNetworkObjectMovesToDDOL.unity.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 76743cb7b342c49279327834918a9c6e +guid: 4c20c17b4f92e634f8796b0460851d49 DefaultImporter: externalObjects: {} userData: diff --git a/testproject/Assets/Tests/Manual/IntegrationTestScenes/MoveADynamicObjectInAwake.unity b/testproject/Assets/Tests/Manual/IntegrationTestScenes/MoveADynamicObjectInAwake.unity new file mode 100644 index 0000000000..f5b385433f --- /dev/null +++ b/testproject/Assets/Tests/Manual/IntegrationTestScenes/MoveADynamicObjectInAwake.unity @@ -0,0 +1,170 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!29 &1 +OcclusionCullingSettings: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_OcclusionBakeSettings: + smallestOccluder: 5 + smallestHole: 0.25 + backfaceThreshold: 100 + m_SceneGUID: 00000000000000000000000000000000 + m_OcclusionCullingData: {fileID: 0} +--- !u!104 &2 +RenderSettings: + m_ObjectHideFlags: 0 + serializedVersion: 10 + m_Fog: 0 + m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} + m_FogMode: 3 + m_FogDensity: 0.01 + m_LinearFogStart: 0 + m_LinearFogEnd: 300 + m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1} + m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1} + m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1} + m_AmbientIntensity: 1 + m_AmbientMode: 0 + m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1} + m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0} + m_HaloStrength: 0.5 + m_FlareStrength: 1 + m_FlareFadeSpeed: 3 + m_HaloTexture: {fileID: 0} + m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0} + m_DefaultReflectionMode: 0 + m_DefaultReflectionResolution: 128 + m_ReflectionBounces: 1 + m_ReflectionIntensity: 1 + m_CustomReflection: {fileID: 0} + m_Sun: {fileID: 0} + m_UseRadianceAmbientProbe: 0 +--- !u!157 &3 +LightmapSettings: + m_ObjectHideFlags: 0 + serializedVersion: 13 + m_BakeOnSceneLoad: 0 + m_GISettings: + serializedVersion: 2 + m_BounceScale: 1 + m_IndirectOutputScale: 1 + m_AlbedoBoost: 1 + m_EnvironmentLightingMode: 0 + m_EnableBakedLightmaps: 1 + m_EnableRealtimeLightmaps: 0 + m_LightmapEditorSettings: + serializedVersion: 12 + m_Resolution: 2 + m_BakeResolution: 40 + m_AtlasSize: 1024 + m_AO: 0 + m_AOMaxDistance: 1 + m_CompAOExponent: 1 + m_CompAOExponentDirect: 0 + m_ExtractAmbientOcclusion: 0 + m_Padding: 2 + m_LightmapParameters: {fileID: 0} + m_LightmapsBakeMode: 1 + m_TextureCompression: 1 + m_ReflectionCompression: 2 + m_MixedBakeMode: 2 + m_BakeBackend: 1 + m_PVRSampling: 1 + m_PVRDirectSampleCount: 32 + m_PVRSampleCount: 512 + m_PVRBounces: 2 + m_PVREnvironmentSampleCount: 256 + m_PVREnvironmentReferencePointCount: 2048 + m_PVRFilteringMode: 1 + m_PVRDenoiserTypeDirect: 1 + m_PVRDenoiserTypeIndirect: 1 + m_PVRDenoiserTypeAO: 1 + m_PVRFilterTypeDirect: 0 + m_PVRFilterTypeIndirect: 0 + m_PVRFilterTypeAO: 0 + m_PVREnvironmentMIS: 1 + m_PVRCulling: 1 + m_PVRFilteringGaussRadiusDirect: 1 + m_PVRFilteringGaussRadiusIndirect: 5 + m_PVRFilteringGaussRadiusAO: 2 + m_PVRFilteringAtrousPositionSigmaDirect: 0.5 + m_PVRFilteringAtrousPositionSigmaIndirect: 2 + m_PVRFilteringAtrousPositionSigmaAO: 1 + m_ExportTrainingData: 0 + m_TrainingDataDestination: TrainingData + m_LightProbeSampleCountMultiplier: 4 + m_LightingDataAsset: {fileID: 0} + m_LightingSettings: {fileID: 0} +--- !u!196 &4 +NavMeshSettings: + serializedVersion: 2 + m_ObjectHideFlags: 0 + m_BuildSettings: + serializedVersion: 3 + agentTypeID: 0 + agentRadius: 0.5 + agentHeight: 2 + agentSlope: 45 + agentClimb: 0.4 + ledgeDropHeight: 0 + maxJumpAcrossDistance: 0 + minRegionArea: 2 + manualCellSize: 0 + cellSize: 0.16666667 + manualTileSize: 0 + tileSize: 256 + buildHeightMesh: 0 + maxJobWorkers: 0 + preserveTilesOutsideBounds: 0 + debug: + m_Flags: 0 + m_NavMeshData: {fileID: 0} +--- !u!1 &1786247463 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1786247465} + - component: {fileID: 1786247464} + m_Layer: 0 + m_Name: MoveDynamicSpawnInAwake + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &1786247464 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1786247463} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 566f22ce0b192499d8728df60af83423, type: 3} + m_Name: + m_EditorClassIdentifier: TestProject::MoveDynamicSpawnInAwake +--- !u!4 &1786247465 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1786247463} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 1.09747, y: 0, z: 1.59747} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1660057539 &9223372036854775807 +SceneRoots: + m_ObjectHideFlags: 0 + m_Roots: + - {fileID: 1786247465} diff --git a/testproject/Assets/Tests/Manual/IntegrationTestScenes/MoveADynamicObjectInAwake.unity.meta b/testproject/Assets/Tests/Manual/IntegrationTestScenes/MoveADynamicObjectInAwake.unity.meta new file mode 100644 index 0000000000..46669dd13d --- /dev/null +++ b/testproject/Assets/Tests/Manual/IntegrationTestScenes/MoveADynamicObjectInAwake.unity.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: abd4c8b51c445d54faa16c67ac973f1b +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/testproject/Assets/Tests/Manual/Scripts/MoveInScenePlacedToDDOL.cs b/testproject/Assets/Tests/Manual/Scripts/MoveInScenePlacedToDDOL.cs new file mode 100644 index 0000000000..0e9fa457a9 --- /dev/null +++ b/testproject/Assets/Tests/Manual/Scripts/MoveInScenePlacedToDDOL.cs @@ -0,0 +1,34 @@ +using Unity.Netcode; +using UnityEngine; + +namespace TestProject.ManualTests +{ + public class MoveInScenePlacedToDDOL : NetworkBehaviour + { + public bool ProcessedRpc { get; private set; } + + private void Awake() + { + ProcessedRpc = false; + var networkObject = GetComponent(); + Debug.Log($"[{name}][Moving to DDOL] InScenePlaced: {networkObject.InScenePlaced}"); + DontDestroyOnLoad(gameObject); + } + + protected override void OnNetworkPostSpawn() + { + if (HasAuthority) + { + SendOnSpawnRpc(); + } + + base.OnNetworkPostSpawn(); + } + + [Rpc(SendTo.Everyone)] + private void SendOnSpawnRpc(RpcParams rpcParams = default) + { + ProcessedRpc = true; + } + } +} diff --git a/testproject/Assets/Tests/Manual/Scripts/MoveInScenePlacedToDDOL.cs.meta b/testproject/Assets/Tests/Manual/Scripts/MoveInScenePlacedToDDOL.cs.meta new file mode 100644 index 0000000000..739e4ca2d4 --- /dev/null +++ b/testproject/Assets/Tests/Manual/Scripts/MoveInScenePlacedToDDOL.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 112072ebb4fab6341bfee4bd9d7e58da \ No newline at end of file diff --git a/testproject/Assets/Tests/Manual/Scripts/NetworkPrefabPool.cs b/testproject/Assets/Tests/Manual/Scripts/NetworkPrefabPool.cs index 5b045b1855..9f441b8f58 100644 --- a/testproject/Assets/Tests/Manual/Scripts/NetworkPrefabPool.cs +++ b/testproject/Assets/Tests/Manual/Scripts/NetworkPrefabPool.cs @@ -496,12 +496,12 @@ public void UpdateSpawnsPerSecond() { StartSpawningBoxes(); } - else //Handle case where spawning coroutine is running but we set our spawn rate to zero - if (SpawnsPerSecond == 0 && m_IsSpawningObjects) - { - m_IsSpawningObjects = false; - StopCoroutine(SpawnObjects()); - } + //Handle case where spawning coroutine is running but we set our spawn rate to zero + else if (SpawnsPerSecond == 0 && m_IsSpawningObjects) + { + m_IsSpawningObjects = false; + StopCoroutine(SpawnObjects()); + } } } diff --git a/testproject/Assets/Tests/Manual/Scripts/NetworkPrefabPoolAdditive.cs b/testproject/Assets/Tests/Manual/Scripts/NetworkPrefabPoolAdditive.cs index 0c4992cbd9..44decc3dce 100644 --- a/testproject/Assets/Tests/Manual/Scripts/NetworkPrefabPoolAdditive.cs +++ b/testproject/Assets/Tests/Manual/Scripts/NetworkPrefabPoolAdditive.cs @@ -342,12 +342,12 @@ public void UpdateSpawnsPerSecond() { StartSpawningBoxes(); } - else //Handle case where spawning coroutine is running but we set our spawn rate to zero - if (SpawnsPerSecond == 0 && m_IsSpawningObjects) - { - m_IsSpawningObjects = false; - InternalStopCoroutine(); - } + //Handle case where spawning coroutine is running but we set our spawn rate to zero + else if (SpawnsPerSecond == 0 && m_IsSpawningObjects) + { + m_IsSpawningObjects = false; + InternalStopCoroutine(); + } } diff --git a/testproject/Assets/Tests/Runtime/AddressablesTests.cs b/testproject/Assets/Tests/Runtime/AddressablesTests.cs index 4c9151c0f3..7dd8aff688 100644 --- a/testproject/Assets/Tests/Runtime/AddressablesTests.cs +++ b/testproject/Assets/Tests/Runtime/AddressablesTests.cs @@ -7,6 +7,8 @@ using Unity.Netcode.TestHelpers.Runtime; using UnityEngine; using UnityEngine.AddressableAssets; +using UnityEngine.ResourceManagement.AsyncOperations; +using UnityEngine.SceneManagement; using UnityEngine.TestTools; using Assert = UnityEngine.Assertions.Assert; @@ -24,6 +26,7 @@ public class AddressablesTests : NetcodeIntegrationTest protected override bool m_TearDownIsACoroutine => false; private const string k_ValidObject = "AddressableTestObject.prefab"; + private const string k_ValidScene = "Assets/Scenes/AddressableInSceneObject.unity"; public AddressablesTests(HostOrServer hostOrServer) { @@ -56,6 +59,24 @@ private IEnumerator LoadAsset(AssetReferenceGameObject asset, NetcodeIntegration prefab.Result = handle.Result; } + private IEnumerator LoadSceneWithInSceneObject(AssetReference asset, NetcodeIntegrationTestHelpers.ResultWrapper prefab) + { + var handle = Addressables.LoadSceneAsync(asset, LoadSceneMode.Additive); + while (!handle.IsDone) + { + var nextFrameNumber = Time.frameCount + 1; + yield return new WaitUntil(() => Time.frameCount >= nextFrameNumber); + } + + Assert.AreEqual(AsyncOperationStatus.Succeeded, handle.Status, "Addressables.LoadSceneAsync failed!"); + + foreach (var networkObject in FindObjects.FromSceneByType(handle.Result.Scene, false)) + { + prefab.Result = networkObject.gameObject; + break; + } + } + protected void StartWithAddressableAssetAdded() { StartServerAndClientsWithTimeTravel(); @@ -70,7 +91,7 @@ private void AddPrefab(GameObject prefab) } } - private void SpawnAndValidate(GameObject prefab, bool waitAndAddOnClient = false) + private void SpawnAndValidate(GameObject prefab, bool waitAndAddOnClient = false, bool wasLoadedFromScene = false) { // Have to spawn it ourselves. var serverObj = Object.Instantiate(prefab); @@ -80,7 +101,14 @@ private void SpawnAndValidate(GameObject prefab, bool waitAndAddOnClient = false // Prefabs loaded by addressables actually don't show up in this search. // Unlike other tests that make prefabs programmatically, those aren't added to the scene until they're instantiated - Assert.AreEqual(1, objs.Length); + var numExpected = 1; + if (wasLoadedFromScene) + { + // If prefab was loaded from the scene, there'll be an additional object found + numExpected++; + } + + Assert.AreEqual(numExpected, objs.Length); var startTime = MockTimeProvider.StaticRealTimeSinceStartup; @@ -91,7 +119,7 @@ private void SpawnAndValidate(GameObject prefab, bool waitAndAddOnClient = false // Since it's not added, after the CreateObjectMessage is received, it's not spawned yet // Verify that to be the case as a precondition. objs = FindObjects.ByType(); - Assert.AreEqual(1, objs.Length); + Assert.AreEqual(numExpected, objs.Length); WaitForConditionOrTimeOutWithTimeTravel(() => MockTimeProvider.StaticRealTimeSinceStartup - startTime >= m_ClientNetworkManagers[0].NetworkConfig.SpawnTimeout - 0.25); foreach (var client in m_ClientNetworkManagers) { @@ -100,12 +128,22 @@ private void SpawnAndValidate(GameObject prefab, bool waitAndAddOnClient = false } objs = FindObjects.ByType(); - Assert.AreEqual(NumberOfClients + 1, objs.Length); + Assert.AreEqual(NumberOfClients + numExpected, objs.Length); foreach (var obj in objs) { Assert.AreEqual(1234567, obj.AnIntVal); Assert.AreEqual("1234567", obj.AStringVal); Assert.AreEqual("12345671234567", obj.GetValue()); + + // TODO-[MTT-15388]: Object spawned from a scene should be InScenePlaced after this ticket + if (obj.IsSpawned) + { + Assert.IsFalse(obj.NetworkObject.InScenePlaced, "Object was dynamically spawned and should be marked as such!"); + } + else + { + Assert.IsTrue(obj.NetworkObject.InScenePlaced, "Object that was loaded from scene should have been marked as in-scene placed during loading!"); + } } } @@ -144,7 +182,7 @@ public IEnumerator WhenLoadingAValidObjectAfterStarting_SpawningItSucceedsOnServ } [UnityTest] - public IEnumerator WhenSpawningServerPrefabBeforeClientPrefabHasLoaded_SpawningItSucceedsOnServerAndClientAfterConfiguredDelay([Values(1, 2, 3)] int timeout) + public IEnumerator WhenSpawningServerPrefabBeforeClientPrefabHasLoaded_SpawningItSucceedsOnServerAndClientAfterDelay() { var asset = new AssetReferenceGameObject(k_ValidObject); @@ -152,7 +190,7 @@ public IEnumerator WhenSpawningServerPrefabBeforeClientPrefabHasLoaded_SpawningI m_ServerNetworkManager.NetworkConfig.ForceSamePrefabs = false; foreach (var client in m_ClientNetworkManagers) { - client.NetworkConfig.SpawnTimeout = timeout; + client.NetworkConfig.SpawnTimeout = 3; client.NetworkConfig.ForceSamePrefabs = false; } @@ -163,6 +201,32 @@ public IEnumerator WhenSpawningServerPrefabBeforeClientPrefabHasLoaded_SpawningI SpawnAndValidate(prefabResult.Result, true); } + + // TODO-[MTT-15388]: Reconsider whether this test should be valid + // Reported on Github issue https://github.com/Unity-Technologies/com.unity.netcode.gameobjects/issues/4049 + //[UnityTest] + //public IEnumerator RegisteringPrefabFromLoadedAddressablesSceneWorks() + //{ + // var asset = new AssetReference(k_ValidScene); + + // CreateServerAndClients(); + // foreach (var manager in m_NetworkManagers) + // { + // manager.NetworkConfig.ForceSamePrefabs = false; + // } + + // StartServerAndClientsWithTimeTravel(); + + // var prefabResult = new NetcodeIntegrationTestHelpers.ResultWrapper(); + // yield return LoadSceneWithInSceneObject(asset, prefabResult); + + // foreach (var manager in m_NetworkManagers) + // { + // manager.AddNetworkPrefab(prefabResult.Result); + // } + + // SpawnAndValidate(prefabResult.Result, wasLoadedFromScene: true); + //} } } #endif diff --git a/testproject/Assets/Tests/Runtime/Animation/NetworkAnimatorTests.cs b/testproject/Assets/Tests/Runtime/Animation/NetworkAnimatorTests.cs index dc2493ec28..715e7f6156 100644 --- a/testproject/Assets/Tests/Runtime/Animation/NetworkAnimatorTests.cs +++ b/testproject/Assets/Tests/Runtime/Animation/NetworkAnimatorTests.cs @@ -527,11 +527,10 @@ private bool AllObserversSameLayerWeight(OwnerShipMode ownerShipMode, int layer, return false; } } - else - if (animatorTestHelper.Value.GetLayerWeight(layer) != targetWeight) - { - return false; - } + else if (animatorTestHelper.Value.GetLayerWeight(layer) != targetWeight) + { + return false; + } } return true; } diff --git a/testproject/Assets/Tests/Runtime/NetworkSceneManager/InScenePlacedNetworkObject/InScenePlacedProcessorTests.cs b/testproject/Assets/Tests/Runtime/NetworkSceneManager/InScenePlacedNetworkObject/InScenePlacedProcessorTests.cs new file mode 100644 index 0000000000..807ff09eeb --- /dev/null +++ b/testproject/Assets/Tests/Runtime/NetworkSceneManager/InScenePlacedNetworkObject/InScenePlacedProcessorTests.cs @@ -0,0 +1,75 @@ +using System.Collections; +using NUnit.Framework; +using Unity.Netcode; +using Unity.Netcode.TestHelpers.Runtime; +using UnityEngine; +using UnityEngine.SceneManagement; +using UnityEngine.TestTools; + +namespace TestProject.RuntimeTests +{ + internal class InScenePlacedProcessorTests : NetcodeIntegrationTest + { + protected override int NumberOfClients => 0; + + private static readonly string k_DynamicObjectMoverScene = "MoveADynamicObjectInAwake"; + + private GameObject m_DynamicSpawnPrefab; + + protected override void OnServerAndClientsCreated() + { + m_DynamicSpawnPrefab = CreateNetworkObjectPrefab("DynamicSpawnObject"); + base.OnServerAndClientsCreated(); + } + + [UnityTest] + public IEnumerator InScenePlacedProcessorSkipsMovedObject() + { + var authority = GetAuthorityNetworkManager(); + var spawnedObj = SpawnObject(m_DynamicSpawnPrefab, authority).GetComponent(); + + yield return WaitForSpawnedOnAllOrTimeOut(spawnedObj); + AssertOnTimeout("Timed out waiting for object to spawn!"); + + Assert.IsFalse(spawnedObj.InScenePlaced, "Dynamically spawned object should not be InScenePlaced!"); + + authority.SceneManager.OnSceneEvent += SceneManager_OnSceneEvent; + var status = authority.SceneManager.LoadScene(k_DynamicObjectMoverScene, LoadSceneMode.Additive); + Assert.True(status == SceneEventProgressStatus.Started, $"Failed to start lading scene {k_DynamicObjectMoverScene} with status {status}!"); + yield return WaitForConditionOrTimeOut(() => m_SceneLoaded.IsValid()); + AssertOnTimeout("Timed out waiting for scene to load!"); + + var movers = FindObjects.ByType(); + foreach (var mover in movers) + { + var movedObject = mover.MovedObject; + Assert.IsFalse(movedObject == null); + Assert.IsFalse(movedObject.InScenePlaced, "Dynamically spawned object should not be re-processed as InScenePlaced!"); + Assert.AreEqual(mover.gameObject.scene, movedObject.gameObject.scene, "Object should have moved scenes!"); + } + + yield return CreateAndStartNewClient(); + AssertOnTimeout("Timed out waiting for late joining client!"); + + yield return WaitForSpawnedOnAllOrTimeOut(spawnedObj); + AssertOnTimeout("Timed out waiting for object to be spawned on late joining client!"); + } + + private Scene m_SceneLoaded; + private void SceneManager_OnSceneEvent(SceneEvent sceneEvent) + { + var authority = GetAuthorityNetworkManager(); + switch (sceneEvent.SceneEventType) + { + case SceneEventType.LoadComplete: + { + if (sceneEvent.ClientId == authority.LocalClientId) + { + m_SceneLoaded = sceneEvent.Scene; + } + return; + } + } + } + } +} diff --git a/testproject/Assets/Tests/Runtime/NetworkSceneManager/InScenePlacedNetworkObject/InScenePlacedProcessorTests.cs.meta b/testproject/Assets/Tests/Runtime/NetworkSceneManager/InScenePlacedNetworkObject/InScenePlacedProcessorTests.cs.meta new file mode 100644 index 0000000000..3d0a9439ec --- /dev/null +++ b/testproject/Assets/Tests/Runtime/NetworkSceneManager/InScenePlacedNetworkObject/InScenePlacedProcessorTests.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 9abce9656f174f768488bb052afa8d92 +timeCreated: 1783723861 \ No newline at end of file diff --git a/testproject/Assets/Tests/Runtime/NetworkSceneManager/NetworkObjectSceneMigrationTests.cs b/testproject/Assets/Tests/Runtime/NetworkSceneManager/NetworkObjectSceneMigrationTests.cs index d5eb5f427c..736de24acf 100644 --- a/testproject/Assets/Tests/Runtime/NetworkSceneManager/NetworkObjectSceneMigrationTests.cs +++ b/testproject/Assets/Tests/Runtime/NetworkSceneManager/NetworkObjectSceneMigrationTests.cs @@ -1,6 +1,9 @@ using System; using System.Collections; using System.Collections.Generic; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Text; using NUnit.Framework; using Unity.Netcode; using Unity.Netcode.TestHelpers.Runtime; @@ -13,27 +16,30 @@ namespace TestProject.RuntimeTests { /// /// NetworkObject Scene Migration Integration Tests - /// - /// /// - public class NetworkObjectSceneMigrationTests : NetcodeIntegrationTest + [TestFixture(HostOrServer.Host)] + [TestFixture(HostOrServer.DAHost)] + internal class NetworkObjectSceneMigrationTests : NetcodeIntegrationTest { - private List m_TestScenes = new List() { "EmptyScene1", "EmptyScene2", "EmptyScene3" }; + private readonly List m_TestScenes = new() { "EmptyScene1", "EmptyScene2", "EmptyScene3" }; protected override int NumberOfClients => 2; + private GameObject m_TestPrefab; private GameObject m_TestPrefabAutoSynchActiveScene; private GameObject m_TestPrefabDestroyWithScene; private Scene m_OriginalActiveScene; - private bool m_ClientsLoadedScene; - private bool m_ClientsUnloadedScene; - private Scene m_SceneLoaded; private List m_ServerSpawnedPrefabInstances = new List(); private List m_ServerSpawnedDestroyWithSceneInstances = new List(); - private List m_ScenesLoaded = new List(); - private string m_CurrentSceneLoading; - private string m_CurrentSceneUnloading; + private readonly List m_ScenesLoaded = new List(); + public NetworkObjectSceneMigrationTests(HostOrServer hostOrServer) : base(hostOrServer) { } + + // TODO: [MTT-15430] Fix automatic scene object migration between clients + protected override bool UseCMBService() + { + return false; + } protected override IEnumerator OnSetup() { @@ -41,106 +47,70 @@ protected override IEnumerator OnSetup() return base.OnSetup(); } + protected override void OnCreatePlayerPrefab() + { + Object.DontDestroyOnLoad(m_PlayerPrefab); + m_PlayerPrefab.GetComponent().ActiveSceneSynchronization = true; + base.OnCreatePlayerPrefab(); + } + protected override void OnServerAndClientsCreated() { // Synchronize Scene Changes (default) Test Network Prefab m_TestPrefab = CreateNetworkObjectPrefab("TestObject"); + m_TestPrefab.AddComponent(); // Auto Synchronize Active Scene Changes Test Network Prefab - m_TestPrefabAutoSynchActiveScene = CreateNetworkObjectPrefab("ASASObject"); + m_TestPrefabAutoSynchActiveScene = CreateNetworkObjectPrefab("ActiveSceneSynchronizationObject"); m_TestPrefabAutoSynchActiveScene.GetComponent().ActiveSceneSynchronization = true; + m_TestPrefabAutoSynchActiveScene.AddComponent(); // Destroy With Scene Test Network Prefab - m_TestPrefabDestroyWithScene = CreateNetworkObjectPrefab("DWSObject"); + m_TestPrefabDestroyWithScene = CreateNetworkObjectPrefab("DestroyWithSceneObject"); m_TestPrefabDestroyWithScene.AddComponent(); + m_TestPrefabDestroyWithScene.AddComponent(); - DestroyWithSceneInstancesTestHelper.ShouldNeverSpawn = m_TestPrefabDestroyWithScene; + var neverSpawnObj = CreateNetworkObjectPrefab("ShouldNeverSpawn"); + var shouldNeverSpawn = neverSpawnObj.AddComponent(); + DestroyWithSceneInstancesTestHelper.ShouldNeverSpawn = shouldNeverSpawn; + + var authority = GetAuthorityNetworkManager(); + authority.OnServerStarted += OnServerStarted; base.OnServerAndClientsCreated(); } - private bool DidClientsSpawnInstance(NetworkObject serverObject, bool checkDestroyWithScene = false) - { - foreach (var networkManager in m_ClientNetworkManagers) - { - if (!s_GlobalNetworkObjects.ContainsKey(networkManager.LocalClientId)) - { - return false; - } - var clientNetworkObjects = s_GlobalNetworkObjects[networkManager.LocalClientId]; - if (!clientNetworkObjects.ContainsKey(serverObject.NetworkObjectId)) - { - return false; - } - - if (checkDestroyWithScene) - { - if (serverObject.DestroyWithScene != clientNetworkObjects[serverObject.NetworkObjectId]) - { - return false; - } - } - } - return true; - } - private bool VerifyAllClientsSpawnedInstances() + private void OnServerStarted() { - foreach (var serverObject in m_ServerSpawnedPrefabInstances) - { - if (!DidClientsSpawnInstance(serverObject)) - { - return false; - } - } - - foreach (var serverObject in m_ServerSpawnedDestroyWithSceneInstances) - { - if (!DidClientsSpawnInstance(serverObject, true)) - { - return false; - } - } - - return true; + var authority = GetAuthorityNetworkManager(); + authority.OnServerStarted -= OnServerStarted; + authority.SceneManager.ActiveSceneSynchronizationEnabled = true; } - private bool AreClientInstancesInTheRightScene(NetworkObject serverObject) + private bool VerifyAllScenesMatch(StringBuilder errorLog, List authorityInstances) { - foreach (var networkManager in m_ClientNetworkManagers) + foreach (var authorityInstance in authorityInstances) { - var clientNetworkObjects = s_GlobalNetworkObjects[networkManager.LocalClientId]; - if (clientNetworkObjects == null) - { - continue; - } - // If a networkObject is null then it was destroyed - if (clientNetworkObjects[serverObject.NetworkObjectId].gameObject.scene.name != serverObject.gameObject.scene.name) + foreach (var networkManager in m_NetworkManagers) { - return false; - } - } - return true; - } + if (!networkManager.SpawnManager.SpawnedObjects.TryGetValue(authorityInstance.NetworkObjectId, out var instance)) + { + errorLog.AppendLine($"[{authorityInstance.name}] Client-{networkManager.LocalClientId} doesn't have a local version of network object {authorityInstance.name} with id {authorityInstance.NetworkObjectId}"); + return false; + } - private bool VerifySpawnedObjectsMigrated() - { - foreach (var serverObject in m_ServerSpawnedPrefabInstances) - { - if (!AreClientInstancesInTheRightScene(serverObject)) - { - return false; - } - } + if (instance.gameObject.scene.name != authorityInstance.gameObject.scene.name) + { + errorLog.AppendLine($"[{instance.name}] NetworkObject-{authorityInstance.NetworkObjectId} is in the wrong scene! Expected: {authorityInstance.gameObject.scene.name}, Actual: {instance.gameObject.scene.name}"); + return false; + } - foreach (var serverObject in m_ServerSpawnedDestroyWithSceneInstances) - { - if (!AreClientInstancesInTheRightScene(serverObject)) - { - return false; + // The SceneOrigin should never change + var originalSceneTracker = instance.GetComponent(); + Assert.AreEqual(originalSceneTracker.SceneWhereAwakeHappened, (NetworkSceneHandle)instance.SceneOrigin.handle, "The SceneOrigin of an object should never change!"); } } - return true; } @@ -154,28 +124,31 @@ private bool VerifySpawnedObjectsMigrated() [UnityTest] public IEnumerator MigrateIntoNewSceneTest() { + var authority = GetAuthorityNetworkManager(); + + var authoritySpawnedInstances = new List(); // Spawn 9 NetworkObject instances for (int i = 0; i < k_MaxObjectsToSpawn; i++) { - var serverInstance = Object.Instantiate(m_TestPrefab); - var serverNetworkObject = serverInstance.GetComponent(); - serverNetworkObject.Spawn(); - m_ServerSpawnedPrefabInstances.Add(serverNetworkObject); + var instance = SpawnObject(m_TestPrefab, authority); + var spawnedObject = instance.GetComponent(); + authoritySpawnedInstances.Add(spawnedObject); } - yield return WaitForConditionOrTimeOut(VerifyAllClientsSpawnedInstances); + + yield return WaitForSpawnedOnAllOrTimeOut(authoritySpawnedInstances); AssertOnTimeout($"Timed out waiting for all clients to spawn {nameof(NetworkObject)}s!"); // Now load three scenes to migrate the newly spawned NetworkObjects into - m_ServerNetworkManager.SceneManager.OnSceneEvent += SceneManager_OnSceneEvent; - for (int i = 0; i < 3; i++) + authority.SceneManager.OnSceneEvent += SceneManager_OnSceneEvent; + foreach (var sceneToLoad in m_TestScenes) { - m_ClientsLoadedScene = false; - m_CurrentSceneLoading = m_TestScenes[i]; - var status = m_ServerNetworkManager.SceneManager.LoadScene(m_TestScenes[i], LoadSceneMode.Additive); - Assert.True(status == SceneEventProgressStatus.Started, $"Failed to start loading scene {m_CurrentSceneLoading}! Return status: {status}"); - yield return WaitForConditionOrTimeOut(() => m_ClientsLoadedScene); - AssertOnTimeout($"Timed out waiting for all clients to load scene {m_CurrentSceneLoading}!"); + yield return LoadScene(authority, sceneToLoad); } + authority.SceneManager.OnSceneEvent -= SceneManager_OnSceneEvent; + Assert.AreEqual(m_TestScenes.Count, m_ScenesLoaded.Count, "Not all the test scenes were loaded!"); + + yield return WaitForConditionOrTimeOut(errorLog => VerifyAllScenesMatch(errorLog, authoritySpawnedInstances)); + AssertOnTimeout("[After spawn] Timed out waiting for all clients to migrate all NetworkObjects into the appropriate scenes!"); var objectCount = 0; // Migrate each networkObject into one of the three scenes. @@ -183,31 +156,32 @@ public IEnumerator MigrateIntoNewSceneTest() foreach (var scene in m_ScenesLoaded) { // Now migrate the NetworkObject - SceneManager.MoveGameObjectToScene(m_ServerSpawnedPrefabInstances[objectCount].gameObject, scene); - SceneManager.MoveGameObjectToScene(m_ServerSpawnedPrefabInstances[objectCount + 1].gameObject, scene); - SceneManager.MoveGameObjectToScene(m_ServerSpawnedPrefabInstances[objectCount + 2].gameObject, scene); + SceneManager.MoveGameObjectToScene(authoritySpawnedInstances[objectCount].gameObject, scene); + SceneManager.MoveGameObjectToScene(authoritySpawnedInstances[objectCount + 1].gameObject, scene); + SceneManager.MoveGameObjectToScene(authoritySpawnedInstances[objectCount + 2].gameObject, scene); objectCount += 3; } - yield return WaitForConditionOrTimeOut(VerifySpawnedObjectsMigrated); + yield return WaitForConditionOrTimeOut(errorLog => VerifyAllScenesMatch(errorLog, authoritySpawnedInstances)); AssertOnTimeout($"Timed out waiting for all clients to migrate all NetworkObjects into the appropriate scenes!"); // Register for the server-side client synchronization so we can send an object scene migration event at the same time // the new client begins to synchronize - m_ServerNetworkManager.SceneManager.OnSynchronize += MigrateObjects_OnSynchronize; + m_ServerSpawnedPrefabInstances = authoritySpawnedInstances; + authority.SceneManager.OnSynchronize += MigrateObjects_OnSynchronize; // Verify that a late joining client synchronizes properly even while new scene migrations occur // during its synchronization yield return CreateAndStartNewClient(); - yield return WaitForConditionOrTimeOut(VerifySpawnedObjectsMigrated); + yield return WaitForConditionOrTimeOut(errorLog => VerifyAllScenesMatch(errorLog, authoritySpawnedInstances)); AssertOnTimeout($"[Late Joined Client] Timed out waiting for all clients to migrate all NetworkObjects into the appropriate scenes!"); // Verify that a late joining client synchronizes properly even if we migrate // during its synchronization and despawn some of the NetworkObjects migrated. - m_ServerNetworkManager.SceneManager.OnSynchronize += MigrateAndDespawnObjects_OnSynchronize; + authority.SceneManager.OnSynchronize += MigrateAndDespawnObjects_OnSynchronize; yield return CreateAndStartNewClient(); - yield return WaitForConditionOrTimeOut(VerifySpawnedObjectsMigrated); + yield return WaitForConditionOrTimeOut(errorLog => VerifyAllScenesMatch(errorLog, authoritySpawnedInstances)); AssertOnTimeout($"[Late Joined Client] Timed out waiting for all clients to migrate all NetworkObjects into the appropriate scenes!"); } @@ -219,19 +193,27 @@ public IEnumerator MigrateIntoNewSceneTest() /// private void MigrateAndDespawnObjects_OnSynchronize(ulong clientId) { - var objectCount = 0; + var authority = GetAuthorityNetworkManager(); // Migrate the NetworkObjects into different scenes than they originally were migrated into for (int i = m_ServerSpawnedPrefabInstances.Count - 1; i >= 0; i--) { var scene = m_ScenesLoaded[i % m_ScenesLoaded.Count]; - SceneManager.MoveGameObjectToScene(m_ServerSpawnedPrefabInstances[i].gameObject, scene); + var obj = m_ServerSpawnedPrefabInstances[i]; + if (m_DistributedAuthority) + { + // When the new client joins, authority will be distributed. + // Ensure we have the authority instance. + obj = GetAuthorityInstance(obj); + } + SceneManager.MoveGameObjectToScene(obj.gameObject, scene); // De-spawn every-other object if (i % 2 == 0) { - m_ServerSpawnedPrefabInstances[objectCount + i].Despawn(); + obj.Despawn(); m_ServerSpawnedPrefabInstances.RemoveAt(i); } } + authority.SceneManager.OnSynchronize -= MigrateObjects_OnSynchronize; } /// @@ -252,7 +234,24 @@ private void MigrateObjects_OnSynchronize(ulong clientId) } // Unsubscribe to this event for this part of the test - m_ServerNetworkManager.SceneManager.OnSynchronize -= MigrateObjects_OnSynchronize; + GetAuthorityNetworkManager().SceneManager.OnSynchronize -= MigrateObjects_OnSynchronize; + } + + protected override void OnNewClientCreated(NetworkManager networkManager) + { + var authority = GetAuthorityNetworkManager(); + foreach (var prefab in authority.NetworkConfig.Prefabs.Prefabs) + { + networkManager.NetworkConfig.Prefabs.Add(prefab); + } + networkManager.NetworkConfig.PlayerPrefab = m_PlayerPrefab; + base.OnNewClientCreated(networkManager); + } + + private void SetActiveScene(Scene scene) + { + Debug.Log($"[Previous = {SceneManager.GetActiveScene().name}][New = {scene.name}] Changing the active scene!"); + SceneManager.SetActiveScene(scene); } /// @@ -263,36 +262,47 @@ private void MigrateObjects_OnSynchronize(ulong clientId) [UnityTest] public IEnumerator ActiveSceneSynchronizationTest() { + var authority = GetAuthorityNetworkManager(); // Disable resynchronization for this test to avoid issues with trying // to synchronize them. NetworkSceneManager.DisableReSynchronization = true; + // Load three scenes first + authority.SceneManager.OnSceneEvent += SceneManager_OnSceneEvent; + foreach (var sceneName in m_TestScenes) + { + yield return LoadScene(authority, sceneName); + } + authority.SceneManager.OnSceneEvent -= SceneManager_OnSceneEvent; + + // Set the active scene to be the 1st scene loaded so we don't instantiate within the test runner scene. + SetActiveScene(m_ScenesLoaded[0]); + + var autoSyncActive = new List(); // Spawn 3 NetworkObject instances that auto synchronize to active scene changes for (int i = 0; i < 3; i++) { - var serverInstance = Object.Instantiate(m_TestPrefabAutoSynchActiveScene); - var serverNetworkObject = serverInstance.GetComponent(); // We are also testing that objects marked to synchronize with changes to // the active scene and marked to destroy with scene =are destroyed= if // the scene being unloaded is currently the active scene and the scene that // the NetworkObjects reside within. - serverNetworkObject.Spawn(true); - m_ServerSpawnedPrefabInstances.Add(serverNetworkObject); + var serverInstance = SpawnObject(m_TestPrefabAutoSynchActiveScene, authority, true); + var serverNetworkObject = serverInstance.GetComponent(); + autoSyncActive.Add(serverNetworkObject); } - // Spawn 3 NetworkObject instances that do not auto synchronize to active scene changes // and ==should not be== destroyed with the scene (these should be the only remaining // instances) + var autoSyncInactive = new List(); for (int i = 0; i < 3; i++) { - var serverInstance = Object.Instantiate(m_TestPrefab); - var serverNetworkObject = serverInstance.GetComponent(); // This set of NetworkObjects will be used to verify that NetworkObjets // spawned with DestroyWithScene set to false will migrate into the current // active scene if the scene they currently reside within is destroyed and // is not the currently active scene. - serverNetworkObject.Spawn(); - m_ServerSpawnedPrefabInstances.Add(serverNetworkObject); + var serverInstance = SpawnObject(m_TestPrefab, authority); + var serverNetworkObject = serverInstance.GetComponent(); + autoSyncInactive.Add(serverNetworkObject); } // Spawn 3 NetworkObject instances that do not auto synchronize to active scene changes @@ -307,104 +317,90 @@ public IEnumerator ActiveSceneSynchronizationTest() serverNetworkObject.Spawn(true); m_ServerSpawnedDestroyWithSceneInstances.Add(serverNetworkObject); } + var authoritySpawnedInstances = new List(); + authoritySpawnedInstances.AddRange(autoSyncActive); + authoritySpawnedInstances.AddRange(autoSyncInactive); + authoritySpawnedInstances.AddRange(m_ServerSpawnedDestroyWithSceneInstances); - yield return WaitForConditionOrTimeOut(VerifyAllClientsSpawnedInstances); + yield return WaitForSpawnedOnAllOrTimeOut(authoritySpawnedInstances); AssertOnTimeout($"Timed out waiting for all clients to spawn {nameof(NetworkObject)}s!"); - // Now load three scenes - m_ServerNetworkManager.SceneManager.OnSceneEvent += SceneManager_OnSceneEvent; - for (int i = 0; i < 3; i++) - { - m_ClientsLoadedScene = false; - m_CurrentSceneLoading = m_TestScenes[i]; - var loadStatus = m_ServerNetworkManager.SceneManager.LoadScene(m_TestScenes[i], LoadSceneMode.Additive); - Assert.True(loadStatus == SceneEventProgressStatus.Started, $"Failed to start loading scene {m_CurrentSceneLoading}! Return status: {loadStatus}"); - yield return WaitForConditionOrTimeOut(() => m_ClientsLoadedScene); - AssertOnTimeout($"Timed out waiting for all clients to load scene {m_CurrentSceneLoading}!"); - } - + var sceneToMigrateTo = m_ScenesLoaded[2]; // Migrate the instances that don't synchronize with active scene changes into the 3rd loaded scene // (We are making sure these stay in the same scene they are migrated into) - for (int i = 3; i < m_ServerSpawnedPrefabInstances.Count; i++) + foreach (var spawnedObject in autoSyncInactive) { - SceneManager.MoveGameObjectToScene(m_ServerSpawnedPrefabInstances[i].gameObject, m_ScenesLoaded[2]); + SceneManager.MoveGameObjectToScene(spawnedObject.gameObject, sceneToMigrateTo); } // Migrate the instances that don't synchronize with active scene changes and are destroyed with the // scene unloading into the 3rd loaded scene // (We are making sure these get destroyed when the scene is unloaded) - for (int i = 0; i < m_ServerSpawnedDestroyWithSceneInstances.Count; i++) + foreach (var spawnedObject in m_ServerSpawnedDestroyWithSceneInstances) { - SceneManager.MoveGameObjectToScene(m_ServerSpawnedDestroyWithSceneInstances[i].gameObject, m_ScenesLoaded[2]); + SceneManager.MoveGameObjectToScene(spawnedObject.gameObject, sceneToMigrateTo); } // Make sure they migrated to the proper scene - yield return WaitForConditionOrTimeOut(VerifySpawnedObjectsMigrated); + yield return WaitForConditionOrTimeOut(errorLog => VerifyAllScenesMatch(errorLog, authoritySpawnedInstances)); AssertOnTimeout($"Timed out waiting for all clients to migrate all NetworkObjects into the appropriate scenes!"); // Now change the active scene - SceneManager.SetActiveScene(m_ScenesLoaded[1]); - // We have to do this - Object.DontDestroyOnLoad(m_TestPrefabAutoSynchActiveScene); + var newActiveScene = m_ScenesLoaded[1]; + SetActiveScene(newActiveScene); // First, make sure server-side scenes and client side scenes match - yield return WaitForConditionOrTimeOut(VerifySpawnedObjectsMigrated); + yield return WaitForConditionOrTimeOut(errorLog => VerifyAllScenesMatch(errorLog, authoritySpawnedInstances)); AssertOnTimeout($"Timed out waiting for all clients to migrate all NetworkObjects into the appropriate scenes!"); // Verify that the auto-active-scene synchronization NetworkObjects migrated to the newly // assigned active scene - for (int i = 0; i < 3; i++) + foreach (var obj in autoSyncActive) { - Assert.True(m_ServerSpawnedPrefabInstances[i].gameObject.scene == m_ScenesLoaded[1], - $"{m_ServerSpawnedPrefabInstances[i].gameObject.name} did not migrate into scene {m_ScenesLoaded[1].name}!"); + Assert.AreEqual(newActiveScene, obj.gameObject.scene, $"{obj.gameObject.name} did not migrate into scene {newActiveScene.name}!"); } // Verify that the other NetworkObjects that don't synchronize with active scene changes did // not migrate into the active scene. - for (int i = 3; i < m_ServerSpawnedPrefabInstances.Count; i++) + foreach (var obj in autoSyncInactive) { - Assert.False(m_ServerSpawnedPrefabInstances[i].gameObject.scene == m_ScenesLoaded[1], - $"{m_ServerSpawnedPrefabInstances[i].gameObject.name} migrated into scene {m_ScenesLoaded[1].name}!"); + Assert.AreNotEqual(newActiveScene, obj.gameObject.scene, $"{obj.gameObject.name} migrated into scene {newActiveScene.name}!"); } - for (int i = 0; i < 3; i++) + foreach (var obj in m_ServerSpawnedDestroyWithSceneInstances) { - Assert.False(m_ServerSpawnedDestroyWithSceneInstances[i].gameObject.scene == m_ScenesLoaded[1], - $"{m_ServerSpawnedDestroyWithSceneInstances[i].gameObject.name} migrated into scene {m_ScenesLoaded[1].name}!"); + Assert.AreNotEqual(newActiveScene, obj.gameObject.scene, $"{obj.gameObject.name} migrated into scene {newActiveScene.name}!"); } // Verify that a late joining client synchronizes properly and destroys the appropriate NetworkObjects yield return CreateAndStartNewClient(); - yield return WaitForConditionOrTimeOut(VerifySpawnedObjectsMigrated); + AssertOnTimeout("Failed to start or create a new client!"); + yield return WaitForConditionOrTimeOut(errorLog => VerifyAllScenesMatch(errorLog, authoritySpawnedInstances)); AssertOnTimeout($"[Late Joined Client #1] Timed out waiting for all clients to migrate all NetworkObjects into the appropriate scenes!"); // Now, unload the scene containing the NetworkObjects that don't synchronize with active scene changes DestroyWithSceneInstancesTestHelper.NetworkObjectDestroyed += OnNonActiveSynchDestroyWithSceneNetworkObjectDestroyed; - m_ClientsUnloadedScene = false; - m_CurrentSceneUnloading = m_ScenesLoaded[2].name; - var status = m_ServerNetworkManager.SceneManager.UnloadScene(m_ScenesLoaded[2]); - Assert.True(status == SceneEventProgressStatus.Started, $"Failed to start unloading scene {m_ScenesLoaded[2].name} with status {status}!"); - yield return WaitForConditionOrTimeOut(() => m_ClientsUnloadedScene); + + yield return UnloadScene(authority, sceneToMigrateTo); // Clean up any destroyed NetworkObjects - for (int i = m_ServerSpawnedPrefabInstances.Count - 1; i >= 0; i--) + for (int i = authoritySpawnedInstances.Count - 1; i >= 0; i--) { - if (m_ServerSpawnedPrefabInstances[i] == null) + if (authoritySpawnedInstances[i] == null) { - m_ServerSpawnedPrefabInstances.RemoveAt(i); + authoritySpawnedInstances.RemoveAt(i); } } - AssertOnTimeout($"Timed out waiting for all clients to unload scene {m_CurrentSceneUnloading}!"); - yield return WaitForConditionOrTimeOut(VerifySpawnedObjectsMigrated); + AssertOnTimeout($"Timed out waiting for all clients to unload scene {sceneToMigrateTo.name}!"); + yield return WaitForConditionOrTimeOut(errorLog => VerifyAllScenesMatch(errorLog, authoritySpawnedInstances)); AssertOnTimeout($"Timed out waiting for all clients to migrate all NetworkObjects into the appropriate scenes!"); // Verify that the NetworkObjects that don't synchronize with active scene changes but marked to not // destroy with the scene are migrated into the current active scene - for (int i = 3; i < m_ServerSpawnedPrefabInstances.Count; i++) + foreach (var obj in autoSyncInactive) { - Assert.True(m_ServerSpawnedPrefabInstances[i].gameObject.scene == m_ScenesLoaded[1], - $"{m_ServerSpawnedPrefabInstances[i].gameObject.name} did not migrate into scene {m_ScenesLoaded[1].name} but are in scene {m_ServerSpawnedPrefabInstances[i].gameObject.scene.name}!"); + Assert.True(obj.gameObject.scene == newActiveScene, $"{obj.gameObject.name} did not migrate into scene {newActiveScene.name} but are in scene {obj.gameObject.scene.name}!"); } // Verify all NetworkObjects that should have been destroyed with the scene unloaded were destroyed @@ -414,18 +410,14 @@ public IEnumerator ActiveSceneSynchronizationTest() // Now unload the active scene to verify all remaining NetworkObjects are migrated into the SceneManager // assigned active scene - m_ClientsUnloadedScene = false; - m_CurrentSceneUnloading = m_ScenesLoaded[1].name; - m_ServerNetworkManager.SceneManager.UnloadScene(m_ScenesLoaded[1]); - yield return WaitForConditionOrTimeOut(() => m_ClientsUnloadedScene); - AssertOnTimeout($"Timed out waiting for all clients to unload scene {m_CurrentSceneUnloading}!"); + yield return UnloadScene(authority, newActiveScene); // Clean up any destroyed NetworkObjects - for (int i = m_ServerSpawnedPrefabInstances.Count - 1; i >= 0; i--) + for (int i = authoritySpawnedInstances.Count - 1; i >= 0; i--) { - if (m_ServerSpawnedPrefabInstances[i] == null) + if (authoritySpawnedInstances[i] == null) { - m_ServerSpawnedPrefabInstances.RemoveAt(i); + authoritySpawnedInstances.RemoveAt(i); } } @@ -433,22 +425,63 @@ public IEnumerator ActiveSceneSynchronizationTest() yield return CreateAndStartNewClient(); // Verify the late joining client spawns all instances - yield return WaitForConditionOrTimeOut(VerifyAllClientsSpawnedInstances); - AssertOnTimeout($"Timed out waiting for all clients to spawn {nameof(NetworkObject)}s!"); + yield return WaitForSpawnedOnAllOrTimeOut(authoritySpawnedInstances); + AssertOnTimeout($"[Late Joined Client #2] Timed out waiting for all clients to spawn {nameof(NetworkObject)}s!"); // Verify the instances are in the correct scenes - yield return WaitForConditionOrTimeOut(VerifySpawnedObjectsMigrated); + yield return WaitForConditionOrTimeOut(errorLog => VerifyAllScenesMatch(errorLog, authoritySpawnedInstances)); AssertOnTimeout($"[Late Joined Client #2] Timed out waiting for all clients to migrate all NetworkObjects into the appropriate scenes!"); // All but 3 instances should be destroyed - Assert.True(m_ServerSpawnedPrefabInstances.Count == 3, $"{nameof(m_ServerSpawnedPrefabInstances)} still has a count of {m_ServerSpawnedPrefabInstances.Count} " + - $"NetworkObject instances!"); - Assert.True(m_ServerSpawnedDestroyWithSceneInstances.Count == 0, $"{nameof(m_ServerSpawnedDestroyWithSceneInstances)} still has a count of " + - $"{m_ServerSpawnedDestroyWithSceneInstances.Count} NetworkObject instances!"); - for (int i = 0; i < 3; i++) - { - Assert.True(m_ServerSpawnedPrefabInstances[i].gameObject.name.Contains(m_TestPrefab.gameObject.name), $"Expected {m_ServerSpawnedPrefabInstances[i].gameObject.name} to contain {m_TestPrefab.gameObject.name}!"); - } + Assert.IsEmpty(autoSyncActive.Where(obj => obj != null), $"All the NetworkObjects with {nameof(NetworkObject.ActiveSceneSynchronization)}=true should have been destroyed when the active scene was unloaded!"); + Assert.IsEmpty(m_ServerSpawnedDestroyWithSceneInstances.Where(obj => obj != null), $"All the NetworkObjects with {nameof(NetworkObject.DestroyWithScene)} should have been destroyed when the active scene was unloaded!"); + Assert.AreEqual(3, autoSyncInactive.Count(obj => obj != null), $"All the NetworkObjects with {nameof(NetworkObject.ActiveSceneSynchronization)}=false should have survived the active scene change!"); + } + + /// + /// Helper method to load a scene and wait for the OnLoadEventCompleted event to trigger. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private IEnumerator LoadScene(NetworkManager authority, string sceneToLoad) + { + m_LoadEventCompleted = false; + authority.SceneManager.OnLoadEventCompleted += OnLoadEventCompleted; + var loadStatus = authority.SceneManager.LoadScene(sceneToLoad, LoadSceneMode.Additive); + Assert.True(loadStatus == SceneEventProgressStatus.Started, $"Failed to start loading scene {sceneToLoad}! Return status: {loadStatus}"); + yield return WaitForConditionOrTimeOut(() => m_LoadEventCompleted); + // Remove subscription prior to potentially asserting. + authority.SceneManager.OnLoadEventCompleted -= OnLoadEventCompleted; + AssertOnTimeout($"Timed out waiting for all clients to load scene {sceneToLoad}!"); + } + + /// + /// Helper method to load a scene and wait for the OnUnloadEventCompleted event to trigger. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private IEnumerator UnloadScene(NetworkManager authority, Scene sceneToUnload) + { + m_UnloadEventCompleted = false; + authority.SceneManager.OnUnloadEventCompleted += OnUnloadEventCompleted; + authority.SceneManager.UnloadScene(sceneToUnload); + + // Always make sure the scene event has completed. Trying to check if the scenes are loaded as a metric can + // create edge case scenarios where the scene might have been just loaded but not processed during synchronization. + yield return WaitForConditionOrTimeOut(() => m_UnloadEventCompleted); + // Remove subscription prior to potentially asserting. + authority.SceneManager.OnUnloadEventCompleted -= OnUnloadEventCompleted; + AssertOnTimeout($"Timed out waiting for all clients to unload scene {sceneToUnload.name}!"); + } + + private bool m_LoadEventCompleted; + private void OnLoadEventCompleted(string sceneName, LoadSceneMode loadSceneMode, List clientsCompleted, List clientsTimedOut) + { + m_LoadEventCompleted = true; + } + + private bool m_UnloadEventCompleted; + private void OnUnloadEventCompleted(string sceneName, LoadSceneMode loadSceneMode, List clientsCompleted, List clientsTimedOut) + { + m_UnloadEventCompleted = true; } /// @@ -462,30 +495,16 @@ private void OnNonActiveSynchDestroyWithSceneNetworkObjectDestroyed(NetworkObjec private void SceneManager_OnSceneEvent(SceneEvent sceneEvent) { + var authority = GetAuthorityNetworkManager(); switch (sceneEvent.SceneEventType) { case SceneEventType.LoadComplete: { - if (sceneEvent.ClientId == m_ServerNetworkManager.LocalClientId) + if (sceneEvent.ClientId == authority.LocalClientId) { - m_SceneLoaded = sceneEvent.Scene; m_ScenesLoaded.Add(sceneEvent.Scene); } - break; - } - case SceneEventType.LoadEventCompleted: - { - Assert.IsTrue(sceneEvent.ClientsThatTimedOut.Count == 0, $"{sceneEvent.ClientsThatTimedOut.Count} clients timed out while trying to load scene {m_CurrentSceneLoading}!"); - m_ClientsLoadedScene = true; - break; - } - case SceneEventType.UnloadEventCompleted: - { - if (sceneEvent.SceneName == m_CurrentSceneUnloading) - { - m_ClientsUnloadedScene = true; - } - break; + return; } } } @@ -495,12 +514,51 @@ protected override IEnumerator OnTearDown() m_TestPrefab = null; m_TestPrefabAutoSynchActiveScene = null; m_TestPrefabDestroyWithScene = null; + // Any static event that could be subscribed to but not unsubscribed to due to an assert needs to be cleaned up here. + DestroyWithSceneInstancesTestHelper.NetworkObjectDestroyed -= OnNonActiveSynchDestroyWithSceneNetworkObjectDestroyed; SceneManager.SetActiveScene(m_OriginalActiveScene); m_ServerSpawnedDestroyWithSceneInstances.Clear(); m_ServerSpawnedPrefabInstances.Clear(); m_ScenesLoaded.Clear(); yield return base.OnTearDown(); } + + private NetworkObject GetAuthorityInstance(NetworkObject instance) + { + if (instance.IsOwner) + { + return instance; + } + + var owner = instance.OwnerClientId; + foreach (var networkManager in m_NetworkManagers) + { + if (networkManager.LocalClientId == owner) + { + networkManager.SpawnManager.SpawnedObjects.TryGetValue(instance.NetworkObjectId, out var networkObject); + return networkObject; + } + } + + return null; + } + } + + internal class SceneOriginTracker : NetworkBehaviour + { + public NetworkSceneHandle SceneWhereAwakeHappened; + private void Awake() + { + SceneWhereAwakeHappened = gameObject.scene.handle; + } + } + + internal class ShouldNeverSpawn : NetworkBehaviour + { + public override void OnNetworkSpawn() + { + Assert.Fail("Should never spawn!"); + } } /// @@ -509,7 +567,7 @@ protected override IEnumerator OnTearDown() /// internal class DestroyWithSceneInstancesTestHelper : NetworkBehaviour { - public static GameObject ShouldNeverSpawn; + public static ShouldNeverSpawn ShouldNeverSpawn; public static Dictionary> ObjectRelativeInstances = new Dictionary>(); @@ -544,12 +602,9 @@ public override void OnNetworkDespawn() public override void OnDestroy() { - if (NetworkManager != null) + if (IsSpawned && HasAuthority) { - if (NetworkManager.LocalClientId == NetworkManager.ServerClientId) - { - NetworkObjectDestroyed?.Invoke(NetworkObject); - } + NetworkObjectDestroyed?.Invoke(NetworkObject); } base.OnDestroy(); } diff --git a/testproject/Assets/Tests/Runtime/NetworkSceneManager/NetworkSceneManagerStartupTests.cs b/testproject/Assets/Tests/Runtime/NetworkSceneManager/NetworkSceneManagerStartupTests.cs new file mode 100644 index 0000000000..28cd0b49d2 --- /dev/null +++ b/testproject/Assets/Tests/Runtime/NetworkSceneManager/NetworkSceneManagerStartupTests.cs @@ -0,0 +1,205 @@ +using System.Collections; +using System.Collections.Generic; +using NUnit.Framework; +using Unity.Netcode; +using Unity.Netcode.TestHelpers.Runtime; +using UnityEngine; +using UnityEngine.SceneManagement; +using UnityEngine.TestTools; + +namespace TestProject.RuntimeTests +{ + /// + /// Validates client synchronization. + /// + /// + /// This includes both client synchronization mode passes along with verifying + /// that s migrated into the DDOL will still be spawned + /// and preserve their value. + /// + internal class NetworkSceneManagerStartupTests : NetcodeIntegrationTest + { + private const string k_ActiveScene = "SessionSynchronize"; + private const string k_AdditionalScene = "InSceneNetworkObjectMovesToDDOL"; + + private readonly List m_ObjectsInScenes = new List(); + private Scene m_OriginalActiveScene; + private Scene m_SceneLoaded; + private bool m_CanStart = false; + + // Used with scene pre-loading + private string m_SceneToLoad; + private bool m_SceneWasLoaded; + + #region NetcodeIntegrationTest overrides + protected override int NumberOfClients => 0; + protected override bool CanStartServerAndClients() => m_CanStart; + + protected override void OnOneTimeSetup() + { + // Get the active scene prior to any interation running through the OnSetup. + m_OriginalActiveScene = SceneManager.GetActiveScene(); + base.OnOneTimeSetup(); + } + + protected override IEnumerator OnSetup() + { + // Always reset + m_CanStart = false; + return base.OnSetup(); + } + + protected override void OnCreatePlayerPrefab() + { + // Avoid trying to spawn this + Object.DontDestroyOnLoad(m_PlayerPrefab); + base.OnCreatePlayerPrefab(); + } + + protected override IEnumerator OnTearDown() + { + LogAssert.ignoreFailingMessages = false; + m_ObjectsInScenes.Clear(); + // Restore the integration test scene as the active scene. + SceneManager.SetActiveScene(m_OriginalActiveScene); + + // Unload everything else. + for (int i = 0; i < SceneManager.sceneCount - 1; i++) + { + var scene = SceneManager.GetSceneAt(i); + if (scene == m_OriginalActiveScene) + { + continue; + } + SceneManager.UnloadSceneAsync(scene); + yield return WaitForConditionOrTimeOut(() => !scene.isLoaded); + } + yield return base.OnTearDown(); + } + #endregion + + /// + /// Validates things migrated into the DDOL will be included when synchronizing clients. + /// + /// The client synchronization mode to use for the current pass. + [UnityTest] + public IEnumerator AllExistingObjectsAreSpawnedAtStartup([Values] LoadSceneMode clientSynchronizationMode) + { + LogAssert.ignoreFailingMessages = true; + yield return PreLoadScene(k_ActiveScene); + yield return PreLoadScene(k_AdditionalScene); + SceneManager.SetActiveScene(m_SceneLoaded); + + var existingObjects = new List(); + var dontDestroyOnLoadCount = 0; + + // Now get everything migrated into the DDOL and the DDOL scene itself. + var ddolScene = GetNetworkObjectsInDDOL(); + // Validate NetworkObjects in DDOL + foreach (var obj in m_ObjectsInScenes) + { + Assert.IsFalse(obj.IsSpawned, $"NetworkObject {obj.name} should not have been spawned!"); + + existingObjects.Add(obj); + if (obj.gameObject.scene.name == ddolScene.name) + { + dontDestroyOnLoadCount++; + } + } + + Assert.IsNotEmpty(existingObjects, $"Found no existing {nameof(NetworkObject)}s!"); + Assert.That(dontDestroyOnLoadCount, Is.GreaterThan(0), "Found no {nameof(NetworkObject)}s in the DDOL scene!"); + + // Now enable starting server and clients and start the server + m_CanStart = true; + yield return StartServerAndClients(); + + // Apply the test's client synchronization mode + GetAuthorityNetworkManager().SceneManager.SetClientSynchronizationMode(clientSynchronizationMode); + + // Validate the existing objects + foreach (var existingObject in existingObjects) + { + Assert.IsFalse(existingObject == null, "Expected existing object to still exist!"); + Assert.IsTrue(existingObject.IsSpawned, $"NetworkObject {existingObject.name} in scene {existingObject.gameObject.scene.name} was not spawned!"); + Assert.IsTrue(existingObject.InScenePlaced, $"NetworkObject {existingObject.name} in scene {existingObject.gameObject.scene.name} was not inScenePlaced!"); + } + + // If additive client synchronization mode, load the scenes that are already loaded + // on the scene authority instance so they will be used during client synchronization. + if (clientSynchronizationMode == LoadSceneMode.Additive) + { + yield return PreLoadScene(k_ActiveScene); + yield return PreLoadScene(k_AdditionalScene); + } + + // Late join a client + yield return CreateAndStartNewClient(); + + // Wait for all existing objects to spawn on the client + yield return WaitForSpawnedOnAllOrTimeOut(existingObjects); + AssertOnTimeout("Timed out waiting for objects to spawn on all clients!"); + } + + #region Scene loading and related methods + + /// + /// Uses the 's current scene which should be + /// the DDOL scene. + /// + /// The DDOL scene + private Scene GetNetworkObjectsInDDOL() + { + // This does catch any newly instantiated in-scene placed NetworkObjects moved into DDOL + // during awake. + var sceneToUse = NetworkManager.Singleton.gameObject.scene; + Assert.IsTrue(sceneToUse.IsValid() && sceneToUse.name == "DontDestroyOnLoad", $"[{NetworkManager.Singleton.name}] Is not in the DDOL! Is this being invoked too early?"); + + foreach (var rootObject in sceneToUse.GetRootGameObjects()) + { + foreach (var networkObject in rootObject.GetComponentsInChildren()) + { + if (!m_ObjectsInScenes.Contains(networkObject) && networkObject.InScenePlaced) + { + m_ObjectsInScenes.Add(networkObject); + } + } + } + return sceneToUse; + } + + private IEnumerator PreLoadScene(string sceneName) + { + m_SceneToLoad = sceneName; + m_SceneWasLoaded = false; + SceneManager.sceneLoaded += OnSceneLoad; + SceneManager.LoadScene(sceneName, LoadSceneMode.Additive); + yield return WaitForConditionOrTimeOut(() => m_SceneWasLoaded); + AssertOnTimeout("Timed out waiting for scene to load!"); + SceneManager.sceneLoaded -= OnSceneLoad; + } + + private void TrackObjectsInScene(Scene scene) + { + // This does not catch things moved into the DDOL during awake. + foreach (var rootObject in scene.GetRootGameObjects()) + { + foreach (var networkObject in rootObject.GetComponentsInChildren()) + { + m_ObjectsInScenes.Add(networkObject); + } + } + } + + private void OnSceneLoad(Scene scene, LoadSceneMode loadSceneMode) + { + if (m_SceneToLoad == scene.name) + { + m_SceneWasLoaded = true; + m_SceneLoaded = scene; + TrackObjectsInScene(scene); + } + } + #endregion + } +} diff --git a/testproject/Assets/Tests/Runtime/NetworkSceneManager/NetworkSceneManagerStartupTests.cs.meta b/testproject/Assets/Tests/Runtime/NetworkSceneManager/NetworkSceneManagerStartupTests.cs.meta new file mode 100644 index 0000000000..ddf1a7550e --- /dev/null +++ b/testproject/Assets/Tests/Runtime/NetworkSceneManager/NetworkSceneManagerStartupTests.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: ca8e58d04b6fc6c48a6661c90d4c12dd \ No newline at end of file diff --git a/testproject/Assets/Tests/Runtime/PrefabExtendedTests.cs b/testproject/Assets/Tests/Runtime/PrefabExtendedTests.cs index 909bb7585d..e22d924bac 100644 --- a/testproject/Assets/Tests/Runtime/PrefabExtendedTests.cs +++ b/testproject/Assets/Tests/Runtime/PrefabExtendedTests.cs @@ -1,6 +1,5 @@ using System.Collections; using System.Collections.Generic; -using System.Linq; using System.Text; using NUnit.Framework; using TestProject.ManualTests; @@ -213,9 +212,6 @@ public enum InstantiateAndSpawnMethods [UnityTest] public IEnumerator TestPrefabsSpawning([Values] InstantiateAndSpawnMethods instantiateAndSpawnType) { - var gloabalObjectId = m_SceneManagementEnabled ? 0 : InScenePlacedHelper.ServerInSceneDefined.First().GlobalObjectIdHash; - var firstError = $"[Netcode] Failed to create object locally. [globalObjectIdHash={gloabalObjectId}]. NetworkPrefab could not be found. Is the prefab registered with NetworkManager?"; - var secondError = $"[Netcode] Failed to spawn NetworkObject for Hash {gloabalObjectId}."; m_InstantiateAndSpawnType = instantiateAndSpawnType; // We have to spawn the first client manually in order to account for the errors when scene management is disabled. @@ -224,7 +220,6 @@ public IEnumerator TestPrefabsSpawning([Values] InstantiateAndSpawnMethods insta // spawn the original prefab and when spawning dynamically the override is used. yield return CreateAndStartNewClient(); - var spawnManager = m_ServerNetworkManager.SpawnManager; // If scene management is enabled, then we want to verify against the editor // assigned in-scene placed NetworkObjects if (m_SceneManagementEnabled) diff --git a/testproject/ProjectSettings/EditorBuildSettings.asset b/testproject/ProjectSettings/EditorBuildSettings.asset index b2632cd9f5..63b5a1481e 100644 --- a/testproject/ProjectSettings/EditorBuildSettings.asset +++ b/testproject/ProjectSettings/EditorBuildSettings.asset @@ -44,9 +44,6 @@ EditorBuildSettings: - enabled: 1 path: Assets/Tests/Manual/NetworkSceneManagerCallbacks/SceneWeAreSwitchingFrom.unity guid: 073bd2111475c0643be45b7abe6a97ad - - enabled: 1 - path: Assets/Scenes/MultiprocessTestScene.unity - guid: 76743cb7b342c49279327834918a9c6e - enabled: 1 path: Assets/Scenes/EmptyScene.unity guid: a2545a872c007404fbb6b0393ab74974 @@ -133,6 +130,9 @@ EditorBuildSettings: guid: 17b92153f7381d34fa48c4d5c0393d13 - enabled: 1 path: Assets/Tests/Manual/IntegrationTestScenes/EmptyScene3.unity + guid: bfb4addb64cf6455a88668eba2f759ba + - enabled: 1 + path: Assets/Tests/Manual/IntegrationTestScenes/MoveADynamicObjectInAwake.unity guid: abd4c8b51c445d54faa16c67ac973f1b - enabled: 1 path: Assets/Samples/SpawnObject/SimpleSpawn.unity @@ -158,7 +158,9 @@ EditorBuildSettings: - enabled: 1 path: Assets/Tests/Manual/NetworkAnimatorTests/AnimationBidirectionalTriggers/NetworkAnimatorDualTriggerCheer.unity guid: e12df855278120245a8a936a6a52b5bd + - enabled: 1 + path: Assets/Tests/Manual/IntegrationTestScenes/InSceneNetworkObjectMovesToDDOL.unity + guid: 4c20c17b4f92e634f8796b0460851d49 m_configObjects: com.unity.addressableassets: {fileID: 11400000, guid: 5a3d5c53c25349c48912726ae850f3b0, type: 2} - m_UseUCBPForAssetBundles: 0