com.unity.netcode.gameobjects@1.0.0-pre.6

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.6] - 2022-03-02

### Added
- NetworkAnimator now properly synchrhonizes all animation layers as well as runtime-adjusted weighting between them (#1765)
- Added first set of tests for NetworkAnimator - parameter syncing, trigger set / reset, override network animator (#1735)

### Changed

### Fixed
- Fixed an issue where sometimes the first client to connect to the server could see messages from the server as coming from itself. (#1683)
- Fixed an issue where clients seemed to be able to send messages to ClientId 1, but these messages would actually still go to the server (id 0) instead of that client. (#1683)
- Improved clarity of error messaging when a client attempts to send a message to a destination other than the server, which isn't allowed. (#1683)
- Disallowed async keyword in RPCs (#1681)
- Fixed an issue where Alpha release versions of Unity (version 2022.2.0a5 and later) will not compile due to the UNet Transport no longer existing (#1678)
- Fixed messages larger than 64k being written with incorrectly truncated message size in header (#1686) (credit: @kaen)
- Fixed overloading RPC methods causing collisions and failing on IL2CPP targets. (#1694)
- Fixed spawn flow to propagate `IsSceneObject` down to children NetworkObjects, decouple implicit relationship between object spawning & `IsSceneObject` flag (#1685)
- Fixed error when serializing ConnectionApprovalMessage with scene management disabled when one or more objects is hidden via the CheckObjectVisibility delegate (#1720)
- Fixed CheckObjectVisibility delegate not being properly invoked for connecting clients when Scene Management is enabled. (#1680)
- Fixed NetworkList to properly call INetworkSerializable's NetworkSerialize() method (#1682)
- Fixed NetworkVariables containing more than 1300 bytes of data (such as large NetworkLists) no longer cause an OverflowException (the limit on data size is now whatever limit the chosen transport imposes on fragmented NetworkDelivery mechanisms) (#1725)
- Fixed ServerRpcParams and ClientRpcParams must be the last parameter of an RPC in order to function properly. Added a compile-time check to ensure this is the case and trigger an error if they're placed elsewhere (#1721)
- Fixed FastBufferReader being created with a length of 1 if provided an input of length 0 (#1724)
- Fixed The NetworkConfig's checksum hash includes the NetworkTick so that clients with a different tickrate than the server are identified and not allowed to connect (#1728)
- Fixed OwnedObjects not being properly modified when using ChangeOwnership (#1731)
- Improved performance in NetworkAnimator (#1735)
- Removed the "always sync" network animator (aka "autosend") parameters (#1746)
This commit is contained in:
Unity Technologies
2022-03-02 00:00:00 +00:00
parent 4818405514
commit 5b4aaa8b59
205 changed files with 6971 additions and 2722 deletions

View File

@@ -1,178 +0,0 @@
using System;
using System.Collections;
using System.Linq;
using NUnit.Framework;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.TestTools;
using Object = UnityEngine.Object;
namespace Unity.Netcode.RuntimeTests
{
public abstract class BaseMultiInstanceTest
{
private const string k_FirstPartOfTestRunnerSceneName = "InitTestScene";
protected GameObject m_PlayerPrefab;
protected NetworkManager m_ServerNetworkManager;
protected NetworkManager[] m_ClientNetworkManagers;
protected abstract int NbClients { get; }
protected bool m_BypassStartAndWaitForClients = false;
[UnitySetUp]
public virtual IEnumerator Setup()
{
yield return StartSomeClientsAndServerWithPlayers(true, NbClients, _ => { });
}
[UnityTearDown]
public virtual IEnumerator Teardown()
{
// Shutdown and clean up both of our NetworkManager instances
try
{
MultiInstanceHelpers.Destroy();
}
catch (Exception e) { throw e; }
finally
{
if (m_PlayerPrefab != null)
{
Object.Destroy(m_PlayerPrefab);
m_PlayerPrefab = null;
}
}
// Make sure any NetworkObject with a GlobalObjectIdHash value of 0 is destroyed
// If we are tearing down, we don't want to leave NetworkObjects hanging around
var networkObjects = Object.FindObjectsOfType<NetworkObject>().ToList();
foreach (var networkObject in networkObjects)
{
Object.DestroyImmediate(networkObject);
}
// wait for next frame so everything is destroyed, so following tests can execute from clean environment
int nextFrameNumber = Time.frameCount + 1;
yield return new WaitUntil(() => Time.frameCount >= nextFrameNumber);
}
/// <summary>
/// We want to exclude the TestRunner scene on the host-server side so it won't try to tell clients to
/// synchronize to this scene when they connect
/// </summary>
private static bool VerifySceneIsValidForClientsToLoad(int sceneIndex, string sceneName, LoadSceneMode loadSceneMode)
{
// exclude test runner scene
if (sceneName.StartsWith(k_FirstPartOfTestRunnerSceneName))
{
return false;
}
return true;
}
/// <summary>
/// This registers scene validation callback for the server to prevent it from telling connecting
/// clients to synchronize (i.e. load) the test runner scene. This will also register the test runner
/// scene and its handle for both client(s) and server-host.
/// </summary>
public static void SceneManagerValidationAndTestRunnerInitialization(NetworkManager networkManager)
{
// If VerifySceneBeforeLoading is not already set, then go ahead and set it so the host/server
// will not try to synchronize clients to the TestRunner scene. We only need to do this for the server.
if (networkManager.IsServer && networkManager.SceneManager.VerifySceneBeforeLoading == null)
{
networkManager.SceneManager.VerifySceneBeforeLoading = VerifySceneIsValidForClientsToLoad;
// If a unit/integration test does not handle this on their own, then Ignore the validation warning
networkManager.SceneManager.DisableValidationWarnings(true);
}
// Register the test runner scene so it will be able to synchronize NetworkObjects without logging a
// 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))
{
// 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
// loaded and register the server to client scene handle since host-server shares the test runner scene
// with the clients.
networkManager.SceneManager.GetAndAddNewlyLoadedSceneByName(scene.name);
networkManager.SceneManager.ServerSceneHandleToClientSceneHandle.Add(scene.handle, scene.handle);
}
}
/// <summary>
/// Utility to spawn some clients and a server and set them up
/// </summary>
/// <param name="nbClients"></param>
/// <param name="updatePlayerPrefab">Update the prefab with whatever is needed before players spawn</param>
/// <param name="targetFrameRate">The targetFrameRate of the Unity engine to use while this multi instance test is running. Will be reset on teardown.</param>
/// <returns></returns>
public IEnumerator StartSomeClientsAndServerWithPlayers(bool useHost, int nbClients, Action<GameObject> updatePlayerPrefab = null, int targetFrameRate = 60)
{
// Make sure any NetworkObject with a GlobalObjectIdHash value of 0 is destroyed
// If we are tearing down, we don't want to leave NetworkObjects hanging around
var networkObjects = Object.FindObjectsOfType<NetworkObject>().ToList();
var networkObjectsList = networkObjects.Where(c => c.GlobalObjectIdHash == 0);
foreach (var netObject in networkObjects)
{
Object.DestroyImmediate(netObject);
}
// Create multiple NetworkManager instances
if (!MultiInstanceHelpers.Create(nbClients, out NetworkManager server, out NetworkManager[] clients, targetFrameRate))
{
Debug.LogError("Failed to create instances");
Assert.Fail("Failed to create instances");
}
m_ClientNetworkManagers = clients;
m_ServerNetworkManager = server;
// Create playerPrefab
m_PlayerPrefab = new GameObject("Player");
NetworkObject networkObject = m_PlayerPrefab.AddComponent<NetworkObject>();
/*
* Normally we would only allow player prefabs to be set to a prefab. Not runtime created objects.
* In order to prevent having a Resource folder full of a TON of prefabs that we have to maintain,
* MultiInstanceHelper has a helper function that lets you mark a runtime created object to be
* treated as a prefab by the Netcode. That's how we can get away with creating the player prefab
* at runtime without it being treated as a SceneObject or causing other conflicts with the Netcode.
*/
// Make it a prefab
MultiInstanceHelpers.MakeNetworkObjectTestPrefab(networkObject);
if (updatePlayerPrefab != null)
{
updatePlayerPrefab(m_PlayerPrefab); // update player prefab with whatever is needed before players are spawned
}
// Set the player prefab
server.NetworkConfig.PlayerPrefab = m_PlayerPrefab;
for (int i = 0; i < clients.Length; i++)
{
clients[i].NetworkConfig.PlayerPrefab = m_PlayerPrefab;
}
if (!m_BypassStartAndWaitForClients)
{
// Start the instances and pass in our SceneManagerInitialization action that is invoked immediately after host-server
// is started and after each client is started.
if (!MultiInstanceHelpers.Start(useHost, server, clients, SceneManagerValidationAndTestRunnerInitialization))
{
Debug.LogError("Failed to start instances");
Assert.Fail("Failed to start instances");
}
// Wait for connection on client side
yield return MultiInstanceHelpers.Run(MultiInstanceHelpers.WaitForClientsConnected(clients));
// Wait for connection on server side
yield return MultiInstanceHelpers.Run(MultiInstanceHelpers.WaitForClientsConnectedToServer(server, useHost ? nbClients + 1 : nbClients));
}
}
}
}

View File

@@ -1,3 +0,0 @@
fileFormatVersion: 2
guid: 789a3189410645aca48f11a51c823418
timeCreated: 1621620979

View File

@@ -1,5 +1,6 @@
using System.Collections.Generic;
using UnityEngine;
using Unity.Netcode.TestHelpers.Runtime;
namespace Unity.Netcode.RuntimeTests
{

View File

@@ -1,4 +1,5 @@
using UnityEngine;
using Unity.Netcode.TestHelpers.Runtime;
namespace Unity.Netcode.RuntimeTests
{
@@ -11,24 +12,24 @@ namespace Unity.Netcode.RuntimeTests
/// </summary>
internal class NetworkVariableTestComponent : NetworkBehaviour
{
private NetworkVariable<bool> m_NetworkVariableBool;
private NetworkVariable<byte> m_NetworkVariableByte;
private NetworkVariable<Color> m_NetworkVariableColor;
private NetworkVariable<Color32> m_NetworkVariableColor32;
private NetworkVariable<double> m_NetworkVariableDouble;
private NetworkVariable<float> m_NetworkVariableFloat;
private NetworkVariable<int> m_NetworkVariableInt;
private NetworkVariable<long> m_NetworkVariableLong;
private NetworkVariable<sbyte> m_NetworkVariableSByte;
private NetworkVariable<Quaternion> m_NetworkVariableQuaternion;
private NetworkVariable<short> m_NetworkVariableShort;
private NetworkVariable<Vector4> m_NetworkVariableVector4;
private NetworkVariable<Vector3> m_NetworkVariableVector3;
private NetworkVariable<Vector2> m_NetworkVariableVector2;
private NetworkVariable<Ray> m_NetworkVariableRay;
private NetworkVariable<ulong> m_NetworkVariableULong;
private NetworkVariable<uint> m_NetworkVariableUInt;
private NetworkVariable<ushort> m_NetworkVariableUShort;
private NetworkVariable<bool> m_NetworkVariableBool = new NetworkVariable<bool>();
private NetworkVariable<byte> m_NetworkVariableByte = new NetworkVariable<byte>();
private NetworkVariable<Color> m_NetworkVariableColor = new NetworkVariable<Color>();
private NetworkVariable<Color32> m_NetworkVariableColor32 = new NetworkVariable<Color32>();
private NetworkVariable<double> m_NetworkVariableDouble = new NetworkVariable<double>();
private NetworkVariable<float> m_NetworkVariableFloat = new NetworkVariable<float>();
private NetworkVariable<int> m_NetworkVariableInt = new NetworkVariable<int>();
private NetworkVariable<long> m_NetworkVariableLong = new NetworkVariable<long>();
private NetworkVariable<sbyte> m_NetworkVariableSByte = new NetworkVariable<sbyte>();
private NetworkVariable<Quaternion> m_NetworkVariableQuaternion = new NetworkVariable<Quaternion>();
private NetworkVariable<short> m_NetworkVariableShort = new NetworkVariable<short>();
private NetworkVariable<Vector4> m_NetworkVariableVector4 = new NetworkVariable<Vector4>();
private NetworkVariable<Vector3> m_NetworkVariableVector3 = new NetworkVariable<Vector3>();
private NetworkVariable<Vector2> m_NetworkVariableVector2 = new NetworkVariable<Vector2>();
private NetworkVariable<Ray> m_NetworkVariableRay = new NetworkVariable<Ray>();
private NetworkVariable<ulong> m_NetworkVariableULong = new NetworkVariable<ulong>();
private NetworkVariable<uint> m_NetworkVariableUInt = new NetworkVariable<uint>();
private NetworkVariable<ushort> m_NetworkVariableUShort = new NetworkVariable<ushort>();
public NetworkVariableHelper<bool> Bool_Var;

View File

@@ -0,0 +1,13 @@
namespace Unity.Netcode.RuntimeTests
{
public class NetworkVisibilityComponent : NetworkBehaviour
{
public void Hide()
{
GetComponent<NetworkObject>().CheckObjectVisibility += HandleCheckObjectVisibility;
}
protected virtual bool HandleCheckObjectVisibility(ulong clientId) => false;
}
}

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: c920be150fd14ad4ca1936e1a259417c
guid: 7c8284d1c5a9f4c3783a16e314376ea3
MonoImporter:
externalObjects: {}
serializedVersion: 2

View File

@@ -4,6 +4,7 @@ using System.Collections;
using UnityEngine;
using UnityEngine.TestTools;
using NUnit.Framework;
using Unity.Netcode.TestHelpers.Runtime;
namespace Unity.Netcode.RuntimeTests
{

View File

@@ -3,6 +3,7 @@ using System.Linq;
using NUnit.Framework;
using UnityEngine;
using UnityEngine.TestTools;
using Unity.Netcode.TestHelpers.Runtime;
namespace Unity.Netcode.RuntimeTests
{
@@ -12,13 +13,13 @@ namespace Unity.Netcode.RuntimeTests
public IEnumerator RemoteDisconnectPlayerObjectCleanup()
{
// create server and client instances
MultiInstanceHelpers.Create(1, out NetworkManager server, out NetworkManager[] clients);
NetcodeIntegrationTestHelpers.Create(1, out NetworkManager server, out NetworkManager[] clients);
// create prefab
var gameObject = new GameObject("PlayerObject");
var networkObject = gameObject.AddComponent<NetworkObject>();
networkObject.DontDestroyWithOwner = true;
MultiInstanceHelpers.MakeNetworkObjectTestPrefab(networkObject);
NetcodeIntegrationTestHelpers.MakeNetworkObjectTestPrefab(networkObject);
server.NetworkConfig.PlayerPrefab = gameObject;
@@ -28,13 +29,13 @@ namespace Unity.Netcode.RuntimeTests
}
// start server and connect clients
MultiInstanceHelpers.Start(false, server, clients);
NetcodeIntegrationTestHelpers.Start(false, server, clients);
// wait for connection on client side
yield return MultiInstanceHelpers.Run(MultiInstanceHelpers.WaitForClientsConnected(clients));
yield return NetcodeIntegrationTestHelpers.WaitForClientsConnected(clients);
// wait for connection on server side
yield return MultiInstanceHelpers.Run(MultiInstanceHelpers.WaitForClientConnectedToServer(server));
yield return NetcodeIntegrationTestHelpers.WaitForClientConnectedToServer(server);
// disconnect the remote client
server.DisconnectClient(clients[0].LocalClientId);
@@ -47,7 +48,7 @@ namespace Unity.Netcode.RuntimeTests
Assert.False(server.SpawnManager.SpawnedObjects.Any(x => x.Value.IsPlayerObject && x.Value.OwnerClientId == clients[0].LocalClientId));
// cleanup
MultiInstanceHelpers.Destroy();
NetcodeIntegrationTestHelpers.Destroy();
}
}
}

View File

@@ -1,273 +0,0 @@
using System;
using System.Collections.Generic;
using UnityEngine;
using NUnit.Framework;
using Unity.Netcode.Transports.UNET;
namespace Unity.Netcode.RuntimeTests
{
/// <summary>
/// Helper class to instantiate a NetworkManager
/// This also provides the ability to:
/// --- instantiate GameObjects with NetworkObject components that returns a Guid for accessing it later.
/// --- add NetworkBehaviour components to the instantiated GameObjects
/// --- spawn a NetworkObject using its parent GameObject's Guid
/// Call StartNetworkManager in the constructor of your runtime unit test class.
/// Call ShutdownNetworkManager in the destructor of your runtime unit test class.
///
/// Includes a useful "BuffersMatch" method that allows you to compare two buffers (returns true if they match false if not)
/// </summary>
public static class NetworkManagerHelper
{
public static NetworkManager NetworkManagerObject { get; internal set; }
public static GameObject NetworkManagerGameObject { get; internal set; }
internal static Dictionary<Guid, GameObject> InstantiatedGameObjects = new Dictionary<Guid, GameObject>();
internal static Dictionary<Guid, NetworkObject> InstantiatedNetworkObjects = new Dictionary<Guid, NetworkObject>();
internal static NetworkManagerOperatingMode CurrentNetworkManagerMode;
/// <summary>
/// This provides the ability to start NetworkManager in various modes
/// </summary>
public enum NetworkManagerOperatingMode
{
None,
Host,
Server,
Client,
}
/// <summary>
/// Called upon the RpcQueueTests being instantiated.
/// This creates an instance of the NetworkManager to be used during unit tests.
/// Currently, the best method to run unit tests is by starting in host mode as you can
/// send messages to yourself (i.e. Host-Client to Host-Server and vice versa).
/// As such, the default setting is to start in Host mode.
/// </summary>
/// <param name="managerMode">parameter to specify which mode you want to start the NetworkManager</param>
/// <param name="networkConfig">parameter to specify custom NetworkConfig settings</param>
/// <returns>true if it was instantiated or is already instantiate otherwise false means it failed to instantiate</returns>
public static bool StartNetworkManager(out NetworkManager networkManager, NetworkManagerOperatingMode managerMode = NetworkManagerOperatingMode.Host, NetworkConfig networkConfig = null)
{
// If we are changing the current manager mode and the current manager mode is not "None", then stop the NetworkManager mode
if (CurrentNetworkManagerMode != managerMode && CurrentNetworkManagerMode != NetworkManagerOperatingMode.None)
{
StopNetworkManagerMode();
}
if (NetworkManagerGameObject == null)
{
NetworkManagerGameObject = new GameObject(nameof(NetworkManager));
NetworkManagerObject = NetworkManagerGameObject.AddComponent<NetworkManager>();
if (NetworkManagerObject == null)
{
networkManager = null;
return false;
}
Debug.Log($"{nameof(NetworkManager)} Instantiated.");
var unetTransport = NetworkManagerGameObject.AddComponent<UNetTransport>();
if (networkConfig == null)
{
networkConfig = new NetworkConfig
{
EnableSceneManagement = false,
};
}
NetworkManagerObject.NetworkConfig = networkConfig;
unetTransport.ConnectAddress = "127.0.0.1";
unetTransport.ConnectPort = 7777;
unetTransport.ServerListenPort = 7777;
unetTransport.MessageBufferSize = 65535;
unetTransport.MaxConnections = 100;
unetTransport.MessageSendMode = UNetTransport.SendMode.Immediately;
NetworkManagerObject.NetworkConfig.NetworkTransport = unetTransport;
// Starts the network manager in the mode specified
StartNetworkManagerMode(managerMode);
}
networkManager = NetworkManagerObject;
return true;
}
/// <summary>
/// Add a GameObject with a NetworkObject component
/// </summary>
/// <param name="nameOfGameObject">the name of the object</param>
/// <returns></returns>
public static Guid AddGameNetworkObject(string nameOfGameObject)
{
var gameObjectId = Guid.NewGuid();
// Create the player object that we will spawn as a host
var gameObject = new GameObject(nameOfGameObject);
Assert.IsNotNull(gameObject);
var networkObject = gameObject.AddComponent<NetworkObject>();
Assert.IsNotNull(networkObject);
Assert.IsFalse(InstantiatedGameObjects.ContainsKey(gameObjectId));
Assert.IsFalse(InstantiatedNetworkObjects.ContainsKey(gameObjectId));
InstantiatedGameObjects.Add(gameObjectId, gameObject);
InstantiatedNetworkObjects.Add(gameObjectId, networkObject);
return gameObjectId;
}
/// <summary>
/// Helper class to add a component to the GameObject with a NetoworkObject component
/// </summary>
/// <typeparam name="T">NetworkBehaviour component being added to the GameObject</typeparam>
/// <param name="gameObjectIdentifier">ID returned to reference the game object</param>
/// <returns></returns>
public static T AddComponentToObject<T>(Guid gameObjectIdentifier) where T : NetworkBehaviour
{
Assert.IsTrue(InstantiatedGameObjects.ContainsKey(gameObjectIdentifier));
return InstantiatedGameObjects[gameObjectIdentifier].AddComponent<T>();
}
/// <summary>
/// Spawn the NetworkObject, so Rpcs can flow
/// </summary>
/// <param name="gameObjectIdentifier">ID returned to reference the game object</param>
public static void SpawnNetworkObject(Guid gameObjectIdentifier)
{
Assert.IsTrue(InstantiatedNetworkObjects.ContainsKey(gameObjectIdentifier));
if (!InstantiatedNetworkObjects[gameObjectIdentifier].IsSpawned)
{
InstantiatedNetworkObjects[gameObjectIdentifier].Spawn();
}
}
/// <summary>
/// Starts the NetworkManager in the current mode specified by managerMode
/// </summary>
/// <param name="managerMode">the mode to start the NetworkManager as</param>
private static void StartNetworkManagerMode(NetworkManagerOperatingMode managerMode)
{
CurrentNetworkManagerMode = managerMode;
switch (CurrentNetworkManagerMode)
{
case NetworkManagerOperatingMode.Host:
{
// Starts the host
NetworkManagerObject.StartHost();
break;
}
case NetworkManagerOperatingMode.Server:
{
// Starts the server
NetworkManagerObject.StartServer();
break;
}
case NetworkManagerOperatingMode.Client:
{
// Starts the client
NetworkManagerObject.StartClient();
break;
}
}
// If we started an netcode session
if (CurrentNetworkManagerMode != NetworkManagerOperatingMode.None)
{
// With some unit tests the Singleton can still be from a previous unit test
// depending upon the order of operations that occurred.
if (NetworkManager.Singleton != NetworkManagerObject)
{
NetworkManagerObject.SetSingleton();
}
// Only log this if we started an netcode session
Debug.Log($"{CurrentNetworkManagerMode} started.");
}
}
/// <summary>
/// Stops the current mode of the NetworkManager
/// </summary>
private static void StopNetworkManagerMode()
{
NetworkManagerObject.Shutdown();
Debug.Log($"{CurrentNetworkManagerMode} stopped.");
CurrentNetworkManagerMode = NetworkManagerOperatingMode.None;
}
// This is called, even if we assert and exit early from a test
public static void ShutdownNetworkManager()
{
// clean up any game objects created with custom unit testing components
foreach (var entry in InstantiatedGameObjects)
{
UnityEngine.Object.DestroyImmediate(entry.Value);
}
InstantiatedGameObjects.Clear();
if (NetworkManagerGameObject != null)
{
Debug.Log($"{nameof(NetworkManager)} shutdown.");
StopNetworkManagerMode();
UnityEngine.Object.DestroyImmediate(NetworkManagerGameObject);
Debug.Log($"{nameof(NetworkManager)} destroyed.");
}
NetworkManagerGameObject = null;
NetworkManagerObject = null;
}
public static bool BuffersMatch(int indexOffset, long targetSize, byte[] sourceArray, byte[] originalArray)
{
long largeInt64Blocks = targetSize >> 3; // Divide by 8
int originalArrayOffset = 0;
// process by 8 byte blocks if we can
for (long i = 0; i < largeInt64Blocks; i++)
{
if (BitConverter.ToInt64(sourceArray, indexOffset) != BitConverter.ToInt64(originalArray, originalArrayOffset))
{
return false;
}
indexOffset += 8;
originalArrayOffset += 8;
}
long offset = largeInt64Blocks * 8;
long remainder = targetSize - offset;
// 4 byte block
if (remainder >= 4)
{
if (BitConverter.ToInt32(sourceArray, indexOffset) != BitConverter.ToInt32(originalArray, originalArrayOffset))
{
return false;
}
indexOffset += 4;
originalArrayOffset += 4;
offset += 4;
}
// Remainder of bytes < 4
if (targetSize - offset > 0)
{
for (long i = 0; i < (targetSize - offset); i++)
{
if (sourceArray[indexOffset + i] != originalArray[originalArrayOffset + i])
{
return false;
}
}
}
return true;
}
}
}

View File

@@ -1,153 +0,0 @@
using System;
using System.Collections.Generic;
namespace Unity.Netcode.RuntimeTests
{
/// <summary>
/// Will automatically register for the NetworkVariable OnValueChanged
/// delegate handler. It then will expose that single delegate invocation
/// to anything that registers for this NetworkVariableHelper's instance's OnValueChanged event.
/// This allows us to register any NetworkVariable type as well as there are basically two "types of types":
/// IEquatable<T>
/// ValueType
/// From both we can then at least determine if the value indeed changed
/// </summary>
/// <typeparam name="T"></typeparam>
internal class NetworkVariableHelper<T> : NetworkVariableBaseHelper where T : unmanaged
{
private readonly NetworkVariable<T> m_NetworkVariable;
public delegate void OnMyValueChangedDelegateHandler(T previous, T next);
public event OnMyValueChangedDelegateHandler OnValueChanged;
/// <summary>
/// IEquatable<T> Equals Check
/// </summary>
private void CheckVariableChanged(IEquatable<T> previous, IEquatable<T> next)
{
if (!previous.Equals(next))
{
ValueChanged();
}
}
/// <summary>
/// ValueType Equals Check
/// </summary>
private void CheckVariableChanged(ValueType previous, ValueType next)
{
if (!previous.Equals(next))
{
ValueChanged();
}
}
/// <summary>
/// INetworkVariable's OnVariableChanged delegate callback
/// </summary>
/// <param name="previous"></param>
/// <param name="next"></param>
private void OnVariableChanged(T previous, T next)
{
if (previous is ValueType testValueType)
{
CheckVariableChanged(previous, next);
}
else
{
CheckVariableChanged(previous as IEquatable<T>, next as IEquatable<T>);
}
OnValueChanged?.Invoke(previous, next);
}
public NetworkVariableHelper(NetworkVariableBase networkVariable) : base(networkVariable)
{
m_NetworkVariable = networkVariable as NetworkVariable<T>;
m_NetworkVariable.OnValueChanged = OnVariableChanged;
}
}
/// <summary>
/// The BaseNetworkVariableHelper keeps track of:
/// The number of instances and associates the instance with the NetworkVariable
/// The number of times a specific NetworkVariable instance had its value changed (i.e. !Equal)
/// Note: This could be expanded for future tests focuses around NetworkVariables
/// </summary>
internal class NetworkVariableBaseHelper
{
private static Dictionary<NetworkVariableBaseHelper, NetworkVariableBase> s_Instances;
private static Dictionary<NetworkVariableBase, int> s_InstanceChangedCount;
/// <summary>
/// Returns the total number of registered INetworkVariables
/// </summary>
public static int InstanceCount
{
get
{
if (s_Instances != null)
{
return s_Instances.Count;
}
return 0;
}
}
/// <summary>
/// Returns total number of changes that occurred for all registered INetworkVariables
/// </summary>
public static int VarChangedCount
{
get
{
if (s_InstanceChangedCount != null)
{
var changeCount = 0;
foreach (var keyPair in s_InstanceChangedCount)
{
changeCount += keyPair.Value;
}
return changeCount;
}
return 0;
}
}
/// <summary>
/// Called by the child class NetworkVariableHelper when a value changed
/// </summary>
protected void ValueChanged()
{
if (s_Instances.ContainsKey(this))
{
if (s_InstanceChangedCount.ContainsKey(s_Instances[this]))
{
s_InstanceChangedCount[s_Instances[this]]++;
}
}
}
public NetworkVariableBaseHelper(NetworkVariableBase networkVariable)
{
if (s_Instances == null)
{
s_Instances = new Dictionary<NetworkVariableBaseHelper, NetworkVariableBase>();
}
if (s_InstanceChangedCount == null)
{
s_InstanceChangedCount = new Dictionary<NetworkVariableBase, int>();
}
// Register new instance and associated INetworkVariable
if (!s_Instances.ContainsKey(this))
{
s_Instances.Add(this, networkVariable);
if (!s_InstanceChangedCount.ContainsKey(networkVariable))
{
s_InstanceChangedCount.Add(networkVariable, 0);
}
}
}
}
}

View File

@@ -2,6 +2,7 @@ using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.TestTools;
using Unity.Netcode.TestHelpers.Runtime;
namespace Unity.Netcode.RuntimeTests
{
@@ -41,47 +42,23 @@ namespace Unity.Netcode.RuntimeTests
}
}
public class HiddenVariableTests : BaseMultiInstanceTest
public class HiddenVariableTests : NetcodeIntegrationTest
{
protected override int NbClients => 4;
protected override int NumberOfClients => 4;
private NetworkObject m_NetSpawnedObject;
private List<NetworkObject> m_NetSpawnedObjectOnClient = new List<NetworkObject>();
private GameObject m_TestNetworkPrefab;
[UnitySetUp]
public override IEnumerator Setup()
protected override void OnCreatePlayerPrefab()
{
yield return StartSomeClientsAndServerWithPlayers(useHost: true, nbClients: NbClients,
updatePlayerPrefab: playerPrefab =>
{
var networkTransform = playerPrefab.AddComponent<HiddenVariableTest>();
m_TestNetworkPrefab = PreparePrefab();
});
m_PlayerPrefab.AddComponent<HiddenVariableTest>();
}
public GameObject PreparePrefab()
protected override void OnServerAndClientsCreated()
{
var prefabToSpawn = new GameObject("MyTestObject");
var networkObjectPrefab = prefabToSpawn.AddComponent<NetworkObject>();
MultiInstanceHelpers.MakeNetworkObjectTestPrefab(networkObjectPrefab);
prefabToSpawn.AddComponent<HiddenVariableObject>();
m_ServerNetworkManager.NetworkConfig.NetworkPrefabs.Add(new NetworkPrefab() { Prefab = prefabToSpawn });
foreach (var clientNetworkManager in m_ClientNetworkManagers)
{
clientNetworkManager.NetworkConfig.NetworkPrefabs.Add(new NetworkPrefab() { Prefab = prefabToSpawn });
}
return prefabToSpawn;
}
public IEnumerator WaitForConnectedCount(int targetCount)
{
var endTime = Time.realtimeSinceStartup + 1.0;
while (m_ServerNetworkManager.ConnectedClientsList.Count < targetCount && Time.realtimeSinceStartup < endTime)
{
yield return new WaitForSeconds(0.01f);
}
m_TestNetworkPrefab = CreateNetworkObjectPrefab("MyTestObject");
m_TestNetworkPrefab.AddComponent<HiddenVariableObject>();
}
public IEnumerator WaitForSpawnCount(int targetCount)
@@ -131,12 +108,11 @@ namespace Unity.Netcode.RuntimeTests
foreach (var netMan in m_ClientNetworkManagers)
{
var serverClientPlayerResult = new MultiInstanceHelpers.CoroutineResultWrapper<NetworkObject>();
yield return MultiInstanceHelpers.Run(
MultiInstanceHelpers.GetNetworkObjectByRepresentation(
var serverClientPlayerResult = new NetcodeIntegrationTestHelpers.ResultWrapper<NetworkObject>();
yield return NetcodeIntegrationTestHelpers.GetNetworkObjectByRepresentation(
x => x.NetworkObjectId == m_NetSpawnedObject.NetworkObjectId,
netMan,
serverClientPlayerResult));
serverClientPlayerResult);
m_NetSpawnedObjectOnClient.Add(serverClientPlayerResult.Result);
}
}
@@ -151,22 +127,17 @@ namespace Unity.Netcode.RuntimeTests
Debug.Log("Running test");
var spawnedObject = Object.Instantiate(m_TestNetworkPrefab);
m_NetSpawnedObject = spawnedObject.GetComponent<NetworkObject>();
m_NetSpawnedObject.NetworkManagerOwner = m_ServerNetworkManager;
yield return WaitForConnectedCount(NbClients);
Debug.Log("Clients connected");
// ==== Spawn object with ownership on one client
var client = m_ServerNetworkManager.ConnectedClientsList[1];
var otherClient = m_ServerNetworkManager.ConnectedClientsList[2];
m_NetSpawnedObject.SpawnWithOwnership(client.ClientId);
m_NetSpawnedObject = SpawnObject(m_TestNetworkPrefab, m_ClientNetworkManagers[1]).GetComponent<NetworkObject>();
yield return RefreshGameObects();
// === Check spawn occured
yield return WaitForSpawnCount(NbClients + 1);
Debug.Assert(HiddenVariableObject.SpawnCount == NbClients + 1);
yield return WaitForSpawnCount(NumberOfClients + 1);
Debug.Assert(HiddenVariableObject.SpawnCount == NumberOfClients + 1);
Debug.Log("Objects spawned");
// ==== Set the NetworkVariable value to 2

View File

@@ -0,0 +1,184 @@
using System.Collections;
using System.Linq;
using UnityEngine;
using UnityEngine.TestTools;
using NUnit.Framework;
using Unity.Netcode.TestHelpers.Runtime;
namespace Unity.Netcode.RuntimeTests
{
public class IntegrationTestUpdated : NetcodeIntegrationTest
{
private GameObject m_MyNetworkPrefab;
protected override int NumberOfClients => 1;
protected override void OnServerAndClientsCreated()
{
m_MyNetworkPrefab = CreateNetworkObjectPrefab("Object");
m_MyNetworkPrefab.AddComponent<NetworkVisibilityComponent>();
}
protected override IEnumerator OnServerAndClientsConnected()
{
SpawnObject(m_MyNetworkPrefab, m_ServerNetworkManager);
yield return base.OnServerAndClientsConnected();
}
[UnityTest]
public IEnumerator MyFirstIntegationTest()
{
// Check the condition for this test and automatically handle varying processing
// environments and conditions
yield return WaitForConditionOrTimeOut(() =>
Object.FindObjectsOfType<NetworkVisibilityComponent>().Where(
(c) => c.IsSpawned).Count() == 2);
Assert.False(s_GlobalTimeoutHelper.TimedOut, "Timed out waiting for instances " +
"to be detected!");
}
}
[TestFixture(HostOrServer.Host)]
[TestFixture(HostOrServer.Server)]
public class IntegrationTestExtended : NetcodeIntegrationTest
{
private GameObject m_MyNetworkPrefab;
protected override int NumberOfClients => 1;
protected override void OnServerAndClientsCreated()
{
m_MyNetworkPrefab = CreateNetworkObjectPrefab("Object");
m_MyNetworkPrefab.AddComponent<NetworkVisibilityComponent>();
}
public IntegrationTestExtended(HostOrServer hostOrServer) : base(hostOrServer) { }
protected override IEnumerator OnServerAndClientsConnected()
{
SpawnObject(m_MyNetworkPrefab, m_ServerNetworkManager);
yield return base.OnServerAndClientsConnected();
}
[UnityTest]
public IEnumerator MyFirstIntegationTest()
{
// Check the condition for this test and automatically handle varying processing
// environments and conditions
yield return WaitForConditionOrTimeOut(() =>
Object.FindObjectsOfType<NetworkVisibilityComponent>().Where(
(c) => c.IsSpawned).Count() == 2);
Assert.False(s_GlobalTimeoutHelper.TimedOut, "Timed out waiting for instances " +
"to be detected!");
}
}
public class ExampleTestComponent : NetworkBehaviour
{
}
public class IntegrationTestPlayers : NetcodeIntegrationTest
{
protected override int NumberOfClients => 5;
protected override void OnCreatePlayerPrefab()
{
m_PlayerPrefab.AddComponent<ExampleTestComponent>();
}
protected override IEnumerator OnServerAndClientsConnected()
{
return base.OnServerAndClientsConnected();
}
[Test]
public void TestClientRelativePlayers()
{
// Check that all instances have the ExampleTestComponent
foreach (var clientRelativePlayers in m_PlayerNetworkObjects)
{
foreach (var playerInstance in clientRelativePlayers.Value)
{
var player = playerInstance.Value;
Assert.NotNull(player.GetComponent<ExampleTestComponent>());
}
}
// Confirm Player ID 1 on Client ID 4 is not the local player
Assert.IsFalse(m_PlayerNetworkObjects[4][1].IsLocalPlayer);
// Confirm Player ID 4 on Client ID 4 is the local player
Assert.IsTrue(m_PlayerNetworkObjects[4][4].IsLocalPlayer);
// Confirm Player ID 0 on Client ID 0 (host) NetworkManager is the server
Assert.IsTrue(m_PlayerNetworkObjects[0][0].NetworkManager.IsServer);
// Confirm Player ID 0 on Client ID 4 (client) NetworkManager is not the server
Assert.IsFalse(m_PlayerNetworkObjects[4][0].NetworkManager.IsServer);
}
}
public class SpawnTest : NetworkBehaviour
{
public static int TotalSpawned;
public override void OnNetworkSpawn() { TotalSpawned++; }
public override void OnNetworkDespawn() { TotalSpawned--; }
}
public class IntegrationTestSpawning : NetcodeIntegrationTest
{
protected override int NumberOfClients => 2;
private GameObject m_NetworkPrefabToSpawn;
private int m_NumberToSpawn = 5;
protected override NetworkManagerInstatiationMode OnSetIntegrationTestMode()
{
return NetworkManagerInstatiationMode.AllTests;
}
protected override void OnServerAndClientsCreated()
{
m_NetworkPrefabToSpawn = CreateNetworkObjectPrefab("TrackingTest");
m_NetworkPrefabToSpawn.gameObject.AddComponent<SpawnTest>();
}
protected override IEnumerator OnServerAndClientsConnected()
{
SpawnObjects(m_NetworkPrefabToSpawn, m_ServerNetworkManager, m_NumberToSpawn);
return base.OnServerAndClientsConnected();
}
[UnityTest]
[Order(1)]
public IEnumerator TestRelativeNetworkObjects()
{
var expected = m_NumberToSpawn * TotalClients;
// Wait for all clients to have spawned all instances
yield return WaitForConditionOrTimeOut(() => SpawnTest.TotalSpawned == expected);
Assert.False(s_GlobalTimeoutHelper.TimedOut, $"Timed out waiting for all to " +
$"spawn! Total Spawned: {SpawnTest.TotalSpawned}");
var client1Relative = s_GlobalNetworkObjects[1].Values.Where((c) =>
c.gameObject.GetComponent<SpawnTest>() != null);
foreach (var networkObject in client1Relative)
{
var testComp = networkObject.GetComponent<SpawnTest>();
// Confirm each one is owned by the server
Assert.IsTrue(testComp.IsOwnedByServer, $"{testComp.name} is not owned" +
$" by the server!");
}
}
[UnityTest]
[Order(2)]
public IEnumerator TestDespawnNetworkObjects()
{
var serverRelative = s_GlobalNetworkObjects[0].Values.Where((c) =>
c.gameObject.GetComponent<SpawnTest>() != null).ToList();
foreach (var networkObject in serverRelative)
{
networkObject.Despawn();
}
// Wait for all clients to have spawned all instances
yield return WaitForConditionOrTimeOut(() => SpawnTest.TotalSpawned == 0);
Assert.False(s_GlobalTimeoutHelper.TimedOut, $"Timed out waiting for all to " +
$"despawn! Total Spawned: {SpawnTest.TotalSpawned}");
}
}
}

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 218bb185a48c6f9449e1c74f4855a774
guid: 5a64e8d7b2082a9409b53f83d0c4e537
MonoImporter:
externalObjects: {}
serializedVersion: 2

View File

@@ -5,16 +5,24 @@ using NUnit.Framework;
using Unity.Collections;
using UnityEngine;
using UnityEngine.TestTools;
using Unity.Netcode.TestHelpers.Runtime;
namespace Unity.Netcode.RuntimeTests
{
public class NamedMessageTests : BaseMultiInstanceTest
public class NamedMessageTests : NetcodeIntegrationTest
{
protected override int NbClients => 2;
protected override int NumberOfClients => 2;
private NetworkManager FirstClient => m_ClientNetworkManagers[0];
private NetworkManager SecondClient => m_ClientNetworkManagers[1];
protected override NetworkManagerInstatiationMode OnSetIntegrationTestMode()
{
// Don't spin up and shutdown NetworkManager instances for each test
// within this set of integration tests.
return NetworkManagerInstatiationMode.AllTests;
}
[UnityTest]
public IEnumerator NamedMessageIsReceivedOnClientWithContent()
{

View File

@@ -5,12 +5,13 @@ using NUnit.Framework;
using Unity.Collections;
using UnityEngine;
using UnityEngine.TestTools;
using Unity.Netcode.TestHelpers.Runtime;
namespace Unity.Netcode.RuntimeTests
{
public class UnnamedMessageTests : BaseMultiInstanceTest
public class UnnamedMessageTests : NetcodeIntegrationTest
{
protected override int NbClients => 2;
protected override int NumberOfClients => 2;
private NetworkManager FirstClient => m_ClientNetworkManagers[0];
private NetworkManager SecondClient => m_ClientNetworkManagers[1];

View File

@@ -6,7 +6,7 @@ using System.Linq;
using NUnit.Framework;
using Unity.Collections;
using Unity.Multiplayer.Tools.MetricTypes;
using Unity.Netcode.RuntimeTests.Metrics.Utility;
using Unity.Netcode.TestHelpers.Runtime.Metrics;
using UnityEngine;
using UnityEngine.TestTools;
@@ -20,12 +20,12 @@ namespace Unity.Netcode.RuntimeTests.Metrics
private static readonly int k_NamedMessageOverhead = (int)k_MessageNameHashSize + k_MessageHeaderSize;
private static readonly int k_UnnamedMessageOverhead = k_MessageHeaderSize;
protected override int NbClients => 2;
protected override int NumberOfClients => 2;
[UnityTest]
public IEnumerator TrackNetworkMessageSentMetric()
{
var waitForMetricValues = new WaitForMetricValues<NetworkMessageEvent>(ServerMetrics.Dispatcher, NetworkMetricTypes.NetworkMessageSent);
var waitForMetricValues = new WaitForEventMetricValues<NetworkMessageEvent>(ServerMetrics.Dispatcher, NetworkMetricTypes.NetworkMessageSent);
var messageName = Guid.NewGuid();
using (var writer = new FastBufferWriter(1300, Allocator.Temp))
@@ -38,17 +38,15 @@ namespace Unity.Netcode.RuntimeTests.Metrics
yield return waitForMetricValues.WaitForMetricsReceived();
var networkMessageSentMetricValues = waitForMetricValues.AssertMetricValuesHaveBeenFound();
Assert.AreEqual(1, networkMessageSentMetricValues.Count);
var networkMessageEvent = networkMessageSentMetricValues.First();
Assert.AreEqual(nameof(NamedMessage), networkMessageEvent.Name);
Assert.AreEqual(FirstClient.LocalClientId, networkMessageEvent.Connection.Id);
// We should have 1 NamedMessage and some potential SnapshotMessage
Assert.That(networkMessageSentMetricValues, Has.Exactly(1).Matches<NetworkMessageEvent>(x => x.Name == nameof(NamedMessage)));
}
[UnityTest]
public IEnumerator TrackNetworkMessageSentMetricToMultipleClients()
{
var waitForMetricValues = new WaitForMetricValues<NetworkMessageEvent>(ServerMetrics.Dispatcher, NetworkMetricTypes.NetworkMessageSent);
var waitForMetricValues = new WaitForEventMetricValues<NetworkMessageEvent>(ServerMetrics.Dispatcher, NetworkMetricTypes.NetworkMessageSent);
var messageName = Guid.NewGuid();
using (var writer = new FastBufferWriter(1300, Allocator.Temp))
{
@@ -74,7 +72,9 @@ namespace Unity.Netcode.RuntimeTests.Metrics
{
Debug.Log($"Received from {sender}");
});
var waitForMetricValues = new WaitForMetricValues<NetworkMessageEvent>(FirstClientMetrics.Dispatcher, NetworkMetricTypes.NetworkMessageReceived);
var waitForMetricValues = new WaitForEventMetricValues<NetworkMessageEvent>(FirstClientMetrics.Dispatcher, NetworkMetricTypes.NetworkMessageReceived,
metric => metric.Name == nameof(NamedMessage));
using (var writer = new FastBufferWriter(1300, Allocator.Temp))
{
writer.WriteValueSafe(messageName);
@@ -85,16 +85,14 @@ namespace Unity.Netcode.RuntimeTests.Metrics
yield return waitForMetricValues.WaitForMetricsReceived();
var networkMessageReceivedValues = waitForMetricValues.AssertMetricValuesHaveBeenFound();
Assert.AreEqual(1, networkMessageReceivedValues.Count(x => x.Name.Equals(nameof(NamedMessage))));
var namedMessageReceived = networkMessageReceivedValues.First();
Assert.AreEqual(Server.LocalClientId, namedMessageReceived.Connection.Id);
// We should have 1 NamedMessage and some potential SnapshotMessage
Assert.That(networkMessageReceivedValues, Has.Exactly(1).Matches<NetworkMessageEvent>(x => x.Name == nameof(NamedMessage)));
}
[UnityTest]
public IEnumerator TrackNamedMessageSentMetric()
{
var waitForMetricValues = new WaitForMetricValues<NamedMessageEvent>(ServerMetrics.Dispatcher, NetworkMetricTypes.NamedMessageSent);
var waitForMetricValues = new WaitForEventMetricValues<NamedMessageEvent>(ServerMetrics.Dispatcher, NetworkMetricTypes.NamedMessageSent);
var messageName = Guid.NewGuid();
using (var writer = new FastBufferWriter(1300, Allocator.Temp))
@@ -119,7 +117,7 @@ namespace Unity.Netcode.RuntimeTests.Metrics
[UnityTest]
public IEnumerator TrackNamedMessageSentMetricToMultipleClients()
{
var waitForMetricValues = new WaitForMetricValues<NamedMessageEvent>(ServerMetrics.Dispatcher, NetworkMetricTypes.NamedMessageSent);
var waitForMetricValues = new WaitForEventMetricValues<NamedMessageEvent>(ServerMetrics.Dispatcher, NetworkMetricTypes.NamedMessageSent);
var messageName = Guid.NewGuid();
using (var writer = new FastBufferWriter(1300, Allocator.Temp))
{
@@ -140,7 +138,7 @@ namespace Unity.Netcode.RuntimeTests.Metrics
[UnityTest]
public IEnumerator TrackNamedMessageSentMetricToSelf()
{
var waitForMetricValues = new WaitForMetricValues<NamedMessageEvent>(ServerMetrics.Dispatcher, NetworkMetricTypes.NamedMessageSent);
var waitForMetricValues = new WaitForEventMetricValues<NamedMessageEvent>(ServerMetrics.Dispatcher, NetworkMetricTypes.NamedMessageSent);
var messageName = Guid.NewGuid();
using (var writer = new FastBufferWriter(1300, Allocator.Temp))
{
@@ -157,7 +155,7 @@ namespace Unity.Netcode.RuntimeTests.Metrics
[UnityTest]
public IEnumerator TrackNamedMessageReceivedMetric()
{
var waitForMetricValues = new WaitForMetricValues<NamedMessageEvent>(FirstClientMetrics.Dispatcher, NetworkMetricTypes.NamedMessageReceived);
var waitForMetricValues = new WaitForEventMetricValues<NamedMessageEvent>(FirstClientMetrics.Dispatcher, NetworkMetricTypes.NamedMessageReceived);
var messageName = Guid.NewGuid();
@@ -198,7 +196,7 @@ namespace Unity.Netcode.RuntimeTests.Metrics
}
var waitForMetricValues = new WaitForMetricValues<UnnamedMessageEvent>(ServerMetrics.Dispatcher, NetworkMetricTypes.UnnamedMessageSent);
var waitForMetricValues = new WaitForEventMetricValues<UnnamedMessageEvent>(ServerMetrics.Dispatcher, NetworkMetricTypes.UnnamedMessageSent);
yield return waitForMetricValues.WaitForMetricsReceived();
@@ -214,7 +212,7 @@ namespace Unity.Netcode.RuntimeTests.Metrics
public IEnumerator TrackUnnamedMessageSentMetricToMultipleClients()
{
var message = Guid.NewGuid();
var waitForMetricValues = new WaitForMetricValues<UnnamedMessageEvent>(ServerMetrics.Dispatcher, NetworkMetricTypes.UnnamedMessageSent);
var waitForMetricValues = new WaitForEventMetricValues<UnnamedMessageEvent>(ServerMetrics.Dispatcher, NetworkMetricTypes.UnnamedMessageSent);
using (var writer = new FastBufferWriter(1300, Allocator.Temp))
{
writer.WriteValueSafe(message);
@@ -237,7 +235,7 @@ namespace Unity.Netcode.RuntimeTests.Metrics
[UnityTest]
public IEnumerator TrackUnnamedMessageSentMetricToSelf()
{
var waitForMetricValues = new WaitForMetricValues<UnnamedMessageEvent>(ServerMetrics.Dispatcher, NetworkMetricTypes.UnnamedMessageSent);
var waitForMetricValues = new WaitForEventMetricValues<UnnamedMessageEvent>(ServerMetrics.Dispatcher, NetworkMetricTypes.UnnamedMessageSent);
var messageName = Guid.NewGuid();
using (var writer = new FastBufferWriter(1300, Allocator.Temp))
{
@@ -255,7 +253,7 @@ namespace Unity.Netcode.RuntimeTests.Metrics
public IEnumerator TrackUnnamedMessageReceivedMetric()
{
var message = Guid.NewGuid();
var waitForMetricValues = new WaitForMetricValues<UnnamedMessageEvent>(FirstClientMetrics.Dispatcher, NetworkMetricTypes.UnnamedMessageReceived);
var waitForMetricValues = new WaitForEventMetricValues<UnnamedMessageEvent>(FirstClientMetrics.Dispatcher, NetworkMetricTypes.UnnamedMessageReceived);
using (var writer = new FastBufferWriter(1300, Allocator.Temp))
{
writer.WriteValueSafe(message);

View File

@@ -4,6 +4,8 @@ using System.Collections;
using NUnit.Framework;
using Unity.Multiplayer.Tools.NetStats;
using UnityEngine.TestTools;
using Unity.Netcode.TestHelpers.Runtime;
using Unity.Netcode.TestHelpers.Runtime.Metrics;
namespace Unity.Netcode.RuntimeTests.Metrics
{

View File

@@ -1,52 +1,43 @@
#if MULTIPLAYER_TOOLS
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;
using Unity.Multiplayer.Tools.MetricTypes;
using Unity.Netcode.RuntimeTests.Metrics.Utility;
using UnityEngine;
using UnityEngine.TestTools;
using Unity.Netcode.TestHelpers.Runtime.Metrics;
namespace Unity.Netcode.RuntimeTests.Metrics
{
internal class NetworkObjectMetricsTests : SingleClientMetricTestBase
{
private const string k_NewNetworkObjectName = "TestNetworkObjectToSpawn";
private NetworkObject m_NewNetworkPrefab;
// Keep less than 23 chars to avoid issues if compared against a 32-byte fixed string
// since it will have "(Clone)" appended
private const string k_NewNetworkObjectName = "MetricObject";
private GameObject m_NewNetworkPrefab;
protected override Action<GameObject> UpdatePlayerPrefab => _ =>
/// <summary>
/// Use OnServerAndClientsCreated to create any additional prefabs that you might need
/// </summary>
protected override void OnServerAndClientsCreated()
{
var gameObject = new GameObject(k_NewNetworkObjectName);
m_NewNetworkPrefab = gameObject.AddComponent<NetworkObject>();
MultiInstanceHelpers.MakeNetworkObjectTestPrefab(m_NewNetworkPrefab);
var networkPrefab = new NetworkPrefab { Prefab = gameObject };
m_ServerNetworkManager.NetworkConfig.NetworkPrefabs.Add(networkPrefab);
foreach (var client in m_ClientNetworkManagers)
{
client.NetworkConfig.NetworkPrefabs.Add(networkPrefab);
}
};
base.OnServerAndClientsCreated();
m_NewNetworkPrefab = CreateNetworkObjectPrefab(k_NewNetworkObjectName);
}
private NetworkObject SpawnNetworkObject()
{
// Spawn another network object so we can hide multiple.
var gameObject = UnityEngine.Object.Instantiate(m_NewNetworkPrefab); // new GameObject(NewNetworkObjectName);
var networkObject = gameObject.GetComponent<NetworkObject>();
networkObject.NetworkManagerOwner = Server;
networkObject.Spawn();
return networkObject;
return SpawnObject(m_NewNetworkPrefab, m_ServerNetworkManager).GetComponent<NetworkObject>();
}
[UnityTest]
public IEnumerator TrackNetworkObjectSpawnSentMetric()
{
var waitForMetricEvent = new WaitForMetricValues<ObjectSpawnedEvent>(ServerMetrics.Dispatcher, NetworkMetricTypes.ObjectSpawnedSent);
var waitForMetricEvent = new WaitForEventMetricValues<ObjectSpawnedEvent>(ServerMetrics.Dispatcher, NetworkMetricTypes.ObjectSpawnedSent);
SpawnNetworkObject();
var spawnedObject = SpawnNetworkObject();
yield return waitForMetricEvent.WaitForMetricsReceived();
@@ -55,26 +46,27 @@ namespace Unity.Netcode.RuntimeTests.Metrics
var objectSpawned = objectSpawnedSentMetricValues.Last();
Assert.AreEqual(Client.LocalClientId, objectSpawned.Connection.Id);
Assert.AreEqual($"{k_NewNetworkObjectName}(Clone)", objectSpawned.NetworkId.Name);
Assert.AreEqual(spawnedObject.name, objectSpawned.NetworkId.Name);
Assert.AreNotEqual(0, objectSpawned.BytesCount);
}
[UnityTest]
public IEnumerator TrackNetworkObjectSpawnReceivedMetric()
{
var waitForMetricEvent = new WaitForMetricValues<ObjectSpawnedEvent>(ClientMetrics.Dispatcher, NetworkMetricTypes.ObjectSpawnedReceived);
var waitForMetricEvent = new WaitForEventMetricValues<ObjectSpawnedEvent>(ClientMetrics.Dispatcher, NetworkMetricTypes.ObjectSpawnedReceived);
var networkObject = SpawnNetworkObject();
yield return s_DefaultWaitForTick;
yield return waitForMetricEvent.WaitForMetricsReceived();
var objectSpawnedReceivedMetricValues = waitForMetricEvent.AssertMetricValuesHaveBeenFound();
Assert.AreEqual(1, objectSpawnedReceivedMetricValues.Count);
var clientSideObject = s_GlobalNetworkObjects[1][networkObject.NetworkObjectId];
var objectSpawned = objectSpawnedReceivedMetricValues.First();
Assert.AreEqual(Server.LocalClientId, objectSpawned.Connection.Id);
Assert.AreEqual(networkObject.NetworkObjectId, objectSpawned.NetworkId.NetworkId);
Assert.AreEqual($"{k_NewNetworkObjectName}(Clone)", objectSpawned.NetworkId.Name);
Assert.AreEqual(clientSideObject.name, objectSpawned.NetworkId.Name);
Assert.AreNotEqual(0, objectSpawned.BytesCount);
}
@@ -83,20 +75,22 @@ namespace Unity.Netcode.RuntimeTests.Metrics
{
var networkObject = SpawnNetworkObject();
yield return new WaitForSeconds(0.2f);
yield return s_DefaultWaitForTick;
var waitForMetricEvent = new WaitForMetricValues<ObjectDestroyedEvent>(ServerMetrics.Dispatcher, NetworkMetricTypes.ObjectDestroyedSent);
var waitForMetricEvent = new WaitForEventMetricValues<ObjectDestroyedEvent>(ServerMetrics.Dispatcher, NetworkMetricTypes.ObjectDestroyedSent);
var objectName = networkObject.name;
Server.SpawnManager.OnDespawnObject(networkObject, true);
yield return s_DefaultWaitForTick;
yield return waitForMetricEvent.WaitForMetricsReceived();
var objectDestroyedSentMetricValues = waitForMetricEvent.AssertMetricValuesHaveBeenFound();
Assert.AreEqual(2, objectDestroyedSentMetricValues.Count); // As there's a client and server, this event is emitted twice.
Assert.AreEqual(2, objectDestroyedSentMetricValues.Count);
var objectDestroyed = objectDestroyedSentMetricValues.Last();
Assert.AreEqual(Client.LocalClientId, objectDestroyed.Connection.Id);
Assert.AreEqual($"{k_NewNetworkObjectName}(Clone)", objectDestroyed.NetworkId.Name);
Assert.AreEqual(objectName, objectDestroyed.NetworkId.Name);
Assert.AreNotEqual(0, objectDestroyed.BytesCount);
}
@@ -105,11 +99,14 @@ namespace Unity.Netcode.RuntimeTests.Metrics
{
var networkObject = SpawnNetworkObject();
yield return new WaitForSeconds(0.2f);
yield return s_DefaultWaitForTick;
var waitForMetricEvent = new WaitForMetricValues<ObjectDestroyedEvent>(ClientMetrics.Dispatcher, NetworkMetricTypes.ObjectDestroyedReceived);
var waitForMetricEvent = new WaitForEventMetricValues<ObjectDestroyedEvent>(ClientMetrics.Dispatcher, NetworkMetricTypes.ObjectDestroyedReceived);
var objectId = networkObject.NetworkObjectId;
var objectName = s_GlobalNetworkObjects[1][objectId].name;
Server.SpawnManager.OnDespawnObject(networkObject, true);
yield return s_DefaultWaitForTick;
yield return waitForMetricEvent.WaitForMetricsReceived();
@@ -118,8 +115,8 @@ namespace Unity.Netcode.RuntimeTests.Metrics
var objectDestroyed = objectDestroyedReceivedMetricValues.First();
Assert.AreEqual(Server.LocalClientId, objectDestroyed.Connection.Id);
Assert.AreEqual(networkObject.NetworkObjectId, objectDestroyed.NetworkId.NetworkId);
Assert.AreEqual($"{k_NewNetworkObjectName}(Clone)", objectDestroyed.NetworkId.Name);
Assert.AreEqual(objectId, objectDestroyed.NetworkId.NetworkId);
Assert.AreEqual(objectName, objectDestroyed.NetworkId.Name);
Assert.AreNotEqual(0, objectDestroyed.BytesCount);
}
@@ -128,16 +125,16 @@ namespace Unity.Netcode.RuntimeTests.Metrics
{
var networkObject1 = SpawnNetworkObject();
var networkObject2 = SpawnNetworkObject();
yield return new WaitForSeconds(0.2f);
yield return s_DefaultWaitForTick;
NetworkObject.NetworkHide(new List<NetworkObject> { networkObject1, networkObject2 }, Client.LocalClientId);
yield return new WaitForSeconds(0.2f);
yield return s_DefaultWaitForTick;
var waitForMetricEvent = new WaitForMetricValues<ObjectSpawnedEvent>(ServerMetrics.Dispatcher, NetworkMetricTypes.ObjectSpawnedSent);
var waitForMetricEvent = new WaitForEventMetricValues<ObjectSpawnedEvent>(ServerMetrics.Dispatcher, NetworkMetricTypes.ObjectSpawnedSent);
NetworkObject.NetworkShow(new List<NetworkObject> { networkObject1, networkObject2 }, Client.LocalClientId);
yield return s_DefaultWaitForTick;
yield return waitForMetricEvent.WaitForMetricsReceived();
@@ -166,12 +163,12 @@ namespace Unity.Netcode.RuntimeTests.Metrics
var networkObject1 = SpawnNetworkObject();
var networkObject2 = SpawnNetworkObject();
yield return new WaitForSeconds(0.2f);
yield return s_DefaultWaitForTick;
var waitForMetricEvent = new WaitForMetricValues<ObjectDestroyedEvent>(ServerMetrics.Dispatcher, NetworkMetricTypes.ObjectDestroyedSent);
var waitForMetricEvent = new WaitForEventMetricValues<ObjectDestroyedEvent>(ServerMetrics.Dispatcher, NetworkMetricTypes.ObjectDestroyedSent);
NetworkObject.NetworkHide(new List<NetworkObject> { networkObject1, networkObject2 }, Client.LocalClientId);
yield return s_DefaultWaitForTick;
yield return waitForMetricEvent.WaitForMetricsReceived();
var objectDestroyedSentMetricValues = waitForMetricEvent.AssertMetricValuesHaveBeenFound();

View File

@@ -1,23 +1,25 @@
#if MULTIPLAYER_TOOLS
using System;
using System.Collections;
using System.Linq;
using NUnit.Framework;
using Unity.Multiplayer.Tools.MetricTypes;
using Unity.Netcode.RuntimeTests.Metrics.Utility;
using UnityEngine;
using UnityEngine.TestTools;
using Unity.Netcode.TestHelpers.Runtime.Metrics;
namespace Unity.Netcode.RuntimeTests.Metrics
{
internal class NetworkVariableMetricsTests : SingleClientMetricTestBase
{
protected override Action<GameObject> UpdatePlayerPrefab => prefab => prefab.AddComponent<NetworkVariableComponent>();
protected override void OnCreatePlayerPrefab()
{
m_PlayerPrefab.AddComponent<NetworkVariableComponent>();
base.OnCreatePlayerPrefab();
}
[UnityTest]
public IEnumerator TrackNetworkVariableDeltaSentMetric()
{
var waitForMetricValues = new WaitForMetricValues<NetworkVariableEvent>(ServerMetrics.Dispatcher, NetworkMetricTypes.NetworkVariableDeltaSent);
var waitForMetricValues = new WaitForEventMetricValues<NetworkVariableEvent>(ServerMetrics.Dispatcher, NetworkMetricTypes.NetworkVariableDeltaSent);
yield return waitForMetricValues.WaitForMetricsReceived();
@@ -32,7 +34,7 @@ namespace Unity.Netcode.RuntimeTests.Metrics
[UnityTest]
public IEnumerator TrackNetworkVariableDeltaReceivedMetric()
{
var waitForMetricValues = new WaitForMetricValues<NetworkVariableEvent>(ClientMetrics.Dispatcher, NetworkMetricTypes.NetworkVariableDeltaReceived);
var waitForMetricValues = new WaitForEventMetricValues<NetworkVariableEvent>(ClientMetrics.Dispatcher, NetworkMetricTypes.NetworkVariableDeltaReceived);
yield return waitForMetricValues.WaitForMetricsReceived();

View File

@@ -4,9 +4,10 @@ using System.Collections;
using System.Linq;
using NUnit.Framework;
using Unity.Multiplayer.Tools.MetricTypes;
using Unity.Netcode.RuntimeTests.Metrics.Utility;
using UnityEngine;
using UnityEngine.TestTools;
using Unity.Netcode.TestHelpers.Runtime;
using Unity.Netcode.TestHelpers.Runtime.Metrics;
namespace Unity.Netcode.RuntimeTests.Metrics
{
@@ -17,11 +18,11 @@ namespace Unity.Netcode.RuntimeTests.Metrics
// Header is dynamically sized due to packing, will be 2 bytes for all test messages.
private const int k_MessageHeaderSize = 2;
protected override Action<GameObject> UpdatePlayerPrefab => _ =>
protected override void OnServerAndClientsCreated()
{
var gameObject = new GameObject(k_NewNetworkObjectName);
m_NewNetworkPrefab = gameObject.AddComponent<NetworkObject>();
MultiInstanceHelpers.MakeNetworkObjectTestPrefab(m_NewNetworkPrefab);
NetcodeIntegrationTestHelpers.MakeNetworkObjectTestPrefab(m_NewNetworkPrefab);
var networkPrefab = new NetworkPrefab { Prefab = gameObject };
m_ServerNetworkManager.NetworkConfig.NetworkPrefabs.Add(networkPrefab);
@@ -29,7 +30,8 @@ namespace Unity.Netcode.RuntimeTests.Metrics
{
client.NetworkConfig.NetworkPrefabs.Add(networkPrefab);
}
};
base.OnServerAndClientsCreated();
}
private NetworkObject SpawnNetworkObject()
{
@@ -49,7 +51,7 @@ namespace Unity.Netcode.RuntimeTests.Metrics
yield return new WaitForSeconds(0.2f);
var waitForMetricValues = new WaitForMetricValues<OwnershipChangeEvent>(ServerMetrics.Dispatcher, NetworkMetricTypes.OwnershipChangeSent);
var waitForMetricValues = new WaitForEventMetricValues<OwnershipChangeEvent>(ServerMetrics.Dispatcher, NetworkMetricTypes.OwnershipChangeSent);
networkObject.ChangeOwnership(1);
@@ -70,7 +72,7 @@ namespace Unity.Netcode.RuntimeTests.Metrics
yield return new WaitForSeconds(0.2f);
var waitForMetricValues = new WaitForMetricValues<OwnershipChangeEvent>(ClientMetrics.Dispatcher, NetworkMetricTypes.OwnershipChangeReceived);
var waitForMetricValues = new WaitForEventMetricValues<OwnershipChangeEvent>(ClientMetrics.Dispatcher, NetworkMetricTypes.OwnershipChangeReceived);
networkObject.ChangeOwnership(1);

View File

@@ -0,0 +1,62 @@
#if MULTIPLAYER_TOOLS
#if MULTIPLAYER_TOOLS_1_0_0_PRE_4
using System.Collections;
using NUnit.Framework;
using Unity.Collections;
using Unity.Multiplayer.Tools.MetricTypes;
using UnityEngine.TestTools;
using Unity.Netcode.TestHelpers.Runtime;
using Unity.Netcode.TestHelpers.Runtime.Metrics;
namespace Unity.Netcode.RuntimeTests.Metrics
{
internal class PacketMetricsTests : SingleClientMetricTestBase
{
protected override void OnOneTimeSetup()
{
#if UTP_ADAPTER
m_NetworkTransport = NetcodeIntegrationTestHelpers.InstanceTransport.UTP;
#else
m_NetworkTransport = NetcodeIntegrationTestHelpers.InstanceTransport.SIP;
#endif
base.OnOneTimeSetup();
}
[UnityTest]
public IEnumerator TrackPacketSentMetric()
{
var waitForMetricValues = new WaitForCounterMetricValue(ServerMetrics.Dispatcher, NetworkMetricTypes.PacketsSent, metric => metric > 0);
using (var writer = new FastBufferWriter(sizeof(uint), Allocator.Temp))
{
writer.WriteValueSafe(1337);
Server.CustomMessagingManager.SendUnnamedMessageToAll(writer);
}
yield return waitForMetricValues.WaitForMetricsReceived();
var totalPacketCount = waitForMetricValues.AssertMetricValueHaveBeenFound();
Assert.That(totalPacketCount, Is.InRange(1, 4));
}
[UnityTest]
public IEnumerator TrackPacketReceivedMetric()
{
var waitForMetricValues = new WaitForCounterMetricValue(ClientMetrics.Dispatcher, NetworkMetricTypes.PacketsReceived, metric => metric > 0);
using (var writer = new FastBufferWriter(sizeof(uint), Allocator.Temp))
{
writer.WriteValueSafe(1337);
Server.CustomMessagingManager.SendUnnamedMessageToAll(writer);
}
yield return waitForMetricValues.WaitForMetricsReceived();
var totalPacketCount = waitForMetricValues.AssertMetricValueHaveBeenFound();
Assert.That(totalPacketCount, Is.InRange(1, 4));
}
}
}
#endif
#endif

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 84a4884f4ea744a9944284d56b29531b
timeCreated: 1644269306

View File

@@ -1,28 +1,27 @@
#if MULTIPLAYER_TOOLS
using System;
using System.Collections;
using System.Linq;
using NUnit.Framework;
using Unity.Multiplayer.Tools.MetricTypes;
using Unity.Netcode.RuntimeTests.Metrics.Utility;
using UnityEngine;
using UnityEngine.TestTools;
using Unity.Netcode.TestHelpers.Runtime.Metrics;
namespace Unity.Netcode.RuntimeTests.Metrics
{
internal class RpcMetricsTests : SingleClientMetricTestBase
{
protected override Action<GameObject> UpdatePlayerPrefab => prefab => prefab.AddComponent<RpcTestComponent>();
protected override void OnCreatePlayerPrefab()
{
m_PlayerPrefab.AddComponent<RpcTestComponent>();
base.OnCreatePlayerPrefab();
}
[UnityTest]
public IEnumerator TrackRpcSentMetricOnServer()
{
var clientPlayer = new MultiInstanceHelpers.CoroutineResultWrapper<NetworkObject>();
yield return MultiInstanceHelpers.Run(MultiInstanceHelpers.GetNetworkObjectByRepresentation(x => x.IsPlayerObject && x.OwnerClientId == Client.LocalClientId, Server, clientPlayer));
var waitForMetricValues = new WaitForEventMetricValues<RpcEvent>(ServerMetrics.Dispatcher, NetworkMetricTypes.RpcSent);
var waitForMetricValues = new WaitForMetricValues<RpcEvent>(ServerMetrics.Dispatcher, NetworkMetricTypes.RpcSent);
clientPlayer.Result.GetComponent<RpcTestComponent>().MyClientRpc();
m_PlayerNetworkObjects[m_ServerNetworkManager.LocalClientId][Client.LocalClientId].GetComponent<RpcTestComponent>().MyClientRpc();
yield return waitForMetricValues.WaitForMetricsReceived();
@@ -39,12 +38,9 @@ namespace Unity.Netcode.RuntimeTests.Metrics
[UnityTest]
public IEnumerator TrackRpcSentMetricOnClient()
{
var clientPlayer = new MultiInstanceHelpers.CoroutineResultWrapper<NetworkObject>();
yield return MultiInstanceHelpers.Run(MultiInstanceHelpers.GetNetworkObjectByRepresentation(x => x.IsPlayerObject && x.OwnerClientId == Client.LocalClientId, Client, clientPlayer));
var waitForClientMetricsValues = new WaitForEventMetricValues<RpcEvent>(ClientMetrics.Dispatcher, NetworkMetricTypes.RpcSent);
var waitForClientMetricsValues = new WaitForMetricValues<RpcEvent>(ClientMetrics.Dispatcher, NetworkMetricTypes.RpcSent);
clientPlayer.Result.GetComponent<RpcTestComponent>().MyServerRpc();
m_PlayerNetworkObjects[Client.LocalClientId][Client.LocalClientId].GetComponent<RpcTestComponent>().MyServerRpc();
yield return waitForClientMetricsValues.WaitForMetricsReceived();
@@ -61,12 +57,8 @@ namespace Unity.Netcode.RuntimeTests.Metrics
[UnityTest]
public IEnumerator TrackRpcReceivedMetricOnServer()
{
var clientPlayer = new MultiInstanceHelpers.CoroutineResultWrapper<NetworkObject>();
yield return MultiInstanceHelpers.Run(MultiInstanceHelpers.GetNetworkObjectByRepresentation(x => x.IsPlayerObject && x.OwnerClientId == Client.LocalClientId, Client, clientPlayer));
var waitForServerMetricsValues = new WaitForMetricValues<RpcEvent>(ServerMetrics.Dispatcher, NetworkMetricTypes.RpcReceived);
clientPlayer.Result.GetComponent<RpcTestComponent>().MyServerRpc();
var waitForServerMetricsValues = new WaitForEventMetricValues<RpcEvent>(ServerMetrics.Dispatcher, NetworkMetricTypes.RpcReceived);
m_PlayerNetworkObjects[Client.LocalClientId][Client.LocalClientId].GetComponent<RpcTestComponent>().MyServerRpc();
yield return waitForServerMetricsValues.WaitForMetricsReceived();
@@ -83,16 +75,13 @@ namespace Unity.Netcode.RuntimeTests.Metrics
[UnityTest]
public IEnumerator TrackRpcReceivedMetricOnClient()
{
var clientPlayer = new MultiInstanceHelpers.CoroutineResultWrapper<NetworkObject>();
yield return MultiInstanceHelpers.Run(MultiInstanceHelpers.GetNetworkObjectByRepresentation(x => x.IsPlayerObject && x.OwnerClientId == Client.LocalClientId, Server, clientPlayer));
var waitForClientMetricsValues = new WaitForEventMetricValues<RpcEvent>(ClientMetrics.Dispatcher, NetworkMetricTypes.RpcReceived);
var waitForServerMetricsValues = new WaitForMetricValues<RpcEvent>(ServerMetrics.Dispatcher, NetworkMetricTypes.RpcReceived);
m_PlayerNetworkObjects[m_ServerNetworkManager.LocalClientId][Client.LocalClientId].GetComponent<RpcTestComponent>().MyClientRpc();
clientPlayer.Result.GetComponent<RpcTestComponent>().MyClientRpc();
yield return waitForClientMetricsValues.WaitForMetricsReceived();
yield return waitForServerMetricsValues.WaitForMetricsReceived();
var clientRpcReceivedValues = waitForServerMetricsValues.AssertMetricValuesHaveBeenFound();
var clientRpcReceivedValues = waitForClientMetricsValues.AssertMetricValuesHaveBeenFound();
Assert.AreEqual(1, clientRpcReceivedValues.Count);
var rpcReceived = clientRpcReceivedValues.First();

View File

@@ -0,0 +1,101 @@
#if MULTIPLAYER_TOOLS
#if MULTIPLAYER_TOOLS_1_0_0_PRE_4
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;
using Unity.Collections;
using Unity.Multiplayer.Tools.MetricTypes;
using UnityEngine.TestTools;
using Unity.Netcode.TestHelpers.Runtime;
using Unity.Netcode.TestHelpers.Runtime.Metrics;
namespace Unity.Netcode.RuntimeTests.Metrics
{
/// <summary>
/// Note: This is one way to easily identify each specific test.
/// Since the test only tested 1 and then 2 clients, I made this
/// and enum, but you can always remove the enum in the constructor,
/// replace it with an int, and then test from 1 to 9 clients.
/// Just an example of how you can accomplish the same task using
/// the NetcodeIntegrationTest
/// </summary>
[TestFixture(ClientCount.OneClient)]
[TestFixture(ClientCount.TwoClients)]
internal class RttMetricsTests : NetcodeIntegrationTest
{
protected override int NumberOfClients => m_ClientCount;
public enum ClientCount
{
OneClient,
TwoClients
}
private int m_ClientCount;
public RttMetricsTests(ClientCount numberOfClients)
{
m_ClientCount = numberOfClients == ClientCount.OneClient ? 1 : 2;
}
/// <summary>
/// Note: We are using the OnOneTimeSetup to select the transport to use for
/// this test set.
/// </summary>
protected override void OnOneTimeSetup()
{
#if UTP_ADAPTER
m_NetworkTransport = NetcodeIntegrationTestHelpers.InstanceTransport.UTP;
#else
m_NetworkTransport = NetcodeIntegrationTestHelpers.InstanceTransport.SIP;
#endif
}
[UnityTest]
public IEnumerator TrackRttMetricServerToClient()
{
var waitForMetricValues = new WaitForGaugeMetricValues((m_ServerNetworkManager.NetworkMetrics as NetworkMetrics).Dispatcher, NetworkMetricTypes.RttToServer);
using (var writer = new FastBufferWriter(sizeof(uint), Allocator.Temp))
{
writer.WriteValueSafe(1337);
m_ServerNetworkManager.CustomMessagingManager.SendUnnamedMessageToAll(writer);
}
yield return WaitForConditionOrTimeOut(() => waitForMetricValues.MetricFound());
Assert.False(s_GlobalTimeoutHelper.TimedOut, $"{nameof(TrackRttMetricServerToClient)} timed out waiting for metric to be found for {m_ClientCount} clients!");
var rttValue = waitForMetricValues.AssertMetricValueHaveBeenFound();
Assert.AreEqual(0f, rttValue);
}
[UnityTest]
public IEnumerator TrackRttMetricClientToServer()
{
var clientGaugeMetricValues = new List<WaitForGaugeMetricValues>();
foreach (var client in m_ClientNetworkManagers)
{
clientGaugeMetricValues.Add(new WaitForGaugeMetricValues((client.NetworkMetrics as NetworkMetrics).Dispatcher, NetworkMetricTypes.RttToServer, metric => metric > 0f));
}
using (var writer = new FastBufferWriter(sizeof(uint), Allocator.Temp))
{
writer.WriteValueSafe(1337);
m_ServerNetworkManager.CustomMessagingManager.SendUnnamedMessageToAll(writer);
}
yield return WaitForConditionOrTimeOut(() => clientGaugeMetricValues.Where((c) => c.MetricFound()).Count() == NumberOfClients);
Assert.False(s_GlobalTimeoutHelper.TimedOut, $"{nameof(TrackRttMetricClientToServer)} timed out waiting for metric to be found for {m_ClientCount} clients!");
foreach (var clientGaugeMetricValue in clientGaugeMetricValues)
{
var rttValue = clientGaugeMetricValue.AssertMetricValueHaveBeenFound();
Assert.That(rttValue, Is.GreaterThanOrEqualTo(1f));
}
}
}
}
#endif
#endif

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 452fbcb436d24291ba7db3a68e3e50ac
timeCreated: 1644269321

View File

@@ -4,8 +4,8 @@ using System.Collections;
using System.Linq;
using NUnit.Framework;
using Unity.Multiplayer.Tools.MetricTypes;
using Unity.Netcode.RuntimeTests.Metrics.Utility;
using UnityEngine.TestTools;
using Unity.Netcode.TestHelpers.Runtime.Metrics;
namespace Unity.Netcode.RuntimeTests.Metrics
{
@@ -19,10 +19,13 @@ namespace Unity.Netcode.RuntimeTests.Metrics
[UnityTest]
public IEnumerator TrackServerLogSentMetric()
{
var waitForSentMetric = new WaitForMetricValues<ServerLogEvent>(ClientMetrics.Dispatcher, NetworkMetricTypes.ServerLogSent);
var waitForSentMetric = new WaitForEventMetricValues<ServerLogEvent>(ClientMetrics.Dispatcher, NetworkMetricTypes.ServerLogSent);
var message = Guid.NewGuid().ToString();
Client.LogLevel = LogLevel.Developer;
Server.LogLevel = LogLevel.Developer;
NetworkLog.LogWarningServer(message);
yield return s_DefaultWaitForTick;
yield return waitForSentMetric.WaitForMetricsReceived();
@@ -38,11 +41,15 @@ namespace Unity.Netcode.RuntimeTests.Metrics
[UnityTest]
public IEnumerator TrackServerLogReceivedMetric()
{
var waitForReceivedMetric = new WaitForMetricValues<ServerLogEvent>(ServerMetrics.Dispatcher, NetworkMetricTypes.ServerLogReceived);
var waitForReceivedMetric = new WaitForEventMetricValues<ServerLogEvent>(ServerMetrics.Dispatcher, NetworkMetricTypes.ServerLogReceived);
var message = Guid.NewGuid().ToString();
Client.LogLevel = LogLevel.Developer;
Server.LogLevel = LogLevel.Developer;
NetworkLog.LogWarningServer(message);
yield return s_DefaultWaitForTick;
yield return waitForReceivedMetric.WaitForMetricsReceived();
var receivedMetrics = waitForReceivedMetric.AssertMetricValuesHaveBeenFound();

View File

@@ -6,7 +6,7 @@ using NUnit.Framework;
using Unity.Collections;
using Unity.Multiplayer.Tools.MetricTypes;
using Unity.Multiplayer.Tools.NetStats;
using Unity.Netcode.RuntimeTests.Metrics.Utility;
using Unity.Netcode.TestHelpers.Runtime.Metrics;
using UnityEngine.TestTools;
namespace Unity.Netcode.RuntimeTests.Metrics
@@ -26,7 +26,7 @@ namespace Unity.Netcode.RuntimeTests.Metrics
try
{
writer.WriteValueSafe(messageName);
Server.CustomMessagingManager.SendNamedMessage(messageName.ToString(), Client.LocalClientId, writer);
}
finally
@@ -54,7 +54,7 @@ namespace Unity.Netcode.RuntimeTests.Metrics
try
{
writer.WriteValueSafe(messageName);
Server.CustomMessagingManager.SendNamedMessage(messageName.ToString(), Client.LocalClientId, writer);
}
finally

View File

@@ -1,71 +0,0 @@
#if MULTIPLAYER_TOOLS
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;
using Unity.Multiplayer.Tools.MetricTypes;
using UnityEngine;
using UnityEngine.TestTools;
namespace Unity.Netcode.RuntimeTests.Metrics.Utility
{
internal abstract class SingleClientMetricTestBase : BaseMultiInstanceTest
{
protected override int NbClients => 1;
protected virtual Action<GameObject> UpdatePlayerPrefab => _ => { };
internal NetworkManager Server { get; private set; }
internal NetworkMetrics ServerMetrics { get; private set; }
internal NetworkManager Client { get; private set; }
internal NetworkMetrics ClientMetrics { get; private set; }
[UnitySetUp]
public override IEnumerator Setup()
{
yield return StartSomeClientsAndServerWithPlayers(true, NbClients, UpdatePlayerPrefab);
Server = m_ServerNetworkManager;
ServerMetrics = Server.NetworkMetrics as NetworkMetrics;
Client = m_ClientNetworkManagers[0];
ClientMetrics = Client.NetworkMetrics as NetworkMetrics;
}
}
public abstract class DualClientMetricTestBase : BaseMultiInstanceTest
{
protected override int NbClients => 2;
protected virtual Action<GameObject> UpdatePlayerPrefab => _ => { };
internal NetworkManager Server { get; private set; }
internal NetworkMetrics ServerMetrics { get; private set; }
internal NetworkManager FirstClient { get; private set; }
internal NetworkMetrics FirstClientMetrics { get; private set; }
internal NetworkManager SecondClient { get; private set; }
internal NetworkMetrics SecondClientMetrics { get; private set; }
[UnitySetUp]
public override IEnumerator Setup()
{
yield return StartSomeClientsAndServerWithPlayers(true, NbClients, UpdatePlayerPrefab);
Server = m_ServerNetworkManager;
ServerMetrics = Server.NetworkMetrics as NetworkMetrics;
FirstClient = m_ClientNetworkManagers[0];
FirstClientMetrics = FirstClient.NetworkMetrics as NetworkMetrics;
SecondClient = m_ClientNetworkManagers[0];
SecondClientMetrics = SecondClient.NetworkMetrics as NetworkMetrics;
}
}
}
#endif

View File

@@ -1,19 +0,0 @@
#if MULTIPLAYER_TOOLS
using UnityEngine;
namespace Unity.Netcode.RuntimeTests.Metrics.Utility
{
public class NetworkVariableComponent : NetworkBehaviour
{
public NetworkVariable<int> MyNetworkVariable { get; } = new NetworkVariable<int>();
private void Update()
{
if (IsServer)
{
MyNetworkVariable.Value = Random.Range(100, 999);
}
}
}
}
#endif

View File

@@ -1,22 +0,0 @@
using System;
namespace Unity.Netcode.RuntimeTests.Metrics.Utility
{
public class RpcTestComponent : NetworkBehaviour
{
public event Action OnServerRpcAction;
public event Action OnClientRpcAction;
[ServerRpc]
public void MyServerRpc()
{
OnServerRpcAction?.Invoke();
}
[ClientRpc]
public void MyClientRpc()
{
OnClientRpcAction?.Invoke();
}
}
}

View File

@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: fdfa28da9866545428083671c445a9ef
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,118 +0,0 @@
#if MULTIPLAYER_TOOLS
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;
using Unity.Multiplayer.Tools.MetricTypes;
using Unity.Multiplayer.Tools.NetStats;
namespace Unity.Netcode.RuntimeTests.Metrics.Utility
{
internal class WaitForMetricValues<TMetric> : IMetricObserver
{
readonly string m_MetricName;
bool m_Found;
bool m_HasError;
string m_Error;
uint m_NbFrames = 0;
IReadOnlyCollection<TMetric> m_Values;
public delegate bool Filter(TMetric metric);
Filter m_FilterDelegate;
public WaitForMetricValues(IMetricDispatcher dispatcher, DirectionalMetricInfo directionalMetricName)
{
m_MetricName = directionalMetricName.Id;
dispatcher.RegisterObserver(this);
}
public WaitForMetricValues(IMetricDispatcher dispatcher, DirectionalMetricInfo directionalMetricName, Filter filter)
: this(dispatcher, directionalMetricName)
{
m_FilterDelegate = filter;
}
public IEnumerator WaitForMetricsReceived()
{
yield return WaitForFrames(60);
}
public IReadOnlyCollection<TMetric> AssertMetricValuesHaveBeenFound()
{
if (m_HasError)
{
Assert.Fail(m_Error);
}
if (!m_Found)
{
Assert.Fail($"Found no matching values for metric of type '{typeof(TMetric).Name}', with name '{m_MetricName}' during '{m_NbFrames}' frames.");
}
return m_Values;
}
public void AssertMetricValuesHaveNotBeenFound()
{
if (m_HasError)
{
Assert.Fail(m_Error);
}
if (!m_Found)
{
Assert.Pass();
}
else
{
Assert.Fail();
}
}
public void Observe(MetricCollection collection)
{
if (m_Found || m_HasError)
{
return;
}
var metric = collection.Metrics.SingleOrDefault(x => x.Name == m_MetricName);
if (metric == default)
{
m_HasError = true;
m_Error = $"Metric collection does not contain metric named '{m_MetricName}'.";
return;
}
var typedMetric = metric as IEventMetric<TMetric>;
if (typedMetric == default)
{
m_HasError = true;
m_Error = $"Metric collection contains a metric of type '{metric.GetType().Name}' for name '{m_MetricName}', but was expecting '{typeof(TMetric).Name}'.";
return;
}
if (typedMetric.Values.Any())
{
// Apply filter if one was provided
m_Values = m_FilterDelegate != null ? typedMetric.Values.Where(x => m_FilterDelegate(x)).ToList() : typedMetric.Values.ToList();
m_Found = m_Values.Count > 0;
}
}
private IEnumerator WaitForFrames(uint maxNbFrames)
{
while (!m_Found && m_NbFrames < maxNbFrames)
{
m_NbFrames++;
yield return null;
}
}
}
}
#endif

View File

@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 176888f06e2c5e14db33783fd0299668
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,505 +0,0 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;
using UnityEngine;
using UnityEngine.SceneManagement;
using Object = UnityEngine.Object;
namespace Unity.Netcode.RuntimeTests
{
/// <summary>
/// Provides helpers for running multi instance tests.
/// </summary>
public static class MultiInstanceHelpers
{
public const int DefaultMinFrames = 1;
public const int DefaultMaxFrames = 64;
private static List<NetworkManager> s_NetworkManagerInstances = new List<NetworkManager>();
private static bool s_IsStarted;
private static int s_ClientCount;
private static int s_OriginalTargetFrameRate = -1;
public static List<NetworkManager> NetworkManagerInstances => s_NetworkManagerInstances;
/// <summary>
/// Creates NetworkingManagers and configures them for use in a multi instance setting.
/// </summary>
/// <param name="clientCount">The amount of clients</param>
/// <param name="server">The server NetworkManager</param>
/// <param name="clients">The clients NetworkManagers</param>
/// <param name="targetFrameRate">The targetFrameRate of the Unity engine to use while the multi instance helper is running. Will be reset on shutdown.</param>
public static bool Create(int clientCount, out NetworkManager server, out NetworkManager[] clients, int targetFrameRate = 60)
{
s_NetworkManagerInstances = new List<NetworkManager>();
CreateNewClients(clientCount, out clients);
// Create gameObject
var go = new GameObject("NetworkManager - Server");
// Create networkManager component
server = go.AddComponent<NetworkManager>();
NetworkManagerInstances.Insert(0, server);
// Set the NetworkConfig
server.NetworkConfig = new NetworkConfig()
{
// Set transport
NetworkTransport = go.AddComponent<SIPTransport>()
};
s_OriginalTargetFrameRate = Application.targetFrameRate;
Application.targetFrameRate = targetFrameRate;
return true;
}
/// <summary>
/// Used to add a client to the already existing list of clients
/// </summary>
/// <param name="clientCount">The amount of clients</param>
/// <param name="clients"></param>
/// <returns></returns>
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>();
// Set the NetworkConfig
clients[i].NetworkConfig = new NetworkConfig()
{
// Set transport
NetworkTransport = go.AddComponent<SIPTransport>()
};
}
NetworkManagerInstances.AddRange(clients);
return true;
}
/// <summary>
/// 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)
{
clientToStop.Shutdown();
Object.Destroy(clientToStop.gameObject);
NetworkManagerInstances.Remove(clientToStop);
}
/// <summary>
/// Should always be invoked when finished with a single unit test
/// (i.e. during TearDown)
/// </summary>
public static void Destroy()
{
if (s_IsStarted == false)
{
return;
}
s_IsStarted = false;
// Shutdown the server which forces clients to disconnect
foreach (var networkManager in NetworkManagerInstances)
{
networkManager.Shutdown();
}
// Destroy the network manager instances
foreach (var networkManager in NetworkManagerInstances)
{
Object.DestroyImmediate(networkManager.gameObject);
}
NetworkManagerInstances.Clear();
// Destroy the temporary GameObject used to run co-routines
if (s_CoroutineRunner != null)
{
s_CoroutineRunner.StopAllCoroutines();
Object.DestroyImmediate(s_CoroutineRunner);
}
Application.targetFrameRate = s_OriginalTargetFrameRate;
}
/// <summary>
/// Starts NetworkManager instances created by the Create method.
/// </summary>
/// <param name="host">Whether or not to create a Host instead of Server</param>
/// <param name="server">The Server NetworkManager</param>
/// <param name="clients">The Clients NetworkManager</param>
/// <param name="startInitializationCallback">called immediately after server and client(s) are started</param>
/// <returns></returns>
public static bool Start(bool host, NetworkManager server, NetworkManager[] clients, Action<NetworkManager> startInitializationCallback = null)
{
if (s_IsStarted)
{
throw new InvalidOperationException("MultiInstanceHelper already started. Did you forget to Destroy?");
}
s_IsStarted = true;
s_ClientCount = clients.Length;
if (host)
{
server.StartHost();
}
else
{
server.StartServer();
}
// if set, then invoke this for the server
startInitializationCallback?.Invoke(server);
for (int i = 0; i < clients.Length; i++)
{
clients[i].StartClient();
// if set, then invoke this for the client
startInitializationCallback?.Invoke(clients[i]);
}
return true;
}
// Empty MonoBehaviour that is a holder of coroutine
private class CoroutineRunner : MonoBehaviour
{
}
private static CoroutineRunner s_CoroutineRunner;
/// <summary>
/// Runs a IEnumerator as a Coroutine on a dummy GameObject. Used to get exceptions coming from the coroutine
/// </summary>
/// <param name="enumerator">The IEnumerator to run</param>
public static Coroutine Run(IEnumerator enumerator)
{
if (s_CoroutineRunner == null)
{
s_CoroutineRunner = new GameObject(nameof(CoroutineRunner)).AddComponent<CoroutineRunner>();
}
return s_CoroutineRunner.StartCoroutine(enumerator);
}
public class CoroutineResultWrapper<T>
{
public T Result;
}
private static uint s_AutoIncrementGlobalObjectIdHashCounter = 111111;
/// <summary>
/// Normally we would only allow player prefabs to be set to a prefab. Not runtime created objects.
/// In order to prevent having a Resource folder full of a TON of prefabs that we have to maintain,
/// MultiInstanceHelper has a helper function that lets you mark a runtime created object to be
/// treated as a prefab by the Netcode. That's how we can get away with creating the player prefab
/// at runtime without it being treated as a SceneObject or causing other conflicts with the Netcode.
/// </summary>
/// <param name="networkObject">The networkObject to be treated as Prefab</param>
/// <param name="globalObjectIdHash">The GlobalObjectId to force</param>
public static void MakeNetworkObjectTestPrefab(NetworkObject networkObject, uint globalObjectIdHash = default)
{
// Override `GlobalObjectIdHash` if `globalObjectIdHash` param is set
if (globalObjectIdHash != default)
{
networkObject.GlobalObjectIdHash = globalObjectIdHash;
}
// Fallback to auto-increment if `GlobalObjectIdHash` was never set
if (networkObject.GlobalObjectIdHash == default)
{
networkObject.GlobalObjectIdHash = ++s_AutoIncrementGlobalObjectIdHashCounter;
}
// Prevent object from being snapped up as a scene object
networkObject.IsSceneObject = false;
}
// We use GameObject instead of SceneObject to be able to keep hierarchy
public static void MarkAsSceneObjectRoot(GameObject networkObjectRoot, NetworkManager server, NetworkManager[] clients)
{
networkObjectRoot.name += " - Server";
NetworkObject[] serverNetworkObjects = networkObjectRoot.GetComponentsInChildren<NetworkObject>();
for (int i = 0; i < serverNetworkObjects.Length; i++)
{
serverNetworkObjects[i].NetworkManagerOwner = server;
}
for (int i = 0; i < clients.Length; i++)
{
GameObject root = Object.Instantiate(networkObjectRoot);
root.name += " - Client - " + i;
NetworkObject[] clientNetworkObjects = root.GetComponentsInChildren<NetworkObject>();
for (int j = 0; j < clientNetworkObjects.Length; j++)
{
clientNetworkObjects[j].NetworkManagerOwner = clients[i];
}
}
}
/// <summary>
/// Waits on the client side to be connected.
/// </summary>
/// <param name="client">The client</param>
/// <param name="result">The result. If null, it will automatically assert</param>
/// <param name="maxFrames">The max frames to wait for</param>
public static IEnumerator WaitForClientConnected(NetworkManager client, CoroutineResultWrapper<bool> result = null, int maxFrames = DefaultMaxFrames)
{
yield return WaitForClientsConnected(new NetworkManager[] { client }, result, maxFrames);
}
/// <summary>
/// Similar to WaitForClientConnected, this waits for multiple clients to be connected.
/// </summary>
/// <param name="clients">The clients to be connected</param>
/// <param name="result">The result. If null, it will automatically assert<</param>
/// <param name="maxFrames">The max frames to wait for</param>
/// <returns></returns>
public static IEnumerator WaitForClientsConnected(NetworkManager[] clients, CoroutineResultWrapper<bool> result = null, int maxFrames = DefaultMaxFrames)
{
// Make sure none are the host client
foreach (var client in clients)
{
if (client.IsServer)
{
throw new InvalidOperationException("Cannot wait for connected as server");
}
}
var startFrameNumber = Time.frameCount;
var allConnected = true;
while (Time.frameCount - startFrameNumber <= maxFrames)
{
allConnected = true;
foreach (var client in clients)
{
if (!client.IsConnectedClient)
{
allConnected = false;
break;
}
}
if (allConnected)
{
break;
}
var nextFrameNumber = Time.frameCount + 1;
yield return new WaitUntil(() => Time.frameCount >= nextFrameNumber);
}
if (result != null)
{
result.Result = allConnected;
}
else
{
for (var i = 0; i < clients.Length; ++i)
{
var client = clients[i];
// Logging i+1 because that's the local client ID they'll get (0 is server)
// Can't use client.LocalClientId because that doesn't get assigned until IsConnectedClient == true,
Assert.True(client.IsConnectedClient, $"Client {i + 1} never connected");
}
}
}
/// <summary>
/// Waits on the server side for 1 client to be connected
/// </summary>
/// <param name="server">The server</param>
/// <param name="result">The result. If null, it will automatically assert</param>
/// <param name="maxFrames">The max frames to wait for</param>
public static IEnumerator WaitForClientConnectedToServer(NetworkManager server, CoroutineResultWrapper<bool> result = null, int maxFrames = DefaultMaxFrames)
{
yield return WaitForClientsConnectedToServer(server, server.IsHost ? s_ClientCount + 1 : s_ClientCount, result, maxFrames);
}
/// <summary>
/// Waits on the server side for 1 client to be connected
/// </summary>
/// <param name="server">The server</param>
/// <param name="result">The result. If null, it will automatically assert</param>
/// <param name="maxFrames">The max frames to wait for</param>
public static IEnumerator WaitForClientsConnectedToServer(NetworkManager server, int clientCount = 1, CoroutineResultWrapper<bool> result = null, int maxFrames = DefaultMaxFrames)
{
if (!server.IsServer)
{
throw new InvalidOperationException("Cannot wait for connected as client");
}
var startFrameNumber = Time.frameCount;
while (Time.frameCount - startFrameNumber <= maxFrames && server.ConnectedClients.Count != clientCount)
{
var nextFrameNumber = Time.frameCount + 1;
yield return new WaitUntil(() => Time.frameCount >= nextFrameNumber);
}
var res = server.ConnectedClients.Count == clientCount;
if (result != null)
{
result.Result = res;
}
else
{
Assert.True(res, "A client never connected to server");
}
}
/// <summary>
/// Gets a NetworkObject instance as it's represented by a certain peer.
/// </summary>
/// <param name="networkObjectId">The networkObjectId to get</param>
/// <param name="representation">The representation to get the object from</param>
/// <param name="result">The result</param>
/// <param name="failIfNull">Whether or not to fail if no object is found and result is null</param>
/// <param name="maxFrames">The max frames to wait for</param>
public static IEnumerator GetNetworkObjectByRepresentation(ulong networkObjectId, NetworkManager representation, CoroutineResultWrapper<NetworkObject> result, bool failIfNull = true, int maxFrames = DefaultMaxFrames)
{
if (result == null)
{
throw new ArgumentNullException("Result cannot be null");
}
var startFrameNumber = Time.frameCount;
while (Time.frameCount - startFrameNumber <= maxFrames && representation.SpawnManager.SpawnedObjects.All(x => x.Value.NetworkObjectId != networkObjectId))
{
var nextFrameNumber = Time.frameCount + 1;
yield return new WaitUntil(() => Time.frameCount >= nextFrameNumber);
}
result.Result = representation.SpawnManager.SpawnedObjects.First(x => x.Value.NetworkObjectId == networkObjectId).Value;
if (failIfNull && result.Result == null)
{
Assert.Fail("NetworkObject could not be found");
}
}
/// <summary>
/// Gets a NetworkObject instance as it's represented by a certain peer.
/// </summary>
/// <param name="predicate">The predicate used to filter for your target NetworkObject</param>
/// <param name="representation">The representation to get the object from</param>
/// <param name="result">The result</param>
/// <param name="failIfNull">Whether or not to fail if no object is found and result is null</param>
/// <param name="maxFrames">The max frames to wait for</param>
public static IEnumerator GetNetworkObjectByRepresentation(Func<NetworkObject, bool> predicate, NetworkManager representation, CoroutineResultWrapper<NetworkObject> result, bool failIfNull = true, int maxFrames = DefaultMaxFrames)
{
if (result == null)
{
throw new ArgumentNullException("Result cannot be null");
}
if (predicate == null)
{
throw new ArgumentNullException("Predicate cannot be null");
}
var startFrame = Time.frameCount;
while (Time.frameCount - startFrame <= maxFrames && !representation.SpawnManager.SpawnedObjects.Any(x => predicate(x.Value)))
{
var nextFrameNumber = Time.frameCount + 1;
yield return new WaitUntil(() => Time.frameCount >= nextFrameNumber);
}
result.Result = representation.SpawnManager.SpawnedObjects.FirstOrDefault(x => predicate(x.Value)).Value;
if (failIfNull && result.Result == null)
{
Assert.Fail("NetworkObject could not be found");
}
}
/// <summary>
/// Runs some code, then verifies the condition (combines 'Run' and 'WaitForCondition')
/// </summary>
/// <param name="workload">Action / code to run</param>
/// <param name="predicate">The predicate to wait for</param>
/// <param name="maxFrames">The max frames to wait for</param>
public static IEnumerator RunAndWaitForCondition(Action workload, Func<bool> predicate, int maxFrames = DefaultMaxFrames, int minFrames = DefaultMinFrames)
{
var waitResult = new CoroutineResultWrapper<bool>();
workload();
yield return Run(WaitForCondition(
predicate,
waitResult,
maxFrames: maxFrames,
minFrames: minFrames));
if (!waitResult.Result)
{
Assert.Fail("Predicate condition failed");
}
}
/// <summary>
/// Waits for a predicate condition to be met
/// </summary>
/// <param name="predicate">The predicate to wait for</param>
/// <param name="result">The result. If null, it will fail if the predicate is not met</param>
/// <param name="minFrames">The min frames to wait for</param>
/// <param name="maxFrames">The max frames to wait for</param>
public static IEnumerator WaitForCondition(Func<bool> predicate, CoroutineResultWrapper<bool> result = null, int maxFrames = DefaultMaxFrames, int minFrames = DefaultMinFrames)
{
if (predicate == null)
{
throw new ArgumentNullException("Predicate cannot be null");
}
var startFrameNumber = Time.frameCount;
if (minFrames > 0)
{
yield return new WaitUntil(() =>
{
return Time.frameCount >= minFrames;
});
}
while (Time.frameCount - startFrameNumber <= maxFrames &&
!predicate())
{
// Changed to 2 frames to avoid the scenario where it would take 1+ frames to
// see a value change (i.e. discovered in the NetworkTransformTests)
var nextFrameNumber = Time.frameCount + 2;
yield return new WaitUntil(() =>
{
return Time.frameCount >= nextFrameNumber;
});
}
var res = predicate();
if (result != null)
{
result.Result = res;
}
else
{
Assert.True(res, "PREDICATE CONDITION");
}
}
}
}

View File

@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: a1c62160e3e5b4489b2143fc21b56e55
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,37 +1,38 @@
using System.Collections;
using UnityEngine;
using NUnit.Framework;
using UnityEngine.TestTools;
using Unity.Netcode;
using Unity.Netcode.RuntimeTests;
using Unity.Netcode.TestHelpers.Runtime;
using Object = UnityEngine.Object;
namespace TestProject.RuntimeTests
namespace Unity.Netcode.RuntimeTests
{
public class NestedNetworkManagerTests
{
[UnityTest]
public IEnumerator CheckNestedNetworkManager()
[Test]
public void CheckNestedNetworkManager()
{
var parent = new GameObject("ParentObject");
var networkManagerObject = new GameObject(nameof(CheckNestedNetworkManager));
// Make our NetworkManager's GameObject nested
networkManagerObject.transform.parent = parent.transform;
// Pre-generate the error message we are expecting to see
var messageToCheck = NetworkManager.GenerateNestedNetworkManagerMessage(networkManagerObject.transform);
var transport = networkManagerObject.AddComponent<SIPTransport>();
var networkManager = networkManagerObject.AddComponent<NetworkManager>();
networkManager.NetworkConfig = new NetworkConfig() { NetworkTransport = transport };
// Trap for the nested NetworkManager exception
LogAssert.Expect(LogType.Error, messageToCheck);
yield return new WaitForSeconds(0.02f);
// Make our NetworkManager's GameObject nested
networkManagerObject.transform.parent = parent.transform;
// Generate the error message we are expecting to see
var messageToCheck = NetworkManager.GenerateNestedNetworkManagerMessage(networkManagerObject.transform);
// Trap for the nested NetworkManager exception
#if UNITY_EDITOR
LogAssert.Expect(LogType.Error, messageToCheck);
#else
LogAssert.Expect(LogType.Exception, $"Exception: {messageToCheck}");
#endif
// Clean up
Object.Destroy(parent);
yield return null;
}
}
}

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: fb1b6e801936c7f4a9af28dbed5ea2ff
guid: 3acde7838205d4b09ae3a035554c51c5
folderAsset: yes
DefaultImporter:
externalObjects: {}

View File

@@ -0,0 +1,237 @@
using System.Collections;
using System.Collections.Generic;
using NUnit.Framework;
using Unity.Netcode.Components;
using UnityEngine;
using UnityEngine.TestTools;
using Unity.Netcode.TestHelpers.Runtime;
namespace Unity.Netcode.RuntimeTests
{
[TestFixture(HostOrServer.Host)]
[TestFixture(HostOrServer.Server)]
public class NetworkAnimatorTests : NetcodeIntegrationTest
{
protected override int NumberOfClients => 1;
private GameObject m_PlayerOnServer;
private GameObject m_PlayerOnClient;
private Animator m_PlayerOnServerAnimator;
private Animator m_PlayerOnClientAnimator;
public NetworkAnimatorTests(HostOrServer hostOrServer) : base(hostOrServer) { }
protected override void OnCreatePlayerPrefab()
{
// ideally, we would build up the AnimatorController entirely in code and not need an asset,
// but after some attempts this doesn't seem readily doable. Instead, we load a controller
var controller = Resources.Load("TestAnimatorController") as RuntimeAnimatorController;
var animator = m_PlayerPrefab.AddComponent<Animator>();
animator.runtimeAnimatorController = controller;
var networkAnimator = m_PlayerPrefab.AddComponent<NetworkAnimator>();
networkAnimator.Animator = animator;
}
protected override IEnumerator OnServerAndClientsConnected()
{
m_PlayerOnServer = m_PlayerNetworkObjects[m_ServerNetworkManager.LocalClientId][m_ClientNetworkManagers[0].LocalClientId].gameObject;
m_PlayerOnServerAnimator = m_PlayerOnServerAnimator = m_PlayerOnServer.GetComponent<Animator>();
m_PlayerOnClient = m_PlayerNetworkObjects[m_ClientNetworkManagers[0].LocalClientId][m_ClientNetworkManagers[0].LocalClientId].gameObject;
m_PlayerOnClientAnimator = m_PlayerOnClient.GetComponent<Animator>();
return base.OnServerAndClientsConnected();
}
// helper function to scan an animator and verify a given clip is present
private bool HasClip(Animator animator, string clipName)
{
var clips = new List<AnimatorClipInfo>();
animator.GetCurrentAnimatorClipInfo(0, clips);
foreach (var clip in clips)
{
if (clip.clip.name == clipName)
{
return true;
}
}
return false;
}
[UnityTest]
public IEnumerator AnimationTriggerReset([Values(true, false)] bool asHash)
{
// We have "UnboundTrigger" purposely not bound to any animations so we can test resetting.
// If we used a trigger that was bound to a transition, then the trigger would reset as soon as the
// transition happens. This way it will stay stuck on
string triggerString = "UnboundTrigger";
int triggerHash = Animator.StringToHash(triggerString);
// Verify trigger is off
Assert.True(m_PlayerOnServerAnimator.GetBool(triggerString) == false);
Assert.True(m_PlayerOnClientAnimator.GetBool(triggerString) == false);
// trigger.
if (asHash)
{
m_PlayerOnServer.GetComponent<NetworkAnimator>().SetTrigger(triggerHash);
}
else
{
m_PlayerOnServer.GetComponent<NetworkAnimator>().SetTrigger(triggerString);
}
// verify trigger is set for client and server
yield return WaitForConditionOrTimeOut(() => asHash ? m_PlayerOnServerAnimator.GetBool(triggerHash) : m_PlayerOnServerAnimator.GetBool(triggerString));
Assert.False(s_GlobalTimeoutHelper.TimedOut, "Timed out on server trigger set check");
yield return WaitForConditionOrTimeOut(() => asHash ? m_PlayerOnClientAnimator.GetBool(triggerHash) : m_PlayerOnClientAnimator.GetBool(triggerString));
Assert.False(s_GlobalTimeoutHelper.TimedOut, "Timed out on client trigger set check");
// reset the trigger
if (asHash)
{
m_PlayerOnServer.GetComponent<NetworkAnimator>().ResetTrigger(triggerHash);
}
else
{
m_PlayerOnServer.GetComponent<NetworkAnimator>().ResetTrigger(triggerString);
}
// verify trigger is reset for client and server
yield return WaitForConditionOrTimeOut(() => asHash ? m_PlayerOnServerAnimator.GetBool(triggerHash) == false : m_PlayerOnServerAnimator.GetBool(triggerString) == false);
Assert.False(s_GlobalTimeoutHelper.TimedOut, "Timed out on server reset check");
yield return WaitForConditionOrTimeOut(() => asHash ? m_PlayerOnClientAnimator.GetBool(triggerHash) == false : m_PlayerOnClientAnimator.GetBool(triggerString) == false);
Assert.False(s_GlobalTimeoutHelper.TimedOut, "Timed out on client reset check");
}
[UnityTest]
public IEnumerator AnimationStateSyncTest()
{
// check that we have started in the default state
Assert.True(m_PlayerOnServerAnimator.GetCurrentAnimatorStateInfo(0).IsName("DefaultState"));
Assert.True(m_PlayerOnClientAnimator.GetCurrentAnimatorStateInfo(0).IsName("DefaultState"));
// cause a change to the AlphaState state by setting AlphaParameter, which is
// the variable bound to the transition from default to AlphaState (see the TestAnimatorController asset)
m_PlayerOnServerAnimator.SetBool("AlphaParameter", true);
// ...and now we should be in the AlphaState having triggered the AlphaParameter
yield return WaitForConditionOrTimeOut(() => m_PlayerOnServerAnimator.GetCurrentAnimatorStateInfo(0).IsName("AlphaState"));
Assert.False(s_GlobalTimeoutHelper.TimedOut, "Server failed to reach its animation state");
// ...and now the client should also have sync'd and arrived at the correct state
yield return WaitForConditionOrTimeOut(() => m_PlayerOnClientAnimator.GetCurrentAnimatorStateInfo(0).IsName("AlphaState"));
Assert.False(s_GlobalTimeoutHelper.TimedOut, "Client failed to sync its animation state from the server");
}
[UnityTest]
public IEnumerator AnimationLayerStateSyncTest()
{
int layer = 1;
// check that we have started in the default state
Assert.True(m_PlayerOnServerAnimator.GetCurrentAnimatorStateInfo(layer).IsName("DefaultStateLayer2"));
Assert.True(m_PlayerOnClientAnimator.GetCurrentAnimatorStateInfo(layer).IsName("DefaultStateLayer2"));
// cause a change to the AlphaState state by setting AlphaParameter, which is
// the variable bound to the transition from default to AlphaState (see the TestAnimatorController asset)
m_PlayerOnServerAnimator.SetBool("Layer2AlphaParameter", true);
// ...and now we should be in the AlphaState having triggered the AlphaParameter
yield return WaitForConditionOrTimeOut(() => m_PlayerOnServerAnimator.GetCurrentAnimatorStateInfo(layer).IsName("Layer2AlphaState"));
Assert.False(s_GlobalTimeoutHelper.TimedOut, "Server failed to reach its animation state");
// ...and now the client should also have sync'd and arrived at the correct state
yield return WaitForConditionOrTimeOut(() => m_PlayerOnClientAnimator.GetCurrentAnimatorStateInfo(layer).IsName("Layer2AlphaState"));
Assert.False(s_GlobalTimeoutHelper.TimedOut, "Client failed to sync its animation state from the server");
}
[UnityTest]
public IEnumerator AnimationLayerWeightTest()
{
int layer = 1;
float targetWeight = 0.333f;
// check that we have started in the default state
Assert.True(Mathf.Approximately(m_PlayerOnServerAnimator.GetLayerWeight(layer), 1f));
Assert.True(Mathf.Approximately(m_PlayerOnClientAnimator.GetLayerWeight(layer), 1f));
m_PlayerOnServerAnimator.SetLayerWeight(layer, targetWeight);
// ...and now we should be in the AlphaState having triggered the AlphaParameter
yield return WaitForConditionOrTimeOut(() =>
Mathf.Approximately(m_PlayerOnServerAnimator.GetLayerWeight(layer), targetWeight)
);
Assert.False(s_GlobalTimeoutHelper.TimedOut, "Server failed to reach its animation state");
// ...and now the client should also have sync'd and arrived at the correct state
yield return WaitForConditionOrTimeOut(() =>
Mathf.Approximately(m_PlayerOnClientAnimator.GetLayerWeight(layer), targetWeight)
);
Assert.False(s_GlobalTimeoutHelper.TimedOut, "Server failed to reach its animation state");
}
[UnityTest]
public IEnumerator AnimationStateSyncTriggerTest([Values(true, false)] bool asHash)
{
string triggerString = "TestTrigger";
int triggerHash = Animator.StringToHash(triggerString);
// check that we have started in the default state
Assert.True(m_PlayerOnServerAnimator.GetCurrentAnimatorStateInfo(0).IsName("DefaultState"));
Assert.True(m_PlayerOnClientAnimator.GetCurrentAnimatorStateInfo(0).IsName("DefaultState"));
// cause a change to the AlphaState state by setting TestTrigger
// note, we have a special test for triggers because activating triggers via the
// NetworkAnimator is special; for other parameters you set them on the Animator and NetworkAnimator
// listens. But because triggers are super short and transitory, we require users to call
// NetworkAnimator.SetTrigger so we don't miss it
if (asHash)
{
m_PlayerOnServer.GetComponent<NetworkAnimator>().SetTrigger(triggerHash);
}
else
{
m_PlayerOnServer.GetComponent<NetworkAnimator>().SetTrigger(triggerString);
}
// ...and now we should be in the AlphaState having triggered the AlphaParameter
yield return WaitForConditionOrTimeOut(() => m_PlayerOnServerAnimator.GetCurrentAnimatorStateInfo(0).IsName("TriggeredState"));
Assert.False(s_GlobalTimeoutHelper.TimedOut, "Server failed to reach its animation state via trigger");
// ...and now the client should also have sync'd and arrived at the correct state
yield return WaitForConditionOrTimeOut(() => m_PlayerOnClientAnimator.GetCurrentAnimatorStateInfo(0).IsName("TriggeredState"));
Assert.False(s_GlobalTimeoutHelper.TimedOut, "Client failed to sync its animation state from the server via trigger");
}
[UnityTest]
public IEnumerator AnimationStateSyncTestWithOverride()
{
// set up the animation override controller
var overrideController = Resources.Load("TestAnimatorOverrideController") as AnimatorOverrideController;
m_PlayerOnServer.GetComponent<Animator>().runtimeAnimatorController = overrideController;
m_PlayerOnClient.GetComponent<Animator>().runtimeAnimatorController = overrideController;
// in our default state, we should see the OverrideDefaultAnimation clip
Assert.True(HasClip(m_PlayerOnServerAnimator, "OverrideDefaultAnimation"));
Assert.True(HasClip(m_PlayerOnClientAnimator, "OverrideDefaultAnimation"));
// cause a change to the AlphaState state by setting AlphaParameter, which is
// the variable bound to the transition from default to AlphaState (see the TestAnimatorController asset)
m_PlayerOnServerAnimator.SetBool("AlphaParameter", true);
// ...and now we should be in the AlphaState having set the AlphaParameter
yield return WaitForConditionOrTimeOut(() => HasClip(m_PlayerOnServerAnimator, "OverrideAlphaAnimation"));
Assert.False(s_GlobalTimeoutHelper.TimedOut, "Server failed to reach its overriden animation state");
// ...and now the client should also have sync'd and arrived at the correct state
yield return WaitForConditionOrTimeOut(() => HasClip(m_PlayerOnServerAnimator, "OverrideAlphaAnimation"));
Assert.False(s_GlobalTimeoutHelper.TimedOut, "Client failed to reach its overriden animation state");
}
}
}

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: c726f5bc421c3874d9c1a26bcac3f091
guid: c2e5a740c1abd4315801e3f26ecf8adb
MonoImporter:
externalObjects: {}
serializedVersion: 2

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 4e60372130aba464f9f9ae4a24bb9fe0
guid: c3a8707ef624947a7ae8843ca6c70c0a
folderAsset: yes
DefaultImporter:
externalObjects: {}

View File

@@ -0,0 +1,53 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!74 &7400000
AnimationClip:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_Name: AlphaAnimation
serializedVersion: 6
m_Legacy: 0
m_Compressed: 0
m_UseHighQualityCurve: 1
m_RotationCurves: []
m_CompressedRotationCurves: []
m_EulerCurves: []
m_PositionCurves: []
m_ScaleCurves: []
m_FloatCurves: []
m_PPtrCurves: []
m_SampleRate: 60
m_WrapMode: 0
m_Bounds:
m_Center: {x: 0, y: 0, z: 0}
m_Extent: {x: 0, y: 0, z: 0}
m_ClipBindingConstant:
genericBindings: []
pptrCurveMapping: []
m_AnimationClipSettings:
serializedVersion: 2
m_AdditiveReferencePoseClip: {fileID: 0}
m_AdditiveReferencePoseTime: 0
m_StartTime: 0
m_StopTime: 1
m_OrientationOffsetY: 0
m_Level: 0
m_CycleOffset: 0
m_HasAdditiveReferencePose: 0
m_LoopTime: 0
m_LoopBlend: 0
m_LoopBlendOrientation: 0
m_LoopBlendPositionY: 0
m_LoopBlendPositionXZ: 0
m_KeepOriginalOrientation: 0
m_KeepOriginalPositionY: 1
m_KeepOriginalPositionXZ: 0
m_HeightFromFeet: 0
m_Mirror: 0
m_EditorCurves: []
m_EulerEditorCurves: []
m_HasGenericRootTransform: 0
m_HasMotionFloatCurves: 0
m_Events: []

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: db8faf64ca46248abb6624513ac1fb1b
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 7400000
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,53 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!74 &7400000
AnimationClip:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_Name: DefaultAnimation
serializedVersion: 6
m_Legacy: 0
m_Compressed: 0
m_UseHighQualityCurve: 1
m_RotationCurves: []
m_CompressedRotationCurves: []
m_EulerCurves: []
m_PositionCurves: []
m_ScaleCurves: []
m_FloatCurves: []
m_PPtrCurves: []
m_SampleRate: 60
m_WrapMode: 0
m_Bounds:
m_Center: {x: 0, y: 0, z: 0}
m_Extent: {x: 0, y: 0, z: 0}
m_ClipBindingConstant:
genericBindings: []
pptrCurveMapping: []
m_AnimationClipSettings:
serializedVersion: 2
m_AdditiveReferencePoseClip: {fileID: 0}
m_AdditiveReferencePoseTime: 0
m_StartTime: 0
m_StopTime: 1
m_OrientationOffsetY: 0
m_Level: 0
m_CycleOffset: 0
m_HasAdditiveReferencePose: 0
m_LoopTime: 0
m_LoopBlend: 0
m_LoopBlendOrientation: 0
m_LoopBlendPositionY: 0
m_LoopBlendPositionXZ: 0
m_KeepOriginalOrientation: 0
m_KeepOriginalPositionY: 1
m_KeepOriginalPositionXZ: 0
m_HeightFromFeet: 0
m_Mirror: 0
m_EditorCurves: []
m_EulerEditorCurves: []
m_HasGenericRootTransform: 0
m_HasMotionFloatCurves: 0
m_Events: []

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 1f6191147839943ab93e2171cc15c5e9
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 7400000
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,53 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!74 &7400000
AnimationClip:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_Name: Layer2Animation
serializedVersion: 6
m_Legacy: 0
m_Compressed: 0
m_UseHighQualityCurve: 1
m_RotationCurves: []
m_CompressedRotationCurves: []
m_EulerCurves: []
m_PositionCurves: []
m_ScaleCurves: []
m_FloatCurves: []
m_PPtrCurves: []
m_SampleRate: 60
m_WrapMode: 0
m_Bounds:
m_Center: {x: 0, y: 0, z: 0}
m_Extent: {x: 0, y: 0, z: 0}
m_ClipBindingConstant:
genericBindings: []
pptrCurveMapping: []
m_AnimationClipSettings:
serializedVersion: 2
m_AdditiveReferencePoseClip: {fileID: 0}
m_AdditiveReferencePoseTime: 0
m_StartTime: 0
m_StopTime: 1
m_OrientationOffsetY: 0
m_Level: 0
m_CycleOffset: 0
m_HasAdditiveReferencePose: 0
m_LoopTime: 0
m_LoopBlend: 0
m_LoopBlendOrientation: 0
m_LoopBlendPositionY: 0
m_LoopBlendPositionXZ: 0
m_KeepOriginalOrientation: 0
m_KeepOriginalPositionY: 1
m_KeepOriginalPositionXZ: 0
m_HeightFromFeet: 0
m_Mirror: 0
m_EditorCurves: []
m_EulerEditorCurves: []
m_HasGenericRootTransform: 0
m_HasMotionFloatCurves: 0
m_Events: []

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: d31c84f6372c54d7eb8decb27010d005
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 7400000
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,53 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!74 &7400000
AnimationClip:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_Name: OverrideAlphaAnimation
serializedVersion: 6
m_Legacy: 0
m_Compressed: 0
m_UseHighQualityCurve: 1
m_RotationCurves: []
m_CompressedRotationCurves: []
m_EulerCurves: []
m_PositionCurves: []
m_ScaleCurves: []
m_FloatCurves: []
m_PPtrCurves: []
m_SampleRate: 60
m_WrapMode: 0
m_Bounds:
m_Center: {x: 0, y: 0, z: 0}
m_Extent: {x: 0, y: 0, z: 0}
m_ClipBindingConstant:
genericBindings: []
pptrCurveMapping: []
m_AnimationClipSettings:
serializedVersion: 2
m_AdditiveReferencePoseClip: {fileID: 0}
m_AdditiveReferencePoseTime: 0
m_StartTime: 0
m_StopTime: 1
m_OrientationOffsetY: 0
m_Level: 0
m_CycleOffset: 0
m_HasAdditiveReferencePose: 0
m_LoopTime: 0
m_LoopBlend: 0
m_LoopBlendOrientation: 0
m_LoopBlendPositionY: 0
m_LoopBlendPositionXZ: 0
m_KeepOriginalOrientation: 0
m_KeepOriginalPositionY: 1
m_KeepOriginalPositionXZ: 0
m_HeightFromFeet: 0
m_Mirror: 0
m_EditorCurves: []
m_EulerEditorCurves: []
m_HasGenericRootTransform: 0
m_HasMotionFloatCurves: 0
m_Events: []

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 05a2afc2ff8884d32afc64ed6765880a
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 7400000
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,53 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!74 &7400000
AnimationClip:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_Name: OverrideDefaultAnimation
serializedVersion: 6
m_Legacy: 0
m_Compressed: 0
m_UseHighQualityCurve: 1
m_RotationCurves: []
m_CompressedRotationCurves: []
m_EulerCurves: []
m_PositionCurves: []
m_ScaleCurves: []
m_FloatCurves: []
m_PPtrCurves: []
m_SampleRate: 60
m_WrapMode: 0
m_Bounds:
m_Center: {x: 0, y: 0, z: 0}
m_Extent: {x: 0, y: 0, z: 0}
m_ClipBindingConstant:
genericBindings: []
pptrCurveMapping: []
m_AnimationClipSettings:
serializedVersion: 2
m_AdditiveReferencePoseClip: {fileID: 0}
m_AdditiveReferencePoseTime: 0
m_StartTime: 0
m_StopTime: 1
m_OrientationOffsetY: 0
m_Level: 0
m_CycleOffset: 0
m_HasAdditiveReferencePose: 0
m_LoopTime: 0
m_LoopBlend: 0
m_LoopBlendOrientation: 0
m_LoopBlendPositionY: 0
m_LoopBlendPositionXZ: 0
m_KeepOriginalOrientation: 0
m_KeepOriginalPositionY: 1
m_KeepOriginalPositionXZ: 0
m_HeightFromFeet: 0
m_Mirror: 0
m_EditorCurves: []
m_EulerEditorCurves: []
m_HasGenericRootTransform: 0
m_HasMotionFloatCurves: 0
m_Events: []

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: cf503a5569d0b4df4910a26d09ce4530
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 7400000
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,449 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!1102 &-8144973961595650150
AnimatorState:
serializedVersion: 6
m_ObjectHideFlags: 1
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_Name: New State
m_Speed: 1
m_CycleOffset: 0
m_Transitions: []
m_StateMachineBehaviours: []
m_Position: {x: 50, y: 50, z: 0}
m_IKOnFeet: 0
m_WriteDefaultValues: 1
m_Mirror: 0
m_SpeedParameterActive: 0
m_MirrorParameterActive: 0
m_CycleOffsetParameterActive: 0
m_TimeParameterActive: 0
m_Motion: {fileID: 0}
m_Tag:
m_SpeedParameter:
m_MirrorParameter:
m_CycleOffsetParameter:
m_TimeParameter:
--- !u!1102 &-7257898091357968356
AnimatorState:
serializedVersion: 6
m_ObjectHideFlags: 1
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_Name: New State
m_Speed: 1
m_CycleOffset: 0
m_Transitions: []
m_StateMachineBehaviours: []
m_Position: {x: 50, y: 50, z: 0}
m_IKOnFeet: 0
m_WriteDefaultValues: 1
m_Mirror: 0
m_SpeedParameterActive: 0
m_MirrorParameterActive: 0
m_CycleOffsetParameterActive: 0
m_TimeParameterActive: 0
m_Motion: {fileID: 0}
m_Tag:
m_SpeedParameter:
m_MirrorParameter:
m_CycleOffsetParameter:
m_TimeParameter:
--- !u!1101 &-7235917949335567458
AnimatorStateTransition:
m_ObjectHideFlags: 1
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_Name:
m_Conditions:
- m_ConditionMode: 2
m_ConditionEvent: Layer2AlphaParameter
m_EventTreshold: 0
m_DstStateMachine: {fileID: 0}
m_DstState: {fileID: 6016706997111698284}
m_Solo: 0
m_Mute: 0
m_IsExit: 0
serializedVersion: 3
m_TransitionDuration: 0.25
m_TransitionOffset: 0
m_ExitTime: 0.75
m_HasExitTime: 1
m_HasFixedDuration: 1
m_InterruptionSource: 2
m_OrderedInterruption: 1
m_CanTransitionToSelf: 1
--- !u!1101 &-6097014330458455406
AnimatorStateTransition:
m_ObjectHideFlags: 1
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_Name:
m_Conditions:
- m_ConditionMode: 2
m_ConditionEvent: AlphaParameter
m_EventTreshold: 0
m_DstStateMachine: {fileID: 0}
m_DstState: {fileID: -1198466922477486815}
m_Solo: 0
m_Mute: 0
m_IsExit: 0
serializedVersion: 3
m_TransitionDuration: 0.25
m_TransitionOffset: 0
m_ExitTime: 0.75
m_HasExitTime: 1
m_HasFixedDuration: 1
m_InterruptionSource: 0
m_OrderedInterruption: 1
m_CanTransitionToSelf: 1
--- !u!1107 &-1914299053840757887
AnimatorStateMachine:
serializedVersion: 6
m_ObjectHideFlags: 1
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_Name: Base Layer
m_ChildStates:
- serializedVersion: 1
m_State: {fileID: -1198466922477486815}
m_Position: {x: 70, y: 290, z: 0}
- serializedVersion: 1
m_State: {fileID: 320527679719022362}
m_Position: {x: 110, y: 490, z: 0}
- serializedVersion: 1
m_State: {fileID: 3942933370568001311}
m_Position: {x: 380, y: 280, z: 0}
m_ChildStateMachines: []
m_AnyStateTransitions: []
m_EntryTransitions: []
m_StateMachineTransitions: {}
m_StateMachineBehaviours: []
m_AnyStatePosition: {x: 50, y: 20, z: 0}
m_EntryPosition: {x: 30, y: 180, z: 0}
m_ExitPosition: {x: 800, y: 120, z: 0}
m_ParentStateMachinePosition: {x: 800, y: 20, z: 0}
m_DefaultState: {fileID: -1198466922477486815}
--- !u!1102 &-1198466922477486815
AnimatorState:
serializedVersion: 6
m_ObjectHideFlags: 1
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_Name: DefaultState
m_Speed: 1
m_CycleOffset: 0
m_Transitions:
- {fileID: 232953446134799302}
- {fileID: 8340347106517238820}
m_StateMachineBehaviours: []
m_Position: {x: 50, y: 50, z: 0}
m_IKOnFeet: 0
m_WriteDefaultValues: 1
m_Mirror: 0
m_SpeedParameterActive: 0
m_MirrorParameterActive: 0
m_CycleOffsetParameterActive: 0
m_TimeParameterActive: 0
m_Motion: {fileID: 7400000, guid: 1f6191147839943ab93e2171cc15c5e9, type: 2}
m_Tag:
m_SpeedParameter:
m_MirrorParameter:
m_CycleOffsetParameter:
m_TimeParameter:
--- !u!91 &9100000
AnimatorController:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_Name: TestAnimatorController
serializedVersion: 5
m_AnimatorParameters:
- m_Name: AlphaParameter
m_Type: 4
m_DefaultFloat: 0
m_DefaultInt: 0
m_DefaultBool: 0
m_Controller: {fileID: 9100000}
- m_Name: TestTrigger
m_Type: 9
m_DefaultFloat: 0
m_DefaultInt: 0
m_DefaultBool: 0
m_Controller: {fileID: 9100000}
- m_Name: UnboundTrigger
m_Type: 9
m_DefaultFloat: 0
m_DefaultInt: 0
m_DefaultBool: 0
m_Controller: {fileID: 9100000}
- m_Name: Layer2AlphaParameter
m_Type: 4
m_DefaultFloat: 0
m_DefaultInt: 0
m_DefaultBool: 0
m_Controller: {fileID: 9100000}
m_AnimatorLayers:
- serializedVersion: 5
m_Name: Base Layer
m_StateMachine: {fileID: -1914299053840757887}
m_Mask: {fileID: 0}
m_Motions: []
m_Behaviours: []
m_BlendingMode: 0
m_SyncedLayerIndex: -1
m_DefaultWeight: 0
m_IKPass: 0
m_SyncedLayerAffectsTiming: 0
m_Controller: {fileID: 9100000}
- serializedVersion: 5
m_Name: Layer2
m_StateMachine: {fileID: 1433017894673297828}
m_Mask: {fileID: 0}
m_Motions: []
m_Behaviours: []
m_BlendingMode: 0
m_SyncedLayerIndex: -1
m_DefaultWeight: 1
m_IKPass: 0
m_SyncedLayerAffectsTiming: 0
m_Controller: {fileID: 9100000}
--- !u!1101 &232953446134799302
AnimatorStateTransition:
m_ObjectHideFlags: 1
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_Name:
m_Conditions:
- m_ConditionMode: 1
m_ConditionEvent: AlphaParameter
m_EventTreshold: 0
m_DstStateMachine: {fileID: 0}
m_DstState: {fileID: 320527679719022362}
m_Solo: 0
m_Mute: 0
m_IsExit: 0
serializedVersion: 3
m_TransitionDuration: 0.25
m_TransitionOffset: 0
m_ExitTime: 0.75
m_HasExitTime: 1
m_HasFixedDuration: 1
m_InterruptionSource: 0
m_OrderedInterruption: 1
m_CanTransitionToSelf: 1
--- !u!1102 &320527679719022362
AnimatorState:
serializedVersion: 6
m_ObjectHideFlags: 1
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_Name: AlphaState
m_Speed: 1
m_CycleOffset: 0
m_Transitions: []
m_StateMachineBehaviours: []
m_Position: {x: 50, y: 50, z: 0}
m_IKOnFeet: 0
m_WriteDefaultValues: 1
m_Mirror: 0
m_SpeedParameterActive: 0
m_MirrorParameterActive: 0
m_CycleOffsetParameterActive: 0
m_TimeParameterActive: 0
m_Motion: {fileID: 7400000, guid: db8faf64ca46248abb6624513ac1fb1b, type: 2}
m_Tag:
m_SpeedParameter:
m_MirrorParameter:
m_CycleOffsetParameter:
m_TimeParameter:
--- !u!1102 &927597079590233140
AnimatorState:
serializedVersion: 6
m_ObjectHideFlags: 1
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_Name: Layer2AlphaState
m_Speed: 1
m_CycleOffset: 0
m_Transitions:
- {fileID: -7235917949335567458}
m_StateMachineBehaviours: []
m_Position: {x: 50, y: 50, z: 0}
m_IKOnFeet: 0
m_WriteDefaultValues: 1
m_Mirror: 0
m_SpeedParameterActive: 0
m_MirrorParameterActive: 0
m_CycleOffsetParameterActive: 0
m_TimeParameterActive: 0
m_Motion: {fileID: 7400000, guid: d31c84f6372c54d7eb8decb27010d005, type: 2}
m_Tag:
m_SpeedParameter:
m_MirrorParameter:
m_CycleOffsetParameter:
m_TimeParameter:
--- !u!1107 &1433017894673297828
AnimatorStateMachine:
serializedVersion: 6
m_ObjectHideFlags: 1
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_Name: Layer2
m_ChildStates:
- serializedVersion: 1
m_State: {fileID: 6016706997111698284}
m_Position: {x: 160, y: 250, z: 0}
- serializedVersion: 1
m_State: {fileID: 927597079590233140}
m_Position: {x: 270, y: 370, z: 0}
m_ChildStateMachines: []
m_AnyStateTransitions: []
m_EntryTransitions: []
m_StateMachineTransitions: {}
m_StateMachineBehaviours: []
m_AnyStatePosition: {x: 50, y: 20, z: 0}
m_EntryPosition: {x: 50, y: 120, z: 0}
m_ExitPosition: {x: 800, y: 120, z: 0}
m_ParentStateMachinePosition: {x: 800, y: 20, z: 0}
m_DefaultState: {fileID: 6016706997111698284}
--- !u!1102 &3942933370568001311
AnimatorState:
serializedVersion: 6
m_ObjectHideFlags: 1
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_Name: TriggeredState
m_Speed: 1
m_CycleOffset: 0
m_Transitions: []
m_StateMachineBehaviours: []
m_Position: {x: 50, y: 50, z: 0}
m_IKOnFeet: 0
m_WriteDefaultValues: 1
m_Mirror: 0
m_SpeedParameterActive: 0
m_MirrorParameterActive: 0
m_CycleOffsetParameterActive: 0
m_TimeParameterActive: 0
m_Motion: {fileID: 7400000, guid: db8faf64ca46248abb6624513ac1fb1b, type: 2}
m_Tag:
m_SpeedParameter:
m_MirrorParameter:
m_CycleOffsetParameter:
m_TimeParameter:
--- !u!1101 &5326371122012901575
AnimatorStateTransition:
m_ObjectHideFlags: 1
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_Name:
m_Conditions:
- m_ConditionMode: 2
m_ConditionEvent: AlphaParameter
m_EventTreshold: 0
m_DstStateMachine: {fileID: 0}
m_DstState: {fileID: -1198466922477486815}
m_Solo: 0
m_Mute: 0
m_IsExit: 0
serializedVersion: 3
m_TransitionDuration: 0.25
m_TransitionOffset: 0
m_ExitTime: 0.75
m_HasExitTime: 1
m_HasFixedDuration: 1
m_InterruptionSource: 0
m_OrderedInterruption: 1
m_CanTransitionToSelf: 1
--- !u!1102 &6016706997111698284
AnimatorState:
serializedVersion: 6
m_ObjectHideFlags: 1
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_Name: DefaultStateLayer2
m_Speed: 1
m_CycleOffset: 0
m_Transitions:
- {fileID: 6324505406226331058}
m_StateMachineBehaviours: []
m_Position: {x: 50, y: 50, z: 0}
m_IKOnFeet: 0
m_WriteDefaultValues: 1
m_Mirror: 0
m_SpeedParameterActive: 0
m_MirrorParameterActive: 0
m_CycleOffsetParameterActive: 0
m_TimeParameterActive: 0
m_Motion: {fileID: 0}
m_Tag:
m_SpeedParameter:
m_MirrorParameter:
m_CycleOffsetParameter:
m_TimeParameter:
--- !u!1101 &6324505406226331058
AnimatorStateTransition:
m_ObjectHideFlags: 1
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_Name:
m_Conditions:
- m_ConditionMode: 1
m_ConditionEvent: Layer2AlphaParameter
m_EventTreshold: 0
m_DstStateMachine: {fileID: 0}
m_DstState: {fileID: 927597079590233140}
m_Solo: 0
m_Mute: 0
m_IsExit: 0
serializedVersion: 3
m_TransitionDuration: 0.25
m_TransitionOffset: 0
m_ExitTime: 0.75
m_HasExitTime: 1
m_HasFixedDuration: 1
m_InterruptionSource: 2
m_OrderedInterruption: 1
m_CanTransitionToSelf: 1
--- !u!1101 &8340347106517238820
AnimatorStateTransition:
m_ObjectHideFlags: 1
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_Name:
m_Conditions:
- m_ConditionMode: 1
m_ConditionEvent: TestTrigger
m_EventTreshold: 0
m_DstStateMachine: {fileID: 0}
m_DstState: {fileID: 3942933370568001311}
m_Solo: 0
m_Mute: 0
m_IsExit: 0
serializedVersion: 3
m_TransitionDuration: 0.25
m_TransitionOffset: 0
m_ExitTime: 0.75
m_HasExitTime: 1
m_HasFixedDuration: 1
m_InterruptionSource: 0
m_OrderedInterruption: 1
m_CanTransitionToSelf: 1

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: a0b8ebecb362240989d16159bdfa067c
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 9100000
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,15 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!221 &22100000
AnimatorOverrideController:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_Name: TestAnimatorOverrideController
m_Controller: {fileID: 9100000, guid: a0b8ebecb362240989d16159bdfa067c, type: 2}
m_Clips:
- m_OriginalClip: {fileID: 7400000, guid: 1f6191147839943ab93e2171cc15c5e9, type: 2}
m_OverrideClip: {fileID: 7400000, guid: cf503a5569d0b4df4910a26d09ce4530, type: 2}
- m_OriginalClip: {fileID: 7400000, guid: db8faf64ca46248abb6624513ac1fb1b, type: 2}
m_OverrideClip: {fileID: 7400000, guid: 05a2afc2ff8884d32afc64ed6765880a, type: 2}

View File

@@ -0,0 +1,61 @@
using System.Collections;
using UnityEngine;
using UnityEngine.TestTools;
using Unity.Netcode.TestHelpers.Runtime;
namespace Unity.Netcode.RuntimeTests
{
/// <summary>
/// This class is for testing general fixes or functionality of NetworkBehaviours
/// </summary>
public class NetworkBehaviourGenericTests : NetcodeIntegrationTest
{
protected override int NumberOfClients => 0;
private bool m_AllowServerToStart;
protected override bool CanStartServerAndClients()
{
return m_AllowServerToStart;
}
public class SimpleNetworkBehaviour : NetworkBehaviour
{
}
/// <summary>
/// This test validates a fix to NetworkBehaviour.NetworkObject when
/// the NetworkManager.LogLevel is set to Developer
/// Note: This test does not require any clients, but should not impact this
/// particular test if new tests are added to this class that do require clients
/// </summary>
[UnityTest]
public IEnumerator ValidateNoSpam()
{
m_AllowServerToStart = true;
var objectToTest = new GameObject();
var simpleNetworkBehaviour = objectToTest.AddComponent<SimpleNetworkBehaviour>();
// Now just start the Host
yield return StartServerAndClients();
// set the log level to developer
m_ServerNetworkManager.LogLevel = LogLevel.Developer;
// Verify the warning gets logged under normal conditions
var isNull = simpleNetworkBehaviour.NetworkObject == null;
LogAssert.Expect(LogType.Warning, $"[Netcode] Could not get {nameof(NetworkObject)} for the {nameof(NetworkBehaviour)}. Are you missing a {nameof(NetworkObject)} component?");
var networkObjectToTest = objectToTest.AddComponent<NetworkObject>();
networkObjectToTest.NetworkManagerOwner = m_ServerNetworkManager;
networkObjectToTest.Spawn();
// Assure no log messages are logged when they should not be logged
isNull = simpleNetworkBehaviour.NetworkObject != null;
LogAssert.NoUnexpectedReceived();
networkObjectToTest.Despawn();
Object.Destroy(networkObjectToTest);
}
}
}

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 124489f89ef59d449ab4bed1f5ef2f59
guid: f87989d8d290ed24a9048b6dbddae527
MonoImporter:
externalObjects: {}
serializedVersion: 2

View File

@@ -1,180 +1,344 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;
using UnityEngine;
using UnityEngine.TestTools;
using Unity.Netcode.TestHelpers.Runtime;
using Object = UnityEngine.Object;
namespace Unity.Netcode.RuntimeTests
{
public class NetworkBehaviourUpdaterTests : BaseMultiInstanceTest
/// <summary>
/// This is a refactor of the original test's NetworkBehaviour INetVarInfo derived NetworkBehaviours
/// </summary>
public class NetVarContainer : NetworkBehaviour
{
protected override int NbClients => throw new NotSupportedException("handled per test");
private static Type[] s_TypesToTest = new[] { null, typeof(ZeroNetVar), typeof(OneNetVar), typeof(TwoNetVar) };
[UnitySetUp]
public override IEnumerator Setup()
/// <summary>
/// Creates a prefab with two instances of this NetworkBehaviour
/// </summary>
/// <returns></returns>
public static GameObject CreatePrefabGameObject(NetVarCombinationTypes netVarsToCheck)
{
yield break;
var gameObject = new GameObject
{
// Always a good idea to name the Prefab for easy identification purposes
name = "NetVarContainerObject"
};
var networkObject = gameObject.AddComponent<NetworkObject>();
// Create the two instances of the NetVarContainer components and add them to the
// GameObject of this prefab
var netVarContainer = gameObject.AddComponent<NetVarContainer>();
netVarContainer.NumberOfNetVarsToCheck = netVarsToCheck.FirstType;
netVarContainer.ValueToSetNetVarTo = NetworkBehaviourUpdaterTests.NetVarValueToSet;
netVarContainer = gameObject.AddComponent<NetVarContainer>();
netVarContainer.NumberOfNetVarsToCheck = netVarsToCheck.SecondType;
netVarContainer.ValueToSetNetVarTo = NetworkBehaviourUpdaterTests.NetVarValueToSet;
NetcodeIntegrationTestHelpers.MakeNetworkObjectTestPrefab(networkObject);
return gameObject;
}
public enum NetVarsToCheck
{
One,
Two
}
public NetVarsToCheck NumberOfNetVarsToCheck;
public int ValueToSetNetVarTo = 0;
/// <summary>
/// Only used on the client-side for this test, this
/// is used to see if the network variables have changed.
/// </summary>
public bool HaveAllValuesChanged(int valueToCheck)
{
var allValuesChanged = false;
switch (NumberOfNetVarsToCheck)
{
case NetVarsToCheck.Two:
{
allValuesChanged = m_FirstValue.Value == valueToCheck && m_SeconValue.Value == valueToCheck;
break;
}
case NetVarsToCheck.One:
{
allValuesChanged = m_FirstValue.Value == valueToCheck;
break;
}
}
return allValuesChanged;
}
/// <summary>
/// This runs test combinations for the following
/// test with 0, 1, 2 clients
/// test with host and server mode
/// test with 0, 1, 2 spawned objects
/// test with 0, 1, 2 network behaviour per prefab
/// test with 0, 1, 2 network variable per network behaviour
/// for each, update netvar
/// for each check value changed
/// check that all network variables are no longer dirty after update
/// Only used on the server side to check the isDirty flag for the
/// NetworkVariables being used for each test iteration
/// </summary>
/// <param name="nbClients"></param>
/// <param name="useHost"></param>
/// <param name="nbSpawnedObjects"></param>
/// <param name="firstNetworkBehaviour"></param>
/// <param name="secondNetworkBehaviour"></param>
/// <param name="thirdNetworkBehaviour"></param>
/// <returns></returns>
[UnityTest]
public IEnumerator BehaviourUpdaterAllTests([Values(0, 1, 2)] int nbClients, [Values] bool useHost, [Values(0, 1, 2)] int nbSpawnedObjects,
[ValueSource(nameof(s_TypesToTest))] Type firstNetworkBehaviour, [ValueSource(nameof(s_TypesToTest))] Type secondNetworkBehaviour)
public bool AreNetVarsDirty()
{
// Create multiple NetworkManager instances
if (!MultiInstanceHelpers.Create(nbClients, out NetworkManager server, out NetworkManager[] clients))
var areDirty = false;
switch (NumberOfNetVarsToCheck)
{
Debug.LogError("Failed to create instances");
Assert.Fail("Failed to create instances");
}
m_ClientNetworkManagers = clients;
m_ServerNetworkManager = server;
Assert.That(m_ClientNetworkManagers.Length, Is.EqualTo(nbClients));
Assert.That(m_ServerNetworkManager, Is.Not.Null);
// setup prefab to spawn
void AddNetworkBehaviour(Type type, GameObject prefab)
{
if (type != null)
{
var info = prefab.AddComponent(type) as INetVarInfo;
}
}
var prefabToSpawn = new GameObject();
var networkObjectPrefab = prefabToSpawn.AddComponent<NetworkObject>();
AddNetworkBehaviour(firstNetworkBehaviour, prefabToSpawn);
AddNetworkBehaviour(secondNetworkBehaviour, prefabToSpawn);
MultiInstanceHelpers.MakeNetworkObjectTestPrefab(networkObjectPrefab);
m_ServerNetworkManager.NetworkConfig.NetworkPrefabs.Add(new NetworkPrefab() { Prefab = prefabToSpawn });
foreach (var clientNetworkManager in m_ClientNetworkManagers)
{
clientNetworkManager.NetworkConfig.NetworkPrefabs.Add(new NetworkPrefab() { Prefab = prefabToSpawn });
}
// Start the instances
if (!MultiInstanceHelpers.Start(useHost, server, clients))
{
Debug.LogError("Failed to start instances");
Assert.Fail("Failed to start instances");
}
// Wait for connection on client side
yield return MultiInstanceHelpers.Run(MultiInstanceHelpers.WaitForClientsConnected(clients));
// Wait for connection on server side
yield return MultiInstanceHelpers.Run(MultiInstanceHelpers.WaitForClientsConnectedToServer(server, clientCount: useHost ? nbClients + 1 : nbClients));
// gathering netvars to test on
var serverNetVarsToUpdate = new List<NetworkVariable<int>>();
for (int i = 0; i < nbSpawnedObjects; i++)
{
var spawnedObject = Object.Instantiate(prefabToSpawn);
var networkSpawnedObject = spawnedObject.GetComponent<NetworkObject>();
networkSpawnedObject.NetworkManagerOwner = m_ServerNetworkManager;
networkSpawnedObject.Spawn();
int nbBehaviours = 0;
foreach (var networkBehaviour in spawnedObject.GetComponents<NetworkBehaviour>())
{
serverNetVarsToUpdate.AddRange(((INetVarInfo)networkBehaviour).AllNetVars);
nbBehaviours++;
}
Assert.That(nbBehaviours, Is.EqualTo((firstNetworkBehaviour == null ? 0 : 1) + (secondNetworkBehaviour == null ? 0 : 1)));
}
var serverNetVarCount = serverNetVarsToUpdate.Count;
yield return new WaitForSeconds(0); // wait a frame to make sure spawn is done
// todo: with Snapshot spawns enabled and the current race condition, the following line is needed:
// yield return new WaitForSeconds(0.2f); // wait a bit to fix the spawn/update race condition
foreach (var netVar in serverNetVarsToUpdate)
{
Assert.That(netVar.Value, Is.EqualTo(0)); // sanity check
}
// test updating all netvars
int updatedValue = 1;
foreach (var netVar in serverNetVarsToUpdate)
{
netVar.Value = updatedValue;
Assert.That(netVar.IsDirty, Is.True);
}
m_ServerNetworkManager.BehaviourUpdater.NetworkBehaviourUpdate(m_ServerNetworkManager);
// make sure we're not dirty anymore and that clients will receive that new value
foreach (var netVar in serverNetVarsToUpdate)
{
// if we don't have connected clients, netvars remain dirty
Assert.That(netVar.IsDirty, nbClients > 0 || useHost ? Is.Not.True : Is.True);
}
foreach (var client in m_ClientNetworkManagers)
{
var nbVarsCheckedClientSide = 0;
var countSpawnObjectResult = new MultiInstanceHelpers.CoroutineResultWrapper<bool>();
yield return MultiInstanceHelpers.WaitForCondition(() => client.SpawnManager.SpawnedObjects.Count == nbSpawnedObjects, countSpawnObjectResult);
Assert.That(countSpawnObjectResult.Result, Is.True);
foreach (var spawnedObject in client.SpawnManager.SpawnedObjects)
{
foreach (var behaviour in spawnedObject.Value.GetComponentsInChildren<NetworkBehaviour>())
case NetVarsToCheck.Two:
{
foreach (var networkVariable in behaviour.NetworkVariableFields)
{
var varInt = networkVariable as NetworkVariable<int>;
var varUpdateResult = new MultiInstanceHelpers.CoroutineResultWrapper<bool>();
yield return MultiInstanceHelpers.WaitForCondition(() => varInt.Value == updatedValue, varUpdateResult);
Assert.That(varUpdateResult.Result, Is.True);
nbVarsCheckedClientSide++;
Assert.That(varInt.Value, Is.EqualTo(updatedValue));
}
areDirty = m_FirstValue.IsDirty() && m_SeconValue.IsDirty();
break;
}
case NetVarsToCheck.One:
{
areDirty = m_FirstValue.IsDirty();
break;
}
}
return areDirty;
}
/// <summary>
/// The original version of this test only ever had up to 2 NetworkVariables per
/// NetworkBehaviour. As opposed to using a List of NetworkVariables, we just
/// create the maximum number that could be used and then only use what we need
/// for each test iteration.
/// </summary>
private NetworkVariable<int> m_FirstValue = new NetworkVariable<int>();
private NetworkVariable<int> m_SeconValue = new NetworkVariable<int>();
public override void OnNetworkSpawn()
{
// Clients will register each NetworkObject when it is spawned
if (!IsServer)
{
NetworkBehaviourUpdaterTests.ClientSideNotifyObjectSpawned(gameObject);
}
}
/// <summary>
/// Server side only, sets the NetworkVariables being used to the ValueToSetNetVarTo
/// that is pre-configured when the Network Prefab is created.
/// </summary>
public void SetNetworkVariableValues()
{
if (IsServer)
{
switch (NumberOfNetVarsToCheck)
{
case NetVarsToCheck.Two:
{
m_FirstValue.Value = ValueToSetNetVarTo;
m_SeconValue.Value = ValueToSetNetVarTo;
Assert.True(AreNetVarsDirty(), "Not all NetworkVariables were marked dirty on server after spawned!");
break;
}
case NetVarsToCheck.One:
{
m_FirstValue.Value = ValueToSetNetVarTo;
Assert.True(AreNetVarsDirty(), "Not all NetworkVariables were marked dirty on server after spawned!");
break;
}
}
Assert.That(nbVarsCheckedClientSide, Is.EqualTo(m_ClientNetworkManagers.Length > 0 ? serverNetVarCount : 0));
}
}
}
public interface INetVarInfo
/// <summary>
/// Used to define how many NetworkVariables to use per NetVarContainer instance.
/// There are always two
/// </summary>
public struct NetVarCombinationTypes
{
public List<NetworkVariable<int>> AllNetVars { get; }
public NetVarContainer.NetVarsToCheck FirstType;
public NetVarContainer.NetVarsToCheck SecondType;
}
public class ZeroNetVar : NetworkBehaviour, INetVarInfo
public class NetworkBehaviourUpdaterTests : NetcodeIntegrationTest
{
public List<NetworkVariable<int>> AllNetVars => new List<NetworkVariable<int>>(); // Needed to be independant from NetworkBehaviour's list of fields. This way, if that changes, we can still do this validation in this test
}
// Go ahead and create maximum number of clients (not all tests will use them)
protected override int NumberOfClients => 2;
public const int NetVarValueToSet = 1;
private static List<GameObject> s_ClientSpawnedNetworkObjects = new List<GameObject>();
private List<NetworkManager> m_ActiveClientsForCurrentTest;
public class OneNetVar : NetworkBehaviour, INetVarInfo
{
private NetworkVariable<int> m_SomeValue = new NetworkVariable<int>();
public List<NetworkVariable<int>> AllNetVars => new List<NetworkVariable<int>>() { m_SomeValue };
}
/// <summary>
/// Clients will call this when NetworkObjects are spawned on their end
/// </summary>
/// <param name="objectSpaned">the GameObject of the NetworkObject spawned</param>
public static void ClientSideNotifyObjectSpawned(GameObject objectSpaned)
{
if (!s_ClientSpawnedNetworkObjects.Contains(objectSpaned))
{
s_ClientSpawnedNetworkObjects.Add(objectSpaned);
}
}
public class TwoNetVar : NetworkBehaviour, INetVarInfo
{
private NetworkVariable<int> m_SomeValue = new NetworkVariable<int>();
private NetworkVariable<int> m_SomeOtherValue = new NetworkVariable<int>();
public List<NetworkVariable<int>> AllNetVars => new List<NetworkVariable<int>>() { m_SomeValue, m_SomeOtherValue };
protected override bool CanStartServerAndClients()
{
return false;
}
/// <summary>
/// Creates the server and client(s) required for this particular test iteration
/// </summary>
private IEnumerator StartClientsAndServer(bool useHost, int numberOfClients, GameObject prefabObject)
{
// Sanity check to make sure we are not trying to create more clients than we have available to use
Assert.True(numberOfClients <= m_ClientNetworkManagers.Length);
m_ActiveClientsForCurrentTest = new List<NetworkManager>();
// Create a list of the clients to be used in this test from the available clients
for (int i = 0; i < numberOfClients; i++)
{
m_ActiveClientsForCurrentTest.Add(m_ClientNetworkManagers[i]);
}
// Add the prefab to be used for this particular test iteration
m_ServerNetworkManager.NetworkConfig.NetworkPrefabs.Add(new NetworkPrefab() { Prefab = prefabObject });
m_ServerNetworkManager.NetworkConfig.TickRate = 30;
foreach (var clientManager in m_ActiveClientsForCurrentTest)
{
m_ServerNetworkManager.NetworkConfig.TickRate = 30;
clientManager.NetworkConfig.NetworkPrefabs.Add(new NetworkPrefab() { Prefab = prefabObject });
}
// Now spin everything up normally
var clientsAsArry = m_ActiveClientsForCurrentTest.ToArray();
Assert.True(NetcodeIntegrationTestHelpers.Start(useHost, m_ServerNetworkManager, clientsAsArry), "Failed to start server and client instances");
// Only if we have clients (not host)
if (numberOfClients > 0)
{
RegisterSceneManagerHandler();
}
// Wait for connection on client and server side
yield return WaitForClientsConnectedOrTimeOut(clientsAsArry);
}
/// <summary>
/// This list replaces the original NetworkVariable types to be checked.
/// Both NetworkVariables are of type int and the original version of this test was testing
/// the NetworkBehaviour Update when there were 1 or more (i.e two) on the same NetworkBehaviour.
/// After reviewing, we really only needed to test a much smaller combination of types and so
/// this pre-generated array represents the reduced set of combinations to test.
/// Note:
/// The original test was also testing for no NetworkVariables of type int, which there ended up
/// being no reason to do that and only added to the length of the execution time for this test.
/// </summary>
public static NetVarCombinationTypes[] NetVarCombinationTypeValues = new[]{
new NetVarCombinationTypes() { FirstType = NetVarContainer.NetVarsToCheck.One, SecondType = NetVarContainer.NetVarsToCheck.One },
new NetVarCombinationTypes() { FirstType = NetVarContainer.NetVarsToCheck.One, SecondType = NetVarContainer.NetVarsToCheck.Two },
new NetVarCombinationTypes() { FirstType = NetVarContainer.NetVarsToCheck.Two, SecondType = NetVarContainer.NetVarsToCheck.Two }};
/// <summary>
/// The updated BehaviourUpdaterAllTests was re-designed to replicate the same functionality being tested in the
/// original version of this test with additional time out handling and a re-organization in the order of operations.
/// Things like making sure all clients have spawned the NetworkObjects in question prior to testing for the
/// NetworkVariable value changes helped to eliminate the timing issues that were happening when this test was run
/// in a stand alone test runner build (i.e. all consoles run the stand alone version as opposed to the in-editor
/// version like the desktop tests use).
/// This update also updated how the server and clients were being constructed to help reduce the execution time.
/// </summary>
/// <param name="useHost"> whether to run the server as a host or not</param>
/// <param name="varCombinationTypes">the NetworkVariable combination types</param>
/// <param name="nbClients"> number of clients to use for the test</param>
/// <param name="numToSpawn"> number of NetworkObjects to be spawned</param>
[UnityTest]
public IEnumerator BehaviourUpdaterAllTests([Values] bool useHost,
[ValueSource(nameof(NetVarCombinationTypeValues))] NetVarCombinationTypes varCombinationTypes,
[Values(0, 1, 2)] int nbClients, [Values(1, 2)] int numToSpawn)
{
s_ClientSpawnedNetworkObjects.Clear();
// The edge case scenario where we can exit early is when we are running
// just the server (i.e. non-host) and there are zero clients. Under this
// edge case scenario of the various combinations we do not need to run
// this test as the IsDirty flag is never cleared when no clients exist at all.
if (nbClients == 0 && !useHost)
{
yield break;
}
// Create our prefab based on the NetVarCombinationTypes
var prefabToSpawn = NetVarContainer.CreatePrefabGameObject(varCombinationTypes);
yield return StartClientsAndServer(useHost, nbClients, prefabToSpawn);
// Tracks the server-side spawned prefab instances
var spawnedPrefabs = new List<GameObject>();
var tickInterval = 1.0f / m_ServerNetworkManager.NetworkConfig.TickRate;
// Used to determine if the client-side checks of this test should be
// executed or not as well is used to make sure all clients have spawned
// the appropriate number of NetworkObjects with the NetVarContainer behaviour
var numberOfObjectsToSpawnOnClients = numToSpawn * nbClients;
// spawn the objects
for (int i = 0; i < numToSpawn; i++)
{
var spawnedObject = Object.Instantiate(prefabToSpawn);
spawnedPrefabs.Add(spawnedObject);
var networkSpawnedObject = spawnedObject.GetComponent<NetworkObject>();
networkSpawnedObject.NetworkManagerOwner = m_ServerNetworkManager;
networkSpawnedObject.Spawn();
}
// When there are no clients (excluding when server is in host mode), we can skip all of this
// wait until all objects are spawned on the clients
if (numberOfObjectsToSpawnOnClients > 0)
{
// Waits for all clients to spawn the NetworkObjects
yield return WaitForConditionOrTimeOut(() => numberOfObjectsToSpawnOnClients == s_ClientSpawnedNetworkObjects.Count);
Assert.IsFalse(s_GlobalTimeoutHelper.TimedOut, $"Timed out waiting for clients to report spawning objects! " +
$"Total reported client-side spawned objects {s_ClientSpawnedNetworkObjects.Count}");
}
// Once all clients have spawned the NetworkObjects, set the network variables for
// those NetworkObjects on the server-side.
foreach (var spawnedPrefab in spawnedPrefabs)
{
var netVarContiners = spawnedPrefab.GetComponents<NetVarContainer>();
foreach (var netVarContiner in netVarContiners)
{
netVarContiner.SetNetworkVariableValues();
}
}
// Update the NetworkBehaviours to make sure all network variables are no longer marked as dirty
m_ServerNetworkManager.BehaviourUpdater.NetworkBehaviourUpdate(m_ServerNetworkManager);
// Verify that all network variables are no longer dirty on server side only if we have clients (including host)
foreach (var serverSpawnedObject in spawnedPrefabs)
{
var netVarContainers = serverSpawnedObject.GetComponents<NetVarContainer>();
foreach (var netVarContainer in netVarContainers)
{
Assert.False(netVarContainer.AreNetVarsDirty(), "Some NetworkVariables were still marked dirty after NetworkBehaviourUpdate!");
}
}
// When there are no clients (excluding when server is in host mode), we can skip all of this
if (numberOfObjectsToSpawnOnClients > 0)
{
// Get a list of all NetVarContainer components on the client-side spawned NetworkObjects
var clientSideNetVarContainers = new List<NetVarContainer>();
foreach (var clientSpawnedObjects in s_ClientSpawnedNetworkObjects)
{
var netVarContainers = clientSpawnedObjects.GetComponents<NetVarContainer>();
foreach (var netvarContiner in netVarContainers)
{
clientSideNetVarContainers.Add(netvarContiner);
}
}
yield return WaitForConditionOrTimeOut(() =>
clientSideNetVarContainers.Where(d =>
d.HaveAllValuesChanged(NetVarValueToSet)).Count() == clientSideNetVarContainers.Count);
Assert.IsFalse(s_GlobalTimeoutHelper.TimedOut, $"Timed out waiting for client side NetVarContainers to report all NetworkVariables have been updated!");
}
Object.DestroyImmediate(prefabToSpawn);
}
}
}

View File

@@ -0,0 +1,35 @@
using NUnit.Framework;
using UnityEngine;
namespace Unity.Netcode.RuntimeTests
{
public class NetworkManagerCustomMessageManagerTests
{
[Test]
public void CustomMessageManagerAssigned()
{
var gameObject = new GameObject(nameof(CustomMessageManagerAssigned));
var networkManager = gameObject.AddComponent<NetworkManager>();
var transport = gameObject.AddComponent<DummyTransport>();
networkManager.NetworkConfig = new NetworkConfig();
// Set dummy transport that does nothing
networkManager.NetworkConfig.NetworkTransport = transport;
CustomMessagingManager preManager = networkManager.CustomMessagingManager;
// Start server to cause initialization
networkManager.StartServer();
Debug.Assert(preManager == null);
Debug.Assert(networkManager.CustomMessagingManager != null);
networkManager.Shutdown();
Object.DestroyImmediate(gameObject);
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 315ffe39806441839400d21871d566a0
timeCreated: 1618478909

View File

@@ -0,0 +1,29 @@
using NUnit.Framework;
using UnityEngine;
namespace Unity.Netcode.RuntimeTests
{
public class NetworkManagerSceneManagerTests
{
[Test]
public void SceneManagerAssigned()
{
var gameObject = new GameObject(nameof(SceneManagerAssigned));
var networkManager = gameObject.AddComponent<NetworkManager>();
var transport = gameObject.AddComponent<DummyTransport>();
networkManager.NetworkConfig = new NetworkConfig();
// Set dummy transport that does nothing
networkManager.NetworkConfig.NetworkTransport = transport;
NetworkSceneManager preManager = networkManager.SceneManager;
// Start server to cause initialization process
networkManager.StartServer();
Debug.Assert(preManager == null);
Debug.Assert(networkManager.SceneManager != null);
Object.DestroyImmediate(gameObject);
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 9753bf4088484cbebee95d917699dec6
timeCreated: 1618482634

View File

@@ -2,6 +2,7 @@ using System.Collections;
using NUnit.Framework;
using UnityEngine;
using UnityEngine.TestTools;
using Unity.Netcode.TestHelpers.Runtime;
using Object = UnityEngine.Object;
namespace Unity.Netcode.RuntimeTests
@@ -12,18 +13,9 @@ namespace Unity.Netcode.RuntimeTests
/// - Server destroy spawned => Object gets destroyed and despawned/destroyed on all clients. Server does not run <see cref="NetworkPrefaInstanceHandler.HandleNetworkPrefabDestroy"/>. Client runs it.
/// - Client destroy spawned => throw exception.
/// </summary>
public class NetworkObjectDestroyTests : BaseMultiInstanceTest
public class NetworkObjectDestroyTests : NetcodeIntegrationTest
{
protected override int NbClients => 1;
[UnitySetUp]
public override IEnumerator Setup()
{
yield return StartSomeClientsAndServerWithPlayers(true, NbClients, playerPrefab =>
{
// playerPrefab.AddComponent<TestDestroy>();
});
}
protected override int NumberOfClients => 1;
/// <summary>
/// Tests that a server can destroy a NetworkObject and that it gets despawned correctly.
@@ -33,12 +25,12 @@ namespace Unity.Netcode.RuntimeTests
public IEnumerator TestNetworkObjectServerDestroy()
{
// This is the *SERVER VERSION* of the *CLIENT PLAYER*
var serverClientPlayerResult = new MultiInstanceHelpers.CoroutineResultWrapper<NetworkObject>();
yield return MultiInstanceHelpers.Run(MultiInstanceHelpers.GetNetworkObjectByRepresentation((x => x.IsPlayerObject && x.OwnerClientId == m_ClientNetworkManagers[0].LocalClientId), m_ServerNetworkManager, serverClientPlayerResult));
var serverClientPlayerResult = new NetcodeIntegrationTestHelpers.ResultWrapper<NetworkObject>();
yield return NetcodeIntegrationTestHelpers.GetNetworkObjectByRepresentation(x => x.IsPlayerObject && x.OwnerClientId == m_ClientNetworkManagers[0].LocalClientId, m_ServerNetworkManager, serverClientPlayerResult);
// This is the *CLIENT VERSION* of the *CLIENT PLAYER*
var clientClientPlayerResult = new MultiInstanceHelpers.CoroutineResultWrapper<NetworkObject>();
yield return MultiInstanceHelpers.Run(MultiInstanceHelpers.GetNetworkObjectByRepresentation((x => x.IsPlayerObject && x.OwnerClientId == m_ClientNetworkManagers[0].LocalClientId), m_ClientNetworkManagers[0], clientClientPlayerResult));
var clientClientPlayerResult = new NetcodeIntegrationTestHelpers.ResultWrapper<NetworkObject>();
yield return NetcodeIntegrationTestHelpers.GetNetworkObjectByRepresentation(x => x.IsPlayerObject && x.OwnerClientId == m_ClientNetworkManagers[0].LocalClientId, m_ClientNetworkManagers[0], clientClientPlayerResult);
Assert.IsNotNull(serverClientPlayerResult.Result.gameObject);
Assert.IsNotNull(clientClientPlayerResult.Result.gameObject);
@@ -46,12 +38,9 @@ namespace Unity.Netcode.RuntimeTests
// destroy the server player
Object.Destroy(serverClientPlayerResult.Result.gameObject);
yield return null;
yield return NetcodeIntegrationTestHelpers.WaitForMessageOfType<DestroyObjectMessage>(m_ClientNetworkManagers[0]);
Assert.IsTrue(serverClientPlayerResult.Result == null); // Assert.IsNull doesn't work here
yield return null; // wait one frame more until we receive on client
Assert.IsTrue(clientClientPlayerResult.Result == null);
// create an unspawned networkobject and destroy it
@@ -71,12 +60,12 @@ namespace Unity.Netcode.RuntimeTests
public IEnumerator TestNetworkObjectClientDestroy()
{
// This is the *SERVER VERSION* of the *CLIENT PLAYER*
var serverClientPlayerResult = new MultiInstanceHelpers.CoroutineResultWrapper<NetworkObject>();
yield return MultiInstanceHelpers.Run(MultiInstanceHelpers.GetNetworkObjectByRepresentation((x => x.IsPlayerObject && x.OwnerClientId == m_ClientNetworkManagers[0].LocalClientId), m_ServerNetworkManager, serverClientPlayerResult));
var serverClientPlayerResult = new NetcodeIntegrationTestHelpers.ResultWrapper<NetworkObject>();
yield return NetcodeIntegrationTestHelpers.GetNetworkObjectByRepresentation(x => x.IsPlayerObject && x.OwnerClientId == m_ClientNetworkManagers[0].LocalClientId, m_ServerNetworkManager, serverClientPlayerResult);
// This is the *CLIENT VERSION* of the *CLIENT PLAYER*
var clientClientPlayerResult = new MultiInstanceHelpers.CoroutineResultWrapper<NetworkObject>();
yield return MultiInstanceHelpers.Run(MultiInstanceHelpers.GetNetworkObjectByRepresentation((x => x.IsPlayerObject && x.OwnerClientId == m_ClientNetworkManagers[0].LocalClientId), m_ClientNetworkManagers[0], clientClientPlayerResult));
var clientClientPlayerResult = new NetcodeIntegrationTestHelpers.ResultWrapper<NetworkObject>();
yield return NetcodeIntegrationTestHelpers.GetNetworkObjectByRepresentation(x => x.IsPlayerObject && x.OwnerClientId == m_ClientNetworkManagers[0].LocalClientId, m_ClientNetworkManagers[0], clientClientPlayerResult);
// destroy the client player, this is not allowed
LogAssert.Expect(LogType.Exception, "NotServerException: Destroy a spawned NetworkObject on a non-host client is not valid. Call Destroy or Despawn on the server/host instead.");

View File

@@ -3,6 +3,7 @@ using System.Collections.Generic;
using NUnit.Framework;
using UnityEngine;
using UnityEngine.TestTools;
using Unity.Netcode.TestHelpers.Runtime;
using Object = UnityEngine.Object;
namespace Unity.Netcode.RuntimeTests
@@ -13,13 +14,13 @@ namespace Unity.Netcode.RuntimeTests
public IEnumerator DontDestroyWithOwnerTest()
{
// create server and client instances
MultiInstanceHelpers.Create(1, out NetworkManager server, out NetworkManager[] clients);
NetcodeIntegrationTestHelpers.Create(1, out NetworkManager server, out NetworkManager[] clients);
// create prefab
var gameObject = new GameObject("ClientOwnedObject");
var networkObject = gameObject.AddComponent<NetworkObject>();
networkObject.DontDestroyWithOwner = true;
MultiInstanceHelpers.MakeNetworkObjectTestPrefab(networkObject);
NetcodeIntegrationTestHelpers.MakeNetworkObjectTestPrefab(networkObject);
server.NetworkConfig.NetworkPrefabs.Add(new NetworkPrefab()
{
@@ -35,13 +36,13 @@ namespace Unity.Netcode.RuntimeTests
}
// start server and connect clients
MultiInstanceHelpers.Start(false, server, clients);
NetcodeIntegrationTestHelpers.Start(false, server, clients);
// wait for connection on client side
yield return MultiInstanceHelpers.Run(MultiInstanceHelpers.WaitForClientsConnected(clients));
yield return NetcodeIntegrationTestHelpers.WaitForClientsConnected(clients);
// wait for connection on server side
yield return MultiInstanceHelpers.Run(MultiInstanceHelpers.WaitForClientConnectedToServer(server));
yield return NetcodeIntegrationTestHelpers.WaitForClientConnectedToServer(server);
// network objects
var networkObjects = new List<NetworkObject>();
@@ -56,13 +57,13 @@ namespace Unity.Netcode.RuntimeTests
}
// wait for object spawn on client
yield return MultiInstanceHelpers.Run(MultiInstanceHelpers.WaitForCondition(() => clients[0].SpawnManager.SpawnedObjects.Count == 32));
yield return NetcodeIntegrationTest.WaitForConditionOrTimeOut(() => clients[0].SpawnManager.SpawnedObjects.Count == 32);
// disconnect the client that owns all the clients
MultiInstanceHelpers.StopOneClient(clients[0]);
NetcodeIntegrationTestHelpers.StopOneClient(clients[0]);
// wait for disconnect
yield return MultiInstanceHelpers.Run(MultiInstanceHelpers.WaitForCondition(() => server.ConnectedClients.Count == 0));
yield return NetcodeIntegrationTest.WaitForConditionOrTimeOut(() => server.ConnectedClients.Count == 0);
for (int i = 0; i < networkObjects.Count; i++)
{
@@ -71,7 +72,7 @@ namespace Unity.Netcode.RuntimeTests
}
// cleanup
MultiInstanceHelpers.Destroy();
NetcodeIntegrationTestHelpers.Destroy();
}
}
}

View File

@@ -0,0 +1,58 @@
using System.Collections;
using System.Linq;
using NUnit.Framework;
using UnityEngine;
using UnityEngine.TestTools;
using Unity.Netcode.TestHelpers.Runtime;
namespace Unity.Netcode.RuntimeTests
{
public class NetworkObjectNetworkClientOwnedObjectsTests : NetcodeIntegrationTest
{
protected override int NumberOfClients => 1;
private NetworkPrefab m_NetworkPrefab;
protected override void OnServerAndClientsCreated()
{
// create prefab
var gameObject = new GameObject("ClientOwnedObject");
var networkObject = gameObject.AddComponent<NetworkObject>();
NetcodeIntegrationTestHelpers.MakeNetworkObjectTestPrefab(networkObject);
m_NetworkPrefab = (new NetworkPrefab()
{
Prefab = gameObject
});
m_ServerNetworkManager.NetworkConfig.NetworkPrefabs.Add(m_NetworkPrefab);
foreach (var client in m_ClientNetworkManagers)
{
client.NetworkConfig.NetworkPrefabs.Add(m_NetworkPrefab);
}
}
[UnityTest]
public IEnumerator ChangeOwnershipOwnedObjectsAddTest()
{
NetworkObject serverObject = Object.Instantiate(m_NetworkPrefab.Prefab).GetComponent<NetworkObject>();
serverObject.NetworkManagerOwner = m_ServerNetworkManager;
serverObject.Spawn();
// Provide enough time for the client to receive and process the spawned message.
yield return s_DefaultWaitForTick;
// The object is owned by server
Assert.False(m_ServerNetworkManager.ConnectedClients[m_ClientNetworkManagers[0].LocalClientId].OwnedObjects.Any(x => x.NetworkObjectId == serverObject.NetworkObjectId));
// Change the ownership
serverObject.ChangeOwnership(m_ClientNetworkManagers[0].LocalClientId);
// Provide enough time for the client to receive and process the change in ownership message.
yield return s_DefaultWaitForTick;
// Ensure it's now added to the list
Assert.True(m_ServerNetworkManager.ConnectedClients[m_ClientNetworkManagers[0].LocalClientId].OwnedObjects.Any(x => x.NetworkObjectId == serverObject.NetworkObjectId));
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 067d53283c8fa4c31b638b830473c5b7
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -2,6 +2,7 @@ using System.Collections;
using NUnit.Framework;
using UnityEngine;
using UnityEngine.TestTools;
using Unity.Netcode.TestHelpers.Runtime;
namespace Unity.Netcode.RuntimeTests
@@ -37,14 +38,14 @@ namespace Unity.Netcode.RuntimeTests
[UnitySetUp]
public IEnumerator Setup()
{
Assert.IsTrue(MultiInstanceHelpers.Create(1, out m_ServerHost, out m_Clients));
Assert.IsTrue(NetcodeIntegrationTestHelpers.Create(1, out m_ServerHost, out m_Clients));
m_ObjectToSpawn = new GameObject();
m_NetworkObject = m_ObjectToSpawn.AddComponent<NetworkObject>();
m_ObjectToSpawn.AddComponent<OnNetworkDespawnTestComponent>();
// Make it a prefab
MultiInstanceHelpers.MakeNetworkObjectTestPrefab(m_NetworkObject);
NetcodeIntegrationTestHelpers.MakeNetworkObjectTestPrefab(m_NetworkObject);
var networkPrefab = new NetworkPrefab();
networkPrefab.Prefab = m_ObjectToSpawn;
@@ -67,7 +68,7 @@ namespace Unity.Netcode.RuntimeTests
Object.Destroy(m_ObjectToSpawn);
m_ObjectToSpawn = null;
}
MultiInstanceHelpers.Destroy();
NetcodeIntegrationTestHelpers.Destroy();
yield return null;
}
@@ -85,22 +86,22 @@ namespace Unity.Netcode.RuntimeTests
[UnityTest]
public IEnumerator TestNetworkObjectDespawnOnShutdown([Values(InstanceType.Server, InstanceType.Host, InstanceType.Client)] InstanceType despawnCheck)
{
var useHost = despawnCheck == InstanceType.Server ? false : true;
var useHost = despawnCheck != InstanceType.Server;
var networkManager = despawnCheck == InstanceType.Host || despawnCheck == InstanceType.Server ? m_ServerHost : m_Clients[0];
// Start the instances
if (!MultiInstanceHelpers.Start(useHost, m_ServerHost, m_Clients))
if (!NetcodeIntegrationTestHelpers.Start(useHost, m_ServerHost, m_Clients))
{
Debug.LogError("Failed to start instances");
Assert.Fail("Failed to start instances");
}
// [Client-Side] Wait for a connection to the server
yield return MultiInstanceHelpers.WaitForClientsConnected(m_Clients, null, 512);
yield return NetcodeIntegrationTestHelpers.WaitForClientsConnected(m_Clients, null, 512);
// [Host-Server-Side] Check to make sure all clients are connected
var clientCount = useHost ? m_Clients.Length + 1 : m_Clients.Length;
yield return MultiInstanceHelpers.WaitForClientsConnectedToServer(m_ServerHost, clientCount, null, 512);
yield return NetcodeIntegrationTestHelpers.WaitForClientsConnectedToServer(m_ServerHost, clientCount, null, 512);
// Spawn the test object
var spawnedObject = Object.Instantiate(m_NetworkObject);
@@ -109,8 +110,8 @@ namespace Unity.Netcode.RuntimeTests
spawnedNetworkObject.Spawn(true);
// Get the spawned object relative to which NetworkManager instance we are testing.
var relativeSpawnedObject = new MultiInstanceHelpers.CoroutineResultWrapper<NetworkObject>();
yield return MultiInstanceHelpers.Run(MultiInstanceHelpers.GetNetworkObjectByRepresentation((x => x.GetComponent<OnNetworkDespawnTestComponent>() != null), networkManager, relativeSpawnedObject));
var relativeSpawnedObject = new NetcodeIntegrationTestHelpers.ResultWrapper<NetworkObject>();
yield return NetcodeIntegrationTestHelpers.GetNetworkObjectByRepresentation((x => x.GetComponent<OnNetworkDespawnTestComponent>() != null), networkManager, relativeSpawnedObject);
var onNetworkDespawnTestComponent = relativeSpawnedObject.Result.GetComponent<OnNetworkDespawnTestComponent>();
// Confirm it is not set before shutting down the NetworkManager

View File

@@ -3,22 +3,21 @@ using System.Collections.Generic;
using NUnit.Framework;
using UnityEngine;
using UnityEngine.TestTools;
using Unity.Netcode.TestHelpers.Runtime;
namespace Unity.Netcode.RuntimeTests
{
public class NetworkObjectOnSpawnTests : BaseMultiInstanceTest
public class NetworkObjectOnSpawnTests : NetcodeIntegrationTest
{
private GameObject m_TestNetworkObjectPrefab;
private GameObject m_TestNetworkObjectInstance;
protected override int NbClients => 2;
protected override int NumberOfClients => 2;
/// <summary>
/// Tests that instantiating a <see cref="NetworkObject"/> and destroying without spawning it
/// does not run <see cref="NetworkBehaviour.OnNetworkSpawn"/> or <see cref="NetworkBehaviour.OnNetworkSpawn"/>.
/// </summary>
/// <returns></returns>
[UnityTest]
public IEnumerator InstantiateDestroySpawnNotCalled()
{
@@ -29,6 +28,8 @@ namespace Unity.Netcode.RuntimeTests
// instantiate
m_TestNetworkObjectInstance = Object.Instantiate(m_TestNetworkObjectPrefab);
yield return null;
Object.Destroy(m_TestNetworkObjectInstance);
}
private class FailWhenSpawned : NetworkBehaviour
@@ -44,20 +45,13 @@ namespace Unity.Netcode.RuntimeTests
}
}
[UnitySetUp]
public override IEnumerator Setup()
protected override void OnCreatePlayerPrefab()
{
yield return StartSomeClientsAndServerWithPlayers(true, NbClients, playerPrefab =>
{
// add test component
playerPrefab.AddComponent<TrackOnSpawnFunctions>();
});
m_PlayerPrefab.AddComponent<TrackOnSpawnFunctions>();
}
[UnityTearDown]
public override IEnumerator Teardown()
protected override IEnumerator OnTearDown()
{
if (m_TestNetworkObjectPrefab != null)
{
Object.Destroy(m_TestNetworkObjectPrefab);
@@ -67,10 +61,11 @@ namespace Unity.Netcode.RuntimeTests
{
Object.Destroy(m_TestNetworkObjectInstance);
}
yield return base.Teardown();
yield return base.OnTearDown();
}
private List<TrackOnSpawnFunctions> m_ClientTrackOnSpawnInstances = new List<TrackOnSpawnFunctions>();
/// <summary>
/// Test that callbacks are run for playerobject spawn, despawn, regular spawn, destroy on server.
/// </summary>
@@ -79,19 +74,13 @@ namespace Unity.Netcode.RuntimeTests
public IEnumerator TestOnNetworkSpawnCallbacks()
{
// [Host-Side] Get the Host owned instance
var serverClientPlayerResult = new MultiInstanceHelpers.CoroutineResultWrapper<NetworkObject>();
yield return MultiInstanceHelpers.Run(MultiInstanceHelpers.GetNetworkObjectByRepresentation((x => x.IsPlayerObject && x.OwnerClientId == m_ClientNetworkManagers[0].LocalClientId), m_ServerNetworkManager, serverClientPlayerResult));
var serverInstance = m_PlayerNetworkObjects[m_ServerNetworkManager.LocalClientId][m_ServerNetworkManager.LocalClientId].GetComponent<TrackOnSpawnFunctions>();
var serverInstance = serverClientPlayerResult.Result.GetComponent<TrackOnSpawnFunctions>();
var clientInstances = new List<TrackOnSpawnFunctions>();
foreach (var client in m_ClientNetworkManagers)
{
var clientClientPlayerResult = new MultiInstanceHelpers.CoroutineResultWrapper<NetworkObject>();
yield return MultiInstanceHelpers.Run(MultiInstanceHelpers.GetNetworkObjectByRepresentation((x => x.IsPlayerObject && x.OwnerClientId == m_ClientNetworkManagers[0].LocalClientId), client, clientClientPlayerResult));
var clientRpcTests = clientClientPlayerResult.Result.GetComponent<TrackOnSpawnFunctions>();
var clientRpcTests = m_PlayerNetworkObjects[client.LocalClientId][m_ServerNetworkManager.LocalClientId].gameObject.GetComponent<TrackOnSpawnFunctions>();
Assert.IsNotNull(clientRpcTests);
clientInstances.Add(clientRpcTests);
m_ClientTrackOnSpawnInstances.Add(clientRpcTests);
}
// -------------- step 1 check player spawn despawn
@@ -99,69 +88,84 @@ namespace Unity.Netcode.RuntimeTests
// check spawned on server
Assert.AreEqual(1, serverInstance.OnNetworkSpawnCalledCount);
// safety check despawned
// safety check server despawned
Assert.AreEqual(0, serverInstance.OnNetworkDespawnCalledCount);
// check spawned on client
foreach (var clientInstance in clientInstances)
// Conditional check for clients spawning or despawning
var checkSpawnCondition = false;
var expectedSpawnCount = 1;
var expectedDespawnCount = 0;
bool HasConditionBeenMet()
{
Assert.AreEqual(1, clientInstance.OnNetworkSpawnCalledCount);
// safety check despawned
Assert.AreEqual(0, clientInstance.OnNetworkDespawnCalledCount);
var clientsCompleted = 0;
// check spawned on client
foreach (var clientInstance in m_ClientTrackOnSpawnInstances)
{
if (checkSpawnCondition)
{
if (clientInstance.OnNetworkSpawnCalledCount == expectedSpawnCount)
{
clientsCompleted++;
}
}
else
{
if (clientInstance.OnNetworkDespawnCalledCount == expectedDespawnCount)
{
clientsCompleted++;
}
}
}
return clientsCompleted >= NumberOfClients;
}
// despawn on server. However, since we'll be using this object later in the test, don't delete it (false)
// safety check that all clients have not been despawned yet
Assert.True(HasConditionBeenMet(), "Failed condition that all clients not despawned yet!");
// now verify that all clients have been spawned
checkSpawnCondition = true;
yield return WaitForConditionOrTimeOut(HasConditionBeenMet);
Assert.False(s_GlobalTimeoutHelper.TimedOut, "Timed out while waiting for client side spawns!");
// despawn on server. However, since we'll be using this object later in the test, don't delete it
serverInstance.GetComponent<NetworkObject>().Despawn(false);
// check despawned on server
Assert.AreEqual(1, serverInstance.OnNetworkDespawnCalledCount);
// we now expect the clients to each have despawned once
expectedDespawnCount = 1;
// wait long enough for player object to be despawned
int nextFrameNumber = Time.frameCount + 2;
yield return new WaitUntil(() => Time.frameCount >= nextFrameNumber);
yield return s_DefaultWaitForTick;
// verify that all client-side instances are despawned
checkSpawnCondition = false;
yield return WaitForConditionOrTimeOut(HasConditionBeenMet);
// check despawned on clients
foreach (var clientInstance in clientInstances)
{
Assert.AreEqual(1, clientInstance.OnNetworkDespawnCalledCount);
}
//----------- step 2 check spawn again and destroy
Assert.False(s_GlobalTimeoutHelper.TimedOut, "Timed out while waiting for client side despawns!");
//----------- step 2 check spawn and destroy again
serverInstance.GetComponent<NetworkObject>().Spawn();
// wait long enough for player object to be spawned
nextFrameNumber = Time.frameCount + 2;
yield return new WaitUntil(() => Time.frameCount >= nextFrameNumber);
// wait a tick
yield return s_DefaultWaitForTick;
// check spawned again on server this is 2 because we are reusing the object which was already spawned once.
Assert.AreEqual(2, serverInstance.OnNetworkSpawnCalledCount);
// check spawned on client
foreach (var clientInstance in clientInstances)
{
Assert.AreEqual(1, clientInstance.OnNetworkSpawnCalledCount);
}
checkSpawnCondition = true;
yield return WaitForConditionOrTimeOut(HasConditionBeenMet);
Assert.False(s_GlobalTimeoutHelper.TimedOut, "Timed out while waiting for client side spawns! (2nd pass)");
// destroy the server object
Object.Destroy(serverInstance.gameObject);
// wait one frame for destroy to kick in
yield return null;
yield return s_DefaultWaitForTick;
// check whether despawned was called again on server instance
Assert.AreEqual(2, serverInstance.OnNetworkDespawnCalledCount);
// wait long enough for player object to be despawned on client
nextFrameNumber = Time.frameCount + 2;
yield return new WaitUntil(() => Time.frameCount >= nextFrameNumber);
checkSpawnCondition = false;
yield return WaitForConditionOrTimeOut(HasConditionBeenMet);
// check despawned on clients
foreach (var clientInstance in clientInstances)
{
Assert.AreEqual(1, clientInstance.OnNetworkDespawnCalledCount);
}
Assert.False(s_GlobalTimeoutHelper.TimedOut, "Timed out while waiting for client side despawns! (2nd pass)");
}
private class TrackOnSpawnFunctions : NetworkBehaviour

View File

@@ -2,6 +2,7 @@ using System.Collections;
using NUnit.Framework;
using UnityEngine;
using UnityEngine.TestTools;
using Unity.Netcode.TestHelpers.Runtime;
namespace Unity.Netcode.RuntimeTests
{
@@ -52,7 +53,7 @@ namespace Unity.Netcode.RuntimeTests
Assert.That(k_ClientInstanceCount, Is.GreaterThan(0));
// create NetworkManager instances
Assert.That(MultiInstanceHelpers.Create(k_ClientInstanceCount, out m_ServerNetworkManager, out m_ClientNetworkManagers));
Assert.That(NetcodeIntegrationTestHelpers.Create(k_ClientInstanceCount, out m_ServerNetworkManager, out m_ClientNetworkManagers));
Assert.That(m_ServerNetworkManager, Is.Not.Null);
Assert.That(m_ClientNetworkManagers, Is.Not.Null);
Assert.That(m_ClientNetworkManagers.Length, Is.EqualTo(k_ClientInstanceCount));
@@ -61,7 +62,7 @@ namespace Unity.Netcode.RuntimeTests
m_DummyPrefab = new GameObject("DummyPrefabPrototype");
m_DummyPrefab.AddComponent<NetworkObject>();
m_DummyPrefab.AddComponent<NetworkObjectOwnershipComponent>();
MultiInstanceHelpers.MakeNetworkObjectTestPrefab(m_DummyPrefab.GetComponent<NetworkObject>());
NetcodeIntegrationTestHelpers.MakeNetworkObjectTestPrefab(m_DummyPrefab.GetComponent<NetworkObject>());
m_ServerNetworkManager.NetworkConfig.NetworkPrefabs.Add(new NetworkPrefab { Prefab = m_DummyPrefab });
foreach (var clientNetworkManager in m_ClientNetworkManagers)
{
@@ -69,19 +70,19 @@ namespace Unity.Netcode.RuntimeTests
}
// start server and client NetworkManager instances
Assert.That(MultiInstanceHelpers.Start(m_IsHost, m_ServerNetworkManager, m_ClientNetworkManagers));
Assert.That(NetcodeIntegrationTestHelpers.Start(m_IsHost, m_ServerNetworkManager, m_ClientNetworkManagers));
// wait for connection on client side
yield return MultiInstanceHelpers.Run(MultiInstanceHelpers.WaitForClientsConnected(m_ClientNetworkManagers));
yield return NetcodeIntegrationTestHelpers.WaitForClientsConnected(m_ClientNetworkManagers);
// wait for connection on server side
yield return MultiInstanceHelpers.Run(MultiInstanceHelpers.WaitForClientConnectedToServer(m_ServerNetworkManager));
yield return NetcodeIntegrationTestHelpers.WaitForClientConnectedToServer(m_ServerNetworkManager);
}
[TearDown]
public void Teardown()
{
MultiInstanceHelpers.Destroy();
NetcodeIntegrationTestHelpers.Destroy();
if (m_DummyGameObject != null)
{
@@ -106,8 +107,7 @@ namespace Unity.Netcode.RuntimeTests
var dummyNetworkObjectId = dummyNetworkObject.NetworkObjectId;
Assert.That(dummyNetworkObjectId, Is.GreaterThan(0));
int nextFrameNumber = Time.frameCount + 2;
yield return new WaitUntil(() => Time.frameCount >= nextFrameNumber);
yield return NetcodeIntegrationTestHelpers.WaitForMessageOfType<CreateObjectMessage>(m_ClientNetworkManagers[0]);
Assert.That(m_ServerNetworkManager.SpawnManager.SpawnedObjects.ContainsKey(dummyNetworkObjectId));
foreach (var clientNetworkManager in m_ClientNetworkManagers)
@@ -136,17 +136,14 @@ namespace Unity.Netcode.RuntimeTests
Assert.That(m_ServerNetworkManager.ConnectedClients.ContainsKey(m_ClientNetworkManagers[0].LocalClientId));
serverObject.ChangeOwnership(m_ClientNetworkManagers[0].LocalClientId);
nextFrameNumber = Time.frameCount + 2;
yield return new WaitUntil(() => Time.frameCount >= nextFrameNumber);
yield return NetcodeIntegrationTestHelpers.WaitForMessageOfType<ChangeOwnershipMessage>(m_ClientNetworkManagers[0]);
Assert.That(clientComponent.OnGainedOwnershipFired);
Assert.That(clientComponent.CachedOwnerIdOnGainedOwnership, Is.EqualTo(m_ClientNetworkManagers[0].LocalClientId));
serverObject.ChangeOwnership(m_ServerNetworkManager.ServerClientId);
nextFrameNumber = Time.frameCount + 2;
yield return new WaitUntil(() => Time.frameCount >= nextFrameNumber);
yield return NetcodeIntegrationTestHelpers.WaitForMessageOfType<ChangeOwnershipMessage>(m_ClientNetworkManagers[0]);
Assert.That(serverObject.OwnerClientId, Is.EqualTo(m_ServerNetworkManager.LocalClientId));
Assert.That(clientComponent.OnLostOwnershipFired);

View File

@@ -3,6 +3,7 @@ using UnityEngine;
using UnityEngine.SceneManagement;
using NUnit.Framework;
using Unity.Collections;
using Unity.Netcode.TestHelpers.Runtime;
namespace Unity.Netcode.RuntimeTests
{

View File

@@ -0,0 +1,65 @@
using System.Collections;
using NUnit.Framework;
using UnityEngine;
using UnityEngine.TestTools;
using Unity.Netcode.TestHelpers.Runtime;
namespace Unity.Netcode.RuntimeTests
{
public class NetworkObjectSpawnManyObjectsTests : NetcodeIntegrationTest
{
protected override int NumberOfClients => 1;
// "many" in this case means enough to exceed a ushort_max message size written in the header
// 1500 is not a magic number except that it's big enough to trigger a failure
private const int k_SpawnedObjects = 1500;
private NetworkPrefab m_PrefabToSpawn;
// Using this component assures we will know precisely how many prefabs were spawned on the client
public class SpawnObjecTrackingComponent : NetworkBehaviour
{
public static int SpawnedObjects;
public override void OnNetworkSpawn()
{
if (!IsServer)
{
SpawnedObjects++;
}
}
}
protected override void OnServerAndClientsCreated()
{
SpawnObjecTrackingComponent.SpawnedObjects = 0;
// create prefab
var gameObject = new GameObject("TestObject");
var networkObject = gameObject.AddComponent<NetworkObject>();
NetcodeIntegrationTestHelpers.MakeNetworkObjectTestPrefab(networkObject);
gameObject.AddComponent<SpawnObjecTrackingComponent>();
m_PrefabToSpawn = new NetworkPrefab() { Prefab = gameObject };
m_ServerNetworkManager.NetworkConfig.NetworkPrefabs.Add(m_PrefabToSpawn);
foreach (var client in m_ClientNetworkManagers)
{
client.NetworkConfig.NetworkPrefabs.Add(m_PrefabToSpawn);
}
}
[UnityTest]
// When this test fails it does so without an exception and will wait the default ~6 minutes
[Timeout(10000)]
public IEnumerator WhenManyObjectsAreSpawnedAtOnce_AllAreReceived()
{
for (int x = 0; x < k_SpawnedObjects; x++)
{
NetworkObject serverObject = Object.Instantiate(m_PrefabToSpawn.Prefab).GetComponent<NetworkObject>();
serverObject.NetworkManagerOwner = m_ServerNetworkManager;
serverObject.Spawn();
}
// ensure all objects are replicated before spawning more
yield return WaitForConditionOrTimeOut(() => SpawnObjecTrackingComponent.SpawnedObjects < k_SpawnedObjects);
Assert.False(s_GlobalTimeoutHelper.TimedOut, $"Timed out waiting for the client to spawn {k_SpawnedObjects} objects!");
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 4e0439aa2d2a72e4aa42b051d26af366
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -3,6 +3,7 @@ using System.Linq;
using System.Collections.Generic;
using UnityEngine;
using NUnit.Framework;
using Unity.Netcode.TestHelpers.Runtime;
namespace Unity.Netcode.RuntimeTests
{
@@ -22,7 +23,7 @@ namespace Unity.Netcode.RuntimeTests
{
Guid baseObjectID = NetworkManagerHelper.AddGameNetworkObject(k_TestPrefabObjectName + m_ObjectId.ToString());
NetworkObject validPrefab = NetworkManagerHelper.InstantiatedNetworkObjects[baseObjectID];
MultiInstanceHelpers.MakeNetworkObjectTestPrefab(validPrefab);
NetcodeIntegrationTestHelpers.MakeNetworkObjectTestPrefab(validPrefab);
m_ObjectId++;
return validPrefab.gameObject;
}

View File

@@ -4,6 +4,7 @@ using System.Collections.Generic;
using NUnit.Framework;
using UnityEngine;
using UnityEngine.TestTools;
using Unity.Netcode.TestHelpers.Runtime;
namespace Unity.Netcode.RuntimeTests
{
@@ -29,9 +30,9 @@ namespace Unity.Netcode.RuntimeTests
}
public class NetworkShowHideTests : BaseMultiInstanceTest
public class NetworkShowHideTests : NetcodeIntegrationTest
{
protected override int NbClients => 2;
protected override int NumberOfClients => 2;
private ulong m_ClientId0;
private GameObject m_PrefabToSpawn;
@@ -43,15 +44,14 @@ namespace Unity.Netcode.RuntimeTests
private NetworkObject m_Object2OnClient0;
private NetworkObject m_Object3OnClient0;
[UnitySetUp]
public override IEnumerator Setup()
protected override void OnCreatePlayerPrefab()
{
yield return StartSomeClientsAndServerWithPlayers(useHost: true, nbClients: NbClients,
updatePlayerPrefab: playerPrefab =>
{
var networkTransform = playerPrefab.AddComponent<NetworkShowHideTest>();
m_PrefabToSpawn = PreparePrefab(typeof(ShowHideObject));
});
var networkTransform = m_PlayerPrefab.AddComponent<NetworkShowHideTest>();
}
protected override void OnServerAndClientsCreated()
{
m_PrefabToSpawn = PreparePrefab(typeof(ShowHideObject));
}
public GameObject PreparePrefab(Type type)
@@ -59,7 +59,7 @@ namespace Unity.Netcode.RuntimeTests
var prefabToSpawn = new GameObject();
prefabToSpawn.AddComponent(type);
var networkObjectPrefab = prefabToSpawn.AddComponent<NetworkObject>();
MultiInstanceHelpers.MakeNetworkObjectTestPrefab(networkObjectPrefab);
NetcodeIntegrationTestHelpers.MakeNetworkObjectTestPrefab(networkObjectPrefab);
m_ServerNetworkManager.NetworkConfig.NetworkPrefabs.Add(new NetworkPrefab() { Prefab = prefabToSpawn });
foreach (var clientNetworkManager in m_ClientNetworkManagers)
{
@@ -138,25 +138,22 @@ namespace Unity.Netcode.RuntimeTests
private IEnumerator RefreshNetworkObjects()
{
var serverClientPlayerResult = new MultiInstanceHelpers.CoroutineResultWrapper<NetworkObject>();
yield return MultiInstanceHelpers.Run(
MultiInstanceHelpers.GetNetworkObjectByRepresentation(
var serverClientPlayerResult = new NetcodeIntegrationTestHelpers.ResultWrapper<NetworkObject>();
yield return NetcodeIntegrationTestHelpers.GetNetworkObjectByRepresentation(
x => x.NetworkObjectId == m_NetSpawnedObject1.NetworkObjectId,
m_ClientNetworkManagers[0],
serverClientPlayerResult));
serverClientPlayerResult);
m_Object1OnClient0 = serverClientPlayerResult.Result;
yield return MultiInstanceHelpers.Run(
MultiInstanceHelpers.GetNetworkObjectByRepresentation(
yield return NetcodeIntegrationTestHelpers.GetNetworkObjectByRepresentation(
x => x.NetworkObjectId == m_NetSpawnedObject2.NetworkObjectId,
m_ClientNetworkManagers[0],
serverClientPlayerResult));
serverClientPlayerResult);
m_Object2OnClient0 = serverClientPlayerResult.Result;
serverClientPlayerResult = new MultiInstanceHelpers.CoroutineResultWrapper<NetworkObject>();
yield return MultiInstanceHelpers.Run(
MultiInstanceHelpers.GetNetworkObjectByRepresentation(
serverClientPlayerResult = new NetcodeIntegrationTestHelpers.ResultWrapper<NetworkObject>();
yield return NetcodeIntegrationTestHelpers.GetNetworkObjectByRepresentation(
x => x.NetworkObjectId == m_NetSpawnedObject3.NetworkObjectId,
m_ClientNetworkManagers[0],
serverClientPlayerResult));
serverClientPlayerResult);
m_Object3OnClient0 = serverClientPlayerResult.Result;
// make sure the objects are set with the right network manager

View File

@@ -2,16 +2,17 @@ using System.Collections;
using NUnit.Framework;
using UnityEngine;
using UnityEngine.TestTools;
using Unity.Netcode.TestHelpers.Runtime;
namespace Unity.Netcode.RuntimeTests
{
public class NetworkSpawnManagerTests : BaseMultiInstanceTest
public class NetworkSpawnManagerTests : NetcodeIntegrationTest
{
private ulong serverSideClientId => m_ServerNetworkManager.ServerClientId;
private ulong clientSideClientId => m_ClientNetworkManagers[0].LocalClientId;
private ulong otherClientSideClientId => m_ClientNetworkManagers[1].LocalClientId;
protected override int NbClients => 2;
protected override int NumberOfClients => 2;
[Test]
public void TestServerCanAccessItsOwnPlayer()
@@ -96,7 +97,7 @@ namespace Unity.Netcode.RuntimeTests
// test when client connects, player object is now available
// connect new client
if (!MultiInstanceHelpers.CreateNewClients(1, out NetworkManager[] clients))
if (!NetcodeIntegrationTestHelpers.CreateNewClients(1, out NetworkManager[] clients))
{
Debug.LogError("Failed to create instances");
Assert.Fail("Failed to create instances");
@@ -104,8 +105,8 @@ namespace Unity.Netcode.RuntimeTests
var newClientNetworkManager = clients[0];
newClientNetworkManager.NetworkConfig.PlayerPrefab = m_PlayerPrefab;
newClientNetworkManager.StartClient();
yield return MultiInstanceHelpers.Run(MultiInstanceHelpers.WaitForClientConnected(newClientNetworkManager));
yield return MultiInstanceHelpers.Run(MultiInstanceHelpers.WaitForCondition(() => m_ServerNetworkManager.ConnectedClients.ContainsKey(newClientNetworkManager.LocalClientId)));
yield return NetcodeIntegrationTestHelpers.WaitForClientConnected(newClientNetworkManager);
yield return WaitForConditionOrTimeOut(() => m_ServerNetworkManager.ConnectedClients.ContainsKey(newClientNetworkManager.LocalClientId));
var newClientLocalClientId = newClientNetworkManager.LocalClientId;
// test new client can get that itself locally
@@ -119,8 +120,8 @@ namespace Unity.Netcode.RuntimeTests
// test when client disconnects, player object no longer available.
var nbConnectedClients = m_ServerNetworkManager.ConnectedClients.Count;
MultiInstanceHelpers.StopOneClient(newClientNetworkManager);
yield return MultiInstanceHelpers.Run(MultiInstanceHelpers.WaitForCondition(() => m_ServerNetworkManager.ConnectedClients.Count == nbConnectedClients - 1));
NetcodeIntegrationTestHelpers.StopOneClient(newClientNetworkManager);
yield return WaitForConditionOrTimeOut(() => m_ServerNetworkManager.ConnectedClients.Count == nbConnectedClients - 1);
serverSideNewClientPlayer = m_ServerNetworkManager.SpawnManager.GetPlayerNetworkObject(newClientLocalClientId);
Assert.Null(serverSideNewClientPlayer);

View File

@@ -8,90 +8,92 @@ using NUnit.Framework;
// using Unity.Netcode.Samples;
using UnityEngine;
using UnityEngine.TestTools;
using Unity.Netcode.TestHelpers.Runtime;
namespace Unity.Netcode.RuntimeTests
{
public class NetworkTransformTestComponent : NetworkTransform
{
public bool ReadyToReceivePositionUpdate = false;
public override void OnNetworkSpawn()
{
base.OnNetworkSpawn();
ReadyToReceivePositionUpdate = true;
}
}
// [TestFixture(true, true)]
[TestFixture(true, false)]
// [TestFixture(false, true)]
[TestFixture(false, false)]
public class NetworkTransformTests : BaseMultiInstanceTest
public class NetworkTransformTests : NetcodeIntegrationTest
{
private NetworkObject m_ClientSideClientPlayer;
private NetworkObject m_ServerSideClientPlayer;
private readonly bool m_TestWithClientNetworkTransform;
private readonly bool m_TestWithHost;
public NetworkTransformTests(bool testWithHost, bool testWithClientNetworkTransform)
{
m_TestWithHost = testWithHost; // from test fixture
m_UseHost = testWithHost; // from test fixture
m_TestWithClientNetworkTransform = testWithClientNetworkTransform;
}
protected override int NbClients => 1;
protected override int NumberOfClients => 1;
[UnitySetUp]
public override IEnumerator Setup()
protected override void OnCreatePlayerPrefab()
{
yield return StartSomeClientsAndServerWithPlayers(useHost: m_TestWithHost, nbClients: NbClients, updatePlayerPrefab: playerPrefab =>
if (m_TestWithClientNetworkTransform)
{
if (m_TestWithClientNetworkTransform)
{
// playerPrefab.AddComponent<ClientNetworkTransform>();
}
else
{
playerPrefab.AddComponent<NetworkTransform>();
}
});
// m_PlayerPrefab.AddComponent<ClientNetworkTransform>();
}
else
{
var networkTransform = m_PlayerPrefab.AddComponent<NetworkTransformTestComponent>();
networkTransform.Interpolate = false;
}
}
protected override void OnServerAndClientsCreated()
{
#if NGO_TRANSFORM_DEBUG
// Log assert for writing without authority is a developer log...
// TODO: This is why monolithic test base classes and test helpers are an anti-pattern - this is part of an individual test case setup but is separated from the code verifying it!
m_ServerNetworkManager.LogLevel = LogLevel.Developer;
m_ClientNetworkManagers[0].LogLevel = LogLevel.Developer;
#endif
}
// This is the *SERVER VERSION* of the *CLIENT PLAYER*
var serverClientPlayerResult = new MultiInstanceHelpers.CoroutineResultWrapper<NetworkObject>();
yield return MultiInstanceHelpers.Run(MultiInstanceHelpers.GetNetworkObjectByRepresentation(x => x.IsPlayerObject && x.OwnerClientId == m_ClientNetworkManagers[0].LocalClientId, m_ServerNetworkManager, serverClientPlayerResult));
protected override IEnumerator OnServerAndClientsConnected()
{
// Get the client player representation on both the server and the client side
m_ServerSideClientPlayer = m_PlayerNetworkObjects[m_ServerNetworkManager.LocalClientId][m_ClientNetworkManagers[0].LocalClientId];
m_ClientSideClientPlayer = m_PlayerNetworkObjects[m_ClientNetworkManagers[0].LocalClientId][m_ClientNetworkManagers[0].LocalClientId];
// This is the *CLIENT VERSION* of the *CLIENT PLAYER*
var clientClientPlayerResult = new MultiInstanceHelpers.CoroutineResultWrapper<NetworkObject>();
yield return MultiInstanceHelpers.Run(MultiInstanceHelpers.GetNetworkObjectByRepresentation(x => x.IsPlayerObject && x.OwnerClientId == m_ClientNetworkManagers[0].LocalClientId, m_ClientNetworkManagers[0], clientClientPlayerResult));
// Get the NetworkTransformTestComponent to make sure the client side is ready before starting test
var otherSideNetworkTransformComponent = m_ClientSideClientPlayer.GetComponent<NetworkTransformTestComponent>();
m_ServerSideClientPlayer = serverClientPlayerResult.Result;
m_ClientSideClientPlayer = clientClientPlayerResult.Result;
// Wait for the client-side to notify it is finished initializing and spawning.
yield return WaitForConditionOrTimeOut(() => otherSideNetworkTransformComponent.ReadyToReceivePositionUpdate == true);
Assert.False(s_GlobalTimeoutHelper.TimedOut, "Timed out waiting for client-side to notify it is ready!");
yield return base.OnServerAndClientsConnected();
}
// TODO: rewrite after perms & authority changes
[UnityTest]
public IEnumerator TestAuthoritativeTransformChangeOneAtATime([Values] bool testLocalTransform)
{
var waitResult = new MultiInstanceHelpers.CoroutineResultWrapper<bool>();
// Get the client player's NetworkTransform for both instances
var authoritativeNetworkTransform = m_ServerSideClientPlayer.GetComponent<NetworkTransform>();
var otherSideNetworkTransform = m_ClientSideClientPlayer.GetComponent<NetworkTransform>();
NetworkTransform authoritativeNetworkTransform;
NetworkTransform otherSideNetworkTransform;
// if (m_TestWithClientNetworkTransform)
// {
// // client auth net transform can write from client, not from server
// otherSideNetworkTransform = m_ServerSideClientPlayer.GetComponent<ClientNetworkTransform>();
// authoritativeNetworkTransform = m_ClientSideClientPlayer.GetComponent<ClientNetworkTransform>();
// }
// else
{
// server auth net transform can't write from client, not from client
authoritativeNetworkTransform = m_ServerSideClientPlayer.GetComponent<NetworkTransform>();
otherSideNetworkTransform = m_ClientSideClientPlayer.GetComponent<NetworkTransform>();
}
Assert.That(!otherSideNetworkTransform.CanCommitToTransform);
Assert.That(authoritativeNetworkTransform.CanCommitToTransform);
authoritativeNetworkTransform.Interpolate = false;
otherSideNetworkTransform.Interpolate = false;
if (authoritativeNetworkTransform.CanCommitToTransform)
{
authoritativeNetworkTransform.InLocalSpace = testLocalTransform;
@@ -106,23 +108,25 @@ namespace Unity.Netcode.RuntimeTests
// test position
var authPlayerTransform = authoritativeNetworkTransform.transform;
authPlayerTransform.position = new Vector3(10, 20, 30);
Assert.AreEqual(Vector3.zero, otherSideNetworkTransform.transform.position, "server side pos should be zero at first"); // sanity check
yield return MultiInstanceHelpers.Run(MultiInstanceHelpers.WaitForCondition(() => otherSideNetworkTransform.transform.position.x > approximation, waitResult, maxFrames: 120));
if (!waitResult.Result)
{
throw new Exception("timeout while waiting for position change");
}
authPlayerTransform.position = new Vector3(10, 20, 30);
yield return WaitForConditionOrTimeOut(() => otherSideNetworkTransform.transform.position.x > approximation);
Assert.False(s_GlobalTimeoutHelper.TimedOut, $"timeout while waiting for position change! Otherside value {otherSideNetworkTransform.transform.position.x} vs. Approximation {approximation}");
Assert.True(new Vector3(10, 20, 30) == otherSideNetworkTransform.transform.position, $"wrong position on ghost, {otherSideNetworkTransform.transform.position}"); // Vector3 already does float approximation with ==
// test rotation
authPlayerTransform.rotation = Quaternion.Euler(45, 40, 35); // using euler angles instead of quaternions directly to really see issues users might encounter
Assert.AreEqual(Quaternion.identity, otherSideNetworkTransform.transform.rotation, "wrong initial value for rotation"); // sanity check
yield return MultiInstanceHelpers.Run(MultiInstanceHelpers.WaitForCondition(() => otherSideNetworkTransform.transform.rotation.eulerAngles.x > approximation, waitResult, maxFrames: 120));
if (!waitResult.Result)
{
throw new Exception("timeout while waiting for rotation change");
}
yield return WaitForConditionOrTimeOut(() => otherSideNetworkTransform.transform.rotation.eulerAngles.x > approximation);
Assert.False(s_GlobalTimeoutHelper.TimedOut, "timeout while waiting for rotation change");
// approximation needed here since eulerAngles isn't super precise.
Assert.LessOrEqual(Math.Abs(45 - otherSideNetworkTransform.transform.rotation.eulerAngles.x), approximation, $"wrong rotation on ghost on x, got {otherSideNetworkTransform.transform.rotation.eulerAngles.x}");
Assert.LessOrEqual(Math.Abs(40 - otherSideNetworkTransform.transform.rotation.eulerAngles.y), approximation, $"wrong rotation on ghost on y, got {otherSideNetworkTransform.transform.rotation.eulerAngles.y}");
@@ -133,11 +137,11 @@ namespace Unity.Netcode.RuntimeTests
UnityEngine.Assertions.Assert.AreApproximatelyEqual(1f, otherSideNetworkTransform.transform.lossyScale.y, "wrong initial value for scale"); // sanity check
UnityEngine.Assertions.Assert.AreApproximatelyEqual(1f, otherSideNetworkTransform.transform.lossyScale.z, "wrong initial value for scale"); // sanity check
authPlayerTransform.localScale = new Vector3(2, 3, 4);
yield return MultiInstanceHelpers.Run(MultiInstanceHelpers.WaitForCondition(() => otherSideNetworkTransform.transform.lossyScale.x > 1f + approximation, waitResult, maxFrames: 120));
if (!waitResult.Result)
{
throw new Exception("timeout while waiting for scale change");
}
yield return WaitForConditionOrTimeOut(() => otherSideNetworkTransform.transform.lossyScale.x > 1f + approximation);
Assert.False(s_GlobalTimeoutHelper.TimedOut, "timeout while waiting for scale change");
UnityEngine.Assertions.Assert.AreApproximatelyEqual(2f, otherSideNetworkTransform.transform.lossyScale.x, "wrong scale on ghost");
UnityEngine.Assertions.Assert.AreApproximatelyEqual(3f, otherSideNetworkTransform.transform.lossyScale.y, "wrong scale on ghost");
UnityEngine.Assertions.Assert.AreApproximatelyEqual(4f, otherSideNetworkTransform.transform.lossyScale.z, "wrong scale on ghost");
@@ -147,33 +151,17 @@ namespace Unity.Netcode.RuntimeTests
}
[UnityTest]
// [Ignore("skipping for now, still need to figure weird multiinstance issue with hosts")]
public IEnumerator TestCantChangeTransformFromOtherSideAuthority([Values] bool testClientAuthority)
{
// test server can't change client authoritative transform
NetworkTransform authoritativeNetworkTransform;
NetworkTransform otherSideNetworkTransform;
// if (m_TestWithClientNetworkTransform)
// {
// // client auth net transform can write from client, not from server
// otherSideNetworkTransform = m_ServerSideClientPlayer.GetComponent<ClientNetworkTransform>();
// authoritativeNetworkTransform = m_ClientSideClientPlayer.GetComponent<ClientNetworkTransform>();
// }
// else
{
// server auth net transform can't write from client, not from client
authoritativeNetworkTransform = m_ServerSideClientPlayer.GetComponent<NetworkTransform>();
otherSideNetworkTransform = m_ClientSideClientPlayer.GetComponent<NetworkTransform>();
}
authoritativeNetworkTransform.Interpolate = false;
otherSideNetworkTransform.Interpolate = false;
// Get the client player's NetworkTransform for both instances
var authoritativeNetworkTransform = m_ServerSideClientPlayer.GetComponent<NetworkTransform>();
var otherSideNetworkTransform = m_ClientSideClientPlayer.GetComponent<NetworkTransform>();
Assert.AreEqual(Vector3.zero, otherSideNetworkTransform.transform.position, "other side pos should be zero at first"); // sanity check
otherSideNetworkTransform.transform.position = new Vector3(4, 5, 6);
yield return null; // one frame
yield return s_DefaultWaitForTick;
Assert.AreEqual(Vector3.zero, otherSideNetworkTransform.transform.position, "got authority error, but other side still moved!");
#if NGO_TRANSFORM_DEBUG
@@ -190,12 +178,10 @@ namespace Unity.Netcode.RuntimeTests
* test teleport without interpolation
* test dynamic spawning
*/
[UnityTearDown]
public override IEnumerator Teardown()
protected override IEnumerator OnTearDown()
{
yield return base.Teardown();
UnityEngine.Object.DestroyImmediate(m_PlayerPrefab);
yield return base.OnTearDown();
}
}
}

View File

@@ -1,10 +1,12 @@
using System.Collections;
using System.Collections.Generic;
using NUnit.Framework;
using UnityEngine.TestTools;
using Unity.Netcode.TestHelpers.Runtime;
namespace Unity.Netcode.RuntimeTests
{
public class NetworkVarBufferCopyTest : BaseMultiInstanceTest
public class NetworkVarBufferCopyTest : NetcodeIntegrationTest
{
public class DummyNetVar : NetworkVariableBase
{
@@ -13,7 +15,7 @@ namespace Unity.Netcode.RuntimeTests
public bool FieldWritten;
public bool DeltaRead;
public bool FieldRead;
public bool Dirty = true;
public bool Dirty = false;
public override void ResetDirty()
{
@@ -80,56 +82,88 @@ namespace Unity.Netcode.RuntimeTests
public class DummyNetBehaviour : NetworkBehaviour
{
public DummyNetVar NetVar;
}
protected override int NbClients => 1;
public DummyNetVar NetVar = new DummyNetVar();
[UnitySetUp]
public override IEnumerator Setup()
{
yield return StartSomeClientsAndServerWithPlayers(useHost: true, nbClients: NbClients,
updatePlayerPrefab: playerPrefab =>
public override void OnNetworkSpawn()
{
if (!IsServer)
{
var dummyNetBehaviour = playerPrefab.AddComponent<DummyNetBehaviour>();
});
ClientDummyNetBehaviourSpawned(this);
}
base.OnNetworkSpawn();
}
}
protected override int NumberOfClients => 1;
private static List<DummyNetBehaviour> s_ClientDummyNetBehavioursSpawned = new List<DummyNetBehaviour>();
public static void ClientDummyNetBehaviourSpawned(DummyNetBehaviour dummyNetBehaviour)
{
s_ClientDummyNetBehavioursSpawned.Add(dummyNetBehaviour);
}
protected override IEnumerator OnSetup()
{
s_ClientDummyNetBehavioursSpawned.Clear();
return base.OnSetup();
}
protected override void OnCreatePlayerPrefab()
{
m_PlayerPrefab.AddComponent<DummyNetBehaviour>();
}
[UnityTest]
public IEnumerator TestEntireBufferIsCopiedOnNetworkVariableDelta()
{
// This is the *SERVER VERSION* of the *CLIENT PLAYER*
var serverClientPlayerResult = new MultiInstanceHelpers.CoroutineResultWrapper<NetworkObject>();
yield return MultiInstanceHelpers.Run(MultiInstanceHelpers.GetNetworkObjectByRepresentation(
var serverClientPlayerResult = new NetcodeIntegrationTestHelpers.ResultWrapper<NetworkObject>();
yield return NetcodeIntegrationTestHelpers.GetNetworkObjectByRepresentation(
x => x.IsPlayerObject && x.OwnerClientId == m_ClientNetworkManagers[0].LocalClientId,
m_ServerNetworkManager, serverClientPlayerResult));
// This is the *CLIENT VERSION* of the *CLIENT PLAYER*
var clientClientPlayerResult = new MultiInstanceHelpers.CoroutineResultWrapper<NetworkObject>();
yield return MultiInstanceHelpers.Run(MultiInstanceHelpers.GetNetworkObjectByRepresentation(
x => x.IsPlayerObject && x.OwnerClientId == m_ClientNetworkManagers[0].LocalClientId,
m_ClientNetworkManagers[0], clientClientPlayerResult));
m_ServerNetworkManager, serverClientPlayerResult);
var serverSideClientPlayer = serverClientPlayerResult.Result;
var serverComponent = serverSideClientPlayer.GetComponent<DummyNetBehaviour>();
// This is the *CLIENT VERSION* of the *CLIENT PLAYER*
var clientClientPlayerResult = new NetcodeIntegrationTestHelpers.ResultWrapper<NetworkObject>();
yield return NetcodeIntegrationTestHelpers.GetNetworkObjectByRepresentation(
x => x.IsPlayerObject && x.OwnerClientId == m_ClientNetworkManagers[0].LocalClientId,
m_ClientNetworkManagers[0], clientClientPlayerResult);
var clientSideClientPlayer = clientClientPlayerResult.Result;
var clientComponent = clientSideClientPlayer.GetComponent<DummyNetBehaviour>();
var serverComponent = (serverSideClientPlayer).GetComponent<DummyNetBehaviour>();
var clientComponent = (clientSideClientPlayer).GetComponent<DummyNetBehaviour>();
// Wait for the DummyNetBehaviours on the client side to notify they have been initialized and spawned
yield return WaitForConditionOrTimeOut(() => s_ClientDummyNetBehavioursSpawned.Count >= 1);
Assert.IsFalse(s_GlobalTimeoutHelper.TimedOut, "Timed out waiting for client side DummyNetBehaviour to register it was spawned!");
var waitResult = new MultiInstanceHelpers.CoroutineResultWrapper<bool>();
yield return MultiInstanceHelpers.Run(MultiInstanceHelpers.WaitForCondition(
() => clientComponent.NetVar.DeltaRead == true,
waitResult,
maxFrames: 120));
if (!waitResult.Result)
{
Assert.Fail("Failed to send a delta within 120 frames");
}
// Check that FieldWritten is written when dirty
serverComponent.NetVar.Dirty = true;
yield return s_DefaultWaitForTick;
Assert.True(serverComponent.NetVar.FieldWritten);
// Check that DeltaWritten is written when dirty
serverComponent.NetVar.Dirty = true;
yield return s_DefaultWaitForTick;
Assert.True(serverComponent.NetVar.DeltaWritten);
Assert.True(clientComponent.NetVar.FieldRead);
Assert.True(clientComponent.NetVar.DeltaRead);
// Check that both FieldRead and DeltaRead were invoked on the client side
yield return WaitForConditionOrTimeOut(() => clientComponent.NetVar.FieldRead == true && clientComponent.NetVar.DeltaRead == true);
var timedOutMessage = "Timed out waiting for client reads: ";
if (s_GlobalTimeoutHelper.TimedOut)
{
if (!clientComponent.NetVar.FieldRead)
{
timedOutMessage += "[FieldRead]";
}
if (!clientComponent.NetVar.DeltaRead)
{
timedOutMessage += "[DeltaRead]";
}
}
Assert.IsFalse(s_GlobalTimeoutHelper.TimedOut, timedOutMessage);
}
}
}

View File

@@ -1,13 +1,15 @@
using System;
using System.Collections;
using UnityEngine;
using System.Collections.Generic;
using UnityEngine.TestTools;
using NUnit.Framework;
using Unity.Collections;
using Unity.Netcode.TestHelpers.Runtime;
using Random = UnityEngine.Random;
namespace Unity.Netcode.RuntimeTests
{
public struct TestStruct : INetworkSerializable
public struct TestStruct : INetworkSerializable, IEquatable<TestStruct>
{
public uint SomeInt;
public bool SomeBool;
@@ -27,12 +29,31 @@ namespace Unity.Netcode.RuntimeTests
serializer.SerializeValue(ref SomeInt);
serializer.SerializeValue(ref SomeBool);
}
public bool Equals(TestStruct other)
{
return SomeInt == other.SomeInt && SomeBool == other.SomeBool;
}
public override bool Equals(object obj)
{
return obj is TestStruct other && Equals(other);
}
public override int GetHashCode()
{
unchecked
{
return ((int)SomeInt * 397) ^ SomeBool.GetHashCode();
}
}
}
public class NetworkVariableTest : NetworkBehaviour
{
public readonly NetworkVariable<int> TheScalar = new NetworkVariable<int>();
public readonly NetworkList<int> TheList = new NetworkList<int>();
public readonly NetworkList<FixedString128Bytes> TheLargeList = new NetworkList<FixedString128Bytes>();
public readonly NetworkVariable<FixedString32Bytes> FixedString32 = new NetworkVariable<FixedString32Bytes>();
@@ -47,14 +68,26 @@ namespace Unity.Netcode.RuntimeTests
}
public readonly NetworkVariable<TestStruct> TheStruct = new NetworkVariable<TestStruct>();
public readonly NetworkList<TestStruct> TheListOfStructs = new NetworkList<TestStruct>();
public bool ListDelegateTriggered;
public override void OnNetworkSpawn()
{
if (!IsServer)
{
NetworkVariableTests.ClientNetworkVariableTestSpawned(this);
}
base.OnNetworkSpawn();
}
}
public class NetworkVariableTests : BaseMultiInstanceTest
[TestFixture(true)]
[TestFixture(false)]
public class NetworkVariableTests : NetcodeIntegrationTest
{
private const string k_FixedStringTestValue = "abcdefghijklmnopqrstuvwxyz";
protected override int NbClients => 2;
protected override int NumberOfClients => 2;
private const uint k_TestUInt = 0x12345678;
@@ -64,36 +97,72 @@ namespace Unity.Netcode.RuntimeTests
private const int k_TestKey1 = 0x0f0f;
private static List<NetworkVariableTest> s_ClientNetworkVariableTestInstances = new List<NetworkVariableTest>();
public static void ClientNetworkVariableTestSpawned(NetworkVariableTest networkVariableTest)
{
s_ClientNetworkVariableTestInstances.Add(networkVariableTest);
}
// Player1 component on the server
private NetworkVariableTest m_Player1OnServer;
// Player1 component on client1
private NetworkVariableTest m_Player1OnClient1;
private bool m_TestWithHost;
private NetworkListTestPredicate m_NetworkListPredicateHandler;
[UnitySetUp]
public override IEnumerator Setup()
private bool m_EnsureLengthSafety;
public NetworkVariableTests(bool ensureLengthSafety)
{
yield return StartSomeClientsAndServerWithPlayers(useHost: m_TestWithHost, nbClients: NbClients,
updatePlayerPrefab: playerPrefab =>
{
playerPrefab.AddComponent<NetworkVariableTest>();
});
m_EnsureLengthSafety = ensureLengthSafety;
}
protected override bool CanStartServerAndClients()
{
return false;
}
/// <summary>
/// This is an adjustment to how the server and clients are started in order
/// to avoid timing issues when running in a stand alone test runner build.
/// </summary>
private IEnumerator InitializeServerAndClients(bool useHost)
{
s_ClientNetworkVariableTestInstances.Clear();
m_PlayerPrefab.AddComponent<NetworkVariableTest>();
m_ServerNetworkManager.NetworkConfig.EnsureNetworkVariableLengthSafety = m_EnsureLengthSafety;
m_ServerNetworkManager.NetworkConfig.PlayerPrefab = m_PlayerPrefab;
foreach (var client in m_ClientNetworkManagers)
{
client.NetworkConfig.EnsureNetworkVariableLengthSafety = m_EnsureLengthSafety;
client.NetworkConfig.PlayerPrefab = m_PlayerPrefab;
}
Assert.True(NetcodeIntegrationTestHelpers.Start(useHost, m_ServerNetworkManager, m_ClientNetworkManagers), "Failed to start server and client instances");
RegisterSceneManagerHandler();
// Wait for connection on client and server side
yield return WaitForClientsConnectedOrTimeOut();
// These are the *SERVER VERSIONS* of the *CLIENT PLAYER 1 & 2*
var result = new MultiInstanceHelpers.CoroutineResultWrapper<NetworkObject>();
var result = new NetcodeIntegrationTestHelpers.ResultWrapper<NetworkObject>();
yield return MultiInstanceHelpers.Run(MultiInstanceHelpers.GetNetworkObjectByRepresentation(
yield return NetcodeIntegrationTestHelpers.GetNetworkObjectByRepresentation(
x => x.IsPlayerObject && x.OwnerClientId == m_ClientNetworkManagers[0].LocalClientId,
m_ServerNetworkManager, result));
m_ServerNetworkManager, result);
// Assign server-side client's player
m_Player1OnServer = result.Result.GetComponent<NetworkVariableTest>();
// This is client1's view of itself
yield return MultiInstanceHelpers.Run(MultiInstanceHelpers.GetNetworkObjectByRepresentation(
yield return NetcodeIntegrationTestHelpers.GetNetworkObjectByRepresentation(
x => x.IsPlayerObject && x.OwnerClientId == m_ClientNetworkManagers[0].LocalClientId,
m_ClientNetworkManagers[0], result));
m_ClientNetworkManagers[0], result);
// Assign client-side local player
m_Player1OnClient1 = result.Result.GetComponent<NetworkVariableTest>();
m_Player1OnServer.TheList.Clear();
@@ -106,6 +175,14 @@ namespace Unity.Netcode.RuntimeTests
{
throw new Exception("at least one client network container not empty at start");
}
var instanceCount = useHost ? NumberOfClients * 3 : NumberOfClients * 2;
// Wait for the client-side to notify it is finished initializing and spawning.
yield return WaitForConditionOrTimeOut(() => s_ClientNetworkVariableTestInstances.Count == instanceCount);
Assert.False(s_GlobalTimeoutHelper.TimedOut, "Timed out waiting for all client NetworkVariableTest instances to register they have spawned!");
yield return s_DefaultWaitForTick;
}
/// <summary>
@@ -114,13 +191,13 @@ namespace Unity.Netcode.RuntimeTests
[UnityTest]
public IEnumerator AllNetworkVariableTypes([Values(true, false)] bool useHost)
{
m_TestWithHost = useHost;
// Create, instantiate, and host
// This would normally go in Setup, but since every other test but this one
// uses MultiInstanceHelper, and it does its own NetworkManager setup / teardown,
// uses NetworkManagerHelper, and it does its own NetworkManager setup / teardown,
// for now we put this within this one test until we migrate it to MIH
Assert.IsTrue(NetworkManagerHelper.StartNetworkManager(out _));
Assert.IsTrue(NetworkManagerHelper.StartNetworkManager(out NetworkManager server, useHost ? NetworkManagerHelper.NetworkManagerOperatingMode.Host : NetworkManagerHelper.NetworkManagerOperatingMode.Server));
Assert.IsTrue(server.IsHost == useHost, $"{nameof(useHost)} does not match the server.IsHost value!");
Guid gameObjectId = NetworkManagerHelper.AddGameNetworkObject("NetworkVariableTestComponent");
@@ -131,14 +208,8 @@ namespace Unity.Netcode.RuntimeTests
// Start Testing
networkVariableTestComponent.EnableTesting = true;
var testsAreComplete = networkVariableTestComponent.IsTestComplete();
// Wait for the NetworkVariable tests to complete
while (!testsAreComplete)
{
yield return new WaitForSeconds(0.003f);
testsAreComplete = networkVariableTestComponent.IsTestComplete();
}
yield return WaitForConditionOrTimeOut(() => true == networkVariableTestComponent.IsTestComplete());
Assert.IsFalse(s_GlobalTimeoutHelper.TimedOut, "Timed out waiting for the test to complete!");
// Stop Testing
networkVariableTestComponent.EnableTesting = false;
@@ -148,18 +219,16 @@ namespace Unity.Netcode.RuntimeTests
// Disable this once we are done.
networkVariableTestComponent.gameObject.SetActive(false);
Assert.IsTrue(testsAreComplete);
// This would normally go in Teardown, but since every other test but this one
// uses MultiInstanceHelper, and it does its own NetworkManager setup / teardown,
// uses NetworkManagerHelper, and it does its own NetworkManager setup / teardown,
// for now we put this within this one test until we migrate it to MIH
NetworkManagerHelper.ShutdownNetworkManager();
}
[Test]
public void ClientWritePermissionTest([Values(true, false)] bool useHost)
[UnityTest]
public IEnumerator ClientWritePermissionTest([Values(true, false)] bool useHost)
{
m_TestWithHost = useHost;
yield return InitializeServerAndClients(useHost);
// client must not be allowed to write to a server auth variable
Assert.Throws<InvalidOperationException>(() => m_Player1OnClient1.TheScalar.Value = k_TestVal1);
@@ -168,222 +237,186 @@ namespace Unity.Netcode.RuntimeTests
[UnityTest]
public IEnumerator FixedString32Test([Values(true, false)] bool useHost)
{
m_TestWithHost = useHost;
yield return MultiInstanceHelpers.RunAndWaitForCondition(
() =>
{
m_Player1OnServer.FixedString32.Value = k_FixedStringTestValue;
yield return InitializeServerAndClients(useHost);
m_Player1OnServer.FixedString32.Value = k_FixedStringTestValue;
// we are writing to the private and public variables on player 1's object...
},
() =>
{
// ...and we should see the writes to the private var only on the server & the owner,
// but the public variable everywhere
return
m_Player1OnClient1.FixedString32.Value == k_FixedStringTestValue;
}
);
// Now wait for the client side version to be updated to k_FixedStringTestValue
yield return WaitForConditionOrTimeOut(() => m_Player1OnClient1.FixedString32.Value == k_FixedStringTestValue);
Assert.IsFalse(s_GlobalTimeoutHelper.TimedOut, "Timed out waiting for client-side NetworkVariable to update!");
}
[UnityTest]
public IEnumerator NetworkListAdd([Values(true, false)] bool useHost)
{
m_TestWithHost = useHost;
yield return MultiInstanceHelpers.RunAndWaitForCondition(
() =>
{
m_Player1OnServer.TheList.Add(k_TestVal1);
m_Player1OnServer.TheList.Add(k_TestVal2);
},
() =>
{
return m_Player1OnServer.TheList.Count == 2 &&
m_Player1OnClient1.TheList.Count == 2 &&
m_Player1OnServer.ListDelegateTriggered &&
m_Player1OnClient1.ListDelegateTriggered &&
m_Player1OnServer.TheList[0] == k_TestVal1 &&
m_Player1OnClient1.TheList[0] == k_TestVal1 &&
m_Player1OnServer.TheList[1] == k_TestVal2 &&
m_Player1OnClient1.TheList[1] == k_TestVal2;
}
);
yield return InitializeServerAndClients(useHost);
m_NetworkListPredicateHandler = new NetworkListTestPredicate(m_Player1OnServer, m_Player1OnClient1, NetworkListTestPredicate.NetworkListTestStates.Add, 10);
yield return WaitForConditionOrTimeOut(m_NetworkListPredicateHandler);
}
[UnityTest]
public IEnumerator WhenListContainsManyLargeValues_OverflowExceptionIsNotThrown([Values(true, false)] bool useHost)
{
yield return InitializeServerAndClients(useHost);
m_NetworkListPredicateHandler = new NetworkListTestPredicate(m_Player1OnServer, m_Player1OnClient1, NetworkListTestPredicate.NetworkListTestStates.ContainsLarge, 20);
yield return WaitForConditionOrTimeOut(m_NetworkListPredicateHandler);
}
[UnityTest]
public IEnumerator NetworkListContains([Values(true, false)] bool useHost)
{
m_TestWithHost = useHost;
yield return MultiInstanceHelpers.RunAndWaitForCondition(
() =>
{
m_Player1OnServer.TheList.Add(k_TestVal1);
},
() =>
{
return m_Player1OnServer.TheList.Count == 1 &&
m_Player1OnClient1.TheList.Count == 1 &&
m_Player1OnServer.TheList.Contains(k_TestVal1) &&
m_Player1OnClient1.TheList.Contains(k_TestVal1);
}
);
// Re-use the NetworkListAdd to initialize the server and client as well as make sure the list is populated
yield return NetworkListAdd(useHost);
// Now test the NetworkList.Contains method
m_NetworkListPredicateHandler.SetNetworkListTestState(NetworkListTestPredicate.NetworkListTestStates.Contains);
yield return WaitForConditionOrTimeOut(m_NetworkListPredicateHandler);
}
[UnityTest]
public IEnumerator NetworkListRemoveValue([Values(true, false)] bool useHost)
public IEnumerator NetworkListRemove([Values(true, false)] bool useHost)
{
m_TestWithHost = useHost;
yield return MultiInstanceHelpers.RunAndWaitForCondition(
() =>
{
m_Player1OnServer.TheList.Add(k_TestVal1);
m_Player1OnServer.TheList.Add(k_TestVal2);
m_Player1OnServer.TheList.Add(k_TestVal3);
m_Player1OnServer.TheList.Remove(k_TestVal2);
},
() =>
{
return m_Player1OnServer.TheList.Count == 2 &&
m_Player1OnClient1.TheList.Count == 2 &&
m_Player1OnServer.TheList[0] == k_TestVal1 &&
m_Player1OnClient1.TheList[0] == k_TestVal1 &&
m_Player1OnServer.TheList[1] == k_TestVal3 &&
m_Player1OnClient1.TheList[1] == k_TestVal3;
}
);
// Re-use the NetworkListAdd to initialize the server and client as well as make sure the list is populated
yield return NetworkListAdd(useHost);
// Remove two entries by index
m_Player1OnServer.TheList.Remove(3);
m_Player1OnServer.TheList.Remove(5);
// Really just verifies the data at this point
m_NetworkListPredicateHandler.SetNetworkListTestState(NetworkListTestPredicate.NetworkListTestStates.VerifyData);
yield return WaitForConditionOrTimeOut(m_NetworkListPredicateHandler);
}
[UnityTest]
public IEnumerator NetworkListInsert([Values(true, false)] bool useHost)
{
m_TestWithHost = useHost;
yield return MultiInstanceHelpers.RunAndWaitForCondition(
() =>
{
m_Player1OnServer.TheList.Add(k_TestVal1);
m_Player1OnServer.TheList.Add(k_TestVal2);
m_Player1OnServer.TheList.Insert(1, k_TestVal3);
},
() =>
{
return m_Player1OnServer.TheList.Count == 3 &&
m_Player1OnClient1.TheList.Count == 3 &&
m_Player1OnServer.ListDelegateTriggered &&
m_Player1OnClient1.ListDelegateTriggered &&
m_Player1OnServer.TheList[0] == k_TestVal1 &&
m_Player1OnClient1.TheList[0] == k_TestVal1 &&
m_Player1OnServer.TheList[1] == k_TestVal3 &&
m_Player1OnClient1.TheList[1] == k_TestVal3 &&
m_Player1OnServer.TheList[2] == k_TestVal2 &&
m_Player1OnClient1.TheList[2] == k_TestVal2;
}
);
// Re-use the NetworkListAdd to initialize the server and client as well as make sure the list is populated
yield return NetworkListAdd(useHost);
// Now randomly insert a random value entry
m_Player1OnServer.TheList.Insert(Random.Range(0, 9), Random.Range(1, 99));
// Verify the element count and values on the client matches the server
m_NetworkListPredicateHandler.SetNetworkListTestState(NetworkListTestPredicate.NetworkListTestStates.VerifyData);
yield return WaitForConditionOrTimeOut(m_NetworkListPredicateHandler);
}
[UnityTest]
public IEnumerator NetworkListIndexOf([Values(true, false)] bool useHost)
{
m_TestWithHost = useHost;
yield return MultiInstanceHelpers.RunAndWaitForCondition(
() =>
{
m_Player1OnServer.TheList.Add(k_TestVal1);
m_Player1OnServer.TheList.Add(k_TestVal2);
m_Player1OnServer.TheList.Add(k_TestVal3);
},
() =>
{
return m_Player1OnServer.TheList.IndexOf(k_TestVal1) == 0 &&
m_Player1OnClient1.TheList.IndexOf(k_TestVal1) == 0 &&
m_Player1OnServer.TheList.IndexOf(k_TestVal2) == 1 &&
m_Player1OnClient1.TheList.IndexOf(k_TestVal2) == 1 &&
m_Player1OnServer.TheList.IndexOf(k_TestVal3) == 2 &&
m_Player1OnClient1.TheList.IndexOf(k_TestVal3) == 2;
}
);
}
// Re-use the NetworkListAdd to initialize the server and client as well as make sure the list is populated
yield return NetworkListAdd(useHost);
[UnityTest]
public IEnumerator NetworkListArrayOperator([Values(true, false)] bool useHost)
{
m_TestWithHost = useHost;
yield return MultiInstanceHelpers.RunAndWaitForCondition(
() =>
{
m_Player1OnServer.TheList.Add(k_TestVal3);
m_Player1OnServer.TheList.Add(k_TestVal3);
m_Player1OnServer.TheList[0] = k_TestVal1;
m_Player1OnServer.TheList[1] = k_TestVal2;
},
() =>
{
return m_Player1OnServer.TheList.Count == 2 &&
m_Player1OnClient1.TheList.Count == 2 &&
m_Player1OnServer.TheList[0] == k_TestVal1 &&
m_Player1OnClient1.TheList[0] == k_TestVal1 &&
m_Player1OnServer.TheList[1] == k_TestVal2 &&
m_Player1OnClient1.TheList[1] == k_TestVal2;
}
);
m_NetworkListPredicateHandler.SetNetworkListTestState(NetworkListTestPredicate.NetworkListTestStates.IndexOf);
yield return WaitForConditionOrTimeOut(m_NetworkListPredicateHandler);
}
[UnityTest]
public IEnumerator NetworkListValueUpdate([Values(true, false)] bool useHost)
{
m_TestWithHost = useHost;
yield return MultiInstanceHelpers.RunAndWaitForCondition(
() =>
{
m_Player1OnServer.TheList.Add(k_TestVal1);
},
() =>
{
return m_Player1OnServer.TheList.Count == 1 &&
m_Player1OnClient1.TheList.Count == 1 &&
m_Player1OnServer.TheList[0] == k_TestVal1 &&
m_Player1OnClient1.TheList[0] == k_TestVal1;
}
);
var testSucceeded = false;
yield return InitializeServerAndClients(useHost);
// Add 1 element value and verify it is the same on the client
m_NetworkListPredicateHandler = new NetworkListTestPredicate(m_Player1OnServer, m_Player1OnClient1, NetworkListTestPredicate.NetworkListTestStates.Add, 1);
yield return WaitForConditionOrTimeOut(m_NetworkListPredicateHandler);
// Setup our original and
var previousValue = m_Player1OnServer.TheList[0];
var updatedValue = previousValue + 10;
// Callback that verifies the changed event occurred and that the original and new values are correct
void TestValueUpdatedCallback(NetworkListEvent<int> changedEvent)
{
testSucceeded = changedEvent.PreviousValue == k_TestVal1 &&
changedEvent.Value == k_TestVal3;
testSucceeded = changedEvent.PreviousValue == previousValue &&
changedEvent.Value == updatedValue;
}
try
{
yield return MultiInstanceHelpers.RunAndWaitForCondition(
() =>
{
m_Player1OnServer.TheList[0] = k_TestVal3;
m_Player1OnClient1.TheList.OnListChanged += TestValueUpdatedCallback;
},
() =>
{
return m_Player1OnServer.TheList.Count == 1 &&
m_Player1OnClient1.TheList.Count == 1 &&
m_Player1OnServer.TheList[0] == k_TestVal3 &&
m_Player1OnClient1.TheList[0] == k_TestVal3;
}
);
}
finally
{
m_Player1OnClient1.TheList.OnListChanged -= TestValueUpdatedCallback;
}
// Subscribe to the OnListChanged event on the client side and
m_Player1OnClient1.TheList.OnListChanged += TestValueUpdatedCallback;
m_Player1OnServer.TheList[0] = updatedValue;
// Wait until we know the client side matches the server side before checking if the callback was a success
m_NetworkListPredicateHandler.SetNetworkListTestState(NetworkListTestPredicate.NetworkListTestStates.VerifyData);
yield return WaitForConditionOrTimeOut(m_NetworkListPredicateHandler);
Assert.That(testSucceeded);
m_Player1OnClient1.TheList.OnListChanged -= TestValueUpdatedCallback;
}
[Test]
public void NetworkListIEnumerator([Values(true, false)] bool useHost)
[UnityTest]
public IEnumerator NetworkListRemoveAt([Values(true, false)] bool useHost)
{
m_TestWithHost = useHost;
// Re-use the NetworkListAdd to initialize the server and client as well as make sure the list is populated
yield return NetworkListAdd(useHost);
// Randomly remove a few entries
m_Player1OnServer.TheList.RemoveAt(Random.Range(0, m_Player1OnServer.TheList.Count - 1));
m_Player1OnServer.TheList.RemoveAt(Random.Range(0, m_Player1OnServer.TheList.Count - 1));
m_Player1OnServer.TheList.RemoveAt(Random.Range(0, m_Player1OnServer.TheList.Count - 1));
// Verify the element count and values on the client matches the server
m_NetworkListPredicateHandler.SetNetworkListTestState(NetworkListTestPredicate.NetworkListTestStates.VerifyData);
yield return WaitForConditionOrTimeOut(m_NetworkListPredicateHandler);
}
[UnityTest]
public IEnumerator NetworkListClear([Values(true, false)] bool useHost)
{
// Re-use the NetworkListAdd to initialize the server and client as well as make sure the list is populated
yield return NetworkListAdd(useHost);
m_Player1OnServer.TheList.Clear();
// Verify the element count and values on the client matches the server
m_NetworkListPredicateHandler.SetNetworkListTestState(NetworkListTestPredicate.NetworkListTestStates.VerifyData);
yield return WaitForConditionOrTimeOut(m_NetworkListPredicateHandler);
}
[UnityTest]
public IEnumerator TestNetworkVariableStruct([Values(true, false)] bool useHost)
{
yield return InitializeServerAndClients(useHost);
bool VerifyStructure()
{
return m_Player1OnClient1.TheStruct.Value.SomeBool == m_Player1OnServer.TheStruct.Value.SomeBool &&
m_Player1OnClient1.TheStruct.Value.SomeInt == m_Player1OnServer.TheStruct.Value.SomeInt;
}
m_Player1OnServer.TheStruct.Value = new TestStruct() { SomeInt = k_TestUInt, SomeBool = false };
m_Player1OnServer.TheStruct.SetDirty(true);
// Wait for the client-side to notify it is finished initializing and spawning.
yield return WaitForConditionOrTimeOut(VerifyStructure);
}
[UnityTest]
public IEnumerator TestINetworkSerializableCallsNetworkSerialize([Values(true, false)] bool useHost)
{
yield return InitializeServerAndClients(useHost);
TestStruct.NetworkSerializeCalledOnWrite = false;
TestStruct.NetworkSerializeCalledOnRead = false;
m_Player1OnServer.TheStruct.Value = new TestStruct() { SomeInt = k_TestUInt, SomeBool = false };
static bool VerifyCallback() => TestStruct.NetworkSerializeCalledOnWrite && TestStruct.NetworkSerializeCalledOnRead;
// Wait for the client-side to notify it is finished initializing and spawning.
yield return WaitForConditionOrTimeOut(VerifyCallback);
}
#region COULD_BE_REMOVED
[UnityTest]
[Ignore("This is used several times already in the NetworkListPredicate")]
// TODO: If we end up using the new suggested pattern, then delete this
public IEnumerator NetworkListArrayOperator([Values(true, false)] bool useHost)
{
yield return NetworkListAdd(useHost);
}
[UnityTest]
[Ignore("This is used several times already in the NetworkListPredicate")]
// TODO: If we end up using the new suggested pattern, then delete this
public IEnumerator NetworkListIEnumerator([Values(true, false)] bool useHost)
{
yield return InitializeServerAndClients(useHost);
var correctVals = new int[3];
correctVals[0] = k_TestVal1;
correctVals[1] = k_TestVal2;
@@ -404,99 +437,184 @@ namespace Unity.Netcode.RuntimeTests
}
}
}
#endregion
[UnityTest]
public IEnumerator NetworkListRemoveAt([Values(true, false)] bool useHost)
protected override IEnumerator OnTearDown()
{
m_TestWithHost = useHost;
m_NetworkListPredicateHandler = null;
yield return base.OnTearDown();
}
}
yield return MultiInstanceHelpers.RunAndWaitForCondition(
() =>
{
m_Player1OnServer.TheList.Add(k_TestVal1);
m_Player1OnServer.TheList.Add(k_TestVal2);
m_Player1OnServer.TheList.Add(k_TestVal3);
m_Player1OnServer.TheList.RemoveAt(1);
},
() =>
{
return m_Player1OnServer.TheList.Count == 2 &&
m_Player1OnClient1.TheList.Count == 2 &&
m_Player1OnServer.TheList[0] == k_TestVal1 &&
m_Player1OnClient1.TheList[0] == k_TestVal1 &&
m_Player1OnServer.TheList[1] == k_TestVal3 &&
m_Player1OnClient1.TheList[1] == k_TestVal3;
}
);
/// <summary>
/// Handles the more generic conditional logic for NetworkList tests
/// which can be used with the <see cref="NetcodeIntegrationTest.WaitForConditionOrTimeOut"/>
/// that accepts anything derived from the <see cref="ConditionalPredicateBase"/> class
/// as a parameter.
/// </summary>
public class NetworkListTestPredicate : ConditionalPredicateBase
{
private const int k_MaxRandomValue = 1000;
private Dictionary<NetworkListTestStates, Func<bool>> m_StateFunctions;
// Player1 component on the Server
private NetworkVariableTest m_Player1OnServer;
// Player1 component on client1
private NetworkVariableTest m_Player1OnClient1;
private string m_TestStageFailedMessage;
public enum NetworkListTestStates
{
Add,
ContainsLarge,
Contains,
VerifyData,
IndexOf,
}
[UnityTest]
public IEnumerator NetworkListClear([Values(true, false)] bool useHost)
private NetworkListTestStates m_NetworkListTestState;
public void SetNetworkListTestState(NetworkListTestStates networkListTestState)
{
m_TestWithHost = useHost;
// first put some stuff in; re-use the add test
yield return NetworkListAdd(useHost);
yield return MultiInstanceHelpers.RunAndWaitForCondition(
() => m_Player1OnServer.TheList.Clear(),
() =>
{
return
m_Player1OnServer.ListDelegateTriggered &&
m_Player1OnClient1.ListDelegateTriggered &&
m_Player1OnServer.TheList.Count == 0 &&
m_Player1OnClient1.TheList.Count == 0;
}
);
m_NetworkListTestState = networkListTestState;
}
[UnityTest]
public IEnumerator TestNetworkVariableStruct([Values(true, false)] bool useHost)
/// <summary>
/// Determines if the condition has been reached for the current NetworkListTestState
/// </summary>
protected override bool OnHasConditionBeenReached()
{
m_TestWithHost = useHost;
yield return MultiInstanceHelpers.RunAndWaitForCondition(
() =>
{
m_Player1OnServer.TheStruct.Value =
new TestStruct() { SomeInt = k_TestUInt, SomeBool = false };
m_Player1OnServer.TheStruct.SetDirty(true);
},
() =>
{
return
m_Player1OnClient1.TheStruct.Value.SomeBool == false &&
m_Player1OnClient1.TheStruct.Value.SomeInt == k_TestUInt;
}
);
var isStateRegistered = m_StateFunctions.ContainsKey(m_NetworkListTestState);
Assert.IsTrue(isStateRegistered);
return m_StateFunctions[m_NetworkListTestState].Invoke();
}
[UnityTest]
public IEnumerator TestINetworkSerializableCallsNetworkSerialize([Values(true, false)] bool useHost)
/// <summary>
/// Provides all information about the players for both sides for simplicity and informative sake.
/// </summary>
/// <returns></returns>
private string ConditionFailedInfo()
{
m_TestWithHost = useHost;
yield return MultiInstanceHelpers.RunAndWaitForCondition(
() =>
{
TestStruct.NetworkSerializeCalledOnWrite = false;
TestStruct.NetworkSerializeCalledOnRead = false;
m_Player1OnServer.TheStruct.Value =
new TestStruct() { SomeInt = k_TestUInt, SomeBool = false };
m_Player1OnServer.TheStruct.SetDirty(true);
},
() =>
{
return
TestStruct.NetworkSerializeCalledOnWrite &&
TestStruct.NetworkSerializeCalledOnRead;
}
);
return $"{m_NetworkListTestState} condition test failed:\n Server List Count: { m_Player1OnServer.TheList.Count} vs Client List Count: { m_Player1OnClient1.TheList.Count}\n" +
$"Server List Count: { m_Player1OnServer.TheLargeList.Count} vs Client List Count: { m_Player1OnClient1.TheLargeList.Count}\n" +
$"Server Delegate Triggered: {m_Player1OnServer.ListDelegateTriggered} | Client Delegate Triggered: {m_Player1OnClient1.ListDelegateTriggered}\n";
}
[UnityTearDown]
public override IEnumerator Teardown()
/// <summary>
/// When finished, check if a time out occurred and if so assert and provide meaningful information to troubleshoot why
/// </summary>
protected override void OnFinished()
{
yield return base.Teardown();
Assert.IsFalse(TimedOut, $"{nameof(NetworkListTestPredicate)} timed out waiting for the {m_NetworkListTestState} condition to be reached! \n" + ConditionFailedInfo());
}
// Uses the ArrayOperator and validates that on both sides the count and values are the same
private bool OnVerifyData()
{
// Wait until both sides have the same number of elements
if (m_Player1OnServer.TheList.Count != m_Player1OnClient1.TheList.Count)
{
return false;
}
// Check the client values against the server values to make sure they match
for (int i = 0; i < m_Player1OnServer.TheList.Count; i++)
{
if (m_Player1OnServer.TheList[i] != m_Player1OnClient1.TheList[i])
{
return false;
}
}
return true;
}
/// <summary>
/// Verifies the data count, values, and that the ListDelegate on both sides was triggered
/// </summary>
private bool OnAdd()
{
bool wasTriggerred = m_Player1OnServer.ListDelegateTriggered && m_Player1OnClient1.ListDelegateTriggered;
return wasTriggerred && OnVerifyData();
}
/// <summary>
/// The current version of this test only verified the count of the large list, so that is what this does
/// </summary>
private bool OnContainsLarge()
{
return m_Player1OnServer.TheLargeList.Count == m_Player1OnClient1.TheLargeList.Count;
}
/// <summary>
/// Tests NetworkList.Contains which also verifies all values are the same on both sides
/// </summary>
private bool OnContains()
{
// Wait until both sides have the same number of elements
if (m_Player1OnServer.TheList.Count != m_Player1OnClient1.TheList.Count)
{
return false;
}
// Parse through all server values and use the NetworkList.Contains method to check if the value is in the list on the client side
foreach (var serverValue in m_Player1OnServer.TheList)
{
if (!m_Player1OnClient1.TheList.Contains(serverValue))
{
return false;
}
}
return true;
}
/// <summary>
/// Tests NetworkList.IndexOf and verifies that all values are aligned on both sides
/// </summary>
private bool OnIndexOf()
{
foreach (var serverSideValue in m_Player1OnServer.TheList)
{
var indexToTest = m_Player1OnServer.TheList.IndexOf(serverSideValue);
if (indexToTest != m_Player1OnServer.TheList.IndexOf(serverSideValue))
{
return false;
}
}
return true;
}
public NetworkListTestPredicate(NetworkVariableTest player1OnServer, NetworkVariableTest player1OnClient1, NetworkListTestStates networkListTestState, int elementCount)
{
m_NetworkListTestState = networkListTestState;
m_Player1OnServer = player1OnServer;
m_Player1OnClient1 = player1OnClient1;
m_StateFunctions = new Dictionary<NetworkListTestStates, Func<bool>>
{
{ NetworkListTestStates.Add, OnAdd },
{ NetworkListTestStates.ContainsLarge, OnContainsLarge },
{ NetworkListTestStates.Contains, OnContains },
{ NetworkListTestStates.VerifyData, OnVerifyData },
{ NetworkListTestStates.IndexOf, OnIndexOf }
};
if (networkListTestState == NetworkListTestStates.ContainsLarge)
{
for (var i = 0; i < elementCount; ++i)
{
m_Player1OnServer.TheLargeList.Add(new FixedString128Bytes());
}
}
else
{
for (int i = 0; i < elementCount; i++)
{
m_Player1OnServer.TheList.Add(Random.Range(0, k_MaxRandomValue));
}
}
}
}
}

View File

@@ -0,0 +1,55 @@
using System.Collections;
using System.Linq;
using UnityEngine.TestTools;
using NUnit.Framework;
using UnityEngine;
using Unity.Netcode.TestHelpers.Runtime;
namespace Unity.Netcode.RuntimeTests
{
[TestFixture(SceneManagementState.SceneManagementEnabled)]
[TestFixture(SceneManagementState.SceneManagementDisabled)]
public class NetworkVisibilityTests : NetcodeIntegrationTest
{
public enum SceneManagementState
{
SceneManagementEnabled,
SceneManagementDisabled
}
protected override int NumberOfClients => 1;
private GameObject m_TestNetworkPrefab;
private bool m_SceneManagementEnabled;
public NetworkVisibilityTests(SceneManagementState sceneManagementState)
{
m_SceneManagementEnabled = sceneManagementState == SceneManagementState.SceneManagementEnabled;
}
protected override void OnServerAndClientsCreated()
{
m_TestNetworkPrefab = CreateNetworkObjectPrefab("Object");
m_TestNetworkPrefab.AddComponent<NetworkVisibilityComponent>();
m_ServerNetworkManager.NetworkConfig.EnableSceneManagement = m_SceneManagementEnabled;
foreach (var clientNetworkManager in m_ClientNetworkManagers)
{
clientNetworkManager.NetworkConfig.EnableSceneManagement = m_SceneManagementEnabled;
}
base.OnServerAndClientsCreated();
}
protected override IEnumerator OnServerAndClientsConnected()
{
SpawnObject(m_TestNetworkPrefab, m_ServerNetworkManager);
yield return base.OnServerAndClientsConnected();
}
[UnityTest]
public IEnumerator HiddenObjectsTest()
{
yield return WaitForConditionOrTimeOut(() => Object.FindObjectsOfType<NetworkVisibilityComponent>().Where((c) => c.IsSpawned).Count() == 2);
Assert.IsFalse(s_GlobalTimeoutHelper.TimedOut, "Timed out waiting for the visible object count to equal 2!");
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 45ff8252bf32540509fde11c19e0f3c2
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -3,8 +3,9 @@ using NUnit.Framework;
using Unity.Netcode.Components;
using UnityEngine;
using UnityEngine.TestTools;
using Unity.Netcode.TestHelpers.Runtime;
namespace Unity.Netcode.RuntimeTests.Physics
namespace Unity.Netcode.RuntimeTests
{
public class NetworkRigidbody2DDynamicTest : NetworkRigidbody2DTestBase
{
@@ -16,23 +17,19 @@ namespace Unity.Netcode.RuntimeTests.Physics
public override bool Kinematic => true;
}
public abstract class NetworkRigidbody2DTestBase : BaseMultiInstanceTest
public abstract class NetworkRigidbody2DTestBase : NetcodeIntegrationTest
{
protected override int NbClients => 1;
protected override int NumberOfClients => 1;
public abstract bool Kinematic { get; }
[UnitySetUp]
public override IEnumerator Setup()
protected override void OnCreatePlayerPrefab()
{
yield return StartSomeClientsAndServerWithPlayers(true, NbClients, playerPrefab =>
{
playerPrefab.AddComponent<NetworkTransform>();
playerPrefab.AddComponent<Rigidbody2D>();
playerPrefab.AddComponent<NetworkRigidbody2D>();
playerPrefab.GetComponent<Rigidbody2D>().interpolation = RigidbodyInterpolation2D.Interpolate;
playerPrefab.GetComponent<Rigidbody2D>().isKinematic = Kinematic;
});
m_PlayerPrefab.AddComponent<NetworkTransform>();
m_PlayerPrefab.AddComponent<Rigidbody2D>();
m_PlayerPrefab.AddComponent<NetworkRigidbody2D>();
m_PlayerPrefab.GetComponent<Rigidbody2D>().interpolation = RigidbodyInterpolation2D.Interpolate;
m_PlayerPrefab.GetComponent<Rigidbody2D>().isKinematic = Kinematic;
}
/// <summary>
@@ -43,19 +40,19 @@ namespace Unity.Netcode.RuntimeTests.Physics
public IEnumerator TestRigidbodyKinematicEnableDisable()
{
// This is the *SERVER VERSION* of the *CLIENT PLAYER*
var serverClientPlayerResult = new MultiInstanceHelpers.CoroutineResultWrapper<NetworkObject>();
yield return MultiInstanceHelpers.Run(MultiInstanceHelpers.GetNetworkObjectByRepresentation((x => x.IsPlayerObject && x.OwnerClientId == m_ClientNetworkManagers[0].LocalClientId), m_ServerNetworkManager, serverClientPlayerResult));
var serverClientPlayerResult = new NetcodeIntegrationTestHelpers.ResultWrapper<NetworkObject>();
yield return NetcodeIntegrationTestHelpers.GetNetworkObjectByRepresentation((x => x.IsPlayerObject && x.OwnerClientId == m_ClientNetworkManagers[0].LocalClientId), m_ServerNetworkManager, serverClientPlayerResult);
var serverPlayer = serverClientPlayerResult.Result.gameObject;
// This is the *CLIENT VERSION* of the *CLIENT PLAYER*
var clientClientPlayerResult = new MultiInstanceHelpers.CoroutineResultWrapper<NetworkObject>();
yield return MultiInstanceHelpers.Run(MultiInstanceHelpers.GetNetworkObjectByRepresentation((x => x.IsPlayerObject && x.OwnerClientId == m_ClientNetworkManagers[0].LocalClientId), m_ClientNetworkManagers[0], clientClientPlayerResult));
var clientClientPlayerResult = new NetcodeIntegrationTestHelpers.ResultWrapper<NetworkObject>();
yield return NetcodeIntegrationTestHelpers.GetNetworkObjectByRepresentation((x => x.IsPlayerObject && x.OwnerClientId == m_ClientNetworkManagers[0].LocalClientId), m_ClientNetworkManagers[0], clientClientPlayerResult);
var clientPlayer = clientClientPlayerResult.Result.gameObject;
Assert.IsNotNull(serverPlayer);
Assert.IsNotNull(clientPlayer);
yield return NetworkRigidbodyTestBase.WaitForFrames(5);
yield return NetcodeIntegrationTestHelpers.WaitForTicks(m_ServerNetworkManager, 5);
// server rigidbody has authority and should have a kinematic mode of false
Assert.True(serverPlayer.GetComponent<Rigidbody2D>().isKinematic == Kinematic);
@@ -68,15 +65,14 @@ namespace Unity.Netcode.RuntimeTests.Physics
// despawn the server player, (but keep it around on the server)
serverPlayer.GetComponent<NetworkObject>().Despawn(false);
yield return NetworkRigidbodyTestBase.WaitForFrames(5);
yield return NetcodeIntegrationTestHelpers.WaitForTicks(m_ServerNetworkManager, 5);
// This should equal Kinematic
Assert.IsTrue(serverPlayer.GetComponent<Rigidbody2D>().isKinematic == Kinematic);
yield return NetworkRigidbodyTestBase.WaitForFrames(5);
yield return NetcodeIntegrationTestHelpers.WaitForTicks(m_ServerNetworkManager, 5);
Assert.IsTrue(clientPlayer == null); // safety check that object is actually despawned.
}
}
}

View File

@@ -3,8 +3,9 @@ using NUnit.Framework;
using Unity.Netcode.Components;
using UnityEngine;
using UnityEngine.TestTools;
using Unity.Netcode.TestHelpers.Runtime;
namespace Unity.Netcode.RuntimeTests.Physics
namespace Unity.Netcode.RuntimeTests
{
public class NetworkRigidbodyDynamicTest : NetworkRigidbodyTestBase
{
@@ -16,23 +17,19 @@ namespace Unity.Netcode.RuntimeTests.Physics
public override bool Kinematic => true;
}
public abstract class NetworkRigidbodyTestBase : BaseMultiInstanceTest
public abstract class NetworkRigidbodyTestBase : NetcodeIntegrationTest
{
protected override int NbClients => 1;
protected override int NumberOfClients => 1;
public abstract bool Kinematic { get; }
[UnitySetUp]
public override IEnumerator Setup()
protected override void OnCreatePlayerPrefab()
{
yield return StartSomeClientsAndServerWithPlayers(true, NbClients, playerPrefab =>
{
playerPrefab.AddComponent<NetworkTransform>();
playerPrefab.AddComponent<Rigidbody>();
playerPrefab.AddComponent<NetworkRigidbody>();
playerPrefab.GetComponent<Rigidbody>().interpolation = RigidbodyInterpolation.Interpolate;
playerPrefab.GetComponent<Rigidbody>().isKinematic = Kinematic;
});
m_PlayerPrefab.AddComponent<NetworkTransform>();
m_PlayerPrefab.AddComponent<Rigidbody>();
m_PlayerPrefab.AddComponent<NetworkRigidbody>();
m_PlayerPrefab.GetComponent<Rigidbody>().interpolation = RigidbodyInterpolation.Interpolate;
m_PlayerPrefab.GetComponent<Rigidbody>().isKinematic = Kinematic;
}
/// <summary>
@@ -43,44 +40,38 @@ namespace Unity.Netcode.RuntimeTests.Physics
public IEnumerator TestRigidbodyKinematicEnableDisable()
{
// This is the *SERVER VERSION* of the *CLIENT PLAYER*
var serverClientPlayerResult = new MultiInstanceHelpers.CoroutineResultWrapper<NetworkObject>();
yield return MultiInstanceHelpers.Run(MultiInstanceHelpers.GetNetworkObjectByRepresentation((x => x.IsPlayerObject && x.OwnerClientId == m_ClientNetworkManagers[0].LocalClientId), m_ServerNetworkManager, serverClientPlayerResult));
var serverClientPlayerResult = new NetcodeIntegrationTestHelpers.ResultWrapper<NetworkObject>();
yield return NetcodeIntegrationTestHelpers.GetNetworkObjectByRepresentation((x => x.IsPlayerObject && x.OwnerClientId == m_ClientNetworkManagers[0].LocalClientId), m_ServerNetworkManager, serverClientPlayerResult);
var serverPlayer = serverClientPlayerResult.Result.gameObject;
// This is the *CLIENT VERSION* of the *CLIENT PLAYER*
var clientClientPlayerResult = new MultiInstanceHelpers.CoroutineResultWrapper<NetworkObject>();
yield return MultiInstanceHelpers.Run(MultiInstanceHelpers.GetNetworkObjectByRepresentation((x => x.IsPlayerObject && x.OwnerClientId == m_ClientNetworkManagers[0].LocalClientId), m_ClientNetworkManagers[0], clientClientPlayerResult));
var clientClientPlayerResult = new NetcodeIntegrationTestHelpers.ResultWrapper<NetworkObject>();
yield return NetcodeIntegrationTestHelpers.GetNetworkObjectByRepresentation((x => x.IsPlayerObject && x.OwnerClientId == m_ClientNetworkManagers[0].LocalClientId), m_ClientNetworkManagers[0], clientClientPlayerResult);
var clientPlayer = clientClientPlayerResult.Result.gameObject;
Assert.IsNotNull(serverPlayer);
Assert.IsNotNull(clientPlayer);
Assert.IsNotNull(serverPlayer, "serverPlayer is not null");
Assert.IsNotNull(clientPlayer, "clientPlayer is not null");
yield return WaitForFrames(5);
yield return NetcodeIntegrationTestHelpers.WaitForTicks(m_ServerNetworkManager, 3);
// server rigidbody has authority and should have a kinematic mode of false
Assert.True(serverPlayer.GetComponent<Rigidbody>().isKinematic == Kinematic);
Assert.AreEqual(RigidbodyInterpolation.Interpolate, serverPlayer.GetComponent<Rigidbody>().interpolation);
Assert.True(serverPlayer.GetComponent<Rigidbody>().isKinematic == Kinematic, "serverPlayer kinematic");
Assert.AreEqual(RigidbodyInterpolation.Interpolate, serverPlayer.GetComponent<Rigidbody>().interpolation, "server equal interpolate");
// client rigidbody has no authority and should have a kinematic mode of true
Assert.True(clientPlayer.GetComponent<Rigidbody>().isKinematic);
Assert.AreEqual(RigidbodyInterpolation.None, clientPlayer.GetComponent<Rigidbody>().interpolation);
Assert.True(clientPlayer.GetComponent<Rigidbody>().isKinematic, "clientPlayer kinematic");
Assert.AreEqual(RigidbodyInterpolation.None, clientPlayer.GetComponent<Rigidbody>().interpolation, "client equal interpolate");
// despawn the server player (but keep it around on the server)
serverPlayer.GetComponent<NetworkObject>().Despawn(false);
yield return WaitForFrames(5);
yield return NetcodeIntegrationTestHelpers.WaitForTicks(m_ServerNetworkManager, 3);
Assert.IsTrue(serverPlayer.GetComponent<Rigidbody>().isKinematic == Kinematic);
Assert.IsTrue(serverPlayer.GetComponent<Rigidbody>().isKinematic == Kinematic, "serverPlayer second kinematic");
yield return WaitForFrames(5);
yield return NetcodeIntegrationTestHelpers.WaitForTicks(m_ServerNetworkManager, 3);
Assert.IsTrue(clientPlayer == null); // safety check that object is actually despawned.
}
public static IEnumerator WaitForFrames(int count)
{
int nextFrameNumber = Time.frameCount + count;
yield return new WaitUntil(() => Time.frameCount >= nextFrameNumber);
Assert.IsTrue(clientPlayer == null, "clientPlayer being null"); // safety check that object is actually despawned.
}
}
}

View File

@@ -1,5 +1,6 @@
using System;
using NUnit.Framework;
using Unity.Netcode.TestHelpers.Runtime;
namespace Unity.Netcode.RuntimeTests
{

View File

@@ -0,0 +1,153 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;
using UnityEngine;
using UnityEngine.TestTools;
using Unity.Netcode.TestHelpers.Runtime;
namespace Unity.Netcode.RuntimeTests
{
public class RpcManyClientsObject : NetworkBehaviour
{
public int Count = 0;
public List<ulong> ReceivedFrom = new List<ulong>();
[ServerRpc(RequireOwnership = false)]
public void ResponseServerRpc(ServerRpcParams rpcParams = default)
{
ReceivedFrom.Add(rpcParams.Receive.SenderClientId);
Count++;
}
[ClientRpc]
public void NoParamsClientRpc()
{
ResponseServerRpc();
}
[ClientRpc]
public void OneParamClientRpc(int value)
{
ResponseServerRpc();
}
[ClientRpc]
public void TwoParamsClientRpc(int value1, int value2)
{
ResponseServerRpc();
}
[ClientRpc]
public void WithParamsClientRpc(ClientRpcParams param)
{
ResponseServerRpc();
}
}
public class RpcManyClientsTests : NetcodeIntegrationTest
{
protected override int NumberOfClients => 10;
private GameObject m_PrefabToSpawn;
protected override void OnServerAndClientsCreated()
{
m_PrefabToSpawn = PreparePrefab(typeof(RpcManyClientsObject));
}
public GameObject PreparePrefab(Type type)
{
var prefabToSpawn = new GameObject();
prefabToSpawn.AddComponent(type);
var networkObjectPrefab = prefabToSpawn.AddComponent<NetworkObject>();
NetcodeIntegrationTestHelpers.MakeNetworkObjectTestPrefab(networkObjectPrefab);
m_ServerNetworkManager.NetworkConfig.NetworkPrefabs.Add(new NetworkPrefab() { Prefab = prefabToSpawn });
foreach (var clientNetworkManager in m_ClientNetworkManagers)
{
clientNetworkManager.NetworkConfig.NetworkPrefabs.Add(new NetworkPrefab() { Prefab = prefabToSpawn });
}
return prefabToSpawn;
}
[UnityTest]
public IEnumerator RpcManyClientsTest()
{
var spawnedObject = UnityEngine.Object.Instantiate(m_PrefabToSpawn);
var netSpawnedObject = spawnedObject.GetComponent<NetworkObject>();
netSpawnedObject.NetworkManagerOwner = m_ServerNetworkManager;
netSpawnedObject.Spawn();
var messageHookList = new List<MessageHookEntry>();
var serverMessageHookEntry = new MessageHookEntry(m_ServerNetworkManager);
serverMessageHookEntry.AssignMessageType<ServerRpcMessage>();
messageHookList.Add(serverMessageHookEntry);
foreach (var client in m_ClientNetworkManagers)
{
var clientMessageHookEntry = new MessageHookEntry(client);
clientMessageHookEntry.AssignMessageType<ServerRpcMessage>();
messageHookList.Add(clientMessageHookEntry);
}
var rpcMessageHooks = new MessageHooksConditional(messageHookList);
var rpcManyClientsObject = netSpawnedObject.GetComponent<RpcManyClientsObject>();
rpcManyClientsObject.Count = 0;
rpcManyClientsObject.NoParamsClientRpc(); // RPC with no params
// Check that all ServerRpcMessages were sent
yield return WaitForConditionOrTimeOut(rpcMessageHooks);
// Now provide a small window of time to let the server receive and process all messages
yield return WaitForConditionOrTimeOut(() => TotalClients == rpcManyClientsObject.Count);
Assert.False(s_GlobalTimeoutHelper.TimedOut, $"Timed out wait for {nameof(rpcManyClientsObject.NoParamsClientRpc)}! Only {rpcManyClientsObject.Count} of {TotalClients} was received!");
rpcManyClientsObject.Count = 0;
rpcManyClientsObject.OneParamClientRpc(0); // RPC with one param
rpcMessageHooks.Reset();
yield return WaitForConditionOrTimeOut(rpcMessageHooks);
// Now provide a small window of time to let the server receive and process all messages
yield return WaitForConditionOrTimeOut(() => TotalClients == rpcManyClientsObject.Count);
Assert.False(s_GlobalTimeoutHelper.TimedOut, $"Timed out wait for {nameof(rpcManyClientsObject.OneParamClientRpc)}! Only {rpcManyClientsObject.Count} of {TotalClients} was received!");
var param = new ClientRpcParams();
rpcManyClientsObject.Count = 0;
rpcManyClientsObject.TwoParamsClientRpc(0, 0); // RPC with two params
rpcMessageHooks.Reset();
yield return WaitForConditionOrTimeOut(rpcMessageHooks);
// Now provide a small window of time to let the server receive and process all messages
yield return WaitForConditionOrTimeOut(() => TotalClients == rpcManyClientsObject.Count);
Assert.False(s_GlobalTimeoutHelper.TimedOut, $"Timed out wait for {nameof(rpcManyClientsObject.TwoParamsClientRpc)}! Only {rpcManyClientsObject.Count} of {TotalClients} was received!");
rpcManyClientsObject.ReceivedFrom.Clear();
rpcManyClientsObject.Count = 0;
var target = new List<ulong> { m_ClientNetworkManagers[1].LocalClientId, m_ClientNetworkManagers[2].LocalClientId };
param.Send.TargetClientIds = target;
rpcManyClientsObject.WithParamsClientRpc(param);
messageHookList.Clear();
var targetedClientMessageHookEntry = new MessageHookEntry(m_ClientNetworkManagers[1]);
targetedClientMessageHookEntry.AssignMessageType<ServerRpcMessage>();
messageHookList.Add(targetedClientMessageHookEntry);
targetedClientMessageHookEntry = new MessageHookEntry(m_ClientNetworkManagers[2]);
targetedClientMessageHookEntry.AssignMessageType<ServerRpcMessage>();
messageHookList.Add(targetedClientMessageHookEntry);
rpcMessageHooks = new MessageHooksConditional(messageHookList);
yield return WaitForConditionOrTimeOut(rpcMessageHooks);
// Now provide a small window of time to let the server receive and process all messages
yield return WaitForConditionOrTimeOut(() => 2 == rpcManyClientsObject.Count);
Assert.False(s_GlobalTimeoutHelper.TimedOut, $"Timed out wait for {nameof(rpcManyClientsObject.TwoParamsClientRpc)}! Only {rpcManyClientsObject.Count} of 2 was received!");
// either of the 2 selected clients can reply to the server first, due to network timing
var possibility1 = new List<ulong> { m_ClientNetworkManagers[1].LocalClientId, m_ClientNetworkManagers[2].LocalClientId };
var possibility2 = new List<ulong> { m_ClientNetworkManagers[2].LocalClientId, m_ClientNetworkManagers[1].LocalClientId };
Debug.Assert(Enumerable.SequenceEqual(rpcManyClientsObject.ReceivedFrom, possibility1) || Enumerable.SequenceEqual(rpcManyClientsObject.ReceivedFrom, possibility2));
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 1fc23d25ed71f46ecadbff65a20522c8
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -3,6 +3,7 @@ using System.Collections;
using UnityEngine;
using UnityEngine.TestTools;
using NUnit.Framework;
using Unity.Netcode.TestHelpers.Runtime;
namespace Unity.Netcode.RuntimeTests
{

View File

@@ -1,12 +1,14 @@
using System;
using System.Collections;
using System.Collections.Generic;
using NUnit.Framework;
using UnityEngine.TestTools;
using Unity.Netcode.TestHelpers.Runtime;
using Debug = UnityEngine.Debug;
namespace Unity.Netcode.RuntimeTests
{
public class RpcTests : BaseMultiInstanceTest
public class RpcTests : NetcodeIntegrationTest
{
public class RpcTestNB : NetworkBehaviour
{
@@ -26,54 +28,47 @@ namespace Unity.Netcode.RuntimeTests
}
}
protected override int NbClients => 1;
protected override int NumberOfClients => 1;
[UnitySetUp]
public override IEnumerator Setup()
protected override void OnCreatePlayerPrefab()
{
yield return StartSomeClientsAndServerWithPlayers(true, NbClients, playerPrefab =>
{
playerPrefab.AddComponent<RpcTestNB>();
});
m_PlayerPrefab.AddComponent<RpcTestNB>();
}
[UnityTest]
public IEnumerator TestRpcs()
{
// This is the *SERVER VERSION* of the *CLIENT PLAYER*
var serverClientPlayerResult = new MultiInstanceHelpers.CoroutineResultWrapper<NetworkObject>();
var clientId = m_ClientNetworkManagers[0].LocalClientId;
yield return MultiInstanceHelpers.Run(MultiInstanceHelpers.GetNetworkObjectByRepresentation((x => x.IsPlayerObject && x.OwnerClientId == clientId), m_ServerNetworkManager, serverClientPlayerResult));
// This is the *SERVER VERSION* of the *CLIENT PLAYER* RpcTestNB component
var serverClientRpcTestNB = m_PlayerNetworkObjects[m_ServerNetworkManager.LocalClientId][m_ClientNetworkManagers[0].LocalClientId].GetComponent<RpcTestNB>();
// This is the *CLIENT VERSION* of the *CLIENT PLAYER*
var clientClientPlayerResult = new MultiInstanceHelpers.CoroutineResultWrapper<NetworkObject>();
yield return MultiInstanceHelpers.Run(MultiInstanceHelpers.GetNetworkObjectByRepresentation((x => x.IsPlayerObject && x.OwnerClientId == clientId), m_ClientNetworkManagers[0], clientClientPlayerResult));
// This is the *CLIENT VERSION* of the *CLIENT PLAYER* RpcTestNB component
var localClienRpcTestNB = m_PlayerNetworkObjects[m_ClientNetworkManagers[0].LocalClientId][m_ClientNetworkManagers[0].LocalClientId].GetComponent<RpcTestNB>();
// Setup state
bool hasReceivedServerRpc = false;
bool hasReceivedClientRpcRemotely = false;
bool hasReceivedClientRpcLocally = false;
clientClientPlayerResult.Result.GetComponent<RpcTestNB>().OnClient_Rpc += () =>
localClienRpcTestNB.OnClient_Rpc += () =>
{
Debug.Log("ClientRpc received on client object");
hasReceivedClientRpcRemotely = true;
};
clientClientPlayerResult.Result.GetComponent<RpcTestNB>().OnServer_Rpc += (clientId, param) =>
localClienRpcTestNB.OnServer_Rpc += (clientId, param) =>
{
// The RPC invoked locally. (Weaver failure?)
Assert.Fail("ServerRpc invoked locally. Weaver failure?");
};
serverClientPlayerResult.Result.GetComponent<RpcTestNB>().OnServer_Rpc += (clientId, param) =>
serverClientRpcTestNB.OnServer_Rpc += (clientId, param) =>
{
Debug.Log("ServerRpc received on server object");
Assert.True(param.Receive.SenderClientId == clientId);
hasReceivedServerRpc = true;
};
serverClientPlayerResult.Result.GetComponent<RpcTestNB>().OnClient_Rpc += () =>
serverClientRpcTestNB.OnClient_Rpc += () =>
{
// The RPC invoked locally. (Weaver failure?)
Debug.Log("ClientRpc received on server object");
@@ -81,13 +76,28 @@ namespace Unity.Netcode.RuntimeTests
};
// Send ServerRpc
clientClientPlayerResult.Result.GetComponent<RpcTestNB>().MyServerRpc(clientId);
localClienRpcTestNB.MyServerRpc(m_ClientNetworkManagers[0].LocalClientId);
// Send ClientRpc
serverClientPlayerResult.Result.GetComponent<RpcTestNB>().MyClientRpc();
serverClientRpcTestNB.MyClientRpc();
// Wait for RPCs to be received
yield return MultiInstanceHelpers.Run(MultiInstanceHelpers.WaitForCondition(() => hasReceivedServerRpc && hasReceivedClientRpcLocally && hasReceivedClientRpcRemotely));
// Validate each NetworkManager relative MessagingSystem received each respective RPC
var messageHookList = new List<MessageHookEntry>();
var serverMessageHookEntry = new MessageHookEntry(m_ServerNetworkManager);
serverMessageHookEntry.AssignMessageType<ServerRpcMessage>();
messageHookList.Add(serverMessageHookEntry);
foreach (var client in m_ClientNetworkManagers)
{
var clientMessageHookEntry = new MessageHookEntry(client);
clientMessageHookEntry.AssignMessageType<ClientRpcMessage>();
messageHookList.Add(clientMessageHookEntry);
}
var rpcMessageHooks = new MessageHooksConditional(messageHookList);
yield return WaitForConditionOrTimeOut(rpcMessageHooks);
Assert.False(s_GlobalTimeoutHelper.TimedOut, $"Timed out waiting for messages: {rpcMessageHooks.GetHooksStillWaiting()}");
// Make sure RPCs propagated all the way up and were called on the relative destination class instance
yield return WaitForConditionOrTimeOut(() => hasReceivedServerRpc && hasReceivedClientRpcLocally && hasReceivedClientRpcRemotely);
Assert.True(hasReceivedServerRpc, "ServerRpc was not received");
Assert.True(hasReceivedClientRpcLocally, "ClientRpc was not locally received on the server");

View File

@@ -3,8 +3,9 @@ using System.Collections;
using NUnit.Framework;
using UnityEngine;
using UnityEngine.TestTools;
using Unity.Netcode.TestHelpers.Runtime;
namespace Unity.Netcode.RuntimeTests.Serialization
namespace Unity.Netcode.RuntimeTests
{
/// <summary>
/// Unit tests to test:

View File

@@ -4,9 +4,10 @@ using NUnit.Framework;
using Unity.Collections;
using UnityEngine;
using UnityEngine.TestTools;
using Unity.Netcode.TestHelpers.Runtime;
using Object = UnityEngine.Object;
namespace Unity.Netcode.RuntimeTests.Serialization
namespace Unity.Netcode.RuntimeTests
{
/// <summary>
/// Unit tests to test:

View File

@@ -0,0 +1,75 @@
using NUnit.Framework;
using UnityEngine;
namespace Unity.Netcode.RuntimeTests
{
public class StartStopTests
{
private NetworkManager m_NetworkManager;
[SetUp]
public void Setup()
{
// Create the reusable NetworkManager
m_NetworkManager = new GameObject(nameof(NetworkManager)).AddComponent<NetworkManager>();
var transport = m_NetworkManager.gameObject.AddComponent<DummyTransport>();
m_NetworkManager.NetworkConfig = new NetworkConfig()
{
NetworkTransport = transport
};
}
[Test]
public void TestStopAndRestartForExceptions()
{
m_NetworkManager.StartServer();
m_NetworkManager.Shutdown();
m_NetworkManager.StartServer();
m_NetworkManager.Shutdown();
}
[Test]
public void TestStartupServerState()
{
m_NetworkManager.StartServer();
Assert.True(m_NetworkManager.IsServer);
Assert.False(m_NetworkManager.IsClient);
Assert.False(m_NetworkManager.IsHost);
m_NetworkManager.Shutdown();
}
[Test]
public void TestFlagShutdown()
{
m_NetworkManager.StartServer();
m_NetworkManager.ShutdownInternal();
Assert.False(m_NetworkManager.IsServer);
Assert.False(m_NetworkManager.IsClient);
Assert.False(m_NetworkManager.IsHost);
}
[Test]
public void TestShutdownWithoutStartForExceptions()
{
m_NetworkManager.ShutdownInternal();
}
[Test]
public void TestShutdownWithoutConfigForExceptions()
{
m_NetworkManager.NetworkConfig = null;
m_NetworkManager.ShutdownInternal();
}
[TearDown]
public void Teardown()
{
// Cleanup
Object.DestroyImmediate(m_NetworkManager.gameObject);
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: e8e36047cb5542bcaade2a9a8746d713
timeCreated: 1630336158

View File

@@ -2,6 +2,7 @@ using System.Collections;
using NUnit.Framework;
using UnityEngine;
using UnityEngine.TestTools;
using Unity.Netcode.TestHelpers.Runtime;
namespace Unity.Netcode.RuntimeTests
{
@@ -10,7 +11,7 @@ namespace Unity.Netcode.RuntimeTests
[UnityTest]
public IEnumerator WhenShuttingDownAndRestarting_SDKRestartsSuccessfullyAndStaysRunning()
{ // create server and client instances
MultiInstanceHelpers.Create(1, out NetworkManager server, out NetworkManager[] clients);
NetcodeIntegrationTestHelpers.Create(1, out NetworkManager server, out NetworkManager[] clients);
try
{
@@ -19,7 +20,7 @@ namespace Unity.Netcode.RuntimeTests
var gameObject = new GameObject("PlayerObject");
var networkObject = gameObject.AddComponent<NetworkObject>();
networkObject.DontDestroyWithOwner = true;
MultiInstanceHelpers.MakeNetworkObjectTestPrefab(networkObject);
NetcodeIntegrationTestHelpers.MakeNetworkObjectTestPrefab(networkObject);
server.NetworkConfig.PlayerPrefab = gameObject;
@@ -29,13 +30,13 @@ namespace Unity.Netcode.RuntimeTests
}
// start server and connect clients
MultiInstanceHelpers.Start(false, server, clients);
NetcodeIntegrationTestHelpers.Start(false, server, clients);
// wait for connection on client side
yield return MultiInstanceHelpers.Run(MultiInstanceHelpers.WaitForClientsConnected(clients));
yield return NetcodeIntegrationTestHelpers.WaitForClientsConnected(clients);
// wait for connection on server side
yield return MultiInstanceHelpers.Run(MultiInstanceHelpers.WaitForClientConnectedToServer(server));
yield return NetcodeIntegrationTestHelpers.WaitForClientConnectedToServer(server);
// shutdown the server
server.Shutdown();
@@ -66,7 +67,7 @@ namespace Unity.Netcode.RuntimeTests
finally
{
// cleanup
MultiInstanceHelpers.Destroy();
NetcodeIntegrationTestHelpers.Destroy();
}
}
}

View File

@@ -2,6 +2,7 @@ using System.Collections;
using NUnit.Framework;
using UnityEngine;
using UnityEngine.TestTools;
using Unity.Netcode.TestHelpers.Runtime;
namespace Unity.Netcode.RuntimeTests
{
@@ -41,13 +42,35 @@ namespace Unity.Netcode.RuntimeTests
{
var tickSystem = NetworkManager.Singleton.NetworkTickSystem;
var delta = tickSystem.LocalTime.FixedDeltaTime;
var previous_localTickCalculated = 0;
var previous_serverTickCalculated = 0;
while (tickSystem.LocalTime.Time < 3f)
{
yield return null;
Assert.AreEqual(Mathf.FloorToInt((tickSystem.LocalTime.TimeAsFloat / delta)), NetworkManager.Singleton.LocalTime.Tick);
Assert.AreEqual(Mathf.FloorToInt((tickSystem.ServerTime.TimeAsFloat / delta)), NetworkManager.Singleton.ServerTime.Tick);
Assert.True(Mathf.Approximately((float)NetworkManager.Singleton.LocalTime.Time, (float)NetworkManager.Singleton.ServerTime.Time));
var tickCalculated = tickSystem.LocalTime.Time / delta;
previous_localTickCalculated = (int)tickCalculated;
// This check is needed due to double division imprecision of large numbers
if ((tickCalculated - previous_localTickCalculated) >= 0.999999999999)
{
previous_localTickCalculated++;
}
tickCalculated = NetworkManager.Singleton.ServerTime.Time / delta;
previous_serverTickCalculated = (int)tickCalculated;
// This check is needed due to double division imprecision of large numbers
if ((tickCalculated - previous_serverTickCalculated) >= 0.999999999999)
{
previous_serverTickCalculated++;
}
Assert.AreEqual(previous_localTickCalculated, NetworkManager.Singleton.LocalTime.Tick, $"Calculated local tick {previous_localTickCalculated} does not match local tick {NetworkManager.Singleton.LocalTime.Tick}!");
Assert.AreEqual(previous_serverTickCalculated, NetworkManager.Singleton.ServerTime.Tick, $"Calculated server tick {previous_serverTickCalculated} does not match server tick {NetworkManager.Singleton.ServerTime.Tick}!");
Assert.True(Mathf.Approximately((float)NetworkManager.Singleton.LocalTime.Time, (float)NetworkManager.Singleton.ServerTime.Time), $"Local time {(float)NetworkManager.Singleton.LocalTime.Time} is not approximately server time {(float)NetworkManager.Singleton.ServerTime.Time}!");
}
}

View File

@@ -2,6 +2,7 @@ using System.Collections;
using NUnit.Framework;
using UnityEngine;
using UnityEngine.TestTools;
using Unity.Netcode.TestHelpers.Runtime;
namespace Unity.Netcode.RuntimeTests
{
@@ -18,14 +19,14 @@ namespace Unity.Netcode.RuntimeTests
public IEnumerator TestClientTimeInitializationOnConnect([Values(0, 1f)] float serverStartDelay, [Values(0, 1f)] float clientStartDelay, [Values(true, false)] bool isHost)
{
// Create multiple NetworkManager instances
if (!MultiInstanceHelpers.Create(1, out NetworkManager server, out NetworkManager[] clients, 30))
if (!NetcodeIntegrationTestHelpers.Create(1, out NetworkManager server, out NetworkManager[] clients, 30))
{
Debug.LogError("Failed to create instances");
Assert.Fail("Failed to create instances");
}
yield return new WaitForSeconds(serverStartDelay);
MultiInstanceHelpers.Start(false, server, new NetworkManager[] { }, BaseMultiInstanceTest.SceneManagerValidationAndTestRunnerInitialization); // passing no clients on purpose to start them manually later
NetcodeIntegrationTestHelpers.Start(false, server, new NetworkManager[] { }); // passing no clients on purpose to start them manually later
// 0 ticks should have passed
var serverTick = server.NetworkTickSystem.ServerTime.Tick;
@@ -34,9 +35,11 @@ namespace Unity.Netcode.RuntimeTests
// server time should be 0
Assert.AreEqual(0, server.NetworkTickSystem.ServerTime.Time);
// wait 2 frames to ensure network tick is run
yield return null;
yield return null;
// wait until at least more than 2 server ticks have passed
// Note: Waiting for more than 2 ticks on the server is due
// to the time system applying buffering to the received time
// in NetworkTimeSystem.Sync
yield return new WaitUntil(() => server.NetworkTickSystem.ServerTime.Tick > 2);
var serverTimePassed = server.NetworkTickSystem.ServerTime.Time;
var expectedServerTickCount = Mathf.FloorToInt((float)(serverTimePassed * 30));
@@ -56,16 +59,13 @@ namespace Unity.Netcode.RuntimeTests
var clientStartRealTime = Time.time;
m_Client.StartClient();
BaseMultiInstanceTest.SceneManagerValidationAndTestRunnerInitialization(clients[0]);
NetcodeIntegrationTestHelpers.RegisterHandlers(clients[0]);
m_Client.NetworkTickSystem.Tick += NetworkTickSystemOnTick;
m_ClientTickCounter = 0;
// don't check for anything here and assume non-async connection.
// Wait for connection on client side
yield return MultiInstanceHelpers.Run(MultiInstanceHelpers.WaitForClientsConnected(clients));
yield return NetcodeIntegrationTestHelpers.WaitForClientsConnected(clients);
var clientStartRealTimeDuration = Time.time - clientStartRealTime;
var clientStartRealTickDuration = Mathf.FloorToInt(clientStartRealTimeDuration * 30);
@@ -75,7 +75,6 @@ namespace Unity.Netcode.RuntimeTests
Assert.True(m_ClientTickCounter <= clientStartRealTickDuration);
MultiInstanceHelpers.Destroy();
yield return null;
}
@@ -95,7 +94,7 @@ namespace Unity.Netcode.RuntimeTests
[UnityTearDown]
public virtual IEnumerator Teardown()
{
MultiInstanceHelpers.Destroy();
NetcodeIntegrationTestHelpers.Destroy();
yield return null;
}
}

View File

@@ -4,13 +4,14 @@ using System.Linq;
using NUnit.Framework;
using UnityEngine;
using UnityEngine.TestTools;
using Unity.Netcode.TestHelpers.Runtime;
namespace Unity.Netcode.RuntimeTests
{
/// <summary>
/// Tests the times of two clients connecting to a server using the SIPTransport (returns 50ms RTT but has no latency simulation)
/// </summary>
public class TimeMultiInstanceTest : BaseMultiInstanceTest
public class TimeIntegrationTest : NetcodeIntegrationTest
{
private const double k_AdditionalTimeTolerance = 0.3d; // magic number and in theory not needed but without this mac os test fail in Yamato because it looks like we get random framerate drops during unit test.
@@ -18,12 +19,11 @@ namespace Unity.Netcode.RuntimeTests
private NetworkTimeState m_Client1State;
private NetworkTimeState m_Client2State;
protected override int NbClients => 2;
protected override int NumberOfClients => 2;
// we need to change frame rate which is done in startup so removing this from here and moving into the test.
public override IEnumerator Setup()
protected override NetworkManagerInstatiationMode OnSetIntegrationTestMode()
{
yield break;
return NetworkManagerInstatiationMode.DoNotCreate;
}
private void UpdateTimeStates(NetworkManager[] networkManagers)
@@ -46,14 +46,14 @@ namespace Unity.Netcode.RuntimeTests
[TestCase(10, 30u, ExpectedResult = null)]
[TestCase(60, 60u, ExpectedResult = null)]
[TestCase(60, 10u, ExpectedResult = null)]
public IEnumerator TestTimeMultiInstance(int targetFrameRate, uint tickRate)
public IEnumerator TestTimeIntegrationTest(int targetFrameRate, uint tickRate)
{
yield return StartSomeClientsAndServerWithPlayersCustom(true, NbClients, targetFrameRate, tickRate);
yield return StartSomeClientsAndServerWithPlayersCustom(true, NumberOfClients, targetFrameRate, tickRate);
double frameInterval = 1d / targetFrameRate;
double tickInterval = 1d / tickRate;
var networkManagers = MultiInstanceHelpers.NetworkManagerInstances.ToArray();
var networkManagers = NetcodeIntegrationTestHelpers.NetworkManagerInstances.ToArray();
var server = networkManagers.First(t => t.IsServer);
var firstClient = networkManagers.First(t => !t.IsServer);
@@ -89,13 +89,15 @@ namespace Unity.Netcode.RuntimeTests
// compares the two client times, only difference should be based on buffering.
m_Client1State.AssertCheckDifference(m_Client2State, 0.2 - tickInterval, (0.1 - tickInterval), tickInterval * 2 + frameInterval * 2 + k_AdditionalTimeTolerance);
}
ShutdownAndCleanUp();
}
// This is from BaseMultiInstanceTest but we need a custom version of this to modifiy the config
// This is from NetcodeIntegrationTest but we need a custom version of this to modifiy the config
private IEnumerator StartSomeClientsAndServerWithPlayersCustom(bool useHost, int nbClients, int targetFrameRate, uint tickRate)
{
// Create multiple NetworkManager instances
if (!MultiInstanceHelpers.Create(nbClients, out NetworkManager server, out NetworkManager[] clients, targetFrameRate))
if (!NetcodeIntegrationTestHelpers.Create(nbClients, out NetworkManager server, out NetworkManager[] clients, targetFrameRate))
{
Debug.LogError("Failed to create instances");
Assert.Fail("Failed to create instances");
@@ -111,12 +113,12 @@ namespace Unity.Netcode.RuntimeTests
/*
* Normally we would only allow player prefabs to be set to a prefab. Not runtime created objects.
* In order to prevent having a Resource folder full of a TON of prefabs that we have to maintain,
* MultiInstanceHelper has a helper function that lets you mark a runtime created object to be
* NetcodeIntegrationTestHelpers has a helper function that lets you mark a runtime created object to be
* treated as a prefab by the Netcode. That's how we can get away with creating the player prefab
* at runtime without it being treated as a SceneObject or causing other conflicts with the Netcode.
*/
// Make it a prefab
MultiInstanceHelpers.MakeNetworkObjectTestPrefab(networkObject);
NetcodeIntegrationTestHelpers.MakeNetworkObjectTestPrefab(networkObject);
// Set the player prefab
server.NetworkConfig.PlayerPrefab = m_PlayerPrefab;
@@ -130,23 +132,14 @@ namespace Unity.Netcode.RuntimeTests
server.NetworkConfig.TickRate = tickRate;
// Start the instances
if (!MultiInstanceHelpers.Start(useHost, server, clients))
if (!NetcodeIntegrationTestHelpers.Start(useHost, server, clients))
{
Debug.LogError("Failed to start instances");
Assert.Fail("Failed to start instances");
}
// Wait for connection on client side
yield return MultiInstanceHelpers.Run(MultiInstanceHelpers.WaitForClientsConnected(clients));
// Wait for connection on server side
yield return MultiInstanceHelpers.Run(MultiInstanceHelpers.WaitForClientsConnectedToServer(server, useHost ? nbClients + 1 : nbClients));
}
private IEnumerator WaitForFrames(int count)
{
int nextFrameNumber = Time.frameCount + count;
yield return new WaitUntil(() => Time.frameCount >= nextFrameNumber);
// Wait for connection on client and server side
yield return WaitForClientsConnectedOrTimeOut();
}
private readonly struct NetworkTimeState : IEquatable<NetworkTimeState>

View File

@@ -0,0 +1,116 @@
using System.Collections;
using Unity.Netcode.Components;
using NUnit.Framework;
using UnityEngine;
using UnityEngine.TestTools;
using Unity.Netcode.TestHelpers.Runtime;
namespace Unity.Netcode.RuntimeTests
{
public class TransformInterpolationObject : NetworkBehaviour
{
public bool CheckPosition;
public bool IsMoving;
public bool IsFixed;
private void Update()
{
// Check the position of the nested object on the client
if (CheckPosition)
{
if (transform.position.y < 0.0f || transform.position.y > 100.0f)
{
Debug.LogError($"Interpolation failure. transform.position.y is {transform.position.y}. Should be between 0.0 and 100.0");
}
}
// Move the nested object on the server
if (IsMoving)
{
var y = Time.realtimeSinceStartup;
while (y > 10.0f)
{
y -= 10.0f;
}
// change the space between local and global every second
GetComponent<NetworkTransform>().InLocalSpace = ((int)y % 2 == 0);
transform.position = new Vector3(0.0f, y * 10, 0.0f);
}
// On the server, make sure to keep the parent object at a fixed position
if (IsFixed)
{
transform.position = new Vector3(1000.0f, 1000.0f, 1000.0f);
}
}
}
public class TransformInterpolationTests : NetcodeIntegrationTest
{
protected override int NumberOfClients => 1;
private ulong m_ClientId0;
private GameObject m_PrefabToSpawn;
private NetworkObject m_AsNetworkObject;
private NetworkObject m_SpawnedObjectOnClient;
protected override void OnServerAndClientsCreated()
{
m_PrefabToSpawn = CreateNetworkObjectPrefab("InterpTestObject");
m_PrefabToSpawn.AddComponent<NetworkTransform>();
m_PrefabToSpawn.AddComponent<TransformInterpolationObject>();
}
private IEnumerator RefreshNetworkObjects()
{
var clientId = m_ClientNetworkManagers[0].LocalClientId;
yield return WaitForConditionOrTimeOut(() => s_GlobalNetworkObjects.ContainsKey(clientId) &&
s_GlobalNetworkObjects[clientId].ContainsKey(m_AsNetworkObject.NetworkObjectId));
Assert.False(s_GlobalTimeoutHelper.TimedOut, $"Timed out waiting for client side {nameof(NetworkObject)} ID of {m_AsNetworkObject.NetworkObjectId}");
m_SpawnedObjectOnClient = s_GlobalNetworkObjects[clientId][m_AsNetworkObject.NetworkObjectId];
// make sure the objects are set with the right network manager
m_SpawnedObjectOnClient.NetworkManagerOwner = m_ClientNetworkManagers[0];
}
[UnityTest]
public IEnumerator TransformInterpolationTest()
{
m_ClientId0 = m_ClientNetworkManagers[0].LocalClientId;
// create an object
var spawnedObject = Object.Instantiate(m_PrefabToSpawn);
var baseObject = Object.Instantiate(m_PrefabToSpawn);
baseObject.GetComponent<NetworkObject>().NetworkManagerOwner = m_ServerNetworkManager;
baseObject.GetComponent<NetworkObject>().Spawn();
m_AsNetworkObject = spawnedObject.GetComponent<NetworkObject>();
m_AsNetworkObject.NetworkManagerOwner = m_ServerNetworkManager;
m_AsNetworkObject.TrySetParent(baseObject);
m_AsNetworkObject.Spawn();
yield return RefreshNetworkObjects();
m_AsNetworkObject.TrySetParent(baseObject);
baseObject.GetComponent<TransformInterpolationObject>().IsFixed = true;
spawnedObject.GetComponent<TransformInterpolationObject>().IsMoving = true;
// Give two seconds for the object to settle
yield return new WaitForSeconds(2.0f);
m_SpawnedObjectOnClient.GetComponent<TransformInterpolationObject>().CheckPosition = true;
// Test that interpolation works correctly for 10 seconds
// Increasing this duration gives you the opportunity to go check in the Editor how the objects are setup
// and how they move
yield return new WaitForSeconds(10.0f);
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 99e1c086232df436498da7c180b59898
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: d764f651f0e54e8281952933cc49be97
guid: be6919760502fc9419376258fd62ec0e
folderAsset: yes
DefaultImporter:
externalObjects: {}

View File

@@ -0,0 +1,52 @@
using System;
namespace Unity.Netcode.RuntimeTests
{
internal class DummyTransport : TestingNetworkTransport
{
public override ulong ServerClientId { get; } = 0;
public override void Send(ulong clientId, ArraySegment<byte> payload, NetworkDelivery networkDelivery)
{
}
public override NetworkEvent PollEvent(out ulong clientId, out ArraySegment<byte> payload, out float receiveTime)
{
clientId = 0;
payload = new ArraySegment<byte>();
receiveTime = 0;
return NetworkEvent.Nothing;
}
public override bool StartClient()
{
return true;
}
public override bool StartServer()
{
return true;
}
public override void DisconnectRemoteClient(ulong clientId)
{
}
public override void DisconnectLocalClient()
{
}
public override ulong GetCurrentRtt(ulong clientId)
{
return 0;
}
public override void Shutdown()
{
}
public override void Initialize(NetworkManager networkManager = null)
{
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 976ca592c7fa4bcb854203dfbadc0ad9
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,273 +0,0 @@
using System;
using System.Collections.Generic;
#if UNITY_EDITOR
using Unity.Netcode.Editor;
#endif
using UnityEngine;
namespace Unity.Netcode.RuntimeTests
{
/// <summary>
/// SIPTransport (SIngleProcessTransport)
/// is a NetworkTransport designed to be used with multiple network instances in a single process
/// it's designed for the netcode in a way where no networking stack has to be available
/// it's designed for testing purposes and it's not designed with speed in mind
/// </summary>
#if UNITY_EDITOR
[DontShowInTransportDropdown]
#endif
public class SIPTransport : NetworkTransport
{
private struct Event
{
public NetworkEvent Type;
public ulong ConnectionId;
public ArraySegment<byte> Data;
}
private class Peer
{
public ulong ConnectionId;
public SIPTransport Transport;
public Queue<Event> IncomingBuffer = new Queue<Event>();
}
private readonly Dictionary<ulong, Peer> m_Peers = new Dictionary<ulong, Peer>();
private ulong m_ClientsCounter = 1;
private static Peer s_Server;
private Peer m_LocalConnection;
public override ulong ServerClientId => 0;
public ulong LocalClientId;
public override void DisconnectLocalClient()
{
if (m_LocalConnection != null)
{
// Inject local disconnect
m_LocalConnection.IncomingBuffer.Enqueue(new Event
{
Type = NetworkEvent.Disconnect,
ConnectionId = m_LocalConnection.ConnectionId,
Data = new ArraySegment<byte>()
});
if (s_Server != null && m_LocalConnection != null)
{
// Remove the connection
s_Server.Transport.m_Peers.Remove(m_LocalConnection.ConnectionId);
}
if (m_LocalConnection.ConnectionId == ServerClientId)
{
StopServer();
}
// Remove the local connection
m_LocalConnection = null;
}
}
// Called by server
public override void DisconnectRemoteClient(ulong clientId)
{
if (m_Peers.ContainsKey(clientId))
{
// Inject disconnect into remote
m_Peers[clientId].IncomingBuffer.Enqueue(new Event
{
Type = NetworkEvent.Disconnect,
ConnectionId = clientId,
Data = new ArraySegment<byte>()
});
// Inject local disconnect
m_LocalConnection.IncomingBuffer.Enqueue(new Event
{
Type = NetworkEvent.Disconnect,
ConnectionId = clientId,
Data = new ArraySegment<byte>()
});
// Remove the local connection on remote
m_Peers[clientId].Transport.m_LocalConnection = null;
// Remove connection on server
m_Peers.Remove(clientId);
}
}
public override ulong GetCurrentRtt(ulong clientId)
{
// Always returns 50ms
return 50;
}
public override void Initialize()
{
}
private void StopServer()
{
s_Server = null;
m_Peers.Remove(ServerClientId);
m_LocalConnection = null;
}
public override void Shutdown()
{
// Inject disconnects to all the remotes
foreach (KeyValuePair<ulong, Peer> onePeer in m_Peers)
{
onePeer.Value.IncomingBuffer.Enqueue(new Event
{
Type = NetworkEvent.Disconnect,
ConnectionId = LocalClientId,
Data = new ArraySegment<byte>()
});
}
if (m_LocalConnection != null && m_LocalConnection.ConnectionId == ServerClientId)
{
StopServer();
}
// TODO: Cleanup
}
public override bool StartClient()
{
if (s_Server == null)
{
// No server
Debug.LogError("No server");
return false;
}
if (m_LocalConnection != null)
{
// Already connected
Debug.LogError("Already connected");
return false;
}
// Generate an Id for the server that represents this client
ulong serverConnectionId = ++s_Server.Transport.m_ClientsCounter;
LocalClientId = serverConnectionId;
// Create local connection
m_LocalConnection = new Peer()
{
ConnectionId = serverConnectionId,
Transport = this,
IncomingBuffer = new Queue<Event>()
};
// Add the server as a local connection
m_Peers.Add(ServerClientId, s_Server);
// Add local connection as a connection on the server
s_Server.Transport.m_Peers.Add(serverConnectionId, m_LocalConnection);
// Sends a connect message to the server
s_Server.Transport.m_LocalConnection.IncomingBuffer.Enqueue(new Event()
{
Type = NetworkEvent.Connect,
ConnectionId = serverConnectionId,
Data = new ArraySegment<byte>()
});
// Send a local connect message
m_LocalConnection.IncomingBuffer.Enqueue(new Event
{
Type = NetworkEvent.Connect,
ConnectionId = ServerClientId,
Data = new ArraySegment<byte>()
});
return true;
}
public override bool StartServer()
{
if (s_Server != null)
{
// Can only have one server
Debug.LogError("Server already started");
return false;
}
if (m_LocalConnection != null)
{
// Already connected
Debug.LogError("Already connected");
return false;
}
// Create local connection
m_LocalConnection = new Peer()
{
ConnectionId = ServerClientId,
Transport = this,
IncomingBuffer = new Queue<Event>()
};
// Set the local connection as the server
s_Server = m_LocalConnection;
m_Peers.Add(ServerClientId, s_Server);
return true;
}
public override void Send(ulong clientId, ArraySegment<byte> payload, NetworkDelivery networkDelivery)
{
if (m_LocalConnection != null)
{
// Create copy since netcode wants the byte array back straight after the method call.
// Hard on GC.
byte[] copy = new byte[payload.Count];
Buffer.BlockCopy(payload.Array, payload.Offset, copy, 0, payload.Count);
if (m_Peers.ContainsKey(clientId))
{
m_Peers[clientId].IncomingBuffer.Enqueue(new Event
{
Type = NetworkEvent.Data,
ConnectionId = m_LocalConnection.ConnectionId,
Data = new ArraySegment<byte>(copy)
});
}
}
}
public override NetworkEvent PollEvent(out ulong clientId, out ArraySegment<byte> payload, out float receiveTime)
{
if (m_LocalConnection != null)
{
if (m_LocalConnection.IncomingBuffer.Count == 0)
{
clientId = 0;
payload = new ArraySegment<byte>();
receiveTime = 0;
return NetworkEvent.Nothing;
}
var peerEvent = m_LocalConnection.IncomingBuffer.Dequeue();
clientId = peerEvent.ConnectionId;
payload = peerEvent.Data;
receiveTime = 0;
return peerEvent.Type;
}
clientId = 0;
payload = new ArraySegment<byte>();
receiveTime = 0;
return NetworkEvent.Nothing;
}
}
}

View File

@@ -1,3 +0,0 @@
fileFormatVersion: 2
guid: 1fd1b14eba874a189f13f12d343c331c
timeCreated: 1620145176

Some files were not shown because too many files have changed in this diff Show More