com.unity.netcode.gameobjects@1.1.0
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.1.0] - 2022-10-21 ### Added - Added `NetworkManager.IsApproved` flag that is set to `true` a client has been approved.(#2261) - `UnityTransport` now provides a way to set the Relay server data directly from the `RelayServerData` structure (provided by the Unity Transport package) throuh its `SetRelayServerData` method. This allows making use of the new APIs in UTP 1.3 that simplify integration of the Relay SDK. (#2235) - IPv6 is now supported for direct connections when using `UnityTransport`. (#2232) - Added WebSocket support when using UTP 2.0 with `UseWebSockets` property in the `UnityTransport` component of the `NetworkManager` allowing to pick WebSockets for communication. When building for WebGL, this selection happens automatically. (#2201) - Added position, rotation, and scale to the `ParentSyncMessage` which provides users the ability to specify the final values on the server-side when `OnNetworkObjectParentChanged` is invoked just before the message is created (when the `Transform` values are applied to the message). (#2146) - Added `NetworkObject.TryRemoveParent` method for convenience purposes opposed to having to cast null to either `GameObject` or `NetworkObject`. (#2146) ### Changed - Updated `UnityTransport` dependency on `com.unity.transport` to 1.3.0. (#2231) - The send queues of `UnityTransport` are now dynamically-sized. This means that there shouldn't be any need anymore to tweak the 'Max Send Queue Size' value. In fact, this field is now removed from the inspector and will not be serialized anymore. It is still possible to set it manually using the `MaxSendQueueSize` property, but it is not recommended to do so aside from some specific needs (e.g. limiting the amount of memory used by the send queues in very constrained environments). (#2212) - As a consequence of the above change, the `UnityTransport.InitialMaxSendQueueSize` field is now deprecated. There is no default value anymore since send queues are dynamically-sized. (#2212) - The debug simulator in `UnityTransport` is now non-deterministic. Its random number generator used to be seeded with a constant value, leading to the same pattern of packet drops, delays, and jitter in every run. (#2196) - `NetworkVariable<>` now supports managed `INetworkSerializable` types, as well as other managed types with serialization/deserialization delegates registered to `UserNetworkVariableSerialization<T>.WriteValue` and `UserNetworkVariableSerialization<T>.ReadValue` (#2219) - `NetworkVariable<>` and `BufferSerializer<BufferSerializerReader>` now deserialize `INetworkSerializable` types in-place, rather than constructing new ones. (#2219) ### Fixed - Fixed `NetworkManager.ApprovalTimeout` will not timeout due to slower client synchronization times as it now uses the added `NetworkManager.IsApproved` flag to determined if the client has been approved or not.(#2261) - Fixed issue caused when changing ownership of objects hidden to some clients (#2242) - Fixed issue where an in-scene placed NetworkObject would not invoke NetworkBehaviour.OnNetworkSpawn if the GameObject was disabled when it was despawned. (#2239) - Fixed issue where clients were not rebuilding the `NetworkConfig` hash value for each unique connection request. (#2226) - Fixed the issue where player objects were not taking the `DontDestroyWithOwner` property into consideration when a client disconnected. (#2225) - Fixed issue where `SceneEventProgress` would not complete if a client late joins while it is still in progress. (#2222) - Fixed issue where `SceneEventProgress` would not complete if a client disconnects. (#2222) - Fixed issues with detecting if a `SceneEventProgress` has timed out. (#2222) - Fixed issue #1924 where `UnityTransport` would fail to restart after a first failure (even if what caused the initial failure was addressed). (#2220) - Fixed issue where `NetworkTransform.SetStateServerRpc` and `NetworkTransform.SetStateClientRpc` were not honoring local vs world space settings when applying the position and rotation. (#2203) - Fixed ILPP `TypeLoadException` on WebGL on MacOS Editor and potentially other platforms. (#2199) - Implicit conversion of NetworkObjectReference to GameObject will now return null instead of throwing an exception if the referenced object could not be found (i.e., was already despawned) (#2158) - Fixed warning resulting from a stray NetworkAnimator.meta file (#2153) - Fixed Connection Approval Timeout not working client side. (#2164) - Fixed issue where the `WorldPositionStays` parenting parameter was not being synchronized with clients. (#2146) - Fixed issue where parented in-scene placed `NetworkObject`s would fail for late joining clients. (#2146) - Fixed issue where scale was not being synchronized which caused issues with nested parenting and scale when `WorldPositionStays` was true. (#2146) - Fixed issue with `NetworkTransform.ApplyTransformToNetworkStateWithInfo` where it was not honoring axis sync settings when `NetworkTransformState.IsTeleportingNextFrame` was true. (#2146) - Fixed issue with `NetworkTransform.TryCommitTransformToServer` where it was not honoring the `InLocalSpace` setting. (#2146) - Fixed ClientRpcs always reporting in the profiler view as going to all clients, even when limited to a subset of clients by `ClientRpcParams`. (#2144) - Fixed RPC codegen failing to choose the correct extension methods for `FastBufferReader` and `FastBufferWriter` when the parameters were a generic type (i.e., List<int>) and extensions for multiple instantiations of that type have been defined (i.e., List<int> and List<string>) (#2142) - Fixed the issue where running a server (i.e. not host) the second player would not receive updates (unless a third player joined). (#2127) - Fixed issue where late-joining client transition synchronization could fail when more than one transition was occurring.(#2127) - Fixed throwing an exception in `OnNetworkUpdate` causing other `OnNetworkUpdate` calls to not be executed. (#1739) - Fixed synchronization when Time.timeScale is set to 0. This changes timing update to use unscaled deltatime. Now network updates rate are independent from the local time scale. (#2171) - Fixed not sending all NetworkVariables to all clients when a client connects to a server. (#1987) - Fixed IsOwner/IsOwnedByServer being wrong on the server after calling RemoveOwnership (#2211)
This commit is contained in:
@@ -22,17 +22,18 @@ namespace Unity.Netcode.RuntimeTests
|
||||
// Host is irrelevant, messages don't get sent to the host "client"
|
||||
m_UseHost = false;
|
||||
|
||||
yield return null;
|
||||
}
|
||||
|
||||
protected override void OnServerAndClientsCreated()
|
||||
{
|
||||
m_Prefab = new GameObject("Object");
|
||||
var networkObject = m_Prefab.AddComponent<NetworkObject>();
|
||||
m_Prefab.AddComponent<EmptyComponent>();
|
||||
|
||||
// Make it a prefab
|
||||
NetcodeIntegrationTestHelpers.MakeNetworkObjectTestPrefab(networkObject);
|
||||
yield return null;
|
||||
}
|
||||
|
||||
protected override void OnServerAndClientsCreated()
|
||||
{
|
||||
m_ServerNetworkManager.NetworkConfig.SpawnTimeout = 0;
|
||||
m_ServerNetworkManager.NetworkConfig.ForceSamePrefabs = false;
|
||||
foreach (var client in m_ClientNetworkManagers)
|
||||
|
||||
@@ -1,8 +1,161 @@
|
||||
using System;
|
||||
using NUnit.Framework;
|
||||
using Unity.Collections;
|
||||
using UnityEngine;
|
||||
using Unity.Netcode.TestHelpers.Runtime;
|
||||
|
||||
namespace Unity.Netcode.RuntimeTests
|
||||
{
|
||||
public class ManagedNetworkSerializableType : INetworkSerializable, IEquatable<ManagedNetworkSerializableType>
|
||||
{
|
||||
public string Str = "";
|
||||
public int[] Ints = Array.Empty<int>();
|
||||
public int InMemoryValue;
|
||||
|
||||
public void NetworkSerialize<T>(BufferSerializer<T> serializer) where T : IReaderWriter
|
||||
{
|
||||
serializer.SerializeValue(ref Str, true);
|
||||
var length = Ints.Length;
|
||||
serializer.SerializeValue(ref length);
|
||||
if (serializer.IsReader)
|
||||
{
|
||||
Ints = new int[length];
|
||||
}
|
||||
|
||||
for (var i = 0; i < length; ++i)
|
||||
{
|
||||
var val = Ints[i];
|
||||
serializer.SerializeValue(ref val);
|
||||
Ints[i] = val;
|
||||
}
|
||||
}
|
||||
|
||||
public bool Equals(ManagedNetworkSerializableType other)
|
||||
{
|
||||
if (ReferenceEquals(null, other))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ReferenceEquals(this, other))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (Str != other.Str)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Ints.Length != other.Ints.Length)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
for (var i = 0; i < Ints.Length; ++i)
|
||||
{
|
||||
if (Ints[i] != other.Ints[i])
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (ReferenceEquals(null, obj))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ReferenceEquals(this, obj))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (obj.GetType() != GetType())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return Equals((ManagedNetworkSerializableType)obj);
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
public struct UnmanagedNetworkSerializableType : INetworkSerializable, IEquatable<UnmanagedNetworkSerializableType>
|
||||
{
|
||||
public FixedString32Bytes Str;
|
||||
public int Int;
|
||||
public int InMemoryValue;
|
||||
|
||||
public void NetworkSerialize<T>(BufferSerializer<T> serializer) where T : IReaderWriter
|
||||
{
|
||||
serializer.SerializeValue(ref Str);
|
||||
serializer.SerializeValue(ref Int);
|
||||
}
|
||||
|
||||
public bool Equals(UnmanagedNetworkSerializableType other)
|
||||
{
|
||||
return Str.Equals(other.Str) && Int == other.Int;
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (obj == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (obj.GetType() != GetType())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return Equals((ManagedNetworkSerializableType)obj);
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return Str.GetHashCode() ^ Int.GetHashCode() ^ InMemoryValue.GetHashCode();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public struct UnmanagedTemplateNetworkSerializableType<T> : INetworkSerializable where T : unmanaged, INetworkSerializable
|
||||
{
|
||||
public T Value;
|
||||
|
||||
public void NetworkSerialize<TReaderWriterType>(BufferSerializer<TReaderWriterType> serializer) where TReaderWriterType : IReaderWriter
|
||||
{
|
||||
serializer.SerializeValue(ref Value);
|
||||
}
|
||||
}
|
||||
|
||||
public struct ManagedTemplateNetworkSerializableType<T> : INetworkSerializable where T : class, INetworkSerializable, new()
|
||||
{
|
||||
public T Value;
|
||||
|
||||
public void NetworkSerialize<TReaderWriterType>(BufferSerializer<TReaderWriterType> serializer) where TReaderWriterType : IReaderWriter
|
||||
{
|
||||
bool isNull = Value == null;
|
||||
serializer.SerializeValue(ref isNull);
|
||||
if (!isNull)
|
||||
{
|
||||
if (Value == null)
|
||||
{
|
||||
Value = new T();
|
||||
}
|
||||
serializer.SerializeValue(ref Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This provides coverage for all of the predefined NetworkVariable types
|
||||
/// The initial goal is for generalized full coverage of NetworkVariables:
|
||||
@@ -30,6 +183,12 @@ namespace Unity.Netcode.RuntimeTests
|
||||
private NetworkVariable<ulong> m_NetworkVariableULong = new NetworkVariable<ulong>();
|
||||
private NetworkVariable<uint> m_NetworkVariableUInt = new NetworkVariable<uint>();
|
||||
private NetworkVariable<ushort> m_NetworkVariableUShort = new NetworkVariable<ushort>();
|
||||
private NetworkVariable<FixedString32Bytes> m_NetworkVariableFixedString32 = new NetworkVariable<FixedString32Bytes>();
|
||||
private NetworkVariable<FixedString64Bytes> m_NetworkVariableFixedString64 = new NetworkVariable<FixedString64Bytes>();
|
||||
private NetworkVariable<FixedString128Bytes> m_NetworkVariableFixedString128 = new NetworkVariable<FixedString128Bytes>();
|
||||
private NetworkVariable<FixedString512Bytes> m_NetworkVariableFixedString512 = new NetworkVariable<FixedString512Bytes>();
|
||||
private NetworkVariable<FixedString4096Bytes> m_NetworkVariableFixedString4096 = new NetworkVariable<FixedString4096Bytes>();
|
||||
private NetworkVariable<ManagedNetworkSerializableType> m_NetworkVariableManaged = new NetworkVariable<ManagedNetworkSerializableType>();
|
||||
|
||||
|
||||
public NetworkVariableHelper<bool> Bool_Var;
|
||||
@@ -50,6 +209,12 @@ namespace Unity.Netcode.RuntimeTests
|
||||
public NetworkVariableHelper<ulong> Ulong_Var;
|
||||
public NetworkVariableHelper<uint> Uint_Var;
|
||||
public NetworkVariableHelper<ushort> Ushort_Var;
|
||||
public NetworkVariableHelper<FixedString32Bytes> FixedString32_Var;
|
||||
public NetworkVariableHelper<FixedString64Bytes> FixedString64_Var;
|
||||
public NetworkVariableHelper<FixedString128Bytes> FixedString128_Var;
|
||||
public NetworkVariableHelper<FixedString512Bytes> FixedString512_Var;
|
||||
public NetworkVariableHelper<FixedString4096Bytes> FixedString4096_Var;
|
||||
public NetworkVariableHelper<ManagedNetworkSerializableType> Managed_Var;
|
||||
|
||||
|
||||
public bool EnableTesting;
|
||||
@@ -80,6 +245,12 @@ namespace Unity.Netcode.RuntimeTests
|
||||
m_NetworkVariableULong = new NetworkVariable<ulong>();
|
||||
m_NetworkVariableUInt = new NetworkVariable<uint>();
|
||||
m_NetworkVariableUShort = new NetworkVariable<ushort>();
|
||||
m_NetworkVariableFixedString32 = new NetworkVariable<FixedString32Bytes>();
|
||||
m_NetworkVariableFixedString64 = new NetworkVariable<FixedString64Bytes>();
|
||||
m_NetworkVariableFixedString128 = new NetworkVariable<FixedString128Bytes>();
|
||||
m_NetworkVariableFixedString512 = new NetworkVariable<FixedString512Bytes>();
|
||||
m_NetworkVariableFixedString4096 = new NetworkVariable<FixedString4096Bytes>();
|
||||
m_NetworkVariableManaged = new NetworkVariable<ManagedNetworkSerializableType>();
|
||||
|
||||
|
||||
// NetworkVariable Value Type Constructor Test Coverage
|
||||
@@ -101,6 +272,16 @@ namespace Unity.Netcode.RuntimeTests
|
||||
m_NetworkVariableULong = new NetworkVariable<ulong>(1);
|
||||
m_NetworkVariableUInt = new NetworkVariable<uint>(1);
|
||||
m_NetworkVariableUShort = new NetworkVariable<ushort>(1);
|
||||
m_NetworkVariableFixedString32 = new NetworkVariable<FixedString32Bytes>("1234567890");
|
||||
m_NetworkVariableFixedString64 = new NetworkVariable<FixedString64Bytes>("1234567890");
|
||||
m_NetworkVariableFixedString128 = new NetworkVariable<FixedString128Bytes>("1234567890");
|
||||
m_NetworkVariableFixedString512 = new NetworkVariable<FixedString512Bytes>("1234567890");
|
||||
m_NetworkVariableFixedString4096 = new NetworkVariable<FixedString4096Bytes>("1234567890");
|
||||
m_NetworkVariableManaged = new NetworkVariable<ManagedNetworkSerializableType>(new ManagedNetworkSerializableType
|
||||
{
|
||||
Str = "1234567890",
|
||||
Ints = new[] { 1, 2, 3, 4, 5 }
|
||||
});
|
||||
|
||||
// Use this nifty class: NetworkVariableHelper
|
||||
// Tracks if NetworkVariable changed invokes the OnValueChanged callback for the given instance type
|
||||
@@ -122,6 +303,12 @@ namespace Unity.Netcode.RuntimeTests
|
||||
Ulong_Var = new NetworkVariableHelper<ulong>(m_NetworkVariableULong);
|
||||
Uint_Var = new NetworkVariableHelper<uint>(m_NetworkVariableUInt);
|
||||
Ushort_Var = new NetworkVariableHelper<ushort>(m_NetworkVariableUShort);
|
||||
FixedString32_Var = new NetworkVariableHelper<FixedString32Bytes>(m_NetworkVariableFixedString32);
|
||||
FixedString64_Var = new NetworkVariableHelper<FixedString64Bytes>(m_NetworkVariableFixedString64);
|
||||
FixedString128_Var = new NetworkVariableHelper<FixedString128Bytes>(m_NetworkVariableFixedString128);
|
||||
FixedString512_Var = new NetworkVariableHelper<FixedString512Bytes>(m_NetworkVariableFixedString512);
|
||||
FixedString4096_Var = new NetworkVariableHelper<FixedString4096Bytes>(m_NetworkVariableFixedString4096);
|
||||
Managed_Var = new NetworkVariableHelper<ManagedNetworkSerializableType>(m_NetworkVariableManaged);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -152,6 +339,57 @@ namespace Unity.Netcode.RuntimeTests
|
||||
InitializeTest();
|
||||
}
|
||||
|
||||
public void AssertAllValuesAreCorrect()
|
||||
{
|
||||
Assert.AreEqual(false, m_NetworkVariableBool.Value);
|
||||
Assert.AreEqual(255, m_NetworkVariableByte.Value);
|
||||
Assert.AreEqual(100, m_NetworkVariableColor.Value.r);
|
||||
Assert.AreEqual(100, m_NetworkVariableColor.Value.g);
|
||||
Assert.AreEqual(100, m_NetworkVariableColor.Value.b);
|
||||
Assert.AreEqual(100, m_NetworkVariableColor32.Value.r);
|
||||
Assert.AreEqual(100, m_NetworkVariableColor32.Value.g);
|
||||
Assert.AreEqual(100, m_NetworkVariableColor32.Value.b);
|
||||
Assert.AreEqual(100, m_NetworkVariableColor32.Value.a);
|
||||
Assert.AreEqual(1000, m_NetworkVariableDouble.Value);
|
||||
Assert.AreEqual(1000.0f, m_NetworkVariableFloat.Value);
|
||||
Assert.AreEqual(1000, m_NetworkVariableInt.Value);
|
||||
Assert.AreEqual(100000, m_NetworkVariableLong.Value);
|
||||
Assert.AreEqual(-127, m_NetworkVariableSByte.Value);
|
||||
Assert.AreEqual(100, m_NetworkVariableQuaternion.Value.w);
|
||||
Assert.AreEqual(100, m_NetworkVariableQuaternion.Value.x);
|
||||
Assert.AreEqual(100, m_NetworkVariableQuaternion.Value.y);
|
||||
Assert.AreEqual(100, m_NetworkVariableQuaternion.Value.z);
|
||||
Assert.AreEqual(short.MaxValue, m_NetworkVariableShort.Value);
|
||||
Assert.AreEqual(1000, m_NetworkVariableVector4.Value.w);
|
||||
Assert.AreEqual(1000, m_NetworkVariableVector4.Value.x);
|
||||
Assert.AreEqual(1000, m_NetworkVariableVector4.Value.y);
|
||||
Assert.AreEqual(1000, m_NetworkVariableVector4.Value.z);
|
||||
Assert.AreEqual(1000, m_NetworkVariableVector3.Value.x);
|
||||
Assert.AreEqual(1000, m_NetworkVariableVector3.Value.y);
|
||||
Assert.AreEqual(1000, m_NetworkVariableVector3.Value.z);
|
||||
Assert.AreEqual(1000, m_NetworkVariableVector2.Value.x);
|
||||
Assert.AreEqual(1000, m_NetworkVariableVector2.Value.y);
|
||||
Assert.AreEqual(Vector3.one.x, m_NetworkVariableRay.Value.origin.x);
|
||||
Assert.AreEqual(Vector3.one.y, m_NetworkVariableRay.Value.origin.y);
|
||||
Assert.AreEqual(Vector3.one.z, m_NetworkVariableRay.Value.origin.z);
|
||||
Assert.AreEqual(Vector3.right.x, m_NetworkVariableRay.Value.direction.x);
|
||||
Assert.AreEqual(Vector3.right.y, m_NetworkVariableRay.Value.direction.y);
|
||||
Assert.AreEqual(Vector3.right.z, m_NetworkVariableRay.Value.direction.z);
|
||||
Assert.AreEqual(ulong.MaxValue, m_NetworkVariableULong.Value);
|
||||
Assert.AreEqual(uint.MaxValue, m_NetworkVariableUInt.Value);
|
||||
Assert.AreEqual(ushort.MaxValue, m_NetworkVariableUShort.Value);
|
||||
Assert.IsTrue(m_NetworkVariableFixedString32.Value.Equals("FixedString32Bytes"));
|
||||
Assert.IsTrue(m_NetworkVariableFixedString64.Value.Equals("FixedString64Bytes"));
|
||||
Assert.IsTrue(m_NetworkVariableFixedString128.Value.Equals("FixedString128Bytes"));
|
||||
Assert.IsTrue(m_NetworkVariableFixedString512.Value.Equals("FixedString512Bytes"));
|
||||
Assert.IsTrue(m_NetworkVariableFixedString4096.Value.Equals("FixedString4096Bytes"));
|
||||
Assert.IsTrue(m_NetworkVariableManaged.Value.Equals(new ManagedNetworkSerializableType
|
||||
{
|
||||
Str = "ManagedNetworkSerializableType",
|
||||
Ints = new[] { 1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000, 10000 }
|
||||
}));
|
||||
}
|
||||
|
||||
// Update is called once per frame
|
||||
private void Update()
|
||||
{
|
||||
@@ -187,6 +425,16 @@ namespace Unity.Netcode.RuntimeTests
|
||||
m_NetworkVariableULong.Value = ulong.MaxValue;
|
||||
m_NetworkVariableUInt.Value = uint.MaxValue;
|
||||
m_NetworkVariableUShort.Value = ushort.MaxValue;
|
||||
m_NetworkVariableFixedString32.Value = new FixedString32Bytes("FixedString32Bytes");
|
||||
m_NetworkVariableFixedString64.Value = new FixedString64Bytes("FixedString64Bytes");
|
||||
m_NetworkVariableFixedString128.Value = new FixedString128Bytes("FixedString128Bytes");
|
||||
m_NetworkVariableFixedString512.Value = new FixedString512Bytes("FixedString512Bytes");
|
||||
m_NetworkVariableFixedString4096.Value = new FixedString4096Bytes("FixedString4096Bytes");
|
||||
m_NetworkVariableManaged.Value = new ManagedNetworkSerializableType
|
||||
{
|
||||
Str = "ManagedNetworkSerializableType",
|
||||
Ints = new[] { 1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000, 10000 }
|
||||
};
|
||||
|
||||
//Set the timeout (i.e. how long we will wait for all NetworkVariables to have registered their changes)
|
||||
m_WaitForChangesTimeout = Time.realtimeSinceStartup + 0.50f;
|
||||
|
||||
@@ -62,11 +62,27 @@ namespace Unity.Netcode.RuntimeTests
|
||||
response.PlayerPrefabHash = null;
|
||||
}
|
||||
|
||||
|
||||
[Test]
|
||||
public void VerifyUniqueNetworkConfigPerRequest()
|
||||
{
|
||||
var networkConfig = new NetworkConfig();
|
||||
networkConfig.EnableSceneManagement = true;
|
||||
networkConfig.TickRate = 30;
|
||||
var currentHash = networkConfig.GetConfig();
|
||||
networkConfig.EnableSceneManagement = false;
|
||||
networkConfig.TickRate = 60;
|
||||
var newHash = networkConfig.GetConfig(false);
|
||||
|
||||
Assert.True(currentHash != newHash, $"Hashed {nameof(NetworkConfig)} values {currentHash} and {newHash} should not be the same!");
|
||||
}
|
||||
|
||||
[TearDown]
|
||||
public void TearDown()
|
||||
{
|
||||
// Stop, shutdown, and destroy
|
||||
NetworkManagerHelper.ShutdownNetworkManager();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
101
Tests/Runtime/ConnectionApprovalTimeoutTests.cs
Normal file
101
Tests/Runtime/ConnectionApprovalTimeoutTests.cs
Normal file
@@ -0,0 +1,101 @@
|
||||
using System.Collections;
|
||||
using System.Text.RegularExpressions;
|
||||
using NUnit.Framework;
|
||||
using Unity.Netcode.TestHelpers.Runtime;
|
||||
using UnityEngine;
|
||||
using UnityEngine.TestTools;
|
||||
|
||||
namespace Unity.Netcode.RuntimeTests
|
||||
{
|
||||
[TestFixture(ApprovalTimedOutTypes.ServerDoesNotRespond)]
|
||||
[TestFixture(ApprovalTimedOutTypes.ClientDoesNotRequest)]
|
||||
public class ConnectionApprovalTimeoutTests : NetcodeIntegrationTest
|
||||
{
|
||||
protected override int NumberOfClients => 1;
|
||||
|
||||
public enum ApprovalTimedOutTypes
|
||||
{
|
||||
ClientDoesNotRequest,
|
||||
ServerDoesNotRespond
|
||||
}
|
||||
|
||||
private ApprovalTimedOutTypes m_ApprovalFailureType;
|
||||
|
||||
public ConnectionApprovalTimeoutTests(ApprovalTimedOutTypes approvalFailureType)
|
||||
{
|
||||
m_ApprovalFailureType = approvalFailureType;
|
||||
}
|
||||
|
||||
// Must be >= 2 since this is an int value and the test waits for timeout - 1 to try to verify it doesn't
|
||||
// time out early
|
||||
private const int k_TestTimeoutPeriod = 1;
|
||||
|
||||
private Regex m_ExpectedLogMessage;
|
||||
private LogType m_LogType;
|
||||
|
||||
|
||||
protected override IEnumerator OnSetup()
|
||||
{
|
||||
m_BypassConnectionTimeout = true;
|
||||
return base.OnSetup();
|
||||
}
|
||||
|
||||
protected override IEnumerator OnTearDown()
|
||||
{
|
||||
m_BypassConnectionTimeout = false;
|
||||
return base.OnTearDown();
|
||||
}
|
||||
|
||||
protected override void OnServerAndClientsCreated()
|
||||
{
|
||||
m_ServerNetworkManager.NetworkConfig.ClientConnectionBufferTimeout = k_TestTimeoutPeriod;
|
||||
m_ServerNetworkManager.LogLevel = LogLevel.Developer;
|
||||
m_ClientNetworkManagers[0].NetworkConfig.ClientConnectionBufferTimeout = k_TestTimeoutPeriod;
|
||||
m_ClientNetworkManagers[0].LogLevel = LogLevel.Developer;
|
||||
base.OnServerAndClientsCreated();
|
||||
}
|
||||
|
||||
protected override IEnumerator OnStartedServerAndClients()
|
||||
{
|
||||
if (m_ApprovalFailureType == ApprovalTimedOutTypes.ServerDoesNotRespond)
|
||||
{
|
||||
// We catch (don't process) the incoming approval message to simulate the server not sending the approved message in time
|
||||
m_ClientNetworkManagers[0].MessagingSystem.Hook(new MessageCatcher<ConnectionApprovedMessage>(m_ClientNetworkManagers[0]));
|
||||
m_ExpectedLogMessage = new Regex("Timed out waiting for the server to approve the connection request.");
|
||||
m_LogType = LogType.Log;
|
||||
}
|
||||
else
|
||||
{
|
||||
// We catch (don't process) the incoming connection request message to simulate a transport connection but the client never
|
||||
// sends (or takes too long to send) the connection request.
|
||||
m_ServerNetworkManager.MessagingSystem.Hook(new MessageCatcher<ConnectionRequestMessage>(m_ServerNetworkManager));
|
||||
|
||||
// For this test, we know the timed out client will be Client-1
|
||||
m_ExpectedLogMessage = new Regex("Server detected a transport connection from Client-1, but timed out waiting for the connection request message.");
|
||||
m_LogType = LogType.Warning;
|
||||
}
|
||||
yield return null;
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator ValidateApprovalTimeout()
|
||||
{
|
||||
// Delay for half of the wait period
|
||||
yield return new WaitForSeconds(k_TestTimeoutPeriod * 0.5f);
|
||||
|
||||
// Verify we haven't received the time out message yet
|
||||
NetcodeLogAssert.LogWasNotReceived(LogType.Log, m_ExpectedLogMessage);
|
||||
|
||||
// Wait for 3/4s of the time out period to pass (totaling 1.25x the wait period)
|
||||
yield return new WaitForSeconds(k_TestTimeoutPeriod * 0.75f);
|
||||
|
||||
// We should have the test relative log message by this time.
|
||||
NetcodeLogAssert.LogWasReceived(m_LogType, m_ExpectedLogMessage);
|
||||
|
||||
// It should only have the host client connected
|
||||
Assert.AreEqual(1, m_ServerNetworkManager.ConnectedClients.Count, $"Expected only one client when there were {m_ServerNetworkManager.ConnectedClients.Count} clients connected!");
|
||||
Assert.AreEqual(0, m_ServerNetworkManager.PendingClients.Count, $"Expected no pending clients when there were {m_ServerNetworkManager.PendingClients.Count} pending clients!");
|
||||
Assert.True(!m_ClientNetworkManagers[0].IsApproved, $"Expected the client to not have been approved, but it was!");
|
||||
}
|
||||
}
|
||||
}
|
||||
3
Tests/Runtime/ConnectionApprovalTimeoutTests.cs.meta
Normal file
3
Tests/Runtime/ConnectionApprovalTimeoutTests.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b0c4159ea234415fa9497860e6ef4fc2
|
||||
timeCreated: 1661796642
|
||||
@@ -1,8 +1,8 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using Unity.Collections;
|
||||
using UnityEngine;
|
||||
using UnityEngine.TestTools;
|
||||
using Unity.Netcode.TestHelpers.Runtime;
|
||||
@@ -113,82 +113,6 @@ namespace Unity.Netcode.RuntimeTests
|
||||
}
|
||||
}
|
||||
|
||||
internal class SpawnCatcher : INetworkHooks
|
||||
{
|
||||
public struct TriggerData
|
||||
{
|
||||
public FastBufferReader Reader;
|
||||
public MessageHeader Header;
|
||||
public ulong SenderId;
|
||||
public float Timestamp;
|
||||
public int SerializedHeaderSize;
|
||||
}
|
||||
public readonly List<TriggerData> CaughtMessages = new List<TriggerData>();
|
||||
|
||||
public void OnBeforeSendMessage<T>(ulong clientId, ref T message, NetworkDelivery delivery) where T : INetworkMessage
|
||||
{
|
||||
}
|
||||
|
||||
public void OnAfterSendMessage<T>(ulong clientId, ref T message, NetworkDelivery delivery, int messageSizeBytes) where T : INetworkMessage
|
||||
{
|
||||
}
|
||||
|
||||
public void OnBeforeReceiveMessage(ulong senderId, Type messageType, int messageSizeBytes)
|
||||
{
|
||||
}
|
||||
|
||||
public void OnAfterReceiveMessage(ulong senderId, Type messageType, int messageSizeBytes)
|
||||
{
|
||||
}
|
||||
|
||||
public void OnBeforeSendBatch(ulong clientId, int messageCount, int batchSizeInBytes, NetworkDelivery delivery)
|
||||
{
|
||||
}
|
||||
|
||||
public void OnAfterSendBatch(ulong clientId, int messageCount, int batchSizeInBytes, NetworkDelivery delivery)
|
||||
{
|
||||
}
|
||||
|
||||
public void OnBeforeReceiveBatch(ulong senderId, int messageCount, int batchSizeInBytes)
|
||||
{
|
||||
}
|
||||
|
||||
public void OnAfterReceiveBatch(ulong senderId, int messageCount, int batchSizeInBytes)
|
||||
{
|
||||
}
|
||||
|
||||
public bool OnVerifyCanSend(ulong destinationId, Type messageType, NetworkDelivery delivery)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool OnVerifyCanReceive(ulong senderId, Type messageType, FastBufferReader messageContent, ref NetworkContext context)
|
||||
{
|
||||
if (messageType == typeof(CreateObjectMessage))
|
||||
{
|
||||
CaughtMessages.Add(new TriggerData
|
||||
{
|
||||
Reader = new FastBufferReader(messageContent, Allocator.Persistent),
|
||||
Header = context.Header,
|
||||
Timestamp = context.Timestamp,
|
||||
SenderId = context.SenderId,
|
||||
SerializedHeaderSize = context.SerializedHeaderSize
|
||||
});
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void OnBeforeHandleMessage<T>(ref T message, ref NetworkContext context) where T : INetworkMessage
|
||||
{
|
||||
}
|
||||
|
||||
public void OnAfterHandleMessage<T>(ref T message, ref NetworkContext context) where T : INetworkMessage
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public class DeferredMessageTestRpcComponent : NetworkBehaviour
|
||||
{
|
||||
public bool ClientRpcCalled;
|
||||
@@ -198,62 +122,87 @@ namespace Unity.Netcode.RuntimeTests
|
||||
{
|
||||
ClientRpcCalled = true;
|
||||
}
|
||||
|
||||
public static readonly List<ulong> ClientInstances = new List<ulong>();
|
||||
public override void OnNetworkSpawn()
|
||||
{
|
||||
if (!IsServer)
|
||||
{
|
||||
ClientInstances.Add(NetworkManager.LocalClientId);
|
||||
}
|
||||
base.OnNetworkSpawn();
|
||||
}
|
||||
}
|
||||
|
||||
public class DeferredMessageTestNetworkVariableComponent : NetworkBehaviour
|
||||
{
|
||||
public NetworkVariable<int> TestNetworkVariable = new NetworkVariable<int>();
|
||||
public static readonly List<ulong> ClientInstances = new List<ulong>();
|
||||
|
||||
public NetworkVariable<int> TestNetworkVariable;
|
||||
|
||||
public void Awake()
|
||||
{
|
||||
TestNetworkVariable = new NetworkVariable<int>(default, NetworkVariableReadPermission.Everyone, NetworkVariableWritePermission.Owner);
|
||||
}
|
||||
|
||||
public override void OnNetworkSpawn()
|
||||
{
|
||||
if (!IsServer)
|
||||
{
|
||||
ClientInstances.Add(NetworkManager.LocalClientId);
|
||||
}
|
||||
base.OnNetworkSpawn();
|
||||
}
|
||||
}
|
||||
|
||||
public class DeferredMessageTestRpcAndNetworkVariableComponent : NetworkBehaviour
|
||||
{
|
||||
public static readonly List<ulong> ClientInstances = new List<ulong>();
|
||||
public bool ClientRpcCalled;
|
||||
public NetworkVariable<int> TestNetworkVariable;
|
||||
|
||||
public void Awake()
|
||||
{
|
||||
TestNetworkVariable = new NetworkVariable<int>(default, NetworkVariableReadPermission.Everyone, NetworkVariableWritePermission.Owner);
|
||||
}
|
||||
|
||||
public override void OnNetworkSpawn()
|
||||
{
|
||||
if (!IsServer)
|
||||
{
|
||||
ClientInstances.Add(NetworkManager.LocalClientId);
|
||||
}
|
||||
base.OnNetworkSpawn();
|
||||
}
|
||||
|
||||
[ClientRpc]
|
||||
public void SendTestClientRpc()
|
||||
{
|
||||
ClientRpcCalled = true;
|
||||
}
|
||||
|
||||
public NetworkVariable<int> TestNetworkVariable = new NetworkVariable<int>();
|
||||
}
|
||||
|
||||
public class DeferredMessagingTest : NetcodeIntegrationTest
|
||||
{
|
||||
protected override int NumberOfClients => 2;
|
||||
protected override int NumberOfClients => 0;
|
||||
|
||||
private List<SpawnCatcher> m_ClientSpawnCatchers = new List<SpawnCatcher>();
|
||||
private List<MessageCatcher<CreateObjectMessage>> m_ClientSpawnCatchers = new List<MessageCatcher<CreateObjectMessage>>();
|
||||
|
||||
private GameObject m_RpcPrefab;
|
||||
private GameObject m_NetworkVariablePrefab;
|
||||
private GameObject m_RpcAndNetworkVariablePrefab;
|
||||
|
||||
private int m_NumberOfClientsToLateJoin = 2;
|
||||
|
||||
protected override IEnumerator OnSetup()
|
||||
{
|
||||
DeferredMessageTestRpcAndNetworkVariableComponent.ClientInstances.Clear();
|
||||
DeferredMessageTestRpcComponent.ClientInstances.Clear();
|
||||
DeferredMessageTestNetworkVariableComponent.ClientInstances.Clear();
|
||||
m_SkipAddingPrefabsToClient = false;
|
||||
// Host is irrelevant, messages don't get sent to the host "client"
|
||||
m_UseHost = false;
|
||||
|
||||
m_RpcPrefab = new GameObject("Object With RPC");
|
||||
var networkObject = m_RpcPrefab.AddComponent<NetworkObject>();
|
||||
m_RpcPrefab.AddComponent<DeferredMessageTestRpcComponent>();
|
||||
|
||||
// Make it a prefab
|
||||
NetcodeIntegrationTestHelpers.MakeNetworkObjectTestPrefab(networkObject);
|
||||
|
||||
m_NetworkVariablePrefab = new GameObject("Object With NetworkVariable");
|
||||
networkObject = m_NetworkVariablePrefab.AddComponent<NetworkObject>();
|
||||
m_NetworkVariablePrefab.AddComponent<DeferredMessageTestNetworkVariableComponent>();
|
||||
|
||||
// Make it a prefab
|
||||
NetcodeIntegrationTestHelpers.MakeNetworkObjectTestPrefab(networkObject);
|
||||
|
||||
m_RpcAndNetworkVariablePrefab = new GameObject("Object With NetworkVariable And RPC");
|
||||
networkObject = m_RpcAndNetworkVariablePrefab.AddComponent<NetworkObject>();
|
||||
m_RpcAndNetworkVariablePrefab.AddComponent<DeferredMessageTestRpcAndNetworkVariableComponent>();
|
||||
|
||||
// Make it a prefab
|
||||
NetcodeIntegrationTestHelpers.MakeNetworkObjectTestPrefab(networkObject);
|
||||
|
||||
// Replace the IDeferredMessageManager component with our test one in the component factory
|
||||
ComponentFactory.Register<IDeferredMessageManager>(networkManager => new TestDeferredMessageManager(networkManager));
|
||||
yield return null;
|
||||
@@ -269,13 +218,54 @@ namespace Unity.Netcode.RuntimeTests
|
||||
|
||||
protected override void OnServerAndClientsCreated()
|
||||
{
|
||||
m_ServerNetworkManager.AddNetworkPrefab(m_RpcPrefab);
|
||||
m_ServerNetworkManager.AddNetworkPrefab(m_NetworkVariablePrefab);
|
||||
m_ServerNetworkManager.AddNetworkPrefab(m_RpcAndNetworkVariablePrefab);
|
||||
// Note: This is where prefabs should be created
|
||||
m_RpcPrefab = CreateNetworkObjectPrefab("Object With RPC");
|
||||
var networkObject = m_RpcPrefab.GetComponent<NetworkObject>();
|
||||
m_RpcPrefab.AddComponent<DeferredMessageTestRpcComponent>();
|
||||
|
||||
m_NetworkVariablePrefab = CreateNetworkObjectPrefab("Object With NetworkVariable");
|
||||
networkObject = m_NetworkVariablePrefab.GetComponent<NetworkObject>();
|
||||
m_NetworkVariablePrefab.AddComponent<DeferredMessageTestNetworkVariableComponent>();
|
||||
|
||||
m_RpcAndNetworkVariablePrefab = CreateNetworkObjectPrefab("Object With NetworkVariable And RPC");
|
||||
networkObject = m_RpcAndNetworkVariablePrefab.GetComponent<NetworkObject>();
|
||||
m_RpcAndNetworkVariablePrefab.AddComponent<DeferredMessageTestRpcAndNetworkVariableComponent>();
|
||||
|
||||
m_ServerNetworkManager.NetworkConfig.ForceSamePrefabs = false;
|
||||
foreach (var client in m_ClientNetworkManagers)
|
||||
|
||||
}
|
||||
|
||||
private bool m_SkipAddingPrefabsToClient = false;
|
||||
|
||||
private void AddPrefabsToClient(NetworkManager networkManager)
|
||||
{
|
||||
networkManager.AddNetworkPrefab(m_RpcPrefab);
|
||||
networkManager.AddNetworkPrefab(m_NetworkVariablePrefab);
|
||||
networkManager.AddNetworkPrefab(m_RpcAndNetworkVariablePrefab);
|
||||
}
|
||||
|
||||
protected override void OnNewClientCreated(NetworkManager networkManager)
|
||||
{
|
||||
networkManager.NetworkConfig.ForceSamePrefabs = false;
|
||||
if (!m_SkipAddingPrefabsToClient)
|
||||
{
|
||||
client.NetworkConfig.ForceSamePrefabs = false;
|
||||
AddPrefabsToClient(networkManager);
|
||||
}
|
||||
|
||||
base.OnNewClientCreated(networkManager);
|
||||
}
|
||||
|
||||
private IEnumerator SpawnClients(bool clearTestDeferredMessageManagerCallFlags = true)
|
||||
{
|
||||
for (int i = 0; i < m_NumberOfClientsToLateJoin; i++)
|
||||
{
|
||||
// Create and join client
|
||||
yield return CreateAndStartNewClient();
|
||||
}
|
||||
|
||||
if (clearTestDeferredMessageManagerCallFlags)
|
||||
{
|
||||
ClearTestDeferredMessageManagerCallFlags();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -296,38 +286,19 @@ namespace Unity.Netcode.RuntimeTests
|
||||
{
|
||||
foreach (var client in m_ClientNetworkManagers)
|
||||
{
|
||||
var catcher = new SpawnCatcher();
|
||||
var catcher = new MessageCatcher<CreateObjectMessage>(client);
|
||||
m_ClientSpawnCatchers.Add(catcher);
|
||||
client.MessagingSystem.Hook(catcher);
|
||||
}
|
||||
}
|
||||
|
||||
private void RegisterClientPrefabs(bool clearTestDeferredMessageManagerCallFlags = true)
|
||||
{
|
||||
foreach (var client in m_ClientNetworkManagers)
|
||||
{
|
||||
client.AddNetworkPrefab(m_RpcPrefab);
|
||||
client.AddNetworkPrefab(m_NetworkVariablePrefab);
|
||||
client.AddNetworkPrefab(m_RpcAndNetworkVariablePrefab);
|
||||
}
|
||||
|
||||
if (clearTestDeferredMessageManagerCallFlags)
|
||||
{
|
||||
ClearTestDeferredMessageManagerCallFlags();
|
||||
}
|
||||
}
|
||||
|
||||
private void ReleaseSpawns()
|
||||
{
|
||||
for (var i = 0; i < m_ClientNetworkManagers.Length; ++i)
|
||||
{
|
||||
// Unhook first so the spawn catcher stops catching spawns
|
||||
m_ClientNetworkManagers[i].MessagingSystem.Unhook(m_ClientSpawnCatchers[i]);
|
||||
foreach (var caughtSpawn in m_ClientSpawnCatchers[i].CaughtMessages)
|
||||
{
|
||||
// Reader will be disposed within HandleMessage
|
||||
m_ClientNetworkManagers[i].MessagingSystem.HandleMessage(caughtSpawn.Header, caughtSpawn.Reader, caughtSpawn.SenderId, caughtSpawn.Timestamp, caughtSpawn.SerializedHeaderSize);
|
||||
}
|
||||
m_ClientSpawnCatchers[i].ReleaseMessages();
|
||||
}
|
||||
m_ClientSpawnCatchers.Clear();
|
||||
}
|
||||
@@ -345,7 +316,7 @@ namespace Unity.Netcode.RuntimeTests
|
||||
{
|
||||
foreach (var catcher in m_ClientSpawnCatchers)
|
||||
{
|
||||
if (catcher.CaughtMessages.Count != count)
|
||||
if (catcher.CaughtMessageCount != count)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -372,89 +343,54 @@ namespace Unity.Netcode.RuntimeTests
|
||||
Assert.AreEqual(0, manager.DeferredMessageCountForType(IDeferredMessageManager.TriggerType.OnAddPrefab));
|
||||
}
|
||||
|
||||
private static CoroutineRunner s_CoroutineRunner;
|
||||
|
||||
private Coroutine Run(IEnumerator enumerator)
|
||||
private IEnumerator WaitForAllClientsToReceive<T>() where T : INetworkMessage
|
||||
{
|
||||
if (s_CoroutineRunner == null)
|
||||
{
|
||||
s_CoroutineRunner = new GameObject(nameof(CoroutineRunner)).AddComponent<CoroutineRunner>();
|
||||
}
|
||||
|
||||
return s_CoroutineRunner.StartCoroutine(enumerator);
|
||||
yield return WaitForMessageReceived<T>(m_ClientNetworkManagers.ToList(), ReceiptType.Received);
|
||||
}
|
||||
|
||||
private IEnumerator RunMultiple(List<IEnumerator> waitFor)
|
||||
{
|
||||
yield return WaitMultiple(StartMultiple(waitFor));
|
||||
}
|
||||
|
||||
private List<Coroutine> StartMultiple(List<IEnumerator> waitFor)
|
||||
{
|
||||
var runningCoroutines = new List<Coroutine>();
|
||||
foreach (var enumerator in waitFor)
|
||||
{
|
||||
runningCoroutines.Add(Run(enumerator));
|
||||
}
|
||||
|
||||
return runningCoroutines;
|
||||
}
|
||||
|
||||
private IEnumerator WaitMultiple(List<Coroutine> runningCoroutines)
|
||||
{
|
||||
foreach (var coroutine in runningCoroutines)
|
||||
{
|
||||
yield return coroutine;
|
||||
}
|
||||
}
|
||||
|
||||
private List<IEnumerator> WaitForAllClientsToReceive<T>() where T : INetworkMessage
|
||||
{
|
||||
var waiters = new List<IEnumerator>();
|
||||
foreach (var client in m_ClientNetworkManagers)
|
||||
{
|
||||
waiters.Add(NetcodeIntegrationTestHelpers.WaitForMessageOfTypeReceived<T>(client));
|
||||
}
|
||||
|
||||
return waiters;
|
||||
}
|
||||
|
||||
private List<IEnumerator> WaitForAllClientsToReceive<TFirstMessage, TSecondMessage>()
|
||||
private IEnumerator WaitForAllClientsToReceive<TFirstMessage, TSecondMessage>()
|
||||
where TFirstMessage : INetworkMessage
|
||||
where TSecondMessage : INetworkMessage
|
||||
{
|
||||
var waiters = new List<IEnumerator>();
|
||||
foreach (var client in m_ClientNetworkManagers)
|
||||
yield return WaitForMessagesReceived(new List<Type>
|
||||
{
|
||||
waiters.Add(NetcodeIntegrationTestHelpers.WaitForMessageOfTypeReceived<TFirstMessage>(client));
|
||||
waiters.Add(NetcodeIntegrationTestHelpers.WaitForMessageOfTypeReceived<TSecondMessage>(client));
|
||||
}
|
||||
|
||||
return waiters;
|
||||
typeof(TFirstMessage),
|
||||
typeof(TSecondMessage)
|
||||
}, m_ClientNetworkManagers.ToList(), ReceiptType.Received);
|
||||
}
|
||||
|
||||
private List<IEnumerator> WaitForAllClientsToReceive<TFirstMessage, TSecondMessage, TThirdMessage, TFourthMessage>()
|
||||
private IEnumerator WaitForAllClientsToReceive<TFirstMessage, TSecondMessage, TThirdMessage>()
|
||||
where TFirstMessage : INetworkMessage
|
||||
where TSecondMessage : INetworkMessage
|
||||
where TThirdMessage : INetworkMessage
|
||||
{
|
||||
yield return WaitForMessagesReceived(new List<Type>
|
||||
{
|
||||
typeof(TFirstMessage),
|
||||
typeof(TSecondMessage),
|
||||
typeof(TThirdMessage),
|
||||
}, m_ClientNetworkManagers.ToList(), ReceiptType.Received);
|
||||
}
|
||||
|
||||
private IEnumerator WaitForAllClientsToReceive<TFirstMessage, TSecondMessage, TThirdMessage, TFourthMessage>()
|
||||
where TFirstMessage : INetworkMessage
|
||||
where TSecondMessage : INetworkMessage
|
||||
where TThirdMessage : INetworkMessage
|
||||
where TFourthMessage : INetworkMessage
|
||||
{
|
||||
var waiters = new List<IEnumerator>();
|
||||
foreach (var client in m_ClientNetworkManagers)
|
||||
yield return WaitForMessagesReceived(new List<Type>
|
||||
{
|
||||
waiters.Add(NetcodeIntegrationTestHelpers.WaitForMessageOfTypeReceived<TFirstMessage>(client));
|
||||
waiters.Add(NetcodeIntegrationTestHelpers.WaitForMessageOfTypeReceived<TSecondMessage>(client));
|
||||
waiters.Add(NetcodeIntegrationTestHelpers.WaitForMessageOfTypeReceived<TThirdMessage>(client));
|
||||
waiters.Add(NetcodeIntegrationTestHelpers.WaitForMessageOfTypeReceived<TFourthMessage>(client));
|
||||
}
|
||||
|
||||
return waiters;
|
||||
typeof(TFirstMessage),
|
||||
typeof(TSecondMessage),
|
||||
typeof(TThirdMessage),
|
||||
typeof(TFourthMessage),
|
||||
}, m_ClientNetworkManagers.ToList(), ReceiptType.Received);
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator WhenAnRpcArrivesBeforeASpawnArrives_ItIsDeferred()
|
||||
{
|
||||
RegisterClientPrefabs();
|
||||
yield return SpawnClients();
|
||||
CatchSpawns();
|
||||
var serverObject = Object.Instantiate(m_RpcPrefab);
|
||||
serverObject.GetComponent<NetworkObject>().NetworkManagerOwner = m_ServerNetworkManager;
|
||||
@@ -463,7 +399,7 @@ namespace Unity.Netcode.RuntimeTests
|
||||
|
||||
serverObject.GetComponent<DeferredMessageTestRpcComponent>().SendTestClientRpc();
|
||||
|
||||
yield return RunMultiple(WaitForAllClientsToReceive<ClientRpcMessage>());
|
||||
yield return WaitForAllClientsToReceive<ClientRpcMessage>();
|
||||
|
||||
foreach (var client in m_ClientNetworkManagers)
|
||||
{
|
||||
@@ -477,7 +413,7 @@ namespace Unity.Netcode.RuntimeTests
|
||||
[UnityTest]
|
||||
public IEnumerator WhenADespawnArrivesBeforeASpawnArrives_ItIsDeferred()
|
||||
{
|
||||
RegisterClientPrefabs();
|
||||
yield return SpawnClients();
|
||||
CatchSpawns();
|
||||
var serverObject = Object.Instantiate(m_RpcPrefab);
|
||||
serverObject.GetComponent<NetworkObject>().NetworkManagerOwner = m_ServerNetworkManager;
|
||||
@@ -486,7 +422,7 @@ namespace Unity.Netcode.RuntimeTests
|
||||
|
||||
serverObject.GetComponent<NetworkObject>().Despawn(false);
|
||||
|
||||
yield return RunMultiple(WaitForAllClientsToReceive<DestroyObjectMessage>());
|
||||
yield return WaitForAllClientsToReceive<DestroyObjectMessage>();
|
||||
|
||||
foreach (var client in m_ClientNetworkManagers)
|
||||
{
|
||||
@@ -500,7 +436,7 @@ namespace Unity.Netcode.RuntimeTests
|
||||
[UnityTest]
|
||||
public IEnumerator WhenAChangeOwnershipMessageArrivesBeforeASpawnArrives_ItIsDeferred()
|
||||
{
|
||||
RegisterClientPrefabs();
|
||||
yield return SpawnClients();
|
||||
CatchSpawns();
|
||||
var serverObject = Object.Instantiate(m_RpcPrefab);
|
||||
serverObject.GetComponent<NetworkObject>().NetworkManagerOwner = m_ServerNetworkManager;
|
||||
@@ -508,7 +444,7 @@ namespace Unity.Netcode.RuntimeTests
|
||||
yield return WaitForClientsToCatchSpawns();
|
||||
|
||||
serverObject.GetComponent<NetworkObject>().ChangeOwnership(m_ClientNetworkManagers[0].LocalClientId);
|
||||
yield return RunMultiple(WaitForAllClientsToReceive<ChangeOwnershipMessage>());
|
||||
yield return WaitForAllClientsToReceive<ChangeOwnershipMessage>();
|
||||
foreach (var client in m_ClientNetworkManagers)
|
||||
{
|
||||
var manager = (TestDeferredMessageManager)client.DeferredMessageManager;
|
||||
@@ -521,13 +457,10 @@ namespace Unity.Netcode.RuntimeTests
|
||||
[UnityTest]
|
||||
public IEnumerator WhenANetworkVariableDeltaMessageArrivesBeforeASpawnArrives_ItIsDeferred()
|
||||
{
|
||||
RegisterClientPrefabs();
|
||||
m_SkipAddingPrefabsToClient = true;
|
||||
yield return SpawnClients();
|
||||
CatchSpawns();
|
||||
|
||||
// Have to start these before spawning here because spawning sends a NetworkVariableDeltaMessage, too
|
||||
// Depending on timing, if we start this after spawning, we may end up missing the first one.
|
||||
var waiters = WaitForAllClientsToReceive<NetworkVariableDeltaMessage, NetworkVariableDeltaMessage>();
|
||||
var coroutines = StartMultiple(waiters);
|
||||
|
||||
var serverObject = Object.Instantiate(m_NetworkVariablePrefab);
|
||||
serverObject.GetComponent<NetworkObject>().NetworkManagerOwner = m_ServerNetworkManager;
|
||||
@@ -536,7 +469,7 @@ namespace Unity.Netcode.RuntimeTests
|
||||
|
||||
serverObject.GetComponent<DeferredMessageTestNetworkVariableComponent>().TestNetworkVariable.Value = 1;
|
||||
|
||||
yield return WaitMultiple(coroutines);
|
||||
yield return WaitForAllClientsToReceive<NetworkVariableDeltaMessage>();
|
||||
|
||||
foreach (var client in m_ClientNetworkManagers)
|
||||
{
|
||||
@@ -545,18 +478,21 @@ namespace Unity.Netcode.RuntimeTests
|
||||
Assert.IsFalse(manager.ProcessTriggersCalled);
|
||||
// TODO: Network Variables generate an extra message immediately at spawn for some reason...
|
||||
// Seems like a bug since the network variable data is in the spawn message already.
|
||||
AssertSpawnTriggerCountForObject(manager, serverObject, 2);
|
||||
AssertSpawnTriggerCountForObject(manager, serverObject, 1);
|
||||
}
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
//[Ignore("Disabling this temporarily until it is migrated into new integration test.")]
|
||||
public IEnumerator WhenASpawnMessageArrivesBeforeThePrefabIsAvailable_ItIsDeferred()
|
||||
{
|
||||
m_SkipAddingPrefabsToClient = true;
|
||||
yield return SpawnClients();
|
||||
var serverObject = Object.Instantiate(m_RpcPrefab);
|
||||
serverObject.GetComponent<NetworkObject>().NetworkManagerOwner = m_ServerNetworkManager;
|
||||
serverObject.GetComponent<NetworkObject>().Spawn();
|
||||
|
||||
yield return RunMultiple(WaitForAllClientsToReceive<CreateObjectMessage>());
|
||||
yield return WaitForAllClientsToReceive<CreateObjectMessage>();
|
||||
|
||||
foreach (var client in m_ClientNetworkManagers)
|
||||
{
|
||||
@@ -631,8 +567,28 @@ namespace Unity.Netcode.RuntimeTests
|
||||
public IEnumerator WhenANetworkVariableDeltaMessageIsDeferred_ItIsProcessedOnSpawn()
|
||||
{
|
||||
yield return WhenANetworkVariableDeltaMessageArrivesBeforeASpawnArrives_ItIsDeferred();
|
||||
|
||||
foreach (var client in m_ClientNetworkManagers)
|
||||
{
|
||||
AddPrefabsToClient(client);
|
||||
}
|
||||
|
||||
ReleaseSpawns();
|
||||
|
||||
// Wait for the clients to spawn the NetworkObjects
|
||||
bool HaveAllClientsSpawned()
|
||||
{
|
||||
foreach (var client in m_ClientNetworkManagers)
|
||||
{
|
||||
if (!DeferredMessageTestNetworkVariableComponent.ClientInstances.Contains(client.LocalClientId))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
yield return WaitForConditionOrTimeOut(HaveAllClientsSpawned);
|
||||
|
||||
foreach (var client in m_ClientNetworkManagers)
|
||||
{
|
||||
var manager = (TestDeferredMessageManager)client.DeferredMessageManager;
|
||||
@@ -647,9 +603,31 @@ namespace Unity.Netcode.RuntimeTests
|
||||
[UnityTest]
|
||||
public IEnumerator WhenASpawnMessageIsDeferred_ItIsProcessedOnAddPrefab()
|
||||
{
|
||||
// This will prevent spawned clients from adding prefabs
|
||||
m_SkipAddingPrefabsToClient = true;
|
||||
yield return WhenASpawnMessageArrivesBeforeThePrefabIsAvailable_ItIsDeferred();
|
||||
RegisterClientPrefabs(false);
|
||||
|
||||
// Now add the prefabs
|
||||
foreach (var client in m_ClientNetworkManagers)
|
||||
{
|
||||
AddPrefabsToClient(client);
|
||||
}
|
||||
|
||||
// Wait for the clients to spawn the NetworkObjects
|
||||
bool HaveAllClientsSpawned()
|
||||
{
|
||||
foreach (var client in m_ClientNetworkManagers)
|
||||
{
|
||||
if (!DeferredMessageTestRpcComponent.ClientInstances.Contains(client.LocalClientId))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
yield return WaitForConditionOrTimeOut(HaveAllClientsSpawned);
|
||||
|
||||
// Validate this test
|
||||
foreach (var client in m_ClientNetworkManagers)
|
||||
{
|
||||
var manager = (TestDeferredMessageManager)client.DeferredMessageManager;
|
||||
@@ -664,14 +642,10 @@ namespace Unity.Netcode.RuntimeTests
|
||||
[UnityTest]
|
||||
public IEnumerator WhenMultipleSpawnTriggeredMessagesAreDeferred_TheyAreAllProcessedOnSpawn()
|
||||
{
|
||||
RegisterClientPrefabs();
|
||||
m_SkipAddingPrefabsToClient = true;
|
||||
yield return SpawnClients();
|
||||
CatchSpawns();
|
||||
|
||||
// Have to start these before spawning here because spawning sends a NetworkVariableDeltaMessage, too
|
||||
// Depending on timing, if we start this after spawning, we may end up missing the first one.
|
||||
var waiters = WaitForAllClientsToReceive<ClientRpcMessage, NetworkVariableDeltaMessage, NetworkVariableDeltaMessage, ChangeOwnershipMessage>();
|
||||
var coroutines = StartMultiple(waiters);
|
||||
|
||||
var serverObject = Object.Instantiate(m_RpcAndNetworkVariablePrefab);
|
||||
serverObject.GetComponent<NetworkObject>().NetworkManagerOwner = m_ServerNetworkManager;
|
||||
serverObject.GetComponent<NetworkObject>().Spawn();
|
||||
@@ -679,10 +653,12 @@ namespace Unity.Netcode.RuntimeTests
|
||||
|
||||
serverObject.GetComponent<DeferredMessageTestRpcAndNetworkVariableComponent>().SendTestClientRpc();
|
||||
serverObject.GetComponent<DeferredMessageTestRpcAndNetworkVariableComponent>().TestNetworkVariable.Value = 1;
|
||||
|
||||
yield return WaitForAllClientsToReceive<ClientRpcMessage, NetworkVariableDeltaMessage>();
|
||||
|
||||
serverObject.GetComponent<NetworkObject>().ChangeOwnership(m_ClientNetworkManagers[0].LocalClientId);
|
||||
|
||||
// Should be received in order so we'll wait for the last one.
|
||||
yield return WaitMultiple(coroutines);
|
||||
yield return WaitForAllClientsToReceive<ChangeOwnershipMessage>();
|
||||
|
||||
foreach (var client in m_ClientNetworkManagers)
|
||||
{
|
||||
@@ -690,29 +666,49 @@ namespace Unity.Netcode.RuntimeTests
|
||||
Assert.IsTrue(manager.DeferMessageCalled);
|
||||
Assert.IsFalse(manager.ProcessTriggersCalled);
|
||||
|
||||
Assert.AreEqual(4, manager.DeferredMessageCountTotal());
|
||||
Assert.AreEqual(4, manager.DeferredMessageCountForType(IDeferredMessageManager.TriggerType.OnSpawn));
|
||||
Assert.AreEqual(4, manager.DeferredMessageCountForKey(IDeferredMessageManager.TriggerType.OnSpawn, serverObject.GetComponent<NetworkObject>().NetworkObjectId));
|
||||
Assert.AreEqual(3, manager.DeferredMessageCountTotal());
|
||||
Assert.AreEqual(3, manager.DeferredMessageCountForType(IDeferredMessageManager.TriggerType.OnSpawn));
|
||||
Assert.AreEqual(3, manager.DeferredMessageCountForKey(IDeferredMessageManager.TriggerType.OnSpawn, serverObject.GetComponent<NetworkObject>().NetworkObjectId));
|
||||
Assert.AreEqual(0, manager.DeferredMessageCountForType(IDeferredMessageManager.TriggerType.OnAddPrefab));
|
||||
AddPrefabsToClient(client);
|
||||
}
|
||||
|
||||
ReleaseSpawns();
|
||||
|
||||
// Wait for the clients to spawn the NetworkObjects
|
||||
bool HaveAllClientsSpawned()
|
||||
{
|
||||
foreach (var client in m_ClientNetworkManagers)
|
||||
{
|
||||
if (!DeferredMessageTestRpcAndNetworkVariableComponent.ClientInstances.Contains(client.LocalClientId))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
yield return WaitForConditionOrTimeOut(HaveAllClientsSpawned);
|
||||
yield return new WaitForSeconds(0.1f);
|
||||
|
||||
// Validate the spawned objects
|
||||
foreach (var client in m_ClientNetworkManagers)
|
||||
{
|
||||
var manager = (TestDeferredMessageManager)client.DeferredMessageManager;
|
||||
Assert.IsTrue(manager.ProcessTriggersCalled);
|
||||
Assert.AreEqual(0, manager.DeferredMessageCountTotal());
|
||||
Assert.IsTrue(manager.ProcessTriggersCalled, "Process triggers were not called!");
|
||||
Assert.AreEqual(0, manager.DeferredMessageCountTotal(), $"Deferred message count ({manager.DeferredMessageCountTotal()}) is not zero!");
|
||||
|
||||
var component = GetComponentForClient<DeferredMessageTestRpcAndNetworkVariableComponent>(client.LocalClientId);
|
||||
Assert.IsTrue(component.ClientRpcCalled);
|
||||
Assert.AreEqual(1, component.TestNetworkVariable.Value);
|
||||
Assert.AreEqual(m_ClientNetworkManagers[0].LocalClientId, component.OwnerClientId);
|
||||
Assert.IsTrue(component.ClientRpcCalled, "Client RPC was not called!");
|
||||
Assert.AreEqual(1, component.TestNetworkVariable.Value, $"Test {nameof(NetworkVariable<int>)} ({component.TestNetworkVariable.Value}) does not equal 1!");
|
||||
Assert.AreEqual(m_ClientNetworkManagers[0].LocalClientId, component.OwnerClientId, $"{component.name} owner id ({component.OwnerClientId}) does not equal first client id ({m_ClientNetworkManagers[0].LocalClientId})");
|
||||
}
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator WhenMultipleAddPrefabTriggeredMessagesAreDeferred_TheyAreAllProcessedOnAddNetworkPrefab()
|
||||
{
|
||||
m_SkipAddingPrefabsToClient = true;
|
||||
yield return SpawnClients();
|
||||
var serverObject = Object.Instantiate(m_RpcPrefab);
|
||||
serverObject.GetComponent<NetworkObject>().NetworkManagerOwner = m_ServerNetworkManager;
|
||||
serverObject.GetComponent<NetworkObject>().Spawn();
|
||||
@@ -721,7 +717,7 @@ namespace Unity.Netcode.RuntimeTests
|
||||
serverObject2.GetComponent<NetworkObject>().NetworkManagerOwner = m_ServerNetworkManager;
|
||||
serverObject2.GetComponent<NetworkObject>().Spawn();
|
||||
|
||||
yield return RunMultiple(WaitForAllClientsToReceive<CreateObjectMessage, CreateObjectMessage>());
|
||||
yield return WaitForAllClientsToReceive<CreateObjectMessage, CreateObjectMessage>();
|
||||
|
||||
foreach (var client in m_ClientNetworkManagers)
|
||||
{
|
||||
@@ -733,9 +729,23 @@ namespace Unity.Netcode.RuntimeTests
|
||||
Assert.AreEqual(0, manager.DeferredMessageCountForType(IDeferredMessageManager.TriggerType.OnSpawn));
|
||||
Assert.AreEqual(2, manager.DeferredMessageCountForType(IDeferredMessageManager.TriggerType.OnAddPrefab));
|
||||
Assert.AreEqual(2, manager.DeferredMessageCountForKey(IDeferredMessageManager.TriggerType.OnAddPrefab, serverObject.GetComponent<NetworkObject>().GlobalObjectIdHash));
|
||||
AddPrefabsToClient(client);
|
||||
}
|
||||
|
||||
RegisterClientPrefabs(false);
|
||||
// Wait for the clients to spawn the NetworkObjects
|
||||
bool HaveAllClientsSpawned()
|
||||
{
|
||||
foreach (var client in m_ClientNetworkManagers)
|
||||
{
|
||||
if (!DeferredMessageTestRpcComponent.ClientInstances.Contains(client.LocalClientId))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
yield return WaitForConditionOrTimeOut(HaveAllClientsSpawned);
|
||||
|
||||
|
||||
foreach (var client in m_ClientNetworkManagers)
|
||||
{
|
||||
@@ -769,10 +779,8 @@ namespace Unity.Netcode.RuntimeTests
|
||||
[UnityTest]
|
||||
public IEnumerator WhenSpawnTriggeredMessagesAreDeferredBeforeThePrefabIsAdded_AddingThePrefabCausesThemToBeProcessed()
|
||||
{
|
||||
// Because we're not waiting for the client to receive the spawn before we change the network variable value,
|
||||
// there's only one NetworkVariableDeltaMessage this time.
|
||||
var waiters = WaitForAllClientsToReceive<CreateObjectMessage, ClientRpcMessage, NetworkVariableDeltaMessage, ChangeOwnershipMessage>();
|
||||
var coroutines = StartMultiple(waiters);
|
||||
m_SkipAddingPrefabsToClient = true;
|
||||
yield return SpawnClients();
|
||||
|
||||
var serverObject = Object.Instantiate(m_RpcAndNetworkVariablePrefab);
|
||||
serverObject.GetComponent<NetworkObject>().NetworkManagerOwner = m_ServerNetworkManager;
|
||||
@@ -780,10 +788,15 @@ namespace Unity.Netcode.RuntimeTests
|
||||
|
||||
serverObject.GetComponent<DeferredMessageTestRpcAndNetworkVariableComponent>().SendTestClientRpc();
|
||||
serverObject.GetComponent<DeferredMessageTestRpcAndNetworkVariableComponent>().TestNetworkVariable.Value = 1;
|
||||
// TODO: Remove this if we figure out how to work around the NetworkVariableDeltaMessage.Serialized issue at line 59
|
||||
// Otherwise, we have to wait for at least 1 tick for the NetworkVariableDeltaMessage to be generated before changing ownership
|
||||
yield return WaitForAllClientsToReceive<CreateObjectMessage, ClientRpcMessage, NetworkVariableDeltaMessage>();
|
||||
|
||||
serverObject.GetComponent<NetworkObject>().ChangeOwnership(m_ClientNetworkManagers[0].LocalClientId);
|
||||
|
||||
yield return WaitMultiple(coroutines);
|
||||
yield return WaitForAllClientsToReceive<ChangeOwnershipMessage>();
|
||||
|
||||
// Validate messages are deferred and pending
|
||||
foreach (var client in m_ClientNetworkManagers)
|
||||
{
|
||||
var manager = (TestDeferredMessageManager)client.DeferredMessageManager;
|
||||
@@ -794,10 +807,26 @@ namespace Unity.Netcode.RuntimeTests
|
||||
Assert.AreEqual(3, manager.DeferredMessageCountForKey(IDeferredMessageManager.TriggerType.OnSpawn, serverObject.GetComponent<NetworkObject>().NetworkObjectId));
|
||||
Assert.AreEqual(1, manager.DeferredMessageCountForType(IDeferredMessageManager.TriggerType.OnAddPrefab));
|
||||
Assert.AreEqual(1, manager.DeferredMessageCountForKey(IDeferredMessageManager.TriggerType.OnAddPrefab, serverObject.GetComponent<NetworkObject>().GlobalObjectIdHash));
|
||||
AddPrefabsToClient(client);
|
||||
}
|
||||
|
||||
RegisterClientPrefabs(false);
|
||||
// Wait for the clients to spawn the NetworkObjects
|
||||
bool HaveAllClientsSpawned()
|
||||
{
|
||||
foreach (var client in m_ClientNetworkManagers)
|
||||
{
|
||||
if (!DeferredMessageTestRpcAndNetworkVariableComponent.ClientInstances.Contains(client.LocalClientId))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
yield return WaitForConditionOrTimeOut(HaveAllClientsSpawned);
|
||||
|
||||
yield return new WaitForSeconds(0.1f);
|
||||
|
||||
// Validate the test
|
||||
foreach (var client in m_ClientNetworkManagers)
|
||||
{
|
||||
var manager = (TestDeferredMessageManager)client.DeferredMessageManager;
|
||||
@@ -813,10 +842,10 @@ namespace Unity.Netcode.RuntimeTests
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
[Ignore("This test is unstable (MTT-4146)")]
|
||||
public IEnumerator WhenAMessageIsDeferredForMoreThanTheConfiguredTime_ItIsRemoved([Values(1, 2, 3)] int timeout)
|
||||
{
|
||||
RegisterClientPrefabs();
|
||||
m_SkipAddingPrefabsToClient = true;
|
||||
yield return SpawnClients();
|
||||
CatchSpawns();
|
||||
foreach (var client in m_ClientNetworkManagers)
|
||||
{
|
||||
@@ -870,24 +899,29 @@ namespace Unity.Netcode.RuntimeTests
|
||||
|
||||
yield return new WaitForSeconds(timeout + 0.1f);
|
||||
|
||||
Assert.AreEqual(NumberOfClients, purgeCount);
|
||||
foreach (var client in m_ClientNetworkManagers)
|
||||
bool HaveAllClientsPurged()
|
||||
{
|
||||
var manager = (TestDeferredMessageManager)client.DeferredMessageManager;
|
||||
Assert.AreEqual(0, manager.DeferredMessageCountTotal());
|
||||
foreach (var client in m_ClientNetworkManagers)
|
||||
{
|
||||
var manager = (TestDeferredMessageManager)client.DeferredMessageManager;
|
||||
if (manager.DeferredMessageCountTotal() != 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
yield return WaitForConditionOrTimeOut(HaveAllClientsPurged);
|
||||
AssertOnTimeout("Timed out waiting for all clients to purge their deferred messages!");
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
[Ignore("This test is unstable on standalones")]
|
||||
public IEnumerator WhenMultipleMessagesForTheSameObjectAreDeferredForMoreThanTheConfiguredTime_TheyAreAllRemoved([Values(1, 2, 3)] int timeout)
|
||||
{
|
||||
RegisterClientPrefabs();
|
||||
m_SkipAddingPrefabsToClient = true;
|
||||
yield return SpawnClients();
|
||||
CatchSpawns();
|
||||
// Have to start these before spawning here because spawning sends a NetworkVariableDeltaMessage, too
|
||||
// Depending on timing, if we start this after spawning, we may end up missing the first one.
|
||||
var waiters = WaitForAllClientsToReceive<ClientRpcMessage, NetworkVariableDeltaMessage, NetworkVariableDeltaMessage, ChangeOwnershipMessage>();
|
||||
var coroutines = StartMultiple(waiters);
|
||||
|
||||
foreach (var client in m_ClientNetworkManagers)
|
||||
{
|
||||
@@ -917,7 +951,9 @@ namespace Unity.Netcode.RuntimeTests
|
||||
serverObject.GetComponent<DeferredMessageTestRpcAndNetworkVariableComponent>().TestNetworkVariable.Value = 1;
|
||||
serverObject.GetComponent<NetworkObject>().ChangeOwnership(m_ClientNetworkManagers[0].LocalClientId);
|
||||
|
||||
yield return WaitMultiple(coroutines);
|
||||
yield return WaitForMessagesReceived(
|
||||
new List<Type> {typeof(ClientRpcMessage), typeof(NetworkVariableDeltaMessage), typeof(ChangeOwnershipMessage),
|
||||
}, m_ClientNetworkManagers.ToList(), ReceiptType.Received);
|
||||
|
||||
foreach (var unused in m_ClientNetworkManagers)
|
||||
{
|
||||
@@ -931,38 +967,40 @@ namespace Unity.Netcode.RuntimeTests
|
||||
{
|
||||
++purgeCount;
|
||||
var elapsed = Time.realtimeSinceStartup - start;
|
||||
Assert.GreaterOrEqual(elapsed, timeout - 0.05f);
|
||||
Assert.AreEqual(4, manager.DeferredMessageCountTotal());
|
||||
Assert.AreEqual(4, manager.DeferredMessageCountForType(IDeferredMessageManager.TriggerType.OnSpawn));
|
||||
Assert.AreEqual(4, manager.DeferredMessageCountForKey(IDeferredMessageManager.TriggerType.OnSpawn, key));
|
||||
Assert.GreaterOrEqual(elapsed, timeout - 0.25f);
|
||||
Assert.AreEqual(3, manager.DeferredMessageCountTotal());
|
||||
Assert.AreEqual(3, manager.DeferredMessageCountForType(IDeferredMessageManager.TriggerType.OnSpawn));
|
||||
Assert.AreEqual(3, manager.DeferredMessageCountForKey(IDeferredMessageManager.TriggerType.OnSpawn, key));
|
||||
Assert.AreEqual(serverObject.GetComponent<NetworkObject>().NetworkObjectId, key);
|
||||
};
|
||||
var manager = (TestDeferredMessageManager)client.DeferredMessageManager;
|
||||
manager.OnBeforePurge = beforePurge;
|
||||
}
|
||||
|
||||
yield return new WaitForSeconds(timeout + 0.1f);
|
||||
|
||||
Assert.AreEqual(NumberOfClients, purgeCount);
|
||||
foreach (var client in m_ClientNetworkManagers)
|
||||
bool HaveAllClientsPurged()
|
||||
{
|
||||
var manager = (TestDeferredMessageManager)client.DeferredMessageManager;
|
||||
Assert.AreEqual(0, manager.DeferredMessageCountTotal());
|
||||
foreach (var client in m_ClientNetworkManagers)
|
||||
{
|
||||
var manager = (TestDeferredMessageManager)client.DeferredMessageManager;
|
||||
if (manager.DeferredMessageCountTotal() != 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
yield return WaitForConditionOrTimeOut(HaveAllClientsPurged);
|
||||
AssertOnTimeout("Timed out waiting for all clients to purge their deferred messages!");
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator WhenMultipleMessagesForDifferentObjectsAreDeferredForMoreThanTheConfiguredTime_TheyAreAllRemoved([Values(1, 2, 3)] int timeout)
|
||||
{
|
||||
RegisterClientPrefabs();
|
||||
m_SkipAddingPrefabsToClient = true;
|
||||
yield return SpawnClients();
|
||||
CatchSpawns();
|
||||
|
||||
// Have to start these before spawning here because spawning sends a NetworkVariableDeltaMessage, too
|
||||
// Depending on timing, if we start this after spawning, we may end up missing the first one.
|
||||
var waiters = WaitForAllClientsToReceive<ClientRpcMessage, NetworkVariableDeltaMessage, NetworkVariableDeltaMessage, ChangeOwnershipMessage>();
|
||||
waiters.AddRange(WaitForAllClientsToReceive<ClientRpcMessage, NetworkVariableDeltaMessage, NetworkVariableDeltaMessage, ChangeOwnershipMessage>());
|
||||
var coroutines = StartMultiple(waiters);
|
||||
|
||||
foreach (var client in m_ClientNetworkManagers)
|
||||
{
|
||||
client.NetworkConfig.SpawnTimeout = timeout;
|
||||
@@ -1000,10 +1038,13 @@ namespace Unity.Netcode.RuntimeTests
|
||||
serverObject2.GetComponent<DeferredMessageTestRpcAndNetworkVariableComponent>().TestNetworkVariable.Value = 1;
|
||||
serverObject2.GetComponent<NetworkObject>().ChangeOwnership(m_ClientNetworkManagers[0].LocalClientId);
|
||||
|
||||
yield return WaitMultiple(coroutines);
|
||||
yield return WaitForMessagesReceived(
|
||||
new List<Type> {typeof(ClientRpcMessage), typeof(NetworkVariableDeltaMessage), typeof(ChangeOwnershipMessage),typeof(ClientRpcMessage), typeof(NetworkVariableDeltaMessage), typeof(ChangeOwnershipMessage),
|
||||
}, m_ClientNetworkManagers.ToList(), ReceiptType.Received);
|
||||
|
||||
foreach (var unused in m_ClientNetworkManagers)
|
||||
{
|
||||
|
||||
LogAssert.Expect(LogType.Warning, $"[Netcode] Deferred messages were received for a trigger of type {IDeferredMessageManager.TriggerType.OnSpawn} with key {serverObject.GetComponent<NetworkObject>().NetworkObjectId}, but that trigger was not received within within {timeout} second(s).");
|
||||
LogAssert.Expect(LogType.Warning, $"[Netcode] Deferred messages were received for a trigger of type {IDeferredMessageManager.TriggerType.OnSpawn} with key {serverObject2.GetComponent<NetworkObject>().NetworkObjectId}, but that trigger was not received within within {timeout} second(s).");
|
||||
}
|
||||
@@ -1011,24 +1052,27 @@ namespace Unity.Netcode.RuntimeTests
|
||||
int purgeCount = 0;
|
||||
foreach (var client in m_ClientNetworkManagers)
|
||||
{
|
||||
var remainingMessagesTotalThisClient = 8;
|
||||
var remainingMessagesTotalThisClient = 6;
|
||||
TestDeferredMessageManager.BeforePurgeDelegate beforePurge = (manager, key) =>
|
||||
{
|
||||
++purgeCount;
|
||||
var elapsed = Time.realtimeSinceStartup - start;
|
||||
Assert.GreaterOrEqual(elapsed, timeout - 0.05f);
|
||||
Assert.GreaterOrEqual(elapsed, timeout - 0.25f);
|
||||
Assert.AreEqual(remainingMessagesTotalThisClient, manager.DeferredMessageCountTotal());
|
||||
Assert.AreEqual(remainingMessagesTotalThisClient, manager.DeferredMessageCountForType(IDeferredMessageManager.TriggerType.OnSpawn));
|
||||
Assert.AreEqual(4, manager.DeferredMessageCountForKey(IDeferredMessageManager.TriggerType.OnSpawn, key));
|
||||
remainingMessagesTotalThisClient -= 4;
|
||||
Assert.AreEqual(3, manager.DeferredMessageCountForKey(IDeferredMessageManager.TriggerType.OnSpawn, key));
|
||||
remainingMessagesTotalThisClient -= 3;
|
||||
};
|
||||
var manager = (TestDeferredMessageManager)client.DeferredMessageManager;
|
||||
manager.OnBeforePurge = beforePurge;
|
||||
}
|
||||
|
||||
yield return new WaitForSeconds(timeout + 0.1f);
|
||||
|
||||
Assert.AreEqual(NumberOfClients * 2, purgeCount);
|
||||
foreach (var client in m_ClientNetworkManagers)
|
||||
{
|
||||
AddPrefabsToClient(client);
|
||||
}
|
||||
Assert.AreEqual(m_NumberOfClientsToLateJoin * 2, purgeCount);
|
||||
foreach (var client in m_ClientNetworkManagers)
|
||||
{
|
||||
var manager = (TestDeferredMessageManager)client.DeferredMessageManager;
|
||||
@@ -1039,7 +1083,8 @@ namespace Unity.Netcode.RuntimeTests
|
||||
[UnityTest]
|
||||
public IEnumerator WhenADeferredMessageIsRemoved_OtherMessagesForSameObjectAreRemoved([Values(1, 2, 3)] int timeout)
|
||||
{
|
||||
RegisterClientPrefabs();
|
||||
m_SkipAddingPrefabsToClient = true;
|
||||
yield return SpawnClients();
|
||||
CatchSpawns();
|
||||
foreach (var client in m_ClientNetworkManagers)
|
||||
{
|
||||
@@ -1067,7 +1112,7 @@ namespace Unity.Netcode.RuntimeTests
|
||||
|
||||
serverObject.GetComponent<NetworkObject>().ChangeOwnership(m_ClientNetworkManagers[0].LocalClientId);
|
||||
|
||||
yield return RunMultiple(WaitForAllClientsToReceive<ChangeOwnershipMessage>());
|
||||
yield return WaitForAllClientsToReceive<ChangeOwnershipMessage>();
|
||||
|
||||
yield return new WaitForSeconds(timeout - 0.5f);
|
||||
|
||||
@@ -1080,7 +1125,7 @@ namespace Unity.Netcode.RuntimeTests
|
||||
}
|
||||
|
||||
serverObject.GetComponent<NetworkObject>().ChangeOwnership(m_ServerNetworkManager.LocalClientId);
|
||||
yield return RunMultiple(WaitForAllClientsToReceive<ChangeOwnershipMessage>());
|
||||
yield return WaitForAllClientsToReceive<ChangeOwnershipMessage>();
|
||||
|
||||
foreach (var client in m_ClientNetworkManagers)
|
||||
{
|
||||
@@ -1112,9 +1157,14 @@ namespace Unity.Netcode.RuntimeTests
|
||||
manager.OnBeforePurge = beforePurge;
|
||||
}
|
||||
|
||||
foreach (var client in m_ClientNetworkManagers)
|
||||
{
|
||||
AddPrefabsToClient(client);
|
||||
}
|
||||
|
||||
yield return new WaitForSeconds(0.6f);
|
||||
|
||||
Assert.AreEqual(NumberOfClients, purgeCount);
|
||||
Assert.AreEqual(m_NumberOfClientsToLateJoin, purgeCount);
|
||||
foreach (var client in m_ClientNetworkManagers)
|
||||
{
|
||||
var manager = (TestDeferredMessageManager)client.DeferredMessageManager;
|
||||
@@ -1125,7 +1175,8 @@ namespace Unity.Netcode.RuntimeTests
|
||||
[UnityTest]
|
||||
public IEnumerator WhenADeferredMessageIsRemoved_OtherMessagesForDifferentObjectsAreNotRemoved([Values(1, 2, 3)] int timeout)
|
||||
{
|
||||
RegisterClientPrefabs();
|
||||
m_SkipAddingPrefabsToClient = true;
|
||||
yield return SpawnClients();
|
||||
CatchSpawns();
|
||||
foreach (var client in m_ClientNetworkManagers)
|
||||
{
|
||||
@@ -1156,7 +1207,7 @@ namespace Unity.Netcode.RuntimeTests
|
||||
|
||||
serverObject.GetComponent<NetworkObject>().ChangeOwnership(m_ClientNetworkManagers[0].LocalClientId);
|
||||
|
||||
yield return RunMultiple(WaitForAllClientsToReceive<ChangeOwnershipMessage>());
|
||||
yield return WaitForAllClientsToReceive<ChangeOwnershipMessage>();
|
||||
|
||||
yield return new WaitForSeconds(timeout - 0.5f);
|
||||
|
||||
@@ -1170,7 +1221,7 @@ namespace Unity.Netcode.RuntimeTests
|
||||
}
|
||||
|
||||
serverObject2.GetComponent<NetworkObject>().ChangeOwnership(m_ServerNetworkManager.LocalClientId);
|
||||
yield return RunMultiple(WaitForAllClientsToReceive<ChangeOwnershipMessage>());
|
||||
yield return WaitForAllClientsToReceive<ChangeOwnershipMessage>();
|
||||
|
||||
foreach (var client in m_ClientNetworkManagers)
|
||||
{
|
||||
@@ -1206,9 +1257,14 @@ namespace Unity.Netcode.RuntimeTests
|
||||
manager.OnBeforePurge = beforePurge;
|
||||
}
|
||||
|
||||
foreach (var client in m_ClientNetworkManagers)
|
||||
{
|
||||
AddPrefabsToClient(client);
|
||||
}
|
||||
|
||||
yield return new WaitForSeconds(0.6f);
|
||||
|
||||
Assert.AreEqual(NumberOfClients, purgeCount);
|
||||
Assert.AreEqual(m_NumberOfClientsToLateJoin, purgeCount);
|
||||
foreach (var client in m_ClientNetworkManagers)
|
||||
{
|
||||
var manager = (TestDeferredMessageManager)client.DeferredMessageManager;
|
||||
|
||||
@@ -60,5 +60,53 @@ namespace Unity.Netcode.RuntimeTests
|
||||
{
|
||||
m_ClientDisconnected = true;
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator ClientDisconnectPlayerObjectCleanup()
|
||||
{
|
||||
// create server and client instances
|
||||
NetcodeIntegrationTestHelpers.Create(1, out NetworkManager server, out NetworkManager[] clients);
|
||||
|
||||
// create prefab
|
||||
var gameObject = new GameObject("PlayerObject");
|
||||
var networkObject = gameObject.AddComponent<NetworkObject>();
|
||||
networkObject.DontDestroyWithOwner = true;
|
||||
NetcodeIntegrationTestHelpers.MakeNetworkObjectTestPrefab(networkObject);
|
||||
|
||||
server.NetworkConfig.PlayerPrefab = gameObject;
|
||||
|
||||
for (int i = 0; i < clients.Length; i++)
|
||||
{
|
||||
clients[i].NetworkConfig.PlayerPrefab = gameObject;
|
||||
}
|
||||
|
||||
// start server and connect clients
|
||||
NetcodeIntegrationTestHelpers.Start(false, server, clients);
|
||||
|
||||
// wait for connection on client side
|
||||
yield return NetcodeIntegrationTestHelpers.WaitForClientsConnected(clients);
|
||||
|
||||
// wait for connection on server side
|
||||
yield return NetcodeIntegrationTestHelpers.WaitForClientConnectedToServer(server);
|
||||
|
||||
// disconnect the remote client
|
||||
m_ClientDisconnected = false;
|
||||
|
||||
server.OnClientDisconnectCallback += OnClientDisconnectCallback;
|
||||
|
||||
var serverSideClientPlayer = server.ConnectedClients[clients[0].LocalClientId].PlayerObject;
|
||||
|
||||
// Stopping the client is the same as the client disconnecting
|
||||
NetcodeIntegrationTestHelpers.StopOneClient(clients[0]);
|
||||
|
||||
var timeoutHelper = new TimeoutHelper();
|
||||
yield return NetcodeIntegrationTest.WaitForConditionOrTimeOut(() => m_ClientDisconnected, timeoutHelper);
|
||||
|
||||
// ensure the object was destroyed
|
||||
Assert.True(serverSideClientPlayer.IsOwnedByServer, $"The client's player object's ownership was not transferred back to the server!");
|
||||
|
||||
// cleanup
|
||||
NetcodeIntegrationTestHelpers.Destroy();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
#if MULTIPLAYER_TOOLS_1_0_0_PRE_7
|
||||
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using NUnit.Framework;
|
||||
using Unity.Multiplayer.Tools.MetricTypes;
|
||||
using Unity.Netcode.TestHelpers.Runtime;
|
||||
|
||||
@@ -5,7 +5,6 @@ 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
|
||||
{
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
#if MULTIPLAYER_TOOLS
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
@@ -36,7 +35,7 @@ namespace Unity.Netcode.RuntimeTests.Metrics
|
||||
private NetworkObject SpawnNetworkObject()
|
||||
{
|
||||
// Spawn another network object so we can hide multiple.
|
||||
var gameObject = UnityEngine.Object.Instantiate(m_NewNetworkPrefab); // new GameObject(NewNetworkObjectName);
|
||||
var gameObject = Object.Instantiate(m_NewNetworkPrefab); // new GameObject(NewNetworkObjectName);
|
||||
var networkObject = gameObject.GetComponent<NetworkObject>();
|
||||
networkObject.NetworkManagerOwner = Server;
|
||||
networkObject.Spawn();
|
||||
@@ -62,6 +61,13 @@ namespace Unity.Netcode.RuntimeTests.Metrics
|
||||
var ownershipChangeSent = metricValues.First();
|
||||
Assert.AreEqual(networkObject.NetworkObjectId, ownershipChangeSent.NetworkId.NetworkId);
|
||||
Assert.AreEqual(Server.LocalClientId, ownershipChangeSent.Connection.Id);
|
||||
Assert.AreEqual(0, ownershipChangeSent.BytesCount);
|
||||
|
||||
// The first metric is to the server(self), so its size is now correctly reported as 0.
|
||||
// Let's check the last one instead, to have a valid value
|
||||
ownershipChangeSent = metricValues.Last();
|
||||
Assert.AreEqual(networkObject.NetworkObjectId, ownershipChangeSent.NetworkId.NetworkId);
|
||||
Assert.AreEqual(Client.LocalClientId, ownershipChangeSent.Connection.Id);
|
||||
Assert.AreEqual(FastBufferWriter.GetWriteSize<ChangeOwnershipMessage>() + k_MessageHeaderSize, ownershipChangeSent.BytesCount);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#if MULTIPLAYER_TOOLS
|
||||
#if MULTIPLAYER_TOOLS_1_0_0_PRE_7
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using NUnit.Framework;
|
||||
using Unity.Collections;
|
||||
@@ -9,7 +8,9 @@ using Unity.Multiplayer.Tools.MetricTypes;
|
||||
using Unity.Netcode.TestHelpers.Runtime;
|
||||
using Unity.Netcode.TestHelpers.Runtime.Metrics;
|
||||
using Unity.Netcode.Transports.UTP;
|
||||
using UnityEngine;
|
||||
#if UTP_TRANSPORT_2_0_ABOVE
|
||||
using Unity.Networking.Transport.Utilities;
|
||||
#endif
|
||||
using UnityEngine.TestTools;
|
||||
|
||||
namespace Unity.Netcode.RuntimeTests.Metrics
|
||||
@@ -18,16 +19,25 @@ namespace Unity.Netcode.RuntimeTests.Metrics
|
||||
{
|
||||
protected override int NumberOfClients => 1;
|
||||
private readonly int m_PacketLossRate = 25;
|
||||
private readonly int m_PacketLossRangeDelta = 5;
|
||||
private readonly int m_PacketLossRangeDelta = 3;
|
||||
private readonly int m_MessageSize = 200;
|
||||
|
||||
public PacketLossMetricsTests()
|
||||
: base(HostOrServer.Server)
|
||||
{}
|
||||
{ }
|
||||
|
||||
protected override void OnServerAndClientsCreated()
|
||||
{
|
||||
var clientTransport = (UnityTransport)m_ClientNetworkManagers[0].NetworkConfig.NetworkTransport;
|
||||
#if !UTP_TRANSPORT_2_0_ABOVE
|
||||
clientTransport.SetDebugSimulatorParameters(0, 0, m_PacketLossRate);
|
||||
#endif
|
||||
|
||||
// Determined through trial and error. With both UTP 1.2 and 2.0, this random seed
|
||||
// results in an effective packet loss percentage between 22% and 28%. Future UTP
|
||||
// updates may change the RNG call patterns and cause this test to fail, in which
|
||||
// case the value should be modified again.
|
||||
clientTransport.DebugSimulatorRandomSeed = 4;
|
||||
|
||||
base.OnServerAndClientsCreated();
|
||||
}
|
||||
@@ -41,11 +51,9 @@ namespace Unity.Netcode.RuntimeTests.Metrics
|
||||
|
||||
for (int i = 0; i < 1000; ++i)
|
||||
{
|
||||
using (var writer = new FastBufferWriter(sizeof(byte), Allocator.Persistent))
|
||||
{
|
||||
writer.WriteByteSafe(42);
|
||||
m_ServerNetworkManager.CustomMessagingManager.SendNamedMessage("Test", m_ServerNetworkManager.ConnectedClientsIds, writer);
|
||||
}
|
||||
using var writer = new FastBufferWriter(m_MessageSize, Allocator.Persistent);
|
||||
writer.WriteBytesSafe(new byte[m_MessageSize]);
|
||||
m_ServerNetworkManager.CustomMessagingManager.SendNamedMessage("Test", m_ServerNetworkManager.ConnectedClientsIds, writer);
|
||||
}
|
||||
|
||||
yield return waitForPacketLossMetric.WaitForMetricsReceived();
|
||||
@@ -57,20 +65,26 @@ namespace Unity.Netcode.RuntimeTests.Metrics
|
||||
[UnityTest]
|
||||
public IEnumerator TrackPacketLossAsClient()
|
||||
{
|
||||
double packetLossRateMinRange = (m_PacketLossRate-m_PacketLossRangeDelta) / 100d;
|
||||
double packetLossRateMinRange = (m_PacketLossRate - m_PacketLossRangeDelta) / 100d;
|
||||
double packetLossRateMaxrange = (m_PacketLossRate + m_PacketLossRangeDelta) / 100d;
|
||||
var clientNetworkManager = m_ClientNetworkManagers[0];
|
||||
|
||||
#if UTP_TRANSPORT_2_0_ABOVE
|
||||
var clientTransport = (UnityTransport)clientNetworkManager.NetworkConfig.NetworkTransport;
|
||||
clientTransport.NetworkDriver.CurrentSettings.TryGet<SimulatorUtility.Parameters>(out var parameters);
|
||||
parameters.PacketDropPercentage = m_PacketLossRate;
|
||||
clientTransport.NetworkDriver.ModifySimulatorStageParameters(parameters);
|
||||
#endif
|
||||
|
||||
var waitForPacketLossMetric = new WaitForGaugeMetricValues((clientNetworkManager.NetworkMetrics as NetworkMetrics).Dispatcher,
|
||||
NetworkMetricTypes.PacketLoss,
|
||||
metric => packetLossRateMinRange <= metric && metric <= packetLossRateMaxrange);
|
||||
|
||||
for (int i = 0; i < 1000; ++i)
|
||||
{
|
||||
using (var writer = new FastBufferWriter(sizeof(byte), Allocator.Persistent))
|
||||
{
|
||||
writer.WriteByteSafe(42);
|
||||
m_ServerNetworkManager.CustomMessagingManager.SendNamedMessage("Test", m_ServerNetworkManager.ConnectedClientsIds, writer);
|
||||
}
|
||||
using var writer = new FastBufferWriter(m_MessageSize, Allocator.Persistent);
|
||||
writer.WriteBytesSafe(new byte[m_MessageSize]);
|
||||
m_ServerNetworkManager.CustomMessagingManager.SendNamedMessage("Test", m_ServerNetworkManager.ConnectedClientsIds, writer);
|
||||
}
|
||||
|
||||
yield return waitForPacketLossMetric.WaitForMetricsReceived();
|
||||
|
||||
@@ -5,7 +5,6 @@ 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
|
||||
|
||||
@@ -2,13 +2,14 @@
|
||||
using System.Collections;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using Unity.Collections;
|
||||
using Unity.Multiplayer.Tools.MetricTypes;
|
||||
using UnityEngine.TestTools;
|
||||
using Unity.Netcode.TestHelpers.Runtime.Metrics;
|
||||
|
||||
namespace Unity.Netcode.RuntimeTests.Metrics
|
||||
{
|
||||
internal class RpcMetricsTests : SingleClientMetricTestBase
|
||||
internal class RpcMetricsTests : DualClientMetricTestBase
|
||||
{
|
||||
protected override void OnCreatePlayerPrefab()
|
||||
{
|
||||
@@ -17,30 +18,79 @@ namespace Unity.Netcode.RuntimeTests.Metrics
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator TrackRpcSentMetricOnServer()
|
||||
public IEnumerator TrackRpcSentMetricOnServerToOnlyOneClientWithArray()
|
||||
{
|
||||
var waitForMetricValues = new WaitForEventMetricValues<RpcEvent>(ServerMetrics.Dispatcher, NetworkMetricTypes.RpcSent);
|
||||
|
||||
m_PlayerNetworkObjects[m_ServerNetworkManager.LocalClientId][Client.LocalClientId].GetComponent<RpcTestComponent>().MyClientRpc();
|
||||
m_PlayerNetworkObjects[m_ServerNetworkManager.LocalClientId][FirstClient.LocalClientId].GetComponent<RpcTestComponent>().MyClientRpc(new ClientRpcParams
|
||||
{
|
||||
Send = new ClientRpcSendParams
|
||||
{
|
||||
TargetClientIds = new[] { FirstClient.LocalClientId }
|
||||
}
|
||||
});
|
||||
|
||||
yield return waitForMetricValues.WaitForMetricsReceived();
|
||||
|
||||
var serverRpcSentValues = waitForMetricValues.AssertMetricValuesHaveBeenFound();
|
||||
Assert.AreEqual(2, serverRpcSentValues.Count); // Server will receive this, since it's host
|
||||
Assert.AreEqual(1, serverRpcSentValues.Count);
|
||||
|
||||
Assert.That(serverRpcSentValues, Has.All.Matches<RpcEvent>(x => x.Name == nameof(RpcTestComponent.MyClientRpc)));
|
||||
Assert.That(serverRpcSentValues, Has.All.Matches<RpcEvent>(x => x.NetworkBehaviourName == nameof(RpcTestComponent)));
|
||||
Assert.That(serverRpcSentValues, Has.All.Matches<RpcEvent>(x => x.BytesCount != 0));
|
||||
Assert.AreEqual(FirstClient.LocalClientId, serverRpcSentValues.First().Connection.Id);
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator TrackRpcSentMetricOnServerToOnlyOneClientWithNativeArray()
|
||||
{
|
||||
var waitForMetricValues = new WaitForEventMetricValues<RpcEvent>(ServerMetrics.Dispatcher, NetworkMetricTypes.RpcSent);
|
||||
|
||||
m_PlayerNetworkObjects[m_ServerNetworkManager.LocalClientId][FirstClient.LocalClientId].GetComponent<RpcTestComponent>().MyClientRpc(new ClientRpcParams
|
||||
{
|
||||
Send = new ClientRpcSendParams
|
||||
{
|
||||
TargetClientIdsNativeArray = new NativeArray<ulong>(new[] { FirstClient.LocalClientId }, Allocator.Temp)
|
||||
}
|
||||
});
|
||||
|
||||
yield return waitForMetricValues.WaitForMetricsReceived();
|
||||
|
||||
var serverRpcSentValues = waitForMetricValues.AssertMetricValuesHaveBeenFound();
|
||||
Assert.AreEqual(1, serverRpcSentValues.Count);
|
||||
|
||||
Assert.That(serverRpcSentValues, Has.All.Matches<RpcEvent>(x => x.Name == nameof(RpcTestComponent.MyClientRpc)));
|
||||
Assert.That(serverRpcSentValues, Has.All.Matches<RpcEvent>(x => x.NetworkBehaviourName == nameof(RpcTestComponent)));
|
||||
Assert.That(serverRpcSentValues, Has.All.Matches<RpcEvent>(x => x.BytesCount != 0));
|
||||
Assert.AreEqual(FirstClient.LocalClientId, serverRpcSentValues.First().Connection.Id);
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator TrackRpcSentMetricOnServerToAllClients()
|
||||
{
|
||||
var waitForMetricValues = new WaitForEventMetricValues<RpcEvent>(ServerMetrics.Dispatcher, NetworkMetricTypes.RpcSent);
|
||||
|
||||
m_PlayerNetworkObjects[m_ServerNetworkManager.LocalClientId][FirstClient.LocalClientId].GetComponent<RpcTestComponent>().MyClientRpc();
|
||||
|
||||
yield return waitForMetricValues.WaitForMetricsReceived();
|
||||
|
||||
var serverRpcSentValues = waitForMetricValues.AssertMetricValuesHaveBeenFound();
|
||||
Assert.AreEqual(3, serverRpcSentValues.Count); // Server will receive this, since it's host
|
||||
|
||||
Assert.That(serverRpcSentValues, Has.All.Matches<RpcEvent>(x => x.Name == nameof(RpcTestComponent.MyClientRpc)));
|
||||
Assert.That(serverRpcSentValues, Has.All.Matches<RpcEvent>(x => x.NetworkBehaviourName == nameof(RpcTestComponent)));
|
||||
Assert.That(serverRpcSentValues, Has.All.Matches<RpcEvent>(x => x.BytesCount != 0));
|
||||
Assert.Contains(Server.LocalClientId, serverRpcSentValues.Select(x => x.Connection.Id).ToArray());
|
||||
Assert.Contains(Client.LocalClientId, serverRpcSentValues.Select(x => x.Connection.Id).ToArray());
|
||||
Assert.Contains(FirstClient.LocalClientId, serverRpcSentValues.Select(x => x.Connection.Id).ToArray());
|
||||
Assert.Contains(SecondClient.LocalClientId, serverRpcSentValues.Select(x => x.Connection.Id).ToArray());
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator TrackRpcSentMetricOnClient()
|
||||
{
|
||||
var waitForClientMetricsValues = new WaitForEventMetricValues<RpcEvent>(ClientMetrics.Dispatcher, NetworkMetricTypes.RpcSent);
|
||||
var waitForClientMetricsValues = new WaitForEventMetricValues<RpcEvent>(FirstClientMetrics.Dispatcher, NetworkMetricTypes.RpcSent);
|
||||
|
||||
m_PlayerNetworkObjects[Client.LocalClientId][Client.LocalClientId].GetComponent<RpcTestComponent>().MyServerRpc();
|
||||
m_PlayerNetworkObjects[FirstClient.LocalClientId][FirstClient.LocalClientId].GetComponent<RpcTestComponent>().MyServerRpc();
|
||||
|
||||
yield return waitForClientMetricsValues.WaitForMetricsReceived();
|
||||
|
||||
@@ -58,7 +108,7 @@ namespace Unity.Netcode.RuntimeTests.Metrics
|
||||
public IEnumerator TrackRpcReceivedMetricOnServer()
|
||||
{
|
||||
var waitForServerMetricsValues = new WaitForEventMetricValues<RpcEvent>(ServerMetrics.Dispatcher, NetworkMetricTypes.RpcReceived);
|
||||
m_PlayerNetworkObjects[Client.LocalClientId][Client.LocalClientId].GetComponent<RpcTestComponent>().MyServerRpc();
|
||||
m_PlayerNetworkObjects[FirstClient.LocalClientId][FirstClient.LocalClientId].GetComponent<RpcTestComponent>().MyServerRpc();
|
||||
|
||||
yield return waitForServerMetricsValues.WaitForMetricsReceived();
|
||||
|
||||
@@ -66,7 +116,7 @@ namespace Unity.Netcode.RuntimeTests.Metrics
|
||||
Assert.AreEqual(1, serverRpcReceivedValues.Count);
|
||||
|
||||
var rpcReceived = serverRpcReceivedValues.First();
|
||||
Assert.AreEqual(Client.LocalClientId, rpcReceived.Connection.Id);
|
||||
Assert.AreEqual(FirstClient.LocalClientId, rpcReceived.Connection.Id);
|
||||
Assert.AreEqual(nameof(RpcTestComponent.MyServerRpc), rpcReceived.Name);
|
||||
Assert.AreEqual(nameof(RpcTestComponent), rpcReceived.NetworkBehaviourName);
|
||||
Assert.AreNotEqual(0, rpcReceived.BytesCount);
|
||||
@@ -75,9 +125,9 @@ namespace Unity.Netcode.RuntimeTests.Metrics
|
||||
[UnityTest]
|
||||
public IEnumerator TrackRpcReceivedMetricOnClient()
|
||||
{
|
||||
var waitForClientMetricsValues = new WaitForEventMetricValues<RpcEvent>(ClientMetrics.Dispatcher, NetworkMetricTypes.RpcReceived);
|
||||
var waitForClientMetricsValues = new WaitForEventMetricValues<RpcEvent>(FirstClientMetrics.Dispatcher, NetworkMetricTypes.RpcReceived);
|
||||
|
||||
m_PlayerNetworkObjects[m_ServerNetworkManager.LocalClientId][Client.LocalClientId].GetComponent<RpcTestComponent>().MyClientRpc();
|
||||
m_PlayerNetworkObjects[m_ServerNetworkManager.LocalClientId][FirstClient.LocalClientId].GetComponent<RpcTestComponent>().MyClientRpc();
|
||||
|
||||
yield return waitForClientMetricsValues.WaitForMetricsReceived();
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#if MULTIPLAYER_TOOLS
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.IO;
|
||||
using NUnit.Framework;
|
||||
using Unity.Collections;
|
||||
using Unity.Multiplayer.Tools.MetricTypes;
|
||||
@@ -15,7 +14,7 @@ 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;
|
||||
static readonly long MessageOverhead = 8 + FastBufferWriter.GetWriteSize<BatchHeader>() + k_MessageHeaderSize;
|
||||
private static readonly long k_MessageOverhead = 8 + FastBufferWriter.GetWriteSize<BatchHeader>() + k_MessageHeaderSize;
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator TrackTotalNumberOfBytesSent()
|
||||
@@ -42,7 +41,7 @@ namespace Unity.Netcode.RuntimeTests.Metrics
|
||||
}
|
||||
|
||||
Assert.True(observer.Found);
|
||||
Assert.AreEqual(FastBufferWriter.GetWriteSize(messageName) + MessageOverhead, observer.Value);
|
||||
Assert.AreEqual(FastBufferWriter.GetWriteSize(messageName) + k_MessageOverhead, observer.Value);
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
@@ -72,7 +71,7 @@ namespace Unity.Netcode.RuntimeTests.Metrics
|
||||
}
|
||||
|
||||
Assert.True(observer.Found);
|
||||
Assert.AreEqual(FastBufferWriter.GetWriteSize(messageName) + MessageOverhead, observer.Value);
|
||||
Assert.AreEqual(FastBufferWriter.GetWriteSize(messageName) + k_MessageOverhead, observer.Value);
|
||||
}
|
||||
|
||||
private class TotalBytesObserver : IMetricObserver
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3acde7838205d4b09ae3a035554c51c5
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -9,6 +9,11 @@ namespace Unity.Netcode.RuntimeTests
|
||||
{
|
||||
public class NetworkObjectNetworkClientOwnedObjectsTests : NetcodeIntegrationTest
|
||||
{
|
||||
private class DummyNetworkBehaviour : NetworkBehaviour
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
protected override int NumberOfClients => 1;
|
||||
private NetworkPrefab m_NetworkPrefab;
|
||||
protected override void OnServerAndClientsCreated()
|
||||
@@ -16,6 +21,7 @@ namespace Unity.Netcode.RuntimeTests
|
||||
// create prefab
|
||||
var gameObject = new GameObject("ClientOwnedObject");
|
||||
var networkObject = gameObject.AddComponent<NetworkObject>();
|
||||
gameObject.AddComponent<DummyNetworkBehaviour>();
|
||||
NetcodeIntegrationTestHelpers.MakeNetworkObjectTestPrefab(networkObject);
|
||||
|
||||
m_NetworkPrefab = (new NetworkPrefab()
|
||||
@@ -39,7 +45,7 @@ namespace Unity.Netcode.RuntimeTests
|
||||
serverObject.Spawn();
|
||||
|
||||
// Provide enough time for the client to receive and process the spawned message.
|
||||
yield return s_DefaultWaitForTick;
|
||||
yield return WaitForMessageReceived<CreateObjectMessage>(m_ClientNetworkManagers.ToList());
|
||||
|
||||
// The object is owned by server
|
||||
Assert.False(m_ServerNetworkManager.SpawnManager.GetClientOwnedObjects(m_ClientNetworkManagers[0].LocalClientId).Any(x => x.NetworkObjectId == serverObject.NetworkObjectId));
|
||||
@@ -48,13 +54,71 @@ namespace Unity.Netcode.RuntimeTests
|
||||
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;
|
||||
yield return WaitForMessageReceived<ChangeOwnershipMessage>(m_ClientNetworkManagers.ToList());
|
||||
|
||||
// Ensure it's now added to the list
|
||||
yield return WaitForConditionOrTimeOut(() => m_ClientNetworkManagers[0].SpawnManager.GetClientOwnedObjects(m_ClientNetworkManagers[0].LocalClientId).Any(x => x.NetworkObjectId == serverObject.NetworkObjectId));
|
||||
Assert.False(s_GlobalTimeoutHelper.TimedOut, $"Timed out waiting for client to gain ownership!");
|
||||
Assert.True(m_ClientNetworkManagers[0].SpawnManager.GetClientOwnedObjects(m_ClientNetworkManagers[0].LocalClientId).Any(x => x.NetworkObjectId == serverObject.NetworkObjectId));
|
||||
Assert.True(m_ServerNetworkManager.SpawnManager.GetClientOwnedObjects(m_ClientNetworkManagers[0].LocalClientId).Any(x => x.NetworkObjectId == serverObject.NetworkObjectId));
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator WhenOwnershipIsChanged_OwnershipValuesUpdateCorrectly()
|
||||
{
|
||||
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 WaitForMessageReceived<CreateObjectMessage>(m_ClientNetworkManagers.ToList());
|
||||
|
||||
// The object is owned by server
|
||||
Assert.False(m_ServerNetworkManager.SpawnManager.GetClientOwnedObjects(m_ClientNetworkManagers[0].LocalClientId).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 WaitForMessageReceived<ChangeOwnershipMessage>(m_ClientNetworkManagers.ToList());
|
||||
|
||||
Assert.IsFalse(serverObject.IsOwner);
|
||||
Assert.IsFalse(serverObject.IsOwnedByServer);
|
||||
Assert.AreEqual(m_ClientNetworkManagers[0].LocalClientId, serverObject.OwnerClientId);
|
||||
|
||||
var serverBehaviour = serverObject.GetComponent<DummyNetworkBehaviour>();
|
||||
Assert.IsFalse(serverBehaviour.IsOwner);
|
||||
Assert.IsFalse(serverBehaviour.IsOwnedByServer);
|
||||
Assert.AreEqual(m_ClientNetworkManagers[0].LocalClientId, serverBehaviour.OwnerClientId);
|
||||
|
||||
var clientObject = Object.FindObjectsOfType<NetworkObject>().Where((obj) => obj.NetworkManagerOwner == m_ClientNetworkManagers[0]).FirstOrDefault();
|
||||
|
||||
Assert.IsNotNull(clientObject);
|
||||
Assert.IsTrue(clientObject.IsOwner);
|
||||
Assert.IsFalse(clientObject.IsOwnedByServer);
|
||||
Assert.AreEqual(m_ClientNetworkManagers[0].LocalClientId, clientObject.OwnerClientId);
|
||||
|
||||
var clientBehaviour = clientObject.GetComponent<DummyNetworkBehaviour>();
|
||||
Assert.IsTrue(clientBehaviour.IsOwner);
|
||||
Assert.IsFalse(clientBehaviour.IsOwnedByServer);
|
||||
Assert.AreEqual(m_ClientNetworkManagers[0].LocalClientId, clientBehaviour.OwnerClientId);
|
||||
|
||||
serverObject.RemoveOwnership();
|
||||
|
||||
// Provide enough time for the client to receive and process the change in ownership message.
|
||||
yield return WaitForMessageReceived<ChangeOwnershipMessage>(m_ClientNetworkManagers.ToList());
|
||||
|
||||
Assert.IsTrue(serverObject.IsOwner);
|
||||
Assert.IsTrue(serverObject.IsOwnedByServer);
|
||||
Assert.AreEqual(NetworkManager.ServerClientId, serverObject.OwnerClientId);
|
||||
Assert.IsTrue(serverBehaviour.IsOwner);
|
||||
Assert.IsTrue(serverBehaviour.IsOwnedByServer);
|
||||
Assert.AreEqual(NetworkManager.ServerClientId, serverBehaviour.OwnerClientId);
|
||||
|
||||
Assert.IsFalse(clientObject.IsOwner);
|
||||
Assert.IsTrue(clientObject.IsOwnedByServer);
|
||||
Assert.AreEqual(NetworkManager.ServerClientId, clientObject.OwnerClientId);
|
||||
Assert.IsFalse(clientBehaviour.IsOwner);
|
||||
Assert.IsTrue(clientBehaviour.IsOwnedByServer);
|
||||
Assert.AreEqual(NetworkManager.ServerClientId, clientBehaviour.OwnerClientId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ namespace Unity.Netcode.RuntimeTests
|
||||
{
|
||||
public static List<ShowHideObject> ClientTargetedNetworkObjects = new List<ShowHideObject>();
|
||||
public static ulong ClientIdToTarget;
|
||||
public static bool Silent;
|
||||
|
||||
public static NetworkObject GetNetworkObjectById(ulong networkObjectId)
|
||||
{
|
||||
@@ -36,6 +37,17 @@ namespace Unity.Netcode.RuntimeTests
|
||||
{
|
||||
ClientTargetedNetworkObjects.Add(this);
|
||||
}
|
||||
|
||||
if (IsServer)
|
||||
{
|
||||
MyListSetOnSpawn.Add(45);
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.Assert(MyListSetOnSpawn.Count == 1);
|
||||
Debug.Assert(MyListSetOnSpawn[0] == 45);
|
||||
}
|
||||
|
||||
base.OnNetworkSpawn();
|
||||
}
|
||||
|
||||
@@ -49,16 +61,22 @@ namespace Unity.Netcode.RuntimeTests
|
||||
}
|
||||
|
||||
public NetworkVariable<int> MyNetworkVariable;
|
||||
public NetworkList<int> MyListSetOnSpawn;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
MyNetworkVariable = new NetworkVariable<int>();
|
||||
MyNetworkVariable.OnValueChanged += Changed;
|
||||
|
||||
MyListSetOnSpawn = new NetworkList<int>();
|
||||
}
|
||||
|
||||
public void Changed(int before, int after)
|
||||
{
|
||||
Debug.Log($"Value changed from {before} to {after}");
|
||||
if (!Silent)
|
||||
{
|
||||
Debug.Log($"Value changed from {before} to {after}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -264,5 +282,61 @@ namespace Unity.Netcode.RuntimeTests
|
||||
yield return CheckVisible(true);
|
||||
}
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator NetworkHideDespawnTest()
|
||||
{
|
||||
m_ClientId0 = m_ClientNetworkManagers[0].LocalClientId;
|
||||
ShowHideObject.ClientTargetedNetworkObjects.Clear();
|
||||
ShowHideObject.ClientIdToTarget = m_ClientId0;
|
||||
ShowHideObject.Silent = true;
|
||||
|
||||
var spawnedObject1 = SpawnObject(m_PrefabToSpawn, m_ServerNetworkManager);
|
||||
var spawnedObject2 = SpawnObject(m_PrefabToSpawn, m_ServerNetworkManager);
|
||||
var spawnedObject3 = SpawnObject(m_PrefabToSpawn, m_ServerNetworkManager);
|
||||
m_NetSpawnedObject1 = spawnedObject1.GetComponent<NetworkObject>();
|
||||
m_NetSpawnedObject2 = spawnedObject2.GetComponent<NetworkObject>();
|
||||
m_NetSpawnedObject3 = spawnedObject3.GetComponent<NetworkObject>();
|
||||
|
||||
m_NetSpawnedObject1.GetComponent<ShowHideObject>().MyNetworkVariable.Value++;
|
||||
m_NetSpawnedObject1.NetworkHide(m_ClientId0);
|
||||
m_NetSpawnedObject1.Despawn();
|
||||
|
||||
yield return NetcodeIntegrationTestHelpers.WaitForTicks(m_ServerNetworkManager, 5);
|
||||
|
||||
LogAssert.NoUnexpectedReceived();
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator NetworkHideChangeOwnership()
|
||||
{
|
||||
ShowHideObject.ClientTargetedNetworkObjects.Clear();
|
||||
ShowHideObject.ClientIdToTarget = m_ClientNetworkManagers[1].LocalClientId;
|
||||
ShowHideObject.Silent = true;
|
||||
|
||||
var spawnedObject1 = SpawnObject(m_PrefabToSpawn, m_ServerNetworkManager);
|
||||
m_NetSpawnedObject1 = spawnedObject1.GetComponent<NetworkObject>();
|
||||
|
||||
m_NetSpawnedObject1.GetComponent<ShowHideObject>().MyNetworkVariable.Value++;
|
||||
// Hide an object to a client
|
||||
m_NetSpawnedObject1.NetworkHide(m_ClientNetworkManagers[1].LocalClientId);
|
||||
|
||||
yield return WaitForConditionOrTimeOut(() => ShowHideObject.ClientTargetedNetworkObjects.Count == 0);
|
||||
|
||||
// Change ownership while the object is hidden to some
|
||||
m_NetSpawnedObject1.ChangeOwnership(m_ClientNetworkManagers[0].LocalClientId);
|
||||
|
||||
// The two-second wait is actually needed as there's a potential warning of unhandled message after 1 second
|
||||
yield return new WaitForSeconds(1.25f);
|
||||
|
||||
LogAssert.NoUnexpectedReceived();
|
||||
|
||||
// Show the object again to check nothing unexpected happens
|
||||
m_NetSpawnedObject1.NetworkShow(m_ClientNetworkManagers[1].LocalClientId);
|
||||
|
||||
yield return WaitForConditionOrTimeOut(() => ShowHideObject.ClientTargetedNetworkObjects.Count == 1);
|
||||
|
||||
Assert.True(ShowHideObject.ClientTargetedNetworkObjects[0].OwnerClientId == m_ClientNetworkManagers[0].LocalClientId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,15 +4,87 @@ using UnityEngine;
|
||||
|
||||
namespace Unity.Netcode.RuntimeTests
|
||||
{
|
||||
|
||||
[TestFixture(TransformSpace.World)]
|
||||
[TestFixture(TransformSpace.Local)]
|
||||
public class NetworkTransformStateTests
|
||||
{
|
||||
[Test]
|
||||
public void TestSyncAxes(
|
||||
[Values] bool inLocalSpace,
|
||||
[Values] bool syncPosX, [Values] bool syncPosY, [Values] bool syncPosZ,
|
||||
[Values] bool syncRotX, [Values] bool syncRotY, [Values] bool syncRotZ,
|
||||
[Values] bool syncScaX, [Values] bool syncScaY, [Values] bool syncScaZ)
|
||||
public enum SyncAxis
|
||||
{
|
||||
SyncPosX,
|
||||
SyncPosY,
|
||||
SyncPosZ,
|
||||
SyncPosXY,
|
||||
SyncPosXZ,
|
||||
SyncPosYZ,
|
||||
SyncPosXYZ,
|
||||
SyncRotX,
|
||||
SyncRotY,
|
||||
SyncRotZ,
|
||||
SyncRotXY,
|
||||
SyncRotXZ,
|
||||
SyncRotYZ,
|
||||
SyncRotXYZ,
|
||||
SyncScaleX,
|
||||
SyncScaleY,
|
||||
SyncScaleZ,
|
||||
SyncScaleXY,
|
||||
SyncScaleXZ,
|
||||
SyncScaleYZ,
|
||||
SyncScaleXYZ,
|
||||
SyncAllX,
|
||||
SyncAllY,
|
||||
SyncAllZ,
|
||||
SyncAllXY,
|
||||
SyncAllXZ,
|
||||
SyncAllYZ,
|
||||
SyncAllXYZ
|
||||
}
|
||||
|
||||
public enum TransformSpace
|
||||
{
|
||||
World,
|
||||
Local
|
||||
}
|
||||
|
||||
public enum SynchronizationType
|
||||
{
|
||||
Delta,
|
||||
Teleport
|
||||
}
|
||||
|
||||
private TransformSpace m_TransformSpace;
|
||||
|
||||
public NetworkTransformStateTests(TransformSpace transformSpace)
|
||||
{
|
||||
m_TransformSpace = transformSpace;
|
||||
}
|
||||
|
||||
private bool WillAnAxisBeSynchronized(ref NetworkTransform networkTransform)
|
||||
{
|
||||
return networkTransform.SyncScaleX || networkTransform.SyncScaleY || networkTransform.SyncScaleZ ||
|
||||
networkTransform.SyncRotAngleX || networkTransform.SyncRotAngleY || networkTransform.SyncRotAngleZ ||
|
||||
networkTransform.SyncPositionX || networkTransform.SyncPositionY || networkTransform.SyncPositionZ;
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestSyncAxes([Values] SynchronizationType synchronizationType, [Values] SyncAxis syncAxis)
|
||||
|
||||
{
|
||||
bool inLocalSpace = m_TransformSpace == TransformSpace.Local;
|
||||
bool isTeleporting = synchronizationType == SynchronizationType.Teleport;
|
||||
bool syncPosX = syncAxis == SyncAxis.SyncPosX || syncAxis == SyncAxis.SyncPosXY || syncAxis == SyncAxis.SyncPosXZ || syncAxis == SyncAxis.SyncPosXYZ || syncAxis == SyncAxis.SyncAllX || syncAxis == SyncAxis.SyncAllXY || syncAxis == SyncAxis.SyncAllXZ || syncAxis == SyncAxis.SyncAllXYZ;
|
||||
bool syncPosY = syncAxis == SyncAxis.SyncPosY || syncAxis == SyncAxis.SyncPosXY || syncAxis == SyncAxis.SyncPosYZ || syncAxis == SyncAxis.SyncPosXYZ || syncAxis == SyncAxis.SyncAllY || syncAxis == SyncAxis.SyncAllXY || syncAxis == SyncAxis.SyncAllYZ || syncAxis == SyncAxis.SyncAllXYZ;
|
||||
bool syncPosZ = syncAxis == SyncAxis.SyncPosZ || syncAxis == SyncAxis.SyncPosXZ || syncAxis == SyncAxis.SyncPosYZ || syncAxis == SyncAxis.SyncPosXYZ || syncAxis == SyncAxis.SyncAllZ || syncAxis == SyncAxis.SyncAllXZ || syncAxis == SyncAxis.SyncAllYZ || syncAxis == SyncAxis.SyncAllXYZ;
|
||||
|
||||
bool syncRotX = syncAxis == SyncAxis.SyncRotX || syncAxis == SyncAxis.SyncRotXY || syncAxis == SyncAxis.SyncRotXZ || syncAxis == SyncAxis.SyncRotXYZ || syncAxis == SyncAxis.SyncRotX || syncAxis == SyncAxis.SyncAllXY || syncAxis == SyncAxis.SyncAllXZ || syncAxis == SyncAxis.SyncAllXYZ;
|
||||
bool syncRotY = syncAxis == SyncAxis.SyncRotY || syncAxis == SyncAxis.SyncRotXY || syncAxis == SyncAxis.SyncRotYZ || syncAxis == SyncAxis.SyncRotXYZ || syncAxis == SyncAxis.SyncRotY || syncAxis == SyncAxis.SyncAllXY || syncAxis == SyncAxis.SyncAllYZ || syncAxis == SyncAxis.SyncAllXYZ;
|
||||
bool syncRotZ = syncAxis == SyncAxis.SyncRotZ || syncAxis == SyncAxis.SyncRotXZ || syncAxis == SyncAxis.SyncRotYZ || syncAxis == SyncAxis.SyncRotXYZ || syncAxis == SyncAxis.SyncRotZ || syncAxis == SyncAxis.SyncAllXZ || syncAxis == SyncAxis.SyncAllYZ || syncAxis == SyncAxis.SyncAllXYZ;
|
||||
|
||||
bool syncScaX = syncAxis == SyncAxis.SyncScaleX || syncAxis == SyncAxis.SyncScaleXY || syncAxis == SyncAxis.SyncScaleXZ || syncAxis == SyncAxis.SyncScaleXYZ || syncAxis == SyncAxis.SyncAllX || syncAxis == SyncAxis.SyncAllXY || syncAxis == SyncAxis.SyncAllXZ || syncAxis == SyncAxis.SyncAllXYZ;
|
||||
bool syncScaY = syncAxis == SyncAxis.SyncScaleY || syncAxis == SyncAxis.SyncScaleXY || syncAxis == SyncAxis.SyncScaleYZ || syncAxis == SyncAxis.SyncScaleXYZ || syncAxis == SyncAxis.SyncAllY || syncAxis == SyncAxis.SyncAllXY || syncAxis == SyncAxis.SyncAllYZ || syncAxis == SyncAxis.SyncAllXYZ;
|
||||
bool syncScaZ = syncAxis == SyncAxis.SyncScaleZ || syncAxis == SyncAxis.SyncScaleXZ || syncAxis == SyncAxis.SyncScaleYZ || syncAxis == SyncAxis.SyncScaleXYZ || syncAxis == SyncAxis.SyncAllZ || syncAxis == SyncAxis.SyncAllXZ || syncAxis == SyncAxis.SyncAllYZ || syncAxis == SyncAxis.SyncAllXYZ;
|
||||
|
||||
var gameObject = new GameObject($"Test-{nameof(NetworkTransformStateTests)}.{nameof(TestSyncAxes)}");
|
||||
var networkObject = gameObject.AddComponent<NetworkObject>();
|
||||
var networkTransform = gameObject.AddComponent<NetworkTransform>();
|
||||
@@ -36,27 +108,13 @@ namespace Unity.Netcode.RuntimeTests
|
||||
networkTransform.SyncScaleZ = syncScaZ;
|
||||
networkTransform.InLocalSpace = inLocalSpace;
|
||||
|
||||
// We want a relatively clean networkTransform state before we try to apply the transform to it
|
||||
// We only preserve InLocalSpace and IsTeleportingNextFrame properties as they are the only things
|
||||
// needed when applying a transform to a NetworkTransformState
|
||||
var networkTransformState = new NetworkTransform.NetworkTransformState
|
||||
{
|
||||
PositionX = initialPosition.x,
|
||||
PositionY = initialPosition.y,
|
||||
PositionZ = initialPosition.z,
|
||||
RotAngleX = initialRotAngles.x,
|
||||
RotAngleY = initialRotAngles.y,
|
||||
RotAngleZ = initialRotAngles.z,
|
||||
ScaleX = initialScale.x,
|
||||
ScaleY = initialScale.y,
|
||||
ScaleZ = initialScale.z,
|
||||
HasPositionX = syncPosX,
|
||||
HasPositionY = syncPosY,
|
||||
HasPositionZ = syncPosZ,
|
||||
HasRotAngleX = syncRotX,
|
||||
HasRotAngleY = syncRotY,
|
||||
HasRotAngleZ = syncRotZ,
|
||||
HasScaleX = syncScaX,
|
||||
HasScaleY = syncScaY,
|
||||
HasScaleZ = syncScaZ,
|
||||
InLocalSpace = inLocalSpace
|
||||
InLocalSpace = inLocalSpace,
|
||||
IsTeleportingNextFrame = isTeleporting,
|
||||
};
|
||||
|
||||
// Step 1: change properties, expect state to be dirty
|
||||
@@ -71,95 +129,382 @@ namespace Unity.Netcode.RuntimeTests
|
||||
}
|
||||
}
|
||||
|
||||
// Step 2: disable a particular sync flag, expect state to be not dirty
|
||||
// We want to start with a fresh NetworkTransformState since it could have other state
|
||||
// information from the last time we applied the transform
|
||||
networkTransformState = new NetworkTransform.NetworkTransformState
|
||||
{
|
||||
var position = networkTransform.transform.position;
|
||||
var rotAngles = networkTransform.transform.eulerAngles;
|
||||
var scale = networkTransform.transform.localScale;
|
||||
InLocalSpace = inLocalSpace,
|
||||
IsTeleportingNextFrame = isTeleporting,
|
||||
};
|
||||
var position = networkTransform.transform.position;
|
||||
var rotAngles = networkTransform.transform.eulerAngles;
|
||||
var scale = networkTransform.transform.localScale;
|
||||
|
||||
// Step 2: Verify the state changes in a tick are additive
|
||||
// TODO: This will need to change if we update NetworkTransform to send all of the
|
||||
// axis deltas that happened over a tick as a collection instead of collapsing them
|
||||
// as the changes are detected.
|
||||
{
|
||||
networkTransformState = new NetworkTransform.NetworkTransformState
|
||||
{
|
||||
InLocalSpace = inLocalSpace,
|
||||
IsTeleportingNextFrame = isTeleporting,
|
||||
};
|
||||
|
||||
// SyncPositionX
|
||||
if (syncPosX)
|
||||
{
|
||||
position.x++;
|
||||
networkTransform.transform.position = position;
|
||||
Assert.IsTrue(networkTransform.ApplyTransformToNetworkState(ref networkTransformState, 0, networkTransform.transform));
|
||||
Assert.IsTrue(networkTransformState.HasPositionX);
|
||||
}
|
||||
|
||||
// SyncPositionY
|
||||
if (syncPosY)
|
||||
{
|
||||
position = networkTransform.transform.position;
|
||||
position.y++;
|
||||
networkTransform.transform.position = position;
|
||||
Assert.IsTrue(networkTransform.ApplyTransformToNetworkState(ref networkTransformState, 0, networkTransform.transform));
|
||||
Assert.IsTrue(networkTransformState.HasPositionX || !syncPosX);
|
||||
Assert.IsTrue(networkTransformState.HasPositionY);
|
||||
}
|
||||
|
||||
// SyncPositionZ
|
||||
if (syncPosZ)
|
||||
{
|
||||
position = networkTransform.transform.position;
|
||||
position.z++;
|
||||
networkTransform.transform.position = position;
|
||||
Assert.IsTrue(networkTransform.ApplyTransformToNetworkState(ref networkTransformState, 0, networkTransform.transform));
|
||||
Assert.IsTrue(networkTransformState.HasPositionX || !syncPosX);
|
||||
Assert.IsTrue(networkTransformState.HasPositionY || !syncPosY);
|
||||
Assert.IsTrue(networkTransformState.HasPositionZ);
|
||||
}
|
||||
|
||||
// SyncRotAngleX
|
||||
if (syncRotX)
|
||||
{
|
||||
rotAngles = networkTransform.transform.eulerAngles;
|
||||
rotAngles.x++;
|
||||
networkTransform.transform.eulerAngles = rotAngles;
|
||||
Assert.IsTrue(networkTransform.ApplyTransformToNetworkState(ref networkTransformState, 0, networkTransform.transform));
|
||||
Assert.IsTrue(networkTransformState.HasPositionX || !syncPosX);
|
||||
Assert.IsTrue(networkTransformState.HasPositionY || !syncPosY);
|
||||
Assert.IsTrue(networkTransformState.HasPositionZ || !syncPosZ);
|
||||
Assert.IsTrue(networkTransformState.HasRotAngleX);
|
||||
}
|
||||
|
||||
// SyncRotAngleY
|
||||
if (syncRotY)
|
||||
{
|
||||
rotAngles = networkTransform.transform.eulerAngles;
|
||||
rotAngles.y++;
|
||||
networkTransform.transform.eulerAngles = rotAngles;
|
||||
Assert.IsTrue(networkTransform.ApplyTransformToNetworkState(ref networkTransformState, 0, networkTransform.transform));
|
||||
Assert.IsTrue(networkTransformState.HasPositionX || !syncPosX);
|
||||
Assert.IsTrue(networkTransformState.HasPositionY || !syncPosY);
|
||||
Assert.IsTrue(networkTransformState.HasPositionZ || !syncPosZ);
|
||||
Assert.IsTrue(networkTransformState.HasRotAngleX || !syncRotX);
|
||||
Assert.IsTrue(networkTransformState.HasRotAngleY);
|
||||
}
|
||||
// SyncRotAngleZ
|
||||
if (syncRotZ)
|
||||
{
|
||||
rotAngles = networkTransform.transform.eulerAngles;
|
||||
rotAngles.z++;
|
||||
networkTransform.transform.eulerAngles = rotAngles;
|
||||
Assert.IsTrue(networkTransform.ApplyTransformToNetworkState(ref networkTransformState, 0, networkTransform.transform));
|
||||
Assert.IsTrue(networkTransformState.HasPositionX || !syncPosX);
|
||||
Assert.IsTrue(networkTransformState.HasPositionY || !syncPosY);
|
||||
Assert.IsTrue(networkTransformState.HasPositionZ || !syncPosZ);
|
||||
Assert.IsTrue(networkTransformState.HasRotAngleX || !syncRotX);
|
||||
Assert.IsTrue(networkTransformState.HasRotAngleY || !syncRotY);
|
||||
Assert.IsTrue(networkTransformState.HasRotAngleZ);
|
||||
}
|
||||
|
||||
// SyncScaleX
|
||||
if (syncScaX)
|
||||
{
|
||||
scale = networkTransform.transform.localScale;
|
||||
scale.x++;
|
||||
networkTransform.transform.localScale = scale;
|
||||
Assert.IsTrue(networkTransform.ApplyTransformToNetworkState(ref networkTransformState, 0, networkTransform.transform));
|
||||
Assert.IsTrue(networkTransformState.HasPositionX || !syncPosX);
|
||||
Assert.IsTrue(networkTransformState.HasPositionY || !syncPosY);
|
||||
Assert.IsTrue(networkTransformState.HasPositionZ || !syncPosZ);
|
||||
Assert.IsTrue(networkTransformState.HasRotAngleX || !syncRotX);
|
||||
Assert.IsTrue(networkTransformState.HasRotAngleY || !syncRotY);
|
||||
Assert.IsTrue(networkTransformState.HasRotAngleZ || !syncRotZ);
|
||||
Assert.IsTrue(networkTransformState.HasScaleX);
|
||||
}
|
||||
// SyncScaleY
|
||||
if (syncScaY)
|
||||
{
|
||||
scale = networkTransform.transform.localScale;
|
||||
scale.y++;
|
||||
networkTransform.transform.localScale = scale;
|
||||
Assert.IsTrue(networkTransform.ApplyTransformToNetworkState(ref networkTransformState, 0, networkTransform.transform));
|
||||
Assert.IsTrue(networkTransformState.HasPositionX || !syncPosX);
|
||||
Assert.IsTrue(networkTransformState.HasPositionY || !syncPosY);
|
||||
Assert.IsTrue(networkTransformState.HasPositionZ || !syncPosZ);
|
||||
Assert.IsTrue(networkTransformState.HasRotAngleX || !syncRotX);
|
||||
Assert.IsTrue(networkTransformState.HasRotAngleY || !syncRotY);
|
||||
Assert.IsTrue(networkTransformState.HasRotAngleZ || !syncRotZ);
|
||||
Assert.IsTrue(networkTransformState.HasScaleX || !syncScaX);
|
||||
Assert.IsTrue(networkTransformState.HasScaleY);
|
||||
}
|
||||
// SyncScaleZ
|
||||
if (syncScaZ)
|
||||
{
|
||||
scale = networkTransform.transform.localScale;
|
||||
scale.z++;
|
||||
networkTransform.transform.localScale = scale;
|
||||
Assert.IsTrue(networkTransform.ApplyTransformToNetworkState(ref networkTransformState, 0, networkTransform.transform));
|
||||
Assert.IsTrue(networkTransformState.HasPositionX || !syncPosX);
|
||||
Assert.IsTrue(networkTransformState.HasPositionY || !syncPosY);
|
||||
Assert.IsTrue(networkTransformState.HasPositionZ || !syncPosZ);
|
||||
Assert.IsTrue(networkTransformState.HasRotAngleX || !syncRotX);
|
||||
Assert.IsTrue(networkTransformState.HasRotAngleY || !syncRotY);
|
||||
Assert.IsTrue(networkTransformState.HasRotAngleZ || !syncRotZ);
|
||||
Assert.IsTrue(networkTransformState.HasScaleX || !syncScaX);
|
||||
Assert.IsTrue(networkTransformState.HasScaleY || !syncScaY);
|
||||
Assert.IsTrue(networkTransformState.HasScaleZ);
|
||||
}
|
||||
}
|
||||
|
||||
// Step 3: disable a particular sync flag, expect state to be not dirty
|
||||
// We do this last because it changes which axis will be synchronized.
|
||||
{
|
||||
networkTransformState = new NetworkTransform.NetworkTransformState
|
||||
{
|
||||
InLocalSpace = inLocalSpace,
|
||||
IsTeleportingNextFrame = isTeleporting,
|
||||
};
|
||||
|
||||
position = networkTransform.transform.position;
|
||||
rotAngles = networkTransform.transform.eulerAngles;
|
||||
scale = networkTransform.transform.localScale;
|
||||
|
||||
// SyncPositionX
|
||||
if (syncPosX)
|
||||
{
|
||||
networkTransform.SyncPositionX = false;
|
||||
|
||||
position.x++;
|
||||
networkTransform.transform.position = position;
|
||||
|
||||
Assert.IsFalse(networkTransform.ApplyTransformToNetworkState(ref networkTransformState, 0, networkTransform.transform));
|
||||
// If we are synchronizing more than 1 axis (teleporting impacts this too)
|
||||
if (syncAxis != SyncAxis.SyncPosX && WillAnAxisBeSynchronized(ref networkTransform))
|
||||
{
|
||||
// For the x axis position value We should expect the state to still be considered dirty (more than one axis is being synchronized and we are teleporting)
|
||||
Assert.IsTrue(networkTransform.ApplyTransformToNetworkState(ref networkTransformState, 0, networkTransform.transform));
|
||||
// However, we expect it to not have applied the position x delta
|
||||
Assert.IsFalse(networkTransformState.HasPositionX);
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert.IsFalse(networkTransform.ApplyTransformToNetworkState(ref networkTransformState, 0, networkTransform.transform));
|
||||
}
|
||||
}
|
||||
|
||||
// SyncPositionY
|
||||
if (syncPosY)
|
||||
{
|
||||
networkTransform.SyncPositionY = false;
|
||||
|
||||
position.y++;
|
||||
networkTransform.transform.position = position;
|
||||
|
||||
Assert.IsFalse(networkTransform.ApplyTransformToNetworkState(ref networkTransformState, 0, networkTransform.transform));
|
||||
if (syncAxis != SyncAxis.SyncPosY && WillAnAxisBeSynchronized(ref networkTransform))
|
||||
{
|
||||
// We want to start with a fresh NetworkTransformState since it could have other state
|
||||
// information from the last time we applied the transform
|
||||
networkTransformState = new NetworkTransform.NetworkTransformState
|
||||
{
|
||||
InLocalSpace = inLocalSpace,
|
||||
IsTeleportingNextFrame = isTeleporting,
|
||||
};
|
||||
Assert.IsTrue(networkTransform.ApplyTransformToNetworkState(ref networkTransformState, 0, networkTransform.transform));
|
||||
Assert.IsFalse(networkTransformState.HasPositionY);
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert.IsFalse(networkTransform.ApplyTransformToNetworkState(ref networkTransformState, 0, networkTransform.transform));
|
||||
}
|
||||
}
|
||||
|
||||
// SyncPositionZ
|
||||
if (syncPosZ)
|
||||
{
|
||||
networkTransform.SyncPositionZ = false;
|
||||
|
||||
position.z++;
|
||||
networkTransform.transform.position = position;
|
||||
|
||||
Assert.IsFalse(networkTransform.ApplyTransformToNetworkState(ref networkTransformState, 0, networkTransform.transform));
|
||||
if (syncAxis != SyncAxis.SyncPosZ && WillAnAxisBeSynchronized(ref networkTransform))
|
||||
{
|
||||
// We want to start with a fresh NetworkTransformState since it could have other state
|
||||
// information from the last time we applied the transform
|
||||
networkTransformState = new NetworkTransform.NetworkTransformState
|
||||
{
|
||||
InLocalSpace = inLocalSpace,
|
||||
IsTeleportingNextFrame = isTeleporting,
|
||||
};
|
||||
Assert.IsTrue(networkTransform.ApplyTransformToNetworkState(ref networkTransformState, 0, networkTransform.transform));
|
||||
Assert.IsFalse(networkTransformState.HasPositionZ);
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert.IsFalse(networkTransform.ApplyTransformToNetworkState(ref networkTransformState, 0, networkTransform.transform));
|
||||
}
|
||||
}
|
||||
|
||||
// SyncRotAngleX
|
||||
if (syncRotX)
|
||||
{
|
||||
networkTransform.SyncRotAngleX = false;
|
||||
|
||||
rotAngles.x++;
|
||||
networkTransform.transform.eulerAngles = rotAngles;
|
||||
|
||||
Assert.IsFalse(networkTransform.ApplyTransformToNetworkState(ref networkTransformState, 0, networkTransform.transform));
|
||||
if (syncAxis != SyncAxis.SyncRotX && WillAnAxisBeSynchronized(ref networkTransform))
|
||||
{
|
||||
// We want to start with a fresh NetworkTransformState since it could have other state
|
||||
// information from the last time we applied the transform
|
||||
networkTransformState = new NetworkTransform.NetworkTransformState
|
||||
{
|
||||
InLocalSpace = inLocalSpace,
|
||||
IsTeleportingNextFrame = isTeleporting,
|
||||
};
|
||||
Assert.IsTrue(networkTransform.ApplyTransformToNetworkState(ref networkTransformState, 0, networkTransform.transform));
|
||||
Assert.IsFalse(networkTransformState.HasRotAngleX);
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert.IsFalse(networkTransform.ApplyTransformToNetworkState(ref networkTransformState, 0, networkTransform.transform));
|
||||
}
|
||||
}
|
||||
// SyncRotAngleY
|
||||
if (syncRotY)
|
||||
{
|
||||
networkTransform.SyncRotAngleY = false;
|
||||
|
||||
rotAngles.y++;
|
||||
networkTransform.transform.eulerAngles = rotAngles;
|
||||
|
||||
Assert.IsFalse(networkTransform.ApplyTransformToNetworkState(ref networkTransformState, 0, networkTransform.transform));
|
||||
if (syncAxis != SyncAxis.SyncRotY && WillAnAxisBeSynchronized(ref networkTransform))
|
||||
{
|
||||
// We want to start with a fresh NetworkTransformState since it could have other state
|
||||
// information from the last time we applied the transform
|
||||
networkTransformState = new NetworkTransform.NetworkTransformState
|
||||
{
|
||||
InLocalSpace = inLocalSpace,
|
||||
IsTeleportingNextFrame = isTeleporting,
|
||||
};
|
||||
Assert.IsTrue(networkTransform.ApplyTransformToNetworkState(ref networkTransformState, 0, networkTransform.transform));
|
||||
Assert.IsFalse(networkTransformState.HasRotAngleY);
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert.IsFalse(networkTransform.ApplyTransformToNetworkState(ref networkTransformState, 0, networkTransform.transform));
|
||||
}
|
||||
}
|
||||
// SyncRotAngleZ
|
||||
if (syncRotZ)
|
||||
{
|
||||
networkTransform.SyncRotAngleZ = false;
|
||||
|
||||
rotAngles.z++;
|
||||
networkTransform.transform.eulerAngles = rotAngles;
|
||||
|
||||
Assert.IsFalse(networkTransform.ApplyTransformToNetworkState(ref networkTransformState, 0, networkTransform.transform));
|
||||
if (syncAxis != SyncAxis.SyncRotZ && WillAnAxisBeSynchronized(ref networkTransform))
|
||||
{
|
||||
// We want to start with a fresh NetworkTransformState since it could have other state
|
||||
// information from the last time we applied the transform
|
||||
networkTransformState = new NetworkTransform.NetworkTransformState
|
||||
{
|
||||
InLocalSpace = inLocalSpace,
|
||||
IsTeleportingNextFrame = isTeleporting,
|
||||
};
|
||||
Assert.IsTrue(networkTransform.ApplyTransformToNetworkState(ref networkTransformState, 0, networkTransform.transform));
|
||||
Assert.IsFalse(networkTransformState.HasRotAngleZ);
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert.IsFalse(networkTransform.ApplyTransformToNetworkState(ref networkTransformState, 0, networkTransform.transform));
|
||||
}
|
||||
}
|
||||
|
||||
// SyncScaleX
|
||||
if (syncScaX)
|
||||
{
|
||||
networkTransform.SyncScaleX = false;
|
||||
|
||||
scale.x++;
|
||||
networkTransform.transform.localScale = scale;
|
||||
|
||||
Assert.IsFalse(networkTransform.ApplyTransformToNetworkState(ref networkTransformState, 0, networkTransform.transform));
|
||||
if (syncAxis != SyncAxis.SyncScaleX && WillAnAxisBeSynchronized(ref networkTransform))
|
||||
{
|
||||
// We want to start with a fresh NetworkTransformState since it could have other state
|
||||
// information from the last time we applied the transform
|
||||
networkTransformState = new NetworkTransform.NetworkTransformState
|
||||
{
|
||||
InLocalSpace = inLocalSpace,
|
||||
IsTeleportingNextFrame = isTeleporting,
|
||||
};
|
||||
Assert.IsTrue(networkTransform.ApplyTransformToNetworkState(ref networkTransformState, 0, networkTransform.transform));
|
||||
Assert.IsFalse(networkTransformState.HasScaleX);
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert.IsFalse(networkTransform.ApplyTransformToNetworkState(ref networkTransformState, 0, networkTransform.transform));
|
||||
}
|
||||
}
|
||||
// SyncScaleY
|
||||
if (syncScaY)
|
||||
{
|
||||
networkTransform.SyncScaleY = false;
|
||||
|
||||
scale.y++;
|
||||
networkTransform.transform.localScale = scale;
|
||||
|
||||
Assert.IsFalse(networkTransform.ApplyTransformToNetworkState(ref networkTransformState, 0, networkTransform.transform));
|
||||
if (syncAxis != SyncAxis.SyncScaleY && WillAnAxisBeSynchronized(ref networkTransform))
|
||||
{
|
||||
// We want to start with a fresh NetworkTransformState since it could have other state
|
||||
// information from the last time we applied the transform
|
||||
networkTransformState = new NetworkTransform.NetworkTransformState
|
||||
{
|
||||
InLocalSpace = inLocalSpace,
|
||||
IsTeleportingNextFrame = isTeleporting,
|
||||
};
|
||||
Assert.IsTrue(networkTransform.ApplyTransformToNetworkState(ref networkTransformState, 0, networkTransform.transform));
|
||||
Assert.IsFalse(networkTransformState.HasScaleY);
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert.IsFalse(networkTransform.ApplyTransformToNetworkState(ref networkTransformState, 0, networkTransform.transform));
|
||||
}
|
||||
}
|
||||
// SyncScaleZ
|
||||
if (syncScaZ)
|
||||
{
|
||||
networkTransform.SyncScaleZ = false;
|
||||
|
||||
scale.z++;
|
||||
networkTransform.transform.localScale = scale;
|
||||
|
||||
Assert.IsFalse(networkTransform.ApplyTransformToNetworkState(ref networkTransformState, 0, networkTransform.transform));
|
||||
if (syncAxis != SyncAxis.SyncScaleZ && WillAnAxisBeSynchronized(ref networkTransform))
|
||||
{
|
||||
// We want to start with a fresh NetworkTransformState since it could have other state
|
||||
// information from the last time we applied the transform
|
||||
networkTransformState = new NetworkTransform.NetworkTransformState
|
||||
{
|
||||
InLocalSpace = inLocalSpace,
|
||||
IsTeleportingNextFrame = isTeleporting,
|
||||
};
|
||||
Assert.IsTrue(networkTransform.ApplyTransformToNetworkState(ref networkTransformState, 0, networkTransform.transform));
|
||||
Assert.IsFalse(networkTransformState.HasScaleZ);
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert.IsFalse(networkTransform.ApplyTransformToNetworkState(ref networkTransformState, 0, networkTransform.transform));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Object.DestroyImmediate(gameObject);
|
||||
@@ -168,11 +513,11 @@ namespace Unity.Netcode.RuntimeTests
|
||||
|
||||
[Test]
|
||||
public void TestThresholds(
|
||||
[Values] bool inLocalSpace,
|
||||
[Values(NetworkTransform.PositionThresholdDefault, 1.0f)] float positionThreshold,
|
||||
[Values(NetworkTransform.RotAngleThresholdDefault, 1.0f)] float rotAngleThreshold,
|
||||
[Values(NetworkTransform.ScaleThresholdDefault, 0.5f)] float scaleThreshold)
|
||||
{
|
||||
var inLocalSpace = m_TransformSpace == TransformSpace.Local;
|
||||
var gameObject = new GameObject($"Test-{nameof(NetworkTransformStateTests)}.{nameof(TestThresholds)}");
|
||||
var networkTransform = gameObject.AddComponent<NetworkTransform>();
|
||||
networkTransform.enabled = false; // do not tick `FixedUpdate()` or `Update()`
|
||||
|
||||
@@ -189,7 +189,8 @@ namespace Unity.Netcode.RuntimeTests
|
||||
public enum OverrideState
|
||||
{
|
||||
Update,
|
||||
CommitToTransform
|
||||
CommitToTransform,
|
||||
SetState
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -299,9 +300,8 @@ namespace Unity.Netcode.RuntimeTests
|
||||
/// parented under another NetworkTransform
|
||||
/// </summary>
|
||||
[UnityTest]
|
||||
public IEnumerator NetworkTransformParentedLocalSpaceTest([Values] Interpolation interpolation, [Values] OverrideState overideState)
|
||||
public IEnumerator NetworkTransformParentedLocalSpaceTest([Values] Interpolation interpolation)
|
||||
{
|
||||
var overrideUpdate = overideState == OverrideState.CommitToTransform;
|
||||
m_AuthoritativeTransform.Interpolate = interpolation == Interpolation.EnableInterpolate;
|
||||
m_NonAuthoritativeTransform.Interpolate = interpolation == Interpolation.EnableInterpolate;
|
||||
var authoritativeChildObject = SpawnObject(m_ChildObjectToBeParented.gameObject, m_AuthoritativeTransform.NetworkManager);
|
||||
@@ -334,15 +334,28 @@ namespace Unity.Netcode.RuntimeTests
|
||||
/// Validates that moving, rotating, and scaling the authority side with a single
|
||||
/// tick will properly synchronize the non-authoritative side with the same values.
|
||||
/// </summary>
|
||||
private IEnumerator MoveRotateAndScaleAuthority(Vector3 position, Vector3 rotation, Vector3 scale)
|
||||
private IEnumerator MoveRotateAndScaleAuthority(Vector3 position, Vector3 rotation, Vector3 scale, OverrideState overrideState)
|
||||
{
|
||||
m_AuthoritativeTransform.transform.position = position;
|
||||
yield return null;
|
||||
var authoritativeRotation = m_AuthoritativeTransform.transform.rotation;
|
||||
authoritativeRotation.eulerAngles = rotation;
|
||||
m_AuthoritativeTransform.transform.rotation = authoritativeRotation;
|
||||
yield return null;
|
||||
m_AuthoritativeTransform.transform.localScale = scale;
|
||||
switch (overrideState)
|
||||
{
|
||||
case OverrideState.SetState:
|
||||
{
|
||||
m_AuthoritativeTransform.SetState(position, Quaternion.Euler(rotation), scale);
|
||||
break;
|
||||
}
|
||||
case OverrideState.Update:
|
||||
default:
|
||||
{
|
||||
m_AuthoritativeTransform.transform.position = position;
|
||||
yield return null;
|
||||
var authoritativeRotation = m_AuthoritativeTransform.transform.rotation;
|
||||
authoritativeRotation.eulerAngles = rotation;
|
||||
m_AuthoritativeTransform.transform.rotation = authoritativeRotation;
|
||||
yield return null;
|
||||
m_AuthoritativeTransform.transform.localScale = scale;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -400,7 +413,6 @@ namespace Unity.Netcode.RuntimeTests
|
||||
[UnityTest]
|
||||
public IEnumerator NetworkTransformMultipleChangesOverTime([Values] TransformSpace testLocalTransform, [Values] OverrideState overideState)
|
||||
{
|
||||
var overrideUpdate = overideState == OverrideState.CommitToTransform;
|
||||
m_AuthoritativeTransform.InLocalSpace = testLocalTransform == TransformSpace.Local;
|
||||
|
||||
var positionStart = new Vector3(1.0f, 0.5f, 2.0f);
|
||||
@@ -422,7 +434,7 @@ namespace Unity.Netcode.RuntimeTests
|
||||
yield return WaitForNextTick();
|
||||
|
||||
// Apply deltas
|
||||
MoveRotateAndScaleAuthority(position, rotation, scale);
|
||||
MoveRotateAndScaleAuthority(position, rotation, scale, overideState);
|
||||
|
||||
// Wait for deltas to synchronize on non-authoritative side
|
||||
yield return WaitForPositionRotationAndScaleToMatch(4);
|
||||
@@ -455,7 +467,7 @@ namespace Unity.Netcode.RuntimeTests
|
||||
// to apply both deltas within the same tick period.
|
||||
yield return WaitForNextTick();
|
||||
|
||||
MoveRotateAndScaleAuthority(position, rotation, scale);
|
||||
MoveRotateAndScaleAuthority(position, rotation, scale, overideState);
|
||||
yield return WaitForPositionRotationAndScaleToMatch(4);
|
||||
}
|
||||
|
||||
@@ -471,7 +483,7 @@ namespace Unity.Netcode.RuntimeTests
|
||||
rotation = rotationStart * i;
|
||||
scale = scaleStart * i;
|
||||
|
||||
MoveRotateAndScaleAuthority(position, rotation, scale);
|
||||
MoveRotateAndScaleAuthority(position, rotation, scale, overideState);
|
||||
}
|
||||
|
||||
yield return WaitForPositionRotationAndScaleToMatch(1);
|
||||
@@ -486,7 +498,7 @@ namespace Unity.Netcode.RuntimeTests
|
||||
position = positionStart * i;
|
||||
rotation = rotationStart * i;
|
||||
scale = scaleStart * i;
|
||||
MoveRotateAndScaleAuthority(position, rotation, scale);
|
||||
MoveRotateAndScaleAuthority(position, rotation, scale, overideState);
|
||||
}
|
||||
yield return WaitForPositionRotationAndScaleToMatch(1);
|
||||
}
|
||||
@@ -513,11 +525,16 @@ namespace Unity.Netcode.RuntimeTests
|
||||
|
||||
Assert.AreEqual(Vector3.zero, m_NonAuthoritativeTransform.transform.position, "server side pos should be zero at first"); // sanity check
|
||||
|
||||
authPlayerTransform.position = new Vector3(10, 20, 30);
|
||||
if (overrideUpdate)
|
||||
var nextPosition = new Vector3(10, 20, 30);
|
||||
if (overideState != OverrideState.SetState)
|
||||
{
|
||||
authPlayerTransform.position = nextPosition;
|
||||
m_OwnerTransform.CommitToTransform();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_OwnerTransform.SetState(nextPosition, null, null, m_AuthoritativeTransform.Interpolate);
|
||||
}
|
||||
|
||||
yield return WaitForConditionOrTimeOut(PositionsMatch);
|
||||
AssertOnTimeout($"Timed out waiting for positions to match");
|
||||
@@ -525,20 +542,30 @@ namespace Unity.Netcode.RuntimeTests
|
||||
// test rotation
|
||||
Assert.AreEqual(Quaternion.identity, m_NonAuthoritativeTransform.transform.rotation, "wrong initial value for rotation"); // sanity check
|
||||
|
||||
authPlayerTransform.rotation = Quaternion.Euler(45, 40, 35); // using euler angles instead of quaternions directly to really see issues users might encounter
|
||||
if (overrideUpdate)
|
||||
var nextRotation = Quaternion.Euler(45, 40, 35); // using euler angles instead of quaternions directly to really see issues users might encounter
|
||||
if (overideState != OverrideState.SetState)
|
||||
{
|
||||
authPlayerTransform.rotation = nextRotation;
|
||||
m_OwnerTransform.CommitToTransform();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_OwnerTransform.SetState(null, nextRotation, null, m_AuthoritativeTransform.Interpolate);
|
||||
}
|
||||
|
||||
yield return WaitForConditionOrTimeOut(RotationsMatch);
|
||||
AssertOnTimeout($"Timed out waiting for rotations to match");
|
||||
|
||||
authPlayerTransform.localScale = new Vector3(2, 3, 4);
|
||||
var nextScale = new Vector3(2, 3, 4);
|
||||
if (overrideUpdate)
|
||||
{
|
||||
authPlayerTransform.localScale = nextScale;
|
||||
m_OwnerTransform.CommitToTransform();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_OwnerTransform.SetState(null, null, nextScale, m_AuthoritativeTransform.Interpolate);
|
||||
}
|
||||
|
||||
yield return WaitForConditionOrTimeOut(ScaleValuesMatch);
|
||||
AssertOnTimeout($"Timed out waiting for scale values to match");
|
||||
|
||||
@@ -17,6 +17,57 @@ namespace Unity.Netcode.RuntimeTests
|
||||
public NetworkVariable<Vector3> OwnerReadWrite_Position = new NetworkVariable<Vector3>(Vector3.one, NetworkVariableReadPermission.Owner, NetworkVariableWritePermission.Owner);
|
||||
}
|
||||
|
||||
// The ILPP code for NetworkVariables to determine how to serialize them relies on them existing as fields of a NetworkBehaviour to find them.
|
||||
// Some of the tests below create NetworkVariables on the stack, so this class is here just to make sure the relevant types are all accounted for.
|
||||
public class NetVarILPPClassForTests : NetworkBehaviour
|
||||
{
|
||||
public NetworkVariable<UnmanagedNetworkSerializableType> UnmanagedNetworkSerializableTypeVar;
|
||||
public NetworkVariable<ManagedNetworkSerializableType> ManagedNetworkSerializableTypeVar;
|
||||
public NetworkVariable<string> StringVar;
|
||||
public NetworkVariable<Guid> GuidVar;
|
||||
}
|
||||
|
||||
public class TemplateNetworkBehaviourType<T> : NetworkBehaviour
|
||||
{
|
||||
public NetworkVariable<T> TheVar;
|
||||
}
|
||||
|
||||
public class ClassHavingNetworkBehaviour : TemplateNetworkBehaviourType<TestClass>
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
// Please do not reference TestClass2 anywhere other than here!
|
||||
public class ClassHavingNetworkBehaviour2 : TemplateNetworkBehaviourType<TestClass_ReferencedOnlyByTemplateNetworkBehavourType>
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public class StructHavingNetworkBehaviour : TemplateNetworkBehaviourType<TestStruct>
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public struct StructUsedOnlyInNetworkList : IEquatable<StructUsedOnlyInNetworkList>, INetworkSerializeByMemcpy
|
||||
{
|
||||
public int Value;
|
||||
|
||||
public bool Equals(StructUsedOnlyInNetworkList other)
|
||||
{
|
||||
return Value == other.Value;
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
return obj is StructUsedOnlyInNetworkList other && Equals(other);
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return Value;
|
||||
}
|
||||
}
|
||||
|
||||
[TestFixtureSource(nameof(TestDataSource))]
|
||||
public class NetworkVariablePermissionTests : NetcodeIntegrationTest
|
||||
{
|
||||
@@ -344,6 +395,53 @@ namespace Unity.Netcode.RuntimeTests
|
||||
}
|
||||
}
|
||||
|
||||
public class TestClass : INetworkSerializable, IEquatable<TestClass>
|
||||
{
|
||||
public uint SomeInt;
|
||||
public bool SomeBool;
|
||||
public static bool NetworkSerializeCalledOnWrite;
|
||||
public static bool NetworkSerializeCalledOnRead;
|
||||
|
||||
public void NetworkSerialize<T>(BufferSerializer<T> serializer) where T : IReaderWriter
|
||||
{
|
||||
if (serializer.IsReader)
|
||||
{
|
||||
NetworkSerializeCalledOnRead = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
NetworkSerializeCalledOnWrite = true;
|
||||
}
|
||||
serializer.SerializeValue(ref SomeInt);
|
||||
serializer.SerializeValue(ref SomeBool);
|
||||
}
|
||||
|
||||
public bool Equals(TestClass other)
|
||||
{
|
||||
return SomeInt == other.SomeInt && SomeBool == other.SomeBool;
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
return obj is TestClass other && Equals(other);
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
return ((int)SomeInt * 397) ^ SomeBool.GetHashCode();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Used just to create a NetworkVariable in the templated NetworkBehaviour type that isn't referenced anywhere else
|
||||
// Please do not reference this class anywhere else!
|
||||
public class TestClass_ReferencedOnlyByTemplateNetworkBehavourType : TestClass
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public class NetworkVariableTest : NetworkBehaviour
|
||||
{
|
||||
public enum SomeEnum
|
||||
@@ -355,6 +453,7 @@ namespace Unity.Netcode.RuntimeTests
|
||||
public readonly NetworkVariable<int> TheScalar = new NetworkVariable<int>();
|
||||
public readonly NetworkVariable<SomeEnum> TheEnum = new NetworkVariable<SomeEnum>();
|
||||
public readonly NetworkList<int> TheList = new NetworkList<int>();
|
||||
public readonly NetworkList<StructUsedOnlyInNetworkList> TheStructList = new NetworkList<StructUsedOnlyInNetworkList>();
|
||||
public readonly NetworkList<FixedString128Bytes> TheLargeList = new NetworkList<FixedString128Bytes>();
|
||||
|
||||
public readonly NetworkVariable<FixedString32Bytes> FixedString32 = new NetworkVariable<FixedString32Bytes>();
|
||||
@@ -370,7 +469,10 @@ namespace Unity.Netcode.RuntimeTests
|
||||
}
|
||||
|
||||
public readonly NetworkVariable<TestStruct> TheStruct = new NetworkVariable<TestStruct>();
|
||||
public readonly NetworkList<TestStruct> TheListOfStructs = new NetworkList<TestStruct>();
|
||||
public readonly NetworkVariable<TestClass> TheClass = new NetworkVariable<TestClass>();
|
||||
|
||||
public NetworkVariable<UnmanagedTemplateNetworkSerializableType<TestStruct>> TheTemplateStruct = new NetworkVariable<UnmanagedTemplateNetworkSerializableType<TestStruct>>();
|
||||
public NetworkVariable<ManagedTemplateNetworkSerializableType<TestClass>> TheTemplateClass = new NetworkVariable<ManagedTemplateNetworkSerializableType<TestClass>>();
|
||||
|
||||
public bool ListDelegateTriggered;
|
||||
|
||||
@@ -433,6 +535,10 @@ namespace Unity.Netcode.RuntimeTests
|
||||
s_ClientNetworkVariableTestInstances.Clear();
|
||||
m_PlayerPrefab.AddComponent<NetworkVariableTest>();
|
||||
|
||||
m_PlayerPrefab.AddComponent<ClassHavingNetworkBehaviour>();
|
||||
m_PlayerPrefab.AddComponent<ClassHavingNetworkBehaviour2>();
|
||||
m_PlayerPrefab.AddComponent<StructHavingNetworkBehaviour>();
|
||||
|
||||
m_ServerNetworkManager.NetworkConfig.EnsureNetworkVariableLengthSafety = m_EnsureLengthSafety;
|
||||
m_ServerNetworkManager.NetworkConfig.PlayerPrefab = m_PlayerPrefab;
|
||||
foreach (var client in m_ClientNetworkManagers)
|
||||
@@ -517,6 +623,7 @@ namespace Unity.Netcode.RuntimeTests
|
||||
networkVariableTestComponent.EnableTesting = false;
|
||||
|
||||
Assert.IsTrue(networkVariableTestComponent.DidAllValuesChange());
|
||||
networkVariableTestComponent.AssertAllValuesAreCorrect();
|
||||
|
||||
// Disable this once we are done.
|
||||
networkVariableTestComponent.gameObject.SetActive(false);
|
||||
@@ -536,6 +643,23 @@ namespace Unity.Netcode.RuntimeTests
|
||||
Assert.Throws<InvalidOperationException>(() => m_Player1OnClient1.TheScalar.Value = k_TestVal1);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Runs tests that network variables sync on client whatever the local value of <see cref="Time.timeScale"/>.
|
||||
/// </summary>
|
||||
[UnityTest]
|
||||
public IEnumerator NetworkVariableSync_WithDifferentTimeScale([Values(true, false)] bool useHost, [Values(0.0f, 1.0f, 2.0f)] float timeScale)
|
||||
{
|
||||
Time.timeScale = timeScale;
|
||||
|
||||
yield return InitializeServerAndClients(useHost);
|
||||
|
||||
m_Player1OnServer.TheScalar.Value = k_TestVal1;
|
||||
|
||||
// Now wait for the client side version to be updated to k_TestVal1
|
||||
yield return WaitForConditionOrTimeOut(() => m_Player1OnClient1.TheScalar.Value == k_TestVal1);
|
||||
Assert.IsFalse(s_GlobalTimeoutHelper.TimedOut, "Timed out waiting for client-side NetworkVariable to update!");
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator FixedString32Test([Values(true, false)] bool useHost)
|
||||
{
|
||||
@@ -672,6 +796,63 @@ namespace Unity.Netcode.RuntimeTests
|
||||
yield return WaitForConditionOrTimeOut(m_NetworkListPredicateHandler);
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator TestNetworkVariableClass([Values(true, false)] bool useHost)
|
||||
{
|
||||
yield return InitializeServerAndClients(useHost);
|
||||
|
||||
bool VerifyClass()
|
||||
{
|
||||
return m_Player1OnClient1.TheClass.Value != null &&
|
||||
m_Player1OnClient1.TheClass.Value.SomeBool == m_Player1OnServer.TheClass.Value.SomeBool &&
|
||||
m_Player1OnClient1.TheClass.Value.SomeInt == m_Player1OnServer.TheClass.Value.SomeInt;
|
||||
}
|
||||
|
||||
m_Player1OnServer.TheClass.Value = new TestClass { SomeInt = k_TestUInt, SomeBool = false };
|
||||
m_Player1OnServer.TheClass.SetDirty(true);
|
||||
|
||||
// Wait for the client-side to notify it is finished initializing and spawning.
|
||||
yield return WaitForConditionOrTimeOut(VerifyClass);
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator TestNetworkVariableTemplateClass([Values(true, false)] bool useHost)
|
||||
{
|
||||
yield return InitializeServerAndClients(useHost);
|
||||
|
||||
bool VerifyClass()
|
||||
{
|
||||
return m_Player1OnClient1.TheTemplateClass.Value.Value != null && m_Player1OnClient1.TheTemplateClass.Value.Value.SomeBool == m_Player1OnServer.TheTemplateClass.Value.Value.SomeBool &&
|
||||
m_Player1OnClient1.TheTemplateClass.Value.Value.SomeInt == m_Player1OnServer.TheTemplateClass.Value.Value.SomeInt;
|
||||
}
|
||||
|
||||
m_Player1OnServer.TheTemplateClass.Value = new ManagedTemplateNetworkSerializableType<TestClass> { Value = new TestClass { SomeInt = k_TestUInt, SomeBool = false } };
|
||||
m_Player1OnServer.TheTemplateClass.SetDirty(true);
|
||||
|
||||
// Wait for the client-side to notify it is finished initializing and spawning.
|
||||
yield return WaitForConditionOrTimeOut(VerifyClass);
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator TestNetworkListStruct([Values(true, false)] bool useHost)
|
||||
{
|
||||
yield return InitializeServerAndClients(useHost);
|
||||
|
||||
bool VerifyList()
|
||||
{
|
||||
return m_Player1OnClient1.TheStructList.Count == m_Player1OnServer.TheStructList.Count &&
|
||||
m_Player1OnClient1.TheStructList[0].Value == m_Player1OnServer.TheStructList[0].Value &&
|
||||
m_Player1OnClient1.TheStructList[1].Value == m_Player1OnServer.TheStructList[1].Value;
|
||||
}
|
||||
|
||||
m_Player1OnServer.TheStructList.Add(new StructUsedOnlyInNetworkList { Value = 1 });
|
||||
m_Player1OnServer.TheStructList.Add(new StructUsedOnlyInNetworkList { Value = 2 });
|
||||
m_Player1OnServer.TheStructList.SetDirty(true);
|
||||
|
||||
// Wait for the client-side to notify it is finished initializing and spawning.
|
||||
yield return WaitForConditionOrTimeOut(VerifyList);
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator TestNetworkVariableStruct([Values(true, false)] bool useHost)
|
||||
{
|
||||
@@ -683,13 +864,85 @@ namespace Unity.Netcode.RuntimeTests
|
||||
m_Player1OnClient1.TheStruct.Value.SomeInt == m_Player1OnServer.TheStruct.Value.SomeInt;
|
||||
}
|
||||
|
||||
m_Player1OnServer.TheStruct.Value = new TestStruct() { SomeInt = k_TestUInt, SomeBool = false };
|
||||
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 TestNetworkVariableTemplateStruct([Values(true, false)] bool useHost)
|
||||
{
|
||||
yield return InitializeServerAndClients(useHost);
|
||||
|
||||
bool VerifyStructure()
|
||||
{
|
||||
return m_Player1OnClient1.TheTemplateStruct.Value.Value.SomeBool == m_Player1OnServer.TheTemplateStruct.Value.Value.SomeBool &&
|
||||
m_Player1OnClient1.TheTemplateStruct.Value.Value.SomeInt == m_Player1OnServer.TheTemplateStruct.Value.Value.SomeInt;
|
||||
}
|
||||
|
||||
m_Player1OnServer.TheTemplateStruct.Value = new UnmanagedTemplateNetworkSerializableType<TestStruct> { Value = new TestStruct { SomeInt = k_TestUInt, SomeBool = false } };
|
||||
m_Player1OnServer.TheTemplateStruct.SetDirty(true);
|
||||
|
||||
// Wait for the client-side to notify it is finished initializing and spawning.
|
||||
yield return WaitForConditionOrTimeOut(VerifyStructure);
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator TestNetworkVariableTemplateBehaviourClass([Values(true, false)] bool useHost)
|
||||
{
|
||||
yield return InitializeServerAndClients(useHost);
|
||||
|
||||
bool VerifyClass()
|
||||
{
|
||||
return m_Player1OnClient1.GetComponent<ClassHavingNetworkBehaviour>().TheVar.Value != null && m_Player1OnClient1.GetComponent<ClassHavingNetworkBehaviour>().TheVar.Value.SomeBool == m_Player1OnServer.GetComponent<ClassHavingNetworkBehaviour>().TheVar.Value.SomeBool &&
|
||||
m_Player1OnClient1.GetComponent<ClassHavingNetworkBehaviour>().TheVar.Value.SomeInt == m_Player1OnServer.GetComponent<ClassHavingNetworkBehaviour>().TheVar.Value.SomeInt;
|
||||
}
|
||||
|
||||
m_Player1OnServer.GetComponent<ClassHavingNetworkBehaviour>().TheVar.Value = new TestClass { SomeInt = k_TestUInt, SomeBool = false };
|
||||
m_Player1OnServer.GetComponent<ClassHavingNetworkBehaviour>().TheVar.SetDirty(true);
|
||||
|
||||
// Wait for the client-side to notify it is finished initializing and spawning.
|
||||
yield return WaitForConditionOrTimeOut(VerifyClass);
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator TestNetworkVariableTemplateBehaviourClassNotReferencedElsewhere([Values(true, false)] bool useHost)
|
||||
{
|
||||
yield return InitializeServerAndClients(useHost);
|
||||
|
||||
bool VerifyClass()
|
||||
{
|
||||
return m_Player1OnClient1.GetComponent<ClassHavingNetworkBehaviour2>().TheVar.Value != null && m_Player1OnClient1.GetComponent<ClassHavingNetworkBehaviour2>().TheVar.Value.SomeBool == m_Player1OnServer.GetComponent<ClassHavingNetworkBehaviour2>().TheVar.Value.SomeBool &&
|
||||
m_Player1OnClient1.GetComponent<ClassHavingNetworkBehaviour2>().TheVar.Value.SomeInt == m_Player1OnServer.GetComponent<ClassHavingNetworkBehaviour2>().TheVar.Value.SomeInt;
|
||||
}
|
||||
|
||||
m_Player1OnServer.GetComponent<ClassHavingNetworkBehaviour2>().TheVar.Value = new TestClass_ReferencedOnlyByTemplateNetworkBehavourType { SomeInt = k_TestUInt, SomeBool = false };
|
||||
m_Player1OnServer.GetComponent<ClassHavingNetworkBehaviour2>().TheVar.SetDirty(true);
|
||||
|
||||
// Wait for the client-side to notify it is finished initializing and spawning.
|
||||
yield return WaitForConditionOrTimeOut(VerifyClass);
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator TestNetworkVariableTemplateBehaviourStruct([Values(true, false)] bool useHost)
|
||||
{
|
||||
yield return InitializeServerAndClients(useHost);
|
||||
|
||||
bool VerifyClass()
|
||||
{
|
||||
return m_Player1OnClient1.GetComponent<StructHavingNetworkBehaviour>().TheVar.Value.SomeBool == m_Player1OnServer.GetComponent<StructHavingNetworkBehaviour>().TheVar.Value.SomeBool &&
|
||||
m_Player1OnClient1.GetComponent<StructHavingNetworkBehaviour>().TheVar.Value.SomeInt == m_Player1OnServer.GetComponent<StructHavingNetworkBehaviour>().TheVar.Value.SomeInt;
|
||||
}
|
||||
|
||||
m_Player1OnServer.GetComponent<StructHavingNetworkBehaviour>().TheVar.Value = new TestStruct { SomeInt = k_TestUInt, SomeBool = false };
|
||||
m_Player1OnServer.GetComponent<StructHavingNetworkBehaviour>().TheVar.SetDirty(true);
|
||||
|
||||
// Wait for the client-side to notify it is finished initializing and spawning.
|
||||
yield return WaitForConditionOrTimeOut(VerifyClass);
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator TestNetworkVariableEnum([Values(true, false)] bool useHost)
|
||||
{
|
||||
@@ -708,7 +961,25 @@ namespace Unity.Netcode.RuntimeTests
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator TestINetworkSerializableCallsNetworkSerialize([Values(true, false)] bool useHost)
|
||||
public IEnumerator TestINetworkSerializableClassCallsNetworkSerialize([Values(true, false)] bool useHost)
|
||||
{
|
||||
yield return InitializeServerAndClients(useHost);
|
||||
TestClass.NetworkSerializeCalledOnWrite = false;
|
||||
TestClass.NetworkSerializeCalledOnRead = false;
|
||||
m_Player1OnServer.TheClass.Value = new TestClass
|
||||
{
|
||||
SomeBool = true,
|
||||
SomeInt = 32
|
||||
};
|
||||
|
||||
static bool VerifyCallback() => TestClass.NetworkSerializeCalledOnWrite && TestClass.NetworkSerializeCalledOnRead;
|
||||
|
||||
// Wait for the client-side to notify it is finished initializing and spawning.
|
||||
yield return WaitForConditionOrTimeOut(VerifyCallback);
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator TestINetworkSerializableStructCallsNetworkSerialize([Values(true, false)] bool useHost)
|
||||
{
|
||||
yield return InitializeServerAndClients(useHost);
|
||||
TestStruct.NetworkSerializeCalledOnWrite = false;
|
||||
@@ -756,11 +1027,181 @@ namespace Unity.Netcode.RuntimeTests
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestUnsupportedManagedTypesThrowExceptions()
|
||||
{
|
||||
var variable = new NetworkVariable<string>();
|
||||
using var writer = new FastBufferWriter(1024, Allocator.Temp);
|
||||
using var reader = new FastBufferReader(writer, Allocator.None);
|
||||
// Just making sure these are null, just in case.
|
||||
UserNetworkVariableSerialization<string>.ReadValue = null;
|
||||
UserNetworkVariableSerialization<string>.WriteValue = null;
|
||||
Assert.Throws<ArgumentException>(() =>
|
||||
{
|
||||
variable.WriteField(writer);
|
||||
});
|
||||
Assert.Throws<ArgumentException>(() =>
|
||||
{
|
||||
variable.ReadField(reader);
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestUnsupportedManagedTypesWithUserSerializationDoNotThrowExceptions()
|
||||
{
|
||||
var variable = new NetworkVariable<string>();
|
||||
UserNetworkVariableSerialization<string>.ReadValue = (FastBufferReader reader, out string value) =>
|
||||
{
|
||||
reader.ReadValueSafe(out value);
|
||||
};
|
||||
UserNetworkVariableSerialization<string>.WriteValue = (FastBufferWriter writer, in string value) =>
|
||||
{
|
||||
writer.WriteValueSafe(value);
|
||||
};
|
||||
try
|
||||
{
|
||||
using var writer = new FastBufferWriter(1024, Allocator.Temp);
|
||||
variable.Value = "012345";
|
||||
variable.WriteField(writer);
|
||||
variable.Value = "";
|
||||
|
||||
using var reader = new FastBufferReader(writer, Allocator.None);
|
||||
variable.ReadField(reader);
|
||||
Assert.AreEqual("012345", variable.Value);
|
||||
}
|
||||
finally
|
||||
{
|
||||
UserNetworkVariableSerialization<string>.ReadValue = null;
|
||||
UserNetworkVariableSerialization<string>.WriteValue = null;
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestUnsupportedUnmanagedTypesThrowExceptions()
|
||||
{
|
||||
var variable = new NetworkVariable<Guid>();
|
||||
using var writer = new FastBufferWriter(1024, Allocator.Temp);
|
||||
using var reader = new FastBufferReader(writer, Allocator.None);
|
||||
// Just making sure these are null, just in case.
|
||||
UserNetworkVariableSerialization<Guid>.ReadValue = null;
|
||||
UserNetworkVariableSerialization<Guid>.WriteValue = null;
|
||||
Assert.Throws<ArgumentException>(() =>
|
||||
{
|
||||
variable.WriteField(writer);
|
||||
});
|
||||
Assert.Throws<ArgumentException>(() =>
|
||||
{
|
||||
variable.ReadField(reader);
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestUnsupportedUnmanagedTypesWithUserSerializationDoNotThrowExceptions()
|
||||
{
|
||||
var variable = new NetworkVariable<Guid>();
|
||||
UserNetworkVariableSerialization<Guid>.ReadValue = (FastBufferReader reader, out Guid value) =>
|
||||
{
|
||||
var tmpValue = new ForceNetworkSerializeByMemcpy<Guid>();
|
||||
reader.ReadValueSafe(out tmpValue);
|
||||
value = tmpValue.Value;
|
||||
};
|
||||
UserNetworkVariableSerialization<Guid>.WriteValue = (FastBufferWriter writer, in Guid value) =>
|
||||
{
|
||||
var tmpValue = new ForceNetworkSerializeByMemcpy<Guid>(value);
|
||||
writer.WriteValueSafe(tmpValue);
|
||||
};
|
||||
try
|
||||
{
|
||||
using var writer = new FastBufferWriter(1024, Allocator.Temp);
|
||||
var guid = Guid.NewGuid();
|
||||
variable.Value = guid;
|
||||
variable.WriteField(writer);
|
||||
variable.Value = Guid.Empty;
|
||||
|
||||
using var reader = new FastBufferReader(writer, Allocator.None);
|
||||
variable.ReadField(reader);
|
||||
Assert.AreEqual(guid, variable.Value);
|
||||
}
|
||||
finally
|
||||
{
|
||||
UserNetworkVariableSerialization<Guid>.ReadValue = null;
|
||||
UserNetworkVariableSerialization<Guid>.WriteValue = null;
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestManagedINetworkSerializableNetworkVariablesDeserializeInPlace()
|
||||
{
|
||||
var variable = new NetworkVariable<ManagedNetworkSerializableType>();
|
||||
variable.Value = new ManagedNetworkSerializableType
|
||||
{
|
||||
InMemoryValue = 1,
|
||||
Ints = new[] { 2, 3, 4 },
|
||||
Str = "five"
|
||||
};
|
||||
|
||||
using var writer = new FastBufferWriter(1024, Allocator.Temp);
|
||||
variable.WriteField(writer);
|
||||
Assert.AreEqual(1, variable.Value.InMemoryValue);
|
||||
Assert.AreEqual(new[] { 2, 3, 4 }, variable.Value.Ints);
|
||||
Assert.AreEqual("five", variable.Value.Str);
|
||||
variable.Value = new ManagedNetworkSerializableType
|
||||
{
|
||||
InMemoryValue = 10,
|
||||
Ints = new[] { 20, 30, 40, 50 },
|
||||
Str = "sixty"
|
||||
};
|
||||
|
||||
using var reader = new FastBufferReader(writer, Allocator.None);
|
||||
variable.ReadField(reader);
|
||||
Assert.AreEqual(10, variable.Value.InMemoryValue, "In-memory value was not the same - in-place deserialization should not change this");
|
||||
Assert.AreEqual(new[] { 2, 3, 4 }, variable.Value.Ints, "Ints were not correctly deserialized");
|
||||
Assert.AreEqual("five", variable.Value.Str, "Str was not correctly deserialized");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestUnmnagedINetworkSerializableNetworkVariablesDeserializeInPlace()
|
||||
{
|
||||
var variable = new NetworkVariable<UnmanagedNetworkSerializableType>();
|
||||
variable.Value = new UnmanagedNetworkSerializableType
|
||||
{
|
||||
InMemoryValue = 1,
|
||||
Int = 2,
|
||||
Str = "three"
|
||||
};
|
||||
using var writer = new FastBufferWriter(1024, Allocator.Temp);
|
||||
variable.WriteField(writer);
|
||||
Assert.AreEqual(1, variable.Value.InMemoryValue);
|
||||
Assert.AreEqual(2, variable.Value.Int);
|
||||
Assert.AreEqual("three", variable.Value.Str);
|
||||
variable.Value = new UnmanagedNetworkSerializableType
|
||||
{
|
||||
InMemoryValue = 10,
|
||||
Int = 20,
|
||||
Str = "thirty"
|
||||
};
|
||||
|
||||
using var reader = new FastBufferReader(writer, Allocator.None);
|
||||
variable.ReadField(reader);
|
||||
Assert.AreEqual(10, variable.Value.InMemoryValue, "In-memory value was not the same - in-place deserialization should not change this");
|
||||
Assert.AreEqual(2, variable.Value.Int, "Int was not correctly deserialized");
|
||||
Assert.AreEqual("three", variable.Value.Str, "Str was not correctly deserialized");
|
||||
}
|
||||
#endregion
|
||||
|
||||
private float m_OriginalTimeScale = 1.0f;
|
||||
|
||||
protected override IEnumerator OnSetup()
|
||||
{
|
||||
m_OriginalTimeScale = Time.timeScale;
|
||||
yield return null;
|
||||
}
|
||||
|
||||
protected override IEnumerator OnTearDown()
|
||||
{
|
||||
Time.timeScale = m_OriginalTimeScale;
|
||||
|
||||
m_NetworkListPredicateHandler = null;
|
||||
yield return base.OnTearDown();
|
||||
}
|
||||
@@ -818,8 +1259,8 @@ namespace Unity.Netcode.RuntimeTests
|
||||
/// <returns></returns>
|
||||
private string ConditionFailedInfo()
|
||||
{
|
||||
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" +
|
||||
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";
|
||||
}
|
||||
|
||||
|
||||
209
Tests/Runtime/OwnerPermissionTests.cs
Normal file
209
Tests/Runtime/OwnerPermissionTests.cs
Normal file
@@ -0,0 +1,209 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.TestTools;
|
||||
using Unity.Netcode.TestHelpers.Runtime;
|
||||
|
||||
namespace Unity.Netcode.RuntimeTests
|
||||
{
|
||||
public class OwnerPermissionObject : NetworkBehaviour
|
||||
{
|
||||
// indexed by [object, machine]
|
||||
public static OwnerPermissionObject[,] Objects = new OwnerPermissionObject[3, 3];
|
||||
public static int CurrentlySpawning = 0;
|
||||
|
||||
public static List<OwnerPermissionObject> ClientTargetedNetworkObjects = new List<OwnerPermissionObject>();
|
||||
// a client-owned NetworkVariable
|
||||
public NetworkVariable<int> MyNetworkVariableOwner;
|
||||
// a server-owned NetworkVariable
|
||||
public NetworkVariable<int> MyNetworkVariableServer;
|
||||
|
||||
// a client-owned NetworkVariable
|
||||
public NetworkList<int> MyNetworkListOwner;
|
||||
// a server-owned NetworkVariable
|
||||
public NetworkList<int> MyNetworkListServer;
|
||||
|
||||
// verifies two lists are identical
|
||||
public static void CheckLists(NetworkList<int> listA, NetworkList<int> listB)
|
||||
{
|
||||
Debug.Assert(listA.Count == listB.Count);
|
||||
for (var i = 0; i < listA.Count; i++)
|
||||
{
|
||||
Debug.Assert(listA[i] == listB[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// verifies all objects have consistent lists on all clients
|
||||
public static void VerifyConsistency()
|
||||
{
|
||||
for (var objectIndex = 0; objectIndex < 3; objectIndex++)
|
||||
{
|
||||
CheckLists(Objects[objectIndex, 0].MyNetworkListOwner, Objects[objectIndex, 1].MyNetworkListOwner);
|
||||
CheckLists(Objects[objectIndex, 0].MyNetworkListOwner, Objects[objectIndex, 2].MyNetworkListOwner);
|
||||
|
||||
CheckLists(Objects[objectIndex, 0].MyNetworkListServer, Objects[objectIndex, 1].MyNetworkListServer);
|
||||
CheckLists(Objects[objectIndex, 0].MyNetworkListServer, Objects[objectIndex, 2].MyNetworkListServer);
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnNetworkSpawn()
|
||||
{
|
||||
Objects[CurrentlySpawning, NetworkManager.LocalClientId] = GetComponent<OwnerPermissionObject>();
|
||||
Debug.Log($"Object index ({CurrentlySpawning}) spawned on client {NetworkManager.LocalClientId}");
|
||||
}
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
MyNetworkVariableOwner = new NetworkVariable<int>(writePerm: NetworkVariableWritePermission.Owner);
|
||||
MyNetworkVariableOwner.OnValueChanged += OwnerChanged;
|
||||
|
||||
MyNetworkVariableServer = new NetworkVariable<int>(writePerm: NetworkVariableWritePermission.Server);
|
||||
MyNetworkVariableServer.OnValueChanged += ServerChanged;
|
||||
|
||||
MyNetworkListOwner = new NetworkList<int>(writePerm: NetworkVariableWritePermission.Owner);
|
||||
MyNetworkListOwner.OnListChanged += ListOwnerChanged;
|
||||
|
||||
MyNetworkListServer = new NetworkList<int>(writePerm: NetworkVariableWritePermission.Server);
|
||||
MyNetworkListServer.OnListChanged += ListServerChanged;
|
||||
}
|
||||
|
||||
public void OwnerChanged(int before, int after)
|
||||
{
|
||||
}
|
||||
|
||||
public void ServerChanged(int before, int after)
|
||||
{
|
||||
}
|
||||
|
||||
public void ListOwnerChanged(NetworkListEvent<int> listEvent)
|
||||
{
|
||||
}
|
||||
|
||||
public void ListServerChanged(NetworkListEvent<int> listEvent)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public class OwnerPermissionHideTests : NetcodeIntegrationTest
|
||||
{
|
||||
protected override int NumberOfClients => 2;
|
||||
|
||||
private GameObject m_PrefabToSpawn;
|
||||
|
||||
protected override void OnServerAndClientsCreated()
|
||||
{
|
||||
m_PrefabToSpawn = CreateNetworkObjectPrefab("OwnerPermissionObject");
|
||||
m_PrefabToSpawn.AddComponent<OwnerPermissionObject>();
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator OwnerPermissionTest()
|
||||
{
|
||||
// create 3 objects
|
||||
for (var objectIndex = 0; objectIndex < 3; objectIndex++)
|
||||
{
|
||||
OwnerPermissionObject.CurrentlySpawning = objectIndex;
|
||||
|
||||
NetworkManager ownerManager = m_ServerNetworkManager;
|
||||
if (objectIndex != 0)
|
||||
{
|
||||
ownerManager = m_ClientNetworkManagers[objectIndex - 1];
|
||||
}
|
||||
SpawnObject(m_PrefabToSpawn, ownerManager);
|
||||
|
||||
// wait for each object to spawn on each client
|
||||
for (var clientIndex = 0; clientIndex < 3; clientIndex++)
|
||||
{
|
||||
while (OwnerPermissionObject.Objects[objectIndex, clientIndex] == null)
|
||||
{
|
||||
yield return new WaitForSeconds(0.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var nextValueToWrite = 1;
|
||||
var serverIndex = 0;
|
||||
|
||||
for (var objectIndex = 0; objectIndex < 3; objectIndex++)
|
||||
{
|
||||
for (var clientWriting = 0; clientWriting < 3; clientWriting++)
|
||||
{
|
||||
// ==== Server-writable NetworkVariable ====
|
||||
var gotException = false;
|
||||
Debug.Log($"Writing to server-write variable on object {objectIndex} on client {clientWriting}");
|
||||
|
||||
try
|
||||
{
|
||||
nextValueToWrite++;
|
||||
OwnerPermissionObject.Objects[objectIndex, clientWriting].MyNetworkVariableServer.Value = nextValueToWrite;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
gotException = true;
|
||||
}
|
||||
|
||||
// Verify server-owned netvar can only be written by server
|
||||
Debug.Assert(gotException == (clientWriting != serverIndex));
|
||||
|
||||
// ==== Owner-writable NetworkVariable ====
|
||||
gotException = false;
|
||||
Debug.Log($"Writing to owner-write variable on object {objectIndex} on client {clientWriting}");
|
||||
|
||||
try
|
||||
{
|
||||
nextValueToWrite++;
|
||||
OwnerPermissionObject.Objects[objectIndex, clientWriting].MyNetworkVariableOwner.Value = nextValueToWrite;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
gotException = true;
|
||||
}
|
||||
|
||||
// Verify client-owned netvar can only be written by owner
|
||||
Debug.Assert(gotException == (clientWriting != objectIndex));
|
||||
|
||||
// ==== Server-writable NetworkList ====
|
||||
gotException = false;
|
||||
Debug.Log($"Writing to server-write list on object {objectIndex} on client {clientWriting}");
|
||||
|
||||
try
|
||||
{
|
||||
nextValueToWrite++;
|
||||
OwnerPermissionObject.Objects[objectIndex, clientWriting].MyNetworkListServer.Add(nextValueToWrite);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
gotException = true;
|
||||
}
|
||||
|
||||
// Verify server-owned networkList can only be written by server
|
||||
Debug.Assert(gotException == (clientWriting != serverIndex));
|
||||
|
||||
// ==== Owner-writable NetworkList ====
|
||||
gotException = false;
|
||||
Debug.Log($"Writing to owner-write list on object {objectIndex} on client {clientWriting}");
|
||||
|
||||
try
|
||||
{
|
||||
nextValueToWrite++;
|
||||
OwnerPermissionObject.Objects[objectIndex, clientWriting].MyNetworkListOwner.Add(nextValueToWrite);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
gotException = true;
|
||||
}
|
||||
|
||||
// Verify client-owned networkList can only be written by owner
|
||||
Debug.Assert(gotException == (clientWriting != objectIndex));
|
||||
|
||||
yield return NetcodeIntegrationTestHelpers.WaitForTicks(m_ServerNetworkManager, 5);
|
||||
yield return NetcodeIntegrationTestHelpers.WaitForTicks(m_ClientNetworkManagers[0], 5);
|
||||
yield return NetcodeIntegrationTestHelpers.WaitForTicks(m_ClientNetworkManagers[1], 5);
|
||||
|
||||
OwnerPermissionObject.VerifyConsistency();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Tests/Runtime/OwnerPermissionTests.cs.meta
Normal file
11
Tests/Runtime/OwnerPermissionTests.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 88c657dcbe9a2414ba551b60dab19acd
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -110,6 +110,32 @@ namespace Unity.Netcode.RuntimeTests
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestImplicitConversionToGameObject()
|
||||
{
|
||||
using var networkObjectContext = UnityObjectContext.CreateNetworkObject();
|
||||
networkObjectContext.Object.Spawn();
|
||||
|
||||
NetworkObjectReference outReference = networkObjectContext.Object.gameObject;
|
||||
|
||||
GameObject go = outReference;
|
||||
Assert.AreEqual(networkObjectContext.Object.gameObject, go);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestImplicitToGameObjectIsNullWhenNotFound()
|
||||
{
|
||||
using var networkObjectContext = UnityObjectContext.CreateNetworkObject();
|
||||
networkObjectContext.Object.Spawn();
|
||||
|
||||
NetworkObjectReference outReference = networkObjectContext.Object.gameObject;
|
||||
|
||||
networkObjectContext.Object.Despawn();
|
||||
Object.DestroyImmediate(networkObjectContext.Object.gameObject);
|
||||
|
||||
GameObject go = outReference;
|
||||
Assert.IsNull(go);
|
||||
}
|
||||
[Test]
|
||||
public void TestTryGet()
|
||||
{
|
||||
|
||||
3
Tests/Runtime/TestHelpers.meta
Normal file
3
Tests/Runtime/TestHelpers.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1f398e1797944b5db4d3aa473629f46e
|
||||
timeCreated: 1661800773
|
||||
101
Tests/Runtime/TestHelpers/MessageCatcher.cs
Normal file
101
Tests/Runtime/TestHelpers/MessageCatcher.cs
Normal file
@@ -0,0 +1,101 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Unity.Collections;
|
||||
|
||||
namespace Unity.Netcode.RuntimeTests
|
||||
{
|
||||
internal class MessageCatcher<TMessageType> : INetworkHooks where TMessageType : INetworkMessage
|
||||
{
|
||||
private NetworkManager m_OwnerNetworkManager;
|
||||
|
||||
public MessageCatcher(NetworkManager ownerNetworkManager)
|
||||
{
|
||||
m_OwnerNetworkManager = ownerNetworkManager;
|
||||
}
|
||||
|
||||
private struct TriggerData
|
||||
{
|
||||
public FastBufferReader Reader;
|
||||
public MessageHeader Header;
|
||||
public ulong SenderId;
|
||||
public float Timestamp;
|
||||
public int SerializedHeaderSize;
|
||||
}
|
||||
private readonly List<TriggerData> m_CaughtMessages = new List<TriggerData>();
|
||||
|
||||
public void ReleaseMessages()
|
||||
{
|
||||
|
||||
foreach (var caughtSpawn in m_CaughtMessages)
|
||||
{
|
||||
// Reader will be disposed within HandleMessage
|
||||
m_OwnerNetworkManager.MessagingSystem.HandleMessage(caughtSpawn.Header, caughtSpawn.Reader, caughtSpawn.SenderId, caughtSpawn.Timestamp, caughtSpawn.SerializedHeaderSize);
|
||||
}
|
||||
}
|
||||
|
||||
public int CaughtMessageCount => m_CaughtMessages.Count;
|
||||
|
||||
public void OnBeforeSendMessage<T>(ulong clientId, ref T message, NetworkDelivery delivery) where T : INetworkMessage
|
||||
{
|
||||
}
|
||||
|
||||
public void OnAfterSendMessage<T>(ulong clientId, ref T message, NetworkDelivery delivery, int messageSizeBytes) where T : INetworkMessage
|
||||
{
|
||||
}
|
||||
|
||||
public void OnBeforeReceiveMessage(ulong senderId, Type messageType, int messageSizeBytes)
|
||||
{
|
||||
}
|
||||
|
||||
public void OnAfterReceiveMessage(ulong senderId, Type messageType, int messageSizeBytes)
|
||||
{
|
||||
}
|
||||
|
||||
public void OnBeforeSendBatch(ulong clientId, int messageCount, int batchSizeInBytes, NetworkDelivery delivery)
|
||||
{
|
||||
}
|
||||
|
||||
public void OnAfterSendBatch(ulong clientId, int messageCount, int batchSizeInBytes, NetworkDelivery delivery)
|
||||
{
|
||||
}
|
||||
|
||||
public void OnBeforeReceiveBatch(ulong senderId, int messageCount, int batchSizeInBytes)
|
||||
{
|
||||
}
|
||||
|
||||
public void OnAfterReceiveBatch(ulong senderId, int messageCount, int batchSizeInBytes)
|
||||
{
|
||||
}
|
||||
|
||||
public bool OnVerifyCanSend(ulong destinationId, Type messageType, NetworkDelivery delivery)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool OnVerifyCanReceive(ulong senderId, Type messageType, FastBufferReader messageContent, ref NetworkContext context)
|
||||
{
|
||||
if (messageType == typeof(TMessageType))
|
||||
{
|
||||
m_CaughtMessages.Add(new TriggerData
|
||||
{
|
||||
Reader = new FastBufferReader(messageContent, Allocator.Persistent),
|
||||
Header = context.Header,
|
||||
Timestamp = context.Timestamp,
|
||||
SenderId = context.SenderId,
|
||||
SerializedHeaderSize = context.SerializedHeaderSize
|
||||
});
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void OnBeforeHandleMessage<T>(ref T message, ref NetworkContext context) where T : INetworkMessage
|
||||
{
|
||||
}
|
||||
|
||||
public void OnAfterHandleMessage<T>(ref T message, ref NetworkContext context) where T : INetworkMessage
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
3
Tests/Runtime/TestHelpers/MessageCatcher.cs.meta
Normal file
3
Tests/Runtime/TestHelpers/MessageCatcher.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f008d074bcb841ae90b1949f9e2f0854
|
||||
timeCreated: 1661796973
|
||||
69
Tests/Runtime/TestHelpers/MessageLogger.cs
Normal file
69
Tests/Runtime/TestHelpers/MessageLogger.cs
Normal file
@@ -0,0 +1,69 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Unity.Netcode.RuntimeTests
|
||||
{
|
||||
internal class MessageLogger : INetworkHooks
|
||||
{
|
||||
private NetworkManager m_OwningNetworkManager;
|
||||
public MessageLogger(NetworkManager owningNetworkManager)
|
||||
{
|
||||
m_OwningNetworkManager = owningNetworkManager;
|
||||
}
|
||||
|
||||
public void OnBeforeSendMessage<T>(ulong clientId, ref T message, NetworkDelivery delivery) where T : INetworkMessage
|
||||
{
|
||||
Debug.Log($"{(m_OwningNetworkManager.IsServer ? "Server" : "Client")} {m_OwningNetworkManager.LocalClientId}: Sending {message.GetType().FullName} to {clientId} with {delivery}");
|
||||
}
|
||||
|
||||
public void OnAfterSendMessage<T>(ulong clientId, ref T message, NetworkDelivery delivery, int messageSizeBytes) where T : INetworkMessage
|
||||
{
|
||||
}
|
||||
|
||||
public void OnBeforeReceiveMessage(ulong senderId, Type messageType, int messageSizeBytes)
|
||||
{
|
||||
Debug.Log($"{(m_OwningNetworkManager.IsServer ? "Server" : "Client")} {m_OwningNetworkManager.LocalClientId}: Receiving {messageType.FullName} from {senderId}");
|
||||
}
|
||||
|
||||
public void OnAfterReceiveMessage(ulong senderId, Type messageType, int messageSizeBytes)
|
||||
{
|
||||
}
|
||||
|
||||
public void OnBeforeSendBatch(ulong clientId, int messageCount, int batchSizeInBytes, NetworkDelivery delivery)
|
||||
{
|
||||
Debug.Log($"{(m_OwningNetworkManager.IsServer ? "Server" : "Client")} {m_OwningNetworkManager.LocalClientId}: Sending a batch of to {clientId}: {messageCount} messages, {batchSizeInBytes} bytes, with {delivery}");
|
||||
}
|
||||
|
||||
public void OnAfterSendBatch(ulong clientId, int messageCount, int batchSizeInBytes, NetworkDelivery delivery)
|
||||
{
|
||||
}
|
||||
|
||||
public void OnBeforeReceiveBatch(ulong senderId, int messageCount, int batchSizeInBytes)
|
||||
{
|
||||
Debug.Log($"{(m_OwningNetworkManager.IsServer ? "Server" : "Client")} {m_OwningNetworkManager.LocalClientId}: Received a batch from {senderId}, {messageCount} messages, {batchSizeInBytes} bytes");
|
||||
}
|
||||
|
||||
public void OnAfterReceiveBatch(ulong senderId, int messageCount, int batchSizeInBytes)
|
||||
{
|
||||
}
|
||||
|
||||
public bool OnVerifyCanSend(ulong destinationId, Type messageType, NetworkDelivery delivery)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool OnVerifyCanReceive(ulong senderId, Type messageType, FastBufferReader messageContent, ref NetworkContext context)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public void OnBeforeHandleMessage<T>(ref T message, ref NetworkContext context) where T : INetworkMessage
|
||||
{
|
||||
Debug.Log($"{(m_OwningNetworkManager.IsServer ? "Server" : "Client")} {m_OwningNetworkManager.LocalClientId}: Handling message {message.GetType().FullName}");
|
||||
}
|
||||
|
||||
public void OnAfterHandleMessage<T>(ref T message, ref NetworkContext context) where T : INetworkMessage
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
3
Tests/Runtime/TestHelpers/MessageLogger.cs.meta
Normal file
3
Tests/Runtime/TestHelpers/MessageLogger.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4dbf404fdf544a409bf1bcab2c3f8b3e
|
||||
timeCreated: 1661799489
|
||||
@@ -1,6 +1,7 @@
|
||||
using System.Collections;
|
||||
using NUnit.Framework;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Assertions.Comparers;
|
||||
using UnityEngine.TestTools;
|
||||
using Unity.Netcode.TestHelpers.Runtime;
|
||||
|
||||
@@ -11,25 +12,45 @@ namespace Unity.Netcode.RuntimeTests
|
||||
/// </summary>
|
||||
public class NetworkTimeSystemTests
|
||||
{
|
||||
private MonoBehaviourTest<PlayerLoopTimeTestComponent> m_MonoBehaviourTest; // cache for teardown
|
||||
private MonoBehaviourTest<PlayerLoopFixedTimeTestComponent> m_PlayerLoopFixedTimeTestComponent; // cache for teardown
|
||||
private MonoBehaviourTest<PlayerLoopTimeTestComponent> m_PlayerLoopTimeTestComponent; // cache for teardown
|
||||
|
||||
private float m_OriginalTimeScale = 1.0f;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
m_OriginalTimeScale = Time.timeScale;
|
||||
|
||||
// Create, instantiate, and host
|
||||
Assert.IsTrue(NetworkManagerHelper.StartNetworkManager(out _));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tests whether time is accessible and has correct values inside Update/FixedUpdate.
|
||||
/// This test applies only when <see cref="Time.timeScale"> is 1.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[UnityTest]
|
||||
public IEnumerator PlayerLoopTimeTest()
|
||||
public IEnumerator PlayerLoopFixedTimeTest()
|
||||
{
|
||||
m_MonoBehaviourTest = new MonoBehaviourTest<PlayerLoopTimeTestComponent>();
|
||||
m_PlayerLoopFixedTimeTestComponent = new MonoBehaviourTest<PlayerLoopFixedTimeTestComponent>();
|
||||
|
||||
yield return m_MonoBehaviourTest;
|
||||
yield return m_PlayerLoopFixedTimeTestComponent;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tests whether time is accessible and has correct values inside Update, for multiples <see cref="Time.timeScale"/> values.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[UnityTest]
|
||||
public IEnumerator PlayerLoopTimeTest_WithDifferentTimeScale([Values(0.0f, 0.1f, 0.5f, 1.0f, 2.0f, 5.0f)] float timeScale)
|
||||
{
|
||||
Time.timeScale = timeScale;
|
||||
|
||||
m_PlayerLoopTimeTestComponent = new MonoBehaviourTest<PlayerLoopTimeTestComponent>();
|
||||
|
||||
yield return m_PlayerLoopTimeTestComponent;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -40,10 +61,10 @@ namespace Unity.Netcode.RuntimeTests
|
||||
[UnityTest]
|
||||
public IEnumerator CorrectAmountTicksTest()
|
||||
{
|
||||
var tickSystem = NetworkManager.Singleton.NetworkTickSystem;
|
||||
var delta = tickSystem.LocalTime.FixedDeltaTime;
|
||||
var previous_localTickCalculated = 0;
|
||||
var previous_serverTickCalculated = 0;
|
||||
NetworkTickSystem tickSystem = NetworkManager.Singleton.NetworkTickSystem;
|
||||
float delta = tickSystem.LocalTime.FixedDeltaTime;
|
||||
int previous_localTickCalculated = 0;
|
||||
int previous_serverTickCalculated = 0;
|
||||
|
||||
while (tickSystem.LocalTime.Time < 3f)
|
||||
{
|
||||
@@ -70,7 +91,7 @@ namespace Unity.Netcode.RuntimeTests
|
||||
|
||||
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}!");
|
||||
Assert.AreEqual((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}!", FloatComparer.s_ComparerWithDefaultTolerance);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,15 +101,23 @@ namespace Unity.Netcode.RuntimeTests
|
||||
// Stop, shutdown, and destroy
|
||||
NetworkManagerHelper.ShutdownNetworkManager();
|
||||
|
||||
if (m_MonoBehaviourTest != null)
|
||||
Time.timeScale = m_OriginalTimeScale;
|
||||
|
||||
if (m_PlayerLoopFixedTimeTestComponent != null)
|
||||
{
|
||||
Object.DestroyImmediate(m_MonoBehaviourTest.gameObject);
|
||||
Object.DestroyImmediate(m_PlayerLoopFixedTimeTestComponent.gameObject);
|
||||
m_PlayerLoopFixedTimeTestComponent = null;
|
||||
}
|
||||
|
||||
if (m_PlayerLoopTimeTestComponent != null)
|
||||
{
|
||||
Object.DestroyImmediate(m_PlayerLoopTimeTestComponent.gameObject);
|
||||
m_PlayerLoopTimeTestComponent = null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public class PlayerLoopTimeTestComponent : MonoBehaviour, IMonoBehaviourTest
|
||||
public class PlayerLoopFixedTimeTestComponent : MonoBehaviour, IMonoBehaviourTest
|
||||
{
|
||||
public const int Passes = 100;
|
||||
|
||||
@@ -101,7 +130,7 @@ namespace Unity.Netcode.RuntimeTests
|
||||
private NetworkTime m_ServerTimePreviousUpdate;
|
||||
private NetworkTime m_LocalTimePreviousFixedUpdate;
|
||||
|
||||
public void Start()
|
||||
private void Start()
|
||||
{
|
||||
// Run fixed update at same rate as network tick
|
||||
Time.fixedDeltaTime = NetworkManager.Singleton.LocalTime.FixedDeltaTime;
|
||||
@@ -110,23 +139,23 @@ namespace Unity.Netcode.RuntimeTests
|
||||
Time.maximumDeltaTime = float.MaxValue;
|
||||
}
|
||||
|
||||
public void Update()
|
||||
private void Update()
|
||||
{
|
||||
// This must run first else it wont run if there is an exception
|
||||
m_UpdatePasses++;
|
||||
|
||||
var localTime = NetworkManager.Singleton.LocalTime;
|
||||
var serverTime = NetworkManager.Singleton.ServerTime;
|
||||
NetworkTime localTime = NetworkManager.Singleton.LocalTime;
|
||||
NetworkTime serverTime = NetworkManager.Singleton.ServerTime;
|
||||
|
||||
// time should have advanced on the host/server
|
||||
Assert.True(m_LocalTimePreviousUpdate.Time < localTime.Time);
|
||||
Assert.True(m_ServerTimePreviousUpdate.Time < serverTime.Time);
|
||||
Assert.Less(m_LocalTimePreviousUpdate.Time, localTime.Time);
|
||||
Assert.Less(m_ServerTimePreviousUpdate.Time, serverTime.Time);
|
||||
|
||||
// time should be further then last fixed step in update
|
||||
Assert.True(m_LocalTimePreviousFixedUpdate.FixedTime < localTime.Time);
|
||||
Assert.Less(m_LocalTimePreviousFixedUpdate.FixedTime, localTime.Time);
|
||||
|
||||
// we should be in same or further tick then fixed update
|
||||
Assert.True(m_LocalTimePreviousFixedUpdate.Tick <= localTime.Tick);
|
||||
Assert.LessOrEqual(m_LocalTimePreviousFixedUpdate.Tick, localTime.Tick);
|
||||
|
||||
// fixed update should result in same amounts of tick as network time
|
||||
if (m_TickOffset == -1)
|
||||
@@ -135,26 +164,64 @@ namespace Unity.Netcode.RuntimeTests
|
||||
}
|
||||
else
|
||||
{
|
||||
// offset of 1 is ok, this happens due to different tick duration offsets
|
||||
Assert.True(Mathf.Abs(serverTime.Tick - m_TickOffset - m_LastFixedUpdateTick) <= 1);
|
||||
// offset of 1 is ok, this happens due to different tick duration offsets
|
||||
Assert.LessOrEqual(Mathf.Abs(serverTime.Tick - m_TickOffset - m_LastFixedUpdateTick), 1);
|
||||
}
|
||||
|
||||
m_LocalTimePreviousUpdate = localTime;
|
||||
m_ServerTimePreviousUpdate = serverTime;
|
||||
}
|
||||
|
||||
public void FixedUpdate()
|
||||
private void FixedUpdate()
|
||||
{
|
||||
var time = NetworkManager.Singleton.LocalTime;
|
||||
|
||||
m_LocalTimePreviousFixedUpdate = time;
|
||||
|
||||
Assert.AreEqual(Time.fixedDeltaTime, time.FixedDeltaTime);
|
||||
Assert.True(Mathf.Approximately((float)NetworkManager.Singleton.LocalTime.Time, (float)NetworkManager.Singleton.ServerTime.Time));
|
||||
m_LocalTimePreviousFixedUpdate = NetworkManager.Singleton.LocalTime;
|
||||
|
||||
Assert.AreEqual(Time.fixedDeltaTime, m_LocalTimePreviousFixedUpdate.FixedDeltaTime);
|
||||
Assert.AreEqual((float)NetworkManager.Singleton.LocalTime.Time, (float)NetworkManager.Singleton.ServerTime.Time, null, FloatComparer.s_ComparerWithDefaultTolerance);
|
||||
m_LastFixedUpdateTick++;
|
||||
}
|
||||
|
||||
public bool IsTestFinished => m_UpdatePasses >= Passes;
|
||||
}
|
||||
|
||||
public class PlayerLoopTimeTestComponent : MonoBehaviour, IMonoBehaviourTest
|
||||
{
|
||||
public const int Passes = 100;
|
||||
|
||||
private int m_UpdatePasses = 0;
|
||||
|
||||
private NetworkTime m_LocalTimePreviousUpdate;
|
||||
private NetworkTime m_ServerTimePreviousUpdate;
|
||||
private NetworkTime m_LocalTimePreviousFixedUpdate;
|
||||
|
||||
private void Update()
|
||||
{
|
||||
// This must run first else it wont run if there is an exception
|
||||
m_UpdatePasses++;
|
||||
|
||||
NetworkTime localTime = NetworkManager.Singleton.LocalTime;
|
||||
NetworkTime serverTime = NetworkManager.Singleton.ServerTime;
|
||||
|
||||
// time should have advanced on the host/server
|
||||
Assert.Less(m_LocalTimePreviousUpdate.Time, localTime.Time);
|
||||
Assert.Less(m_ServerTimePreviousUpdate.Time, serverTime.Time);
|
||||
|
||||
// time should be further then last fixed step in update
|
||||
Assert.Less(m_LocalTimePreviousFixedUpdate.FixedTime, localTime.Time);
|
||||
|
||||
// we should be in same or further tick then fixed update
|
||||
Assert.LessOrEqual(m_LocalTimePreviousFixedUpdate.Tick, localTime.Tick);
|
||||
|
||||
m_LocalTimePreviousUpdate = localTime;
|
||||
m_ServerTimePreviousUpdate = serverTime;
|
||||
}
|
||||
|
||||
private void FixedUpdate()
|
||||
{
|
||||
m_LocalTimePreviousFixedUpdate = NetworkManager.Singleton.LocalTime;
|
||||
}
|
||||
|
||||
public bool IsTestFinished => m_UpdatePasses >= Passes;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ namespace Unity.Netcode.RuntimeTests
|
||||
public class TransformInterpolationObject : NetworkBehaviour
|
||||
{
|
||||
// Set the minimum threshold which we will use as our margin of error
|
||||
public const float MinThreshold = 0.001f;
|
||||
public const float MinThreshold = 0.005f;
|
||||
|
||||
public bool CheckPosition;
|
||||
public bool IsMoving;
|
||||
@@ -24,7 +24,7 @@ namespace Unity.Netcode.RuntimeTests
|
||||
{
|
||||
if (transform.position.y < -MinThreshold || transform.position.y > 100.0f + MinThreshold)
|
||||
{
|
||||
Debug.LogError($"Interpolation failure. transform.position.y is {transform.position.y}. Should be between 0.0 and 100.0");
|
||||
Debug.LogError($"Interpolation failure. transform.position.y is {transform.position.y}. Should be between 0.0 and 100.0. Current threshold is [+/- {MinThreshold}].");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -65,7 +65,11 @@ namespace Unity.Netcode.RuntimeTests
|
||||
|
||||
public void Connect()
|
||||
{
|
||||
#if UTP_TRANSPORT_2_0_ABOVE
|
||||
var endpoint = NetworkEndpoint.LoopbackIpv4;
|
||||
#else
|
||||
var endpoint = NetworkEndPoint.LoopbackIpv4;
|
||||
#endif
|
||||
endpoint.Port = 7777;
|
||||
|
||||
m_Connection = m_Driver.Connect(endpoint);
|
||||
|
||||
@@ -3,6 +3,7 @@ using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using Unity.Netcode.Transports.UTP;
|
||||
using Unity.Networking.Transport;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Unity.Netcode.RuntimeTests
|
||||
@@ -36,14 +37,23 @@ namespace Unity.Netcode.RuntimeTests
|
||||
}
|
||||
|
||||
// Common code to initialize a UnityTransport that logs its events.
|
||||
public static void InitializeTransport(out UnityTransport transport, out List<TransportEvent> events, int maxPayloadSize = UnityTransport.InitialMaxPayloadSize)
|
||||
public static void InitializeTransport(out UnityTransport transport, out List<TransportEvent> events,
|
||||
int maxPayloadSize = UnityTransport.InitialMaxPayloadSize, int maxSendQueueSize = 0, NetworkFamily family = NetworkFamily.Ipv4)
|
||||
{
|
||||
var logger = new TransportEventLogger();
|
||||
events = logger.Events;
|
||||
|
||||
transport = new GameObject().AddComponent<UnityTransport>();
|
||||
|
||||
transport.OnTransportEvent += logger.HandleEvent;
|
||||
transport.SetMaxPayloadSize(maxPayloadSize);
|
||||
transport.MaxPayloadSize = maxPayloadSize;
|
||||
transport.MaxSendQueueSize = maxSendQueueSize;
|
||||
|
||||
if (family == NetworkFamily.Ipv6)
|
||||
{
|
||||
transport.SetConnectionData("::1", 7777);
|
||||
}
|
||||
|
||||
transport.Initialize();
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Unity.Netcode.Transports.UTP;
|
||||
using Unity.Networking.Transport;
|
||||
using UnityEngine;
|
||||
using UnityEngine.TestTools;
|
||||
using static Unity.Netcode.RuntimeTests.UnityTransportTestHelpers;
|
||||
@@ -21,6 +22,15 @@ namespace Unity.Netcode.RuntimeTests
|
||||
NetworkDelivery.Reliable
|
||||
};
|
||||
|
||||
private static readonly NetworkFamily[] k_NetworkFamiltyParameters =
|
||||
{
|
||||
NetworkFamily.Ipv4,
|
||||
#if !(UNITY_SWITCH || UNITY_PS4 || UNITY_PS5)
|
||||
// IPv6 is not supported on Switch, PS4, and PS5.
|
||||
NetworkFamily.Ipv6
|
||||
#endif
|
||||
};
|
||||
|
||||
private UnityTransport m_Server, m_Client1, m_Client2;
|
||||
private List<TransportEvent> m_ServerEvents, m_Client1Events, m_Client2Events;
|
||||
|
||||
@@ -60,10 +70,12 @@ namespace Unity.Netcode.RuntimeTests
|
||||
|
||||
// Check if can make a simple data exchange.
|
||||
[UnityTest]
|
||||
public IEnumerator PingPong([ValueSource("k_DeliveryParameters")] NetworkDelivery delivery)
|
||||
public IEnumerator PingPong(
|
||||
[ValueSource("k_DeliveryParameters")] NetworkDelivery delivery,
|
||||
[ValueSource("k_NetworkFamiltyParameters")] NetworkFamily family)
|
||||
{
|
||||
InitializeTransport(out m_Server, out m_ServerEvents);
|
||||
InitializeTransport(out m_Client1, out m_Client1Events);
|
||||
InitializeTransport(out m_Server, out m_ServerEvents, family: family);
|
||||
InitializeTransport(out m_Client1, out m_Client1Events, family: family);
|
||||
|
||||
m_Server.StartServer();
|
||||
m_Client1.StartClient();
|
||||
@@ -89,10 +101,12 @@ namespace Unity.Netcode.RuntimeTests
|
||||
|
||||
// Check if can make a simple data exchange (both ways at a time).
|
||||
[UnityTest]
|
||||
public IEnumerator PingPongSimultaneous([ValueSource("k_DeliveryParameters")] NetworkDelivery delivery)
|
||||
public IEnumerator PingPongSimultaneous(
|
||||
[ValueSource("k_DeliveryParameters")] NetworkDelivery delivery,
|
||||
[ValueSource("k_NetworkFamiltyParameters")] NetworkFamily family)
|
||||
{
|
||||
InitializeTransport(out m_Server, out m_ServerEvents);
|
||||
InitializeTransport(out m_Client1, out m_Client1Events);
|
||||
InitializeTransport(out m_Server, out m_ServerEvents, family: family);
|
||||
InitializeTransport(out m_Client1, out m_Client1Events, family: family);
|
||||
|
||||
m_Server.StartServer();
|
||||
m_Client1.StartClient();
|
||||
@@ -126,13 +140,15 @@ namespace Unity.Netcode.RuntimeTests
|
||||
// loopback traffic are too small for the amount of data sent in a single update here.
|
||||
[UnityTest]
|
||||
[UnityPlatform(exclude = new[] { RuntimePlatform.Switch, RuntimePlatform.PS4, RuntimePlatform.PS5 })]
|
||||
public IEnumerator SendMaximumPayloadSize([ValueSource("k_DeliveryParameters")] NetworkDelivery delivery)
|
||||
public IEnumerator SendMaximumPayloadSize(
|
||||
[ValueSource("k_DeliveryParameters")] NetworkDelivery delivery,
|
||||
[ValueSource("k_NetworkFamiltyParameters")] NetworkFamily family)
|
||||
{
|
||||
// We want something that's over the old limit of ~44KB for reliable payloads.
|
||||
var payloadSize = 64 * 1024;
|
||||
|
||||
InitializeTransport(out m_Server, out m_ServerEvents, payloadSize);
|
||||
InitializeTransport(out m_Client1, out m_Client1Events, payloadSize);
|
||||
InitializeTransport(out m_Server, out m_ServerEvents, payloadSize, family: family);
|
||||
InitializeTransport(out m_Client1, out m_Client1Events, payloadSize, family: family);
|
||||
|
||||
m_Server.StartServer();
|
||||
m_Client1.StartClient();
|
||||
@@ -164,10 +180,12 @@ namespace Unity.Netcode.RuntimeTests
|
||||
|
||||
// Check making multiple sends to a client in a single frame.
|
||||
[UnityTest]
|
||||
public IEnumerator MultipleSendsSingleFrame([ValueSource("k_DeliveryParameters")] NetworkDelivery delivery)
|
||||
public IEnumerator MultipleSendsSingleFrame(
|
||||
[ValueSource("k_DeliveryParameters")] NetworkDelivery delivery,
|
||||
[ValueSource("k_NetworkFamiltyParameters")] NetworkFamily family)
|
||||
{
|
||||
InitializeTransport(out m_Server, out m_ServerEvents);
|
||||
InitializeTransport(out m_Client1, out m_Client1Events);
|
||||
InitializeTransport(out m_Server, out m_ServerEvents, family: family);
|
||||
InitializeTransport(out m_Client1, out m_Client1Events, family: family);
|
||||
|
||||
m_Server.StartServer();
|
||||
m_Client1.StartClient();
|
||||
@@ -193,11 +211,13 @@ namespace Unity.Netcode.RuntimeTests
|
||||
|
||||
// Check sending data to multiple clients.
|
||||
[UnityTest]
|
||||
public IEnumerator SendMultipleClients([ValueSource("k_DeliveryParameters")] NetworkDelivery delivery)
|
||||
public IEnumerator SendMultipleClients(
|
||||
[ValueSource("k_DeliveryParameters")] NetworkDelivery delivery,
|
||||
[ValueSource("k_NetworkFamiltyParameters")] NetworkFamily family)
|
||||
{
|
||||
InitializeTransport(out m_Server, out m_ServerEvents);
|
||||
InitializeTransport(out m_Client1, out m_Client1Events);
|
||||
InitializeTransport(out m_Client2, out m_Client2Events);
|
||||
InitializeTransport(out m_Server, out m_ServerEvents, family: family);
|
||||
InitializeTransport(out m_Client1, out m_Client1Events, family: family);
|
||||
InitializeTransport(out m_Client2, out m_Client2Events, family: family);
|
||||
|
||||
m_Server.StartServer();
|
||||
m_Client1.StartClient();
|
||||
@@ -234,11 +254,13 @@ namespace Unity.Netcode.RuntimeTests
|
||||
|
||||
// Check receiving data from multiple clients.
|
||||
[UnityTest]
|
||||
public IEnumerator ReceiveMultipleClients([ValueSource("k_DeliveryParameters")] NetworkDelivery delivery)
|
||||
public IEnumerator ReceiveMultipleClients(
|
||||
[ValueSource("k_DeliveryParameters")] NetworkDelivery delivery,
|
||||
[ValueSource("k_NetworkFamiltyParameters")] NetworkFamily family)
|
||||
{
|
||||
InitializeTransport(out m_Server, out m_ServerEvents);
|
||||
InitializeTransport(out m_Client1, out m_Client1Events);
|
||||
InitializeTransport(out m_Client2, out m_Client2Events);
|
||||
InitializeTransport(out m_Server, out m_ServerEvents, family: family);
|
||||
InitializeTransport(out m_Client1, out m_Client1Events, family: family);
|
||||
InitializeTransport(out m_Client2, out m_Client2Events, family: family);
|
||||
|
||||
m_Server.StartServer();
|
||||
m_Client1.StartClient();
|
||||
@@ -273,8 +295,10 @@ namespace Unity.Netcode.RuntimeTests
|
||||
[UnityTest]
|
||||
public IEnumerator DisconnectOnReliableSendQueueOverflow()
|
||||
{
|
||||
InitializeTransport(out m_Server, out m_ServerEvents);
|
||||
InitializeTransport(out m_Client1, out m_Client1Events);
|
||||
const int maxSendQueueSize = 16 * 1024;
|
||||
|
||||
InitializeTransport(out m_Server, out m_ServerEvents, maxSendQueueSize: maxSendQueueSize);
|
||||
InitializeTransport(out m_Client1, out m_Client1Events, maxSendQueueSize: maxSendQueueSize);
|
||||
|
||||
m_Server.StartServer();
|
||||
m_Client1.StartClient();
|
||||
@@ -283,7 +307,7 @@ namespace Unity.Netcode.RuntimeTests
|
||||
|
||||
m_Server.Shutdown();
|
||||
|
||||
var numSends = (UnityTransport.InitialMaxSendQueueSize / 1024);
|
||||
var numSends = (maxSendQueueSize / 1024);
|
||||
|
||||
for (int i = 0; i < numSends; i++)
|
||||
{
|
||||
@@ -292,8 +316,7 @@ namespace Unity.Netcode.RuntimeTests
|
||||
}
|
||||
|
||||
LogAssert.Expect(LogType.Error, "Couldn't add payload of size 1024 to reliable send queue. " +
|
||||
$"Closing connection {m_Client1.ServerClientId} as reliability guarantees can't be maintained. " +
|
||||
$"Perhaps 'Max Send Queue Size' ({UnityTransport.InitialMaxSendQueueSize}) is too small for workload.");
|
||||
$"Closing connection {m_Client1.ServerClientId} as reliability guarantees can't be maintained.");
|
||||
|
||||
Assert.AreEqual(2, m_Client1Events.Count);
|
||||
Assert.AreEqual(NetworkEvent.Disconnect, m_Client1Events[1].Type);
|
||||
@@ -308,15 +331,17 @@ namespace Unity.Netcode.RuntimeTests
|
||||
[UnityPlatform(exclude = new[] { RuntimePlatform.Switch, RuntimePlatform.PS4, RuntimePlatform.PS5 })]
|
||||
public IEnumerator SendCompletesOnUnreliableSendQueueOverflow()
|
||||
{
|
||||
InitializeTransport(out m_Server, out m_ServerEvents);
|
||||
InitializeTransport(out m_Client1, out m_Client1Events);
|
||||
const int maxSendQueueSize = 16 * 1024;
|
||||
|
||||
InitializeTransport(out m_Server, out m_ServerEvents, maxSendQueueSize: maxSendQueueSize);
|
||||
InitializeTransport(out m_Client1, out m_Client1Events, maxSendQueueSize: maxSendQueueSize);
|
||||
|
||||
m_Server.StartServer();
|
||||
m_Client1.StartClient();
|
||||
|
||||
yield return WaitForNetworkEvent(NetworkEvent.Connect, m_Client1Events);
|
||||
|
||||
var numSends = (UnityTransport.InitialMaxSendQueueSize / 1024) + 1;
|
||||
var numSends = (maxSendQueueSize / 1024) + 1;
|
||||
|
||||
for (int i = 0; i < numSends; i++)
|
||||
{
|
||||
@@ -340,6 +365,7 @@ namespace Unity.Netcode.RuntimeTests
|
||||
yield return null;
|
||||
}
|
||||
|
||||
#if !UTP_TRANSPORT_2_0_ABOVE
|
||||
// Check that simulator parameters are effective. We only check with the drop rate, because
|
||||
// that's easy to check and we only really want to make sure the simulator parameters are
|
||||
// configured properly (the simulator pipeline stage is already well-tested in UTP).
|
||||
@@ -394,6 +420,7 @@ namespace Unity.Netcode.RuntimeTests
|
||||
|
||||
yield return null;
|
||||
}
|
||||
#endif
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator SendQueuesFlushedOnShutdown([ValueSource("k_DeliveryParameters")] NetworkDelivery delivery)
|
||||
|
||||
@@ -39,6 +39,11 @@
|
||||
"name": "com.unity.modules.physics",
|
||||
"expression": "",
|
||||
"define": "COM_UNITY_MODULES_PHYSICS"
|
||||
},
|
||||
{
|
||||
"name": "com.unity.transport",
|
||||
"expression": "2.0.0-exp",
|
||||
"define": "UTP_TRANSPORT_2_0_ABOVE"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user