diff --git a/com.unity.netcode.gameobjects/Runtime/Core/NetworkObject.cs b/com.unity.netcode.gameobjects/Runtime/Core/NetworkObject.cs
index 73cc6c7e2d..4649761a0b 100644
--- a/com.unity.netcode.gameobjects/Runtime/Core/NetworkObject.cs
+++ b/com.unity.netcode.gameobjects/Runtime/Core/NetworkObject.cs
@@ -416,7 +416,7 @@ public void DeferDespawn(int tickOffset, bool destroy = true)
return;
}
- if (!HasAuthority)
+ if (!m_HasAuthority)
{
if (NetworkManagerOwner.LogLevel <= LogLevel.Error)
{
@@ -633,7 +633,7 @@ public bool SetOwnershipLock(bool lockOwnership = true)
}
// If we don't have authority exit early
- if (!HasAuthority)
+ if (!m_HasAuthority)
{
if (NetworkManager.LogLevel <= LogLevel.Error)
{
@@ -909,7 +909,7 @@ internal void OwnershipRequest(ulong clientRequestingOwnership)
// This action is always authorized as long as the client still has authority.
// We need to pass in that this is a request approval ownership change.
- NetworkManagerOwner.SpawnManager.ChangeOwnership(this, clientRequestingOwnership, HasAuthority, true);
+ NetworkManagerOwner.SpawnManager.ChangeOwnership(this, clientRequestingOwnership, m_HasAuthority, true);
}
else
{
@@ -1155,14 +1155,9 @@ public bool HasOwnershipStatus(OwnershipStatus status)
///
/// When in client-server mode, authority should is not considered the same as ownership.
///
- public bool HasAuthority => InternalHasAuthority();
+ public bool HasAuthority => IsSpawned ? m_HasAuthority : !NetworkManager.DistributedAuthorityMode && NetworkManager.IsServer;
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private bool InternalHasAuthority()
- {
- var networkManager = NetworkManager;
- return networkManager.DistributedAuthorityMode ? OwnerClientId == networkManager.LocalClientId : networkManager.IsServer;
- }
+ private bool m_HasAuthority;
///
/// The NetworkManager that owns this NetworkObject.
@@ -1227,7 +1222,7 @@ private bool InternalHasAuthority()
///
/// Gets if the object has yet been spawned across the network
///
- public bool IsSpawned { get; internal set; }
+ public bool IsSpawned { get; private set; }
///
/// Gets if the object is a SceneObject.
@@ -1448,10 +1443,7 @@ public bool IsNetworkVisibleTo(ulong clientId)
///
internal Scene SceneOrigin
{
- get
- {
- return m_SceneOrigin;
- }
+ get => m_SceneOrigin;
set
{
@@ -1471,13 +1463,8 @@ internal Scene SceneOrigin
///
internal NetworkSceneHandle GetSceneOriginHandle()
{
- if (SceneOriginHandle.IsEmpty() && IsSpawned && InScenePlaced)
- {
- if (NetworkManager.LogLevel <= LogLevel.Error)
- {
- NetworkLog.LogErrorServer($"{nameof(GetSceneOriginHandle)} called when {nameof(SceneOriginHandle)} is still zero but the {nameof(NetworkObject)} is already spawned!");
- }
- }
+ NetworkLog.InternalAssert(!(IsSpawned && InScenePlaced && SceneOriginHandle.IsEmpty()), $"Spawned in scene placed NetworkObject {name} should always have a valid SceneOriginHandle");
+
return !SceneOriginHandle.IsEmpty() ? SceneOriginHandle : gameObject.scene.handle;
}
@@ -1506,7 +1493,7 @@ public void NetworkShow(ulong clientId)
return;
}
- if (!HasAuthority)
+ if (!m_HasAuthority)
{
if (NetworkManagerOwner.DistributedAuthorityMode)
{
@@ -1601,7 +1588,7 @@ public void NetworkHide(ulong clientId)
return;
}
- if (!HasAuthority)
+ if (!m_HasAuthority)
{
if (NetworkManagerOwner.DistributedAuthorityMode)
{
@@ -1760,7 +1747,7 @@ private void OnDestroy()
{
// An authorized destroy is when done by the authority instance or done due to a scene event and the NetworkObject
// was marked as destroy pending scene event (which means the destroy with scene property was set).
- var isAuthorityDestroy = HasAuthority || NetworkManager.DAHost || DestroyPendingSceneEvent;
+ var isAuthorityDestroy = m_HasAuthority || NetworkManager.DAHost || DestroyPendingSceneEvent;
// If the NetworkObject's GameObject is still valid and the scene is still valid and loaded, then we are still valid
var isStillValid = gameObject != null && gameObject.scene.IsValid() && gameObject.scene.isLoaded;
@@ -2005,8 +1992,7 @@ public NetworkObject InstantiateAndSpawn(NetworkManager networkManager, ulong ow
/// Should the object be destroyed when the scene is changed
public void Spawn(bool destroyWithScene = false)
{
- var networkManager = NetworkManager;
- var clientId = networkManager.DistributedAuthorityMode ? networkManager.LocalClientId : NetworkManager.ServerClientId;
+ var clientId = NetworkManager.DistributedAuthorityMode ? NetworkManager.LocalClientId : NetworkManager.ServerClientId;
SpawnInternal(destroyWithScene, clientId, false);
}
@@ -2058,10 +2044,60 @@ public void Despawn(bool destroy = true)
NetworkManagerOwner.SpawnManager.DespawnObject(this, destroy);
}
+ internal void SetupOnSpawn(ulong networkId, bool isPlayerObject, ulong ownerClientId, bool destroyWithScene)
+ {
+ NetworkObjectId = networkId;
+ IsPlayerObject = isPlayerObject;
+ OwnerClientId = ownerClientId;
+ // When spawned, previous owner is always the first assigned owner
+ PreviousOwnerId = ownerClientId;
+ m_HasAuthority = NetworkManagerOwner.DistributedAuthorityMode ? OwnerClientId == NetworkManagerOwner.LocalClientId : NetworkManagerOwner.IsServer;
+ IsSpawned = true;
+
+ // If this is the player, and the client is the owner, then lock ownership by default
+ if (NetworkManagerOwner.DistributedAuthorityMode && NetworkManagerOwner.LocalClientId == ownerClientId && isPlayerObject)
+ {
+ AddOwnershipExtended(OwnershipStatusExtended.Locked);
+ }
+
+ if (IsSpawnAuthority)
+ {
+ SetupObservers();
+ }
+
+ /*
+ * Setup scene related settings
+ */
+ DestroyWithScene = InScenePlaced || destroyWithScene;
+ if (InScenePlaced)
+ {
+ // Always check to make sure our scene of origin is properly set for in-scene placed NetworkObjects
+ // Note: Always check SceneOriginHandle directly at this specific location.
+ if (SceneOriginHandle.IsEmpty())
+ {
+ SceneOrigin = gameObject.scene;
+ }
+
+ // If we are an in-scene placed NetworkObject and our InScenePlacedSourceGlobalObjectIdHash is set
+ // then assign this to the PrefabGlobalObjectIdHash
+ if (InScenePlacedSourceGlobalObjectIdHash != 0)
+ {
+ PrefabGlobalObjectIdHash = InScenePlacedSourceGlobalObjectIdHash;
+ }
+ }
+ else if (ActiveSceneSynchronization)
+ {
+ // Just in case it is a recycled NetworkObject, unsubscribe first
+ SceneManager.activeSceneChanged -= CurrentlyActiveSceneChanged;
+ SceneManager.activeSceneChanged += CurrentlyActiveSceneChanged;
+ }
+ }
+
internal void ResetOnDespawn()
{
// Always clear out the observers list when despawned
Observers.Clear();
+ m_HasAuthority = false;
IsSpawnAuthority = false;
IsSpawned = false;
DeferredDespawnTick = 0;
@@ -2069,6 +2105,62 @@ internal void ResetOnDespawn()
RemoveOwnershipExtended(OwnershipStatusExtended.Locked | OwnershipStatusExtended.Requested);
}
+ internal void SetupObservers()
+ {
+ NetworkLog.InternalAssert(IsSpawnAuthority, "This function should only be called on the authority.");
+
+ if (!SpawnWithObservers)
+ {
+ if (NetworkManagerOwner.DistributedAuthorityMode)
+ {
+ // Always add the owner/authority in DA mode even if SpawnWithObservers is false
+ // (authority should not take into consideration networkObject.CheckObjectVisibility when SpawnWithObservers is false)
+ AddObserver(OwnerClientId);
+ }
+
+ return;
+ }
+
+ // If running as a server only, then make sure to always add the server's client identifier
+ if (NetworkManagerOwner.IsServer && !NetworkManagerOwner.IsHost)
+ {
+ AddObserver(NetworkManager.ServerClientId);
+ }
+
+ // If SpawnWithObservers is set,
+ // then add all connected clients as observers
+ foreach (var clientId in NetworkManagerOwner.ConnectedClientsIds)
+ {
+ // If CheckObjectVisibility has a callback, then allow that method determine who the observers are.
+ if (CheckObjectVisibility != null && !CheckObjectVisibility(clientId))
+ {
+ continue;
+ }
+ AddObserver(clientId);
+ }
+
+ // Intentionally checking as opposed to just assigning in order to generate notification.
+ if (!Observers.Contains(OwnerClientId))
+ {
+ // The owner only needs to always be included in DA mode.
+ if (NetworkManagerOwner.DistributedAuthorityMode)
+ {
+ if (NetworkManager.LogLevel <= LogLevel.Error)
+ {
+ NetworkLog.LogError($"Client-{OwnerClientId} is the owner of {name} but is not an observer! Adding owner as an observer!");
+ }
+ AddObserver(OwnerClientId);
+ }
+ else
+ {
+ if (NetworkManager.LogLevel <= LogLevel.Developer)
+ {
+ NetworkLog.LogWarning($"Client-{OwnerClientId} is the owner of {name} but is not an observer! This may cause issues");
+ }
+ }
+ }
+ }
+
///
/// Removes all ownership of an object from any client. Can only be called from server
///
@@ -2099,7 +2191,7 @@ public void ChangeOwnership(ulong newOwnerClientId)
}
return;
}
- NetworkManagerOwner.SpawnManager.ChangeOwnership(this, newOwnerClientId, HasAuthority);
+ NetworkManagerOwner.SpawnManager.ChangeOwnership(this, newOwnerClientId, m_HasAuthority);
}
///
@@ -2108,20 +2200,18 @@ public void ChangeOwnership(ulong newOwnerClientId)
///
internal void InvokeBehaviourOnOwnershipChanged(ulong originalOwnerClientId, ulong newOwnerClientId)
{
- if (!IsSpawned)
- {
- if (NetworkManager.LogLevel <= LogLevel.Error)
- {
- NetworkLog.LogErrorServer($"[{name}][Attempted behavior invoke on ownership changed before {nameof(NetworkObject)} was spawned]");
- }
- return;
- }
+ NetworkLog.InternalAssert(IsSpawned, "[{name}][Attempted behavior invoke on ownership changed before {nameof(NetworkObject)} was spawned]");
var distributedAuthorityMode = NetworkManagerOwner.DistributedAuthorityMode;
var isServer = NetworkManagerOwner.IsServer;
var isPreviousOwner = originalOwnerClientId == NetworkManagerOwner.LocalClientId;
var isNewOwner = newOwnerClientId == NetworkManagerOwner.LocalClientId;
+ if (distributedAuthorityMode)
+ {
+ m_HasAuthority = isNewOwner;
+ }
+
if (distributedAuthorityMode || isPreviousOwner)
{
NetworkManagerOwner.SpawnManager.UpdateOwnershipTable(this, originalOwnerClientId, true);
@@ -2334,7 +2424,7 @@ public bool TrySetParent(NetworkObject parent, bool worldPositionStays = true)
// DANGO-TODO: Do we want to worry about ownership permissions here?
// It wouldn't make sense to not allow parenting, but keeping this note here as a reminder.
- var isAuthority = HasAuthority || (AllowOwnerToParent && IsOwner);
+ var isAuthority = m_HasAuthority || (AllowOwnerToParent && IsOwner);
// If we don't have authority and we are not shutting down, then don't allow any parenting.
// If we are shutting down and don't have authority then allow it.
@@ -2409,7 +2499,7 @@ private void OnTransformParentChanged()
// With distributed authority, we need to track "valid authoritative" parenting changes.
// So, either the authority or AuthorityAppliedParenting is considered a "valid parenting change".
- var isParentingAuthority = HasAuthority || AuthorityAppliedParenting || (AllowOwnerToParent && IsOwner);
+ var isParentingAuthority = m_HasAuthority || AuthorityAppliedParenting || (AllowOwnerToParent && IsOwner);
// If we are spawned and don't have authority; reset the parent back to the cached parent and exit
if (!isParentingAuthority)
{
@@ -2663,8 +2753,6 @@ internal void InvokeBehaviourNetworkPreSpawn()
internal void InvokeBehaviourNetworkSpawn()
{
- NetworkManagerOwner.SpawnManager.UpdateOwnershipTable(this, OwnerClientId);
-
// Always invoke all InternalOnNetworkSpawn methods on each child NetworkBehaviour
// ** before ** invoking OnNetworkSpawn.
// This assures all NetworkVariables and RPC related tables have been initialized
@@ -3465,29 +3553,13 @@ internal static NetworkObject Deserialize(in SerializedObject serializedObject,
return networkObject;
}
- ///
- /// Subscribes to changes in the currently active scene
- ///
- ///
- /// Only for dynamically spawned NetworkObjects
- ///
- internal void SubscribeToActiveSceneForSynch()
- {
- if (ActiveSceneSynchronization)
- {
- if (!InScenePlaced)
- {
- // Just in case it is a recycled NetworkObject, unsubscribe first
- SceneManager.activeSceneChanged -= CurrentlyActiveSceneChanged;
- SceneManager.activeSceneChanged += CurrentlyActiveSceneChanged;
- }
- }
- }
-
///
/// If AutoSynchActiveScene is enabled, then this is the callback that handles updating
/// a NetworkObject's scene information.
///
+ ///
+ /// Should only be used for dynamically spawned NetworkObjects
+ ///
private void CurrentlyActiveSceneChanged(Scene current, Scene next)
{
// Early exit if the NetworkObject is not spawned, is an in-scene placed NetworkObject,
@@ -3526,15 +3598,14 @@ internal void SceneChangedUpdate(Scene scene, bool notify = false)
return;
}
- var isAuthority = HasAuthority;
SceneOriginHandle = scene.handle;
// non-authority needs to update the NetworkSceneHandle
- if (!isAuthority && NetworkManagerOwner.SceneManager.ClientSceneHandleToServerSceneHandle.ContainsKey(SceneOriginHandle))
+ if (!m_HasAuthority && NetworkManagerOwner.SceneManager.ClientSceneHandleToServerSceneHandle.ContainsKey(SceneOriginHandle))
{
NetworkSceneHandle = NetworkManagerOwner.SceneManager.ClientSceneHandleToServerSceneHandle[SceneOriginHandle];
}
- else if (isAuthority)
+ else if (m_HasAuthority)
{
// Since the authority is the source of truth for the NetworkSceneHandle,
// the NetworkSceneHandle is the same as the SceneOriginHandle.
@@ -3561,7 +3632,7 @@ internal void SceneChangedUpdate(Scene scene, bool notify = false)
OnMigratedToNewScene?.Invoke();
// Only the authority side will notify clients of non-parented NetworkObject scene changes
- if (isAuthority && notify && !transform.parent)
+ if (m_HasAuthority && notify && !transform.parent)
{
NetworkManagerOwner.SceneManager.NotifyNetworkObjectSceneChanged(this);
}
diff --git a/com.unity.netcode.gameobjects/Runtime/Logging/NetworkLog.cs b/com.unity.netcode.gameobjects/Runtime/Logging/NetworkLog.cs
index 12fd9a60bb..df08bee61f 100644
--- a/com.unity.netcode.gameobjects/Runtime/Logging/NetworkLog.cs
+++ b/com.unity.netcode.gameobjects/Runtime/Logging/NetworkLog.cs
@@ -1,8 +1,10 @@
+using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
using System.Text.RegularExpressions;
using Unity.Netcode.Logging;
using UnityEngine;
+using UnityEngine.Assertions;
namespace Unity.Netcode
{
@@ -158,5 +160,11 @@ private static bool TryGetNetworkObjectName([NotNull] NetworkManager networkMana
return true;
}
+ [HideInCallstack]
+ [Conditional("NETCODE_INTERNAL")]
+ internal static void InternalAssert(bool condition, string message)
+ {
+ Assert.IsTrue(condition, message);
+ }
}
}
diff --git a/com.unity.netcode.gameobjects/Runtime/Spawning/NetworkSpawnManager.cs b/com.unity.netcode.gameobjects/Runtime/Spawning/NetworkSpawnManager.cs
index 46f52bc4f9..3a6ada922c 100644
--- a/com.unity.netcode.gameobjects/Runtime/Spawning/NetworkSpawnManager.cs
+++ b/com.unity.netcode.gameobjects/Runtime/Spawning/NetworkSpawnManager.cs
@@ -1137,48 +1137,13 @@ internal bool AuthorityLocalSpawn([NotNull] NetworkObject networkObject, ulong n
networkObject.NetworkManagerOwner = NetworkManager;
networkObject.InvokeBehaviourNetworkPreSpawn();
- // DANGO-TODO: It would be nice to allow users to specify which clients are observers prior to spawning
- // For now, this is the best place I could find to add all connected clients as observers for newly
- // instantiated and spawned NetworkObjects on the authoritative side.
- if (NetworkManager.DistributedAuthorityMode)
+ if (NetworkManager.DistributedAuthorityMode && NetworkManager.NetworkConfig.EnableSceneManagement && sceneObject)
{
- if (NetworkManager.NetworkConfig.EnableSceneManagement && sceneObject)
- {
- networkObject.SceneOriginHandle = networkObject.gameObject.scene.handle;
- networkObject.NetworkSceneHandle = NetworkManager.SceneManager.ClientSceneHandleToServerSceneHandle[networkObject.gameObject.scene.handle];
- }
-
- // Always add the owner/authority even if SpawnWithObservers is false
- // (authority should not take into consideration networkObject.CheckObjectVisibility when SpawnWithObservers is false)
- if (!networkObject.SpawnWithObservers)
- {
- networkObject.AddObserver(ownerClientId);
- }
- else
- {
- foreach (var clientId in NetworkManager.ConnectionManager.ConnectedClientIds)
- {
- // If SpawnWithObservers is enabled, then authority does take networkObject.CheckObjectVisibility into consideration
- if (networkObject.CheckObjectVisibility != null && !networkObject.CheckObjectVisibility.Invoke(clientId))
- {
- continue;
- }
- networkObject.AddObserver(clientId);
- }
-
- // Sanity check to make sure the owner is always included
- // Intentionally checking as opposed to just assigning in order to generate notification.
- if (!networkObject.Observers.Contains(ownerClientId))
- {
- if (NetworkManager.LogLevel <= LogLevel.Error)
- {
- NetworkLog.LogError($"Client-{ownerClientId} is the owner of {networkObject.name} but is not an observer! Adding owner, but there is a bug in observer synchronization!");
- }
- networkObject.AddObserver(ownerClientId);
- }
- }
+ networkObject.SceneOriginHandle = networkObject.gameObject.scene.handle;
+ networkObject.NetworkSceneHandle = NetworkManager.SceneManager.ClientSceneHandleToServerSceneHandle[networkObject.gameObject.scene.handle];
}
+
if (!SpawnNetworkObjectLocallyCommon(networkObject, networkId, sceneObject, playerObject, ownerClientId, destroyWithScene))
{
if (NetworkManager.LogLevel <= LogLevel.Error)
@@ -1295,9 +1260,10 @@ internal bool NonAuthorityLocalSpawn(in NetworkObject.SerializedObject serialize
}
///
- /// Handles the all the final setup and spawning needed for
+ /// Handles all the final setup and spawning needed for spawning a NetworkObject locally.
///
- /// boolean indicating whether the spawn succeeded. Internal dev note: THIS IS A CATCH FOR OURSELVES. DON'T PULL OUT
+ /// boolean indicating whether the spawn succeeded.
+ // Internal dev note: THIS IS A CATCH FOR OURSELVES. DON'T PULL OUT
internal bool SpawnNetworkObjectLocallyCommon(NetworkObject networkObject, ulong networkId, bool sceneObject, bool playerObject, ulong ownerClientId, bool destroyWithScene)
{
// TODO: Replace the following checks with internal Netcode asserts
@@ -1311,7 +1277,7 @@ internal bool SpawnNetworkObjectLocallyCommon(NetworkObject networkObject, ulong
return false;
}
- if (networkId == default)
+ if (networkId == 0)
{
if (NetworkManager.LogLevel <= LogLevel.Error)
{
@@ -1326,82 +1292,23 @@ internal bool SpawnNetworkObjectLocallyCommon(NetworkObject networkObject, ulong
networkObject.SetSceneObjectStatus(sceneObject);
#pragma warning restore CS0618 // Type or member is obsolete
- // Always check to make sure our scene of origin is properly set for in-scene placed NetworkObjects
- // Note: Always check SceneOriginHandle directly at this specific location.
- if (networkObject.InScenePlaced && networkObject.SceneOriginHandle.IsEmpty())
- {
- networkObject.SceneOrigin = networkObject.gameObject.scene;
- }
-
- networkObject.NetworkObjectId = networkId;
-
- networkObject.DestroyWithScene = sceneObject || destroyWithScene;
-
- networkObject.IsPlayerObject = playerObject;
+ networkObject.SetupOnSpawn(networkId, playerObject, ownerClientId, destroyWithScene);
- networkObject.OwnerClientId = ownerClientId;
-
- // When spawned, previous owner is always the first assigned owner
- networkObject.PreviousOwnerId = ownerClientId;
-
- // If this the player and the client is the owner, then lock ownership by default
- if (NetworkManager.DistributedAuthorityMode && NetworkManager.LocalClientId == ownerClientId && playerObject)
- {
- networkObject.AddOwnershipExtended(NetworkObject.OwnershipStatusExtended.Locked);
- }
-
- networkObject.IsSpawned = true;
SpawnedObjects.Add(networkObject.NetworkObjectId, networkObject);
SpawnedObjectsList.Add(networkObject);
-
- // If we are not running in DA mode, this is the server, and the NetworkObject has SpawnWithObservers set,
- // then add all connected clients as observers
- if (!NetworkManager.DistributedAuthorityMode && NetworkManager.IsServer && networkObject.SpawnWithObservers)
- {
- // If running as a server only, then make sure to always add the server's client identifier
- if (!NetworkManager.IsHost)
- {
- networkObject.AddObserver(NetworkManager.LocalClientId);
- }
-
- // Add client observers
- for (int i = 0; i < NetworkManager.ConnectedClientsIds.Count; i++)
- {
- // If CheckObjectVisibility has a callback, then allow that method determine who the observers are.
- if (networkObject.CheckObjectVisibility != null && !networkObject.CheckObjectVisibility(NetworkManager.ConnectedClientsIds[i]))
- {
- continue;
- }
- networkObject.AddObserver(NetworkManager.ConnectedClientsIds[i]);
- }
- }
-
networkObject.ApplyNetworkParenting();
+
NetworkObject.CheckOrphanChildren();
AddNetworkObjectToSceneChangedUpdates(networkObject);
-
+ UpdateOwnershipTable(networkObject, ownerClientId);
networkObject.InvokeBehaviourNetworkSpawn();
-
- // Only dynamically spawned NetworkObjects are allowed
- if (!sceneObject)
- {
- networkObject.SubscribeToActiveSceneForSynch();
- }
-
if (networkObject.IsPlayerObject)
{
UpdateNetworkClientPlayer(networkObject);
}
- // If we are an in-scene placed NetworkObject and our InScenePlacedSourceGlobalObjectIdHash is set
- // then assign this to the PrefabGlobalObjectIdHash
- if (networkObject.InScenePlaced && networkObject.InScenePlacedSourceGlobalObjectIdHash != 0)
- {
- networkObject.PrefabGlobalObjectIdHash = networkObject.InScenePlacedSourceGlobalObjectIdHash;
- }
-
return true;
}
@@ -1554,8 +1461,7 @@ internal void ServerResetShutdownStateForSceneObjects()
{
continue;
}
- sobj.IsSpawned = false;
- sobj.DestroyWithScene = false;
+ sobj.ResetOnDespawn();
}
}
diff --git a/com.unity.netcode.gameobjects/Tests/Runtime/NetworkObject/NetworkObjectOnSpawnTests.cs b/com.unity.netcode.gameobjects/Tests/Runtime/NetworkObject/NetworkObjectOnSpawnTests.cs
index 0cdb31c11e..5b5583f31d 100644
--- a/com.unity.netcode.gameobjects/Tests/Runtime/NetworkObject/NetworkObjectOnSpawnTests.cs
+++ b/com.unity.netcode.gameobjects/Tests/Runtime/NetworkObject/NetworkObjectOnSpawnTests.cs
@@ -341,7 +341,17 @@ bool HasConditionBeenMet()
Assert.False(s_GlobalTimeoutHelper.TimedOut, "Timed out while waiting for client side despawns!");
//----------- step 2 check spawn and destroy again
- authorityInstance.GetComponent().Spawn();
+ var authorityObject = authorityInstance.GetComponent();
+ authorityObject.Spawn();
+
+ // This validates invoking GetSceneOriginHandle will not throw an exception for a dynamically spawned NetworkObject
+ // when the scene of origin hasn't been set.
+ var sceneOriginHandle = authorityObject.GetSceneOriginHandle();
+
+ // This validates that GetSceneOriginHandle will return the GameObject's scene handle that should be the currently active scene
+ var activeSceneHandle = SceneManager.GetActiveScene().handle;
+ Assert.IsTrue(sceneOriginHandle == activeSceneHandle, $"{nameof(NetworkObject)} should have returned the active scene handle of {activeSceneHandle} but returned {sceneOriginHandle}");
+
// wait a tick
yield return s_DefaultWaitForTick;
// check spawned again on server this is 2 because we are reusing the object which was already spawned once.
@@ -366,22 +376,6 @@ bool HasConditionBeenMet()
Assert.False(s_GlobalTimeoutHelper.TimedOut, "Timed out while waiting for client side despawns! (2nd pass)");
}
- [Test]
- public void DynamicallySpawnedNoSceneOriginException()
- {
- var gameObject = new GameObject();
- var networkObject = gameObject.AddComponent();
- networkObject.IsSpawned = true;
- networkObject.SceneOriginHandle = default;
- // This validates invoking GetSceneOriginHandle will not throw an exception for a dynamically spawned NetworkObject
- // when the scene of origin hasn't been set.
- var sceneOriginHandle = networkObject.GetSceneOriginHandle();
-
- // This validates that GetSceneOriginHandle will return the GameObject's scene handle that should be the currently active scene
- var activeSceneHandle = SceneManager.GetActiveScene().handle;
- Assert.IsTrue(sceneOriginHandle == activeSceneHandle, $"{nameof(NetworkObject)} should have returned the active scene handle of {activeSceneHandle} but returned {sceneOriginHandle}");
- }
-
private class TrackOnSpawnFunctions : NetworkBehaviour
{
public int OnNetworkSpawnCalledCount { get; private set; }