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

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

Additional documentation and release notes are available at [Multiplayer Documentation](https://docs-multiplayer.unity3d.com).

## [1.0.0-pre.8] - 2022-04-27

### Changed

- `unmanaged` structs are no longer universally accepted as RPC parameters because some structs (i.e., structs with pointers in them, such as `NativeList<T>`) can't be supported by the default memcpy struct serializer. Structs that are intended to be serialized across the network must add `INetworkSerializeByMemcpy` to the interface list (i.e., `struct Foo : INetworkSerializeByMemcpy`). This interface is empty and just serves to mark the struct as compatible with memcpy serialization. For external structs you can't edit, you can pass them to RPCs by wrapping them in `ForceNetworkSerializeByMemcpy<T>`. (#1901)

### Removed
- Removed `SIPTransport` (#1870)

- Removed `ClientNetworkTransform` from the package samples and moved to Boss Room's Utilities package which can be found [here](https://github.com/Unity-Technologies/com.unity.multiplayer.samples.coop/blob/main/Packages/com.unity.multiplayer.samples.coop/Utilities/Net/ClientAuthority/ClientNetworkTransform.cs).

### Fixed

- Fixed `NetworkTransform` generating false positive rotation delta checks when rolling over between 0 and 360 degrees. (#1890)
- Fixed client throwing an exception if it has messages in the outbound queue when processing the `NetworkEvent.Disconnect` event and is using UTP. (#1884)
- Fixed issue during client synchronization if 'ValidateSceneBeforeLoading' returned false it would halt the client synchronization process resulting in a client that was approved but not synchronized or fully connected with the server. (#1883)
- Fixed an issue where UNetTransport.StartServer would return success even if the underlying transport failed to start (#854)
- Passing generic types to RPCs no longer causes a native crash (#1901)
- Fixed an issue where calling `Shutdown` on a `NetworkManager` that was already shut down would cause an immediate shutdown the next time it was started (basically the fix makes `Shutdown` idempotent). (#1877)
This commit is contained in:
Unity Technologies
2022-04-27 00:00:00 +00:00
parent 60e2dabef4
commit add668dfd2
119 changed files with 4434 additions and 1801 deletions

View File

@@ -340,8 +340,8 @@ MonoBehaviour:
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 593a2fe42fa9d37498c96f9a383b6521, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Name:
m_EditorClassIdentifier:
DontDestroy: 1
RunInBackground: 1
LogLevel: 1
@@ -356,7 +356,7 @@ MonoBehaviour:
TickRate: 30
ClientConnectionBufferTimeout: 10
ConnectionApproval: 0
ConnectionData:
ConnectionData:
EnableTimeResync: 0
TimeResyncInterval: 30
EnableNetworkVariable: 1
@@ -367,5 +367,5 @@ MonoBehaviour:
NetworkIdRecycleDelay: 120
RpcHashSize: 0
LoadSceneTimeOut: 120
MessageBufferTimeout: 20
SpawnTimeout: 20
EnableNetworkLogs: 1

View File

@@ -4,6 +4,7 @@ using NUnit.Framework;
using UnityEditor;
using UnityEditor.Build.Reporting;
using UnityEngine;
using UnityEngine.TestTools;
namespace Unity.Netcode.EditorTests
{
@@ -16,13 +17,25 @@ namespace Unity.Netcode.EditorTests
{
var execAssembly = Assembly.GetExecutingAssembly();
var packagePath = UnityEditor.PackageManager.PackageInfo.FindForAssembly(execAssembly).assetPath;
var buildTarget = EditorUserBuildSettings.activeBuildTarget;
var buildTargetGroup = BuildPipeline.GetBuildTargetGroup(buildTarget);
var buildTargetSupported = BuildPipeline.IsBuildTargetSupported(buildTargetGroup, buildTarget);
var buildReport = BuildPipeline.BuildPlayer(
new[] { Path.Combine(packagePath, DefaultBuildScenePath) },
Path.Combine(Path.GetDirectoryName(Application.dataPath), "Builds", nameof(BuildTests)),
EditorUserBuildSettings.activeBuildTarget,
buildTarget,
BuildOptions.None
);
Assert.AreEqual(BuildResult.Succeeded, buildReport.summary.result);
if (buildTargetSupported)
{
Assert.AreEqual(BuildResult.Succeeded, buildReport.summary.result);
}
else
{
LogAssert.Expect(LogType.Error, "Error building player because build target was unsupported");
}
}
}
}

View File

@@ -9,7 +9,7 @@ namespace Unity.Netcode.EditorTests
{
public class MessageReceivingTests
{
private struct TestMessage : INetworkMessage
private struct TestMessage : INetworkMessage, INetworkSerializeByMemcpy
{
public int A;
public int B;

View File

@@ -5,7 +5,7 @@ namespace Unity.Netcode.EditorTests
{
public class MessageRegistrationTests
{
private struct TestMessageOne : INetworkMessage
private struct TestMessageOne : INetworkMessage, INetworkSerializeByMemcpy
{
public int A;
public int B;
@@ -25,7 +25,7 @@ namespace Unity.Netcode.EditorTests
}
}
private struct TestMessageTwo : INetworkMessage
private struct TestMessageTwo : INetworkMessage, INetworkSerializeByMemcpy
{
public int A;
public int B;
@@ -64,7 +64,7 @@ namespace Unity.Netcode.EditorTests
}
}
private struct TestMessageThree : INetworkMessage
private struct TestMessageThree : INetworkMessage, INetworkSerializeByMemcpy
{
public int A;
public int B;
@@ -97,7 +97,7 @@ namespace Unity.Netcode.EditorTests
};
}
}
private struct TestMessageFour : INetworkMessage
private struct TestMessageFour : INetworkMessage, INetworkSerializeByMemcpy
{
public int A;
public int B;
@@ -173,8 +173,6 @@ namespace Unity.Netcode.EditorTests
MessagingSystem.MessageHandler handlerThree = MessagingSystem.ReceiveMessage<TestMessageThree>;
MessagingSystem.MessageHandler handlerFour = MessagingSystem.ReceiveMessage<TestMessageFour>;
var foundHandlerOne = systemOne.MessageHandlers[systemOne.GetMessageType(typeof(TestMessageOne))];
Assert.AreEqual(handlerOne, systemOne.MessageHandlers[systemOne.GetMessageType(typeof(TestMessageOne))]);
Assert.AreEqual(handlerTwo, systemOne.MessageHandlers[systemOne.GetMessageType(typeof(TestMessageTwo))]);
Assert.AreEqual(handlerThree, systemTwo.MessageHandlers[systemTwo.GetMessageType(typeof(TestMessageThree))]);

View File

@@ -8,7 +8,7 @@ namespace Unity.Netcode.EditorTests
{
public class MessageSendingTests
{
private struct TestMessage : INetworkMessage
private struct TestMessage : INetworkMessage, INetworkSerializeByMemcpy
{
public int A;
public int B;

View File

@@ -58,7 +58,7 @@ namespace Unity.Netcode.EditorTests
C
};
protected struct TestStruct
protected struct TestStruct : INetworkSerializeByMemcpy
{
public byte A;
public short B;
@@ -80,7 +80,6 @@ namespace Unity.Netcode.EditorTests
}
#endregion
protected abstract void RunTypeTest<T>(T valueToTest) where T : unmanaged;
protected abstract void RunTypeTestSafe<T>(T valueToTest) where T : unmanaged;
@@ -114,143 +113,144 @@ namespace Unity.Netcode.EditorTests
#endregion
private void RunTestWithWriteType<T>(T val, WriteType wt, FastBufferWriter.ForPrimitives _ = default) where T : unmanaged
{
switch (wt)
{
case WriteType.WriteDirect:
RunTypeTest(val);
break;
case WriteType.WriteSafe:
RunTypeTestSafe(val);
break;
}
}
public void BaseTypeTest(Type testType, WriteType writeType)
{
var random = new Random();
void RunTypeTestLocal<T>(T val, WriteType wt) where T : unmanaged
{
switch (wt)
{
case WriteType.WriteDirect:
RunTypeTest(val);
break;
case WriteType.WriteSafe:
RunTypeTestSafe(val);
break;
}
}
if (testType == typeof(byte))
{
RunTypeTestLocal((byte)random.Next(), writeType);
RunTestWithWriteType((byte)random.Next(), writeType);
}
else if (testType == typeof(sbyte))
{
RunTypeTestLocal((sbyte)random.Next(), writeType);
RunTestWithWriteType((sbyte)random.Next(), writeType);
}
else if (testType == typeof(short))
{
RunTypeTestLocal((short)random.Next(), writeType);
RunTestWithWriteType((short)random.Next(), writeType);
}
else if (testType == typeof(ushort))
{
RunTypeTestLocal((ushort)random.Next(), writeType);
RunTestWithWriteType((ushort)random.Next(), writeType);
}
else if (testType == typeof(int))
{
RunTypeTestLocal((int)random.Next(), writeType);
RunTestWithWriteType((int)random.Next(), writeType);
}
else if (testType == typeof(uint))
{
RunTypeTestLocal((uint)random.Next(), writeType);
RunTestWithWriteType((uint)random.Next(), writeType);
}
else if (testType == typeof(long))
{
RunTypeTestLocal(((long)random.Next() << 32) + random.Next(), writeType);
RunTestWithWriteType(((long)random.Next() << 32) + random.Next(), writeType);
}
else if (testType == typeof(ulong))
{
RunTypeTestLocal(((ulong)random.Next() << 32) + (ulong)random.Next(), writeType);
RunTestWithWriteType(((ulong)random.Next() << 32) + (ulong)random.Next(), writeType);
}
else if (testType == typeof(bool))
{
RunTypeTestLocal(true, writeType);
RunTestWithWriteType(true, writeType);
}
else if (testType == typeof(char))
{
RunTypeTestLocal('a', writeType);
RunTypeTestLocal('\u263a', writeType);
RunTestWithWriteType('a', writeType);
RunTestWithWriteType('\u263a', writeType);
}
else if (testType == typeof(float))
{
RunTypeTestLocal((float)random.NextDouble(), writeType);
RunTestWithWriteType((float)random.NextDouble(), writeType);
}
else if (testType == typeof(double))
{
RunTypeTestLocal(random.NextDouble(), writeType);
RunTestWithWriteType(random.NextDouble(), writeType);
}
else if (testType == typeof(ByteEnum))
{
RunTypeTestLocal(ByteEnum.C, writeType);
RunTestWithWriteType(ByteEnum.C, writeType);
}
else if (testType == typeof(SByteEnum))
{
RunTypeTestLocal(SByteEnum.C, writeType);
RunTestWithWriteType(SByteEnum.C, writeType);
}
else if (testType == typeof(ShortEnum))
{
RunTypeTestLocal(ShortEnum.C, writeType);
RunTestWithWriteType(ShortEnum.C, writeType);
}
else if (testType == typeof(UShortEnum))
{
RunTypeTestLocal(UShortEnum.C, writeType);
RunTestWithWriteType(UShortEnum.C, writeType);
}
else if (testType == typeof(IntEnum))
{
RunTypeTestLocal(IntEnum.C, writeType);
RunTestWithWriteType(IntEnum.C, writeType);
}
else if (testType == typeof(UIntEnum))
{
RunTypeTestLocal(UIntEnum.C, writeType);
RunTestWithWriteType(UIntEnum.C, writeType);
}
else if (testType == typeof(LongEnum))
{
RunTypeTestLocal(LongEnum.C, writeType);
RunTestWithWriteType(LongEnum.C, writeType);
}
else if (testType == typeof(ULongEnum))
{
RunTypeTestLocal(ULongEnum.C, writeType);
RunTestWithWriteType(ULongEnum.C, writeType);
}
else if (testType == typeof(Vector2))
{
RunTypeTestLocal(new Vector2((float)random.NextDouble(), (float)random.NextDouble()), writeType);
RunTestWithWriteType(new Vector2((float)random.NextDouble(), (float)random.NextDouble()), writeType);
}
else if (testType == typeof(Vector3))
{
RunTypeTestLocal(new Vector3((float)random.NextDouble(), (float)random.NextDouble(), (float)random.NextDouble()), writeType);
RunTestWithWriteType(new Vector3((float)random.NextDouble(), (float)random.NextDouble(), (float)random.NextDouble()), writeType);
}
else if (testType == typeof(Vector4))
{
RunTypeTestLocal(new Vector4((float)random.NextDouble(), (float)random.NextDouble(), (float)random.NextDouble(), (float)random.NextDouble()), writeType);
RunTestWithWriteType(new Vector4((float)random.NextDouble(), (float)random.NextDouble(), (float)random.NextDouble(), (float)random.NextDouble()), writeType);
}
else if (testType == typeof(Quaternion))
{
RunTypeTestLocal(new Quaternion((float)random.NextDouble(), (float)random.NextDouble(), (float)random.NextDouble(), (float)random.NextDouble()), writeType);
RunTestWithWriteType(new Quaternion((float)random.NextDouble(), (float)random.NextDouble(), (float)random.NextDouble(), (float)random.NextDouble()), writeType);
}
else if (testType == typeof(Color))
{
RunTypeTestLocal(new Color((float)random.NextDouble(), (float)random.NextDouble(), (float)random.NextDouble(), (float)random.NextDouble()), writeType);
RunTestWithWriteType(new Color((float)random.NextDouble(), (float)random.NextDouble(), (float)random.NextDouble(), (float)random.NextDouble()), writeType);
}
else if (testType == typeof(Color32))
{
RunTypeTestLocal(new Color32((byte)random.Next(), (byte)random.Next(), (byte)random.Next(), (byte)random.Next()), writeType);
RunTestWithWriteType(new Color32((byte)random.Next(), (byte)random.Next(), (byte)random.Next(), (byte)random.Next()), writeType);
}
else if (testType == typeof(Ray))
{
RunTypeTestLocal(new Ray(
RunTestWithWriteType(new Ray(
new Vector3((float)random.NextDouble(), (float)random.NextDouble(), (float)random.NextDouble()),
new Vector3((float)random.NextDouble(), (float)random.NextDouble(), (float)random.NextDouble())), writeType);
}
else if (testType == typeof(Ray2D))
{
RunTypeTestLocal(new Ray2D(
RunTestWithWriteType(new Ray2D(
new Vector2((float)random.NextDouble(), (float)random.NextDouble()),
new Vector2((float)random.NextDouble(), (float)random.NextDouble())), writeType);
}
else if (testType == typeof(TestStruct))
{
RunTypeTestLocal(GetTestStruct(), writeType);
RunTestWithWriteType(GetTestStruct(), writeType);
}
else
{

View File

@@ -1,4 +1,5 @@
using System;
using System.Reflection;
using NUnit.Framework;
using Unity.Collections;
using UnityEngine;
@@ -51,6 +52,184 @@ namespace Unity.Netcode.EditorTests
return reader;
}
private void RunWriteMethod<T>(string methodName, FastBufferWriter writer, in T value) where T : unmanaged
{
MethodInfo method = typeof(FastBufferWriter).GetMethod(methodName, new[] { typeof(T).MakeByRefType() });
if (method == null)
{
foreach (var candidateMethod in typeof(FastBufferWriter).GetMethods())
{
if (candidateMethod.Name == methodName && candidateMethod.IsGenericMethodDefinition)
{
if (candidateMethod.GetParameters().Length == 0 || (candidateMethod.GetParameters().Length > 1 && !candidateMethod.GetParameters()[1].HasDefaultValue))
{
continue;
}
if (candidateMethod.GetParameters()[0].ParameterType.IsArray)
{
continue;
}
try
{
method = candidateMethod.MakeGenericMethod(typeof(T));
break;
}
catch (ArgumentException)
{
continue;
}
}
}
}
Assert.NotNull(method);
object[] args = new object[method.GetParameters().Length];
args[0] = value;
for (var i = 1; i < args.Length; ++i)
{
args[i] = method.GetParameters()[i].DefaultValue;
}
method.Invoke(writer, args);
}
private void RunWriteMethod<T>(string methodName, FastBufferWriter writer, in T[] value) where T : unmanaged
{
MethodInfo method = typeof(FastBufferWriter).GetMethod(methodName, new[] { typeof(T[]) });
if (method == null)
{
foreach (var candidateMethod in typeof(FastBufferWriter).GetMethods())
{
if (candidateMethod.Name == methodName && candidateMethod.IsGenericMethodDefinition)
{
if (candidateMethod.GetParameters().Length == 0 || (candidateMethod.GetParameters().Length > 1 && !candidateMethod.GetParameters()[1].HasDefaultValue))
{
continue;
}
if (!candidateMethod.GetParameters()[0].ParameterType.IsArray)
{
continue;
}
try
{
method = candidateMethod.MakeGenericMethod(typeof(T));
break;
}
catch (ArgumentException)
{
continue;
}
}
}
}
Assert.NotNull(method);
object[] args = new object[method.GetParameters().Length];
args[0] = value;
for (var i = 1; i < args.Length; ++i)
{
args[i] = method.GetParameters()[i].DefaultValue;
}
method.Invoke(writer, args);
}
private void RunReadMethod<T>(string methodName, FastBufferReader reader, out T value) where T : unmanaged
{
MethodInfo method = typeof(FastBufferReader).GetMethod(methodName, new[] { typeof(T).MakeByRefType() });
if (method == null)
{
foreach (var candidateMethod in typeof(FastBufferReader).GetMethods())
{
if (candidateMethod.Name == methodName && candidateMethod.IsGenericMethodDefinition)
{
if (candidateMethod.GetParameters().Length == 0 || (candidateMethod.GetParameters().Length > 1 && !candidateMethod.GetParameters()[1].HasDefaultValue))
{
continue;
}
if (candidateMethod.GetParameters()[0].ParameterType.IsArray)
{
continue;
}
try
{
method = candidateMethod.MakeGenericMethod(typeof(T));
break;
}
catch (ArgumentException)
{
continue;
}
}
}
}
value = new T();
Assert.NotNull(method);
object[] args = new object[method.GetParameters().Length];
args[0] = value;
for (var i = 1; i < args.Length; ++i)
{
args[i] = method.GetParameters()[i].DefaultValue;
}
method.Invoke(reader, args);
value = (T)args[0];
}
private void RunReadMethod<T>(string methodName, FastBufferReader reader, out T[] value) where T : unmanaged
{
MethodInfo method = null;
try
{
method = typeof(FastBufferReader).GetMethod(methodName, new[] { typeof(T[]).MakeByRefType() });
}
catch (AmbiguousMatchException)
{
// skip.
}
if (method == null)
{
foreach (var candidateMethod in typeof(FastBufferReader).GetMethods())
{
if (candidateMethod.Name == methodName && candidateMethod.IsGenericMethodDefinition)
{
if (candidateMethod.GetParameters().Length == 0 || (candidateMethod.GetParameters().Length > 1 && !candidateMethod.GetParameters()[1].HasDefaultValue))
{
continue;
}
if (!candidateMethod.GetParameters()[0].ParameterType.HasElementType || !candidateMethod.GetParameters()[0].ParameterType.GetElementType().IsArray)
{
continue;
}
try
{
method = candidateMethod.MakeGenericMethod(typeof(T));
break;
}
catch (ArgumentException)
{
continue;
}
}
}
}
Assert.NotNull(method);
value = new T[] { };
object[] args = new object[method.GetParameters().Length];
args[0] = value;
for (var i = 1; i < args.Length; ++i)
{
args[i] = method.GetParameters()[i].DefaultValue;
}
method.Invoke(reader, args);
value = (T[])args[0];
}
#endregion
#region Generic Checks
@@ -66,14 +245,14 @@ namespace Unity.Netcode.EditorTests
var failMessage = $"RunTypeTest failed with type {typeof(T)} and value {valueToTest}";
writer.WriteValue(valueToTest);
RunWriteMethod(nameof(FastBufferWriter.WriteValue), writer, valueToTest);
var reader = CommonChecks(writer, valueToTest, writeSize, failMessage);
using (reader)
{
Assert.IsTrue(reader.TryBeginRead(FastBufferWriter.GetWriteSize<T>()));
reader.ReadValue(out T result);
RunReadMethod(nameof(FastBufferReader.ReadValue), reader, out T result);
Assert.AreEqual(valueToTest, result);
}
}
@@ -89,14 +268,14 @@ namespace Unity.Netcode.EditorTests
var failMessage = $"RunTypeTest failed with type {typeof(T)} and value {valueToTest}";
writer.WriteValueSafe(valueToTest);
RunWriteMethod(nameof(FastBufferWriter.WriteValueSafe), writer, valueToTest);
var reader = CommonChecks(writer, valueToTest, writeSize, failMessage);
using (reader)
{
reader.ReadValueSafe(out T result);
RunReadMethod(nameof(FastBufferReader.ReadValueSafe), reader, out T result);
Assert.AreEqual(valueToTest, result);
}
}
@@ -121,7 +300,7 @@ namespace Unity.Netcode.EditorTests
Assert.AreEqual(sizeof(int) + sizeof(T) * valueToTest.Length, writeSize);
Assert.IsTrue(writer.TryBeginWrite(writeSize + 2), "Writer denied write permission");
writer.WriteValue(valueToTest);
RunWriteMethod(nameof(FastBufferWriter.WriteValue), writer, valueToTest);
WriteCheckBytes(writer, writeSize);
@@ -131,7 +310,7 @@ namespace Unity.Netcode.EditorTests
VerifyPositionAndLength(reader, writer.Length);
Assert.IsTrue(reader.TryBeginRead(writeSize));
reader.ReadValue(out T[] result);
RunReadMethod(nameof(FastBufferReader.ReadValue), reader, out T[] result);
VerifyArrayEquality(valueToTest, result, 0);
VerifyCheckBytes(reader, writeSize);
@@ -147,7 +326,7 @@ namespace Unity.Netcode.EditorTests
{
Assert.AreEqual(sizeof(int) + sizeof(T) * valueToTest.Length, writeSize);
writer.WriteValueSafe(valueToTest);
RunWriteMethod(nameof(FastBufferWriter.WriteValueSafe), writer, valueToTest);
WriteCheckBytes(writer, writeSize);
@@ -156,7 +335,7 @@ namespace Unity.Netcode.EditorTests
{
VerifyPositionAndLength(reader, writer.Length);
reader.ReadValueSafe(out T[] result);
RunReadMethod(nameof(FastBufferReader.ReadValueSafe), reader, out T[] result);
VerifyArrayEquality(valueToTest, result, 0);
VerifyCheckBytes(reader, writeSize);

View File

@@ -1,4 +1,5 @@
using System;
using System.Reflection;
using NUnit.Framework;
using Unity.Collections;
using UnityEngine;
@@ -10,6 +11,7 @@ namespace Unity.Netcode.EditorTests
{
#region Common Checks
private void WriteCheckBytes(FastBufferWriter writer, int writeSize, string failMessage = "")
{
Assert.IsTrue(writer.TryBeginWrite(2), "Writer denied write permission");
@@ -63,9 +65,94 @@ namespace Unity.Netcode.EditorTests
VerifyTypedEquality(valueToTest, writer.GetUnsafePtr());
}
#endregion
#region Generic Checks
private void RunMethod<T>(string methodName, FastBufferWriter writer, in T value) where T : unmanaged
{
MethodInfo method = typeof(FastBufferWriter).GetMethod(methodName, new[] { typeof(T).MakeByRefType() });
if (method == null)
{
foreach (var candidateMethod in typeof(FastBufferWriter).GetMethods())
{
if (candidateMethod.Name == methodName && candidateMethod.IsGenericMethodDefinition)
{
if (candidateMethod.GetParameters().Length == 0 || (candidateMethod.GetParameters().Length > 1 && !candidateMethod.GetParameters()[1].HasDefaultValue))
{
continue;
}
if (candidateMethod.GetParameters()[0].ParameterType.IsArray)
{
continue;
}
try
{
method = candidateMethod.MakeGenericMethod(typeof(T));
break;
}
catch (ArgumentException)
{
continue;
}
}
}
}
Assert.NotNull(method);
object[] args = new object[method.GetParameters().Length];
args[0] = value;
for (var i = 1; i < args.Length; ++i)
{
args[i] = method.GetParameters()[i].DefaultValue;
}
method.Invoke(writer, args);
}
private void RunMethod<T>(string methodName, FastBufferWriter writer, in T[] value) where T : unmanaged
{
MethodInfo method = typeof(FastBufferWriter).GetMethod(methodName, new[] { typeof(T[]) });
if (method == null)
{
foreach (var candidateMethod in typeof(FastBufferWriter).GetMethods())
{
if (candidateMethod.Name == methodName && candidateMethod.IsGenericMethodDefinition)
{
if (candidateMethod.GetParameters().Length == 0 || (candidateMethod.GetParameters().Length > 1 && !candidateMethod.GetParameters()[1].HasDefaultValue))
{
continue;
}
if (!candidateMethod.GetParameters()[0].ParameterType.IsArray)
{
continue;
}
try
{
method = candidateMethod.MakeGenericMethod(typeof(T));
break;
}
catch (ArgumentException)
{
continue;
}
}
}
}
Assert.NotNull(method);
object[] args = new object[method.GetParameters().Length];
args[0] = value;
for (var i = 1; i < args.Length; ++i)
{
args[i] = method.GetParameters()[i].DefaultValue;
}
method.Invoke(writer, args);
}
protected override unsafe void RunTypeTest<T>(T valueToTest)
{
var writeSize = FastBufferWriter.GetWriteSize(valueToTest);
@@ -82,7 +169,7 @@ namespace Unity.Netcode.EditorTests
var failMessage = $"RunTypeTest failed with type {typeof(T)} and value {valueToTest}";
writer.WriteValue(valueToTest);
RunMethod(nameof(FastBufferWriter.WriteValue), writer, valueToTest);
CommonChecks(writer, valueToTest, writeSize, failMessage);
}
@@ -98,7 +185,7 @@ namespace Unity.Netcode.EditorTests
var failMessage = $"RunTypeTest failed with type {typeof(T)} and value {valueToTest}";
writer.WriteValueSafe(valueToTest);
RunMethod(nameof(FastBufferWriter.WriteValueSafe), writer, valueToTest);
CommonChecks(writer, valueToTest, writeSize, failMessage);
}
@@ -129,7 +216,7 @@ namespace Unity.Netcode.EditorTests
Assert.AreEqual(sizeof(int) + sizeof(T) * valueToTest.Length, writeSize);
Assert.IsTrue(writer.TryBeginWrite(writeSize + 2), "Writer denied write permission");
writer.WriteValue(valueToTest);
RunMethod(nameof(FastBufferWriter.WriteValue), writer, valueToTest);
VerifyPositionAndLength(writer, writeSize);
WriteCheckBytes(writer, writeSize);
@@ -150,7 +237,7 @@ namespace Unity.Netcode.EditorTests
Assert.AreEqual(sizeof(int) + sizeof(T) * valueToTest.Length, writeSize);
writer.WriteValueSafe(valueToTest);
RunMethod(nameof(FastBufferWriter.WriteValueSafe), writer, valueToTest);
VerifyPositionAndLength(writer, writeSize);
WriteCheckBytes(writer, writeSize);

View File

@@ -0,0 +1,49 @@
#if UNITY_UNET_PRESENT
#pragma warning disable 618 // disable is obsolete
using NUnit.Framework;
using Unity.Netcode.Transports.UNET;
using UnityEngine;
using UnityEngine.TestTools;
namespace Unity.Netcode.EditorTests
{
public class UNetTransportTests
{
[Test]
public void StartServerReturnsFalseOnFailure()
{
UNetTransport unet1 = null;
UNetTransport unet2 = null;
try
{
// Arrange
// We're expecting an error from UNET, but don't care to validate the specific message
LogAssert.ignoreFailingMessages = true;
var go = new GameObject();
unet1 = go.AddComponent<UNetTransport>();
unet1.ServerListenPort = 1;
unet1.Initialize();
unet1.StartServer();
unet2 = go.AddComponent<UNetTransport>();
unet2.ServerListenPort = 1;
unet2.Initialize();
// Act
var result = unet2.StartServer();
// Assert
Assert.IsFalse(result, "UNET fails to initialize against port already in use");
}
finally
{
unet1?.Shutdown();
unet2?.Shutdown();
}
}
}
}
#pragma warning restore 618
#endif

View File

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

View File

@@ -24,6 +24,11 @@
"name": "com.unity.multiplayer.tools",
"expression": "",
"define": "MULTIPLAYER_TOOLS"
},
{
"name": "Unity",
"expression": "(0,2022.2.0a5)",
"define": "UNITY_UNET_PRESENT"
}
]
}

View File

@@ -3,11 +3,7 @@ using NUnit.Framework;
using UnityEngine;
using UnityEngine.TestTools;
using Unity.Netcode.TestHelpers.Runtime;
#if UNITY_UNET_PRESENT
using Unity.Netcode.Transports.UNET;
#else
using Unity.Netcode.Transports.UTP;
#endif
namespace Unity.Netcode.RuntimeTests
{
@@ -26,15 +22,13 @@ namespace Unity.Netcode.RuntimeTests
m_NetworkManagerGameObject = new GameObject();
m_ClientNetworkManager = m_NetworkManagerGameObject.AddComponent<NetworkManager>();
m_ClientNetworkManager.NetworkConfig = new NetworkConfig();
#if UNITY_UNET_PRESENT
m_TimeoutHelper = new TimeoutHelper(30);
m_ClientNetworkManager.NetworkConfig.NetworkTransport = m_NetworkManagerGameObject.AddComponent<UNetTransport>();
#else
// Default is 1000ms per connection attempt and 60 connection attempts (60s)
// Currently there is no easy way to set these values other than in-editor
m_TimeoutHelper = new TimeoutHelper(70);
m_ClientNetworkManager.NetworkConfig.NetworkTransport = m_NetworkManagerGameObject.AddComponent<UnityTransport>();
#endif
var unityTransport = m_NetworkManagerGameObject.AddComponent<UnityTransport>();
unityTransport.ConnectTimeoutMS = 1000;
unityTransport.MaxConnectAttempts = 1;
m_TimeoutHelper = new TimeoutHelper(2);
m_ClientNetworkManager.NetworkConfig.NetworkTransport = unityTransport;
}
[UnityTest]
@@ -46,10 +40,9 @@ namespace Unity.Netcode.RuntimeTests
// Only start the client (so it will timeout)
m_ClientNetworkManager.StartClient();
#if !UNITY_UNET_PRESENT
// Unity Transport throws an error when it times out
LogAssert.Expect(LogType.Error, "Failed to connect to server.");
#endif
yield return NetcodeIntegrationTest.WaitForConditionOrTimeOut(() => m_WasDisconnected, m_TimeoutHelper);
Assert.False(m_TimeoutHelper.TimedOut, "Timed out waiting for client to timeout waiting to connect!");

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: b3d771dc2a334464ad96e8c66ac776cc
timeCreated: 1650295945

View File

@@ -9,6 +9,8 @@ namespace Unity.Netcode.RuntimeTests
{
public class DisconnectTests
{
private bool m_ClientDisconnected;
[UnityTest]
public IEnumerator RemoteDisconnectPlayerObjectCleanup()
{
@@ -38,11 +40,14 @@ namespace Unity.Netcode.RuntimeTests
yield return NetcodeIntegrationTestHelpers.WaitForClientConnectedToServer(server);
// disconnect the remote client
m_ClientDisconnected = false;
server.DisconnectClient(clients[0].LocalClientId);
clients[0].OnClientDisconnectCallback += OnClientDisconnectCallback;
var timeoutHelper = new TimeoutHelper();
yield return NetcodeIntegrationTest.WaitForConditionOrTimeOut(() => m_ClientDisconnected, timeoutHelper);
// wait 1 frame because destroys are delayed
var nextFrameNumber = Time.frameCount + 1;
yield return new WaitUntil(() => Time.frameCount >= nextFrameNumber);
// We need to do this to remove other associated client properties/values from NetcodeIntegrationTestHelpers
NetcodeIntegrationTestHelpers.StopOneClient(clients[0]);
// ensure the object was destroyed
Assert.False(server.SpawnManager.SpawnedObjects.Any(x => x.Value.IsPlayerObject && x.Value.OwnerClientId == clients[0].LocalClientId));
@@ -50,5 +55,10 @@ namespace Unity.Netcode.RuntimeTests
// cleanup
NetcodeIntegrationTestHelpers.Destroy();
}
private void OnClientDisconnectCallback(ulong obj)
{
m_ClientDisconnected = true;
}
}
}

View File

@@ -27,7 +27,7 @@ namespace Unity.Netcode.RuntimeTests
public IEnumerator NamedMessageIsReceivedOnClientWithContent()
{
var messageName = Guid.NewGuid().ToString();
var messageContent = Guid.NewGuid();
var messageContent = new ForceNetworkSerializeByMemcpy<Guid>(Guid.NewGuid());
var writer = new FastBufferWriter(1300, Allocator.Temp);
using (writer)
{
@@ -39,7 +39,7 @@ namespace Unity.Netcode.RuntimeTests
}
ulong receivedMessageSender = 0;
var receivedMessageContent = new Guid();
var receivedMessageContent = new ForceNetworkSerializeByMemcpy<Guid>(new Guid());
FirstClient.CustomMessagingManager.RegisterNamedMessageHandler(
messageName,
(ulong sender, FastBufferReader reader) =>
@@ -51,7 +51,7 @@ namespace Unity.Netcode.RuntimeTests
yield return new WaitForSeconds(0.2f);
Assert.AreEqual(messageContent, receivedMessageContent);
Assert.AreEqual(messageContent.Value, receivedMessageContent.Value);
Assert.AreEqual(m_ServerNetworkManager.LocalClientId, receivedMessageSender);
}
@@ -59,7 +59,7 @@ namespace Unity.Netcode.RuntimeTests
public IEnumerator NamedMessageIsReceivedOnMultipleClientsWithContent()
{
var messageName = Guid.NewGuid().ToString();
var messageContent = Guid.NewGuid();
var messageContent = new ForceNetworkSerializeByMemcpy<Guid>(Guid.NewGuid());
var writer = new FastBufferWriter(1300, Allocator.Temp);
using (writer)
{
@@ -71,7 +71,7 @@ namespace Unity.Netcode.RuntimeTests
}
ulong firstReceivedMessageSender = 0;
var firstReceivedMessageContent = new Guid();
var firstReceivedMessageContent = new ForceNetworkSerializeByMemcpy<Guid>(new Guid());
FirstClient.CustomMessagingManager.RegisterNamedMessageHandler(
messageName,
(ulong sender, FastBufferReader reader) =>
@@ -82,7 +82,7 @@ namespace Unity.Netcode.RuntimeTests
});
ulong secondReceivedMessageSender = 0;
var secondReceivedMessageContent = new Guid();
var secondReceivedMessageContent = new ForceNetworkSerializeByMemcpy<Guid>(new Guid());
SecondClient.CustomMessagingManager.RegisterNamedMessageHandler(
messageName,
(ulong sender, FastBufferReader reader) =>
@@ -94,10 +94,10 @@ namespace Unity.Netcode.RuntimeTests
yield return new WaitForSeconds(0.2f);
Assert.AreEqual(messageContent, firstReceivedMessageContent);
Assert.AreEqual(messageContent.Value, firstReceivedMessageContent.Value);
Assert.AreEqual(m_ServerNetworkManager.LocalClientId, firstReceivedMessageSender);
Assert.AreEqual(messageContent, secondReceivedMessageContent);
Assert.AreEqual(messageContent.Value, secondReceivedMessageContent.Value);
Assert.AreEqual(m_ServerNetworkManager.LocalClientId, secondReceivedMessageSender);
}
@@ -105,7 +105,7 @@ namespace Unity.Netcode.RuntimeTests
public IEnumerator WhenSendingNamedMessageToAll_AllClientsReceiveIt()
{
var messageName = Guid.NewGuid().ToString();
var messageContent = Guid.NewGuid();
var messageContent = new ForceNetworkSerializeByMemcpy<Guid>(Guid.NewGuid());
var writer = new FastBufferWriter(1300, Allocator.Temp);
using (writer)
{
@@ -114,7 +114,7 @@ namespace Unity.Netcode.RuntimeTests
}
ulong firstReceivedMessageSender = 0;
var firstReceivedMessageContent = new Guid();
var firstReceivedMessageContent = new ForceNetworkSerializeByMemcpy<Guid>(new Guid());
FirstClient.CustomMessagingManager.RegisterNamedMessageHandler(
messageName,
(ulong sender, FastBufferReader reader) =>
@@ -125,7 +125,7 @@ namespace Unity.Netcode.RuntimeTests
});
ulong secondReceivedMessageSender = 0;
var secondReceivedMessageContent = new Guid();
var secondReceivedMessageContent = new ForceNetworkSerializeByMemcpy<Guid>(new Guid());
SecondClient.CustomMessagingManager.RegisterNamedMessageHandler(
messageName,
(ulong sender, FastBufferReader reader) =>
@@ -137,10 +137,10 @@ namespace Unity.Netcode.RuntimeTests
yield return new WaitForSeconds(0.2f);
Assert.AreEqual(messageContent, firstReceivedMessageContent);
Assert.AreEqual(messageContent.Value, firstReceivedMessageContent.Value);
Assert.AreEqual(m_ServerNetworkManager.LocalClientId, firstReceivedMessageSender);
Assert.AreEqual(messageContent, secondReceivedMessageContent);
Assert.AreEqual(messageContent.Value, secondReceivedMessageContent.Value);
Assert.AreEqual(m_ServerNetworkManager.LocalClientId, secondReceivedMessageSender);
}
@@ -148,7 +148,7 @@ namespace Unity.Netcode.RuntimeTests
public void WhenSendingNamedMessageToNullClientList_ArgumentNullExceptionIsThrown()
{
var messageName = Guid.NewGuid().ToString();
var messageContent = Guid.NewGuid();
var messageContent = new ForceNetworkSerializeByMemcpy<Guid>(Guid.NewGuid());
var writer = new FastBufferWriter(1300, Allocator.Temp);
using (writer)
{

View File

@@ -19,7 +19,7 @@ namespace Unity.Netcode.RuntimeTests
[UnityTest]
public IEnumerator UnnamedMessageIsReceivedOnClientWithContent()
{
var messageContent = Guid.NewGuid();
var messageContent = new ForceNetworkSerializeByMemcpy<Guid>(Guid.NewGuid());
var writer = new FastBufferWriter(1300, Allocator.Temp);
using (writer)
{
@@ -30,7 +30,7 @@ namespace Unity.Netcode.RuntimeTests
}
ulong receivedMessageSender = 0;
var receivedMessageContent = new Guid();
var receivedMessageContent = new ForceNetworkSerializeByMemcpy<Guid>(new Guid());
FirstClient.CustomMessagingManager.OnUnnamedMessage +=
(ulong sender, FastBufferReader reader) =>
{
@@ -41,14 +41,14 @@ namespace Unity.Netcode.RuntimeTests
yield return new WaitForSeconds(0.2f);
Assert.AreEqual(messageContent, receivedMessageContent);
Assert.AreEqual(messageContent.Value, receivedMessageContent.Value);
Assert.AreEqual(m_ServerNetworkManager.LocalClientId, receivedMessageSender);
}
[UnityTest]
public IEnumerator UnnamedMessageIsReceivedOnMultipleClientsWithContent()
{
var messageContent = Guid.NewGuid();
var messageContent = new ForceNetworkSerializeByMemcpy<Guid>(Guid.NewGuid());
var writer = new FastBufferWriter(1300, Allocator.Temp);
using (writer)
{
@@ -59,7 +59,7 @@ namespace Unity.Netcode.RuntimeTests
}
ulong firstReceivedMessageSender = 0;
var firstReceivedMessageContent = new Guid();
var firstReceivedMessageContent = new ForceNetworkSerializeByMemcpy<Guid>(new Guid());
FirstClient.CustomMessagingManager.OnUnnamedMessage +=
(ulong sender, FastBufferReader reader) =>
{
@@ -69,7 +69,7 @@ namespace Unity.Netcode.RuntimeTests
};
ulong secondReceivedMessageSender = 0;
var secondReceivedMessageContent = new Guid();
var secondReceivedMessageContent = new ForceNetworkSerializeByMemcpy<Guid>(new Guid());
SecondClient.CustomMessagingManager.OnUnnamedMessage +=
(ulong sender, FastBufferReader reader) =>
{
@@ -80,17 +80,17 @@ namespace Unity.Netcode.RuntimeTests
yield return new WaitForSeconds(0.2f);
Assert.AreEqual(messageContent, firstReceivedMessageContent);
Assert.AreEqual(messageContent.Value, firstReceivedMessageContent.Value);
Assert.AreEqual(m_ServerNetworkManager.LocalClientId, firstReceivedMessageSender);
Assert.AreEqual(messageContent, secondReceivedMessageContent);
Assert.AreEqual(messageContent.Value, secondReceivedMessageContent.Value);
Assert.AreEqual(m_ServerNetworkManager.LocalClientId, secondReceivedMessageSender);
}
[UnityTest]
public IEnumerator WhenSendingUnnamedMessageToAll_AllClientsReceiveIt()
{
var messageContent = Guid.NewGuid();
var messageContent = new ForceNetworkSerializeByMemcpy<Guid>(Guid.NewGuid());
var writer = new FastBufferWriter(1300, Allocator.Temp);
using (writer)
{
@@ -99,7 +99,7 @@ namespace Unity.Netcode.RuntimeTests
}
ulong firstReceivedMessageSender = 0;
var firstReceivedMessageContent = new Guid();
var firstReceivedMessageContent = new ForceNetworkSerializeByMemcpy<Guid>(new Guid());
FirstClient.CustomMessagingManager.OnUnnamedMessage +=
(ulong sender, FastBufferReader reader) =>
{
@@ -109,7 +109,7 @@ namespace Unity.Netcode.RuntimeTests
};
ulong secondReceivedMessageSender = 0;
var secondReceivedMessageContent = new Guid();
var secondReceivedMessageContent = new ForceNetworkSerializeByMemcpy<Guid>(new Guid());
SecondClient.CustomMessagingManager.OnUnnamedMessage +=
(ulong sender, FastBufferReader reader) =>
{
@@ -120,17 +120,17 @@ namespace Unity.Netcode.RuntimeTests
yield return new WaitForSeconds(0.2f);
Assert.AreEqual(messageContent, firstReceivedMessageContent);
Assert.AreEqual(messageContent.Value, firstReceivedMessageContent.Value);
Assert.AreEqual(m_ServerNetworkManager.LocalClientId, firstReceivedMessageSender);
Assert.AreEqual(messageContent, secondReceivedMessageContent);
Assert.AreEqual(messageContent.Value, secondReceivedMessageContent.Value);
Assert.AreEqual(m_ServerNetworkManager.LocalClientId, secondReceivedMessageSender);
}
[Test]
public void WhenSendingNamedMessageToNullClientList_ArgumentNullExceptionIsThrown()
{
var messageContent = Guid.NewGuid();
var messageContent = new ForceNetworkSerializeByMemcpy<Guid>(Guid.NewGuid());
var writer = new FastBufferWriter(1300, Allocator.Temp);
using (writer)
{

View File

@@ -27,12 +27,12 @@ namespace Unity.Netcode.RuntimeTests.Metrics
{
var waitForMetricValues = new WaitForEventMetricValues<NetworkMessageEvent>(ServerMetrics.Dispatcher, NetworkMetricTypes.NetworkMessageSent);
var messageName = Guid.NewGuid();
var messageName = new ForceNetworkSerializeByMemcpy<Guid>(Guid.NewGuid());
using (var writer = new FastBufferWriter(1300, Allocator.Temp))
{
writer.WriteValueSafe(messageName);
Server.CustomMessagingManager.SendNamedMessage(messageName.ToString(), FirstClient.LocalClientId, writer);
Server.CustomMessagingManager.SendNamedMessage(messageName.Value.ToString(), FirstClient.LocalClientId, writer);
}
yield return waitForMetricValues.WaitForMetricsReceived();
@@ -47,12 +47,12 @@ namespace Unity.Netcode.RuntimeTests.Metrics
public IEnumerator TrackNetworkMessageSentMetricToMultipleClients()
{
var waitForMetricValues = new WaitForEventMetricValues<NetworkMessageEvent>(ServerMetrics.Dispatcher, NetworkMetricTypes.NetworkMessageSent);
var messageName = Guid.NewGuid();
var messageName = new ForceNetworkSerializeByMemcpy<Guid>(Guid.NewGuid());
using (var writer = new FastBufferWriter(1300, Allocator.Temp))
{
writer.WriteValueSafe(messageName);
Server.CustomMessagingManager.SendNamedMessage(messageName.ToString(), new List<ulong> { FirstClient.LocalClientId, SecondClient.LocalClientId }, writer);
Server.CustomMessagingManager.SendNamedMessage(messageName.Value.ToString(), new List<ulong> { FirstClient.LocalClientId, SecondClient.LocalClientId }, writer);
}
@@ -65,10 +65,10 @@ namespace Unity.Netcode.RuntimeTests.Metrics
[UnityTest]
public IEnumerator TrackNetworkMessageReceivedMetric()
{
var messageName = Guid.NewGuid();
var messageName = new ForceNetworkSerializeByMemcpy<Guid>(Guid.NewGuid());
LogAssert.Expect(LogType.Log, $"Received from {Server.LocalClientId}");
FirstClient.CustomMessagingManager.RegisterNamedMessageHandler(messageName.ToString(), (ulong sender, FastBufferReader payload) =>
FirstClient.CustomMessagingManager.RegisterNamedMessageHandler(messageName.Value.ToString(), (ulong sender, FastBufferReader payload) =>
{
Debug.Log($"Received from {sender}");
});
@@ -79,7 +79,7 @@ namespace Unity.Netcode.RuntimeTests.Metrics
{
writer.WriteValueSafe(messageName);
Server.CustomMessagingManager.SendNamedMessage(messageName.ToString(), FirstClient.LocalClientId, writer);
Server.CustomMessagingManager.SendNamedMessage(messageName.Value.ToString(), FirstClient.LocalClientId, writer);
}
yield return waitForMetricValues.WaitForMetricsReceived();
@@ -94,12 +94,12 @@ namespace Unity.Netcode.RuntimeTests.Metrics
{
var waitForMetricValues = new WaitForEventMetricValues<NamedMessageEvent>(ServerMetrics.Dispatcher, NetworkMetricTypes.NamedMessageSent);
var messageName = Guid.NewGuid();
var messageName = new ForceNetworkSerializeByMemcpy<Guid>(Guid.NewGuid());
using (var writer = new FastBufferWriter(1300, Allocator.Temp))
{
writer.WriteValueSafe(messageName);
Server.CustomMessagingManager.SendNamedMessage(messageName.ToString(), FirstClient.LocalClientId, writer);
Server.CustomMessagingManager.SendNamedMessage(messageName.Value.ToString(), FirstClient.LocalClientId, writer);
}
@@ -109,7 +109,7 @@ namespace Unity.Netcode.RuntimeTests.Metrics
Assert.AreEqual(1, namedMessageSentMetricValues.Count);
var namedMessageSent = namedMessageSentMetricValues.First();
Assert.AreEqual(messageName.ToString(), namedMessageSent.Name);
Assert.AreEqual(messageName.Value.ToString(), namedMessageSent.Name);
Assert.AreEqual(FirstClient.LocalClientId, namedMessageSent.Connection.Id);
Assert.AreEqual(FastBufferWriter.GetWriteSize(messageName) + k_NamedMessageOverhead, namedMessageSent.BytesCount);
}
@@ -118,12 +118,12 @@ namespace Unity.Netcode.RuntimeTests.Metrics
public IEnumerator TrackNamedMessageSentMetricToMultipleClients()
{
var waitForMetricValues = new WaitForEventMetricValues<NamedMessageEvent>(ServerMetrics.Dispatcher, NetworkMetricTypes.NamedMessageSent);
var messageName = Guid.NewGuid();
var messageName = new ForceNetworkSerializeByMemcpy<Guid>(Guid.NewGuid());
using (var writer = new FastBufferWriter(1300, Allocator.Temp))
{
writer.WriteValueSafe(messageName);
Server.CustomMessagingManager.SendNamedMessage(messageName.ToString(), new List<ulong> { FirstClient.LocalClientId, SecondClient.LocalClientId }, writer);
Server.CustomMessagingManager.SendNamedMessage(messageName.Value.ToString(), new List<ulong> { FirstClient.LocalClientId, SecondClient.LocalClientId }, writer);
}
@@ -131,7 +131,7 @@ namespace Unity.Netcode.RuntimeTests.Metrics
var namedMessageSentMetricValues = waitForMetricValues.AssertMetricValuesHaveBeenFound();
Assert.AreEqual(2, namedMessageSentMetricValues.Count);
Assert.That(namedMessageSentMetricValues.Select(x => x.Name), Has.All.EqualTo(messageName.ToString()));
Assert.That(namedMessageSentMetricValues.Select(x => x.Name), Has.All.EqualTo(messageName.Value.ToString()));
Assert.That(namedMessageSentMetricValues.Select(x => x.BytesCount), Has.All.EqualTo(FastBufferWriter.GetWriteSize(messageName) + k_NamedMessageOverhead));
}
@@ -139,12 +139,12 @@ namespace Unity.Netcode.RuntimeTests.Metrics
public IEnumerator TrackNamedMessageSentMetricToSelf()
{
var waitForMetricValues = new WaitForEventMetricValues<NamedMessageEvent>(ServerMetrics.Dispatcher, NetworkMetricTypes.NamedMessageSent);
var messageName = Guid.NewGuid();
var messageName = new ForceNetworkSerializeByMemcpy<Guid>(Guid.NewGuid());
using (var writer = new FastBufferWriter(1300, Allocator.Temp))
{
writer.WriteValueSafe(messageName);
Server.CustomMessagingManager.SendNamedMessage(messageName.ToString(), Server.LocalClientId, writer);
Server.CustomMessagingManager.SendNamedMessage(messageName.Value.ToString(), Server.LocalClientId, writer);
}
yield return waitForMetricValues.WaitForMetricsReceived();
@@ -157,10 +157,10 @@ namespace Unity.Netcode.RuntimeTests.Metrics
{
var waitForMetricValues = new WaitForEventMetricValues<NamedMessageEvent>(FirstClientMetrics.Dispatcher, NetworkMetricTypes.NamedMessageReceived);
var messageName = Guid.NewGuid();
var messageName = new ForceNetworkSerializeByMemcpy<Guid>(Guid.NewGuid());
LogAssert.Expect(LogType.Log, $"Received from {Server.LocalClientId}");
FirstClient.CustomMessagingManager.RegisterNamedMessageHandler(messageName.ToString(), (ulong sender, FastBufferReader payload) =>
FirstClient.CustomMessagingManager.RegisterNamedMessageHandler(messageName.Value.ToString(), (ulong sender, FastBufferReader payload) =>
{
Debug.Log($"Received from {sender}");
});
@@ -169,7 +169,7 @@ namespace Unity.Netcode.RuntimeTests.Metrics
{
writer.WriteValueSafe(messageName);
Server.CustomMessagingManager.SendNamedMessage(messageName.ToString(), FirstClient.LocalClientId, writer);
Server.CustomMessagingManager.SendNamedMessage(messageName.Value.ToString(), FirstClient.LocalClientId, writer);
}
@@ -179,7 +179,7 @@ namespace Unity.Netcode.RuntimeTests.Metrics
Assert.AreEqual(1, namedMessageReceivedValues.Count);
var namedMessageReceived = namedMessageReceivedValues.First();
Assert.AreEqual(messageName.ToString(), namedMessageReceived.Name);
Assert.AreEqual(messageName.Value.ToString(), namedMessageReceived.Name);
Assert.AreEqual(Server.LocalClientId, namedMessageReceived.Connection.Id);
Assert.AreEqual(FastBufferWriter.GetWriteSize(messageName) + k_NamedMessageOverhead, namedMessageReceived.BytesCount);
}
@@ -187,7 +187,7 @@ namespace Unity.Netcode.RuntimeTests.Metrics
[UnityTest]
public IEnumerator TrackUnnamedMessageSentMetric()
{
var message = Guid.NewGuid();
var message = new ForceNetworkSerializeByMemcpy<Guid>(Guid.NewGuid());
using (var writer = new FastBufferWriter(1300, Allocator.Temp))
{
writer.WriteValueSafe(message);
@@ -211,7 +211,7 @@ namespace Unity.Netcode.RuntimeTests.Metrics
[UnityTest]
public IEnumerator TrackUnnamedMessageSentMetricToMultipleClients()
{
var message = Guid.NewGuid();
var message = new ForceNetworkSerializeByMemcpy<Guid>(Guid.NewGuid());
var waitForMetricValues = new WaitForEventMetricValues<UnnamedMessageEvent>(ServerMetrics.Dispatcher, NetworkMetricTypes.UnnamedMessageSent);
using (var writer = new FastBufferWriter(1300, Allocator.Temp))
{
@@ -236,7 +236,7 @@ namespace Unity.Netcode.RuntimeTests.Metrics
public IEnumerator TrackUnnamedMessageSentMetricToSelf()
{
var waitForMetricValues = new WaitForEventMetricValues<UnnamedMessageEvent>(ServerMetrics.Dispatcher, NetworkMetricTypes.UnnamedMessageSent);
var messageName = Guid.NewGuid();
var messageName = new ForceNetworkSerializeByMemcpy<Guid>(Guid.NewGuid());
using (var writer = new FastBufferWriter(1300, Allocator.Temp))
{
writer.WriteValueSafe(messageName);
@@ -252,7 +252,7 @@ namespace Unity.Netcode.RuntimeTests.Metrics
[UnityTest]
public IEnumerator TrackUnnamedMessageReceivedMetric()
{
var message = Guid.NewGuid();
var message = new ForceNetworkSerializeByMemcpy<Guid>(Guid.NewGuid());
var waitForMetricValues = new WaitForEventMetricValues<UnnamedMessageEvent>(FirstClientMetrics.Dispatcher, NetworkMetricTypes.UnnamedMessageReceived);
using (var writer = new FastBufferWriter(1300, Allocator.Temp))
{

View File

@@ -24,11 +24,6 @@ namespace Unity.Netcode.RuntimeTests.Metrics
: base(HostOrServer.Server)
{}
protected override void OnOneTimeSetup()
{
m_NetworkTransport = NetcodeIntegrationTestHelpers.InstanceTransport.UTP;
}
protected override void OnServerAndClientsCreated()
{
var clientTransport = (UnityTransport)m_ClientNetworkManagers[0].NetworkConfig.NetworkTransport;

View File

@@ -12,13 +12,6 @@ namespace Unity.Netcode.RuntimeTests.Metrics
{
internal class PacketMetricsTests : SingleClientMetricTestBase
{
protected override void OnOneTimeSetup()
{
m_NetworkTransport = NetcodeIntegrationTestHelpers.InstanceTransport.UTP;
base.OnOneTimeSetup();
}
[UnityTest]
public IEnumerator TrackPacketSentMetric()
{

View File

@@ -40,15 +40,6 @@ namespace Unity.Netcode.RuntimeTests.Metrics
m_ClientCount = numberOfClients == ClientCount.OneClient ? 1 : 2;
}
/// <summary>
/// Note: We are using the OnOneTimeSetup to select the transport to use for
/// this test set.
/// </summary>
protected override void OnOneTimeSetup()
{
m_NetworkTransport = NetcodeIntegrationTestHelpers.InstanceTransport.UTP;
}
[UnityTest]
public IEnumerator TrackRttMetricServerToClient()
{

View File

@@ -16,6 +16,12 @@ namespace Unity.Netcode.RuntimeTests.Metrics
private static readonly int k_ServerLogSentMessageOverhead = 2 + k_MessageHeaderSize;
private static readonly int k_ServerLogReceivedMessageOverhead = 2;
protected override IEnumerator OnSetup()
{
m_CreateServerFirst = false;
return base.OnSetup();
}
[UnityTest]
public IEnumerator TrackServerLogSentMetric()
{

View File

@@ -20,14 +20,14 @@ namespace Unity.Netcode.RuntimeTests.Metrics
[UnityTest]
public IEnumerator TrackTotalNumberOfBytesSent()
{
var messageName = Guid.NewGuid();
var messageName = new ForceNetworkSerializeByMemcpy<Guid>(Guid.NewGuid());
var writer = new FastBufferWriter(1300, Allocator.Temp);
var observer = new TotalBytesObserver(ClientMetrics.Dispatcher, NetworkMetricTypes.TotalBytesReceived);
try
{
writer.WriteValueSafe(messageName);
Server.CustomMessagingManager.SendNamedMessage(messageName.ToString(), Client.LocalClientId, writer);
Server.CustomMessagingManager.SendNamedMessage(messageName.Value.ToString(), Client.LocalClientId, writer);
}
finally
{
@@ -48,14 +48,14 @@ namespace Unity.Netcode.RuntimeTests.Metrics
[UnityTest]
public IEnumerator TrackTotalNumberOfBytesReceived()
{
var messageName = Guid.NewGuid();
var messageName = new ForceNetworkSerializeByMemcpy<Guid>(Guid.NewGuid());
var writer = new FastBufferWriter(1300, Allocator.Temp);
var observer = new TotalBytesObserver(ClientMetrics.Dispatcher, NetworkMetricTypes.TotalBytesReceived);
try
{
writer.WriteValueSafe(messageName);
Server.CustomMessagingManager.SendNamedMessage(messageName.ToString(), Client.LocalClientId, writer);
Server.CustomMessagingManager.SendNamedMessage(messageName.Value.ToString(), Client.LocalClientId, writer);
}
finally
{

View File

@@ -1,7 +1,7 @@
using UnityEngine;
using NUnit.Framework;
using UnityEngine.TestTools;
using Unity.Netcode.TestHelpers.Runtime;
using Unity.Netcode.Transports.UTP;
using Object = UnityEngine.Object;
namespace Unity.Netcode.RuntimeTests
@@ -14,9 +14,9 @@ namespace Unity.Netcode.RuntimeTests
var parent = new GameObject("ParentObject");
var networkManagerObject = new GameObject(nameof(CheckNestedNetworkManager));
var transport = networkManagerObject.AddComponent<SIPTransport>();
var unityTransport = networkManagerObject.AddComponent<UnityTransport>();
var networkManager = networkManagerObject.AddComponent<NetworkManager>();
networkManager.NetworkConfig = new NetworkConfig() { NetworkTransport = transport };
networkManager.NetworkConfig = new NetworkConfig() { NetworkTransport = unityTransport };
// Make our NetworkManager's GameObject nested
networkManagerObject.transform.parent = parent.transform;

View File

@@ -38,7 +38,7 @@ namespace Unity.Netcode.RuntimeTests
// destroy the server player
Object.Destroy(serverClientPlayerResult.Result.gameObject);
yield return NetcodeIntegrationTestHelpers.WaitForMessageOfType<DestroyObjectMessage>(m_ClientNetworkManagers[0]);
yield return NetcodeIntegrationTestHelpers.WaitForMessageOfTypeHandled<DestroyObjectMessage>(m_ClientNetworkManagers[0]);
Assert.IsTrue(serverClientPlayerResult.Result == null); // Assert.IsNull doesn't work here
Assert.IsTrue(clientClientPlayerResult.Result == null);

View File

@@ -51,6 +51,8 @@ namespace Unity.Netcode.RuntimeTests
yield return s_DefaultWaitForTick;
// 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));
}

View File

@@ -67,7 +67,7 @@ namespace Unity.Netcode.RuntimeTests
m_OwnershipObject = SpawnObject(m_OwnershipPrefab, m_ServerNetworkManager);
m_OwnershipNetworkObject = m_OwnershipObject.GetComponent<NetworkObject>();
yield return NetcodeIntegrationTestHelpers.WaitForMessageOfType<CreateObjectMessage>(m_ClientNetworkManagers[0]);
yield return NetcodeIntegrationTestHelpers.WaitForMessageOfTypeHandled<CreateObjectMessage>(m_ClientNetworkManagers[0]);
var ownershipNetworkObjectId = m_OwnershipNetworkObject.NetworkObjectId;
Assert.That(ownershipNetworkObjectId, Is.GreaterThan(0));
@@ -95,11 +95,14 @@ namespace Unity.Netcode.RuntimeTests
Assert.That(m_ServerNetworkManager.ConnectedClients.ContainsKey(m_ClientNetworkManagers[0].LocalClientId));
serverObject.ChangeOwnership(m_ClientNetworkManagers[0].LocalClientId);
yield return NetcodeIntegrationTestHelpers.WaitForTicks(m_ServerNetworkManager, 2);
serverObject.ChangeOwnership(clientComponent.NetworkManager.LocalClientId);
yield return s_DefaultWaitForTick;
Assert.That(serverComponent.OnLostOwnershipFired);
Assert.That(serverComponent.OwnerClientId, Is.EqualTo(m_ClientNetworkManagers[0].LocalClientId));
yield return WaitForConditionOrTimeOut(() => clientComponent.OnGainedOwnershipFired);
Assert.False(s_GlobalTimeoutHelper.TimedOut, $"Timed out waiting for client to gain ownership!");
Assert.That(clientComponent.OnGainedOwnershipFired);
Assert.That(clientComponent.OwnerClientId, Is.EqualTo(m_ClientNetworkManagers[0].LocalClientId));
@@ -107,10 +110,13 @@ namespace Unity.Netcode.RuntimeTests
clientComponent.ResetFlags();
serverObject.ChangeOwnership(NetworkManager.ServerClientId);
yield return NetcodeIntegrationTestHelpers.WaitForTicks(m_ServerNetworkManager, 2);
yield return s_DefaultWaitForTick;
Assert.That(serverComponent.OnGainedOwnershipFired);
Assert.That(serverComponent.OwnerClientId, Is.EqualTo(m_ServerNetworkManager.LocalClientId));
yield return WaitForConditionOrTimeOut(() => clientComponent.OnLostOwnershipFired);
Assert.False(s_GlobalTimeoutHelper.TimedOut, $"Timed out waiting for client to lose ownership!");
Assert.That(clientComponent.OnLostOwnershipFired);
Assert.That(clientComponent.OwnerClientId, Is.EqualTo(m_ServerNetworkManager.LocalClientId));
}
@@ -151,11 +157,22 @@ namespace Unity.Netcode.RuntimeTests
var ownershipNetworkObjectId = m_OwnershipNetworkObject.NetworkObjectId;
Assert.That(ownershipNetworkObjectId, Is.GreaterThan(0));
Assert.That(m_ServerNetworkManager.SpawnManager.SpawnedObjects.ContainsKey(ownershipNetworkObjectId));
foreach (var clientNetworkManager in m_ClientNetworkManagers)
bool WaitForClientsToSpawnNetworkObject()
{
Assert.That(clientNetworkManager.SpawnManager.SpawnedObjects.ContainsKey(ownershipNetworkObjectId));
foreach (var clientNetworkManager in m_ClientNetworkManagers)
{
if (!clientNetworkManager.SpawnManager.SpawnedObjects.ContainsKey(ownershipNetworkObjectId))
{
return false;
}
}
return true;
}
yield return WaitForConditionOrTimeOut(WaitForClientsToSpawnNetworkObject);
Assert.False(s_GlobalTimeoutHelper.TimedOut, "Timed out waiting for all clients to change ownership!");
// Verifies that removing the ownership when the default (server) is already set does not cause a Key Not Found Exception
m_ServerNetworkManager.SpawnManager.RemoveOwnership(m_OwnershipNetworkObject);
var serverObject = m_ServerNetworkManager.SpawnManager.SpawnedObjects[ownershipNetworkObjectId];
@@ -237,7 +254,10 @@ namespace Unity.Netcode.RuntimeTests
Assert.That(serverComponent.OnGainedOwnershipFired);
Assert.That(serverComponent.OwnerClientId, Is.EqualTo(m_ServerNetworkManager.LocalClientId));
Assert.That(previousClientComponent.OnLostOwnershipFired);
yield return WaitForConditionOrTimeOut(() => previousClientComponent.OnLostOwnershipFired);
Assert.False(s_GlobalTimeoutHelper.TimedOut, $"Timed out waiting for {previousClientComponent.name} to lose ownership!");
// Make sure all client-side versions of the object is once again owned by the server
for (int i = 0; i < NumberOfClients; i++)

View File

@@ -91,6 +91,8 @@ namespace Unity.Netcode.RuntimeTests
Assert.AreEqual(clientSideClientId, clientSideClientPlayerObject.OwnerClientId);
}
private bool m_ClientDisconnected;
[UnityTest]
public IEnumerator TestConnectAndDisconnect()
{
@@ -120,11 +122,22 @@ namespace Unity.Netcode.RuntimeTests
// test when client disconnects, player object no longer available.
var nbConnectedClients = m_ServerNetworkManager.ConnectedClients.Count;
m_ClientDisconnected = false;
newClientNetworkManager.OnClientDisconnectCallback += ClientNetworkManager_OnClientDisconnectCallback;
m_ServerNetworkManager.DisconnectClient(newClientLocalClientId);
yield return WaitForConditionOrTimeOut(() => m_ClientDisconnected);
Assert.IsFalse(s_GlobalTimeoutHelper.TimedOut, "Timed out waiting for client to disconnect");
// Call this to clean up NetcodeIntegrationTestHelpers
NetcodeIntegrationTestHelpers.StopOneClient(newClientNetworkManager);
yield return WaitForConditionOrTimeOut(() => m_ServerNetworkManager.ConnectedClients.Count == nbConnectedClients - 1);
Assert.AreEqual(m_ServerNetworkManager.ConnectedClients.Count, nbConnectedClients - 1);
serverSideNewClientPlayer = m_ServerNetworkManager.SpawnManager.GetPlayerNetworkObject(newClientLocalClientId);
Assert.Null(serverSideNewClientPlayer);
}
private void ClientNetworkManager_OnClientDisconnectCallback(ulong obj)
{
m_ClientDisconnected = true;
}
}
}

View File

@@ -0,0 +1,277 @@
#if COM_UNITY_MODULES_PHYSICS
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using Unity.Netcode.Components;
using NUnit.Framework;
using UnityEngine;
using UnityEngine.TestTools;
using Unity.Netcode.TestHelpers.Runtime;
namespace Unity.Netcode.RuntimeTests
{
public class NetworkTransformOwnershipTests : NetcodeIntegrationTest
{
protected override int NumberOfClients => 1;
private GameObject m_ClientNetworkTransformPrefab;
private GameObject m_NetworkTransformPrefab;
protected override void OnServerAndClientsCreated()
{
VerifyObjectIsSpawnedOnClient.ResetObjectTable();
m_ClientNetworkTransformPrefab = CreateNetworkObjectPrefab("OwnerAuthorityTest");
var clientNetworkTransform = m_ClientNetworkTransformPrefab.AddComponent<TestClientNetworkTransform>();
clientNetworkTransform.Interpolate = false;
var rigidBody = m_ClientNetworkTransformPrefab.AddComponent<Rigidbody>();
rigidBody.useGravity = false;
m_ClientNetworkTransformPrefab.AddComponent<NetworkRigidbody>();
m_ClientNetworkTransformPrefab.AddComponent<SphereCollider>();
m_ClientNetworkTransformPrefab.AddComponent<VerifyObjectIsSpawnedOnClient>();
m_NetworkTransformPrefab = CreateNetworkObjectPrefab("ServerAuthorityTest");
var networkTransform = m_NetworkTransformPrefab.AddComponent<NetworkTransform>();
rigidBody = m_NetworkTransformPrefab.AddComponent<Rigidbody>();
rigidBody.useGravity = false;
m_NetworkTransformPrefab.AddComponent<NetworkRigidbody>();
m_NetworkTransformPrefab.AddComponent<SphereCollider>();
m_NetworkTransformPrefab.AddComponent<VerifyObjectIsSpawnedOnClient>();
networkTransform.Interpolate = false;
base.OnServerAndClientsCreated();
}
public enum StartingOwnership
{
HostStartsAsOwner,
ClientStartsAsOwner,
}
/// <summary>
/// This verifies that when authority is owner authoritative the owner's
/// Rigidbody is kinematic and the non-owner's is not.
/// This also verifies that we can switch between owners and that only the
/// owner can update the transform while non-owners cannot.
/// </summary>
/// <param name="spawnWithHostOwnership">determines who starts as the owner (true): host | (false): client</param>
[UnityTest]
public IEnumerator OwnerAuthoritativeTest([Values] StartingOwnership startingOwnership)
{
// Get the current ownership layout
var networkManagerOwner = startingOwnership == StartingOwnership.HostStartsAsOwner ? m_ServerNetworkManager : m_ClientNetworkManagers[0];
var networkManagerNonOwner = startingOwnership == StartingOwnership.HostStartsAsOwner ? m_ClientNetworkManagers[0] : m_ServerNetworkManager;
// Spawn the m_ClientNetworkTransformPrefab and wait for the client-side to spawn the object
var serverSideInstance = SpawnObject(m_ClientNetworkTransformPrefab, networkManagerOwner);
yield return WaitForConditionOrTimeOut(() => VerifyObjectIsSpawnedOnClient.GetClientsThatSpawnedThisPrefab().Contains(m_ClientNetworkManagers[0].LocalClientId));
// Get owner relative instances
var ownerInstance = VerifyObjectIsSpawnedOnClient.GetClientInstance(networkManagerOwner.LocalClientId);
var nonOwnerInstance = VerifyObjectIsSpawnedOnClient.GetClientInstance(networkManagerNonOwner.LocalClientId);
Assert.NotNull(ownerInstance);
Assert.NotNull(nonOwnerInstance);
// Make sure the owner is not kinematic and the non-owner(s) are kinematic
Assert.True(nonOwnerInstance.GetComponent<Rigidbody>().isKinematic, $"{networkManagerNonOwner.name}'s object instance {nonOwnerInstance.name} is not kinematic when it should be!");
Assert.False(ownerInstance.GetComponent<Rigidbody>().isKinematic, $"{networkManagerOwner.name}'s object instance {ownerInstance.name} is kinematic when it should not be!");
// Owner changes transform values
var valueSetByOwner = Vector3.one * 2;
ownerInstance.transform.position = valueSetByOwner;
ownerInstance.transform.localScale = valueSetByOwner;
var rotation = new Quaternion();
rotation.eulerAngles = valueSetByOwner;
ownerInstance.transform.rotation = rotation;
var transformToTest = nonOwnerInstance.transform;
yield return WaitForConditionOrTimeOut(() => transformToTest.position == valueSetByOwner && transformToTest.localScale == valueSetByOwner && transformToTest.rotation == rotation);
Assert.False(s_GlobalTimeoutHelper.TimedOut, $"Timed out waiting for {networkManagerNonOwner.name}'s object instance {nonOwnerInstance.name} to change its transform!\n" +
$"Expected Position: {valueSetByOwner} | Current Position: {transformToTest.position}\n" +
$"Expected Rotation: {valueSetByOwner} | Current Rotation: {transformToTest.rotation.eulerAngles}\n" +
$"Expected Scale: {valueSetByOwner} | Current Scale: {transformToTest.localScale}");
// Verify non-owners cannot change transform values
nonOwnerInstance.transform.position = Vector3.zero;
yield return s_DefaultWaitForTick;
Assert.True(nonOwnerInstance.transform.position == valueSetByOwner, $"{networkManagerNonOwner.name}'s object instance {nonOwnerInstance.name} was allowed to change its position! Expected: {Vector3.one} Is Currently:{nonOwnerInstance.transform.position}");
// Change ownership and wait for the non-owner to reflect the change
VerifyObjectIsSpawnedOnClient.ResetObjectTable();
m_ServerNetworkManager.SpawnManager.ChangeOwnership(serverSideInstance.GetComponent<NetworkObject>(), networkManagerNonOwner.LocalClientId);
yield return WaitForConditionOrTimeOut(() => nonOwnerInstance.GetComponent<NetworkObject>().OwnerClientId == networkManagerNonOwner.LocalClientId);
Assert.False(s_GlobalTimeoutHelper.TimedOut, $"Timed out waiting for {networkManagerNonOwner.name}'s object instance {nonOwnerInstance.name} to change ownership!");
// Re-assign the ownership references and wait for the non-owner instance to be notified of ownership change
networkManagerOwner = startingOwnership == StartingOwnership.HostStartsAsOwner ? m_ClientNetworkManagers[0] : m_ServerNetworkManager;
networkManagerNonOwner = startingOwnership == StartingOwnership.HostStartsAsOwner ? m_ServerNetworkManager : m_ClientNetworkManagers[0];
ownerInstance = VerifyObjectIsSpawnedOnClient.GetClientInstance(networkManagerOwner.LocalClientId);
Assert.NotNull(ownerInstance);
yield return WaitForConditionOrTimeOut(() => VerifyObjectIsSpawnedOnClient.GetClientInstance(networkManagerNonOwner.LocalClientId) != null);
nonOwnerInstance = VerifyObjectIsSpawnedOnClient.GetClientInstance(networkManagerNonOwner.LocalClientId);
Assert.NotNull(nonOwnerInstance);
// Make sure the owner is not kinematic and the non-owner(s) are kinematic
Assert.False(ownerInstance.GetComponent<Rigidbody>().isKinematic, $"{networkManagerOwner.name}'s object instance {ownerInstance.name} is kinematic when it should not be!");
Assert.True(nonOwnerInstance.GetComponent<Rigidbody>().isKinematic, $"{networkManagerNonOwner.name}'s object instance {nonOwnerInstance.name} is not kinematic when it should be!");
// Have the new owner change transform values and wait for those values to be applied on the non-owner side.
valueSetByOwner = Vector3.one * 50;
ownerInstance.transform.position = valueSetByOwner;
ownerInstance.transform.localScale = valueSetByOwner;
rotation.eulerAngles = valueSetByOwner;
ownerInstance.transform.rotation = rotation;
transformToTest = nonOwnerInstance.transform;
yield return WaitForConditionOrTimeOut(() => transformToTest.position == valueSetByOwner && transformToTest.localScale == valueSetByOwner && transformToTest.rotation == rotation);
Assert.False(s_GlobalTimeoutHelper.TimedOut, $"Timed out waiting for {networkManagerNonOwner.name}'s object instance {nonOwnerInstance.name} to change its transform!\n" +
$"Expected Position: {valueSetByOwner} | Current Position: {transformToTest.position}\n" +
$"Expected Rotation: {valueSetByOwner} | Current Rotation: {transformToTest.rotation.eulerAngles}\n" +
$"Expected Scale: {valueSetByOwner} | Current Scale: {transformToTest.localScale}");
// The last check is to verify non-owners cannot change transform values after ownership has changed
nonOwnerInstance.transform.position = Vector3.zero;
yield return s_DefaultWaitForTick;
Assert.True(nonOwnerInstance.transform.position == valueSetByOwner, $"{networkManagerNonOwner.name}'s object instance {nonOwnerInstance.name} was allowed to change its position! Expected: {Vector3.one} Is Currently:{nonOwnerInstance.transform.position}");
}
/// <summary>
/// This verifies that when authority is server authoritative the
/// client's Rigidbody is kinematic and the server is not.
/// This also verifies only the server can apply updates to the
/// transform while the clients cannot.
/// </summary>
[UnityTest]
public IEnumerator ServerAuthoritativeTest()
{
// Spawn the m_NetworkTransformPrefab and wait for the client-side to spawn the object
var serverSideInstance = SpawnObject(m_NetworkTransformPrefab, m_ServerNetworkManager);
yield return WaitForConditionOrTimeOut(() => VerifyObjectIsSpawnedOnClient.GetClientsThatSpawnedThisPrefab().Contains(m_ClientNetworkManagers[0].LocalClientId));
var ownerInstance = VerifyObjectIsSpawnedOnClient.GetClientInstance(m_ServerNetworkManager.LocalClientId);
var nonOwnerInstance = VerifyObjectIsSpawnedOnClient.GetClientInstance(m_ClientNetworkManagers[0].LocalClientId);
// Make sure the owner is not kinematic and the non-owner(s) are kinematic
Assert.False(ownerInstance.GetComponent<Rigidbody>().isKinematic, $"{m_ServerNetworkManager.name}'s object instance {ownerInstance.name} is kinematic when it should not be!");
Assert.True(nonOwnerInstance.GetComponent<Rigidbody>().isKinematic, $"{m_ClientNetworkManagers[0].name}'s object instance {nonOwnerInstance.name} is not kinematic when it should be!");
// Server changes transform values
var valueSetByOwner = Vector3.one * 2;
ownerInstance.transform.position = valueSetByOwner;
ownerInstance.transform.localScale = valueSetByOwner;
var rotation = new Quaternion();
rotation.eulerAngles = valueSetByOwner;
ownerInstance.transform.rotation = rotation;
var transformToTest = nonOwnerInstance.transform;
yield return WaitForConditionOrTimeOut(() => transformToTest.position == valueSetByOwner && transformToTest.localScale == valueSetByOwner && transformToTest.rotation == rotation);
Assert.False(s_GlobalTimeoutHelper.TimedOut, $"Timed out waiting for {m_ClientNetworkManagers[0].name}'s object instance {nonOwnerInstance.name} to change its transform!\n" +
$"Expected Position: {valueSetByOwner} | Current Position: {transformToTest.position}\n" +
$"Expected Rotation: {valueSetByOwner} | Current Rotation: {transformToTest.rotation.eulerAngles}\n" +
$"Expected Scale: {valueSetByOwner} | Current Scale: {transformToTest.localScale}");
// The last check is to verify clients cannot change transform values
nonOwnerInstance.transform.position = Vector3.zero;
yield return s_DefaultWaitForTick;
Assert.True(nonOwnerInstance.transform.position == valueSetByOwner, $"{m_ClientNetworkManagers[0].name}'s object instance {nonOwnerInstance.name} was allowed to change its position! Expected: {Vector3.one} Is Currently:{nonOwnerInstance.transform.position}");
}
/// <summary>
/// NetworkTransformOwnershipTests helper behaviour
/// </summary>
public class VerifyObjectIsSpawnedOnClient : NetworkBehaviour
{
private static Dictionary<ulong, VerifyObjectIsSpawnedOnClient> s_NetworkManagerRelativeSpawnedObjects = new Dictionary<ulong, VerifyObjectIsSpawnedOnClient>();
public static void ResetObjectTable()
{
s_NetworkManagerRelativeSpawnedObjects.Clear();
}
public override void OnGainedOwnership()
{
if (!s_NetworkManagerRelativeSpawnedObjects.ContainsKey(NetworkManager.LocalClientId))
{
s_NetworkManagerRelativeSpawnedObjects.Add(NetworkManager.LocalClientId, this);
}
base.OnGainedOwnership();
}
public override void OnLostOwnership()
{
if (!s_NetworkManagerRelativeSpawnedObjects.ContainsKey(NetworkManager.LocalClientId))
{
s_NetworkManagerRelativeSpawnedObjects.Add(NetworkManager.LocalClientId, this);
}
base.OnLostOwnership();
}
public static List<ulong> GetClientsThatSpawnedThisPrefab()
{
return s_NetworkManagerRelativeSpawnedObjects.Keys.ToList();
}
public static VerifyObjectIsSpawnedOnClient GetClientInstance(ulong clientId)
{
if (s_NetworkManagerRelativeSpawnedObjects.ContainsKey(clientId))
{
return s_NetworkManagerRelativeSpawnedObjects[clientId];
}
return null;
}
public override void OnNetworkSpawn()
{
// This makes sure that the NetworkManager relative NetworkObject instances don't collide with each other
// and skew the expected changes to the transforms
foreach (var entry in s_NetworkManagerRelativeSpawnedObjects)
{
Physics.IgnoreCollision(entry.Value.GetComponent<SphereCollider>(), GetComponent<SphereCollider>());
}
if (!s_NetworkManagerRelativeSpawnedObjects.ContainsKey(NetworkManager.LocalClientId))
{
s_NetworkManagerRelativeSpawnedObjects.Add(NetworkManager.LocalClientId, this);
}
base.OnNetworkSpawn();
}
public override void OnNetworkDespawn()
{
if (s_NetworkManagerRelativeSpawnedObjects.ContainsKey(NetworkManager.LocalClientId))
{
s_NetworkManagerRelativeSpawnedObjects.Remove(NetworkManager.LocalClientId);
}
base.OnNetworkDespawn();
}
}
/// <summary>
/// Until we can better locate the ClientNetworkTransform
/// This will have to be used to verify the ownership authority
/// </summary>
[DisallowMultipleComponent]
public class TestClientNetworkTransform : NetworkTransform
{
public override void OnNetworkSpawn()
{
base.OnNetworkSpawn();
CanCommitToTransform = IsOwner;
}
protected override void Update()
{
CanCommitToTransform = IsOwner;
base.Update();
if (NetworkManager.Singleton != null && (NetworkManager.Singleton.IsConnectedClient || NetworkManager.Singleton.IsListening))
{
if (CanCommitToTransform)
{
TryCommitTransformToServer(transform, NetworkManager.LocalTime.Time);
}
}
}
protected override bool OnIsServerAuthoritatitive()
{
return false;
}
}
}
}
#endif

View File

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

View File

@@ -22,6 +22,11 @@ namespace Unity.Netcode.RuntimeTests
ReadyToReceivePositionUpdate = true;
}
public (bool isDirty, bool isPositionDirty, bool isRotationDirty, bool isScaleDirty) ApplyState()
{
return ApplyLocalNetworkState(transform);
}
}
// [TestFixture(true, true)]
@@ -172,6 +177,80 @@ namespace Unity.Netcode.RuntimeTests
#endif
}
/// <summary>
/// Validates that rotation checks don't produce false positive
/// results when rolling over between 0 and 360 degrees
/// </summary>
[UnityTest]
public IEnumerator TestRotationThresholdDeltaCheck()
{
// Get the client player's NetworkTransform for both instances
var authoritativeNetworkTransform = m_ServerSideClientPlayer.GetComponent<NetworkTransformTestComponent>();
var otherSideNetworkTransform = m_ClientSideClientPlayer.GetComponent<NetworkTransformTestComponent>();
otherSideNetworkTransform.RotAngleThreshold = authoritativeNetworkTransform.RotAngleThreshold = 5.0f;
var halfThreshold = authoritativeNetworkTransform.RotAngleThreshold * 0.5001f;
var serverRotation = authoritativeNetworkTransform.transform.rotation;
var serverEulerRotation = serverRotation.eulerAngles;
// Verify rotation is not marked dirty when rotated by half of the threshold
serverEulerRotation.y += halfThreshold;
serverRotation.eulerAngles = serverEulerRotation;
authoritativeNetworkTransform.transform.rotation = serverRotation;
var results = authoritativeNetworkTransform.ApplyState();
Assert.IsFalse(results.isRotationDirty, $"Rotation is dirty when rotation threshold is {authoritativeNetworkTransform.RotAngleThreshold} degrees and only adjusted by {halfThreshold} degrees!");
yield return s_DefaultWaitForTick;
// Verify rotation is marked dirty when rotated by another half threshold value
serverEulerRotation.y += halfThreshold;
serverRotation.eulerAngles = serverEulerRotation;
authoritativeNetworkTransform.transform.rotation = serverRotation;
results = authoritativeNetworkTransform.ApplyState();
Assert.IsTrue(results.isRotationDirty, $"Rotation was not dirty when rotated by the threshold value: {authoritativeNetworkTransform.RotAngleThreshold} degrees!");
yield return s_DefaultWaitForTick;
//Reset rotation back to zero on all axis
serverRotation.eulerAngles = serverEulerRotation = Vector3.zero;
authoritativeNetworkTransform.transform.rotation = serverRotation;
yield return s_DefaultWaitForTick;
// Rotate by 360 minus halfThreshold (which is really just negative halfThreshold) and verify rotation is not marked dirty
serverEulerRotation.y = 360 - halfThreshold;
serverRotation.eulerAngles = serverEulerRotation;
authoritativeNetworkTransform.transform.rotation = serverRotation;
results = authoritativeNetworkTransform.ApplyState();
Assert.IsFalse(results.isRotationDirty, $"Rotation is dirty when rotation threshold is {authoritativeNetworkTransform.RotAngleThreshold} degrees and only adjusted by " +
$"{Mathf.DeltaAngle(0, serverEulerRotation.y)} degrees!");
serverEulerRotation.y -= halfThreshold;
serverRotation.eulerAngles = serverEulerRotation;
authoritativeNetworkTransform.transform.rotation = serverRotation;
results = authoritativeNetworkTransform.ApplyState();
Assert.IsTrue(results.isRotationDirty, $"Rotation was not dirty when rotated by {Mathf.DeltaAngle(0, serverEulerRotation.y)} degrees!");
//Reset rotation back to zero on all axis
serverRotation.eulerAngles = serverEulerRotation = Vector3.zero;
authoritativeNetworkTransform.transform.rotation = serverRotation;
yield return s_DefaultWaitForTick;
serverEulerRotation.y -= halfThreshold;
serverRotation.eulerAngles = serverEulerRotation;
authoritativeNetworkTransform.transform.rotation = serverRotation;
results = authoritativeNetworkTransform.ApplyState();
Assert.IsFalse(results.isRotationDirty, $"Rotation is dirty when rotation threshold is {authoritativeNetworkTransform.RotAngleThreshold} degrees and only adjusted by " +
$"{Mathf.DeltaAngle(0, serverEulerRotation.y)} degrees!");
serverEulerRotation.y -= halfThreshold;
serverRotation.eulerAngles = serverEulerRotation;
authoritativeNetworkTransform.transform.rotation = serverRotation;
results = authoritativeNetworkTransform.ApplyState();
Assert.IsTrue(results.isRotationDirty, $"Rotation was not dirty when rotated by {Mathf.DeltaAngle(0, serverEulerRotation.y)} degrees!");
}
/*
* ownership change
* test teleport with interpolation

View File

@@ -273,9 +273,9 @@ namespace Unity.Netcode.RuntimeTests
{
public readonly NetworkVariable<int> TheScalar = new NetworkVariable<int>();
public readonly NetworkList<int> TheList = new NetworkList<int>();
public readonly NetworkList<FixedString128Bytes> TheLargeList = new NetworkList<FixedString128Bytes>();
public readonly NetworkList<ForceNetworkSerializeByMemcpy<FixedString128Bytes>> TheLargeList = new NetworkList<ForceNetworkSerializeByMemcpy<FixedString128Bytes>>();
public readonly NetworkVariable<FixedString32Bytes> FixedString32 = new NetworkVariable<FixedString32Bytes>();
public readonly NetworkVariable<ForceNetworkSerializeByMemcpy<FixedString32Bytes>> FixedString32 = new NetworkVariable<ForceNetworkSerializeByMemcpy<FixedString32Bytes>>();
private void ListChanged(NetworkListEvent<int> e)
{
@@ -306,7 +306,8 @@ namespace Unity.Netcode.RuntimeTests
[TestFixture(false)]
public class NetworkVariableTests : NetcodeIntegrationTest
{
private const string k_FixedStringTestValue = "abcdefghijklmnopqrstuvwxyz";
private const string k_StringTestValue = "abcdefghijklmnopqrstuvwxyz";
private static readonly FixedString32Bytes k_FixedStringTestValue = k_StringTestValue;
protected override int NumberOfClients => 2;
private const uint k_TestUInt = 0x12345678;

View File

@@ -8,29 +8,16 @@ using Unity.Netcode.TestHelpers.Runtime;
namespace Unity.Netcode.RuntimeTests
{
public class NetworkRigidbodyDynamicTest : NetworkRigidbodyTestBase
{
public override bool Kinematic => false;
}
public class NetworkRigidbodyKinematicTest : NetworkRigidbodyTestBase
{
public override bool Kinematic => true;
}
public abstract class NetworkRigidbodyTestBase : NetcodeIntegrationTest
public class NetworkRigidbodyTest : NetcodeIntegrationTest
{
protected override int NumberOfClients => 1;
public abstract bool Kinematic { get; }
protected override void OnCreatePlayerPrefab()
{
m_PlayerPrefab.AddComponent<NetworkTransform>();
m_PlayerPrefab.AddComponent<Rigidbody>();
m_PlayerPrefab.AddComponent<NetworkRigidbody>();
m_PlayerPrefab.GetComponent<Rigidbody>().interpolation = RigidbodyInterpolation.Interpolate;
m_PlayerPrefab.GetComponent<Rigidbody>().isKinematic = Kinematic;
}
/// <summary>
@@ -55,8 +42,8 @@ namespace Unity.Netcode.RuntimeTests
yield return NetcodeIntegrationTestHelpers.WaitForTicks(m_ServerNetworkManager, 3);
// server rigidbody has authority and should have a kinematic mode of false
Assert.True(serverPlayer.GetComponent<Rigidbody>().isKinematic == Kinematic, "serverPlayer kinematic");
// server rigidbody has authority and should not be kinematic
Assert.True(serverPlayer.GetComponent<Rigidbody>().isKinematic == false, "serverPlayer kinematic");
Assert.AreEqual(RigidbodyInterpolation.Interpolate, serverPlayer.GetComponent<Rigidbody>().interpolation, "server equal interpolate");
// client rigidbody has no authority and should have a kinematic mode of true
@@ -68,7 +55,8 @@ namespace Unity.Netcode.RuntimeTests
yield return NetcodeIntegrationTestHelpers.WaitForTicks(m_ServerNetworkManager, 3);
Assert.IsTrue(serverPlayer.GetComponent<Rigidbody>().isKinematic == Kinematic, "serverPlayer second kinematic");
// When despawned, we should always be kinematic (i.e. don't apply physics when despawned)
Assert.IsTrue(serverPlayer.GetComponent<Rigidbody>().isKinematic == true, "serverPlayer second kinematic");
yield return NetcodeIntegrationTestHelpers.WaitForTicks(m_ServerNetworkManager, 3);

View File

@@ -4,6 +4,7 @@ using System.Collections.Generic;
using NUnit.Framework;
using UnityEngine.TestTools;
using Unity.Netcode.TestHelpers.Runtime;
using UnityEngine;
using Debug = UnityEngine.Debug;
namespace Unity.Netcode.RuntimeTests
@@ -13,6 +14,7 @@ namespace Unity.Netcode.RuntimeTests
public class RpcTestNB : NetworkBehaviour
{
public event Action<ulong, ServerRpcParams> OnServer_Rpc;
public event Action<Vector3, Vector3[]> OnTypedServer_Rpc;
public event Action OnClient_Rpc;
[ServerRpc]
@@ -26,6 +28,12 @@ namespace Unity.Netcode.RuntimeTests
{
OnClient_Rpc();
}
[ServerRpc]
public void MyTypedServerRpc(Vector3 param1, Vector3[] param2)
{
OnTypedServer_Rpc(param1, param2);
}
}
protected override int NumberOfClients => 1;
@@ -46,9 +54,13 @@ namespace Unity.Netcode.RuntimeTests
// Setup state
bool hasReceivedServerRpc = false;
bool hasReceivedTypedServerRpc = false;
bool hasReceivedClientRpcRemotely = false;
bool hasReceivedClientRpcLocally = false;
var vector3 = new Vector3(1, 2, 3);
Vector3[] vector3s = new[] { new Vector3(4, 5, 6), new Vector3(7, 8, 9) };
localClienRpcTestNB.OnClient_Rpc += () =>
{
Debug.Log("ClientRpc received on client object");
@@ -75,9 +87,22 @@ namespace Unity.Netcode.RuntimeTests
hasReceivedClientRpcLocally = true;
};
serverClientRpcTestNB.OnTypedServer_Rpc += (param1, param2) =>
{
Debug.Log("TypedServerRpc received on server object");
Assert.AreEqual(param1, vector3);
Assert.AreEqual(param2.Length, vector3s.Length);
Assert.AreEqual(param2[0], vector3s[0]);
Assert.AreEqual(param2[1], vector3s[1]);
hasReceivedTypedServerRpc = true;
};
// Send ServerRpc
localClienRpcTestNB.MyServerRpc(m_ClientNetworkManagers[0].LocalClientId);
// Send TypedServerRpc
localClienRpcTestNB.MyTypedServerRpc(vector3, vector3s);
// Send ClientRpc
serverClientRpcTestNB.MyClientRpc();
@@ -86,6 +111,11 @@ namespace Unity.Netcode.RuntimeTests
var serverMessageHookEntry = new MessageHookEntry(m_ServerNetworkManager);
serverMessageHookEntry.AssignMessageType<ServerRpcMessage>();
messageHookList.Add(serverMessageHookEntry);
var typedServerMessageHookEntry = new MessageHookEntry(m_ServerNetworkManager);
typedServerMessageHookEntry.AssignMessageType<ServerRpcMessage>();
messageHookList.Add(typedServerMessageHookEntry);
foreach (var client in m_ClientNetworkManagers)
{
var clientMessageHookEntry = new MessageHookEntry(client);
@@ -97,9 +127,10 @@ namespace Unity.Netcode.RuntimeTests
Assert.False(s_GlobalTimeoutHelper.TimedOut, $"Timed out waiting for messages: {rpcMessageHooks.GetHooksStillWaiting()}");
// Make sure RPCs propagated all the way up and were called on the relative destination class instance
yield return WaitForConditionOrTimeOut(() => hasReceivedServerRpc && hasReceivedClientRpcLocally && hasReceivedClientRpcRemotely);
yield return WaitForConditionOrTimeOut(() => hasReceivedServerRpc && hasReceivedClientRpcLocally && hasReceivedClientRpcRemotely && hasReceivedTypedServerRpc);
Assert.True(hasReceivedServerRpc, "ServerRpc was not received");
Assert.True(hasReceivedTypedServerRpc, "TypedServerRpc was not received");
Assert.True(hasReceivedClientRpcLocally, "ClientRpc was not locally received on the server");
Assert.True(hasReceivedClientRpcRemotely, "ClientRpc was not remotely received on the client");
}

View File

@@ -6,69 +6,75 @@ using Unity.Netcode.TestHelpers.Runtime;
namespace Unity.Netcode.RuntimeTests
{
public class StopStartRuntimeTests
public class StopStartRuntimeTests : NetcodeIntegrationTest
{
protected override int NumberOfClients => 1;
protected override void OnOneTimeSetup()
{
m_UseHost = false;
base.OnOneTimeSetup();
}
[UnityTest]
public IEnumerator WhenShuttingDownAndRestarting_SDKRestartsSuccessfullyAndStaysRunning()
{ // create server and client instances
NetcodeIntegrationTestHelpers.Create(1, out NetworkManager server, out NetworkManager[] clients);
{
// shutdown the server
m_ServerNetworkManager.Shutdown();
try
{
// wait 1 frame because shutdowns are delayed
var nextFrameNumber = Time.frameCount + 1;
yield return new WaitUntil(() => Time.frameCount >= nextFrameNumber);
// create prefab
var gameObject = new GameObject("PlayerObject");
var networkObject = gameObject.AddComponent<NetworkObject>();
networkObject.DontDestroyWithOwner = true;
NetcodeIntegrationTestHelpers.MakeNetworkObjectTestPrefab(networkObject);
// Verify the shutdown occurred
Assert.IsFalse(m_ServerNetworkManager.IsServer);
Assert.IsFalse(m_ServerNetworkManager.IsListening);
Assert.IsFalse(m_ServerNetworkManager.IsHost);
Assert.IsFalse(m_ServerNetworkManager.IsClient);
server.NetworkConfig.PlayerPrefab = gameObject;
m_ServerNetworkManager.StartServer();
// Verify the server started
Assert.IsTrue(m_ServerNetworkManager.IsServer);
Assert.IsTrue(m_ServerNetworkManager.IsListening);
for (int i = 0; i < clients.Length; i++)
{
clients[i].NetworkConfig.PlayerPrefab = gameObject;
}
// Wait several frames / one full network tick
yield return s_DefaultWaitForTick;
// start server and connect clients
NetcodeIntegrationTestHelpers.Start(false, server, clients);
// Verify the server is still running
Assert.IsTrue(m_ServerNetworkManager.IsServer);
Assert.IsTrue(m_ServerNetworkManager.IsListening);
}
// wait for connection on client side
yield return NetcodeIntegrationTestHelpers.WaitForClientsConnected(clients);
[UnityTest]
public IEnumerator WhenShuttingDownTwiceAndRestarting_SDKRestartsSuccessfullyAndStaysRunning()
{
// shutdown the server
m_ServerNetworkManager.Shutdown();
// wait for connection on server side
yield return NetcodeIntegrationTestHelpers.WaitForClientConnectedToServer(server);
// wait 1 frame because shutdowns are delayed
var nextFrameNumber = Time.frameCount + 1;
yield return new WaitUntil(() => Time.frameCount >= nextFrameNumber);
// shutdown the server
server.Shutdown();
// Verify the shutdown occurred
Assert.IsFalse(m_ServerNetworkManager.IsServer);
Assert.IsFalse(m_ServerNetworkManager.IsListening);
Assert.IsFalse(m_ServerNetworkManager.IsHost);
Assert.IsFalse(m_ServerNetworkManager.IsClient);
// wait 1 frame because shutdowns are delayed
var nextFrameNumber = Time.frameCount + 1;
yield return new WaitUntil(() => Time.frameCount >= nextFrameNumber);
// Shutdown the server again.
m_ServerNetworkManager.Shutdown();
// Verify the shutdown occurred
Assert.IsFalse(server.IsServer);
Assert.IsFalse(server.IsListening);
Assert.IsFalse(server.IsHost);
Assert.IsFalse(server.IsClient);
m_ServerNetworkManager.StartServer();
// Verify the server started
Assert.IsTrue(m_ServerNetworkManager.IsServer);
Assert.IsTrue(m_ServerNetworkManager.IsListening);
server.StartServer();
// Verify the server started
Assert.IsTrue(server.IsServer);
Assert.IsTrue(server.IsListening);
// Wait several frames / one full network tick
yield return s_DefaultWaitForTick;
// Wait several frames
nextFrameNumber = Time.frameCount + 10;
yield return new WaitUntil(() => Time.frameCount >= nextFrameNumber);
// Verify the server is still running
Assert.IsTrue(server.IsServer);
Assert.IsTrue(server.IsListening);
}
finally
{
// cleanup
NetcodeIntegrationTestHelpers.Destroy();
}
// Verify the server is still running
Assert.IsTrue(m_ServerNetworkManager.IsServer);
Assert.IsTrue(m_ServerNetworkManager.IsListening);
}
}
}

View File

@@ -89,8 +89,13 @@ namespace Unity.Netcode.RuntimeTests
// compares the two client times, only difference should be based on buffering.
m_Client1State.AssertCheckDifference(m_Client2State, 0.2 - tickInterval, (0.1 - tickInterval), tickInterval * 2 + frameInterval * 2 + k_AdditionalTimeTolerance);
}
}
protected override IEnumerator OnTearDown()
{
// Always "shutdown in a tear-down" otherwise you can cause all proceeding tests to fail
ShutdownAndCleanUp();
yield return base.OnTearDown();
}
// This is from NetcodeIntegrationTest but we need a custom version of this to modifiy the config

View File

@@ -57,12 +57,15 @@ namespace Unity.Netcode.RuntimeTests
{
protected override int NumberOfClients => 1;
private ulong m_ClientId0;
private GameObject m_PrefabToSpawn;
private NetworkObject m_AsNetworkObject;
private NetworkObject m_SpawnedAsNetworkObject;
private NetworkObject m_SpawnedObjectOnClient;
private NetworkObject m_BaseAsNetworkObject;
private NetworkObject m_BaseOnClient;
protected override void OnServerAndClientsCreated()
{
m_PrefabToSpawn = CreateNetworkObjectPrefab("InterpTestObject");
@@ -74,41 +77,59 @@ namespace Unity.Netcode.RuntimeTests
{
var clientId = m_ClientNetworkManagers[0].LocalClientId;
yield return WaitForConditionOrTimeOut(() => s_GlobalNetworkObjects.ContainsKey(clientId) &&
s_GlobalNetworkObjects[clientId].ContainsKey(m_AsNetworkObject.NetworkObjectId));
s_GlobalNetworkObjects[clientId].ContainsKey(m_BaseAsNetworkObject.NetworkObjectId) &&
s_GlobalNetworkObjects[clientId].ContainsKey(m_SpawnedAsNetworkObject.NetworkObjectId));
Assert.False(s_GlobalTimeoutHelper.TimedOut, $"Timed out waiting for client side {nameof(NetworkObject)} ID of {m_AsNetworkObject.NetworkObjectId}");
m_SpawnedObjectOnClient = s_GlobalNetworkObjects[clientId][m_AsNetworkObject.NetworkObjectId];
Assert.False(s_GlobalTimeoutHelper.TimedOut, $"Timed out waiting for client side {nameof(NetworkObject)} ID of {m_SpawnedAsNetworkObject.NetworkObjectId}");
m_BaseOnClient = s_GlobalNetworkObjects[clientId][m_BaseAsNetworkObject.NetworkObjectId];
// make sure the objects are set with the right network manager
m_BaseOnClient.NetworkManagerOwner = m_ClientNetworkManagers[0];
m_SpawnedObjectOnClient = s_GlobalNetworkObjects[clientId][m_SpawnedAsNetworkObject.NetworkObjectId];
// make sure the objects are set with the right network manager
m_SpawnedObjectOnClient.NetworkManagerOwner = m_ClientNetworkManagers[0];
}
[UnityTest]
public IEnumerator TransformInterpolationTest()
{
m_ClientId0 = m_ClientNetworkManagers[0].LocalClientId;
// create an object
var spawnedObject = Object.Instantiate(m_PrefabToSpawn);
var baseObject = Object.Instantiate(m_PrefabToSpawn);
baseObject.GetComponent<NetworkObject>().NetworkManagerOwner = m_ServerNetworkManager;
baseObject.GetComponent<NetworkObject>().Spawn();
m_AsNetworkObject = spawnedObject.GetComponent<NetworkObject>();
m_AsNetworkObject.NetworkManagerOwner = m_ServerNetworkManager;
m_SpawnedAsNetworkObject = spawnedObject.GetComponent<NetworkObject>();
m_SpawnedAsNetworkObject.NetworkManagerOwner = m_ServerNetworkManager;
m_AsNetworkObject.TrySetParent(baseObject);
m_BaseAsNetworkObject = baseObject.GetComponent<NetworkObject>();
m_BaseAsNetworkObject.NetworkManagerOwner = m_ServerNetworkManager;
m_AsNetworkObject.Spawn();
m_SpawnedAsNetworkObject.TrySetParent(baseObject);
m_SpawnedAsNetworkObject.Spawn();
yield return RefreshNetworkObjects();
m_AsNetworkObject.TrySetParent(baseObject);
m_SpawnedAsNetworkObject.TrySetParent(baseObject);
baseObject.GetComponent<TransformInterpolationObject>().IsFixed = true;
spawnedObject.GetComponent<TransformInterpolationObject>().IsMoving = true;
// Give two seconds for the object to settle
yield return new WaitForSeconds(2.0f);
const float maxPlacementError = 0.01f;
// Wait for the base object to place itself on both instances
while (m_BaseOnClient.transform.position.y < 1000 - maxPlacementError ||
m_BaseOnClient.transform.position.y > 1000 + maxPlacementError ||
baseObject.transform.position.y < 1000 - maxPlacementError ||
baseObject.transform.position.y > 1000 + maxPlacementError)
{
yield return new WaitForSeconds(0.01f);
}
m_SpawnedObjectOnClient.GetComponent<TransformInterpolationObject>().CheckPosition = true;

View File

@@ -1,53 +0,0 @@
using System;
using System.Text;
using NUnit.Framework;
using UnityEngine;
using Unity.Netcode.TestHelpers.Runtime;
namespace Unity.Netcode.RuntimeTests
{
public class SIPTransportTests
{
[Test]
public void SendReceiveData()
{
SIPTransport server = new GameObject("Server").AddComponent<SIPTransport>();
SIPTransport client = new GameObject("Client").AddComponent<SIPTransport>();
server.Initialize();
server.StartServer();
client.Initialize();
client.StartClient();
NetworkEvent serverEvent = server.PollEvent(out ulong clientId, out _, out _);
NetworkEvent clientEvent = client.PollEvent(out ulong serverId, out _, out _);
// Make sure both connected
Assert.True(serverEvent == NetworkEvent.Connect);
Assert.True(clientEvent == NetworkEvent.Connect);
// Send data
server.Send(clientId, new ArraySegment<byte>(Encoding.ASCII.GetBytes("Hello Client")), NetworkDelivery.ReliableSequenced);
client.Send(serverId, new ArraySegment<byte>(Encoding.ASCII.GetBytes("Hello Server")), NetworkDelivery.ReliableSequenced);
serverEvent = server.PollEvent(out ulong newClientId, out ArraySegment<byte> serverPayload, out _);
clientEvent = client.PollEvent(out ulong newServerId, out ArraySegment<byte> clientPayload, out _);
// Make sure we got data
Assert.True(serverEvent == NetworkEvent.Data);
Assert.True(clientEvent == NetworkEvent.Data);
// Make sure the ID is correct
Assert.True(newClientId == clientId);
Assert.True(newServerId == serverId);
// Make sure the payload was correct
Assert.That(serverPayload, Is.EquivalentTo(Encoding.ASCII.GetBytes("Hello Server")));
Assert.That(clientPayload, Is.EquivalentTo(Encoding.ASCII.GetBytes("Hello Client")));
server.Shutdown();
client.Shutdown();
}
}
}

View File

@@ -1,3 +0,0 @@
fileFormatVersion: 2
guid: e3fe3777ca6a4f4392d6281d148d0d3c
timeCreated: 1620385694

View File

@@ -31,6 +31,11 @@
"name": "com.unity.multiplayer.tools",
"expression": "1.0.0-pre.7",
"define": "MULTIPLAYER_TOOLS_1_0_0_PRE_7"
},
{
"name": "com.unity.modules.physics",
"expression": "",
"define": "COM_UNITY_MODULES_PHYSICS"
}
]
}
}