Skip to content

Commit 42e3d83

Browse files
update + fix
Fixing an edge case that requires manually testing due to how integration tests additively load everything to avoid unloading the test runner test scene when loading a scene. Two parts: - When a server is destroying spawned scene objects due to a single mode scene load, it should also include a check for this and handle marking the NetworkObject and associated NetworkBehaviours as being destroyed and then destroy the object. - Just prior to handling a scene loading event, we need to mark anything that will be destroyed (i.e. destroy with scene) as being destroyed when migrating spawned objects into the DDOL.
1 parent aec2ae6 commit 42e3d83

File tree

2 files changed

+35
-11
lines changed

2 files changed

+35
-11
lines changed

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

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2709,7 +2709,11 @@ internal void MoveObjectsToDontDestroyOnLoad()
27092709
}
27102710
else if (networkObject.HasAuthority)
27112711
{
2712-
networkObject.Despawn();
2712+
networkObject.SetIsDestroying();
2713+
var isSceneObject = networkObject.IsSceneObject;
2714+
// Only destroy non-scene placed NetworkObjects to avoid warnings about destroying in-scene placed NetworkObjects.
2715+
// (MoveObjectsToDontDestroyOnLoad is only invoked during a scene event type of load and the load scene mode is single)
2716+
networkObject.Despawn(isSceneObject.HasValue && isSceneObject.Value == false);
27132717
}
27142718
}
27152719
}

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

Lines changed: 30 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -164,10 +164,16 @@ private void RemovePlayerObject(NetworkObject playerObject, bool destroyingObjec
164164
m_PlayerObjectsTable.Remove(playerObject.OwnerClientId);
165165
}
166166
}
167-
167+
// If the client exists locally and we are destroying...
168168
if (NetworkManager.ConnectionManager.ConnectedClients.ContainsKey(playerObject.OwnerClientId) && destroyingObject)
169169
{
170-
NetworkManager.ConnectionManager.ConnectedClients[playerObject.OwnerClientId].PlayerObject = null;
170+
var client = NetworkManager.ConnectionManager.ConnectedClients[playerObject.OwnerClientId];
171+
// and the client's currently assigned player object is what is being destroyed...
172+
if (client != null && client.PlayerObject == playerObject)
173+
{
174+
// then clear out the clients currently assigned player object.
175+
client.PlayerObject = null;
176+
}
171177
}
172178
}
173179

@@ -1380,21 +1386,31 @@ internal void ServerResetShudownStateForSceneObjects()
13801386
}
13811387

13821388
/// <summary>
1383-
/// Gets called only by NetworkSceneManager.SwitchScene
1389+
/// Gets called only by <see cref="NetworkManager.Load"/> and the load scene mode
1390+
/// is set to <see cref="UnityEngine.SceneManagement.LoadSceneMode.Single"/>.
13841391
/// </summary>
13851392
internal void ServerDestroySpawnedSceneObjects()
13861393
{
1387-
// This Allocation is "OK" for now because this code only executes when a new scene is switched to
1388-
// We need to create a new copy the HashSet of NetworkObjects (SpawnedObjectsList) so we can remove
1389-
// objects from the HashSet (SpawnedObjectsList) without causing a list has been modified exception to occur.
1394+
// This Allocation is "OK" for now because this code only executes when transitioning to a new scene (i.e. lots of allocations and de-allocations).
1395+
// We create new copy of the NetworkObjects (SpawnedObjectsList) HashSet so we can remove from the original list as needed.
13901396
var spawnedObjects = SpawnedObjectsList.ToList();
13911397

1392-
foreach (var sobj in spawnedObjects)
1398+
foreach (var networkObject in spawnedObjects)
13931399
{
1394-
if (sobj.IsSceneObject != null && sobj.IsSceneObject.Value && sobj.DestroyWithScene && sobj.gameObject.scene != NetworkManager.SceneManager.DontDestroyOnLoadScene)
1400+
if (networkObject.IsSceneObject != null && networkObject.IsSceneObject.Value && networkObject.DestroyWithScene
1401+
&& networkObject.gameObject.scene != NetworkManager.SceneManager.DontDestroyOnLoadScene)
13951402
{
1396-
SpawnedObjectsList.Remove(sobj);
1397-
UnityEngine.Object.Destroy(sobj.gameObject);
1403+
if (networkObject.IsSpawned && networkObject.HasAuthority)
1404+
{
1405+
networkObject.Despawn(false);
1406+
}
1407+
else // Non-authority objects should just be destroyed (i.e. DAHost)
1408+
{
1409+
// Mark the object and associated NetworkBehaviours as in the process (or will be) destroyed.
1410+
networkObject.SetIsDestroying();
1411+
UnityEngine.Object.Destroy(networkObject.gameObject);
1412+
SpawnedObjectsList.Remove(networkObject);
1413+
}
13981414
}
13991415
}
14001416
}
@@ -1630,6 +1646,10 @@ internal void OnDespawnObject(NetworkObject networkObject, bool destroyGameObjec
16301646
}
16311647
}
16321648

1649+
if (destroyGameObject)
1650+
{
1651+
networkObject.SetIsDestroying();
1652+
}
16331653
networkObject.InvokeBehaviourNetworkDespawn();
16341654

16351655
// Whether we are in distributedAuthority mode and have authority on this object

0 commit comments

Comments
 (0)