From 00faa4768234f6ee36965dea295559708b75e425 Mon Sep 17 00:00:00 2001 From: Emma Date: Mon, 25 May 2026 18:30:46 -0400 Subject: [PATCH 1/4] chore: Replace IsSceneObject with InScenePlaced bool --- .../Editor/InScenePlacedPrefab.cs | 32 +++++++ .../Editor/InScenePlacedPrefab.cs.meta | 3 + .../Editor/NetworkObjectEditor.cs | 12 +-- .../Runtime/Components/NetworkTransform.cs | 2 +- .../Connection/NetworkConnectionManager.cs | 6 +- .../Runtime/Core/FindObjects.cs | 96 ++++++++++++++++++- .../Runtime/Core/NetworkManager.cs | 2 +- .../Runtime/Core/NetworkObject.cs | 44 +++++---- .../DefaultSceneManagerHandler.cs | 2 +- .../SceneManagement/NetworkSceneHandle.cs | 6 +- .../SceneManagement/NetworkSceneManager.cs | 22 ++--- .../Runtime/SceneManagement/SceneEventData.cs | 37 +++---- .../Runtime/Spawning/NetworkSpawnManager.cs | 69 ++++++------- .../NetworkObjectOnSpawnTests.cs | 1 - .../NetworkObjectSpawnManyObjectsTests.cs | 1 - ...orkVariableBaseInitializesWhenPersisted.cs | 2 - .../Prefabs/NetworkPrefabOverrideTests.cs | 5 - .../IntegrationTestSceneHandler.cs | 50 +++------- .../TestHelpers/NetcodeIntegrationTest.cs | 1 - .../NetcodeIntegrationTestHelpers.cs | 3 - .../Tests/Runtime/NetworkManagerTests.cs | 2 +- .../AttachableBehaviourSceneLoadTests.cs | 2 +- .../ClientSynchronizationValidationTest.cs | 4 +- .../NetworkSceneManagerDDOLTests.cs | 12 +-- .../NetworkSceneManagerEventDataPoolTest.cs | 6 +- ...NetworkSceneManagerPopulateInSceneTests.cs | 4 +- .../ParentDynamicUnderInScenePlaced.cs | 10 +- .../Tests/Runtime/PrefabExtendedTests.cs | 2 +- 28 files changed, 256 insertions(+), 182 deletions(-) create mode 100644 com.unity.netcode.gameobjects/Editor/InScenePlacedPrefab.cs create mode 100644 com.unity.netcode.gameobjects/Editor/InScenePlacedPrefab.cs.meta diff --git a/com.unity.netcode.gameobjects/Editor/InScenePlacedPrefab.cs b/com.unity.netcode.gameobjects/Editor/InScenePlacedPrefab.cs new file mode 100644 index 0000000000..f7613985ae --- /dev/null +++ b/com.unity.netcode.gameobjects/Editor/InScenePlacedPrefab.cs @@ -0,0 +1,32 @@ +using UnityEditor; +using UnityEditor.Build; +using UnityEditor.Build.Reporting; +using UnityEngine; +using UnityEngine.SceneManagement; + +namespace Unity.Netcode.Editor +{ + public class InScenePlacedPrefab : IProcessSceneWithReport + { + public int callbackOrder => 0; + public void OnProcessScene(Scene scene, BuildReport report) + { + foreach (var networkObject in FindObjects.FromSceneByType(scene, true)) + { + networkObject.InScenePlaced = true; + } + } + } + + public class InScenePlacedPrefabBuilder : AssetPostprocessor + { + public void OnPostprocessPrefab(GameObject root) + { + var networkObjects = root.GetComponentsInChildren(true); + foreach (var networkObject in networkObjects) + { + networkObject.InScenePlaced = false; + } + } + } +} diff --git a/com.unity.netcode.gameobjects/Editor/InScenePlacedPrefab.cs.meta b/com.unity.netcode.gameobjects/Editor/InScenePlacedPrefab.cs.meta new file mode 100644 index 0000000000..397923e850 --- /dev/null +++ b/com.unity.netcode.gameobjects/Editor/InScenePlacedPrefab.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: e9b29e08242545899dfb65e4fb568beb +timeCreated: 1779219564 diff --git a/com.unity.netcode.gameobjects/Editor/NetworkObjectEditor.cs b/com.unity.netcode.gameobjects/Editor/NetworkObjectEditor.cs index 04e0d1f698..0335896784 100644 --- a/com.unity.netcode.gameobjects/Editor/NetworkObjectEditor.cs +++ b/com.unity.netcode.gameobjects/Editor/NetworkObjectEditor.cs @@ -67,14 +67,10 @@ public override void OnInspectorGUI() EditorGUILayout.Toggle(nameof(NetworkObject.IsOwner), m_NetworkObject.IsOwner); EditorGUILayout.Toggle(nameof(NetworkObject.IsOwnedByServer), m_NetworkObject.IsOwnedByServer); EditorGUILayout.Toggle(nameof(NetworkObject.IsPlayerObject), m_NetworkObject.IsPlayerObject); - if (m_NetworkObject.IsSceneObject.HasValue) - { - EditorGUILayout.Toggle(nameof(NetworkObject.IsSceneObject), m_NetworkObject.IsSceneObject.Value); - } - else - { - EditorGUILayout.TextField(nameof(NetworkObject.IsSceneObject), "null"); - } +#pragma warning disable CS0618 // Type or member is obsolete + // TODO-3.x: Update name in 3.x branch + EditorGUILayout.Toggle(nameof(NetworkObject.IsSceneObject), m_NetworkObject.InScenePlaced); +#pragma warning restore CS0618 // Type or member is obsolete EditorGUILayout.Toggle(nameof(NetworkObject.DestroyWithScene), m_NetworkObject.DestroyWithScene); EditorGUILayout.TextField(nameof(NetworkObject.NetworkManager), m_NetworkObject.NetworkManager == null ? "null" : m_NetworkObject.NetworkManager.gameObject.name); GUI.enabled = guiEnabled; diff --git a/com.unity.netcode.gameobjects/Runtime/Components/NetworkTransform.cs b/com.unity.netcode.gameobjects/Runtime/Components/NetworkTransform.cs index 3ca9093b34..0259138b46 100644 --- a/com.unity.netcode.gameobjects/Runtime/Components/NetworkTransform.cs +++ b/com.unity.netcode.gameobjects/Runtime/Components/NetworkTransform.cs @@ -2231,7 +2231,7 @@ private bool CheckForStateChange(ref NetworkTransformState networkState, bool is // In-scene placed NetworkObjects parented under a GameObject with no // NetworkObject preserve their lossyScale when synchronizing. - if (parentNetworkObject == null && NetworkObject.IsSceneObject != false) + if (parentNetworkObject == null && NetworkObject.InScenePlaced) { hasParentNetworkObject = true; } diff --git a/com.unity.netcode.gameobjects/Runtime/Connection/NetworkConnectionManager.cs b/com.unity.netcode.gameobjects/Runtime/Connection/NetworkConnectionManager.cs index aaeb67f4db..1da9ddb3bb 100644 --- a/com.unity.netcode.gameobjects/Runtime/Connection/NetworkConnectionManager.cs +++ b/com.unity.netcode.gameobjects/Runtime/Connection/NetworkConnectionManager.cs @@ -1184,7 +1184,11 @@ internal void CreateAndSpawnPlayer(ulong ownerId) return; } - networkObject.IsSceneObject = false; +#pragma warning disable CS0618 // Type or member is obsolete + // Obsolete with warning means we need the underlying behaviour to keep existing + // TODO: remove in the 3.x branch + networkObject.SetSceneObjectStatus(false); +#pragma warning restore CS0618 // Type or member is obsolete networkObject.NetworkManagerOwner = NetworkManager; networkObject.SpawnAsPlayerObject(ownerId, networkObject.DestroyWithScene); } diff --git a/com.unity.netcode.gameobjects/Runtime/Core/FindObjects.cs b/com.unity.netcode.gameobjects/Runtime/Core/FindObjects.cs index a283cabe52..8561b8fa17 100644 --- a/com.unity.netcode.gameobjects/Runtime/Core/FindObjects.cs +++ b/com.unity.netcode.gameobjects/Runtime/Core/FindObjects.cs @@ -1,7 +1,12 @@ #if NGO_FINDOBJECTS_NOSORTING using System; #endif +using System; +using System.Collections; +using System.Collections.Generic; using System.Runtime.CompilerServices; +using UnityEngine; +using UnityEngine.SceneManagement; using Object = UnityEngine.Object; namespace Unity.Netcode @@ -18,14 +23,14 @@ internal static class FindObjects /// /// Replaces to have one place where these changes are applied. /// - /// + /// The type of object to find. Must be a reference type derived from /// When true, inactive objects will be included. /// When true, the array returned will be sorted by identifier. /// Results as an of type T [MethodImpl(MethodImplOptions.AggressiveInlining)] public static T[] ByType(bool includeInactive = false, bool orderByIdentifier = false) where T : Object { - var inactive = includeInactive ? UnityEngine.FindObjectsInactive.Include : UnityEngine.FindObjectsInactive.Exclude; + var inactive = includeInactive ? FindObjectsInactive.Include : FindObjectsInactive.Exclude; #if NGO_FINDOBJECTS_NOSORTING var results = Object.FindObjectsByType(inactive); #if !NGO_FINDOBJECTS_UNORDERED_IDS @@ -35,9 +40,94 @@ public static T[] ByType(bool includeInactive = false, bool orderByIdentifier } #endif #else - var results = Object.FindObjectsByType(inactive, orderByIdentifier ? UnityEngine.FindObjectsSortMode.InstanceID : UnityEngine.FindObjectsSortMode.None); + var results = Object.FindObjectsByType(inactive, orderByIdentifier ? FindObjectsSortMode.InstanceID : FindObjectsSortMode.None); #endif return results; } + + /// + /// Returns an enumerator that enumerates over all the components of a given type in a scene. + /// + /// The scene to use for searching + /// When true, inactive objects will be included. + /// Type of to get from the scene + /// a generator that yields successive NetworkObjects in the current scene + public static IEnumerable FromSceneByType(Scene scene, bool includeInactive) where T : Component + { + return new ObjectsInSceneEnumerator(scene, includeInactive); + } + + /// + /// An Enumerator that enumerates over each component of type in the given scene. + /// + /// Type of to get from the scene + private struct ObjectsInSceneEnumerator : IEnumerable, IEnumerator where T : Component + { + private readonly GameObject[] m_RootObjects; + private int m_RootIndex; + private T[] m_CurrentChildObjects; + private int m_CurrentChildIndex; + + private readonly bool m_IncludeInactive; + + internal ObjectsInSceneEnumerator(Scene scene, bool includeInactive) + { + m_IncludeInactive = includeInactive; + + m_RootObjects = scene.GetRootGameObjects(); + m_RootIndex = 0; + m_CurrentChildObjects = null; + m_CurrentChildIndex = 0; + Current = null; + } + + public void Dispose() { } + + public bool MoveNext() + { + while (m_CurrentChildObjects == null && m_RootIndex < m_RootObjects.Length) + { + m_CurrentChildObjects = m_RootObjects[m_RootIndex].GetComponentsInChildren(m_IncludeInactive); + m_RootIndex++; + + if (m_CurrentChildObjects.Length == 0) + { + m_CurrentChildObjects = null; + } + } + + if (m_CurrentChildObjects != null && m_CurrentChildIndex < m_CurrentChildObjects.Length) + { + Current = m_CurrentChildObjects[m_CurrentChildIndex]; + m_CurrentChildIndex++; + + if (m_CurrentChildIndex >= m_CurrentChildObjects.Length) + { + m_CurrentChildIndex = 0; + m_CurrentChildObjects = null; + } + return true; + } + + Current = null; + return false; + } + + public void Reset() + { + m_RootIndex = 0; + m_CurrentChildObjects = null; + m_CurrentChildIndex = 0; + Current = null; + } + + object IEnumerator.Current => Current; + + public T Current { get; private set; } + + public IEnumerator GetEnumerator() => this; + + IEnumerator IEnumerable.GetEnumerator() => this; + } } } diff --git a/com.unity.netcode.gameobjects/Runtime/Core/NetworkManager.cs b/com.unity.netcode.gameobjects/Runtime/Core/NetworkManager.cs index 8fc97dd84e..563c349a28 100644 --- a/com.unity.netcode.gameobjects/Runtime/Core/NetworkManager.cs +++ b/com.unity.netcode.gameobjects/Runtime/Core/NetworkManager.cs @@ -1641,7 +1641,7 @@ internal void ShutdownInternal() // place (i.e. sending any last state updates or the like). SpawnManager?.DespawnAndDestroyNetworkObjects(); - SpawnManager?.ServerResetShudownStateForSceneObjects(); + SpawnManager?.ServerResetShutdownStateForSceneObjects(); //// RpcTarget?.Dispose(); diff --git a/com.unity.netcode.gameobjects/Runtime/Core/NetworkObject.cs b/com.unity.netcode.gameobjects/Runtime/Core/NetworkObject.cs index d2f5aa5869..7132b59e08 100644 --- a/com.unity.netcode.gameobjects/Runtime/Core/NetworkObject.cs +++ b/com.unity.netcode.gameobjects/Runtime/Core/NetworkObject.cs @@ -291,7 +291,7 @@ internal void OnValidate() if (GlobalObjectIdHash != oldValue) { // Check if this is an in-scnee placed NetworkObject (Special Case for In-Scene Placed). - if (IsSceneObject.HasValue && IsSceneObject.Value) + if (InScenePlaced) { // Sanity check to make sure this is a scene placed object. if (globalId.identifierType != k_SceneObjectType) @@ -340,7 +340,12 @@ private void CheckForInScenePlaced() EditorUtility.SetDirty(this); } } - IsSceneObject = true; + +#pragma warning disable CS0618 // Type or member is obsolete + // Obsolete with warning means we need the underlying behaviour to keep existing + // TODO-3.x: remove in the 3.x branch + SetSceneObjectStatus(true); +#pragma warning restore CS0618 // Type or member is obsolete // Default scene migration synchronization to false for in-scene placed NetworkObjects SceneMigrationSynchronization = false; @@ -1225,15 +1230,21 @@ private bool InternalHasAuthority() public bool IsSpawned { get; internal set; } /// - /// Gets if the object is a SceneObject, null if it's not yet spawned but is a scene object. + /// Gets if the object is a SceneObject. /// + [Obsolete("Use InScenePlaced instead")] public bool? IsSceneObject { get; internal set; } - //DANGOEXP TODO: Determine if we want to keep this + [field: HideInInspector] + [field: SerializeField] + public bool InScenePlaced { get; internal set; } + /// /// Sets whether this NetworkObject was instantiated as part of a scene /// + /// Only use this when using custom scene loading /// When true, marks this as a scene-instantiated object; when false, marks it as runtime-instantiated + [Obsolete("SetSceneObjectStatus is now calculated during the build.")] public void SetSceneObjectStatus(bool isSceneObject = false) { IsSceneObject = isSceneObject; @@ -1457,7 +1468,7 @@ internal Scene SceneOrigin /// internal NetworkSceneHandle GetSceneOriginHandle() { - if (SceneOriginHandle.IsEmpty() && IsSpawned && IsSceneObject != false) + if (SceneOriginHandle.IsEmpty() && IsSpawned && InScenePlaced) { if (NetworkManager.LogLevel <= LogLevel.Error) { @@ -1622,7 +1633,7 @@ public void NetworkHide(ulong clientId) var message = new DestroyObjectMessage { NetworkObjectId = NetworkObjectId, - DestroyGameObject = !IsSceneObject.Value, + DestroyGameObject = !InScenePlaced, IsDistributedAuthority = NetworkManagerOwner.DistributedAuthorityMode, IsTargetedDestroy = NetworkManagerOwner.DistributedAuthorityMode, TargetClientId = clientId, // Just always populate this value whether we write it or not @@ -1750,7 +1761,7 @@ private void OnDestroy() var isStillValid = gameObject != null && gameObject.scene.IsValid() && gameObject.scene.isLoaded; // If we're not the authority and everything is valid and dynamically spawned, then the destroy is not valid. - if (!isAuthorityDestroy && IsSceneObject == false && isStillValid) + if (!isAuthorityDestroy && !InScenePlaced && isStillValid) { if (networkManager.LogLevel <= LogLevel.Error) { @@ -1849,7 +1860,7 @@ internal void SpawnInternal(bool destroyWithScene, ulong ownerClientId, bool pla } } - if (!NetworkManagerOwner.SpawnManager.AuthorityLocalSpawn(this, NetworkManagerOwner.SpawnManager.GetNetworkObjectId(), IsSceneObject.HasValue && IsSceneObject.Value, playerObject, ownerClientId, destroyWithScene)) + if (!NetworkManagerOwner.SpawnManager.AuthorityLocalSpawn(this, NetworkManagerOwner.SpawnManager.GetNetworkObjectId(), InScenePlaced, playerObject, ownerClientId, destroyWithScene)) { if (NetworkManagerOwner.LogLevel <= LogLevel.Normal) { @@ -2528,8 +2539,7 @@ internal bool ApplyNetworkParenting(bool removeParent = false, bool ignoreNotSpa // Handle the first in-scene placed NetworkObject parenting scenarios. Once the m_LatestParent // has been set, this will not be entered into again (i.e. the later code will be invoked and // users will get notifications when the parent changes). - var isInScenePlaced = IsSceneObject.HasValue && IsSceneObject.Value; - if (transform.parent != null && !removeParent && !m_LatestParent.HasValue && isInScenePlaced) + if (transform.parent != null && !removeParent && !m_LatestParent.HasValue && InScenePlaced) { var parentNetworkObject = transform.parent.GetComponent(); @@ -3271,7 +3281,7 @@ internal SerializedObject Serialize(ulong targetClientId = NetworkManager.Server NetworkObjectId = NetworkObjectId, OwnerClientId = OwnerClientId, IsPlayerObject = IsPlayerObject, - IsSceneObject = IsSceneObject ?? true, + IsSceneObject = InScenePlaced, DestroyWithScene = DestroyWithScene, DontDestroyWithOwner = DontDestroyWithOwner, HasOwnershipFlags = NetworkManagerOwner.DistributedAuthorityMode, @@ -3456,7 +3466,7 @@ internal void SubscribeToActiveSceneForSynch() { if (ActiveSceneSynchronization) { - if (IsSceneObject.HasValue && !IsSceneObject.Value) + if (!InScenePlaced) { // Just in case it is a recycled NetworkObject, unsubscribe first SceneManager.activeSceneChanged -= CurrentlyActiveSceneChanged; @@ -3473,7 +3483,7 @@ private void CurrentlyActiveSceneChanged(Scene current, Scene next) { // Early exit if the NetworkObject is not spawned, is an in-scene placed NetworkObject, // or the NetworkManager is shutting down. - if (!IsSpawned || IsSceneObject != false || NetworkManagerOwner.ShutdownInProgress) + if (!IsSpawned || NetworkManagerOwner.ShutdownInProgress || InScenePlaced) { return; } @@ -3483,7 +3493,7 @@ private void CurrentlyActiveSceneChanged(Scene current, Scene next) { // Only dynamically spawned NetworkObjects that are not already in the newly assigned active scene will migrate // and update their scene handles - if (IsSceneObject.HasValue && !IsSceneObject.Value && gameObject.scene != next && gameObject.transform.parent == null) + if (gameObject.scene != next && gameObject.transform.parent == null) { SceneManager.MoveGameObjectToScene(gameObject, next); SceneChangedUpdate(next); @@ -3571,7 +3581,7 @@ internal bool UpdateForSceneChanges() // the NetworkManager is shutting down, the NetworkObject is not spawned, it is an in-scene placed // NetworkObject, or the GameObject's current scene handle is the same as the SceneOriginHandle if (!SceneMigrationSynchronization || !IsSpawned || NetworkManagerOwner.ShutdownInProgress || - !NetworkManagerOwner.NetworkConfig.EnableSceneManagement || IsSceneObject != false || !gameObject) + !NetworkManagerOwner.NetworkConfig.EnableSceneManagement || InScenePlaced || !gameObject) { // Stop checking for a scene migration return false; @@ -3606,7 +3616,7 @@ internal uint CheckForGlobalObjectIdHashOverride() // If scene management is disabled and this is an in-scene placed NetworkObject then go ahead // and send the InScenePlacedSourcePrefab's GlobalObjectIdHash value (i.e. what to dynamically spawn) - if (!networkManager.NetworkConfig.EnableSceneManagement && IsSceneObject.Value && InScenePlacedSourceGlobalObjectIdHash != 0) + if (!networkManager.NetworkConfig.EnableSceneManagement && InScenePlaced && InScenePlacedSourceGlobalObjectIdHash != 0) { return InScenePlacedSourceGlobalObjectIdHash; } @@ -3614,7 +3624,7 @@ internal uint CheckForGlobalObjectIdHashOverride() // If the PrefabGlobalObjectIdHash is a non-zero value and the GlobalObjectIdHash value is // different from the PrefabGlobalObjectIdHash value, then the NetworkObject instance is // an override for the original network prefab (i.e. PrefabGlobalObjectIdHash) - if (!IsSceneObject.Value && GlobalObjectIdHash != PrefabGlobalObjectIdHash) + if (!InScenePlaced && GlobalObjectIdHash != PrefabGlobalObjectIdHash) { // If the PrefabGlobalObjectIdHash is already populated (i.e. InstantiateAndSpawn used), then return this if (PrefabGlobalObjectIdHash != 0) diff --git a/com.unity.netcode.gameobjects/Runtime/SceneManagement/DefaultSceneManagerHandler.cs b/com.unity.netcode.gameobjects/Runtime/SceneManagement/DefaultSceneManagerHandler.cs index 5a11a01b4a..6e3954b294 100644 --- a/com.unity.netcode.gameobjects/Runtime/SceneManagement/DefaultSceneManagerHandler.cs +++ b/com.unity.netcode.gameobjects/Runtime/SceneManagement/DefaultSceneManagerHandler.cs @@ -311,7 +311,7 @@ public void MoveObjectsFromSceneToDontDestroyOnLoad(ref NetworkManager networkMa if (!networkObject.DestroyWithScene && networkObject.gameObject.scene != networkManager.SceneManager.DontDestroyOnLoadScene) { // Only move dynamically spawned NetworkObjects with no parent as the children will follow - if (networkObject.gameObject.transform.parent == null && networkObject.IsSceneObject != null && !networkObject.IsSceneObject.Value) + if (networkObject.gameObject.transform.parent == null && !networkObject.InScenePlaced) { UnityEngine.Object.DontDestroyOnLoad(networkObject.gameObject); } diff --git a/com.unity.netcode.gameobjects/Runtime/SceneManagement/NetworkSceneHandle.cs b/com.unity.netcode.gameobjects/Runtime/SceneManagement/NetworkSceneHandle.cs index e544eb1f24..f57414bcc5 100644 --- a/com.unity.netcode.gameobjects/Runtime/SceneManagement/NetworkSceneHandle.cs +++ b/com.unity.netcode.gameobjects/Runtime/SceneManagement/NetworkSceneHandle.cs @@ -34,7 +34,6 @@ public void NetworkSerialize(BufferSerializer serializer) where T : IReade else { var reader = serializer.GetFastBufferReader(); - // DANGO-TODO Rust needs to be updated to either handle this ulong or to remove the scene store. #if SCENE_MANAGEMENT_SCENE_HANDLE_MUST_USE_ULONG reader.ReadValueSafe(out ulong rawData); m_Handle = SceneHandle.FromRawData(rawData); @@ -87,6 +86,11 @@ internal NetworkSceneHandle(int handle, bool asMock) public int GetRawData() => m_Handle; #endif + public override string ToString() + { + return m_Handle.ToString(); + } + #region Implicit conversions #if SCENE_MANAGEMENT_SCENE_HANDLE_AVAILABLE /// diff --git a/com.unity.netcode.gameobjects/Runtime/SceneManagement/NetworkSceneManager.cs b/com.unity.netcode.gameobjects/Runtime/SceneManagement/NetworkSceneManager.cs index 2fbdf1fbe9..5cc5604e8d 100644 --- a/com.unity.netcode.gameobjects/Runtime/SceneManagement/NetworkSceneManager.cs +++ b/com.unity.netcode.gameobjects/Runtime/SceneManagement/NetworkSceneManager.cs @@ -2234,7 +2234,7 @@ private void SynchronizeNetworkObjectScene() // This is only done for dynamically spawned NetworkObjects // Theoretically, a server could have NetworkObjects in a server-side only scene, if the client doesn't have that scene loaded // then skip it (it will reside in the currently active scene in this scenario on the client-side) - if (networkObject.IsSceneObject.Value == false && ServerSceneHandleToClientSceneHandle.ContainsKey(networkObject.NetworkSceneHandle)) + if (!networkObject.InScenePlaced && ServerSceneHandleToClientSceneHandle.ContainsKey(networkObject.NetworkSceneHandle)) { networkObject.SceneOriginHandle = ServerSceneHandleToClientSceneHandle[networkObject.NetworkSceneHandle]; @@ -2709,7 +2709,7 @@ internal void MoveObjectsToDontDestroyOnLoad() if (!networkObject.DestroyWithScene) { // Only move dynamically spawned NetworkObjects with no parent as the children will follow - if (networkObject.gameObject.transform.parent == null && networkObject.IsSceneObject != null && !networkObject.IsSceneObject.Value) + if (networkObject.gameObject.transform.parent == null && !networkObject.InScenePlaced) { UnityEngine.Object.DontDestroyOnLoad(networkObject.gameObject); // When temporarily migrating to the DDOL, adjust the network and origin scene handles so no messages are generated @@ -2721,10 +2721,9 @@ internal void MoveObjectsToDontDestroyOnLoad() else if (networkObject.HasAuthority) { networkObject.SetIsDestroying(); - var isSceneObject = networkObject.IsSceneObject; // Only destroy non-scene placed NetworkObjects to avoid warnings about destroying in-scene placed NetworkObjects. // (MoveObjectsToDontDestroyOnLoad is only invoked during a scene event type of load and the load scene mode is single) - networkObject.Despawn(isSceneObject.HasValue && isSceneObject.Value == false); + networkObject.Despawn(!networkObject.InScenePlaced); } } } @@ -2745,19 +2744,18 @@ internal void PopulateScenePlacedObjects(Scene sceneToFilterBy, bool clearSceneP { ScenePlacedObjects.Clear(); } - var networkObjects = FindObjects.ByType(); + var sceneHandle = sceneToFilterBy.handle; // Just add every NetworkObject found that isn't already in the list // With additive scenes, we can have multiple in-scene placed NetworkObjects with the same GlobalObjectIdHash value // During Client Side Synchronization: We add them on a FIFO basis, for each scene loaded without clearing, and then // at the end of scene loading we use this list to soft synchronize all in-scene placed NetworkObjects - foreach (var networkObjectInstance in networkObjects) + foreach (var networkObjectInstance in FindObjects.FromSceneByType(sceneToFilterBy, false)) { var globalObjectIdHash = networkObjectInstance.GlobalObjectIdHash; - var sceneHandle = networkObjectInstance.gameObject.scene.handle; - // We check to make sure the NetworkManager instance is the same one to be "NetcodeIntegrationTestHelpers" compatible and filter the list on a per scene basis (for additive scenes) - if (networkObjectInstance.IsSceneObject != false && (networkObjectInstance.NetworkManager == NetworkManager || - networkObjectInstance.NetworkManagerOwner == null) && sceneHandle == sceneToFilterBy.handle) + // We check to make sure the NetworkManager instance is the same one to be "NetcodeIntegrationTestHelpers" compatible and filter the list on a per-scene basis (for additive scenes) + if (networkObjectInstance.InScenePlaced && (networkObjectInstance.NetworkManager == NetworkManager || + networkObjectInstance.NetworkManagerOwner == null)) { if (!ScenePlacedObjects.ContainsKey(globalObjectIdHash)) { @@ -2795,7 +2793,7 @@ internal void MoveObjectsFromDontDestroyOnLoadToScene(Scene scene) { // only move dynamically spawned network objects, with no parent as child objects will follow, // back into the currently active scene - if (networkObject.gameObject.transform.parent == null && networkObject.IsSceneObject != null && !networkObject.IsSceneObject.Value) + if (networkObject.gameObject.transform.parent == null && !networkObject.InScenePlaced) { if (NetworkManager.DistributedAuthorityMode) { @@ -2879,7 +2877,7 @@ internal void NotifyNetworkObjectSceneChanged(NetworkObject networkObject) } // Ignore in-scene placed NetworkObjects - if (networkObject.IsSceneObject != false) + if (networkObject.InScenePlaced) { // Really, this should ever happen but in case it does if (NetworkManager.LogLevel == LogLevel.Developer) diff --git a/com.unity.netcode.gameobjects/Runtime/SceneManagement/SceneEventData.cs b/com.unity.netcode.gameobjects/Runtime/SceneManagement/SceneEventData.cs index 0fff313574..9ab7ea7d86 100644 --- a/com.unity.netcode.gameobjects/Runtime/SceneManagement/SceneEventData.cs +++ b/com.unity.netcode.gameobjects/Runtime/SceneManagement/SceneEventData.cs @@ -133,7 +133,6 @@ internal class SceneEventData : IDisposable private List m_NetworkObjectsSync = new List(); private List m_DespawnedInSceneObjectsSync = new List(); - private Dictionary> m_DespawnedInSceneObjects = new Dictionary>(); /// /// Server Side Re-Synchronization: @@ -369,12 +368,11 @@ internal void AddDespawnedInSceneNetworkObjects() { m_DespawnedInSceneObjectsSync.Clear(); // Find all active and non-active in-scene placed NetworkObjects - var inSceneNetworkObjects = FindObjects.ByType(true, true).Where((c) => c.NetworkManager == m_NetworkManager); + var inSceneNetworkObjects = FindObjects.ByType(true, true); foreach (var sobj in inSceneNetworkObjects) { - if (sobj.IsSceneObject.HasValue && sobj.IsSceneObject.Value && !sobj.IsSpawned) + if (sobj.NetworkManager == m_NetworkManager && sobj.InScenePlaced && !sobj.IsSpawned) { - sobj.NetworkManagerOwner = m_NetworkManager; m_DespawnedInSceneObjectsSync.Add(sobj); } } @@ -1009,7 +1007,6 @@ internal void WriteClientSynchronizationResults(FastBufferWriter writer) private void DeserializeDespawnedInScenePlacedNetworkObjects() { // Process all de-spawned in-scene NetworkObjects for this network session - m_DespawnedInSceneObjects.Clear(); InternalBuffer.ReadValueSafe(out int despawnedObjectsCount); var sceneCache = new Dictionary>(); @@ -1018,25 +1015,21 @@ private void DeserializeDespawnedInScenePlacedNetworkObjects() // We just need to get the scene InternalBuffer.ReadValueSafe(out NetworkSceneHandle networkSceneHandle); InternalBuffer.ReadValueSafe(out uint globalObjectIdHash); - var sceneRelativeNetworkObjects = new Dictionary(); - if (!sceneCache.ContainsKey(networkSceneHandle)) + + // Check if we already have processed the objects in this scene + if (!sceneCache.TryGetValue(networkSceneHandle, out var sceneRelativeNetworkObjects)) { - if (m_NetworkManager.SceneManager.ServerSceneHandleToClientSceneHandle.ContainsKey(networkSceneHandle)) + // If we haven't already cached the objects in this scene, build the cache + sceneRelativeNetworkObjects = new Dictionary(); + if (m_NetworkManager.SceneManager.ServerSceneHandleToClientSceneHandle.TryGetValue(networkSceneHandle, out var localSceneHandle)) { - var localSceneHandle = m_NetworkManager.SceneManager.ServerSceneHandleToClientSceneHandle[networkSceneHandle]; - if (m_NetworkManager.SceneManager.ScenesLoaded.ContainsKey(localSceneHandle)) + if (m_NetworkManager.SceneManager.ScenesLoaded.TryGetValue(localSceneHandle, out var objectRelativeScene)) { - var objectRelativeScene = m_NetworkManager.SceneManager.ScenesLoaded[localSceneHandle]; - - // Find all active and non-active in-scene placed NetworkObjects - var inSceneNetworkObjects = FindObjects.ByType(true, true).Where((c) => - c.GetSceneOriginHandle() == localSceneHandle && (c.IsSceneObject != false)).ToList(); - - foreach (var inSceneObject in inSceneNetworkObjects) + foreach (var networkObject in FindObjects.FromSceneByType(objectRelativeScene, true)) { - if (!sceneRelativeNetworkObjects.ContainsKey(inSceneObject.GlobalObjectIdHash)) + if (networkObject.InScenePlaced) { - sceneRelativeNetworkObjects.Add(inSceneObject.GlobalObjectIdHash, inSceneObject); + sceneRelativeNetworkObjects.TryAdd(networkObject.GlobalObjectIdHash, networkObject); } } // Add this to a cache so we don't have to run this potentially multiple times (nothing will spawn or despawn during this time @@ -1052,10 +1045,6 @@ private void DeserializeDespawnedInScenePlacedNetworkObjects() UnityEngine.Debug.LogError($"In-Scene NetworkObject GlobalObjectIdHash ({globalObjectIdHash}) cannot find its relative NetworkSceneHandle {networkSceneHandle}!"); } } - else // Use the cached NetworkObjects if they exist - { - sceneRelativeNetworkObjects = sceneCache[networkSceneHandle]; - } // Now find the in-scene NetworkObject with the current GlobalObjectIdHash we are looking for if (sceneRelativeNetworkObjects.TryGetValue(globalObjectIdHash, out var despawnedObject)) @@ -1143,7 +1132,7 @@ internal void SynchronizeSceneNetworkObjects(NetworkManager networkManager) // Notify that all in-scene placed NetworkObjects have been spawned foreach (var networkObject in m_NetworkObjectsSync) { - if (networkObject.IsSceneObject.HasValue && networkObject.IsSceneObject.Value) + if (networkObject.IsSpawned && networkObject.InScenePlaced) { networkObject.InternalInSceneNetworkObjectsSpawned(); } diff --git a/com.unity.netcode.gameobjects/Runtime/Spawning/NetworkSpawnManager.cs b/com.unity.netcode.gameobjects/Runtime/Spawning/NetworkSpawnManager.cs index 52e891f8e1..fc5aed77b0 100644 --- a/com.unity.netcode.gameobjects/Runtime/Spawning/NetworkSpawnManager.cs +++ b/com.unity.netcode.gameobjects/Runtime/Spawning/NetworkSpawnManager.cs @@ -1319,11 +1319,15 @@ internal bool SpawnNetworkObjectLocallyCommon(NetworkObject networkObject, ulong return false; } - networkObject.IsSceneObject = sceneObject; +#pragma warning disable CS0618 // Type or member is obsolete + // Obsolete with warning means we need the underlying behaviour to keep existing + // TODO: remove in the 3.x branch + 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.IsSceneObject != false && networkObject.SceneOriginHandle.IsEmpty()) + if (networkObject.InScenePlaced && networkObject.SceneOriginHandle.IsEmpty()) { networkObject.SceneOrigin = networkObject.gameObject.scene; } @@ -1378,17 +1382,6 @@ internal bool SpawnNetworkObjectLocallyCommon(NetworkObject networkObject, ulong networkObject.InvokeBehaviourNetworkSpawn(); - // propagate the IsSceneObject setting to child NetworkObjects - var children = networkObject.GetComponentsInChildren(); - foreach (var childObject in children) - { - // Do not propagate the in-scene object setting if a child was dynamically spawned. - if (childObject.IsSceneObject.HasValue && !childObject.IsSceneObject.Value) - { - continue; - } - childObject.IsSceneObject = sceneObject; - } // Only dynamically spawned NetworkObjects are allowed if (!sceneObject) @@ -1403,7 +1396,7 @@ internal bool SpawnNetworkObjectLocallyCommon(NetworkObject networkObject, ulong // If we are an in-scene placed NetworkObject and our InScenePlacedSourceGlobalObjectIdHash is set // then assign this to the PrefabGlobalObjectIdHash - if (networkObject.IsSceneObject.Value && networkObject.InScenePlacedSourceGlobalObjectIdHash != 0) + if (networkObject.InScenePlaced && networkObject.InScenePlacedSourceGlobalObjectIdHash != 0) { networkObject.PrefabGlobalObjectIdHash = networkObject.InScenePlacedSourceGlobalObjectIdHash; } @@ -1551,14 +1544,17 @@ internal void DespawnObject(NetworkObject networkObject, bool destroyObject = fa } // Makes scene objects ready to be reused - internal void ServerResetShudownStateForSceneObjects() + internal void ServerResetShutdownStateForSceneObjects() { - var networkObjects = FindObjects.ByType(orderByIdentifier: true).Where((c) => c.IsSceneObject != null && c.IsSceneObject == true); + var networkObjects = FindObjects.ByType(orderByIdentifier: true, includeInactive: true); foreach (var sobj in networkObjects) { + if (!sobj.InScenePlaced) + { + continue; + } sobj.IsSpawned = false; sobj.DestroyWithScene = false; - sobj.IsSceneObject = null; } } @@ -1574,7 +1570,7 @@ internal void ServerDestroySpawnedSceneObjects() foreach (var networkObject in spawnedObjects) { - if (networkObject.IsSceneObject != null && networkObject.IsSceneObject.Value && networkObject.DestroyWithScene + if (networkObject.InScenePlaced && networkObject.DestroyWithScene && networkObject.gameObject.scene != NetworkManager.SceneManager.DontDestroyOnLoadScene) { if (networkObject.IsSpawned && networkObject.HasAuthority) @@ -1618,7 +1614,7 @@ internal void DespawnAndDestroyNetworkObjects() { // If it is an in-scene placed NetworkObject then just despawn and let it be destroyed when the scene // is unloaded. Otherwise, despawn and destroy it. - var shouldDestroy = !(networkObject.IsSceneObject == null || (networkObject.IsSceneObject != null && networkObject.IsSceneObject.Value)); + var shouldDestroy = !networkObject.InScenePlaced; // If we are going to destroy this NetworkObject, check for any in-scene placed children that need to be removed if (shouldDestroy) @@ -1634,7 +1630,7 @@ internal void DespawnAndDestroyNetworkObjects() // If the child is an in-scene placed NetworkObject then remove the child from the parent (which was dynamically spawned) // and set its parent to root - if (childObject.IsSceneObject != null && childObject.IsSceneObject.Value) + if (childObject.InScenePlaced) { childObject.TryRemoveParentCachedWorldPositionStays(); } @@ -1653,27 +1649,24 @@ internal void DestroySceneObjects() for (int i = 0; i < networkObjects.Length; i++) { - if (networkObjects[i].NetworkManager == NetworkManager) + if (networkObjects[i].NetworkManager == NetworkManager && networkObjects[i].InScenePlaced) { - if (networkObjects[i].IsSceneObject == null || networkObjects[i].IsSceneObject.Value == true) + if (NetworkManager.PrefabHandler.ContainsHandler(networkObjects[i])) { - if (NetworkManager.PrefabHandler.ContainsHandler(networkObjects[i])) + if (SpawnedObjects.ContainsKey(networkObjects[i].NetworkObjectId)) { - if (SpawnedObjects.ContainsKey(networkObjects[i].NetworkObjectId)) - { - // This method invokes HandleNetworkPrefabDestroy, we only want to handle this once. - OnDespawnObject(networkObjects[i], false); - } - else // If not spawned, then just invoke the handler - { - NetworkManager.PrefabHandler.HandleNetworkPrefabDestroy(networkObjects[i]); - } + // This method invokes HandleNetworkPrefabDestroy, we only want to handle this once. + OnDespawnObject(networkObjects[i], false); } - else + else // If not spawned, then just invoke the handler { - Object.Destroy(networkObjects[i].gameObject); + NetworkManager.PrefabHandler.HandleNetworkPrefabDestroy(networkObjects[i]); } } + else + { + Object.Destroy(networkObjects[i].gameObject); + } } } } @@ -1692,7 +1685,7 @@ internal void ServerSpawnSceneObjectsOnStartSweep() // This used to be two loops. // The first added all NetworkObjects to a list and the second spawned all NetworkObjects in the list. // Now, a parent will set its children's IsSceneObject value when spawned, so we check for null or for true. - if (networkObject.IsSceneObject == null || (networkObject.IsSceneObject.HasValue && networkObject.IsSceneObject.Value)) + if (networkObject.InScenePlaced) { var ownerId = networkObject.OwnerClientId; if (NetworkManager.DistributedAuthorityMode) @@ -1743,7 +1736,7 @@ internal void OnDespawnNonAuthorityObject([NotNull] NetworkObject networkObject, } } - if (networkObject.IsSceneObject == false) + if (!networkObject.InScenePlaced) { // If the object is not an in-scene placed NetworkObject, then we always destroy the object on the non-authority side destroyGameObject = true; @@ -1785,7 +1778,7 @@ internal void OnDespawnObject([NotNull] NetworkObject networkObject, bool destro // DistributedAuthorityMode: All clients need to remove the parent locally due to mixed-authority hierarchies and race-conditions if (!NetworkManager.ShutdownInProgress && (NetworkManager.IsServer || distributedAuthority)) { - if (destroyGameObject && networkObject.IsSceneObject == true && !NetworkManager.SceneManager.IsSceneUnloading(networkObject)) + if (destroyGameObject && networkObject.InScenePlaced && !NetworkManager.SceneManager.IsSceneUnloading(networkObject)) { if (NetworkManager.LogLevel <= LogLevel.Normal) { @@ -2112,7 +2105,7 @@ internal void GetObjectDistribution(ulong clientId, ref Dictionary(); networkObject.IsSpawned = true; networkObject.SceneOriginHandle = default; - networkObject.IsSceneObject = false; // 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(); diff --git a/com.unity.netcode.gameobjects/Tests/Runtime/NetworkObject/NetworkObjectSpawnManyObjectsTests.cs b/com.unity.netcode.gameobjects/Tests/Runtime/NetworkObject/NetworkObjectSpawnManyObjectsTests.cs index cf786bd0c4..ad643d7ca7 100644 --- a/com.unity.netcode.gameobjects/Tests/Runtime/NetworkObject/NetworkObjectSpawnManyObjectsTests.cs +++ b/com.unity.netcode.gameobjects/Tests/Runtime/NetworkObject/NetworkObjectSpawnManyObjectsTests.cs @@ -37,7 +37,6 @@ protected override void OnServerAndClientsCreated() var gameObject = new GameObject("TestObject"); var networkObject = gameObject.AddComponent(); NetcodeIntegrationTestHelpers.MakeNetworkObjectTestPrefab(networkObject); - networkObject.IsSceneObject = false; gameObject.AddComponent(); m_PrefabToSpawn = new NetworkPrefab() { Prefab = gameObject }; diff --git a/com.unity.netcode.gameobjects/Tests/Runtime/NetworkVariable/NetworkVariableBaseInitializesWhenPersisted.cs b/com.unity.netcode.gameobjects/Tests/Runtime/NetworkVariable/NetworkVariableBaseInitializesWhenPersisted.cs index 0245602fcd..6e8dc8cde9 100644 --- a/com.unity.netcode.gameobjects/Tests/Runtime/NetworkVariable/NetworkVariableBaseInitializesWhenPersisted.cs +++ b/com.unity.netcode.gameobjects/Tests/Runtime/NetworkVariable/NetworkVariableBaseInitializesWhenPersisted.cs @@ -26,7 +26,6 @@ protected override void OnOneTimeSetup() s_NetworkPrefab = new GameObject("PresistPrefab"); var networkObject = s_NetworkPrefab.AddComponent(); networkObject.GlobalObjectIdHash = 8888888; - networkObject.SetSceneObjectStatus(false); s_NetworkPrefab.AddComponent(); s_NetworkPrefab.AddComponent(); // Create enough prefab instance handlers to be re-used for all tests. @@ -374,7 +373,6 @@ public NetworkObject GetInstance() if (PrefabInstances.Count == 0) { instanceToReturn = Object.Instantiate(m_NetworkPrefab).GetComponent(); - instanceToReturn.SetSceneObjectStatus(false); instanceToReturn.gameObject.SetActive(true); } else diff --git a/com.unity.netcode.gameobjects/Tests/Runtime/Prefabs/NetworkPrefabOverrideTests.cs b/com.unity.netcode.gameobjects/Tests/Runtime/Prefabs/NetworkPrefabOverrideTests.cs index 502146fa24..571ab30133 100644 --- a/com.unity.netcode.gameobjects/Tests/Runtime/Prefabs/NetworkPrefabOverrideTests.cs +++ b/com.unity.netcode.gameobjects/Tests/Runtime/Prefabs/NetworkPrefabOverrideTests.cs @@ -174,11 +174,6 @@ protected override void OnServerAndClientsCreated() networkManager.NetworkConfig.Prefabs.Add(m_ClientSidePlayerPrefab); } - m_PrefabOverride.Prefab.GetComponent().IsSceneObject = false; - m_PrefabOverride.SourcePrefabToOverride.GetComponent().IsSceneObject = false; - m_PrefabOverride.OverridingTargetPrefab.GetComponent().IsSceneObject = false; - m_ClientSidePlayerPrefab.Prefab.GetComponent().IsSceneObject = false; - base.OnServerAndClientsCreated(); } diff --git a/com.unity.netcode.gameobjects/Tests/Runtime/TestHelpers/IntegrationTestSceneHandler.cs b/com.unity.netcode.gameobjects/Tests/Runtime/TestHelpers/IntegrationTestSceneHandler.cs index 2a5c2c35f9..209caf300b 100644 --- a/com.unity.netcode.gameobjects/Tests/Runtime/TestHelpers/IntegrationTestSceneHandler.cs +++ b/com.unity.netcode.gameobjects/Tests/Runtime/TestHelpers/IntegrationTestSceneHandler.cs @@ -1,7 +1,6 @@ using System; using System.Collections; using System.Collections.Generic; -using System.Linq; using UnityEngine; using UnityEngine.SceneManagement; using Object = UnityEngine.Object; @@ -141,47 +140,27 @@ private static void SceneManager_sceneLoaded(Scene scene, LoadSceneMode loadScen { SceneManager.sceneLoaded -= SceneManager_sceneLoaded; - ProcessInSceneObjects(scene, CurrentQueuedSceneJob.IntegrationTestSceneHandler.NetworkManager); + ProcessInSceneObjects(scene); CurrentQueuedSceneJob.JobType = QueuedSceneJob.JobTypes.Completed; } } /// - /// Handles some pre-spawn processing of in-scene placed NetworkObjects - /// to make sure the appropriate NetworkManagerOwner is assigned. It - /// also makes sure that each in-scene placed NetworkObject has an + /// Handles some pre-spawn processing of in-scene placed NetworkObjects. + /// Makes sure that each in-scene placed NetworkObject has an /// ObjectIdentifier component if one is not assigned to it or its /// children. /// /// the scenes that was just loaded - /// the relative NetworkManager - private static void ProcessInSceneObjects(Scene scene, NetworkManager networkManager) + private static void ProcessInSceneObjects(Scene scene) { - // Get all in-scene placed NeworkObjects that were instantiated when this scene loaded - var inSceneNetworkObjects = FindObjects.ByType(orderByIdentifier: true).Where((c) => c.IsSceneObject != false && c.GetSceneOriginHandle() == scene.handle); - foreach (var sobj in inSceneNetworkObjects) + // Get all in-scene placed NetworkObjects that were instantiated when this scene loaded + foreach (var sceneObject in FindObjects.FromSceneByType(scene, false)) { - ProcessInSceneObject(sobj, networkManager); - } - } - - /// - /// Assures to apply an ObjectNameIdentifier to all children - /// - private static void ProcessInSceneObject(NetworkObject networkObject, NetworkManager networkManager) - { - if (networkObject.GetComponent() == null) - { - networkObject.gameObject.AddComponent(); - var networkObjects = networkObject.gameObject.GetComponentsInChildren(); - foreach (var child in networkObjects) + if (sceneObject.InScenePlaced && sceneObject.GetComponent() == null) { - if (child == networkObject) - { - continue; - } - ProcessInSceneObject(child, networkManager); + sceneObject.gameObject.AddComponent(); } } } @@ -288,7 +267,7 @@ private void Sever_SceneLoaded(Scene scene, LoadSceneMode arg1) if (m_ServerSceneBeingLoaded == scene.name) { SceneManager.sceneLoaded -= Sever_SceneLoaded; - ProcessInSceneObjects(scene, NetworkManager); + ProcessInSceneObjects(scene); } } @@ -708,16 +687,11 @@ public void MoveObjectsFromSceneToDontDestroyOnLoad(ref NetworkManager networkMa { // Create a local copy of the spawned objects list since the spawn manager will adjust the list as objects // are despawned. - var networkObjects = FindObjects.ByType(orderByIdentifier: true).Where((c) => c.IsSpawned); var distributedAuthority = networkManager.DistributedAuthorityMode; - foreach (var networkObject in networkObjects) + foreach (var networkObject in FindObjects.FromSceneByType(scene, false)) { - if (networkObject == null || (networkObject != null && networkObject.gameObject.scene.handle != scene.handle)) + if (!networkObject.IsSpawned) { - if (networkObject != null) - { - VerboseDebug($"[MoveObjects from {scene.name} | {scene.handle}] Ignoring {networkObject.gameObject.name} because it isn't in scene {networkObject.gameObject.scene.name} "); - } continue; } @@ -750,7 +724,7 @@ public void MoveObjectsFromSceneToDontDestroyOnLoad(ref NetworkManager networkMa if (!networkObject.DestroyWithScene && networkObject.gameObject.scene != networkManager.SceneManager.DontDestroyOnLoadScene) { // Only move dynamically spawned NetworkObjects with no parent as the children will follow - if (networkObject.gameObject.transform.parent == null && networkObject.IsSceneObject != null && !networkObject.IsSceneObject.Value) + if (networkObject.gameObject.transform.parent == null && !networkObject.InScenePlaced) { VerboseDebug($"[MoveObjects from {scene.name} | {scene.handle}] Moving {networkObject.gameObject.name} because it is in scene {networkObject.gameObject.scene.name} with DWS = {networkObject.DestroyWithScene}."); Object.DontDestroyOnLoad(networkObject.gameObject); diff --git a/com.unity.netcode.gameobjects/Tests/Runtime/TestHelpers/NetcodeIntegrationTest.cs b/com.unity.netcode.gameobjects/Tests/Runtime/TestHelpers/NetcodeIntegrationTest.cs index a6f4a83275..b9c5623759 100644 --- a/com.unity.netcode.gameobjects/Tests/Runtime/TestHelpers/NetcodeIntegrationTest.cs +++ b/com.unity.netcode.gameobjects/Tests/Runtime/TestHelpers/NetcodeIntegrationTest.cs @@ -728,7 +728,6 @@ private void CreatePlayerPrefab() m_PlayerPrefab = new GameObject("Player"); OnPlayerPrefabGameObjectCreated(); NetworkObject networkObject = m_PlayerPrefab.AddComponent(); - networkObject.IsSceneObject = false; // Make it a prefab NetcodeIntegrationTestHelpers.MakeNetworkObjectTestPrefab(networkObject); diff --git a/com.unity.netcode.gameobjects/Tests/Runtime/TestHelpers/NetcodeIntegrationTestHelpers.cs b/com.unity.netcode.gameobjects/Tests/Runtime/TestHelpers/NetcodeIntegrationTestHelpers.cs index 32a0f734d7..99c7f47afc 100644 --- a/com.unity.netcode.gameobjects/Tests/Runtime/TestHelpers/NetcodeIntegrationTestHelpers.cs +++ b/com.unity.netcode.gameobjects/Tests/Runtime/TestHelpers/NetcodeIntegrationTestHelpers.cs @@ -690,9 +690,6 @@ public static void MakeNetworkObjectTestPrefab(NetworkObject networkObject, uint networkObject.GlobalObjectIdHash = ++s_AutoIncrementGlobalObjectIdHashCounter; } - // Prevent object from being snapped up as a scene object - networkObject.IsSceneObject = false; - // To avoid issues with integration tests that forget to clean up, // this feature only works with NetcodeIntegrationTest derived classes if (IsNetcodeIntegrationTestRunning) diff --git a/testproject/Assets/Tests/Runtime/NetworkManagerTests.cs b/testproject/Assets/Tests/Runtime/NetworkManagerTests.cs index 411d7e6fec..ccf46cb61c 100644 --- a/testproject/Assets/Tests/Runtime/NetworkManagerTests.cs +++ b/testproject/Assets/Tests/Runtime/NetworkManagerTests.cs @@ -155,7 +155,7 @@ public IEnumerator ValidateShutdown([Values] ShutdownChecks shutdownCheck) for (int i = spawnedObjects.Count - 1; i >= 0; i--) { var spawnedObject = spawnedObjects[i]; - if (spawnedObject.IsSceneObject != null && spawnedObject.IsSceneObject.Value) + if (spawnedObject.InScenePlaced) { spawnedObject.Despawn(); } diff --git a/testproject/Assets/Tests/Runtime/NetworkSceneManager/AttachableBehaviourSceneLoadTests.cs b/testproject/Assets/Tests/Runtime/NetworkSceneManager/AttachableBehaviourSceneLoadTests.cs index 58d056d8d0..a3e31983e1 100644 --- a/testproject/Assets/Tests/Runtime/NetworkSceneManager/AttachableBehaviourSceneLoadTests.cs +++ b/testproject/Assets/Tests/Runtime/NetworkSceneManager/AttachableBehaviourSceneLoadTests.cs @@ -318,7 +318,7 @@ public IEnumerator AttachedUponSceneTransition([Values] bool detachOnDespawn) var persists = m_Persists == Persists.AttachableNode ? m_TargetInstance.NetworkObjectId : m_SourceInstance.NetworkObjectId; m_DoesNotPersistNetworkObjectIds.Add(doesNotPersist); persistedObjects.Add(networkManager, persists); - Debug.Log($"[{networkManager.name}] Spawned attachable and attached it."); + VerboseDebug($"[{networkManager.name}] Spawned attachable and attached it."); } // This is the actual validation point where the scene is unloaded and either the attachable or diff --git a/testproject/Assets/Tests/Runtime/NetworkSceneManager/ClientSynchronizationValidationTest.cs b/testproject/Assets/Tests/Runtime/NetworkSceneManager/ClientSynchronizationValidationTest.cs index 32f88e9221..ea5dfc47ad 100644 --- a/testproject/Assets/Tests/Runtime/NetworkSceneManager/ClientSynchronizationValidationTest.cs +++ b/testproject/Assets/Tests/Runtime/NetworkSceneManager/ClientSynchronizationValidationTest.cs @@ -110,7 +110,7 @@ public IEnumerator ClientVerifySceneBeforeLoading([Values] bool startClientBefor foreach (var spawnedObjectEntry in m_ServerNetworkManager.SpawnManager.SpawnedObjects) { var networkObject = spawnedObjectEntry.Value; - if (!networkObject.IsSceneObject.Value) + if (!networkObject.InScenePlaced) { continue; } @@ -138,7 +138,7 @@ public IEnumerator ClientVerifySceneBeforeLoading([Values] bool startClientBefor foreach (var spawnedObjectEntry in m_ServerNetworkManager.SpawnManager.SpawnedObjects) { var networkObject = spawnedObjectEntry.Value; - if (!networkObject.IsSceneObject.Value) + if (!networkObject.InScenePlaced) { continue; } diff --git a/testproject/Assets/Tests/Runtime/NetworkSceneManager/NetworkSceneManagerDDOLTests.cs b/testproject/Assets/Tests/Runtime/NetworkSceneManager/NetworkSceneManagerDDOLTests.cs index f38a311ea8..70ca7c24d2 100644 --- a/testproject/Assets/Tests/Runtime/NetworkSceneManager/NetworkSceneManagerDDOLTests.cs +++ b/testproject/Assets/Tests/Runtime/NetworkSceneManager/NetworkSceneManagerDDOLTests.cs @@ -94,8 +94,8 @@ public IEnumerator InSceneNetworkObjectState([Values(DefaultState.IsEnabled, Def [Values(NetworkObjectType.InScenePlaced, NetworkObjectType.DynamicallySpawned)] NetworkObjectType networkObjectType) { var waitForFullNetworkTick = new WaitForSeconds(1.0f / m_ServerNetworkManager.NetworkConfig.TickRate); - var isActive = activeState == DefaultState.IsEnabled ? true : false; - var isInScene = networkObjectType == NetworkObjectType.InScenePlaced ? true : false; + var isActive = activeState == DefaultState.IsEnabled; + var isInScene = networkObjectType == NetworkObjectType.InScenePlaced; var objectInstance = Object.Instantiate(m_DDOL_ObjectToSpawn); var networkObject = objectInstance.GetComponent(); @@ -110,7 +110,7 @@ public IEnumerator InSceneNetworkObjectState([Values(DefaultState.IsEnabled, Def } // Sets whether we are in-scene or dynamically spawned NetworkObject - ddolBehaviour.SetInScene(isInScene); + networkObject.InScenePlaced = isInScene; networkObject.Spawn(); yield return waitForFullNetworkTick; @@ -148,12 +148,6 @@ public override void OnNetworkSpawn() NetworkObject.DestroyWithScene = false; base.OnNetworkSpawn(); } - - public void SetInScene(bool isInScene) - { - var networkObject = GetComponent(); - networkObject.IsSceneObject = isInScene; - } } } diff --git a/testproject/Assets/Tests/Runtime/NetworkSceneManager/NetworkSceneManagerEventDataPoolTest.cs b/testproject/Assets/Tests/Runtime/NetworkSceneManager/NetworkSceneManagerEventDataPoolTest.cs index 7c448830f6..107db75314 100644 --- a/testproject/Assets/Tests/Runtime/NetworkSceneManager/NetworkSceneManagerEventDataPoolTest.cs +++ b/testproject/Assets/Tests/Runtime/NetworkSceneManager/NetworkSceneManagerEventDataPoolTest.cs @@ -381,11 +381,11 @@ private bool CheckNetworkObjectsToSynchronizeSceneChanges(NetworkManager network m_ErrorMsg.Clear(); if (networkManager.SpawnManager.NetworkObjectsToSynchronizeSceneChanges.Count > 0) { - foreach (var entry in networkManager.SpawnManager.NetworkObjectsToSynchronizeSceneChanges) + foreach (var obj in networkManager.SpawnManager.NetworkObjectsToSynchronizeSceneChanges.Values) { - if (entry.Value.IsSceneObject.HasValue && entry.Value.IsSceneObject.Value) + if (obj.InScenePlaced) { - m_ErrorMsg.AppendLine($"{entry.Value.name} still exists within {nameof(NetworkSpawnManager.NetworkObjectsToSynchronizeSceneChanges)}!"); + m_ErrorMsg.AppendLine($"{obj.name} still exists within {nameof(NetworkSpawnManager.NetworkObjectsToSynchronizeSceneChanges)}!"); } } } diff --git a/testproject/Assets/Tests/Runtime/NetworkSceneManager/NetworkSceneManagerPopulateInSceneTests.cs b/testproject/Assets/Tests/Runtime/NetworkSceneManager/NetworkSceneManagerPopulateInSceneTests.cs index bc3a24cb78..1d2302592e 100644 --- a/testproject/Assets/Tests/Runtime/NetworkSceneManager/NetworkSceneManagerPopulateInSceneTests.cs +++ b/testproject/Assets/Tests/Runtime/NetworkSceneManager/NetworkSceneManagerPopulateInSceneTests.cs @@ -40,7 +40,7 @@ protected override void OnServerAndClientsCreated() // the scene is loaded (i.e. IsSceneObject is null) var inScenePrefab = CreateNetworkObjectPrefab("NewSceneObject"); var networkObject = inScenePrefab.GetComponent(); - networkObject.IsSceneObject = null; + networkObject.InScenePlaced = true; networkObject.NetworkManagerOwner = m_ServerNetworkManager; m_InSceneObjectList.Add(networkObject.GlobalObjectIdHash, inScenePrefab); @@ -49,7 +49,7 @@ protected override void OnServerAndClientsCreated() // unloading/reloading any scenes. inScenePrefab = CreateNetworkObjectPrefab("SetInSceneObject"); networkObject = inScenePrefab.GetComponent(); - networkObject.IsSceneObject = true; + networkObject.InScenePlaced = true; networkObject.NetworkManagerOwner = m_ServerNetworkManager; m_InSceneObjectList.Add(networkObject.GlobalObjectIdHash, inScenePrefab); } diff --git a/testproject/Assets/Tests/Runtime/ObjectParenting/ParentDynamicUnderInScenePlaced.cs b/testproject/Assets/Tests/Runtime/ObjectParenting/ParentDynamicUnderInScenePlaced.cs index 3bf12e7011..2770ed4ce5 100644 --- a/testproject/Assets/Tests/Runtime/ObjectParenting/ParentDynamicUnderInScenePlaced.cs +++ b/testproject/Assets/Tests/Runtime/ObjectParenting/ParentDynamicUnderInScenePlaced.cs @@ -74,7 +74,7 @@ private bool TestParentedAndNotInScenePlaced() { // Always assign m_FailedValidation to avoid possible null reference crashes. var serverPlayer = m_FailedValidation = m_ServerNetworkManager.LocalClient.PlayerObject; - if (serverPlayer.transform.parent == null || serverPlayer.IsSceneObject.Value == true) + if (serverPlayer.transform.parent == null || serverPlayer.InScenePlaced) { m_FailedValidation = serverPlayer; return false; @@ -83,7 +83,7 @@ private bool TestParentedAndNotInScenePlaced() foreach (var clientNetworkManager in m_ClientNetworkManagers) { var lateJoinPlayer = clientNetworkManager.LocalClient.PlayerObject; - if (lateJoinPlayer.transform.parent == null || lateJoinPlayer.IsSceneObject.Value == true) + if (lateJoinPlayer.transform.parent == null || lateJoinPlayer.InScenePlaced) { m_FailedValidation = lateJoinPlayer; return false; @@ -93,7 +93,7 @@ private bool TestParentedAndNotInScenePlaced() foreach (var dynamicallySpawned in ParentDynamicUnderInScenePlacedHelper.Instances) { var networkObject = dynamicallySpawned.Value; - if (networkObject.transform.parent == null || networkObject.IsSceneObject.Value == true) + if (networkObject.transform.parent == null || networkObject.InScenePlaced) { m_FailedValidation = networkObject; return false; @@ -124,7 +124,7 @@ public IEnumerator ParentUnderInSceneplaced() // Wait for the host-server's player to be parented under the in-scene placed NetworkObject yield return WaitForConditionOrTimeOut(TestParentedAndNotInScenePlaced); - AssertOnTimeout($"[{m_FailedValidation.name}] Failed validation! InScenePlaced ({m_FailedValidation.IsSceneObject.Value}) | Was Parented ({m_FailedValidation.transform.position != null})"); + AssertOnTimeout($"[{m_FailedValidation.name}] Failed validation! InScenePlaced ({m_FailedValidation.InScenePlaced}) | Was Parented ({m_FailedValidation.transform.position != null})"); m_TargetScenePlacedId = m_ServerNetworkManager.LocalClient.PlayerObject.transform.parent.GetComponent().NetworkObjectId; // Now dynamically spawn a NetworkObject to also test dynamically spawned NetworkObjects being parented @@ -141,7 +141,7 @@ public IEnumerator ParentUnderInSceneplaced() AssertOnTimeout($"[Client-{i + 1}] Failed to find in-scene placed NetworkObject or failed to parent under it!"); } yield return WaitForConditionOrTimeOut(TestParentedAndNotInScenePlaced); - AssertOnTimeout($"[{m_FailedValidation.name}] Failed validation! InScenePlaced ({m_FailedValidation.IsSceneObject.Value}) | Was Parented ({m_FailedValidation.transform.position != null})"); + AssertOnTimeout($"[{m_FailedValidation.name}] Failed validation! InScenePlaced ({m_FailedValidation.InScenePlaced}) | Was Parented ({m_FailedValidation.transform.position != null})"); } } diff --git a/testproject/Assets/Tests/Runtime/PrefabExtendedTests.cs b/testproject/Assets/Tests/Runtime/PrefabExtendedTests.cs index d0f7e294cb..909bb7585d 100644 --- a/testproject/Assets/Tests/Runtime/PrefabExtendedTests.cs +++ b/testproject/Assets/Tests/Runtime/PrefabExtendedTests.cs @@ -163,7 +163,7 @@ private bool ValidateAllClientsSpawnedObjects() var clientSpawnedObject = s_GlobalNetworkObjects[client.LocalClientId][spawnedObject.NetworkObjectId]; // When scene management is disabled, we match against the InScenePlacedSourceGlobalObjectIdHash for in-scene placed NetworkObjects - var spawnedObjectGlobalObjectIdHash = !m_SceneManagementEnabled && spawnedObject.IsSceneObject.Value ? spawnedObject.InScenePlacedSourceGlobalObjectIdHash : spawnedObject.GlobalObjectIdHash; + var spawnedObjectGlobalObjectIdHash = !m_SceneManagementEnabled && spawnedObject.InScenePlaced ? spawnedObject.InScenePlacedSourceGlobalObjectIdHash : spawnedObject.GlobalObjectIdHash; // Validate the GlobalObjectIdHash values match if (clientSpawnedObject.GlobalObjectIdHash != spawnedObjectGlobalObjectIdHash) { From fc2baa4e232685ea8412fbf3fe7264c347a74d57 Mon Sep 17 00:00:00 2001 From: Emma Date: Mon, 25 May 2026 18:59:15 -0400 Subject: [PATCH 2/4] Add XML doc --- .../Editor/InScenePlacedPrefab.cs | 32 ------------- .../Editor/InScenePlacedPrefab.cs.meta | 3 -- .../Editor/InScenePlacedProcessor.cs | 45 +++++++++++++++++++ .../Editor/InScenePlacedProcessor.cs.meta | 2 + .../Runtime/Core/NetworkObject.cs | 3 ++ 5 files changed, 50 insertions(+), 35 deletions(-) delete mode 100644 com.unity.netcode.gameobjects/Editor/InScenePlacedPrefab.cs delete mode 100644 com.unity.netcode.gameobjects/Editor/InScenePlacedPrefab.cs.meta create mode 100644 com.unity.netcode.gameobjects/Editor/InScenePlacedProcessor.cs create mode 100644 com.unity.netcode.gameobjects/Editor/InScenePlacedProcessor.cs.meta diff --git a/com.unity.netcode.gameobjects/Editor/InScenePlacedPrefab.cs b/com.unity.netcode.gameobjects/Editor/InScenePlacedPrefab.cs deleted file mode 100644 index f7613985ae..0000000000 --- a/com.unity.netcode.gameobjects/Editor/InScenePlacedPrefab.cs +++ /dev/null @@ -1,32 +0,0 @@ -using UnityEditor; -using UnityEditor.Build; -using UnityEditor.Build.Reporting; -using UnityEngine; -using UnityEngine.SceneManagement; - -namespace Unity.Netcode.Editor -{ - public class InScenePlacedPrefab : IProcessSceneWithReport - { - public int callbackOrder => 0; - public void OnProcessScene(Scene scene, BuildReport report) - { - foreach (var networkObject in FindObjects.FromSceneByType(scene, true)) - { - networkObject.InScenePlaced = true; - } - } - } - - public class InScenePlacedPrefabBuilder : AssetPostprocessor - { - public void OnPostprocessPrefab(GameObject root) - { - var networkObjects = root.GetComponentsInChildren(true); - foreach (var networkObject in networkObjects) - { - networkObject.InScenePlaced = false; - } - } - } -} diff --git a/com.unity.netcode.gameobjects/Editor/InScenePlacedPrefab.cs.meta b/com.unity.netcode.gameobjects/Editor/InScenePlacedPrefab.cs.meta deleted file mode 100644 index 397923e850..0000000000 --- a/com.unity.netcode.gameobjects/Editor/InScenePlacedPrefab.cs.meta +++ /dev/null @@ -1,3 +0,0 @@ -fileFormatVersion: 2 -guid: e9b29e08242545899dfb65e4fb568beb -timeCreated: 1779219564 diff --git a/com.unity.netcode.gameobjects/Editor/InScenePlacedProcessor.cs b/com.unity.netcode.gameobjects/Editor/InScenePlacedProcessor.cs new file mode 100644 index 0000000000..423ff4a65c --- /dev/null +++ b/com.unity.netcode.gameobjects/Editor/InScenePlacedProcessor.cs @@ -0,0 +1,45 @@ +using UnityEditor; +using UnityEditor.Build; +using UnityEditor.Build.Reporting; +using UnityEngine; +using UnityEngine.SceneManagement; + +namespace Unity.Netcode.Editor +{ + /// + /// A that sets the property to true for all s in the scene. + /// Ensures that InScenePlaced is always true for all objects in the scene. + /// + /// + /// This will always run as the game enters the scene, + /// + internal class SetInScenePlaced : IProcessSceneWithReport + { + public int callbackOrder => 0; + public void OnProcessScene(Scene scene, BuildReport report) + { + foreach (var networkObject in FindObjects.FromSceneByType(scene, true)) + { + networkObject.InScenePlaced = true; + } + } + } + + /// + /// An that sets the property to false for all s in prefabs. + /// Ensures that InScenePlaced is always false for all prefab objects. + /// This is important because when a prefab is instantiated in the scene, it should be treated as a dynamically spawned object. + /// + internal class InScenePlacedPrefabBuilder : AssetPostprocessor + { + public void OnPostprocessPrefab(GameObject root) + { + var networkObjects = root.GetComponentsInChildren(true); + foreach (var networkObject in networkObjects) + { + networkObject.InScenePlaced = false; + } + } + } +} diff --git a/com.unity.netcode.gameobjects/Editor/InScenePlacedProcessor.cs.meta b/com.unity.netcode.gameobjects/Editor/InScenePlacedProcessor.cs.meta new file mode 100644 index 0000000000..784aa38575 --- /dev/null +++ b/com.unity.netcode.gameobjects/Editor/InScenePlacedProcessor.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: cda0fb70bdcd545a7983ca78f516bcff \ No newline at end of file diff --git a/com.unity.netcode.gameobjects/Runtime/Core/NetworkObject.cs b/com.unity.netcode.gameobjects/Runtime/Core/NetworkObject.cs index 7132b59e08..173d7fba8d 100644 --- a/com.unity.netcode.gameobjects/Runtime/Core/NetworkObject.cs +++ b/com.unity.netcode.gameobjects/Runtime/Core/NetworkObject.cs @@ -1235,6 +1235,9 @@ private bool InternalHasAuthority() [Obsolete("Use InScenePlaced instead")] public bool? IsSceneObject { get; internal set; } + /// + /// True if this object is placed in a scene; false otherwise. + /// [field: HideInInspector] [field: SerializeField] public bool InScenePlaced { get; internal set; } From 0de522232e07d36b32aa9694cb75b4a2a09f0a1f Mon Sep 17 00:00:00 2001 From: Emma Date: Mon, 25 May 2026 19:08:05 -0400 Subject: [PATCH 3/4] Update small files --- com.unity.netcode.gameobjects/CHANGELOG.md | 1 + com.unity.netcode.gameobjects/package.json | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/com.unity.netcode.gameobjects/CHANGELOG.md b/com.unity.netcode.gameobjects/CHANGELOG.md index 06ebf2c108..cc261b6aec 100644 --- a/com.unity.netcode.gameobjects/CHANGELOG.md +++ b/com.unity.netcode.gameobjects/CHANGELOG.md @@ -18,6 +18,7 @@ Additional documentation and release notes are available at [Multiplayer Documen ### Deprecated +- Deprecated the nullable boolean `NetworkObject.IsSceneObject` and introduced `NetworkObject.InScenePlaced`. (#4000) - Deprecated a number of methods that were no longer valid or being used. (#3987) ### Removed diff --git a/com.unity.netcode.gameobjects/package.json b/com.unity.netcode.gameobjects/package.json index bd77e48697..b4e25e69f0 100644 --- a/com.unity.netcode.gameobjects/package.json +++ b/com.unity.netcode.gameobjects/package.json @@ -2,7 +2,7 @@ "name": "com.unity.netcode.gameobjects", "displayName": "Netcode for GameObjects", "description": "Netcode for GameObjects is a high-level netcode SDK that provides networking capabilities to GameObject/MonoBehaviour workflows within Unity and sits on top of underlying transport layer.", - "version": "2.12.0", + "version": "2.13.0", "unity": "6000.0", "dependencies": { "com.unity.nuget.mono-cecil": "1.11.4", From 5b1ce9f4500c22f0a047930c6c15d0ffd497f063 Mon Sep 17 00:00:00 2001 From: Emma Date: Mon, 25 May 2026 19:43:26 -0400 Subject: [PATCH 4/4] Fix findobjects complaints --- .../Runtime/Core/FindObjects.cs | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/com.unity.netcode.gameobjects/Runtime/Core/FindObjects.cs b/com.unity.netcode.gameobjects/Runtime/Core/FindObjects.cs index 8561b8fa17..59329f8a81 100644 --- a/com.unity.netcode.gameobjects/Runtime/Core/FindObjects.cs +++ b/com.unity.netcode.gameobjects/Runtime/Core/FindObjects.cs @@ -1,11 +1,7 @@ -#if NGO_FINDOBJECTS_NOSORTING -using System; -#endif using System; using System.Collections; using System.Collections.Generic; using System.Runtime.CompilerServices; -using UnityEngine; using UnityEngine.SceneManagement; using Object = UnityEngine.Object; @@ -16,7 +12,7 @@ namespace Unity.Netcode /// /// /// It is intentional that we do not include the UnityEngine namespace in order to avoid - /// over-complicatd define wrapping between versions that do or don't support FindObjectsSortMode. + /// over-complicated define wrapping between versions that do or don't support FindObjectsSortMode. /// internal static class FindObjects { @@ -30,7 +26,7 @@ internal static class FindObjects [MethodImpl(MethodImplOptions.AggressiveInlining)] public static T[] ByType(bool includeInactive = false, bool orderByIdentifier = false) where T : Object { - var inactive = includeInactive ? FindObjectsInactive.Include : FindObjectsInactive.Exclude; + var inactive = includeInactive ? UnityEngine.FindObjectsInactive.Include : UnityEngine.FindObjectsInactive.Exclude; #if NGO_FINDOBJECTS_NOSORTING var results = Object.FindObjectsByType(inactive); #if !NGO_FINDOBJECTS_UNORDERED_IDS @@ -40,7 +36,7 @@ public static T[] ByType(bool includeInactive = false, bool orderByIdentifier } #endif #else - var results = Object.FindObjectsByType(inactive, orderByIdentifier ? FindObjectsSortMode.InstanceID : FindObjectsSortMode.None); + var results = Object.FindObjectsByType(inactive, orderByIdentifier ? UnityEngine.FindObjectsSortMode.InstanceID : UnityEngine.FindObjectsSortMode.None); #endif return results; } @@ -52,7 +48,7 @@ public static T[] ByType(bool includeInactive = false, bool orderByIdentifier /// When true, inactive objects will be included. /// Type of to get from the scene /// a generator that yields successive NetworkObjects in the current scene - public static IEnumerable FromSceneByType(Scene scene, bool includeInactive) where T : Component + public static IEnumerable FromSceneByType(Scene scene, bool includeInactive) where T : UnityEngine.Component { return new ObjectsInSceneEnumerator(scene, includeInactive); } @@ -61,9 +57,9 @@ public static IEnumerable FromSceneByType(Scene scene, bool includeInactiv /// An Enumerator that enumerates over each component of type in the given scene. /// /// Type of to get from the scene - private struct ObjectsInSceneEnumerator : IEnumerable, IEnumerator where T : Component + private struct ObjectsInSceneEnumerator : IEnumerable, IEnumerator where T : UnityEngine.Component { - private readonly GameObject[] m_RootObjects; + private readonly UnityEngine.GameObject[] m_RootObjects; private int m_RootIndex; private T[] m_CurrentChildObjects; private int m_CurrentChildIndex;