Skip to content

Commit a597b9f

Browse files
fix: prevent exception when showing despawned or destroyed NetworkObject (#3029)
* fix Adding protections against exceptions in the NetworkSpawnManager.HandleNetworkObjectShow method. * test validate the fix * update adding changelog entry. * update adding PR number to changelog entry. * fix and style Removing whitespace Adding 2022.3 define for find objects.
1 parent ca23b3c commit a597b9f

File tree

3 files changed

+60
-3
lines changed

3 files changed

+60
-3
lines changed

com.unity.netcode.gameobjects/CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,12 @@ Additional documentation and release notes are available at [Multiplayer Documen
1313
### Fixed
1414

1515
- Fixed issue where collections v2.2.x was not supported when using UTP v2.2.x within Unity v2022.3. (#3033)
16+
- Fixed issue where the `NetworkSpawnManager.HandleNetworkObjectShow` could throw an exception if one of the `NetworkObject` components to show was destroyed during the same frame. (#3029)
1617
- Fixed issue where the `NetworkManagerHelper` was continuing to check for hierarchy changes when in play mode. (#3027)
1718

1819
### Changed
1920

21+
2022
## [1.11.0] - 2024-08-20
2123

2224
### Added

com.unity.netcode.gameobjects/Runtime/Spawning/NetworkSpawnManager.cs

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1152,7 +1152,24 @@ internal void HandleNetworkObjectShow()
11521152
ulong clientId = client.Key;
11531153
foreach (var networkObject in client.Value)
11541154
{
1155-
SendSpawnCallForObject(clientId, networkObject);
1155+
// Ignore if null or not spawned (v1.x.x the server should only show what is spawned)
1156+
if (networkObject != null && networkObject.IsSpawned)
1157+
{
1158+
// Prevent exceptions from interrupting this iteration
1159+
// so the ObjectsToShowToClient list will be fully processed
1160+
// and cleard.
1161+
try
1162+
{
1163+
SendSpawnCallForObject(clientId, networkObject);
1164+
}
1165+
catch (Exception ex)
1166+
{
1167+
if (NetworkManager.LogLevel <= LogLevel.Developer)
1168+
{
1169+
Debug.LogException(ex);
1170+
}
1171+
}
1172+
}
11561173
}
11571174
}
11581175
ObjectsToShowToClient.Clear();

com.unity.netcode.gameobjects/Tests/Runtime/NetworkVisibilityTests.cs

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ public enum SceneManagementState
2020
private GameObject m_TestNetworkPrefab;
2121
private bool m_SceneManagementEnabled;
2222

23+
private GameObject m_SpawnedObject;
24+
2325
public NetworkVisibilityTests(SceneManagementState sceneManagementState)
2426
{
2527
m_SceneManagementEnabled = sceneManagementState == SceneManagementState.SceneManagementEnabled;
@@ -40,7 +42,7 @@ protected override void OnServerAndClientsCreated()
4042

4143
protected override IEnumerator OnServerAndClientsConnected()
4244
{
43-
SpawnObject(m_TestNetworkPrefab, m_ServerNetworkManager);
45+
m_SpawnedObject = SpawnObject(m_TestNetworkPrefab, m_ServerNetworkManager);
4446

4547
yield return base.OnServerAndClientsConnected();
4648
}
@@ -54,7 +56,43 @@ public IEnumerator HiddenObjectsTest()
5456
yield return WaitForConditionOrTimeOut(() => Object.FindObjectsOfType<NetworkVisibilityComponent>().Where((c) => c.IsSpawned).Count() == 2);
5557
#endif
5658

57-
Assert.IsFalse(s_GlobalTimeoutHelper.TimedOut, "Timed out waiting for the visible object count to equal 2!");
59+
AssertOnTimeout("Timed out waiting for the visible object count to equal 2!");
60+
}
61+
62+
63+
[UnityTest]
64+
public IEnumerator HideShowAndDeleteTest()
65+
{
66+
#if UNITY_2023_1_OR_NEWER
67+
yield return WaitForConditionOrTimeOut(() => Object.FindObjectsByType<NetworkVisibilityComponent>(FindObjectsSortMode.None).Where((c) => c.IsSpawned).Count() == 2);
68+
#else
69+
yield return WaitForConditionOrTimeOut(() => Object.FindObjectsOfType<NetworkVisibilityComponent>().Where((c) => c.IsSpawned).Count() == 2);
70+
#endif
71+
AssertOnTimeout("Timed out waiting for the visible object count to equal 2!");
72+
73+
var serverNetworkObject = m_SpawnedObject.GetComponent<NetworkObject>();
74+
75+
serverNetworkObject.NetworkHide(m_ClientNetworkManagers[0].LocalClientId);
76+
77+
#if UNITY_2023_1_OR_NEWER
78+
yield return WaitForConditionOrTimeOut(() => Object.FindObjectsByType<NetworkVisibilityComponent>(FindObjectsSortMode.None).Where((c) => c.IsSpawned).Count() == 1);
79+
#else
80+
yield return WaitForConditionOrTimeOut(() => Object.FindObjectsOfType<NetworkVisibilityComponent>().Where((c) => c.IsSpawned).Count() == 1);
81+
#endif
82+
AssertOnTimeout($"Timed out waiting for {m_SpawnedObject.name} to be hidden from client!");
83+
var networkObjectId = serverNetworkObject.NetworkObjectId;
84+
serverNetworkObject.NetworkShow(m_ClientNetworkManagers[0].LocalClientId);
85+
serverNetworkObject.Despawn(true);
86+
87+
// Expect no exceptions
88+
yield return s_DefaultWaitForTick;
89+
90+
// Now force a scenario where it normally would have caused an exception
91+
m_ServerNetworkManager.SpawnManager.ObjectsToShowToClient.Add(m_ClientNetworkManagers[0].LocalClientId, new System.Collections.Generic.List<NetworkObject>());
92+
m_ServerNetworkManager.SpawnManager.ObjectsToShowToClient[m_ClientNetworkManagers[0].LocalClientId].Add(null);
93+
94+
// Expect no exceptions
95+
yield return s_DefaultWaitForTick;
5896
}
5997
}
6098
}

0 commit comments

Comments
 (0)