Skip to content

Commit 0e10948

Browse files
chore: add second part of session restore (#2919)
* update Skip initial in-scene object spawn pass and sending service the initial synchronization when restoring a session. Allow same scene handle entries when restoring a session. Don't spawn the player during connection approval during session restore. Integration test helpers registers validation handler to exclude InitTestScene for all clients. NetworkSceneManager always sends scene events to the service. For now, session owner always uses PostSynchronizationSceneUnloading when processing a session restore synchronization.
1 parent f6f815c commit 0e10948

File tree

3 files changed

+43
-11
lines changed

3 files changed

+43
-11
lines changed

com.unity.netcode.gameobjects/Runtime/Messaging/Messages/ConnectionApprovedMessage.cs

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -236,16 +236,22 @@ public void Handle(ref NetworkContext context)
236236
// Mark the client being connected
237237
networkManager.IsConnectedClient = true;
238238

239-
// Spawn any in-scene placed NetworkObjects
240-
networkManager.SpawnManager.ServerSpawnSceneObjectsOnStartSweep();
239+
networkManager.SceneManager.IsRestoringSession = IsRestoredSession;
241240

242-
// Spawn the local player of the session owner
243-
if (networkManager.AutoSpawnPlayerPrefabClientSide)
241+
if (!IsRestoredSession)
244242
{
245-
networkManager.ConnectionManager.CreateAndSpawnPlayer(OwnerClientId);
243+
// Spawn any in-scene placed NetworkObjects
244+
networkManager.SpawnManager.ServerSpawnSceneObjectsOnStartSweep();
245+
246+
// Spawn the local player of the session owner
247+
if (networkManager.AutoSpawnPlayerPrefabClientSide)
248+
{
249+
networkManager.ConnectionManager.CreateAndSpawnPlayer(OwnerClientId);
250+
}
251+
252+
// Synchronize the service with the initial session owner's loaded scenes and spawned objects
253+
networkManager.SceneManager.SynchronizeNetworkObjects(NetworkManager.ServerClientId);
246254
}
247-
// Synchronize the service with the initial session owner's loaded scenes and spawned objects
248-
networkManager.SceneManager.SynchronizeNetworkObjects(NetworkManager.ServerClientId);
249255
}
250256
}
251257
ConnectedClientIds.Dispose();

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

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -444,6 +444,7 @@ public List<Scene> GetSynchronizedScenes()
444444
internal Dictionary<int, int> ServerSceneHandleToClientSceneHandle = new Dictionary<int, int>();
445445
internal Dictionary<int, int> ClientSceneHandleToServerSceneHandle = new Dictionary<int, int>();
446446

