Skip to content

Commit 3e579ed

Browse files
fix: soft synchronization errors if loading a new scene and setting it as active (#4065)
* fix - NetworkObject null exception on warning log If the NetworkObject was not found then use "null" as the name of the NetworkObject. * fix - synchronizing clients should always load active scene first This fixes the issue where the active scene could end up not being the 1st scene loaded which upon loading the active scene and previously SceneEventData relative loaded scenes would get unloaded when loading the active scene since this will can end up being loaded in SingleMode. * fix - prevent marking dynamically spawned objects as in-scene This fix just ignores any spawned objects when setting any just loaded InScenePlaced objects while running in the editor. * style finishing an incomplete comment * update Removing the changes as this will be fixed in a separate PR. * update Change log entry.
1 parent f4dfd4e commit 3e579ed

2 files changed

Lines changed: 51 additions & 40 deletions

File tree

com.unity.netcode.gameobjects/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ Additional documentation and release notes are available at [Multiplayer Documen
2323
### Fixed
2424

2525
- Issue where a NullReferenceException was thrown when a non-authority failed to spawn a NetworkObject. (#4067)
26+
- Issue where the active scene was not being serialized as the 1st scene which could result in various errors including a soft synchronization error if, on the client-side, other synchronized scenes had already been loaded prior to the active scene, which is always loaded as `LoadSceneMode.SingleMode` when client synchronization is set to `LoadSceneMode.SingleMode`, resulting in the previously loaded scene(s) to be unloaded. (#4065)
2627
- Issue when FastBufferReader is attempting to read a string and all or a portion of the character count has already been read by user script, it could read a character length that results in a negative byte length which could result in an editor crash. (#4052)
2728
- Issue where NetworkRigidbodyBase was not applying rotation correctly when using Rigidbody2D. (#4012)
2829
- Issue where NetworkRigidbodyBase was always checking the 3D rigid body's interpolation mode when determining if it is kinematic and needs to put the rigid body to sleep and then switch to interpolation. (#4012)

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

Lines changed: 50 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1951,6 +1951,21 @@ private void OnClientLoadedScene(uint sceneEventId, Scene scene)
19511951
/// </summary>
19521952
internal List<ulong> ClientConnectionQueue = new List<ulong>();
19531953

1954+
1955+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
1956+
private void AddSceneToClientSynchronization(ref SceneEventData sceneEventData, ref Scene scene)
1957+
{
1958+
// If we are just a normal client and in distributed authority mode, then always use the known server scene handle
1959+
if (NetworkManager.DistributedAuthorityMode && NetworkManager.CMBServiceConnection)
1960+
{
1961+
sceneEventData.AddSceneToSynchronize(SceneHashFromNameOrPath(scene.path), ClientSceneHandleToServerSceneHandle[scene.handle]);
1962+
}
1963+
else
1964+
{
1965+
sceneEventData.AddSceneToSynchronize(SceneHashFromNameOrPath(scene.path), scene.handle);
1966+
}
1967+
}
1968+
19541969
/// <summary>
19551970
/// Server Side:
19561971
/// This is used for players that have just had their connection approved and will assure they are synchronized
@@ -2001,61 +2016,53 @@ internal void SynchronizeNetworkObjects(ulong clientId, bool synchronizingServic
20012016

20022017
// Organize how (and when) we serialize our NetworkObjects
20032018
var hasSynchronizedActive = false;
2004-
for (int i = 0; i < SceneManager.sceneCount; i++)
2005-
{
2006-
var scene = SceneManager.GetSceneAt(i);
20072019

2008-
// NetworkSceneManager does not synchronize scenes that are not loaded by NetworkSceneManager
2009-
// unless the scene in question is the currently active scene.
2010-
if (ExcludeSceneFromSychronization != null && !ExcludeSceneFromSychronization(scene))
2020+
// It is possible a user might not want to synchronize the active scene, so we will check to see if it is valid before adding it to the synchronization list.
2021+
// !! Important !!
2022+
// The active scene MUST always be the first scene in the synchronization list.
2023+
if (ValidateSceneBeforeLoading(activeScene.buildIndex, activeScene.name, sceneEventData.LoadSceneMode))
2024+
{
2025+
sceneEventData.SceneHash = SceneHashFromNameOrPath(activeScene.path);
2026+
if (sceneEventData.SceneHash == sceneEventData.ActiveSceneHash)
20112027
{
2012-
continue;
2028+
hasSynchronizedActive = true;
20132029
}
20142030

2015-
if (scene == DontDestroyOnLoadScene)
2031+
// If we are just a normal client, then always use the server scene handle
2032+
if (NetworkManager.DistributedAuthorityMode)
20162033
{
2017-
continue;
2034+
sceneEventData.SenderClientId = NetworkManager.LocalClientId;
2035+
sceneEventData.SceneHandle = ClientSceneHandleToServerSceneHandle[activeScene.handle];
20182036
}
2019-
2020-
// This would depend upon whether we are additive or not
2021-
// If we are the base scene, then we set the root scene index;
2022-
if (activeScene == scene)
2037+
else
20232038
{
2024-
if (!ValidateSceneBeforeLoading(scene.buildIndex, scene.name, sceneEventData.LoadSceneMode))
2025-
{
2026-
continue;
2027-
}
2028-
sceneEventData.SceneHash = SceneHashFromNameOrPath(scene.path);
2029-
if (sceneEventData.SceneHash == sceneEventData.ActiveSceneHash)
2030-
{
2031-
hasSynchronizedActive = true;
2032-
}
2033-
2034-
// If we are just a normal client, then always use the server scene handle
2035-
if (NetworkManager.DistributedAuthorityMode)
2036-
{
2037-
sceneEventData.SenderClientId = NetworkManager.LocalClientId;
2038-
sceneEventData.SceneHandle = ClientSceneHandleToServerSceneHandle[scene.handle];
2039-
}
2040-
else
2041-
{
2042-
sceneEventData.SceneHandle = scene.handle;
2043-
}
2039+
sceneEventData.SceneHandle = activeScene.handle;
20442040
}
2045-
else if (!ValidateSceneBeforeLoading(scene.buildIndex, scene.name, LoadSceneMode.Additive))
2041+
AddSceneToClientSynchronization(ref sceneEventData, ref activeScene);
2042+
}
2043+
2044+
for (int i = 0; i < SceneManager.sceneCount; i++)
2045+
{
2046+
var scene = SceneManager.GetSceneAt(i);
2047+
// Skip adding the active scene at this point as we are just adding all other additively loaded scenes to the synchronization list.
2048+
// Skip adding the dont destroy on load scene as that is never synchronized.
2049+
if ((scene.handle == activeScene.handle) || (scene == DontDestroyOnLoadScene))
20462050
{
20472051
continue;
20482052
}
20492053

2050-
// If we are just a normal client and in distributed authority mode, then always use the known server scene handle
2051-
if (NetworkManager.DistributedAuthorityMode && NetworkManager.CMBServiceConnection)
2054+
// NetworkSceneManager does not synchronize scenes that are not loaded by NetworkSceneManager
2055+
// unless the scene in question is the currently active scene.
2056+
if (ExcludeSceneFromSychronization != null && !ExcludeSceneFromSychronization(scene))
20522057
{
2053-
sceneEventData.AddSceneToSynchronize(SceneHashFromNameOrPath(scene.path), ClientSceneHandleToServerSceneHandle[scene.handle]);
2058+
continue;
20542059
}
2055-
else
2060+
2061+
if (!ValidateSceneBeforeLoading(scene.buildIndex, scene.name, LoadSceneMode.Additive))
20562062
{
2057-
sceneEventData.AddSceneToSynchronize(SceneHashFromNameOrPath(scene.path), scene.handle);
2063+
continue;
20582064
}
2065+
AddSceneToClientSynchronization(ref sceneEventData, ref scene);
20592066
}
20602067

20612068
if (!hasSynchronizedActive && NetworkManager.CMBServiceConnection && synchronizingService)
@@ -2108,9 +2115,12 @@ private void OnClientBeginSync(uint sceneEventId)
21082115
var sceneHash = sceneEventData.GetNextSceneSynchronizationHash();
21092116
var sceneHandle = sceneEventData.GetNextSceneSynchronizationHandle();
21102117
var sceneName = SceneNameFromHash(sceneHash);
2118+
var activeSceneName = SceneNameFromHash(sceneEventData.ActiveSceneHash);
21112119
var activeScene = SceneManager.GetActiveScene();
21122120

2113-
var loadSceneMode = sceneHash == sceneEventData.SceneHash ? sceneEventData.LoadSceneMode : LoadSceneMode.Additive;
2121+
var activeSceneLoaded = activeSceneName == activeScene.name;
2122+
2123+
var loadSceneMode = sceneHash == sceneEventData.SceneHash && !activeSceneLoaded ? sceneEventData.LoadSceneMode : LoadSceneMode.Additive;
21142124

21152125
// Store the sceneHandle and hash
21162126
sceneEventData.NetworkSceneHandle = sceneHandle;

0 commit comments

Comments
 (0)