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"
}
]
}