447+
internal bool IsRestoringSession;
447448
/// <summary>
448449
/// Add the client to server (and vice versa) scene handle lookup.
449450
/// Add the client-side handle to scene entry in the HandleToScene table.
@@ -455,7 +456,7 @@ internal bool UpdateServerClientSceneHandle(int serverHandle, int clientHandle,
455456
{
456457
ServerSceneHandleToClientSceneHandle.Add(serverHandle, clientHandle);
457458
}
458-
else
459+
else if (!IsRestoringSession)
459460
{
460461
return false;
461462
}
@@ -464,7 +465,7 @@ internal bool UpdateServerClientSceneHandle(int serverHandle, int clientHandle,
464465
{
465466
ClientSceneHandleToServerSceneHandle.Add(clientHandle, serverHandle);
466467
}
467-
else
468+
else if (!IsRestoringSession)
468469
{
469470
return false;
470471
}
@@ -1045,7 +1046,7 @@ internal NetworkObject GetSceneRelativeInSceneNetworkObject(uint globalObjectIdH
10451046
/// <param name="targetClientIds">array of client identifiers to receive the scene event message</param>
10461047
private void SendSceneEventData(uint sceneEventId, ulong[] targetClientIds)
10471048
{
1048-
if (targetClientIds.Length == 0)
1049+
if (targetClientIds.Length == 0 && !NetworkManager.DistributedAuthorityMode)
10491050
{
10501051
// This would be the Host/Server with no clients connected
10511052
// Silently return as there is nothing to be done
@@ -1056,6 +1057,16 @@ private void SendSceneEventData(uint sceneEventId, ulong[] targetClientIds)
10561057

10571058
if (NetworkManager.DistributedAuthorityMode && !NetworkManager.DAHost)
10581059
{
1060+
if (NetworkManager.DistributedAuthorityMode && HasSceneAuthority())
1061+
{
1062+
sceneEvent.TargetClientId = NetworkManager.ServerClientId;
1063+
var message = new SceneEventMessage
1064+
{
1065+
EventData = sceneEvent,
1066+
};
1067+
var size = NetworkManager.ConnectionManager.SendMessage(ref message, k_DeliveryType, NetworkManager.ServerClientId);
1068+
NetworkManager.NetworkMetrics.TrackSceneEventSent(NetworkManager.ServerClientId, (uint)sceneEvent.SceneEventType, SceneNameFromHash(sceneEvent.SceneHash), size);
1069+
}
10591070
foreach (var clientId in targetClientIds)
10601071
{
10611072
sceneEvent.TargetClientId = clientId;
@@ -2430,6 +2441,12 @@ private void HandleClientSceneEvent(uint sceneEventId)
24302441
networkObject.InternalNetworkSessionSynchronized();
24312442
}
24322443

2444+
if (NetworkManager.DistributedAuthorityMode && HasSceneAuthority() && IsRestoringSession)
2445+
{
2446+
IsRestoringSession = false;
2447+
PostSynchronizationSceneUnloading = m_OriginalPostSynchronizationSceneUnloading;
2448+
}
2449+
24332450
EndSceneEvent(sceneEventId);
24342451
}
24352452
break;
@@ -2616,6 +2633,8 @@ private void HandleSessionOwnerEvent(uint sceneEventId, ulong clientId)
26162633
/// </summary>
26172634
internal bool SkipSceneHandling;
26182635

2636+
private bool m_OriginalPostSynchronizationSceneUnloading;
2637+
26192638
/// <summary>
26202639
/// Both Client and Server: Incoming scene event entry point
26212640
/// </summary>
@@ -2689,6 +2708,12 @@ internal void HandleSceneEvent(ulong clientId, FastBufferReader reader)
26892708
// Only if ClientSynchronizationMode is Additive and the client receives a synchronize scene event
26902709
if (ClientSynchronizationMode == LoadSceneMode.Additive)
26912710
{
2711+
if (NetworkManager.DistributedAuthorityMode && HasSceneAuthority() && IsRestoringSession && clientId == NetworkManager.ServerClientId)
2712+
{
2713+
m_OriginalPostSynchronizationSceneUnloading = PostSynchronizationSceneUnloading;
2714+
PostSynchronizationSceneUnloading = true;
2715+
}
2716+
26922717
// Check for scenes already loaded and create a table of scenes already loaded (SceneEntries) that will be
26932718
// used if the server is synchronizing the same scenes (i.e. if a matching scene is already loaded on the
26942719
// client side, then that scene will be used as opposed to loading another scene). This allows for clients

com.unity.netcode.gameobjects/TestHelpers/Runtime/NetcodeIntegrationTestHelpers.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -378,7 +378,8 @@ private static void SceneManagerValidationAndTestRunnerInitialization(NetworkMan
378378
{
379379
// If VerifySceneBeforeLoading is not already set, then go ahead and set it so the host/server
380380
// will not try to synchronize clients to the TestRunner scene. We only need to do this for the server.
381-
if (networkManager.IsServer && networkManager.SceneManager.VerifySceneBeforeLoading == null)
381+
// All clients in distributed authority mode, should have this registered (since any one client can become the session owner).
382+
if ((networkManager.IsServer && networkManager.SceneManager.VerifySceneBeforeLoading == null) || networkManager.DistributedAuthorityMode)
382383
{
383384
networkManager.SceneManager.VerifySceneBeforeLoading = VerifySceneIsValidForClientsToLoad;
384385

0 commit comments

Comments
 (0)