Skip to content

Commit cb6394e

Browse files
fix: In-scene NetworkObjects disabled but never re-enabled after scene transition (#1354) (#1465)
* fix This is the fix for the in-scene NetworkObjects moved into DDOL and the after a scene transition they become disabled but never re-enabled. * test Had to make some private methods internal for testing purposes. Adding test to validate the fix. * style white space fixes. * style Adding comment above the primary line of code that is the fix for this PR * style removing unused namespace. * style removing several LFs * fix and test This now tracks the state of NetworkObjects when a full scene transition takes place. This includes a refactored test for NetworkObjects (dynamically spawned and in-scene placed) that persist a full scene transition. * test update This makes sure that DestroyWithScene is set to false for all InSceneNetworkObjectState tests. * style Removing whitespace. * updated changelog Added entries for the fixes applied in this PR. * refactor After peer review during PR Triage we all decided to not change or track a NetworkObject's parent GameObject's state and to not disable during full scene transition. Removed all active state tracking dictionaries and references as well as removed disabling DDOL migrated GameObjects from the runtime NGO code base. Adjusted the DDOL test to check the state is maintained throughout the scene transition. The DDOL test only required a minor * updated changelog Updating the changelog to reflect most recent updates. Co-authored-by: Noel Stephens <noel.stephens@unity3d.com>
1 parent 39fa7b6 commit cb6394e

File tree

2 files changed

+138
-20
lines changed

2 files changed

+138
-20
lines changed

com.unity.netcode.gameobjects/Runtime/SceneManagement/NetworkSceneManager.cs

Lines changed: 14 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1830,21 +1830,18 @@ internal void HandleSceneEvent(ulong clientId, FastBufferReader reader)
18301830
/// Moves all NetworkObjects that don't have the <see cref="NetworkObject.DestroyWithScene"/> set to
18311831
/// the "Do not destroy on load" scene.
18321832
/// </summary>
1833-
private void MoveObjectsToDontDestroyOnLoad()
1833+
internal void MoveObjectsToDontDestroyOnLoad()
18341834
{
1835-
// Move ALL NetworkObjects to the temp scene
1835+
// Move ALL NetworkObjects marked to persist scene transitions into the DDOL scene
18361836
var objectsToKeep = new HashSet<NetworkObject>(m_NetworkManager.SpawnManager.SpawnedObjectsList);
1837-
18381837
foreach (var sobj in objectsToKeep)
18391838
{
1840-
if (!sobj.DestroyWithScene || (sobj.IsSceneObject != null && sobj.IsSceneObject.Value && sobj.gameObject.scene == DontDestroyOnLoadScene))
1839+
if (!sobj.DestroyWithScene || sobj.gameObject.scene == DontDestroyOnLoadScene)
18411840
{
1842-
// Only move objects with no parent as child objects will follow
1843-
if (sobj.gameObject.transform.parent == null)
1841+
// Only move dynamically spawned network objects with no parent as child objects will follow
1842+
if (sobj.gameObject.transform.parent == null && sobj.IsSceneObject != null && !sobj.IsSceneObject.Value)
18441843
{
18451844
UnityEngine.Object.DontDestroyOnLoad(sobj.gameObject);
1846-
// Since we are doing a scene transition, disable the GameObject until the next scene is loaded
1847-
sobj.gameObject.SetActive(false);
18481845
}
18491846
}
18501847
else if (m_NetworkManager.IsServer)
@@ -1907,24 +1904,22 @@ private void PopulateScenePlacedObjects(Scene sceneToFilterBy, bool clearScenePl
19071904
/// Moves all spawned NetworkObjects (from do not destroy on load) to the scene specified
19081905
/// </summary>
19091906
/// <param name="scene">scene to move the NetworkObjects to</param>
1910-
private void MoveObjectsFromDontDestroyOnLoadToScene(Scene scene)
1907+
internal void MoveObjectsFromDontDestroyOnLoadToScene(Scene scene)
19111908
{
19121909
// Move ALL NetworkObjects to the temp scene
19131910
var objectsToKeep = m_NetworkManager.SpawnManager.SpawnedObjectsList;
19141911

19151912
foreach (var sobj in objectsToKeep)
19161913
{
1917-
if (sobj.gameObject.scene == DontDestroyOnLoadScene && (sobj.IsSceneObject == null || sobj.IsSceneObject.Value))
1918-
{
1919-
continue;
1920-
}
1921-
1922-
// Only move objects with no parent as child objects will follow
1923-
if (sobj.gameObject.transform.parent == null)
1914+
// If it is in the DDOL then
1915+
if (sobj.gameObject.scene == DontDestroyOnLoadScene)
19241916
{
1925-
// set it back to active at this point
1926-
sobj.gameObject.SetActive(true);
1927-
SceneManager.MoveGameObjectToScene(sobj.gameObject, scene);
1917+
// only move dynamically spawned network objects, with no parent as child objects will follow,
1918+
// back into the currently active scene
1919+
if (sobj.gameObject.transform.parent == null && sobj.IsSceneObject != null && !sobj.IsSceneObject.Value)
1920+
{
1921+
SceneManager.MoveGameObjectToScene(sobj.gameObject, scene);
1922+
}
19281923
}
19291924
}
19301925
}

testproject/Assets/Tests/Runtime/NetworkSceneManagerTests.cs

Lines changed: 124 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
using UnityEngine.TestTools;
99
using Unity.Netcode.RuntimeTests;
1010
using Unity.Netcode;
11+
using Object = UnityEngine.Object;
1112

1213
namespace TestProject.RuntimeTests
1314
{
@@ -980,7 +981,129 @@ public IEnumerator FastReaderAllocationTest()
980981
nativeArray.Dispose();
981982
fastBufferWriter.Dispose();
982983
networkManager.Shutdown();
983-
UnityEngine.Object.Destroy(networkManagerGameObject);
984+
Object.Destroy(networkManagerGameObject);
984985
}
985986
}
987+
988+
public class NetworkSceneManagerDDOLTests
989+
{
990+
private NetworkManager m_ServerNetworkManager;
991+
private GameObject m_NetworkManagerGameObject;
992+
private GameObject m_DDOL_ObjectToSpawn;
993+
994+
protected float m_ConditionMetFrequency = 0.1f;
995+
996+
[UnitySetUp]
997+
protected IEnumerator SetUp()
998+
{
999+
m_NetworkManagerGameObject = new GameObject("NetworkManager - Host");
1000+
m_ServerNetworkManager = m_NetworkManagerGameObject.AddComponent<NetworkManager>();
1001+
1002+
m_DDOL_ObjectToSpawn = new GameObject();
1003+
m_DDOL_ObjectToSpawn.AddComponent<NetworkObject>();
1004+
m_DDOL_ObjectToSpawn.AddComponent<DDOLBehaviour>();
1005+
1006+
m_ServerNetworkManager.NetworkConfig = new NetworkConfig()
1007+
{
1008+
ConnectionApproval = false,
1009+
NetworkPrefabs = new List<NetworkPrefab>(),
1010+
NetworkTransport = m_NetworkManagerGameObject.AddComponent<SIPTransport>(),
1011+
};
1012+
m_ServerNetworkManager.StartHost();
1013+
yield break;
1014+
}
1015+
1016+
[UnityTearDown]
1017+
protected IEnumerator TearDown()
1018+
{
1019+
m_ServerNetworkManager.Shutdown();
1020+
1021+
Object.Destroy(m_NetworkManagerGameObject);
1022+
Object.Destroy(m_DDOL_ObjectToSpawn);
1023+
1024+
yield break;
1025+
}
1026+
1027+
public enum DefaultState
1028+
{
1029+
IsEnabled,
1030+
IsDisabled
1031+
}
1032+
1033+
public enum MovedIntoDDOLBy
1034+
{
1035+
User,
1036+
NetworkSceneManager
1037+
}
1038+
1039+
public enum NetworkObjectType
1040+
{
1041+
InScenePlaced,
1042+
DynamicallySpawned
1043+
}
1044+
1045+
/// <summary>
1046+
/// Tests to make sure NetworkObjects moved into the DDOL will
1047+
/// restore back to their currently active state when a full
1048+
/// scene transition is complete.
1049+
/// This tests both in-scene placed and dynamically spawned NetworkObjects
1050+
[UnityTest]
1051+
public IEnumerator InSceneNetworkObjectState([Values(DefaultState.IsEnabled, DefaultState.IsDisabled)] DefaultState activeState,
1052+
[Values(MovedIntoDDOLBy.User, MovedIntoDDOLBy.NetworkSceneManager)] MovedIntoDDOLBy movedIntoDDOLBy,
1053+
[Values(NetworkObjectType.InScenePlaced, NetworkObjectType.DynamicallySpawned)] NetworkObjectType networkObjectType)
1054+
{
1055+
var isActive = activeState == DefaultState.IsEnabled ? true : false;
1056+
var isInScene = networkObjectType == NetworkObjectType.InScenePlaced ? true : false;
1057+
var networkObject = m_DDOL_ObjectToSpawn.GetComponent<NetworkObject>();
1058+
var ddolBehaviour = m_DDOL_ObjectToSpawn.GetComponent<DDOLBehaviour>();
1059+
1060+
// All tests require this to be false
1061+
networkObject.DestroyWithScene = false;
1062+
1063+
if (movedIntoDDOLBy == MovedIntoDDOLBy.User)
1064+
{
1065+
ddolBehaviour.MoveToDDOL();
1066+
}
1067+
1068+
// Sets whether we are in-scene or dynamically spawned NetworkObject
1069+
ddolBehaviour.SetInScene(isInScene);
1070+
1071+
Assert.That(networkObject.IsSpawned);
1072+
1073+
m_DDOL_ObjectToSpawn.SetActive(isActive);
1074+
1075+
m_ServerNetworkManager.SceneManager.MoveObjectsToDontDestroyOnLoad();
1076+
1077+
yield return new WaitForSeconds(0.03f);
1078+
1079+
// It should be isActive when MoveObjectsToDontDestroyOnLoad is called.
1080+
Assert.That(networkObject.isActiveAndEnabled == isActive);
1081+
1082+
m_ServerNetworkManager.SceneManager.MoveObjectsFromDontDestroyOnLoadToScene(SceneManager.GetActiveScene());
1083+
1084+
yield return new WaitForSeconds(0.03f);
1085+
1086+
// It should be isActive when MoveObjectsFromDontDestroyOnLoadToScene is called.
1087+
Assert.That(networkObject.isActiveAndEnabled == isActive);
1088+
1089+
//Done
1090+
networkObject.Despawn(false);
1091+
}
1092+
1093+
public class DDOLBehaviour : NetworkBehaviour
1094+
{
1095+
public void MoveToDDOL()
1096+
{
1097+
DontDestroyOnLoad(gameObject);
1098+
}
1099+
1100+
public void SetInScene(bool isInScene)
1101+
{
1102+
var networkObject = GetComponent<NetworkObject>();
1103+
networkObject.IsSceneObject = isInScene;
1104+
}
1105+
}
1106+
1107+
}
1108+
9861109
}

0 commit comments

Comments
 (0)