com.unity.netcode.gameobjects@1.0.0-pre.10
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). Additional documentation and release notes are available at [Multiplayer Documentation](https://docs-multiplayer.unity3d.com). ## [1.0.0-pre.10] - 2022-06-21 ### Added - Added a new `OnTransportFailure` callback to `NetworkManager`. This callback is invoked when the manager's `NetworkTransport` encounters an unrecoverable error. Transport failures also cause the `NetworkManager` to shut down. Currently, this is only used by `UnityTransport` to signal a timeout of its connection to the Unity Relay servers. (#1994) - Added `NetworkEvent.TransportFailure`, which can be used by implementations of `NetworkTransport` to signal to `NetworkManager` that an unrecoverable error was encountered. (#1994) - Added test to ensure a warning occurs when nesting NetworkObjects in a NetworkPrefab (#1969) - Added `NetworkManager.RemoveNetworkPrefab(...)` to remove a prefab from the prefabs list (#1950) ### Changed - Updated `UnityTransport` dependency on `com.unity.transport` to 1.1.0. (#2025) - (API Breaking) `ConnectionApprovalCallback` is no longer an `event` and will not allow more than 1 handler registered at a time. Also, `ConnectionApprovalCallback` is now a `Func<>` taking `ConnectionApprovalRequest` in and returning `ConnectionApprovalResponse` back out (#1972) ### Removed ### Fixed - Fixed issue where dynamically spawned `NetworkObject`s could throw an exception if the scene of origin handle was zero (0) and the `NetworkObject` was already spawned. (#2017) - Fixed issue where `NetworkObject.Observers` was not being cleared when despawned. (#2009) - Fixed `NetworkAnimator` could not run in the server authoritative mode. (#2003) - Fixed issue where late joining clients would get a soft synchronization error if any in-scene placed NetworkObjects were parented under another `NetworkObject`. (#1985) - Fixed issue where `NetworkBehaviourReference` would throw a type cast exception if using `NetworkBehaviourReference.TryGet` and the component type was not found. (#1984) - Fixed `NetworkSceneManager` was not sending scene event notifications for the currently active scene and any additively loaded scenes when loading a new scene in `LoadSceneMode.Single` mode. (#1975) - Fixed issue where one or more clients disconnecting during a scene event would cause `LoadEventCompleted` or `UnloadEventCompleted` to wait until the `NetworkConfig.LoadSceneTimeOut` period before being triggered. (#1973) - Fixed issues when multiple `ConnectionApprovalCallback`s were registered (#1972) - Fixed a regression in serialization support: `FixedString`, `Vector2Int`, and `Vector3Int` types can now be used in NetworkVariables and RPCs again without requiring a `ForceNetworkSerializeByMemcpy<>` wrapper. (#1961) - Fixed generic types that inherit from NetworkBehaviour causing crashes at compile time. (#1976) - Fixed endless dialog boxes when adding a `NetworkBehaviour` to a `NetworkManager` or vice-versa. (#1947) - Fixed `NetworkAnimator` issue where it was only synchronizing parameters if the layer or state changed or was transitioning between states. (#1946) - Fixed `NetworkAnimator` issue where when it did detect a parameter had changed it would send all parameters as opposed to only the parameters that changed. (#1946) - Fixed `NetworkAnimator` issue where it was not always disposing the `NativeArray` that is allocated when spawned. (#1946) - Fixed `NetworkAnimator` issue where it was not taking the animation speed or state speed multiplier into consideration. (#1946) - Fixed `NetworkAnimator` issue where it was not properly synchronizing late joining clients if they joined while `Animator` was transitioning between states. (#1946) - Fixed `NetworkAnimator` issue where the server was not relaying changes to non-owner clients when a client was the owner. (#1946) - Fixed issue where the `PacketLoss` metric for tools would return the packet loss over a connection lifetime instead of a single frame. (#2004)
This commit is contained in:
@@ -15,8 +15,14 @@ namespace Unity.Netcode
|
||||
{
|
||||
internal uint SceneEventId;
|
||||
internal Action<uint> EventAction;
|
||||
/// <summary>
|
||||
/// Used server-side for integration testing in order to
|
||||
/// invoke the SceneEventProgress once done loading
|
||||
/// </summary>
|
||||
internal Action Completed;
|
||||
internal void Invoke()
|
||||
{
|
||||
Completed?.Invoke();
|
||||
EventAction.Invoke(SceneEventId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ namespace Unity.Netcode
|
||||
/// delegate type <see cref="NetworkSceneManager.SceneEventDelegate"/> uses this class to provide
|
||||
/// scene event status.<br/>
|
||||
/// <em>Note: This is only when <see cref="NetworkConfig.EnableSceneManagement"/> is enabled.</em><br/>
|
||||
/// <em>*** Do not start new scene events within scene event notification callbacks.</em><br/>
|
||||
/// See also: <br/>
|
||||
/// <seealso cref="SceneEventType"/>
|
||||
/// </summary>
|
||||
@@ -166,6 +167,7 @@ namespace Unity.Netcode
|
||||
/// <item><term><see cref="OnUnloadComplete"/> Invoked only when an <see cref="SceneEventType.UnloadComplete"/> event is being processed</term></item>
|
||||
/// <item><term><see cref="OnSynchronizeComplete"/> Invoked only when a <see cref="SceneEventType.SynchronizeComplete"/> event is being processed</term></item>
|
||||
/// </list>
|
||||
/// <em>Note: Do not start new scene events within NetworkSceneManager scene event notification callbacks.</em><br/>
|
||||
/// </summary>
|
||||
public event SceneEventDelegate OnSceneEvent;
|
||||
|
||||
@@ -239,13 +241,15 @@ namespace Unity.Netcode
|
||||
|
||||
/// <summary>
|
||||
/// Invoked when a <see cref="SceneEventType.Load"/> event is started by the server.<br/>
|
||||
/// <em>Note: The server and connected client(s) will always receive this notification.</em>
|
||||
/// <em>Note: The server and connected client(s) will always receive this notification.</em><br/>
|
||||
/// <em>*** Do not start new scene events within scene event notification callbacks.</em><br/>
|
||||
/// </summary>
|
||||
public event OnLoadDelegateHandler OnLoad;
|
||||
|
||||
/// <summary>
|
||||
/// Invoked when a <see cref="SceneEventType.Unload"/> event is started by the server.<br/>
|
||||
/// <em>Note: The server and connected client(s) will always receive this notification.</em>
|
||||
/// <em>Note: The server and connected client(s) will always receive this notification.</em><br/>
|
||||
/// <em>*** Do not start new scene events within scene event notification callbacks.</em><br/>
|
||||
/// </summary>
|
||||
public event OnUnloadDelegateHandler OnUnload;
|
||||
|
||||
@@ -254,7 +258,8 @@ namespace Unity.Netcode
|
||||
/// after a client is approved for connection in order to synchronize the client with the currently loaded
|
||||
/// scenes and NetworkObjects. This event signifies the beginning of the synchronization event.<br/>
|
||||
/// <em>Note: The server and connected client(s) will always receive this notification.
|
||||
/// This event is generated on a per newly connected and approved client basis.</em>
|
||||
/// This event is generated on a per newly connected and approved client basis.</em><br/>
|
||||
/// <em>*** Do not start new scene events within scene event notification callbacks.</em><br/>
|
||||
/// </summary>
|
||||
public event OnSynchronizeDelegateHandler OnSynchronize;
|
||||
|
||||
@@ -263,7 +268,8 @@ namespace Unity.Netcode
|
||||
/// This event signifies the end of an existing <see cref="SceneEventType.Load"/> event as it pertains
|
||||
/// to all clients connected when the event was started. This event signifies that all clients (and server) have
|
||||
/// finished the <see cref="SceneEventType.Load"/> event.<br/>
|
||||
/// <em>Note: this is useful to know when all clients have loaded the same scene (single or additive mode)</em>
|
||||
/// <em>Note: this is useful to know when all clients have loaded the same scene (single or additive mode)</em><br/>
|
||||
/// <em>*** Do not start new scene events within scene event notification callbacks.</em><br/>
|
||||
/// </summary>
|
||||
public event OnEventCompletedDelegateHandler OnLoadEventCompleted;
|
||||
|
||||
@@ -273,21 +279,24 @@ namespace Unity.Netcode
|
||||
/// to all clients connected when the event was started. This event signifies that all clients (and server) have
|
||||
/// finished the <see cref="SceneEventType.Unload"/> event.<br/>
|
||||
/// <em>Note: this is useful to know when all clients have unloaded a specific scene. The <see cref="LoadSceneMode"/> will
|
||||
/// always be <see cref="LoadSceneMode.Additive"/> for this event.</em>
|
||||
/// always be <see cref="LoadSceneMode.Additive"/> for this event.</em><br/>
|
||||
/// <em>*** Do not start new scene events within scene event notification callbacks.</em><br/>
|
||||
/// </summary>
|
||||
public event OnEventCompletedDelegateHandler OnUnloadEventCompleted;
|
||||
|
||||
/// <summary>
|
||||
/// Invoked when a <see cref="SceneEventType.LoadComplete"/> event is generated by a client or server.<br/>
|
||||
/// <em>Note: The server receives this message from all clients (including itself).
|
||||
/// Each client receives their own notification sent to the server.</em>
|
||||
/// Each client receives their own notification sent to the server.</em><br/>
|
||||
/// <em>*** Do not start new scene events within scene event notification callbacks.</em><br/>
|
||||
/// </summary>
|
||||
public event OnLoadCompleteDelegateHandler OnLoadComplete;
|
||||
|
||||
/// <summary>
|
||||
/// Invoked when a <see cref="SceneEventType.UnloadComplete"/> event is generated by a client or server.<br/>
|
||||
/// <em>Note: The server receives this message from all clients (including itself).
|
||||
/// Each client receives their own notification sent to the server.</em>
|
||||
/// Each client receives their own notification sent to the server.</em><br/>
|
||||
/// <em>*** Do not start new scene events within scene event notification callbacks.</em><br/>
|
||||
/// </summary>
|
||||
public event OnUnloadCompleteDelegateHandler OnUnloadComplete;
|
||||
|
||||
@@ -296,6 +305,7 @@ namespace Unity.Netcode
|
||||
/// <em> Note: The server receives this message from the client, but will never generate this event for itself.
|
||||
/// Each client receives their own notification sent to the server. This is useful to know that a client has
|
||||
/// completed the entire connection sequence, loaded all scenes, and synchronized all NetworkObjects.</em>
|
||||
/// <em>*** Do not start new scene events within scene event notification callbacks.</em><br/>
|
||||
/// </summary>
|
||||
public event OnSynchronizeCompleteDelegateHandler OnSynchronizeComplete;
|
||||
|
||||
@@ -319,8 +329,12 @@ namespace Unity.Netcode
|
||||
public VerifySceneBeforeLoadingDelegateHandler VerifySceneBeforeLoading;
|
||||
|
||||
/// <summary>
|
||||
/// Proof of concept: Interface version that allows for the decoupling from
|
||||
/// the SceneManager's Load and Unload methods for testing purposes (potentially other future usage)
|
||||
/// The SceneManagerHandler implementation
|
||||
/// </summary>
|
||||
internal ISceneManagerHandler SceneManagerHandler = new DefaultSceneManagerHandler();
|
||||
|
||||
/// <summary>
|
||||
/// The default SceneManagerHandler that interfaces between the SceneManager and NetworkSceneManager
|
||||
/// </summary>
|
||||
private class DefaultSceneManagerHandler : ISceneManagerHandler
|
||||
{
|
||||
@@ -339,10 +353,6 @@ namespace Unity.Netcode
|
||||
}
|
||||
}
|
||||
|
||||
internal ISceneManagerHandler SceneManagerHandler = new DefaultSceneManagerHandler();
|
||||
/// End of Proof of Concept
|
||||
|
||||
|
||||
internal readonly Dictionary<Guid, SceneEventProgress> SceneEventProgressTracking = new Dictionary<Guid, SceneEventProgress>();
|
||||
|
||||
/// <summary>
|
||||
@@ -425,6 +435,8 @@ namespace Unity.Netcode
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
SceneUnloadEventHandler.Shutdown();
|
||||
|
||||
foreach (var keypair in SceneEventDataStore)
|
||||
{
|
||||
if (NetworkLog.CurrentLogLevel <= LogLevel.Normal)
|
||||
@@ -632,6 +644,12 @@ namespace Unity.Netcode
|
||||
return validated;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Used for NetcodeIntegrationTest testing in order to properly
|
||||
/// assign the right loaded scene to the right client's ScenesLoaded list
|
||||
/// </summary>
|
||||
internal Func<string, Scene> OverrideGetAndAddNewlyLoadedSceneByName;
|
||||
|
||||
/// <summary>
|
||||
/// Since SceneManager.GetSceneByName only returns the first scene that matches the name
|
||||
/// we must "find" a newly added scene by looking through all loaded scenes and determining
|
||||
@@ -643,20 +661,27 @@ namespace Unity.Netcode
|
||||
/// <returns></returns>
|
||||
internal Scene GetAndAddNewlyLoadedSceneByName(string sceneName)
|
||||
{
|
||||
for (int i = 0; i < SceneManager.sceneCount; i++)
|
||||
if (OverrideGetAndAddNewlyLoadedSceneByName != null)
|
||||
{
|
||||
var sceneLoaded = SceneManager.GetSceneAt(i);
|
||||
if (sceneLoaded.name == sceneName)
|
||||
return OverrideGetAndAddNewlyLoadedSceneByName.Invoke(sceneName);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < SceneManager.sceneCount; i++)
|
||||
{
|
||||
if (!ScenesLoaded.ContainsKey(sceneLoaded.handle))
|
||||
var sceneLoaded = SceneManager.GetSceneAt(i);
|
||||
if (sceneLoaded.name == sceneName)
|
||||
{
|
||||
ScenesLoaded.Add(sceneLoaded.handle, sceneLoaded);
|
||||
return sceneLoaded;
|
||||
if (!ScenesLoaded.ContainsKey(sceneLoaded.handle))
|
||||
{
|
||||
ScenesLoaded.Add(sceneLoaded.handle, sceneLoaded);
|
||||
return sceneLoaded;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
throw new Exception($"Failed to find any loaded scene named {sceneName}!");
|
||||
throw new Exception($"Failed to find any loaded scene named {sceneName}!");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -720,18 +745,18 @@ namespace Unity.Netcode
|
||||
/// </summary>
|
||||
/// <param name="globalObjectIdHash"></param>
|
||||
/// <returns></returns>
|
||||
internal NetworkObject GetSceneRelativeInSceneNetworkObject(uint globalObjectIdHash)
|
||||
internal NetworkObject GetSceneRelativeInSceneNetworkObject(uint globalObjectIdHash, int? networkSceneHandle)
|
||||
{
|
||||
if (ScenePlacedObjects.ContainsKey(globalObjectIdHash))
|
||||
{
|
||||
if (ScenePlacedObjects[globalObjectIdHash].ContainsKey(SceneBeingSynchronized.handle))
|
||||
var sceneHandle = SceneBeingSynchronized.handle;
|
||||
if (networkSceneHandle.HasValue && networkSceneHandle.Value != 0)
|
||||
{
|
||||
var inScenePlacedNetworkObject = ScenePlacedObjects[globalObjectIdHash][SceneBeingSynchronized.handle];
|
||||
|
||||
// We can only have 1 duplicated globalObjectIdHash per scene instance, so remove it once it has been returned
|
||||
ScenePlacedObjects[globalObjectIdHash].Remove(SceneBeingSynchronized.handle);
|
||||
|
||||
return inScenePlacedNetworkObject;
|
||||
sceneHandle = ServerSceneHandleToClientSceneHandle[networkSceneHandle.Value];
|
||||
}
|
||||
if (ScenePlacedObjects[globalObjectIdHash].ContainsKey(sceneHandle))
|
||||
{
|
||||
return ScenePlacedObjects[globalObjectIdHash][sceneHandle];
|
||||
}
|
||||
}
|
||||
return null;
|
||||
@@ -859,7 +884,6 @@ namespace Unity.Netcode
|
||||
/// Callback for the <see cref="SceneEventProgress.OnComplete"/> <see cref="SceneEventProgress.OnCompletedDelegate"/> handler
|
||||
/// </summary>
|
||||
/// <param name="sceneEventProgress"></param>
|
||||
/// <returns></returns>
|
||||
private bool OnSceneEventProgressCompleted(SceneEventProgress sceneEventProgress)
|
||||
{
|
||||
var sceneEventData = BeginSceneEvent();
|
||||
@@ -868,7 +892,7 @@ namespace Unity.Netcode
|
||||
sceneEventData.SceneEventType = sceneEventProgress.SceneEventType;
|
||||
sceneEventData.ClientsCompleted = sceneEventProgress.DoneClients;
|
||||
sceneEventData.LoadSceneMode = sceneEventProgress.LoadSceneMode;
|
||||
sceneEventData.ClientsTimedOut = m_NetworkManager.ConnectedClients.Keys.Except(sceneEventProgress.DoneClients).ToList();
|
||||
sceneEventData.ClientsTimedOut = sceneEventProgress.ClientsThatStartedSceneEvent.Except(sceneEventProgress.DoneClients).ToList();
|
||||
|
||||
var message = new SceneEventMessage
|
||||
{
|
||||
@@ -945,11 +969,18 @@ namespace Unity.Netcode
|
||||
sceneEventProgress.SceneEventType = SceneEventType.UnloadEventCompleted;
|
||||
|
||||
ScenesLoaded.Remove(scene.handle);
|
||||
var sceneEventAction = new ISceneManagerHandler.SceneEventAction() { SceneEventId = sceneEventData.SceneEventId, EventAction = OnSceneUnloaded };
|
||||
var sceneUnload = SceneManagerHandler.UnloadSceneAsync(scene, sceneEventAction);
|
||||
|
||||
var sceneUnload = SceneManagerHandler.UnloadSceneAsync(scene,
|
||||
new ISceneManagerHandler.SceneEventAction() { SceneEventId = sceneEventData.SceneEventId, EventAction = OnSceneUnloaded });
|
||||
|
||||
sceneEventProgress.SetSceneLoadOperation(sceneUnload);
|
||||
// If integration testing, IntegrationTestSceneHandler returns null
|
||||
if (sceneUnload == null)
|
||||
{
|
||||
sceneEventProgress.SetSceneLoadOperation(sceneEventAction);
|
||||
}
|
||||
else
|
||||
{
|
||||
sceneEventProgress.SetSceneLoadOperation(sceneUnload);
|
||||
}
|
||||
|
||||
// Notify local server that a scene is going to be unloaded
|
||||
OnSceneEvent?.Invoke(new SceneEvent()
|
||||
@@ -1021,6 +1052,12 @@ namespace Unity.Netcode
|
||||
/// </summary>
|
||||
private void OnSceneUnloaded(uint sceneEventId)
|
||||
{
|
||||
// If we are shutdown or about to shutdown, then ignore this event
|
||||
if (!m_NetworkManager.IsListening || m_NetworkManager.ShutdownInProgress)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var sceneEventData = SceneEventDataStore[sceneEventId];
|
||||
// First thing we do, if we are a server, is to send the unload scene event.
|
||||
if (m_NetworkManager.IsServer)
|
||||
@@ -1064,7 +1101,7 @@ namespace Unity.Netcode
|
||||
|
||||
private void EmptySceneUnloadedOperation(uint sceneEventId)
|
||||
{
|
||||
// Do nothing (this is a stub call since it is only used to flush all currently loaded scenes)
|
||||
// Do nothing (this is a stub call since it is only used to flush all additively loaded scenes)
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1074,6 +1111,7 @@ namespace Unity.Netcode
|
||||
/// </summary>
|
||||
internal void UnloadAdditivelyLoadedScenes(uint sceneEventId)
|
||||
{
|
||||
var sceneEventData = SceneEventDataStore[sceneEventId];
|
||||
// Unload all additive scenes while making sure we don't try to unload the base scene ( loaded in single mode ).
|
||||
var currentActiveScene = SceneManager.GetActiveScene();
|
||||
foreach (var keyHandleEntry in ScenesLoaded)
|
||||
@@ -1083,15 +1121,7 @@ namespace Unity.Netcode
|
||||
{
|
||||
var sceneUnload = SceneManagerHandler.UnloadSceneAsync(keyHandleEntry.Value,
|
||||
new ISceneManagerHandler.SceneEventAction() { SceneEventId = sceneEventId, EventAction = EmptySceneUnloadedOperation });
|
||||
|
||||
OnSceneEvent?.Invoke(new SceneEvent()
|
||||
{
|
||||
AsyncOperation = sceneUnload,
|
||||
SceneEventType = SceneEventType.Unload,
|
||||
SceneName = keyHandleEntry.Value.name,
|
||||
LoadSceneMode = LoadSceneMode.Additive, // The only scenes unloaded are scenes that were additively loaded
|
||||
ClientId = NetworkManager.ServerClientId
|
||||
});
|
||||
SceneUnloadEventHandler.RegisterScene(this, keyHandleEntry.Value, LoadSceneMode.Additive, sceneUnload);
|
||||
}
|
||||
}
|
||||
// clear out our scenes loaded list
|
||||
@@ -1124,12 +1154,12 @@ namespace Unity.Netcode
|
||||
sceneEventData.SceneEventType = SceneEventType.Load;
|
||||
sceneEventData.SceneHash = SceneHashFromNameOrPath(sceneName);
|
||||
sceneEventData.LoadSceneMode = loadSceneMode;
|
||||
|
||||
var sceneEventId = sceneEventData.SceneEventId;
|
||||
// This both checks to make sure the scene is valid and if not resets the active scene event
|
||||
m_IsSceneEventActive = ValidateSceneBeforeLoading(sceneEventData.SceneHash, loadSceneMode);
|
||||
if (!m_IsSceneEventActive)
|
||||
{
|
||||
EndSceneEvent(sceneEventData.SceneEventId);
|
||||
EndSceneEvent(sceneEventId);
|
||||
return SceneEventProgressStatus.SceneFailedVerification;
|
||||
}
|
||||
|
||||
@@ -1142,14 +1172,24 @@ namespace Unity.Netcode
|
||||
MoveObjectsToDontDestroyOnLoad();
|
||||
|
||||
// Now Unload all currently additively loaded scenes
|
||||
UnloadAdditivelyLoadedScenes(sceneEventData.SceneEventId);
|
||||
UnloadAdditivelyLoadedScenes(sceneEventId);
|
||||
|
||||
// Register the active scene for unload scene event notifications
|
||||
SceneUnloadEventHandler.RegisterScene(this, SceneManager.GetActiveScene(), LoadSceneMode.Single);
|
||||
}
|
||||
|
||||
// Now start loading the scene
|
||||
var sceneLoad = SceneManagerHandler.LoadSceneAsync(sceneName, loadSceneMode,
|
||||
new ISceneManagerHandler.SceneEventAction() { SceneEventId = sceneEventData.SceneEventId, EventAction = OnSceneLoaded });
|
||||
|
||||
sceneEventProgress.SetSceneLoadOperation(sceneLoad);
|
||||
var sceneEventAction = new ISceneManagerHandler.SceneEventAction() { SceneEventId = sceneEventId, EventAction = OnSceneLoaded };
|
||||
var sceneLoad = SceneManagerHandler.LoadSceneAsync(sceneName, loadSceneMode, sceneEventAction);
|
||||
// If integration testing, IntegrationTestSceneHandler returns null
|
||||
if (sceneLoad == null)
|
||||
{
|
||||
sceneEventProgress.SetSceneLoadOperation(sceneEventAction);
|
||||
}
|
||||
else
|
||||
{
|
||||
sceneEventProgress.SetSceneLoadOperation(sceneLoad);
|
||||
}
|
||||
|
||||
// Notify the local server that a scene loading event has begun
|
||||
OnSceneEvent?.Invoke(new SceneEvent()
|
||||
@@ -1167,6 +1207,114 @@ namespace Unity.Netcode
|
||||
return sceneEventProgress.Status;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper class used to handle "odd ball" scene unload event notification scenarios
|
||||
/// when scene switching.
|
||||
/// </summary>
|
||||
internal class SceneUnloadEventHandler
|
||||
{
|
||||
private static Dictionary<NetworkManager, List<SceneUnloadEventHandler>> s_Instances = new Dictionary<NetworkManager, List<SceneUnloadEventHandler>>();
|
||||
|
||||
internal static void RegisterScene(NetworkSceneManager networkSceneManager, Scene scene, LoadSceneMode loadSceneMode, AsyncOperation asyncOperation = null)
|
||||
{
|
||||
var networkManager = networkSceneManager.m_NetworkManager;
|
||||
if (!s_Instances.ContainsKey(networkManager))
|
||||
{
|
||||
s_Instances.Add(networkManager, new List<SceneUnloadEventHandler>());
|
||||
}
|
||||
var clientId = networkManager.IsServer ? NetworkManager.ServerClientId : networkManager.LocalClientId;
|
||||
s_Instances[networkManager].Add(new SceneUnloadEventHandler(networkSceneManager, scene, clientId, loadSceneMode, asyncOperation));
|
||||
}
|
||||
|
||||
private static void SceneUnloadComplete(SceneUnloadEventHandler sceneUnloadEventHandler)
|
||||
{
|
||||
if (sceneUnloadEventHandler == null || sceneUnloadEventHandler.m_NetworkSceneManager == null || sceneUnloadEventHandler.m_NetworkSceneManager.m_NetworkManager == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
var networkManager = sceneUnloadEventHandler.m_NetworkSceneManager.m_NetworkManager;
|
||||
if (s_Instances.ContainsKey(networkManager))
|
||||
{
|
||||
s_Instances[networkManager].Remove(sceneUnloadEventHandler);
|
||||
if (s_Instances[networkManager].Count == 0)
|
||||
{
|
||||
s_Instances.Remove(networkManager);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called by NetworkSceneManager when it is disposing
|
||||
/// </summary>
|
||||
internal static void Shutdown()
|
||||
{
|
||||
foreach (var instanceEntry in s_Instances)
|
||||
{
|
||||
foreach (var instance in instanceEntry.Value)
|
||||
{
|
||||
instance.OnShutdown();
|
||||
}
|
||||
instanceEntry.Value.Clear();
|
||||
}
|
||||
s_Instances.Clear();
|
||||
}
|
||||
|
||||
private NetworkSceneManager m_NetworkSceneManager;
|
||||
private AsyncOperation m_AsyncOperation;
|
||||
private LoadSceneMode m_LoadSceneMode;
|
||||
private ulong m_ClientId;
|
||||
private Scene m_Scene;
|
||||
private bool m_ShuttingDown;
|
||||
|
||||
private void OnShutdown()
|
||||
{
|
||||
m_ShuttingDown = true;
|
||||
SceneManager.sceneUnloaded -= SceneUnloaded;
|
||||
}
|
||||
|
||||
private void SceneUnloaded(Scene scene)
|
||||
{
|
||||
if (m_Scene.handle == scene.handle && !m_ShuttingDown)
|
||||
{
|
||||
if (m_NetworkSceneManager != null && m_NetworkSceneManager.m_NetworkManager != null)
|
||||
{
|
||||
m_NetworkSceneManager.OnSceneEvent?.Invoke(new SceneEvent()
|
||||
{
|
||||
AsyncOperation = m_AsyncOperation,
|
||||
SceneEventType = SceneEventType.UnloadComplete,
|
||||
SceneName = m_Scene.name,
|
||||
LoadSceneMode = m_LoadSceneMode,
|
||||
ClientId = m_ClientId
|
||||
});
|
||||
m_NetworkSceneManager.OnUnloadComplete?.Invoke(m_ClientId, m_Scene.name);
|
||||
}
|
||||
SceneManager.sceneUnloaded -= SceneUnloaded;
|
||||
SceneUnloadComplete(this);
|
||||
}
|
||||
}
|
||||
|
||||
private SceneUnloadEventHandler(NetworkSceneManager networkSceneManager, Scene scene, ulong clientId, LoadSceneMode loadSceneMode, AsyncOperation asyncOperation = null)
|
||||
{
|
||||
m_LoadSceneMode = loadSceneMode;
|
||||
m_AsyncOperation = asyncOperation;
|
||||
m_NetworkSceneManager = networkSceneManager;
|
||||
m_ClientId = clientId;
|
||||
m_Scene = scene;
|
||||
SceneManager.sceneUnloaded += SceneUnloaded;
|
||||
// Send the initial unload event notification
|
||||
m_NetworkSceneManager.OnSceneEvent?.Invoke(new SceneEvent()
|
||||
{
|
||||
AsyncOperation = m_AsyncOperation,
|
||||
SceneEventType = SceneEventType.Unload,
|
||||
SceneName = m_Scene.name,
|
||||
LoadSceneMode = m_LoadSceneMode,
|
||||
ClientId = clientId
|
||||
});
|
||||
|
||||
m_NetworkSceneManager.OnUnload?.Invoke(networkSceneManager.m_NetworkManager.LocalClientId, m_Scene.name, null);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Client Side:
|
||||
/// Handles both forms of scene loading
|
||||
@@ -1201,6 +1349,10 @@ namespace Unity.Netcode
|
||||
if (sceneEventData.LoadSceneMode == LoadSceneMode.Single)
|
||||
{
|
||||
IsSpawnedObjectsPendingInDontDestroyOnLoad = true;
|
||||
|
||||
// Register the active scene for unload scene event notifications
|
||||
SceneUnloadEventHandler.RegisterScene(this, SceneManager.GetActiveScene(), LoadSceneMode.Single);
|
||||
|
||||
}
|
||||
|
||||
var sceneLoad = SceneManagerHandler.LoadSceneAsync(sceneName, sceneEventData.LoadSceneMode,
|
||||
@@ -1218,13 +1370,18 @@ namespace Unity.Netcode
|
||||
OnLoad?.Invoke(m_NetworkManager.LocalClientId, sceneName, sceneEventData.LoadSceneMode, sceneLoad);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Client and Server:
|
||||
/// Generic on scene loaded callback method to be called upon a scene loading
|
||||
/// </summary>
|
||||
private void OnSceneLoaded(uint sceneEventId)
|
||||
{
|
||||
// If we are shutdown or about to shutdown, then ignore this event
|
||||
if (!m_NetworkManager.IsListening || m_NetworkManager.ShutdownInProgress)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var sceneEventData = SceneEventDataStore[sceneEventId];
|
||||
var nextScene = GetAndAddNewlyLoadedSceneByName(SceneNameFromHash(sceneEventData.SceneHash));
|
||||
if (!nextScene.isLoaded || !nextScene.IsValid())
|
||||
@@ -1363,6 +1520,13 @@ namespace Unity.Netcode
|
||||
EndSceneEvent(sceneEventId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Used for integration testing, due to the complexities of having all clients loading scenes
|
||||
/// this is needed to "filter" out the scenes not loaded by NetworkSceneManager
|
||||
/// (i.e. we don't want a late joining player to load all of the other client scenes)
|
||||
/// </summary>
|
||||
internal Func<Scene, bool> ExcludeSceneFromSychronization;
|
||||
|
||||
/// <summary>
|
||||
/// Server Side:
|
||||
/// This is used for players that have just had their connection approved and will assure they are synchronized
|
||||
@@ -1389,6 +1553,13 @@ namespace Unity.Netcode
|
||||
{
|
||||
var scene = SceneManager.GetSceneAt(i);
|
||||
|
||||
// NetworkSceneManager does not synchronize scenes that are not loaded by NetworkSceneManager
|
||||
// unless the scene in question is the currently active scene.
|
||||
if (ExcludeSceneFromSychronization != null && !ExcludeSceneFromSychronization(scene))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var sceneHash = SceneHashFromNameOrPath(scene.path);
|
||||
|
||||
// This would depend upon whether we are additive or not
|
||||
@@ -1406,11 +1577,11 @@ namespace Unity.Netcode
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
sceneEventData.AddSceneToSynchronize(sceneHash, scene.handle);
|
||||
}
|
||||
|
||||
sceneEventData.AddSpawnedNetworkObjects();
|
||||
sceneEventData.AddDespawnedInSceneNetworkObjects();
|
||||
|
||||
var message = new SceneEventMessage
|
||||
{
|
||||
@@ -1447,7 +1618,7 @@ namespace Unity.Netcode
|
||||
var loadSceneMode = sceneHash == sceneEventData.SceneHash ? sceneEventData.LoadSceneMode : LoadSceneMode.Additive;
|
||||
|
||||
// Store the sceneHandle and hash
|
||||
sceneEventData.ClientSceneHandle = sceneHandle;
|
||||
sceneEventData.NetworkSceneHandle = sceneHandle;
|
||||
sceneEventData.ClientSceneHash = sceneHash;
|
||||
|
||||
// If this is the beginning of the synchronization event, then send client a notification that synchronization has begun
|
||||
@@ -1536,9 +1707,9 @@ namespace Unity.Netcode
|
||||
SceneManager.SetActiveScene(nextScene);
|
||||
}
|
||||
|
||||
if (!ServerSceneHandleToClientSceneHandle.ContainsKey(sceneEventData.ClientSceneHandle))
|
||||
if (!ServerSceneHandleToClientSceneHandle.ContainsKey(sceneEventData.NetworkSceneHandle))
|
||||
{
|
||||
ServerSceneHandleToClientSceneHandle.Add(sceneEventData.ClientSceneHandle, nextScene.handle);
|
||||
ServerSceneHandleToClientSceneHandle.Add(sceneEventData.NetworkSceneHandle, nextScene.handle);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1862,10 +2033,9 @@ namespace Unity.Netcode
|
||||
foreach (var networkObjectInstance in networkObjects)
|
||||
{
|
||||
var globalObjectIdHash = networkObjectInstance.GlobalObjectIdHash;
|
||||
var sceneHandle = networkObjectInstance.gameObject.scene.handle;
|
||||
var sceneHandle = networkObjectInstance.GetSceneOriginHandle();
|
||||
// We check to make sure the NetworkManager instance is the same one to be "NetcodeIntegrationTestHelpers" compatible and filter the list on a per scene basis (for additive scenes)
|
||||
if (networkObjectInstance.IsSceneObject != false && networkObjectInstance.NetworkManager == m_NetworkManager && networkObjectInstance.gameObject.scene == sceneToFilterBy &&
|
||||
sceneHandle == sceneToFilterBy.handle)
|
||||
if (networkObjectInstance.IsSceneObject != false && networkObjectInstance.NetworkManager == m_NetworkManager && sceneHandle == sceneToFilterBy.handle)
|
||||
{
|
||||
if (!ScenePlacedObjects.ContainsKey(globalObjectIdHash))
|
||||
{
|
||||
|
||||
@@ -100,7 +100,7 @@ namespace Unity.Netcode
|
||||
|
||||
// Used by the client during synchronization
|
||||
internal uint ClientSceneHash;
|
||||
internal int ClientSceneHandle;
|
||||
internal int NetworkSceneHandle;
|
||||
|
||||
/// Only used for <see cref="SceneEventType.Synchronize"/> scene events, this assures permissions when writing
|
||||
/// NetworkVariable information. If that process changes, then we need to update this
|
||||
@@ -118,6 +118,9 @@ namespace Unity.Netcode
|
||||
/// </summary>
|
||||
private List<NetworkObject> m_NetworkObjectsSync = new List<NetworkObject>();
|
||||
|
||||
private List<NetworkObject> m_DespawnedInSceneObjectsSync = new List<NetworkObject>();
|
||||
private Dictionary<int, List<uint>> m_DespawnedInSceneObjects = new Dictionary<int, List<uint>>();
|
||||
|
||||
/// <summary>
|
||||
/// Server Side Re-Synchronization:
|
||||
/// If there happens to be NetworkObjects in the final Event_Sync_Complete message that are no longer spawned,
|
||||
@@ -243,6 +246,19 @@ namespace Unity.Netcode
|
||||
m_NetworkObjectsSync.Sort(SortNetworkObjects);
|
||||
}
|
||||
|
||||
internal void AddDespawnedInSceneNetworkObjects()
|
||||
{
|
||||
m_DespawnedInSceneObjectsSync.Clear();
|
||||
var inSceneNetworkObjects = UnityEngine.Object.FindObjectsOfType<NetworkObject>().Where((c) => c.NetworkManager == m_NetworkManager);
|
||||
foreach (var sobj in inSceneNetworkObjects)
|
||||
{
|
||||
if (sobj.IsSceneObject.HasValue && sobj.IsSceneObject.Value && !sobj.IsSpawned)
|
||||
{
|
||||
m_DespawnedInSceneObjectsSync.Add(sobj);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Server Side:
|
||||
/// Used during the synchronization process to associate NetworkObjects with scenes
|
||||
@@ -372,7 +388,6 @@ namespace Unity.Netcode
|
||||
writer.WriteValueSafe(ScenesToSynchronize.ToArray());
|
||||
writer.WriteValueSafe(SceneHandlesToSynchronize.ToArray());
|
||||
|
||||
|
||||
// Store our current position in the stream to come back and say how much data we have written
|
||||
var positionStart = writer.Position;
|
||||
|
||||
@@ -383,17 +398,31 @@ namespace Unity.Netcode
|
||||
int totalBytes = 0;
|
||||
|
||||
// Write the number of NetworkObjects we are serializing
|
||||
writer.WriteValueSafe(m_NetworkObjectsSync.Count());
|
||||
BytePacker.WriteValuePacked(writer, m_NetworkObjectsSync.Count());
|
||||
// Serialize all NetworkObjects that are spawned
|
||||
for (var i = 0; i < m_NetworkObjectsSync.Count(); ++i)
|
||||
{
|
||||
var noStart = writer.Position;
|
||||
var sceneObject = m_NetworkObjectsSync[i].GetMessageSceneObject(TargetClientId);
|
||||
writer.WriteValueSafe(m_NetworkObjectsSync[i].gameObject.scene.handle);
|
||||
BytePacker.WriteValuePacked(writer, m_NetworkObjectsSync[i].GetSceneOriginHandle());
|
||||
sceneObject.Serialize(writer);
|
||||
var noStop = writer.Position;
|
||||
totalBytes += (int)(noStop - noStart);
|
||||
}
|
||||
|
||||
// Write the number of despawned in-scene placed NetworkObjects
|
||||
writer.WriteValueSafe(m_DespawnedInSceneObjectsSync.Count());
|
||||
// Write the scene handle and GlobalObjectIdHash value
|
||||
for (var i = 0; i < m_DespawnedInSceneObjectsSync.Count(); ++i)
|
||||
{
|
||||
var noStart = writer.Position;
|
||||
var sceneObject = m_DespawnedInSceneObjectsSync[i].GetMessageSceneObject(TargetClientId);
|
||||
BytePacker.WriteValuePacked(writer, m_DespawnedInSceneObjectsSync[i].GetSceneOriginHandle());
|
||||
BytePacker.WriteValuePacked(writer, m_DespawnedInSceneObjectsSync[i].GlobalObjectIdHash);
|
||||
var noStop = writer.Position;
|
||||
totalBytes += (int)(noStop - noStart);
|
||||
}
|
||||
|
||||
// Size Place Holder -- End
|
||||
var positionEnd = writer.Position;
|
||||
var bytesWritten = (uint)(positionEnd - (positionStart + sizeof(uint)));
|
||||
@@ -683,15 +712,16 @@ namespace Unity.Netcode
|
||||
{
|
||||
try
|
||||
{
|
||||
// Process all NetworkObjects for this scene
|
||||
InternalBuffer.ReadValueSafe(out int newObjectsCount);
|
||||
// Process all spawned NetworkObjects for this network session
|
||||
ByteUnpacker.ReadValuePacked(InternalBuffer, out int newObjectsCount);
|
||||
|
||||
|
||||
for (int i = 0; i < newObjectsCount; i++)
|
||||
{
|
||||
// We want to make sure for each NetworkObject we have the appropriate scene selected as the scene that is
|
||||
// currently being synchronized. This assures in-scene placed NetworkObjects will use the right NetworkObject
|
||||
// from the list of populated <see cref="NetworkSceneManager.ScenePlacedObjects"/>
|
||||
InternalBuffer.ReadValueSafe(out int handle);
|
||||
ByteUnpacker.ReadValuePacked(InternalBuffer, out int handle);
|
||||
m_NetworkManager.SceneManager.SetTheSceneBeingSynchronized(handle);
|
||||
|
||||
var sceneObject = new NetworkObject.SceneObject();
|
||||
@@ -703,6 +733,73 @@ namespace Unity.Netcode
|
||||
m_NetworkObjectsSync.Add(spawnedNetworkObject);
|
||||
}
|
||||
}
|
||||
|
||||
// Process all de-spawned in-scene NetworkObjects for this network session
|
||||
m_DespawnedInSceneObjects.Clear();
|
||||
InternalBuffer.ReadValueSafe(out int despawnedObjectsCount);
|
||||
var sceneCache = new Dictionary<int, Dictionary<uint, NetworkObject>>();
|
||||
|
||||
for (int i = 0; i < despawnedObjectsCount; i++)
|
||||
{
|
||||
// We just need to get the scene
|
||||
ByteUnpacker.ReadValuePacked(InternalBuffer, out int networkSceneHandle);
|
||||
ByteUnpacker.ReadValuePacked(InternalBuffer, out uint globalObjectIdHash);
|
||||
var sceneRelativeNetworkObjects = new Dictionary<uint, NetworkObject>();
|
||||
if (!sceneCache.ContainsKey(networkSceneHandle))
|
||||
{
|
||||
if (m_NetworkManager.SceneManager.ServerSceneHandleToClientSceneHandle.ContainsKey(networkSceneHandle))
|
||||
{
|
||||
var localSceneHandle = m_NetworkManager.SceneManager.ServerSceneHandleToClientSceneHandle[networkSceneHandle];
|
||||
if (m_NetworkManager.SceneManager.ScenesLoaded.ContainsKey(localSceneHandle))
|
||||
{
|
||||
var objectRelativeScene = m_NetworkManager.SceneManager.ScenesLoaded[localSceneHandle];
|
||||
var inSceneNetworkObjects = UnityEngine.Object.FindObjectsOfType<NetworkObject>().Where((c) =>
|
||||
c.GetSceneOriginHandle() == localSceneHandle && (c.IsSceneObject != false)).ToList();
|
||||
|
||||
foreach (var inSceneObject in inSceneNetworkObjects)
|
||||
{
|
||||
sceneRelativeNetworkObjects.Add(inSceneObject.GlobalObjectIdHash, inSceneObject);
|
||||
}
|
||||
// Add this to a cache so we don't have to run this potentially multiple times (nothing will spawn or despawn during this time
|
||||
sceneCache.Add(networkSceneHandle, sceneRelativeNetworkObjects);
|
||||
}
|
||||
else
|
||||
{
|
||||
UnityEngine.Debug.LogError($"In-Scene NetworkObject GlobalObjectIdHash ({globalObjectIdHash}) cannot find its relative local scene handle {localSceneHandle}!");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
UnityEngine.Debug.LogError($"In-Scene NetworkObject GlobalObjectIdHash ({globalObjectIdHash}) cannot find its relative NetworkSceneHandle {networkSceneHandle}!");
|
||||
}
|
||||
}
|
||||
else // Use the cached NetworkObjects if they exist
|
||||
{
|
||||
sceneRelativeNetworkObjects = sceneCache[networkSceneHandle];
|
||||
}
|
||||
|
||||
// Now find the in-scene NetworkObject with the current GlobalObjectIdHash we are looking for
|
||||
if (sceneRelativeNetworkObjects.ContainsKey(globalObjectIdHash))
|
||||
{
|
||||
// Since this is a NetworkObject that was never spawned, we just need to send a notification
|
||||
// out that it was despawned so users can make adjustments
|
||||
sceneRelativeNetworkObjects[globalObjectIdHash].InvokeBehaviourNetworkDespawn();
|
||||
if (!m_NetworkManager.SceneManager.ScenePlacedObjects.ContainsKey(globalObjectIdHash))
|
||||
{
|
||||
m_NetworkManager.SceneManager.ScenePlacedObjects.Add(globalObjectIdHash, new Dictionary<int, NetworkObject>());
|
||||
}
|
||||
|
||||
if (!m_NetworkManager.SceneManager.ScenePlacedObjects[globalObjectIdHash].ContainsKey(sceneRelativeNetworkObjects[globalObjectIdHash].GetSceneOriginHandle()))
|
||||
{
|
||||
m_NetworkManager.SceneManager.ScenePlacedObjects[globalObjectIdHash].Add(sceneRelativeNetworkObjects[globalObjectIdHash].GetSceneOriginHandle(), sceneRelativeNetworkObjects[globalObjectIdHash]);
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
UnityEngine.Debug.LogError($"In-Scene NetworkObject GlobalObjectIdHash ({globalObjectIdHash}) could not be found!");
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
||||
@@ -61,9 +61,9 @@ namespace Unity.Netcode
|
||||
internal List<ulong> DoneClients { get; } = new List<ulong>();
|
||||
|
||||
/// <summary>
|
||||
/// The NetworkTime at the moment the scene switch was initiated by the server.
|
||||
/// The local time when the scene event was "roughly started"
|
||||
/// </summary>
|
||||
internal NetworkTime TimeAtInitiation { get; }
|
||||
internal float TimeAtInitiation { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Delegate type for when the switch scene progress is completed. Either by all clients done loading the scene or by time out.
|
||||
@@ -105,22 +105,40 @@ namespace Unity.Netcode
|
||||
|
||||
internal LoadSceneMode LoadSceneMode;
|
||||
|
||||
internal List<ulong> ClientsThatStartedSceneEvent;
|
||||
|
||||
internal SceneEventProgress(NetworkManager networkManager, SceneEventProgressStatus status = SceneEventProgressStatus.Started)
|
||||
{
|
||||
if (status == SceneEventProgressStatus.Started)
|
||||
{
|
||||
// Track the clients that were connected when we started this event
|
||||
ClientsThatStartedSceneEvent = new List<ulong>(networkManager.ConnectedClientsIds);
|
||||
m_NetworkManager = networkManager;
|
||||
m_TimeOutCoroutine = m_NetworkManager.StartCoroutine(TimeOutSceneEventProgress());
|
||||
TimeAtInitiation = networkManager.LocalTime;
|
||||
TimeAtInitiation = Time.realtimeSinceStartup;
|
||||
}
|
||||
Status = status;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Coroutine that checks to see if the scene event is complete every network tick period.
|
||||
/// This will handle completing the scene event when one or more client(s) disconnect(s)
|
||||
/// during a scene event and if it does not complete within the scene loading time out period
|
||||
/// it will time out the scene event.
|
||||
/// </summary>
|
||||
internal IEnumerator TimeOutSceneEventProgress()
|
||||
{
|
||||
yield return new WaitForSecondsRealtime(m_NetworkManager.NetworkConfig.LoadSceneTimeOut);
|
||||
TimedOut = true;
|
||||
CheckCompletion();
|
||||
var waitForNetworkTick = new WaitForSeconds(1.0f / m_NetworkManager.NetworkConfig.TickRate);
|
||||
while (!TimedOut && !IsCompleted)
|
||||
{
|
||||
yield return waitForNetworkTick;
|
||||
|
||||
CheckCompletion();
|
||||
if (!IsCompleted)
|
||||
{
|
||||
TimedOut = TimeAtInitiation - Time.realtimeSinceStartup >= m_NetworkManager.NetworkConfig.LoadSceneTimeOut;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal void AddClientAsDone(ulong clientId)
|
||||
@@ -141,19 +159,49 @@ namespace Unity.Netcode
|
||||
m_SceneLoadOperation.completed += operation => CheckCompletion();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called only on the server-side during integration test (NetcodeIntegrationTest specific)
|
||||
/// scene loading and unloading.
|
||||
///
|
||||
/// Note: During integration testing we must queue all scene loading and unloading requests for
|
||||
/// both the server and all clients so they can be processed in a FIFO/linear fashion to avoid
|
||||
/// conflicts when the <see cref="SceneManager.sceneLoaded"/> and <see cref="SceneManager.sceneUnloaded"/>
|
||||
/// events are triggered. The Completed action simulates the <see cref="AsyncOperation.completed"/> event.
|
||||
/// (See: Unity.Netcode.TestHelpers.Runtime.IntegrationTestSceneHandler)
|
||||
/// </summary>
|
||||
internal void SetSceneLoadOperation(ISceneManagerHandler.SceneEventAction sceneEventAction)
|
||||
{
|
||||
sceneEventAction.Completed = SetComplete;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finalizes the SceneEventProgress
|
||||
/// </summary>
|
||||
internal void SetComplete()
|
||||
{
|
||||
IsCompleted = true;
|
||||
AreAllClientsDoneLoading = true;
|
||||
|
||||
// If OnComplete is not registered or it is and returns true then remove this from the progress tracking
|
||||
if (OnComplete == null || (OnComplete != null && OnComplete.Invoke(this)))
|
||||
{
|
||||
m_NetworkManager.SceneManager.SceneEventProgressTracking.Remove(Guid);
|
||||
}
|
||||
m_NetworkManager.StopCoroutine(m_TimeOutCoroutine);
|
||||
}
|
||||
|
||||
internal void CheckCompletion()
|
||||
{
|
||||
if ((!IsCompleted && DoneClients.Count == m_NetworkManager.ConnectedClientsList.Count && m_SceneLoadOperation.isDone) || (!IsCompleted && TimedOut))
|
||||
try
|
||||
{
|
||||
IsCompleted = true;
|
||||
AreAllClientsDoneLoading = true;
|
||||
|
||||
// If OnComplete is not registered or it is and returns true then remove this from the progress tracking
|
||||
if (OnComplete == null || (OnComplete != null && OnComplete.Invoke(this)))
|
||||
if ((!IsCompleted && DoneClients.Count == m_NetworkManager.ConnectedClientsList.Count && (m_SceneLoadOperation == null || m_SceneLoadOperation.isDone)) || (!IsCompleted && TimedOut))
|
||||
{
|
||||
m_NetworkManager.SceneManager.SceneEventProgressTracking.Remove(Guid);
|
||||
SetComplete();
|
||||
}
|
||||
m_NetworkManager.StopCoroutine(m_TimeOutCoroutine);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.LogException(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user