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:
@@ -1,4 +1,4 @@
|
||||
|
||||
using System;
|
||||
namespace Unity.Netcode.TestHelpers.Runtime
|
||||
{
|
||||
public class ObjectNameIdentifier : NetworkBehaviour
|
||||
@@ -7,36 +7,46 @@ namespace Unity.Netcode.TestHelpers.Runtime
|
||||
private ulong m_CurrentNetworkObjectId;
|
||||
private bool m_IsRegistered;
|
||||
|
||||
private const char k_TagInfoStart = '{';
|
||||
private const char k_TagInfoStop = '}';
|
||||
|
||||
/// <summary>
|
||||
/// Keep a reference to the assigned NetworkObject
|
||||
/// <see cref="OnDestroy"/>
|
||||
/// </summary>
|
||||
[NonSerialized]
|
||||
private NetworkObject m_NetworkObject;
|
||||
private string m_OriginalName;
|
||||
|
||||
public override void OnNetworkSpawn()
|
||||
{
|
||||
RegisterAndLabelNetworkObject();
|
||||
}
|
||||
|
||||
|
||||
protected void RegisterAndLabelNetworkObject()
|
||||
{
|
||||
if (!m_IsRegistered)
|
||||
{
|
||||
if (string.IsNullOrEmpty(m_OriginalName))
|
||||
{
|
||||
m_OriginalName = gameObject.name.Replace("(Clone)", "");
|
||||
}
|
||||
// This is required otherwise it will try to continue to update the NetworkBehaviour even if
|
||||
// it has been destroyed.
|
||||
m_NetworkObject = NetworkObject;
|
||||
m_CurrentOwner = OwnerClientId;
|
||||
m_CurrentNetworkObjectId = NetworkObjectId;
|
||||
var objectOriginalName = gameObject.name.Replace("(Clone)", "");
|
||||
|
||||
var serverOrClient = IsServer ? "Server" : "Client";
|
||||
if (NetworkObject.IsPlayerObject)
|
||||
{
|
||||
gameObject.name = NetworkManager.LocalClientId == OwnerClientId ? $"{objectOriginalName}({OwnerClientId})-Local{objectOriginalName}" :
|
||||
$"{objectOriginalName}({OwnerClientId})-On{serverOrClient}({NetworkManager.LocalClientId})";
|
||||
gameObject.name = NetworkManager.LocalClientId == OwnerClientId ? $"{m_OriginalName}-{k_TagInfoStart}{OwnerClientId}{k_TagInfoStop}-Local{m_OriginalName}" :
|
||||
$"{m_OriginalName}-{k_TagInfoStart}{OwnerClientId}{k_TagInfoStop}- On{serverOrClient}{k_TagInfoStart}{NetworkManager.LocalClientId}{k_TagInfoStop}";
|
||||
}
|
||||
else
|
||||
{
|
||||
gameObject.name = $"{objectOriginalName}({NetworkObjectId})-On{serverOrClient}({NetworkManager.LocalClientId})";
|
||||
gameObject.name = $"{m_OriginalName}{k_TagInfoStart}{NetworkObjectId}{k_TagInfoStop}-On{serverOrClient}{k_TagInfoStart}{NetworkManager.LocalClientId}{k_TagInfoStop}";
|
||||
}
|
||||
|
||||
// Don't add the player objects to the global list of NetworkObjects
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
using UnityEngine.SceneManagement;
|
||||
using Object = UnityEngine.Object;
|
||||
@@ -9,22 +10,51 @@ namespace Unity.Netcode.TestHelpers.Runtime
|
||||
{
|
||||
/// <summary>
|
||||
/// The default SceneManagerHandler used for all NetcodeIntegrationTest derived children.
|
||||
/// This enables clients to load scenes within the same scene hierarchy during integration
|
||||
/// testing.
|
||||
/// </summary>
|
||||
internal class IntegrationTestSceneHandler : ISceneManagerHandler, IDisposable
|
||||
{
|
||||
internal CoroutineRunner CoroutineRunner;
|
||||
// All IntegrationTestSceneHandler instances register their associated NetworkManager
|
||||
internal static List<NetworkManager> NetworkManagers = new List<NetworkManager>();
|
||||
|
||||
// Default client simulated delay time
|
||||
protected const float k_ClientLoadingSimulatedDelay = 0.02f;
|
||||
internal static CoroutineRunner CoroutineRunner;
|
||||
|
||||
internal static Queue<QueuedSceneJob> QueuedSceneJobs = new Queue<QueuedSceneJob>();
|
||||
internal List<Coroutine> CoroutinesRunning = new List<Coroutine>();
|
||||
internal static Coroutine SceneJobProcessor;
|
||||
internal static QueuedSceneJob CurrentQueuedSceneJob;
|
||||
protected static WaitForSeconds s_WaitForSeconds;
|
||||
|
||||
// Controls the client simulated delay time
|
||||
protected float m_ClientLoadingSimulatedDelay = k_ClientLoadingSimulatedDelay;
|
||||
|
||||
public delegate bool CanClientsLoadUnloadDelegateHandler();
|
||||
public event CanClientsLoadUnloadDelegateHandler CanClientsLoad;
|
||||
public event CanClientsLoadUnloadDelegateHandler CanClientsUnload;
|
||||
public static event CanClientsLoadUnloadDelegateHandler CanClientsLoad;
|
||||
public static event CanClientsLoadUnloadDelegateHandler CanClientsUnload;
|
||||
|
||||
internal List<Coroutine> CoroutinesRunning = new List<Coroutine>();
|
||||
|
||||
public static bool VerboseDebugMode;
|
||||
/// <summary>
|
||||
/// Used for loading scenes on the client-side during
|
||||
/// an integration test
|
||||
/// </summary>
|
||||
internal class QueuedSceneJob
|
||||
{
|
||||
public enum JobTypes
|
||||
{
|
||||
Loading,
|
||||
Unloading,
|
||||
Completed
|
||||
}
|
||||
public JobTypes JobType;
|
||||
public string SceneName;
|
||||
public Scene Scene;
|
||||
public ISceneManagerHandler.SceneEventAction SceneAction;
|
||||
public IntegrationTestSceneHandler IntegrationTestSceneHandler;
|
||||
}
|
||||
|
||||
internal NetworkManager NetworkManager;
|
||||
|
||||
internal string NetworkManagerName;
|
||||
|
||||
/// <summary>
|
||||
/// Used to control when clients should attempt to fake-load a scene
|
||||
@@ -44,19 +74,6 @@ namespace Unity.Netcode.TestHelpers.Runtime
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fake-Loads a scene for a client
|
||||
/// </summary>
|
||||
internal IEnumerator ClientLoadSceneCoroutine(string sceneName, ISceneManagerHandler.SceneEventAction sceneEventAction)
|
||||
{
|
||||
yield return new WaitForSeconds(m_ClientLoadingSimulatedDelay);
|
||||
while (!OnCanClientsLoad())
|
||||
{
|
||||
yield return new WaitForSeconds(m_ClientLoadingSimulatedDelay);
|
||||
}
|
||||
sceneEventAction.Invoke();
|
||||
}
|
||||
|
||||
protected bool OnCanClientsUnload()
|
||||
{
|
||||
if (CanClientsUnload != null)
|
||||
@@ -66,35 +83,298 @@ namespace Unity.Netcode.TestHelpers.Runtime
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fake-Unloads a scene for a client
|
||||
/// </summary>
|
||||
internal IEnumerator ClientUnloadSceneCoroutine(ISceneManagerHandler.SceneEventAction sceneEventAction)
|
||||
|
||||
internal static void VerboseDebug(string message)
|
||||
{
|
||||
yield return new WaitForSeconds(m_ClientLoadingSimulatedDelay);
|
||||
while (!OnCanClientsUnload())
|
||||
if (VerboseDebugMode)
|
||||
{
|
||||
yield return new WaitForSeconds(m_ClientLoadingSimulatedDelay);
|
||||
Debug.Log(message);
|
||||
}
|
||||
sceneEventAction.Invoke();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Processes scene loading jobs
|
||||
/// </summary>
|
||||
/// <param name="queuedSceneJob">job to process</param>
|
||||
static internal IEnumerator ProcessLoadingSceneJob(QueuedSceneJob queuedSceneJob)
|
||||
{
|
||||
var itegrationTestSceneHandler = queuedSceneJob.IntegrationTestSceneHandler;
|
||||
while (!itegrationTestSceneHandler.OnCanClientsLoad())
|
||||
{
|
||||
yield return s_WaitForSeconds;
|
||||
}
|
||||
|
||||
SceneManager.sceneLoaded += SceneManager_sceneLoaded;
|
||||
// We always load additively for all scenes during integration tests
|
||||
SceneManager.LoadSceneAsync(queuedSceneJob.SceneName, LoadSceneMode.Additive);
|
||||
|
||||
// Wait for it to finish
|
||||
while (queuedSceneJob.JobType != QueuedSceneJob.JobTypes.Completed)
|
||||
{
|
||||
yield return s_WaitForSeconds;
|
||||
}
|
||||
yield return s_WaitForSeconds;
|
||||
CurrentQueuedSceneJob.SceneAction.Invoke();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles scene loading and assists with making sure the right NetworkManagerOwner
|
||||
/// is assigned to newly instantiated NetworkObjects.
|
||||
///
|
||||
/// Note: Static property usage is OK since jobs are processed one at a time
|
||||
/// </summary>
|
||||
private static void SceneManager_sceneLoaded(Scene scene, LoadSceneMode loadSceneMode)
|
||||
{
|
||||
if (CurrentQueuedSceneJob.JobType != QueuedSceneJob.JobTypes.Completed && CurrentQueuedSceneJob.SceneName == scene.name)
|
||||
{
|
||||
SceneManager.sceneLoaded -= SceneManager_sceneLoaded;
|
||||
|
||||
ProcessInSceneObjects(scene, CurrentQueuedSceneJob.IntegrationTestSceneHandler.NetworkManager);
|
||||
|
||||
CurrentQueuedSceneJob.JobType = QueuedSceneJob.JobTypes.Completed;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles some pre-spawn processing of in-scene placed NetworkObjects
|
||||
/// to make sure the appropriate NetworkManagerOwner is assigned. It
|
||||
/// also makes sure that each in-scene placed NetworkObject has an
|
||||
/// ObjectIdentifier component if one is not assigned to it or its
|
||||
/// children.
|
||||
/// </summary>
|
||||
/// <param name="scene">the scenes that was just loaded</param>
|
||||
/// <param name="networkManager">the relative NetworkManager</param>
|
||||
private static void ProcessInSceneObjects(Scene scene, NetworkManager networkManager)
|
||||
{
|
||||
// Get all in-scene placed NeworkObjects that were instantiated when this scene loaded
|
||||
var inSceneNetworkObjects = Object.FindObjectsOfType<NetworkObject>().Where((c) => c.IsSceneObject != false && c.GetSceneOriginHandle() == scene.handle);
|
||||
foreach (var sobj in inSceneNetworkObjects)
|
||||
{
|
||||
if (sobj.NetworkManagerOwner != networkManager)
|
||||
{
|
||||
sobj.NetworkManagerOwner = networkManager;
|
||||
}
|
||||
if (sobj.GetComponent<ObjectNameIdentifier>() == null && sobj.GetComponentInChildren<ObjectNameIdentifier>() == null)
|
||||
{
|
||||
sobj.gameObject.AddComponent<ObjectNameIdentifier>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Processes scene unloading jobs
|
||||
/// </summary>
|
||||
/// <param name="queuedSceneJob">job to process</param>
|
||||
static internal IEnumerator ProcessUnloadingSceneJob(QueuedSceneJob queuedSceneJob)
|
||||
{
|
||||
var itegrationTestSceneHandler = queuedSceneJob.IntegrationTestSceneHandler;
|
||||
while (!itegrationTestSceneHandler.OnCanClientsUnload())
|
||||
{
|
||||
yield return s_WaitForSeconds;
|
||||
}
|
||||
|
||||
SceneManager.sceneUnloaded += SceneManager_sceneUnloaded;
|
||||
if (queuedSceneJob.Scene.IsValid() && queuedSceneJob.Scene.isLoaded && !queuedSceneJob.Scene.name.Contains(NetcodeIntegrationTestHelpers.FirstPartOfTestRunnerSceneName))
|
||||
{
|
||||
SceneManager.UnloadSceneAsync(queuedSceneJob.Scene);
|
||||
}
|
||||
else
|
||||
{
|
||||
CurrentQueuedSceneJob.JobType = QueuedSceneJob.JobTypes.Completed;
|
||||
}
|
||||
|
||||
// Wait for it to finish
|
||||
while (queuedSceneJob.JobType != QueuedSceneJob.JobTypes.Completed)
|
||||
{
|
||||
yield return s_WaitForSeconds;
|
||||
}
|
||||
CurrentQueuedSceneJob.SceneAction.Invoke();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles closing out scene unloading jobs
|
||||
/// </summary>
|
||||
private static void SceneManager_sceneUnloaded(Scene scene)
|
||||
{
|
||||
if (CurrentQueuedSceneJob.JobType != QueuedSceneJob.JobTypes.Completed && CurrentQueuedSceneJob.Scene.name == scene.name)
|
||||
{
|
||||
SceneManager.sceneUnloaded -= SceneManager_sceneUnloaded;
|
||||
|
||||
CurrentQueuedSceneJob.JobType = QueuedSceneJob.JobTypes.Completed;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Processes all jobs within the queue.
|
||||
/// When all jobs are finished, the coroutine stops.
|
||||
/// </summary>
|
||||
static internal IEnumerator JobQueueProcessor()
|
||||
{
|
||||
while (QueuedSceneJobs.Count != 0)
|
||||
{
|
||||
CurrentQueuedSceneJob = QueuedSceneJobs.Dequeue();
|
||||
VerboseDebug($"[ITSH-START] {CurrentQueuedSceneJob.IntegrationTestSceneHandler.NetworkManagerName} processing {CurrentQueuedSceneJob.JobType} for scene {CurrentQueuedSceneJob.SceneName}.");
|
||||
if (CurrentQueuedSceneJob.JobType == QueuedSceneJob.JobTypes.Loading)
|
||||
{
|
||||
yield return ProcessLoadingSceneJob(CurrentQueuedSceneJob);
|
||||
}
|
||||
else if (CurrentQueuedSceneJob.JobType == QueuedSceneJob.JobTypes.Unloading)
|
||||
{
|
||||
yield return ProcessUnloadingSceneJob(CurrentQueuedSceneJob);
|
||||
}
|
||||
VerboseDebug($"[ITSH-STOP] {CurrentQueuedSceneJob.IntegrationTestSceneHandler.NetworkManagerName} processing {CurrentQueuedSceneJob.JobType} for scene {CurrentQueuedSceneJob.SceneName}.");
|
||||
}
|
||||
SceneJobProcessor = null;
|
||||
yield break;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a job to the job queue, and if the JobQueueProcessor coroutine
|
||||
/// is not running then it will be started as well.
|
||||
/// </summary>
|
||||
/// <param name="queuedSceneJob">job to add to the queue</param>
|
||||
private void AddJobToQueue(QueuedSceneJob queuedSceneJob)
|
||||
{
|
||||
QueuedSceneJobs.Enqueue(queuedSceneJob);
|
||||
if (SceneJobProcessor == null)
|
||||
{
|
||||
SceneJobProcessor = CoroutineRunner.StartCoroutine(JobQueueProcessor());
|
||||
}
|
||||
}
|
||||
|
||||
private string m_ServerSceneBeingLoaded;
|
||||
/// <summary>
|
||||
/// Server always loads like it normally would
|
||||
/// </summary>
|
||||
public AsyncOperation GenericLoadSceneAsync(string sceneName, LoadSceneMode loadSceneMode, ISceneManagerHandler.SceneEventAction sceneEventAction)
|
||||
{
|
||||
m_ServerSceneBeingLoaded = sceneName;
|
||||
if (NetcodeIntegrationTest.IsRunning)
|
||||
{
|
||||
SceneManager.sceneLoaded += Sever_SceneLoaded;
|
||||
}
|
||||
var operation = SceneManager.LoadSceneAsync(sceneName, loadSceneMode);
|
||||
|
||||
operation.completed += new Action<AsyncOperation>(asyncOp2 => { sceneEventAction.Invoke(); });
|
||||
return operation;
|
||||
}
|
||||
|
||||
private void Sever_SceneLoaded(Scene scene, LoadSceneMode arg1)
|
||||
{
|
||||
if (m_ServerSceneBeingLoaded == scene.name)
|
||||
{
|
||||
ProcessInSceneObjects(scene, NetworkManager);
|
||||
SceneManager.sceneLoaded -= Sever_SceneLoaded;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Server always unloads like it normally would
|
||||
/// </summary>
|
||||
public AsyncOperation GenericUnloadSceneAsync(Scene scene, ISceneManagerHandler.SceneEventAction sceneEventAction)
|
||||
{
|
||||
var operation = SceneManager.UnloadSceneAsync(scene);
|
||||
operation.completed += new Action<AsyncOperation>(asyncOp2 => { sceneEventAction.Invoke(); });
|
||||
return operation;
|
||||
}
|
||||
|
||||
|
||||
public AsyncOperation LoadSceneAsync(string sceneName, LoadSceneMode loadSceneMode, ISceneManagerHandler.SceneEventAction sceneEventAction)
|
||||
{
|
||||
CoroutinesRunning.Add(CoroutineRunner.StartCoroutine(ClientLoadSceneCoroutine(sceneName, sceneEventAction)));
|
||||
// This is OK to return a "nothing" AsyncOperation since we are simulating client loading
|
||||
return new AsyncOperation();
|
||||
// Server and non NetcodeIntegrationTest tests use the generic load scene method
|
||||
if (!NetcodeIntegrationTest.IsRunning)
|
||||
{
|
||||
return GenericLoadSceneAsync(sceneName, loadSceneMode, sceneEventAction);
|
||||
}
|
||||
else // NetcodeIntegrationTest Clients always get added to the jobs queue
|
||||
{
|
||||
AddJobToQueue(new QueuedSceneJob() { IntegrationTestSceneHandler = this, SceneName = sceneName, SceneAction = sceneEventAction, JobType = QueuedSceneJob.JobTypes.Loading });
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public AsyncOperation UnloadSceneAsync(Scene scene, ISceneManagerHandler.SceneEventAction sceneEventAction)
|
||||
{
|
||||
CoroutinesRunning.Add(CoroutineRunner.StartCoroutine(ClientUnloadSceneCoroutine(sceneEventAction)));
|
||||
// Server and non NetcodeIntegrationTest tests use the generic unload scene method
|
||||
if (!NetcodeIntegrationTest.IsRunning)
|
||||
{
|
||||
return GenericUnloadSceneAsync(scene, sceneEventAction);
|
||||
}
|
||||
else // NetcodeIntegrationTest Clients always get added to the jobs queue
|
||||
{
|
||||
AddJobToQueue(new QueuedSceneJob() { IntegrationTestSceneHandler = this, Scene = scene, SceneAction = sceneEventAction, JobType = QueuedSceneJob.JobTypes.Unloading });
|
||||
}
|
||||
// This is OK to return a "nothing" AsyncOperation since we are simulating client loading
|
||||
return new AsyncOperation();
|
||||
return null;
|
||||
}
|
||||
|
||||
public IntegrationTestSceneHandler()
|
||||
/// <summary>
|
||||
/// Replacement callback takes other NetworkManagers into consideration
|
||||
/// </summary>
|
||||
internal Scene GetAndAddNewlyLoadedSceneByName(string sceneName)
|
||||
{
|
||||
for (int i = 0; i < SceneManager.sceneCount; i++)
|
||||
{
|
||||
var sceneLoaded = SceneManager.GetSceneAt(i);
|
||||
if (sceneLoaded.name == sceneName)
|
||||
{
|
||||
var skip = false;
|
||||
foreach (var networkManager in NetworkManagers)
|
||||
{
|
||||
if (NetworkManager.LocalClientId == networkManager.LocalClientId || !networkManager.IsListening)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (networkManager.SceneManager.ScenesLoaded.ContainsKey(sceneLoaded.handle))
|
||||
{
|
||||
if (NetworkManager.LogLevel == LogLevel.Developer)
|
||||
{
|
||||
NetworkLog.LogInfo($"{NetworkManager.name}'s ScenesLoaded contains {sceneLoaded.name} with a handle of {sceneLoaded.handle}. Skipping over scene.");
|
||||
}
|
||||
skip = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!skip && !NetworkManager.SceneManager.ScenesLoaded.ContainsKey(sceneLoaded.handle))
|
||||
{
|
||||
if (NetworkManager.LogLevel == LogLevel.Developer)
|
||||
{
|
||||
NetworkLog.LogInfo($"{NetworkManager.name} adding {sceneLoaded.name} with a handle of {sceneLoaded.handle} to its ScenesLoaded.");
|
||||
}
|
||||
NetworkManager.SceneManager.ScenesLoaded.Add(sceneLoaded.handle, sceneLoaded);
|
||||
return sceneLoaded;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
throw new Exception($"Failed to find any loaded scene named {sceneName}!");
|
||||
}
|
||||
|
||||
private bool ExcludeSceneFromSynchronizationCheck(Scene scene)
|
||||
{
|
||||
if (!NetworkManager.SceneManager.ScenesLoaded.ContainsKey(scene.handle) && SceneManager.GetActiveScene().handle != scene.handle)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor now must take NetworkManager
|
||||
/// </summary>
|
||||
public IntegrationTestSceneHandler(NetworkManager networkManager)
|
||||
{
|
||||
networkManager.SceneManager.OverrideGetAndAddNewlyLoadedSceneByName = GetAndAddNewlyLoadedSceneByName;
|
||||
networkManager.SceneManager.ExcludeSceneFromSychronization = ExcludeSceneFromSynchronizationCheck;
|
||||
NetworkManagers.Add(networkManager);
|
||||
NetworkManagerName = networkManager.name;
|
||||
if (s_WaitForSeconds == null)
|
||||
{
|
||||
s_WaitForSeconds = new WaitForSeconds(1.0f / networkManager.NetworkConfig.TickRate);
|
||||
}
|
||||
NetworkManager = networkManager;
|
||||
if (CoroutineRunner == null)
|
||||
{
|
||||
CoroutineRunner = new GameObject("UnitTestSceneHandlerCoroutine").AddComponent<CoroutineRunner>();
|
||||
@@ -103,12 +383,29 @@ namespace Unity.Netcode.TestHelpers.Runtime
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
foreach (var coroutine in CoroutinesRunning)
|
||||
NetworkManagers.Clear();
|
||||
if (SceneJobProcessor != null)
|
||||
{
|
||||
CoroutineRunner.StopCoroutine(coroutine);
|
||||
CoroutineRunner.StopCoroutine(SceneJobProcessor);
|
||||
SceneJobProcessor = null;
|
||||
}
|
||||
CoroutineRunner.StopAllCoroutines();
|
||||
|
||||
foreach (var job in QueuedSceneJobs)
|
||||
{
|
||||
if (job.JobType != QueuedSceneJob.JobTypes.Completed)
|
||||
{
|
||||
if (job.JobType == QueuedSceneJob.JobTypes.Loading)
|
||||
{
|
||||
SceneManager.sceneLoaded -= SceneManager_sceneLoaded;
|
||||
}
|
||||
else
|
||||
{
|
||||
SceneManager.sceneUnloaded -= SceneManager_sceneUnloaded;
|
||||
}
|
||||
job.JobType = QueuedSceneJob.JobTypes.Completed;
|
||||
}
|
||||
}
|
||||
QueuedSceneJobs.Clear();
|
||||
Object.Destroy(CoroutineRunner.gameObject);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using UnityEngine;
|
||||
using UnityEngine.SceneManagement;
|
||||
using UnityEngine.TestTools;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
@@ -16,7 +17,12 @@ namespace Unity.Netcode.TestHelpers.Runtime
|
||||
/// </summary>
|
||||
public abstract class NetcodeIntegrationTest
|
||||
{
|
||||
protected static TimeoutHelper s_GlobalTimeoutHelper = new TimeoutHelper(4.0f);
|
||||
/// <summary>
|
||||
/// Used to determine if a NetcodeIntegrationTest is currently running to
|
||||
/// determine how clients will load scenes
|
||||
/// </summary>
|
||||
internal static bool IsRunning { get; private set; }
|
||||
protected static TimeoutHelper s_GlobalTimeoutHelper = new TimeoutHelper(8.0f);
|
||||
protected static WaitForSeconds s_DefaultWaitForTick = new WaitForSeconds(1.0f / k_DefaultTickRate);
|
||||
|
||||
/// <summary>
|
||||
@@ -74,9 +80,11 @@ namespace Unity.Netcode.TestHelpers.Runtime
|
||||
}
|
||||
}
|
||||
|
||||
protected int TotalClients => m_UseHost ? NumberOfClients + 1 : NumberOfClients;
|
||||
protected int TotalClients => m_UseHost ? m_NumberOfClients + 1 : m_NumberOfClients;
|
||||
|
||||
protected const uint k_DefaultTickRate = 30;
|
||||
|
||||
private int m_NumberOfClients;
|
||||
protected abstract int NumberOfClients { get; }
|
||||
|
||||
/// <summary>
|
||||
@@ -119,7 +127,7 @@ namespace Unity.Netcode.TestHelpers.Runtime
|
||||
|
||||
private NetworkManagerInstatiationMode m_NetworkManagerInstatiationMode;
|
||||
|
||||
private bool m_EnableVerboseDebug;
|
||||
protected bool m_EnableVerboseDebug { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Used to display the various integration test
|
||||
@@ -165,8 +173,11 @@ namespace Unity.Netcode.TestHelpers.Runtime
|
||||
[OneTimeSetUp]
|
||||
public void OneTimeSetup()
|
||||
{
|
||||
Application.runInBackground = true;
|
||||
m_NumberOfClients = NumberOfClients;
|
||||
IsRunning = true;
|
||||
m_EnableVerboseDebug = OnSetVerboseDebug();
|
||||
|
||||
IntegrationTestSceneHandler.VerboseDebugMode = m_EnableVerboseDebug;
|
||||
VerboseDebug($"Entering {nameof(OneTimeSetup)}");
|
||||
|
||||
m_NetworkManagerInstatiationMode = OnSetIntegrationTestMode();
|
||||
@@ -248,6 +259,61 @@ namespace Unity.Netcode.TestHelpers.Runtime
|
||||
CreateServerAndClients(NumberOfClients);
|
||||
}
|
||||
|
||||
protected virtual void OnNewClientCreated(NetworkManager networkManager)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
protected virtual void OnNewClientStartedAndConnected(NetworkManager networkManager)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
private void AddRemoveNetworkManager(NetworkManager networkManager, bool addNetworkManager)
|
||||
{
|
||||
var clientNetworkManagersList = new List<NetworkManager>(m_ClientNetworkManagers);
|
||||
if (addNetworkManager)
|
||||
{
|
||||
clientNetworkManagersList.Add(networkManager);
|
||||
}
|
||||
else
|
||||
{
|
||||
clientNetworkManagersList.Remove(networkManager);
|
||||
}
|
||||
m_ClientNetworkManagers = clientNetworkManagersList.ToArray();
|
||||
m_NumberOfClients = clientNetworkManagersList.Count;
|
||||
}
|
||||
|
||||
protected IEnumerator CreateAndStartNewClient()
|
||||
{
|
||||
var networkManager = NetcodeIntegrationTestHelpers.CreateNewClient(m_ClientNetworkManagers.Length);
|
||||
networkManager.NetworkConfig.PlayerPrefab = m_PlayerPrefab;
|
||||
|
||||
// Notification that the new client (NetworkManager) has been created
|
||||
// in the event any modifications need to be made before starting the client
|
||||
OnNewClientCreated(networkManager);
|
||||
|
||||
NetcodeIntegrationTestHelpers.StartOneClient(networkManager);
|
||||
AddRemoveNetworkManager(networkManager, true);
|
||||
// Wait for the new client to connect
|
||||
yield return WaitForClientsConnectedOrTimeOut();
|
||||
if (s_GlobalTimeoutHelper.TimedOut)
|
||||
{
|
||||
AddRemoveNetworkManager(networkManager, false);
|
||||
Object.Destroy(networkManager.gameObject);
|
||||
}
|
||||
AssertOnTimeout($"{nameof(CreateAndStartNewClient)} timed out waiting for the new client to be connected!");
|
||||
ClientNetworkManagerPostStart(networkManager);
|
||||
VerboseDebug($"[{networkManager.name}] Created and connected!");
|
||||
}
|
||||
|
||||
protected IEnumerator StopOneClient(NetworkManager networkManager, bool destroy = false)
|
||||
{
|
||||
NetcodeIntegrationTestHelpers.StopOneClient(networkManager, destroy);
|
||||
AddRemoveNetworkManager(networkManager, false);
|
||||
yield return WaitForConditionOrTimeOut(() => !networkManager.IsConnectedClient);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates the server and clients
|
||||
/// </summary>
|
||||
@@ -315,6 +381,54 @@ namespace Unity.Netcode.TestHelpers.Runtime
|
||||
yield return null;
|
||||
}
|
||||
|
||||
private void ClientNetworkManagerPostStart(NetworkManager networkManager)
|
||||
{
|
||||
networkManager.name = $"NetworkManager - Client - {networkManager.LocalClientId}";
|
||||
Assert.NotNull(networkManager.LocalClient.PlayerObject, $"{nameof(StartServerAndClients)} detected that client {networkManager.LocalClientId} does not have an assigned player NetworkObject!");
|
||||
|
||||
// Get all player instances for the current client NetworkManager instance
|
||||
var clientPlayerClones = Object.FindObjectsOfType<NetworkObject>().Where((c) => c.IsPlayerObject && c.OwnerClientId == networkManager.LocalClientId);
|
||||
// Add this player instance to each client player entry
|
||||
foreach (var playerNetworkObject in clientPlayerClones)
|
||||
{
|
||||
// When the server is not the host this needs to be done
|
||||
if (!m_PlayerNetworkObjects.ContainsKey(playerNetworkObject.NetworkManager.LocalClientId))
|
||||
{
|
||||
m_PlayerNetworkObjects.Add(playerNetworkObject.NetworkManager.LocalClientId, new Dictionary<ulong, NetworkObject>());
|
||||
}
|
||||
if (!m_PlayerNetworkObjects[playerNetworkObject.NetworkManager.LocalClientId].ContainsKey(networkManager.LocalClientId))
|
||||
{
|
||||
m_PlayerNetworkObjects[playerNetworkObject.NetworkManager.LocalClientId].Add(networkManager.LocalClientId, playerNetworkObject);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void ClientNetworkManagerPostStartInit()
|
||||
{
|
||||
// Creates a dictionary for all player instances client and server relative
|
||||
// This provides a simpler way to get a specific player instance relative to a client instance
|
||||
foreach (var networkManager in m_ClientNetworkManagers)
|
||||
{
|
||||
ClientNetworkManagerPostStart(networkManager);
|
||||
}
|
||||
if (m_UseHost)
|
||||
{
|
||||
var clientSideServerPlayerClones = Object.FindObjectsOfType<NetworkObject>().Where((c) => c.IsPlayerObject && c.OwnerClientId == m_ServerNetworkManager.LocalClientId);
|
||||
foreach (var playerNetworkObject in clientSideServerPlayerClones)
|
||||
{
|
||||
// When the server is not the host this needs to be done
|
||||
if (!m_PlayerNetworkObjects.ContainsKey(playerNetworkObject.NetworkManager.LocalClientId))
|
||||
{
|
||||
m_PlayerNetworkObjects.Add(playerNetworkObject.NetworkManager.LocalClientId, new Dictionary<ulong, NetworkObject>());
|
||||
}
|
||||
if (!m_PlayerNetworkObjects[playerNetworkObject.NetworkManager.LocalClientId].ContainsKey(m_ServerNetworkManager.LocalClientId))
|
||||
{
|
||||
m_PlayerNetworkObjects[playerNetworkObject.NetworkManager.LocalClientId].Add(m_ServerNetworkManager.LocalClientId, playerNetworkObject);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This starts the server and clients as long as <see cref="CanStartServerAndClients"/>
|
||||
/// returns true.
|
||||
@@ -340,8 +454,7 @@ namespace Unity.Netcode.TestHelpers.Runtime
|
||||
|
||||
// Wait for all clients to connect
|
||||
yield return WaitForClientsConnectedOrTimeOut();
|
||||
|
||||
Assert.False(s_GlobalTimeoutHelper.TimedOut, $"{nameof(StartServerAndClients)} timed out waiting for all clients to be connected!");
|
||||
AssertOnTimeout($"{nameof(StartServerAndClients)} timed out waiting for all clients to be connected!");
|
||||
|
||||
if (m_UseHost || m_ServerNetworkManager.IsHost)
|
||||
{
|
||||
@@ -357,25 +470,7 @@ namespace Unity.Netcode.TestHelpers.Runtime
|
||||
}
|
||||
}
|
||||
|
||||
// Creates a dictionary for all player instances client and server relative
|
||||
// This provides a simpler way to get a specific player instance relative to a client instance
|
||||
foreach (var networkManager in m_ClientNetworkManagers)
|
||||
{
|
||||
Assert.NotNull(networkManager.LocalClient.PlayerObject, $"{nameof(StartServerAndClients)} detected that client {networkManager.LocalClientId} does not have an assigned player NetworkObject!");
|
||||
|
||||
// Get all player instances for the current client NetworkManager instance
|
||||
var clientPlayerClones = Object.FindObjectsOfType<NetworkObject>().Where((c) => c.IsPlayerObject && c.OwnerClientId == networkManager.LocalClientId);
|
||||
// Add this player instance to each client player entry
|
||||
foreach (var playerNetworkObject in clientPlayerClones)
|
||||
{
|
||||
// When the server is not the host this needs to be done
|
||||
if (!m_PlayerNetworkObjects.ContainsKey(playerNetworkObject.NetworkManager.LocalClientId))
|
||||
{
|
||||
m_PlayerNetworkObjects.Add(playerNetworkObject.NetworkManager.LocalClientId, new Dictionary<ulong, NetworkObject>());
|
||||
}
|
||||
m_PlayerNetworkObjects[playerNetworkObject.NetworkManager.LocalClientId].Add(networkManager.LocalClientId, playerNetworkObject);
|
||||
}
|
||||
}
|
||||
ClientNetworkManagerPostStartInit();
|
||||
|
||||
// Notification that at this time the server and client(s) are instantiated,
|
||||
// started, and connected on both sides.
|
||||
@@ -409,11 +504,9 @@ namespace Unity.Netcode.TestHelpers.Runtime
|
||||
/// </summary>
|
||||
protected void DeRegisterSceneManagerHandler()
|
||||
{
|
||||
if (NetcodeIntegrationTestHelpers.ClientSceneHandler != null)
|
||||
{
|
||||
NetcodeIntegrationTestHelpers.ClientSceneHandler.CanClientsLoad -= ClientSceneHandler_CanClientsLoad;
|
||||
NetcodeIntegrationTestHelpers.ClientSceneHandler.CanClientsUnload -= ClientSceneHandler_CanClientsUnload;
|
||||
}
|
||||
IntegrationTestSceneHandler.CanClientsLoad -= ClientSceneHandler_CanClientsLoad;
|
||||
IntegrationTestSceneHandler.CanClientsUnload -= ClientSceneHandler_CanClientsUnload;
|
||||
IntegrationTestSceneHandler.NetworkManagers.Clear();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -423,11 +516,9 @@ namespace Unity.Netcode.TestHelpers.Runtime
|
||||
/// </summary>
|
||||
protected void RegisterSceneManagerHandler()
|
||||
{
|
||||
if (NetcodeIntegrationTestHelpers.ClientSceneHandler != null)
|
||||
{
|
||||
NetcodeIntegrationTestHelpers.ClientSceneHandler.CanClientsLoad += ClientSceneHandler_CanClientsLoad;
|
||||
NetcodeIntegrationTestHelpers.ClientSceneHandler.CanClientsUnload += ClientSceneHandler_CanClientsUnload;
|
||||
}
|
||||
IntegrationTestSceneHandler.CanClientsLoad += ClientSceneHandler_CanClientsLoad;
|
||||
IntegrationTestSceneHandler.CanClientsUnload += ClientSceneHandler_CanClientsUnload;
|
||||
NetcodeIntegrationTestHelpers.RegisterSceneManagerHandler(m_ServerNetworkManager, true);
|
||||
}
|
||||
|
||||
private bool ClientSceneHandler_CanClientsUnload()
|
||||
@@ -440,6 +531,11 @@ namespace Unity.Netcode.TestHelpers.Runtime
|
||||
return CanClientsLoad();
|
||||
}
|
||||
|
||||
protected bool OnCanSceneCleanUpUnload(Scene scene)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This shuts down all NetworkManager instances registered via the
|
||||
/// <see cref="NetcodeIntegrationTestHelpers"/> class and cleans up
|
||||
@@ -452,11 +548,7 @@ namespace Unity.Netcode.TestHelpers.Runtime
|
||||
// Shutdown and clean up both of our NetworkManager instances
|
||||
try
|
||||
{
|
||||
if (NetcodeIntegrationTestHelpers.ClientSceneHandler != null)
|
||||
{
|
||||
NetcodeIntegrationTestHelpers.ClientSceneHandler.CanClientsLoad -= ClientSceneHandler_CanClientsLoad;
|
||||
NetcodeIntegrationTestHelpers.ClientSceneHandler.CanClientsUnload -= ClientSceneHandler_CanClientsUnload;
|
||||
}
|
||||
DeRegisterSceneManagerHandler();
|
||||
|
||||
NetcodeIntegrationTestHelpers.Destroy();
|
||||
|
||||
@@ -476,6 +568,8 @@ namespace Unity.Netcode.TestHelpers.Runtime
|
||||
// Cleanup any remaining NetworkObjects
|
||||
DestroySceneNetworkObjects();
|
||||
|
||||
UnloadRemainingScenes();
|
||||
|
||||
// reset the m_ServerWaitForTick for the next test to initialize
|
||||
s_DefaultWaitForTick = new WaitForSeconds(1.0f / k_DefaultTickRate);
|
||||
VerboseDebug($"Exiting {nameof(ShutdownAndCleanUp)}");
|
||||
@@ -517,6 +611,7 @@ namespace Unity.Netcode.TestHelpers.Runtime
|
||||
[OneTimeTearDown]
|
||||
public void OneTimeTearDown()
|
||||
{
|
||||
IntegrationTestSceneHandler.VerboseDebugMode = false;
|
||||
VerboseDebug($"Entering {nameof(OneTimeTearDown)}");
|
||||
OnOneTimeTearDown();
|
||||
|
||||
@@ -528,7 +623,11 @@ namespace Unity.Netcode.TestHelpers.Runtime
|
||||
// Disable NetcodeIntegrationTest auto-label feature
|
||||
NetcodeIntegrationTestHelpers.RegisterNetcodeIntegrationTest(false);
|
||||
|
||||
UnloadRemainingScenes();
|
||||
|
||||
VerboseDebug($"Exiting {nameof(OneTimeTearDown)}");
|
||||
|
||||
IsRunning = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -783,5 +882,32 @@ namespace Unity.Netcode.TestHelpers.Runtime
|
||||
{
|
||||
m_UseHost = hostOrServer == HostOrServer.Host ? true : false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Just a helper function to avoid having to write the entire assert just to check if you
|
||||
/// timed out.
|
||||
/// </summary>
|
||||
protected void AssertOnTimeout(string timeOutErrorMessage, TimeoutHelper assignedTimeoutHelper = null)
|
||||
{
|
||||
var timeoutHelper = assignedTimeoutHelper != null ? assignedTimeoutHelper : s_GlobalTimeoutHelper;
|
||||
Assert.False(timeoutHelper.TimedOut, timeOutErrorMessage);
|
||||
}
|
||||
|
||||
private void UnloadRemainingScenes()
|
||||
{
|
||||
// Unload any remaining scenes loaded but the test runner scene
|
||||
// Note: Some tests only unload the server-side instance, and this
|
||||
// just assures no currently loaded scenes will impact the next test
|
||||
for (int i = 0; i < SceneManager.sceneCount; i++)
|
||||
{
|
||||
var scene = SceneManager.GetSceneAt(i);
|
||||
if (!scene.IsValid() || !scene.isLoaded || scene.name.Contains(NetcodeIntegrationTestHelpers.FirstPartOfTestRunnerSceneName) || !OnCanSceneCleanUpUnload(scene))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
VerboseDebug($"Unloading scene {scene.name}-{scene.handle}");
|
||||
var asyncOperation = SceneManager.UnloadSceneAsync(scene);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ namespace Unity.Netcode.TestHelpers.Runtime
|
||||
public static class NetcodeIntegrationTestHelpers
|
||||
{
|
||||
public const int DefaultMinFrames = 1;
|
||||
public const float DefaultTimeout = 1f;
|
||||
public const float DefaultTimeout = 4f;
|
||||
private static List<NetworkManager> s_NetworkManagerInstances = new List<NetworkManager>();
|
||||
private static Dictionary<NetworkManager, MultiInstanceHooks> s_Hooks = new Dictionary<NetworkManager, MultiInstanceHooks>();
|
||||
private static bool s_IsStarted;
|
||||
@@ -118,25 +118,23 @@ namespace Unity.Netcode.TestHelpers.Runtime
|
||||
}
|
||||
}
|
||||
|
||||
private const string k_FirstPartOfTestRunnerSceneName = "InitTestScene";
|
||||
internal const string FirstPartOfTestRunnerSceneName = "InitTestScene";
|
||||
|
||||
public static List<NetworkManager> NetworkManagerInstances => s_NetworkManagerInstances;
|
||||
|
||||
internal static IntegrationTestSceneHandler ClientSceneHandler = null;
|
||||
internal static List<IntegrationTestSceneHandler> ClientSceneHandlers = new List<IntegrationTestSceneHandler>();
|
||||
|
||||
/// <summary>
|
||||
/// Registers the IntegrationTestSceneHandler for integration tests.
|
||||
/// The default client behavior is to not load scenes on the client side.
|
||||
/// </summary>
|
||||
private static void RegisterSceneManagerHandler(NetworkManager networkManager)
|
||||
internal static void RegisterSceneManagerHandler(NetworkManager networkManager, bool allowServer = false)
|
||||
{
|
||||
if (!networkManager.IsServer)
|
||||
if (!networkManager.IsServer || networkManager.IsServer && allowServer)
|
||||
{
|
||||
if (ClientSceneHandler == null)
|
||||
{
|
||||
ClientSceneHandler = new IntegrationTestSceneHandler();
|
||||
}
|
||||
networkManager.SceneManager.SceneManagerHandler = ClientSceneHandler;
|
||||
var handler = new IntegrationTestSceneHandler(networkManager);
|
||||
ClientSceneHandlers.Add(handler);
|
||||
networkManager.SceneManager.SceneManagerHandler = handler;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -148,11 +146,11 @@ namespace Unity.Netcode.TestHelpers.Runtime
|
||||
/// </summary>
|
||||
public static void CleanUpHandlers()
|
||||
{
|
||||
if (ClientSceneHandler != null)
|
||||
foreach (var handler in ClientSceneHandlers)
|
||||
{
|
||||
ClientSceneHandler.Dispose();
|
||||
ClientSceneHandler = null;
|
||||
handler.Dispose();
|
||||
}
|
||||
ClientSceneHandlers.Clear();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -171,17 +169,10 @@ namespace Unity.Netcode.TestHelpers.Runtime
|
||||
}
|
||||
}
|
||||
|
||||
public static NetworkManager CreateServer()
|
||||
private static void AddUnityTransport(NetworkManager networkManager)
|
||||
{
|
||||
// Create gameObject
|
||||
var go = new GameObject("NetworkManager - Server");
|
||||
|
||||
// Create networkManager component
|
||||
var server = go.AddComponent<NetworkManager>();
|
||||
NetworkManagerInstances.Insert(0, server);
|
||||
|
||||
// Create transport
|
||||
var unityTransport = go.AddComponent<UnityTransport>();
|
||||
var unityTransport = networkManager.gameObject.AddComponent<UnityTransport>();
|
||||
// We need to increase this buffer size for tests that spawn a bunch of things
|
||||
unityTransport.MaxPayloadSize = 256000;
|
||||
unityTransport.MaxSendQueueSize = 1024 * 1024;
|
||||
@@ -191,11 +182,22 @@ namespace Unity.Netcode.TestHelpers.Runtime
|
||||
unityTransport.ConnectTimeoutMS = 500;
|
||||
|
||||
// Set the NetworkConfig
|
||||
server.NetworkConfig = new NetworkConfig()
|
||||
networkManager.NetworkConfig = new NetworkConfig()
|
||||
{
|
||||
// Set transport
|
||||
NetworkTransport = unityTransport
|
||||
};
|
||||
}
|
||||
|
||||
public static NetworkManager CreateServer()
|
||||
{
|
||||
// Create gameObject
|
||||
var go = new GameObject("NetworkManager - Server");
|
||||
|
||||
// Create networkManager component
|
||||
var server = go.AddComponent<NetworkManager>();
|
||||
NetworkManagerInstances.Insert(0, server);
|
||||
AddUnityTransport(server);
|
||||
return server;
|
||||
}
|
||||
|
||||
@@ -229,6 +231,17 @@ namespace Unity.Netcode.TestHelpers.Runtime
|
||||
return true;
|
||||
}
|
||||
|
||||
internal static NetworkManager CreateNewClient(int identifier)
|
||||
{
|
||||
// Create gameObject
|
||||
var go = new GameObject("NetworkManager - Client - " + identifier);
|
||||
// Create networkManager component
|
||||
var networkManager = go.AddComponent<NetworkManager>();
|
||||
AddUnityTransport(networkManager);
|
||||
return networkManager;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Used to add a client to the already existing list of clients
|
||||
/// </summary>
|
||||
@@ -237,23 +250,10 @@ namespace Unity.Netcode.TestHelpers.Runtime
|
||||
public static bool CreateNewClients(int clientCount, out NetworkManager[] clients)
|
||||
{
|
||||
clients = new NetworkManager[clientCount];
|
||||
var activeSceneName = SceneManager.GetActiveScene().name;
|
||||
for (int i = 0; i < clientCount; i++)
|
||||
{
|
||||
// Create gameObject
|
||||
var go = new GameObject("NetworkManager - Client - " + i);
|
||||
// Create networkManager component
|
||||
clients[i] = go.AddComponent<NetworkManager>();
|
||||
|
||||
// Create transport
|
||||
var unityTransport = go.AddComponent<UnityTransport>();
|
||||
|
||||
// Set the NetworkConfig
|
||||
clients[i].NetworkConfig = new NetworkConfig()
|
||||
{
|
||||
// Set transport
|
||||
NetworkTransport = unityTransport
|
||||
};
|
||||
clients[i] = CreateNewClient(i);
|
||||
}
|
||||
|
||||
NetworkManagerInstances.AddRange(clients);
|
||||
@@ -264,12 +264,32 @@ namespace Unity.Netcode.TestHelpers.Runtime
|
||||
/// Stops one single client and makes sure to cleanup any static variables in this helper
|
||||
/// </summary>
|
||||
/// <param name="clientToStop"></param>
|
||||
public static void StopOneClient(NetworkManager clientToStop)
|
||||
public static void StopOneClient(NetworkManager clientToStop, bool destroy = true)
|
||||
{
|
||||
clientToStop.Shutdown();
|
||||
s_Hooks.Remove(clientToStop);
|
||||
Object.Destroy(clientToStop.gameObject);
|
||||
NetworkManagerInstances.Remove(clientToStop);
|
||||
if (destroy)
|
||||
{
|
||||
Object.Destroy(clientToStop.gameObject);
|
||||
NetworkManagerInstances.Remove(clientToStop);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Starts one single client and makes sure to register the required hooks and handlers
|
||||
/// </summary>
|
||||
/// <param name="clientToStart"></param>
|
||||
public static void StartOneClient(NetworkManager clientToStart)
|
||||
{
|
||||
clientToStart.StartClient();
|
||||
s_Hooks[clientToStart] = new MultiInstanceHooks();
|
||||
clientToStart.MessagingSystem.Hook(s_Hooks[clientToStart]);
|
||||
if (!NetworkManagerInstances.Contains(clientToStart))
|
||||
{
|
||||
NetworkManagerInstances.Add(clientToStart);
|
||||
}
|
||||
// if set, then invoke this for the client
|
||||
RegisterHandlers(clientToStart);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -315,7 +335,7 @@ namespace Unity.Netcode.TestHelpers.Runtime
|
||||
private static bool VerifySceneIsValidForClientsToLoad(int sceneIndex, string sceneName, LoadSceneMode loadSceneMode)
|
||||
{
|
||||
// exclude test runner scene
|
||||
if (sceneName.StartsWith(k_FirstPartOfTestRunnerSceneName))
|
||||
if (sceneName.StartsWith(FirstPartOfTestRunnerSceneName))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -342,7 +362,7 @@ namespace Unity.Netcode.TestHelpers.Runtime
|
||||
// warning about using the currently active scene
|
||||
var scene = SceneManager.GetActiveScene();
|
||||
// As long as this is a test runner scene (or most likely a test runner scene)
|
||||
if (scene.name.StartsWith(k_FirstPartOfTestRunnerSceneName))
|
||||
if (scene.name.StartsWith(FirstPartOfTestRunnerSceneName))
|
||||
{
|
||||
// Register the test runner scene just so we avoid another warning about not being able to find the
|
||||
// scene to synchronize NetworkObjects. Next, add the currently active test runner scene to the scenes
|
||||
@@ -458,8 +478,11 @@ namespace Unity.Netcode.TestHelpers.Runtime
|
||||
// this feature only works with NetcodeIntegrationTest derived classes
|
||||
if (IsNetcodeIntegrationTestRunning)
|
||||
{
|
||||
// Add the object identifier component
|
||||
networkObject.gameObject.AddComponent<ObjectNameIdentifier>();
|
||||
if (networkObject.GetComponent<ObjectNameIdentifier>() == null && networkObject.GetComponentInChildren<ObjectNameIdentifier>() == null)
|
||||
{
|
||||
// Add the object identifier component
|
||||
networkObject.gameObject.AddComponent<ObjectNameIdentifier>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -722,7 +745,7 @@ namespace Unity.Netcode.TestHelpers.Runtime
|
||||
/// </summary>
|
||||
/// <param name="result">The result. If null, it will fail if the predicate is not met</param>
|
||||
/// <param name="timeout">The max time in seconds to wait for</param>
|
||||
internal static IEnumerator WaitForMessageOfTypeReceived<T>(NetworkManager toBeReceivedBy, ResultWrapper<bool> result = null, float timeout = 0.5f) where T : INetworkMessage
|
||||
internal static IEnumerator WaitForMessageOfTypeReceived<T>(NetworkManager toBeReceivedBy, ResultWrapper<bool> result = null, float timeout = DefaultTimeout) where T : INetworkMessage
|
||||
{
|
||||
var hooks = s_Hooks[toBeReceivedBy];
|
||||
var check = new MessageReceiveCheckWithResult { CheckType = typeof(T) };
|
||||
@@ -750,7 +773,7 @@ namespace Unity.Netcode.TestHelpers.Runtime
|
||||
/// </summary>
|
||||
/// <param name="result">The result. If null, it will fail if the predicate is not met</param>
|
||||
/// <param name="timeout">The max time in seconds to wait for</param>
|
||||
internal static IEnumerator WaitForMessageOfTypeHandled<T>(NetworkManager toBeReceivedBy, ResultWrapper<bool> result = null, float timeout = 0.5f) where T : INetworkMessage
|
||||
internal static IEnumerator WaitForMessageOfTypeHandled<T>(NetworkManager toBeReceivedBy, ResultWrapper<bool> result = null, float timeout = DefaultTimeout) where T : INetworkMessage
|
||||
{
|
||||
var hooks = s_Hooks[toBeReceivedBy];
|
||||
if (!hooks.HandleChecks.ContainsKey(typeof(T)))
|
||||
|
||||
Reference in New Issue
Block a user