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

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

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

## [1.0.0-pre.10] - 2022-06-21

### Added

- Added a new `OnTransportFailure` callback to `NetworkManager`. This callback is invoked when the manager's `NetworkTransport` encounters an unrecoverable error. Transport failures also cause the `NetworkManager` to shut down. Currently, this is only used by `UnityTransport` to signal a timeout of its connection to the Unity Relay servers. (#1994)
- Added `NetworkEvent.TransportFailure`, which can be used by implementations of `NetworkTransport` to signal to `NetworkManager` that an unrecoverable error was encountered. (#1994)
- Added test to ensure a warning occurs when nesting NetworkObjects in a NetworkPrefab (#1969)
- Added `NetworkManager.RemoveNetworkPrefab(...)` to remove a prefab from the prefabs list (#1950)

### Changed

- Updated `UnityTransport` dependency on `com.unity.transport` to 1.1.0. (#2025)
- (API Breaking) `ConnectionApprovalCallback` is no longer an `event` and will not allow more than 1 handler registered at a time. Also, `ConnectionApprovalCallback` is now a `Func<>` taking `ConnectionApprovalRequest` in and returning `ConnectionApprovalResponse` back out (#1972)

### Removed

### Fixed
- Fixed issue where dynamically spawned `NetworkObject`s could throw an exception if the scene of origin handle was zero (0) and the `NetworkObject` was already spawned. (#2017)
- Fixed issue where `NetworkObject.Observers` was not being cleared when despawned. (#2009)
- Fixed `NetworkAnimator` could not run in the server authoritative mode. (#2003)
- Fixed issue where late joining clients would get a soft synchronization error if any in-scene placed NetworkObjects were parented under another `NetworkObject`. (#1985)
- Fixed issue where `NetworkBehaviourReference` would throw a type cast exception if using `NetworkBehaviourReference.TryGet` and the component type was not found. (#1984)
- Fixed `NetworkSceneManager` was not sending scene event notifications for the currently active scene and any additively loaded scenes when loading a new scene in `LoadSceneMode.Single` mode. (#1975)
- Fixed issue where one or more clients disconnecting during a scene event would cause `LoadEventCompleted` or `UnloadEventCompleted` to wait until the `NetworkConfig.LoadSceneTimeOut` period before being triggered. (#1973)
- Fixed issues when multiple `ConnectionApprovalCallback`s were registered (#1972)
- Fixed a regression in serialization support: `FixedString`, `Vector2Int`, and `Vector3Int` types can now be used in NetworkVariables and RPCs again without requiring a `ForceNetworkSerializeByMemcpy<>` wrapper. (#1961)
- Fixed generic types that inherit from NetworkBehaviour causing crashes at compile time. (#1976)
- Fixed endless dialog boxes when adding a `NetworkBehaviour` to a `NetworkManager` or vice-versa. (#1947)
- Fixed `NetworkAnimator` issue where it was only synchronizing parameters if the layer or state changed or was transitioning between states. (#1946)
- Fixed `NetworkAnimator` issue where when it did detect a parameter had changed it would send all parameters as opposed to only the parameters that changed. (#1946)
- Fixed `NetworkAnimator` issue where it was not always disposing the `NativeArray` that is allocated when spawned. (#1946)
- Fixed `NetworkAnimator` issue where it was not taking the animation speed or state speed multiplier into consideration. (#1946)
- Fixed `NetworkAnimator` issue where it was not properly synchronizing late joining clients if they joined while `Animator` was transitioning between states. (#1946)
- Fixed `NetworkAnimator` issue where the server was not relaying changes to non-owner clients when a client was the owner. (#1946)
- Fixed issue where the `PacketLoss` metric for tools would return the packet loss over a connection lifetime instead of a single frame. (#2004)
This commit is contained in:
Unity Technologies
2022-06-21 00:00:00 +00:00
parent 5b1fc203ed
commit 0f7a30d285
62 changed files with 3763 additions and 1286 deletions

View File

@@ -1,6 +1,8 @@
using NUnit.Framework;
using UnityEngine;
using Unity.Netcode.Editor;
using UnityEditor.SceneManagement;
using UnityEngine.SceneManagement;
using UnityEngine.TestTools;
namespace Unity.Netcode.EditorTests
@@ -78,5 +80,37 @@ namespace Unity.Netcode.EditorTests
// Clean up
Object.DestroyImmediate(gameObject);
}
[Test]
public void NestedNetworkObjectPrefabCheck()
{
// Setup
var networkManagerObject = new GameObject(nameof(NestedNetworkObjectPrefabCheck));
var networkManager = networkManagerObject.AddComponent<NetworkManager>();
networkManager.NetworkConfig = new NetworkConfig();
var parent = new GameObject("Parent").AddComponent<NetworkObject>();
var child = new GameObject("Child").AddComponent<NetworkObject>();
// Set parent
child.transform.SetParent(parent.transform);
// Make it a prefab, warning only applies to prefabs
networkManager.AddNetworkPrefab(parent.gameObject);
// Mark scene as dirty to ensure OnValidate actually runs
EditorSceneManager.MarkSceneDirty(SceneManager.GetActiveScene());
// Force OnValidate
networkManager.OnValidate();
// Expect a warning
LogAssert.Expect(LogType.Warning, $"[Netcode] {NetworkManager.PrefabDebugHelper(networkManager.NetworkConfig.NetworkPrefabs[0])} has child {nameof(NetworkObject)}(s) but they will not be spawned across the network (unsupported {nameof(NetworkPrefab)} setup)");
// Clean up
Object.DestroyImmediate(networkManagerObject);
Object.DestroyImmediate(parent);
}
}
}

View File

@@ -220,6 +220,14 @@ namespace Unity.Netcode.EditorTests
{
RunTestWithWriteType(new Vector3((float)random.NextDouble(), (float)random.NextDouble(), (float)random.NextDouble()), writeType);
}
else if (testType == typeof(Vector2Int))
{
RunTestWithWriteType(new Vector2Int((int)random.NextDouble(), (int)random.NextDouble()), writeType);
}
else if (testType == typeof(Vector3Int))
{
RunTestWithWriteType(new Vector3Int((int)random.NextDouble(), (int)random.NextDouble(), (int)random.NextDouble()), writeType);
}
else if (testType == typeof(Vector4))
{
RunTestWithWriteType(new Vector4((float)random.NextDouble(), (float)random.NextDouble(), (float)random.NextDouble(), (float)random.NextDouble()), writeType);
@@ -495,6 +503,22 @@ namespace Unity.Netcode.EditorTests
new Vector3((float) random.NextDouble(), (float) random.NextDouble(), (float) random.NextDouble()),
}, writeType);
}
else if (testType == typeof(Vector2Int))
{
RunTypeTestLocal(new[]{
new Vector2Int((int) random.NextDouble(), (int) random.NextDouble()),
new Vector2Int((int) random.NextDouble(), (int) random.NextDouble()),
new Vector2Int((int) random.NextDouble(), (int) random.NextDouble()),
}, writeType);
}
else if (testType == typeof(Vector3Int))
{
RunTypeTestLocal(new[]{
new Vector3Int((int) random.NextDouble(), (int) random.NextDouble(), (int) random.NextDouble()),
new Vector3Int((int) random.NextDouble(), (int) random.NextDouble(), (int) random.NextDouble()),
new Vector3Int((int) random.NextDouble(), (int) random.NextDouble(), (int) random.NextDouble()),
}, writeType);
}
else if (testType == typeof(Vector4))
{
RunTypeTestLocal(new[]{

View File

@@ -351,8 +351,9 @@ namespace Unity.Netcode.EditorTests
[Values(typeof(byte), typeof(sbyte), typeof(short), typeof(ushort), typeof(int), typeof(uint),
typeof(long), typeof(ulong), typeof(bool), typeof(char), typeof(float), typeof(double),
typeof(ByteEnum), typeof(SByteEnum), typeof(ShortEnum), typeof(UShortEnum), typeof(IntEnum),
typeof(UIntEnum), typeof(LongEnum), typeof(ULongEnum), typeof(Vector2), typeof(Vector3), typeof(Vector4),
typeof(Quaternion), typeof(Color), typeof(Color32), typeof(Ray), typeof(Ray2D), typeof(TestStruct))]
typeof(UIntEnum), typeof(LongEnum), typeof(ULongEnum), typeof(Vector2), typeof(Vector3),
typeof(Vector2Int), typeof(Vector3Int), typeof(Vector4), typeof(Quaternion), typeof(Color),
typeof(Color32), typeof(Ray), typeof(Ray2D), typeof(TestStruct))]
Type testType,
[Values] WriteType writeType)
{
@@ -364,14 +365,156 @@ namespace Unity.Netcode.EditorTests
[Values(typeof(byte), typeof(sbyte), typeof(short), typeof(ushort), typeof(int), typeof(uint),
typeof(long), typeof(ulong), typeof(bool), typeof(char), typeof(float), typeof(double),
typeof(ByteEnum), typeof(SByteEnum), typeof(ShortEnum), typeof(UShortEnum), typeof(IntEnum),
typeof(UIntEnum), typeof(LongEnum), typeof(ULongEnum), typeof(Vector2), typeof(Vector3), typeof(Vector4),
typeof(Quaternion), typeof(Color), typeof(Color32), typeof(Ray), typeof(Ray2D), typeof(TestStruct))]
typeof(UIntEnum), typeof(LongEnum), typeof(ULongEnum), typeof(Vector2), typeof(Vector3),
typeof(Vector2Int), typeof(Vector3Int), typeof(Vector4), typeof(Quaternion), typeof(Color),
typeof(Color32), typeof(Ray), typeof(Ray2D), typeof(TestStruct))]
Type testType,
[Values] WriteType writeType)
{
BaseArrayTypeTest(testType, writeType);
}
public unsafe void RunFixedStringTest<T>(T fixedStringValue, int numBytesWritten, WriteType writeType) where T : unmanaged, INativeList<byte>, IUTF8Bytes
{
fixedStringValue.Length = numBytesWritten;
var serializedValueSize = FastBufferWriter.GetWriteSize(fixedStringValue);
Assert.AreEqual(serializedValueSize, fixedStringValue.Length + sizeof(int));
var writer = new FastBufferWriter(serializedValueSize + 3, Allocator.Temp);
using (writer)
{
var offset = 0;
switch (writeType)
{
case WriteType.WriteDirect:
Assert.IsTrue(writer.TryBeginWrite(serializedValueSize + 2), "Writer denied write permission");
writer.WriteValue(fixedStringValue);
break;
case WriteType.WriteSafe:
writer.WriteValueSafe(fixedStringValue);
break;
}
WriteCheckBytes(writer, serializedValueSize + offset);
var reader = new FastBufferReader(writer, Allocator.Temp);
using (reader)
{
VerifyPositionAndLength(reader, writer.Length);
var result = new T();
reader.ReadValueSafe(out result);
Assert.AreEqual(fixedStringValue, result);
VerifyCheckBytes(reader, serializedValueSize);
}
}
}
[TestCase(3, WriteType.WriteDirect)]
[TestCase(5, WriteType.WriteSafe)]
[TestCase(16, WriteType.WriteDirect)]
[TestCase(29, WriteType.WriteSafe)]
public void WhenReadingFixedString32Bytes_ValueIsReadCorrectly(int numBytesWritten, WriteType writeType)
{
// Repeats 01234567890123456789...
string valueToTest = "";
for (var i = 0; i < 29; ++i)
{
valueToTest += (i % 10).ToString();
}
var fixedStringValue = new FixedString32Bytes(valueToTest);
RunFixedStringTest(fixedStringValue, numBytesWritten, writeType);
}
[TestCase(3, WriteType.WriteDirect)]
[TestCase(5, WriteType.WriteSafe)]
[TestCase(16, WriteType.WriteDirect)]
[TestCase(29, WriteType.WriteSafe)]
[TestCase(61, WriteType.WriteSafe)]
public void WhenReadingFixedString64Bytes_ValueIsReadCorrectly(int numBytesWritten, WriteType writeType)
{
// Repeats 01234567890123456789...
string valueToTest = "";
for (var i = 0; i < 61; ++i)
{
valueToTest += (i % 10).ToString();
}
var fixedStringValue = new FixedString64Bytes(valueToTest);
RunFixedStringTest(fixedStringValue, numBytesWritten, writeType);
}
[TestCase(3, WriteType.WriteDirect)]
[TestCase(5, WriteType.WriteSafe)]
[TestCase(16, WriteType.WriteDirect)]
[TestCase(29, WriteType.WriteSafe)]
[TestCase(61, WriteType.WriteSafe)]
[TestCase(125, WriteType.WriteSafe)]
public void WhenReadingFixedString128Bytes_ValueIsReadCorrectly(int numBytesWritten, WriteType writeType)
{
// Repeats 01234567890123456789...
string valueToTest = "";
for (var i = 0; i < 125; ++i)
{
valueToTest += (i % 10).ToString();
}
var fixedStringValue = new FixedString128Bytes(valueToTest);
RunFixedStringTest(fixedStringValue, numBytesWritten, writeType);
}
[TestCase(3, WriteType.WriteDirect)]
[TestCase(5, WriteType.WriteSafe)]
[TestCase(16, WriteType.WriteDirect)]
[TestCase(29, WriteType.WriteSafe)]
[TestCase(61, WriteType.WriteSafe)]
[TestCase(125, WriteType.WriteSafe)]
[TestCase(509, WriteType.WriteSafe)]
public void WhenReadingFixedString512Bytes_ValueIsReadCorrectly(int numBytesWritten, WriteType writeType)
{
// Repeats 01234567890123456789...
string valueToTest = "";
for (var i = 0; i < 509; ++i)
{
valueToTest += (i % 10).ToString();
}
var fixedStringValue = new FixedString512Bytes(valueToTest);
RunFixedStringTest(fixedStringValue, numBytesWritten, writeType);
}
[TestCase(3, WriteType.WriteDirect)]
[TestCase(5, WriteType.WriteSafe)]
[TestCase(16, WriteType.WriteDirect)]
[TestCase(29, WriteType.WriteSafe)]
[TestCase(61, WriteType.WriteSafe)]
[TestCase(125, WriteType.WriteSafe)]
[TestCase(509, WriteType.WriteSafe)]
[TestCase(4093, WriteType.WriteSafe)]
public void WhenReadingFixedString4096Bytes_ValueIsReadCorrectly(int numBytesWritten, WriteType writeType)
{
// Repeats 01234567890123456789...
string valueToTest = "";
for (var i = 0; i < 4093; ++i)
{
valueToTest += (i % 10).ToString();
}
var fixedStringValue = new FixedString4096Bytes(valueToTest);
RunFixedStringTest(fixedStringValue, numBytesWritten, writeType);
}
[TestCase(false, WriteType.WriteDirect)]
[TestCase(false, WriteType.WriteSafe)]
[TestCase(true, WriteType.WriteDirect)]

View File

@@ -257,8 +257,9 @@ namespace Unity.Netcode.EditorTests
[Values(typeof(byte), typeof(sbyte), typeof(short), typeof(ushort), typeof(int), typeof(uint),
typeof(long), typeof(ulong), typeof(bool), typeof(char), typeof(float), typeof(double),
typeof(ByteEnum), typeof(SByteEnum), typeof(ShortEnum), typeof(UShortEnum), typeof(IntEnum),
typeof(UIntEnum), typeof(LongEnum), typeof(ULongEnum), typeof(Vector2), typeof(Vector3), typeof(Vector4),
typeof(Quaternion), typeof(Color), typeof(Color32), typeof(Ray), typeof(Ray2D), typeof(TestStruct))]
typeof(UIntEnum), typeof(LongEnum), typeof(ULongEnum), typeof(Vector2), typeof(Vector3),
typeof(Vector2Int), typeof(Vector3Int), typeof(Vector4), typeof(Quaternion), typeof(Color),
typeof(Color32), typeof(Ray), typeof(Ray2D), typeof(TestStruct))]
Type testType,
[Values] WriteType writeType)
{
@@ -270,8 +271,9 @@ namespace Unity.Netcode.EditorTests
[Values(typeof(byte), typeof(sbyte), typeof(short), typeof(ushort), typeof(int), typeof(uint),
typeof(long), typeof(ulong), typeof(bool), typeof(char), typeof(float), typeof(double),
typeof(ByteEnum), typeof(SByteEnum), typeof(ShortEnum), typeof(UShortEnum), typeof(IntEnum),
typeof(UIntEnum), typeof(LongEnum), typeof(ULongEnum), typeof(Vector2), typeof(Vector3), typeof(Vector4),
typeof(Quaternion), typeof(Color), typeof(Color32), typeof(Ray), typeof(Ray2D), typeof(TestStruct))]
typeof(UIntEnum), typeof(LongEnum), typeof(ULongEnum), typeof(Vector2), typeof(Vector3),
typeof(Vector2Int), typeof(Vector3Int), typeof(Vector4), typeof(Quaternion), typeof(Color),
typeof(Color32), typeof(Ray), typeof(Ray2D), typeof(TestStruct))]
Type testType,
[Values] WriteType writeType)
{
@@ -336,6 +338,147 @@ namespace Unity.Netcode.EditorTests
}
}
public unsafe void RunFixedStringTest<T>(T fixedStringValue, int numBytesWritten, WriteType writeType) where T : unmanaged, INativeList<byte>, IUTF8Bytes
{
fixedStringValue.Length = numBytesWritten;
var serializedValueSize = FastBufferWriter.GetWriteSize(fixedStringValue);
Assert.AreEqual(fixedStringValue.Length + sizeof(int), serializedValueSize);
var writer = new FastBufferWriter(serializedValueSize + 3, Allocator.Temp);
using (writer)
{
var offset = 0;
switch (writeType)
{
case WriteType.WriteDirect:
Assert.IsTrue(writer.TryBeginWrite(serializedValueSize + 2), "Writer denied write permission");
writer.WriteValue(fixedStringValue);
break;
case WriteType.WriteSafe:
writer.WriteValueSafe(fixedStringValue);
break;
}
VerifyPositionAndLength(writer, serializedValueSize + offset);
WriteCheckBytes(writer, serializedValueSize + offset);
int* sizeValue = (int*)(writer.GetUnsafePtr() + offset);
Assert.AreEqual(fixedStringValue.Length, *sizeValue);
byte* underlyingByteArray = writer.GetUnsafePtr() + sizeof(int) + offset;
for (var i = 0; i < fixedStringValue.Length; ++i)
{
Assert.AreEqual(fixedStringValue[i], underlyingByteArray[i]);
}
var underlyingArray = writer.ToArray();
VerifyCheckBytes(underlyingArray, serializedValueSize + offset);
}
}
[TestCase(3, WriteType.WriteDirect)]
[TestCase(5, WriteType.WriteSafe)]
[TestCase(16, WriteType.WriteDirect)]
[TestCase(29, WriteType.WriteSafe)]
public void WhenWritingFixedString32Bytes_ValueIsWrittenCorrectly(int numBytesWritten, WriteType writeType)
{
// Repeats 01234567890123456789...
string valueToTest = "";
for (var i = 0; i < 29; ++i)
{
valueToTest += (i % 10).ToString();
}
var fixedStringValue = new FixedString32Bytes(valueToTest);
RunFixedStringTest(fixedStringValue, numBytesWritten, writeType);
}
[TestCase(3, WriteType.WriteDirect)]
[TestCase(5, WriteType.WriteSafe)]
[TestCase(16, WriteType.WriteDirect)]
[TestCase(29, WriteType.WriteSafe)]
[TestCase(61, WriteType.WriteSafe)]
public void WhenWritingFixedString64Bytes_ValueIsWrittenCorrectly(int numBytesWritten, WriteType writeType)
{
// Repeats 01234567890123456789...
string valueToTest = "";
for (var i = 0; i < 61; ++i)
{
valueToTest += (i % 10).ToString();
}
var fixedStringValue = new FixedString64Bytes(valueToTest);
RunFixedStringTest(fixedStringValue, numBytesWritten, writeType);
}
[TestCase(3, WriteType.WriteDirect)]
[TestCase(5, WriteType.WriteSafe)]
[TestCase(16, WriteType.WriteDirect)]
[TestCase(29, WriteType.WriteSafe)]
[TestCase(61, WriteType.WriteSafe)]
[TestCase(125, WriteType.WriteSafe)]
public void WhenWritingFixedString128Bytes_ValueIsWrittenCorrectly(int numBytesWritten, WriteType writeType)
{
// Repeats 01234567890123456789...
string valueToTest = "";
for (var i = 0; i < 125; ++i)
{
valueToTest += (i % 10).ToString();
}
var fixedStringValue = new FixedString128Bytes(valueToTest);
RunFixedStringTest(fixedStringValue, numBytesWritten, writeType);
}
[TestCase(3, WriteType.WriteDirect)]
[TestCase(5, WriteType.WriteSafe)]
[TestCase(16, WriteType.WriteDirect)]
[TestCase(29, WriteType.WriteSafe)]
[TestCase(61, WriteType.WriteSafe)]
[TestCase(125, WriteType.WriteSafe)]
[TestCase(509, WriteType.WriteSafe)]
public void WhenWritingFixedString512Bytes_ValueIsWrittenCorrectly(int numBytesWritten, WriteType writeType)
{
// Repeats 01234567890123456789...
string valueToTest = "";
for (var i = 0; i < 509; ++i)
{
valueToTest += (i % 10).ToString();
}
var fixedStringValue = new FixedString512Bytes(valueToTest);
RunFixedStringTest(fixedStringValue, numBytesWritten, writeType);
}
[TestCase(3, WriteType.WriteDirect)]
[TestCase(5, WriteType.WriteSafe)]
[TestCase(16, WriteType.WriteDirect)]
[TestCase(29, WriteType.WriteSafe)]
[TestCase(61, WriteType.WriteSafe)]
[TestCase(125, WriteType.WriteSafe)]
[TestCase(509, WriteType.WriteSafe)]
[TestCase(4093, WriteType.WriteSafe)]
public void WhenWritingFixedString4096Bytes_ValueIsWrittenCorrectly(int numBytesWritten, WriteType writeType)
{
// Repeats 01234567890123456789...
string valueToTest = "";
for (var i = 0; i < 4093; ++i)
{
valueToTest += (i % 10).ToString();
}
var fixedStringValue = new FixedString4096Bytes(valueToTest);
RunFixedStringTest(fixedStringValue, numBytesWritten, writeType);
}
[TestCase(1, 0)]
[TestCase(2, 0)]
[TestCase(3, 0)]

View File

@@ -0,0 +1,136 @@
using System.Collections;
using NUnit.Framework;
using UnityEngine;
using UnityEngine.TestTools;
using Unity.Netcode.TestHelpers.Runtime;
using Object = UnityEngine.Object;
namespace Unity.Netcode.RuntimeTests
{
public class AddNetworkPrefabTest : NetcodeIntegrationTest
{
public class EmptyComponent : NetworkBehaviour
{
}
protected override int NumberOfClients => 1;
private GameObject m_Prefab;
protected override IEnumerator OnSetup()
{
// Host is irrelevant, messages don't get sent to the host "client"
m_UseHost = false;
m_Prefab = new GameObject("Object");
var networkObject = m_Prefab.AddComponent<NetworkObject>();
m_Prefab.AddComponent<EmptyComponent>();
// Make it a prefab
NetcodeIntegrationTestHelpers.MakeNetworkObjectTestPrefab(networkObject);
yield return null;
}
protected override void OnServerAndClientsCreated()
{
m_ServerNetworkManager.NetworkConfig.SpawnTimeout = 0;
m_ServerNetworkManager.NetworkConfig.ForceSamePrefabs = false;
foreach (var client in m_ClientNetworkManagers)
{
client.NetworkConfig.SpawnTimeout = 0;
client.NetworkConfig.ForceSamePrefabs = false;
}
}
private EmptyComponent GetObjectForClient(ulong clientId)
{
foreach (var component in Object.FindObjectsOfType<EmptyComponent>())
{
if (component.IsSpawned && component.NetworkManager.LocalClientId == clientId)
{
return component;
}
}
return null;
}
private void RegisterPrefab()
{
m_ServerNetworkManager.AddNetworkPrefab(m_Prefab);
foreach (var client in m_ClientNetworkManagers)
{
client.AddNetworkPrefab(m_Prefab);
}
}
private void DeregisterPrefab()
{
m_ServerNetworkManager.RemoveNetworkPrefab(m_Prefab);
foreach (var client in m_ClientNetworkManagers)
{
client.RemoveNetworkPrefab(m_Prefab);
}
}
private static CoroutineRunner s_CoroutineRunner;
[UnityTest]
public IEnumerator WhenSpawningBeforeAddingPrefab_SpawnFails()
{
var serverObject = Object.Instantiate(m_Prefab);
serverObject.GetComponent<NetworkObject>().NetworkManagerOwner = m_ServerNetworkManager;
serverObject.GetComponent<NetworkObject>().Spawn();
yield return NetcodeIntegrationTestHelpers.WaitForMessageOfTypeReceived<CreateObjectMessage>(m_ClientNetworkManagers[0]);
Assert.IsNull(GetObjectForClient(m_ClientNetworkManagers[0].LocalClientId));
}
[UnityTest]
public IEnumerator WhenSpawningAfterAddingServerPrefabButBeforeAddingClientPrefab_SpawnFails()
{
m_ServerNetworkManager.AddNetworkPrefab(m_Prefab);
var serverObject = Object.Instantiate(m_Prefab);
serverObject.GetComponent<NetworkObject>().NetworkManagerOwner = m_ServerNetworkManager;
serverObject.GetComponent<NetworkObject>().Spawn();
yield return NetcodeIntegrationTestHelpers.WaitForMessageOfTypeReceived<CreateObjectMessage>(m_ClientNetworkManagers[0]);
Assert.IsNull(GetObjectForClient(m_ClientNetworkManagers[0].LocalClientId));
}
[UnityTest]
public IEnumerator WhenSpawningAfterAddingPrefabOnServerAndClient_SpawnSucceeds()
{
RegisterPrefab();
var serverObject = Object.Instantiate(m_Prefab);
serverObject.GetComponent<NetworkObject>().NetworkManagerOwner = m_ServerNetworkManager;
serverObject.GetComponent<NetworkObject>().Spawn();
yield return NetcodeIntegrationTestHelpers.WaitForMessageOfTypeHandled<CreateObjectMessage>(m_ClientNetworkManagers[0]);
Assert.IsNotNull(GetObjectForClient(m_ClientNetworkManagers[0].LocalClientId));
}
[UnityTest]
public IEnumerator WhenSpawningAfterRemovingPrefabOnClient_SpawnFails()
{
RegisterPrefab();
var serverObject = Object.Instantiate(m_Prefab);
serverObject.GetComponent<NetworkObject>().NetworkManagerOwner = m_ServerNetworkManager;
serverObject.GetComponent<NetworkObject>().Spawn();
yield return NetcodeIntegrationTestHelpers.WaitForMessageOfTypeReceived<CreateObjectMessage>(m_ClientNetworkManagers[0]);
Assert.IsNotNull(GetObjectForClient(m_ClientNetworkManagers[0].LocalClientId));
serverObject.GetComponent<NetworkObject>().Despawn();
yield return NetcodeIntegrationTestHelpers.WaitForMessageOfTypeReceived<DestroyObjectMessage>(m_ClientNetworkManagers[0]);
Assert.IsNull(GetObjectForClient(m_ClientNetworkManagers[0].LocalClientId));
DeregisterPrefab();
serverObject = Object.Instantiate(m_Prefab);
serverObject.GetComponent<NetworkObject>().NetworkManagerOwner = m_ServerNetworkManager;
serverObject.GetComponent<NetworkObject>().Spawn();
yield return NetcodeIntegrationTestHelpers.WaitForMessageOfTypeReceived<CreateObjectMessage>(m_ClientNetworkManagers[0]);
Assert.IsNull(GetObjectForClient(m_ClientNetworkManagers[0].LocalClientId));
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 67012fa25fe64aeda8fbf60340c1bc2f
timeCreated: 1652205947

View File

@@ -24,7 +24,7 @@ namespace Unity.Netcode.RuntimeTests
[UnityTest]
public IEnumerator ConnectionApproval()
{
NetworkManagerHelper.NetworkManagerObject.ConnectionApprovalCallback += NetworkManagerObject_ConnectionApprovalCallback;
NetworkManagerHelper.NetworkManagerObject.ConnectionApprovalCallback = NetworkManagerObject_ConnectionApprovalCallback;
NetworkManagerHelper.NetworkManagerObject.NetworkConfig.ConnectionApproval = true;
NetworkManagerHelper.NetworkManagerObject.NetworkConfig.PlayerPrefab = null;
NetworkManagerHelper.NetworkManagerObject.NetworkConfig.ConnectionData = Encoding.UTF8.GetBytes(m_ValidationToken.ToString());
@@ -47,14 +47,19 @@ namespace Unity.Netcode.RuntimeTests
Assert.True(m_IsValidated);
}
private void NetworkManagerObject_ConnectionApprovalCallback(byte[] connectionData, ulong clientId, NetworkManager.ConnectionApprovedDelegate callback)
private void NetworkManagerObject_ConnectionApprovalCallback(NetworkManager.ConnectionApprovalRequest request, NetworkManager.ConnectionApprovalResponse response)
{
var stringGuid = Encoding.UTF8.GetString(connectionData);
var stringGuid = Encoding.UTF8.GetString(request.Payload);
if (m_ValidationToken.ToString() == stringGuid)
{
m_IsValidated = true;
}
callback(false, null, m_IsValidated, null, null);
response.Approved = m_IsValidated;
response.CreatePlayerObject = false;
response.Position = null;
response.Rotation = null;
response.PlayerPrefabHash = null;
}
[TearDown]

View File

@@ -878,6 +878,7 @@ namespace Unity.Netcode.RuntimeTests
}
[UnityTest]
[Ignore("This test is unstable on standalones")]
public IEnumerator WhenMultipleMessagesForTheSameObjectAreDeferredForMoreThanTheConfiguredTime_TheyAreAllRemoved([Values(1, 2, 3)] int timeout)
{
RegisterClientPrefabs();

View File

@@ -1,5 +1,6 @@
using System.Collections;
using System.Collections.Generic;
using NUnit.Framework;
using UnityEngine;
using UnityEngine.TestTools;
using Unity.Netcode.TestHelpers.Runtime;
@@ -12,6 +13,8 @@ namespace Unity.Netcode.RuntimeTests
public class HiddenVariableObject : NetworkBehaviour
{
public static List<NetworkObject> ClientInstancesSpawned = new List<NetworkObject>();
public NetworkVariable<int> MyNetworkVariable = new NetworkVariable<int>();
public NetworkList<int> MyNetworkList = new NetworkList<int>();
@@ -21,6 +24,10 @@ namespace Unity.Netcode.RuntimeTests
public override void OnNetworkSpawn()
{
if (!IsServer)
{
ClientInstancesSpawned.Add(NetworkObject);
}
Debug.Log($"{nameof(HiddenVariableObject)}.{nameof(OnNetworkSpawn)}() with value {MyNetworkVariable.Value}");
MyNetworkVariable.OnValueChanged += Changed;
@@ -30,6 +37,15 @@ namespace Unity.Netcode.RuntimeTests
base.OnNetworkSpawn();
}
public override void OnNetworkDespawn()
{
if (!IsServer)
{
ClientInstancesSpawned.Remove(NetworkObject);
}
base.OnNetworkDespawn();
}
public void Changed(int before, int after)
{
Debug.Log($"Value changed from {before} to {after} on {NetworkManager.LocalClientId}");
@@ -71,50 +87,75 @@ namespace Unity.Netcode.RuntimeTests
}
}
public void VerifyLists()
public bool VerifyLists()
{
NetworkList<int> prev = null;
int numComparison = 0;
var prevObject = (NetworkObject)null;
// for all the instances of NetworkList
foreach (var gameObject in m_NetSpawnedObjectOnClient)
foreach (var networkObject in m_NetSpawnedObjectOnClient)
{
// this skips despawned/hidden objects
if (gameObject != null)
if (networkObject != null)
{
// if we've seen another one before
if (prev != null)
{
var curr = gameObject.GetComponent<HiddenVariableObject>().MyNetworkList;
var curr = networkObject.GetComponent<HiddenVariableObject>().MyNetworkList;
// check that the two lists are identical
Debug.Assert(curr.Count == prev.Count);
if (curr.Count != prev.Count)
{
return false;
}
for (int index = 0; index < curr.Count; index++)
{
Debug.Assert(curr[index] == prev[index]);
if (curr[index] != prev[index])
{
return false;
}
}
numComparison++;
}
prevObject = networkObject;
// store the list
prev = gameObject.GetComponent<HiddenVariableObject>().MyNetworkList;
prev = networkObject.GetComponent<HiddenVariableObject>().MyNetworkList;
}
}
Debug.Log($"{numComparison} comparisons done.");
return true;
}
public IEnumerator RefreshGameObects()
public IEnumerator RefreshGameObects(int numberToExpect)
{
m_NetSpawnedObjectOnClient.Clear();
yield return WaitForConditionOrTimeOut(() => numberToExpect == HiddenVariableObject.ClientInstancesSpawned.Count);
Assert.False(s_GlobalTimeoutHelper.TimedOut, $"Timed out waiting for total spawned count to reach {numberToExpect} but is currently {HiddenVariableObject.ClientInstancesSpawned.Count}");
m_NetSpawnedObjectOnClient = HiddenVariableObject.ClientInstancesSpawned;
}
foreach (var netMan in m_ClientNetworkManagers)
private bool CheckValueOnClient(ulong otherClientId, int value)
{
foreach (var id in m_ServerNetworkManager.ConnectedClientsIds)
{
var serverClientPlayerResult = new NetcodeIntegrationTestHelpers.ResultWrapper<NetworkObject>();
yield return NetcodeIntegrationTestHelpers.GetNetworkObjectByRepresentation(
x => x.NetworkObjectId == m_NetSpawnedObject.NetworkObjectId,
netMan,
serverClientPlayerResult);
m_NetSpawnedObjectOnClient.Add(serverClientPlayerResult.Result);
if (id != otherClientId)
{
if (!HiddenVariableObject.ValueOnClient.ContainsKey(id) || HiddenVariableObject.ValueOnClient[id] != value)
{
return false;
}
}
}
return true;
}
private IEnumerator SetAndCheckValueSet(ulong otherClientId, int value)
{
yield return WaitForConditionOrTimeOut(() => CheckValueOnClient(otherClientId, value));
Assert.IsFalse(s_GlobalTimeoutHelper.TimedOut, $"Timed out waiting for all clients to have a value of {value}");
yield return WaitForConditionOrTimeOut(VerifyLists);
Assert.IsFalse(s_GlobalTimeoutHelper.TimedOut, "Timed out waiting for all clients to have identical values!");
Debug.Log("Value changed");
}
[UnityTest]
@@ -127,15 +168,14 @@ namespace Unity.Netcode.RuntimeTests
Debug.Log("Running test");
// ==== Spawn object with ownership on one client
var client = m_ServerNetworkManager.ConnectedClientsList[1];
var otherClient = m_ServerNetworkManager.ConnectedClientsList[2];
m_NetSpawnedObject = SpawnObject(m_TestNetworkPrefab, m_ClientNetworkManagers[1]).GetComponent<NetworkObject>();
yield return RefreshGameObects();
yield return RefreshGameObects(4);
// === Check spawn occured
// === Check spawn occurred
yield return WaitForSpawnCount(NumberOfClients + 1);
Debug.Assert(HiddenVariableObject.SpawnCount == NumberOfClients + 1);
Debug.Log("Objects spawned");
@@ -143,41 +183,22 @@ namespace Unity.Netcode.RuntimeTests
// ==== Set the NetworkVariable value to 2
HiddenVariableObject.ExpectedSize = 1;
HiddenVariableObject.SpawnCount = 0;
var currentValueSet = 2;
m_NetSpawnedObject.GetComponent<HiddenVariableObject>().MyNetworkVariable.Value = 2;
m_NetSpawnedObject.GetComponent<HiddenVariableObject>().MyNetworkList.Add(2);
m_NetSpawnedObject.GetComponent<HiddenVariableObject>().MyNetworkVariable.Value = currentValueSet;
m_NetSpawnedObject.GetComponent<HiddenVariableObject>().MyNetworkList.Add(currentValueSet);
yield return new WaitForSeconds(1.0f);
foreach (var id in m_ServerNetworkManager.ConnectedClientsIds)
{
Debug.Assert(HiddenVariableObject.ValueOnClient[id] == 2);
}
VerifyLists();
Debug.Log("Value changed");
yield return SetAndCheckValueSet(otherClient.ClientId, currentValueSet);
// ==== Hide our object to a different client
HiddenVariableObject.ExpectedSize = 2;
m_NetSpawnedObject.NetworkHide(otherClient.ClientId);
// ==== Change the NetworkVariable value
// we should get one less notification of value changing and no errors or exception
m_NetSpawnedObject.GetComponent<HiddenVariableObject>().MyNetworkVariable.Value = 3;
m_NetSpawnedObject.GetComponent<HiddenVariableObject>().MyNetworkList.Add(3);
currentValueSet = 3;
m_NetSpawnedObject.GetComponent<HiddenVariableObject>().MyNetworkVariable.Value = currentValueSet;
m_NetSpawnedObject.GetComponent<HiddenVariableObject>().MyNetworkList.Add(currentValueSet);
yield return new WaitForSeconds(1.0f);
foreach (var id in m_ServerNetworkManager.ConnectedClientsIds)
{
if (id != otherClient.ClientId)
{
Debug.Assert(HiddenVariableObject.ValueOnClient[id] == 3);
}
}
VerifyLists();
Debug.Log("Values changed");
yield return SetAndCheckValueSet(otherClient.ClientId, currentValueSet);
// ==== Show our object again to this client
HiddenVariableObject.ExpectedSize = 3;
@@ -189,22 +210,13 @@ namespace Unity.Netcode.RuntimeTests
Debug.Log("Object spawned");
// ==== We need a refresh for the newly re-spawned object
yield return RefreshGameObects();
yield return RefreshGameObects(4);
// ==== Change the NetworkVariable value
// we should get all notifications of value changing and no errors or exception
m_NetSpawnedObject.GetComponent<HiddenVariableObject>().MyNetworkVariable.Value = 4;
m_NetSpawnedObject.GetComponent<HiddenVariableObject>().MyNetworkList.Add(4);
currentValueSet = 4;
m_NetSpawnedObject.GetComponent<HiddenVariableObject>().MyNetworkVariable.Value = currentValueSet;
m_NetSpawnedObject.GetComponent<HiddenVariableObject>().MyNetworkList.Add(currentValueSet);
yield return new WaitForSeconds(1.0f);
foreach (var id in m_ServerNetworkManager.ConnectedClientsIds)
{
Debug.Assert(HiddenVariableObject.ValueOnClient[id] == 4);
}
VerifyLists();
Debug.Log("Values changed");
yield return SetAndCheckValueSet(otherClient.ClientId, currentValueSet);
// ==== Hide our object to that different client again, and then destroy it
m_NetSpawnedObject.NetworkHide(otherClient.ClientId);

View File

@@ -18,7 +18,7 @@ namespace Unity.Netcode.RuntimeTests.Metrics
{
protected override int NumberOfClients => 1;
private readonly int m_PacketLossRate = 25;
private int m_DropInterval = 5;
private readonly int m_PacketLossRangeDelta = 5;
public PacketLossMetricsTests()
: base(HostOrServer.Server)
@@ -57,11 +57,12 @@ namespace Unity.Netcode.RuntimeTests.Metrics
[UnityTest]
public IEnumerator TrackPacketLossAsClient()
{
double packetLossRate = m_PacketLossRate/100d;
double packetLossRateMinRange = (m_PacketLossRate-m_PacketLossRangeDelta) / 100d;
double packetLossRateMaxrange = (m_PacketLossRate + m_PacketLossRangeDelta) / 100d;
var clientNetworkManager = m_ClientNetworkManagers[0];
var waitForPacketLossMetric = new WaitForGaugeMetricValues((clientNetworkManager.NetworkMetrics as NetworkMetrics).Dispatcher,
NetworkMetricTypes.PacketLoss,
metric => Math.Abs(metric - packetLossRate) < Double.Epsilon);
metric => packetLossRateMinRange <= metric && metric <= packetLossRateMaxrange);
for (int i = 0; i < 1000; ++i)
{
@@ -75,7 +76,7 @@ namespace Unity.Netcode.RuntimeTests.Metrics
yield return waitForPacketLossMetric.WaitForMetricsReceived();
var packetLossValue = waitForPacketLossMetric.AssertMetricValueHaveBeenFound();
Assert.AreEqual(packetLossRate, packetLossValue);
Assert.That(packetLossValue, Is.InRange(packetLossRateMinRange, packetLossRateMaxrange));
}
}
}

View File

@@ -3,131 +3,158 @@ using System.Collections;
using UnityEngine;
using UnityEngine.TestTools;
using NUnit.Framework;
using Unity.Netcode.TestHelpers.Runtime;
using Object = UnityEngine.Object;
namespace Unity.Netcode.RuntimeTests
{
[TestFixture(HostOrServer.Host)]
[TestFixture(HostOrServer.Server)]
public class NetworkManagerTransportTests : NetcodeIntegrationTest
public class NetworkManagerTransportTests
{
protected override int NumberOfClients => 1;
private bool m_CanStartServerAndClients = false;
public NetworkManagerTransportTests(HostOrServer hostOrServer) : base(hostOrServer) { }
protected override IEnumerator OnSetup()
[Test]
public void ClientDoesNotStartWhenTransportFails()
{
m_CanStartServerAndClients = false;
return base.OnSetup();
bool callbackInvoked = false;
Action onTransportFailure = () => { callbackInvoked = true; };
var manager = new GameObject().AddComponent<NetworkManager>();
manager.OnTransportFailure += onTransportFailure;
var transport = manager.gameObject.AddComponent<FailedTransport>();
transport.FailOnStart = true;
manager.NetworkConfig = new NetworkConfig() { NetworkTransport = transport };
LogAssert.Expect(LogType.Error, $"Client is shutting down due to network transport start failure of {transport.GetType().Name}!");
Assert.False(manager.StartClient());
Assert.False(manager.IsListening);
Assert.False(manager.IsConnectedClient);
Assert.True(callbackInvoked);
}
protected override bool CanStartServerAndClients()
[Test]
public void HostDoesNotStartWhenTransportFails()
{
return m_CanStartServerAndClients;
bool callbackInvoked = false;
Action onTransportFailure = () => { callbackInvoked = true; };
var manager = new GameObject().AddComponent<NetworkManager>();
manager.OnTransportFailure += onTransportFailure;
var transport = manager.gameObject.AddComponent<FailedTransport>();
transport.FailOnStart = true;
manager.NetworkConfig = new NetworkConfig() { NetworkTransport = transport };
LogAssert.Expect(LogType.Error, $"Server is shutting down due to network transport start failure of {transport.GetType().Name}!");
Assert.False(manager.StartHost());
Assert.False(manager.IsListening);
Assert.True(callbackInvoked);
}
[Test]
public void ServerDoesNotStartWhenTransportFails()
{
bool callbackInvoked = false;
Action onTransportFailure = () => { callbackInvoked = true; };
var manager = new GameObject().AddComponent<NetworkManager>();
manager.OnTransportFailure += onTransportFailure;
var transport = manager.gameObject.AddComponent<FailedTransport>();
transport.FailOnStart = true;
manager.NetworkConfig = new NetworkConfig() { NetworkTransport = transport };
LogAssert.Expect(LogType.Error, $"Server is shutting down due to network transport start failure of {transport.GetType().Name}!");
Assert.False(manager.StartServer());
Assert.False(manager.IsListening);
Assert.True(callbackInvoked);
}
[UnityTest]
public IEnumerator ShutsDownWhenTransportFails()
{
bool callbackInvoked = false;
Action onTransportFailure = () => { callbackInvoked = true; };
var manager = new GameObject().AddComponent<NetworkManager>();
manager.OnTransportFailure += onTransportFailure;
var transport = manager.gameObject.AddComponent<FailedTransport>();
transport.FailOnNextPoll = true;
manager.NetworkConfig = new NetworkConfig() { NetworkTransport = transport };
Assert.True(manager.StartServer());
Assert.True(manager.IsListening);
LogAssert.Expect(LogType.Error, $"Shutting down due to network transport failure of {transport.GetType().Name}!");
// Need two updates to actually shut down. First one to see the transport failing, which
// marks the NetworkManager as shutting down. Second one where actual shutdown occurs.
yield return null;
yield return null;
Assert.False(manager.IsListening);
Assert.True(callbackInvoked);
}
/// <summary>
/// Validate that if the NetworkTransport fails to start the NetworkManager
/// will not continue the startup process and will shut itself down.
/// Does nothing but simulate a transport that can fail at startup and/or when polling events.
/// </summary>
/// <param name="testClient">if true it will test the client side</param>
[UnityTest]
public IEnumerator DoesNotStartWhenTransportFails([Values] bool testClient)
public class FailedTransport : TestingNetworkTransport
{
// The error message we should expect
var messageToCheck = "";
if (!testClient)
{
Object.DestroyImmediate(m_ServerNetworkManager.NetworkConfig.NetworkTransport);
m_ServerNetworkManager.NetworkConfig.NetworkTransport = m_ServerNetworkManager.gameObject.AddComponent<FailedTransport>();
m_ServerNetworkManager.NetworkConfig.NetworkTransport.Initialize(m_ServerNetworkManager);
// The error message we should expect
messageToCheck = $"Server is shutting down due to network transport start failure of {m_ServerNetworkManager.NetworkConfig.NetworkTransport.GetType().Name}!";
}
else
{
foreach (var client in m_ClientNetworkManagers)
{
Object.DestroyImmediate(client.NetworkConfig.NetworkTransport);
client.NetworkConfig.NetworkTransport = client.gameObject.AddComponent<FailedTransport>();
client.NetworkConfig.NetworkTransport.Initialize(m_ServerNetworkManager);
}
// The error message we should expect
messageToCheck = $"Client is shutting down due to network transport start failure of {m_ClientNetworkManagers[0].NetworkConfig.NetworkTransport.GetType().Name}!";
}
public bool FailOnStart = false;
public bool FailOnNextPoll = false;
// Trap for the nested NetworkManager exception
LogAssert.Expect(LogType.Error, messageToCheck);
m_CanStartServerAndClients = true;
// Due to other errors, we must not send clients if testing the server-host side
// We can test both server and client(s) when testing client-side only
if (testClient)
public override bool StartClient() => !FailOnStart;
public override bool StartServer() => !FailOnStart;
public override NetworkEvent PollEvent(out ulong clientId, out ArraySegment<byte> payload, out float receiveTime)
{
NetcodeIntegrationTestHelpers.Start(m_UseHost, m_ServerNetworkManager, m_ClientNetworkManagers);
yield return s_DefaultWaitForTick;
foreach (var client in m_ClientNetworkManagers)
clientId = 0;
payload = new ArraySegment<byte>();
receiveTime = 0;
if (FailOnNextPoll)
{
Assert.False(client.IsListening);
Assert.False(client.IsConnectedClient);
FailOnNextPoll = false;
return NetworkEvent.TransportFailure;
}
else
{
return NetworkEvent.Nothing;
}
}
else
public override ulong ServerClientId => 0;
public override void Send(ulong clientId, ArraySegment<byte> payload, NetworkDelivery networkDelivery)
{
NetcodeIntegrationTestHelpers.Start(m_UseHost, m_ServerNetworkManager, new NetworkManager[] { });
yield return s_DefaultWaitForTick;
Assert.False(m_ServerNetworkManager.IsListening);
}
}
}
/// <summary>
/// Does nothing but simulate a transport that failed to start
/// </summary>
public class FailedTransport : TestingNetworkTransport
{
public override void Shutdown()
{
}
public override void Initialize(NetworkManager networkManager = null)
{
}
public override ulong ServerClientId => 0;
public override void Shutdown()
{
}
public override NetworkEvent PollEvent(out ulong clientId, out ArraySegment<byte> payload, out float receiveTime)
{
clientId = 0;
payload = new ArraySegment<byte>();
receiveTime = 0;
return NetworkEvent.Nothing;
}
public override bool StartClient()
{
// Simulate failure, always return false
return false;
}
public override bool StartServer()
{
// Simulate failure, always return false
return false;
}
public override void Send(ulong clientId, ArraySegment<byte> payload, NetworkDelivery networkDelivery)
{
}
public override ulong GetCurrentRtt(ulong clientId) => 0;
public override void DisconnectRemoteClient(ulong clientId)
{
}
public override void DisconnectRemoteClient(ulong clientId)
{
}
public override void Initialize(NetworkManager networkManager = null)
{
}
public override ulong GetCurrentRtt(ulong clientId)
{
return 0;
}
public override void DisconnectLocalClient()
{
public override void DisconnectLocalClient()
{
}
}
}
}

View File

@@ -168,6 +168,23 @@ namespace Unity.Netcode.RuntimeTests
Assert.False(s_GlobalTimeoutHelper.TimedOut, "Timed out while waiting for client side despawns! (2nd pass)");
}
[Test]
public void DynamicallySpawnedNoSceneOriginException()
{
var gameObject = new GameObject();
var networkObject = gameObject.AddComponent<NetworkObject>();
networkObject.IsSpawned = true;
networkObject.SceneOriginHandle = 0;
networkObject.IsSceneObject = false;
// This validates invoking GetSceneOriginHandle will not throw an exception for a dynamically spawned NetworkObject
// when the scene of origin handle is zero
var sceneOriginHandle = networkObject.GetSceneOriginHandle();
// This validates that GetSceneOriginHandle will return the GameObject's scene handle that should be the currently active scene
var activeSceneHandle = UnityEngine.SceneManagement.SceneManager.GetActiveScene().handle;
Assert.IsTrue(sceneOriginHandle == activeSceneHandle, $"{nameof(NetworkObject)} should have returned the active scene handle of {activeSceneHandle} but returned {sceneOriginHandle}");
}
private class TrackOnSpawnFunctions : NetworkBehaviour
{
public int OnNetworkSpawnCalledCount { get; private set; }

View File

@@ -54,7 +54,7 @@ namespace Unity.Netcode.RuntimeTests
invalidNetworkObjects.Add(gameObject);
writer.WriteValueSafe((int)networkObject.gameObject.scene.handle);
writer.WriteValueSafe((int)networkObject.GetSceneOriginHandle());
// Serialize the invalid NetworkObject
var sceneObject = networkObject.GetMessageSceneObject(0);
var prePosition = writer.Position;
@@ -85,7 +85,7 @@ namespace Unity.Netcode.RuntimeTests
networkObjectsToTest.Add(gameObject);
writer.WriteValueSafe((int)networkObject.gameObject.scene.handle);
writer.WriteValueSafe(networkObject.GetSceneOriginHandle());
// Handle populating the scenes loaded list
var scene = networkObject.gameObject.scene;
@@ -96,13 +96,13 @@ namespace Unity.Netcode.RuntimeTests
NetworkManagerHelper.NetworkManagerObject.SceneManager.ScenesLoaded
.Add(scene.handle, scene);
}
var handle = networkObject.GetSceneOriginHandle();
// Since this is a unit test, we will fake the server to client handle lookup by just adding the same handle key and value
if (!NetworkManagerHelper.NetworkManagerObject.SceneManager.ServerSceneHandleToClientSceneHandle
.ContainsKey(networkObject.gameObject.scene.handle))
.ContainsKey(handle))
{
NetworkManagerHelper.NetworkManagerObject.SceneManager.ServerSceneHandleToClientSceneHandle
.Add(networkObject.gameObject.scene.handle, networkObject.gameObject.scene.handle);
.Add(handle, handle);
}
// Serialize the valid NetworkObject

View File

@@ -1,6 +1,6 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;
using UnityEngine;
using UnityEngine.TestTools;
@@ -8,13 +8,46 @@ using Unity.Netcode.TestHelpers.Runtime;
namespace Unity.Netcode.RuntimeTests
{
public class NetworkShowHideTest : NetworkBehaviour
public class NetworkShowHideTestComponent : NetworkBehaviour
{
}
public class ShowHideObject : NetworkBehaviour
{
public static List<ShowHideObject> ClientTargetedNetworkObjects = new List<ShowHideObject>();
public static ulong ClientIdToTarget;
public static NetworkObject GetNetworkObjectById(ulong networkObjectId)
{
foreach (var entry in ClientTargetedNetworkObjects)
{
if (entry.NetworkObjectId == networkObjectId)
{
return entry.NetworkObject;
}
}
return null;
}
public override void OnNetworkSpawn()
{
if (NetworkManager.LocalClientId == ClientIdToTarget)
{
ClientTargetedNetworkObjects.Add(this);
}
base.OnNetworkSpawn();
}
public override void OnNetworkDespawn()
{
if (ClientTargetedNetworkObjects.Contains(this))
{
ClientTargetedNetworkObjects.Remove(this);
}
base.OnNetworkDespawn();
}
public NetworkVariable<int> MyNetworkVariable;
private void Start()
@@ -27,7 +60,6 @@ namespace Unity.Netcode.RuntimeTests
{
Debug.Log($"Value changed from {before} to {after}");
}
}
public class NetworkShowHideTests : NetcodeIntegrationTest
@@ -46,30 +78,17 @@ namespace Unity.Netcode.RuntimeTests
protected override void OnCreatePlayerPrefab()
{
var networkTransform = m_PlayerPrefab.AddComponent<NetworkShowHideTest>();
var networkTransform = m_PlayerPrefab.AddComponent<NetworkShowHideTestComponent>();
}
protected override void OnServerAndClientsCreated()
{
m_PrefabToSpawn = PreparePrefab(typeof(ShowHideObject));
}
public GameObject PreparePrefab(Type type)
{
var prefabToSpawn = new GameObject();
prefabToSpawn.AddComponent(type);
var networkObjectPrefab = prefabToSpawn.AddComponent<NetworkObject>();
NetcodeIntegrationTestHelpers.MakeNetworkObjectTestPrefab(networkObjectPrefab);
m_ServerNetworkManager.NetworkConfig.NetworkPrefabs.Add(new NetworkPrefab() { Prefab = prefabToSpawn });
foreach (var clientNetworkManager in m_ClientNetworkManagers)
{
clientNetworkManager.NetworkConfig.NetworkPrefabs.Add(new NetworkPrefab() { Prefab = prefabToSpawn });
}
return prefabToSpawn;
m_PrefabToSpawn = CreateNetworkObjectPrefab("ShowHideObject");
m_PrefabToSpawn.AddComponent<ShowHideObject>();
}
// Check that the first client see them, or not, as expected
private IEnumerator CheckVisible(bool target)
private IEnumerator CheckVisible(bool isVisible)
{
int count = 0;
do
@@ -83,21 +102,31 @@ namespace Unity.Netcode.RuntimeTests
Assert.Fail("timeout waiting for object to reach the expect visibility");
break;
}
} while (m_NetSpawnedObject1.IsNetworkVisibleTo(m_ClientId0) != target ||
m_NetSpawnedObject2.IsNetworkVisibleTo(m_ClientId0) != target ||
m_NetSpawnedObject3.IsNetworkVisibleTo(m_ClientId0) != target ||
m_Object1OnClient0.IsSpawned != target ||
m_Object2OnClient0.IsSpawned != target ||
m_Object3OnClient0.IsSpawned != target
} while (m_NetSpawnedObject1.IsNetworkVisibleTo(m_ClientId0) != isVisible ||
m_NetSpawnedObject2.IsNetworkVisibleTo(m_ClientId0) != isVisible ||
m_NetSpawnedObject3.IsNetworkVisibleTo(m_ClientId0) != isVisible ||
m_Object1OnClient0.IsSpawned != isVisible ||
m_Object2OnClient0.IsSpawned != isVisible ||
m_Object3OnClient0.IsSpawned != isVisible
);
Debug.Assert(m_NetSpawnedObject1.IsNetworkVisibleTo(m_ClientId0) == target);
Debug.Assert(m_NetSpawnedObject2.IsNetworkVisibleTo(m_ClientId0) == target);
Debug.Assert(m_NetSpawnedObject3.IsNetworkVisibleTo(m_ClientId0) == target);
Debug.Assert(m_NetSpawnedObject1.IsNetworkVisibleTo(m_ClientId0) == isVisible);
Debug.Assert(m_NetSpawnedObject2.IsNetworkVisibleTo(m_ClientId0) == isVisible);
Debug.Assert(m_NetSpawnedObject3.IsNetworkVisibleTo(m_ClientId0) == isVisible);
Debug.Assert(m_Object1OnClient0.IsSpawned == target);
Debug.Assert(m_Object2OnClient0.IsSpawned == target);
Debug.Assert(m_Object3OnClient0.IsSpawned == target);
Debug.Assert(m_Object1OnClient0.IsSpawned == isVisible);
Debug.Assert(m_Object2OnClient0.IsSpawned == isVisible);
Debug.Assert(m_Object3OnClient0.IsSpawned == isVisible);
var clientNetworkManager = m_ClientNetworkManagers.Where((c) => c.LocalClientId == m_ClientId0).First();
if (isVisible)
{
Assert.True(ShowHideObject.ClientTargetedNetworkObjects.Count == 3, $"Client-{clientNetworkManager.LocalClientId} should have 3 instances visible but only has {ShowHideObject.ClientTargetedNetworkObjects.Count}!");
}
else
{
Assert.True(ShowHideObject.ClientTargetedNetworkObjects.Count == 0, $"Client-{clientNetworkManager.LocalClientId} should have no visible instances but still has {ShowHideObject.ClientTargetedNetworkObjects.Count}!");
}
}
// Set the 3 objects visibility
@@ -136,30 +165,19 @@ namespace Unity.Netcode.RuntimeTests
}
}
private IEnumerator RefreshNetworkObjects()
private bool RefreshNetworkObjects()
{
var serverClientPlayerResult = new NetcodeIntegrationTestHelpers.ResultWrapper<NetworkObject>();
yield return NetcodeIntegrationTestHelpers.GetNetworkObjectByRepresentation(
x => x.NetworkObjectId == m_NetSpawnedObject1.NetworkObjectId && x.IsSpawned,
m_ClientNetworkManagers[0],
serverClientPlayerResult);
m_Object1OnClient0 = serverClientPlayerResult.Result;
yield return NetcodeIntegrationTestHelpers.GetNetworkObjectByRepresentation(
x => x.NetworkObjectId == m_NetSpawnedObject2.NetworkObjectId && x.IsSpawned,
m_ClientNetworkManagers[0],
serverClientPlayerResult);
m_Object2OnClient0 = serverClientPlayerResult.Result;
serverClientPlayerResult = new NetcodeIntegrationTestHelpers.ResultWrapper<NetworkObject>();
yield return NetcodeIntegrationTestHelpers.GetNetworkObjectByRepresentation(
x => x.NetworkObjectId == m_NetSpawnedObject3.NetworkObjectId && x.IsSpawned,
m_ClientNetworkManagers[0],
serverClientPlayerResult);
m_Object3OnClient0 = serverClientPlayerResult.Result;
// make sure the objects are set with the right network manager
m_Object1OnClient0.NetworkManagerOwner = m_ClientNetworkManagers[0];
m_Object2OnClient0.NetworkManagerOwner = m_ClientNetworkManagers[0];
m_Object3OnClient0.NetworkManagerOwner = m_ClientNetworkManagers[0];
m_Object1OnClient0 = ShowHideObject.GetNetworkObjectById(m_NetSpawnedObject1.NetworkObjectId);
m_Object2OnClient0 = ShowHideObject.GetNetworkObjectById(m_NetSpawnedObject2.NetworkObjectId);
m_Object3OnClient0 = ShowHideObject.GetNetworkObjectById(m_NetSpawnedObject3.NetworkObjectId);
if (m_Object1OnClient0 == null || m_Object2OnClient0 == null || m_Object3OnClient0 == null)
{
return false;
}
Assert.True(m_Object1OnClient0.NetworkManagerOwner == m_ClientNetworkManagers[0]);
Assert.True(m_Object2OnClient0.NetworkManagerOwner == m_ClientNetworkManagers[0]);
Assert.True(m_Object3OnClient0.NetworkManagerOwner == m_ClientNetworkManagers[0]);
return true;
}
@@ -167,28 +185,23 @@ namespace Unity.Netcode.RuntimeTests
public IEnumerator NetworkShowHideTest()
{
m_ClientId0 = m_ClientNetworkManagers[0].LocalClientId;
ShowHideObject.ClientTargetedNetworkObjects.Clear();
ShowHideObject.ClientIdToTarget = m_ClientId0;
// create 3 objects
var spawnedObject1 = UnityEngine.Object.Instantiate(m_PrefabToSpawn);
var spawnedObject2 = UnityEngine.Object.Instantiate(m_PrefabToSpawn);
var spawnedObject3 = UnityEngine.Object.Instantiate(m_PrefabToSpawn);
var spawnedObject1 = SpawnObject(m_PrefabToSpawn, m_ServerNetworkManager);
var spawnedObject2 = SpawnObject(m_PrefabToSpawn, m_ServerNetworkManager);
var spawnedObject3 = SpawnObject(m_PrefabToSpawn, m_ServerNetworkManager);
m_NetSpawnedObject1 = spawnedObject1.GetComponent<NetworkObject>();
m_NetSpawnedObject2 = spawnedObject2.GetComponent<NetworkObject>();
m_NetSpawnedObject3 = spawnedObject3.GetComponent<NetworkObject>();
m_NetSpawnedObject1.NetworkManagerOwner = m_ServerNetworkManager;
m_NetSpawnedObject2.NetworkManagerOwner = m_ServerNetworkManager;
m_NetSpawnedObject3.NetworkManagerOwner = m_ServerNetworkManager;
m_NetSpawnedObject1.Spawn();
m_NetSpawnedObject2.Spawn();
m_NetSpawnedObject3.Spawn();
for (int mode = 0; mode < 2; mode++)
{
// get the NetworkObject on a client instance
yield return RefreshNetworkObjects();
yield return WaitForConditionOrTimeOut(RefreshNetworkObjects);
AssertOnTimeout($"Could not refresh all NetworkObjects!");
// check object start visible
yield return CheckVisible(true);
@@ -207,7 +220,8 @@ namespace Unity.Netcode.RuntimeTests
// show them to that client
Show(mode == 0, true);
yield return RefreshNetworkObjects();
yield return WaitForConditionOrTimeOut(RefreshNetworkObjects);
AssertOnTimeout($"Could not refresh all NetworkObjects!");
// verify they become visible
yield return CheckVisible(true);
@@ -218,24 +232,21 @@ namespace Unity.Netcode.RuntimeTests
public IEnumerator NetworkShowHideQuickTest()
{
m_ClientId0 = m_ClientNetworkManagers[0].LocalClientId;
ShowHideObject.ClientTargetedNetworkObjects.Clear();
ShowHideObject.ClientIdToTarget = m_ClientId0;
var spawnedObject1 = UnityEngine.Object.Instantiate(m_PrefabToSpawn);
var spawnedObject2 = UnityEngine.Object.Instantiate(m_PrefabToSpawn);
var spawnedObject3 = UnityEngine.Object.Instantiate(m_PrefabToSpawn);
var spawnedObject1 = SpawnObject(m_PrefabToSpawn, m_ServerNetworkManager);
var spawnedObject2 = SpawnObject(m_PrefabToSpawn, m_ServerNetworkManager);
var spawnedObject3 = SpawnObject(m_PrefabToSpawn, m_ServerNetworkManager);
m_NetSpawnedObject1 = spawnedObject1.GetComponent<NetworkObject>();
m_NetSpawnedObject2 = spawnedObject2.GetComponent<NetworkObject>();
m_NetSpawnedObject3 = spawnedObject3.GetComponent<NetworkObject>();
m_NetSpawnedObject1.NetworkManagerOwner = m_ServerNetworkManager;
m_NetSpawnedObject2.NetworkManagerOwner = m_ServerNetworkManager;
m_NetSpawnedObject3.NetworkManagerOwner = m_ServerNetworkManager;
m_NetSpawnedObject1.Spawn();
m_NetSpawnedObject2.Spawn();
m_NetSpawnedObject3.Spawn();
for (int mode = 0; mode < 2; mode++)
{
// get the NetworkObject on a client instance
yield return RefreshNetworkObjects();
yield return WaitForConditionOrTimeOut(RefreshNetworkObjects);
AssertOnTimeout($"Could not refresh all NetworkObjects!");
// check object start visible
yield return CheckVisible(true);
@@ -245,7 +256,8 @@ namespace Unity.Netcode.RuntimeTests
Show(mode == 0, true);
yield return NetcodeIntegrationTestHelpers.WaitForTicks(m_ServerNetworkManager, 5);
yield return RefreshNetworkObjects();
yield return WaitForConditionOrTimeOut(RefreshNetworkObjects);
AssertOnTimeout($"Could not refresh all NetworkObjects!");
yield return NetcodeIntegrationTestHelpers.WaitForTicks(m_ServerNetworkManager, 5);
// verify they become visible

View File

@@ -267,7 +267,7 @@ namespace Unity.Netcode.RuntimeTests
}
}
protected override bool OnIsServerAuthoritatitive()
protected override bool OnIsServerAuthoritative()
{
return false;
}

View File

@@ -271,11 +271,18 @@ namespace Unity.Netcode.RuntimeTests
public class NetworkVariableTest : NetworkBehaviour
{
public enum SomeEnum
{
A,
B,
C
}
public readonly NetworkVariable<int> TheScalar = new NetworkVariable<int>();
public readonly NetworkVariable<SomeEnum> TheEnum = new NetworkVariable<SomeEnum>();
public readonly NetworkList<int> TheList = new NetworkList<int>();
public readonly NetworkList<ForceNetworkSerializeByMemcpy<FixedString128Bytes>> TheLargeList = new NetworkList<ForceNetworkSerializeByMemcpy<FixedString128Bytes>>();
public readonly NetworkList<FixedString128Bytes> TheLargeList = new NetworkList<FixedString128Bytes>();
public readonly NetworkVariable<ForceNetworkSerializeByMemcpy<FixedString32Bytes>> FixedString32 = new NetworkVariable<ForceNetworkSerializeByMemcpy<FixedString32Bytes>>();
public readonly NetworkVariable<FixedString32Bytes> FixedString32 = new NetworkVariable<FixedString32Bytes>();
private void ListChanged(NetworkListEvent<int> e)
{
@@ -365,6 +372,7 @@ namespace Unity.Netcode.RuntimeTests
// Wait for connection on client and server side
yield return WaitForClientsConnectedOrTimeOut();
AssertOnTimeout($"Timed-out waiting for all clients to connect!");
// These are the *SERVER VERSIONS* of the *CLIENT PLAYER 1 & 2*
var result = new NetcodeIntegrationTestHelpers.ResultWrapper<NetworkObject>();
@@ -597,7 +605,7 @@ namespace Unity.Netcode.RuntimeTests
bool VerifyStructure()
{
return m_Player1OnClient1.TheStruct.Value.SomeBool == m_Player1OnServer.TheStruct.Value.SomeBool &&
m_Player1OnClient1.TheStruct.Value.SomeInt == m_Player1OnServer.TheStruct.Value.SomeInt;
m_Player1OnClient1.TheStruct.Value.SomeInt == m_Player1OnServer.TheStruct.Value.SomeInt;
}
m_Player1OnServer.TheStruct.Value = new TestStruct() { SomeInt = k_TestUInt, SomeBool = false };
@@ -607,6 +615,23 @@ namespace Unity.Netcode.RuntimeTests
yield return WaitForConditionOrTimeOut(VerifyStructure);
}
[UnityTest]
public IEnumerator TestNetworkVariableEnum([Values(true, false)] bool useHost)
{
yield return InitializeServerAndClients(useHost);
bool VerifyStructure()
{
return m_Player1OnClient1.TheEnum.Value == NetworkVariableTest.SomeEnum.C;
}
m_Player1OnServer.TheEnum.Value = NetworkVariableTest.SomeEnum.C;
m_Player1OnServer.TheEnum.SetDirty(true);
// Wait for the client-side to notify it is finished initializing and spawning.
yield return WaitForConditionOrTimeOut(VerifyStructure);
}
[UnityTest]
public IEnumerator TestINetworkSerializableCallsNetworkSerialize([Values(true, false)] bool useHost)
{

View File

@@ -0,0 +1,213 @@
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine.TestTools;
using NUnit.Framework;
using Unity.Netcode.TestHelpers.Runtime;
using UnityEngine;
using Object = UnityEngine.Object;
namespace Unity.Netcode.RuntimeTests
{
public struct MyTypeOne
{
public int Value;
}
public struct MyTypeTwo
{
public int Value;
}
public struct MyTypeThree
{
public int Value;
}
/// <summary>
/// Used to help track instances of any child derived class
/// </summary>
public class WorkingUserNetworkVariableComponentBase : NetworkBehaviour
{
private static Dictionary<ulong, WorkingUserNetworkVariableComponentBase> s_Instances = new Dictionary<ulong, WorkingUserNetworkVariableComponentBase>();
internal static T GetRelativeInstance<T>(ulong clientId) where T : NetworkBehaviour
{
if (s_Instances.ContainsKey(clientId))
{
return s_Instances[clientId] as T;
}
return null;
}
public static void Reset()
{
s_Instances.Clear();
}
public override void OnNetworkSpawn()
{
if (!s_Instances.ContainsKey(NetworkManager.LocalClientId))
{
s_Instances.Add(NetworkManager.LocalClientId, this);
}
else
{
Debug.LogWarning($"{name} is spawned but client id {NetworkManager.LocalClientId} instance already exists!");
}
}
public override void OnNetworkDespawn()
{
if (s_Instances.ContainsKey(NetworkManager.LocalClientId))
{
s_Instances.Remove(NetworkManager.LocalClientId);
}
else
{
Debug.LogWarning($"{name} is was never spawned but client id {NetworkManager.LocalClientId} is trying to despawn it!");
}
}
}
public class WorkingUserNetworkVariableComponent : WorkingUserNetworkVariableComponentBase
{
public NetworkVariable<MyTypeOne> NetworkVariable = new NetworkVariable<MyTypeOne>();
}
public class WorkingUserNetworkVariableComponentUsingExtensionMethod : WorkingUserNetworkVariableComponentBase
{
public NetworkVariable<MyTypeTwo> NetworkVariable = new NetworkVariable<MyTypeTwo>();
}
public class NonWorkingUserNetworkVariableComponent : NetworkBehaviour
{
public NetworkVariable<MyTypeThree> NetworkVariable = new NetworkVariable<MyTypeThree>();
}
internal static class NetworkVariableUserSerializableTypesTestsExtensionMethods
{
public static void WriteValueSafe(this FastBufferWriter writer, in MyTypeTwo value)
{
writer.WriteValueSafe(value.Value);
}
public static void ReadValueSafe(this FastBufferReader reader, out MyTypeTwo value)
{
value = new MyTypeTwo();
reader.ReadValueSafe(out value.Value);
}
}
public class NetworkVariableUserSerializableTypesTests : NetcodeIntegrationTest
{
protected override int NumberOfClients => 1;
public NetworkVariableUserSerializableTypesTests()
: base(HostOrServer.Server)
{
}
private GameObject m_WorkingPrefab;
private GameObject m_ExtensionMethodPrefab;
private GameObject m_NonWorkingPrefab;
protected override IEnumerator OnSetup()
{
WorkingUserNetworkVariableComponentBase.Reset();
return base.OnSetup();
}
protected override void OnServerAndClientsCreated()
{
m_WorkingPrefab = CreateNetworkObjectPrefab($"[{nameof(NetworkVariableUserSerializableTypesTests)}.{nameof(m_WorkingPrefab)}]");
m_ExtensionMethodPrefab = CreateNetworkObjectPrefab($"[{nameof(NetworkVariableUserSerializableTypesTests)}.{nameof(m_ExtensionMethodPrefab)}]");
m_NonWorkingPrefab = CreateNetworkObjectPrefab($"[{nameof(NetworkVariableUserSerializableTypesTests)}.{nameof(m_NonWorkingPrefab)}]");
m_WorkingPrefab.AddComponent<WorkingUserNetworkVariableComponent>();
m_ExtensionMethodPrefab.AddComponent<WorkingUserNetworkVariableComponentUsingExtensionMethod>();
m_NonWorkingPrefab.AddComponent<NonWorkingUserNetworkVariableComponent>();
}
private bool CheckForClientInstance<T>() where T : WorkingUserNetworkVariableComponentBase
{
var instance = WorkingUserNetworkVariableComponentBase.GetRelativeInstance<T>(m_ClientNetworkManagers[0].LocalClientId);
return instance != null && instance.IsSpawned;
}
[UnityTest]
public IEnumerator WhenUsingAUserSerializableNetworkVariableWithUserSerialization_ReplicationWorks()
{
UserNetworkVariableSerialization<MyTypeOne>.WriteValue = (FastBufferWriter writer, in MyTypeOne value) =>
{
writer.WriteValueSafe(value.Value);
};
UserNetworkVariableSerialization<MyTypeOne>.ReadValue = (FastBufferReader reader, out MyTypeOne value) =>
{
value = new MyTypeOne();
reader.ReadValueSafe(out value.Value);
};
var serverObject = SpawnObject(m_WorkingPrefab, m_ServerNetworkManager);
var serverNetworkObject = serverObject.GetComponent<NetworkObject>();
// Wait for the client instance to be spawned, which removes the need to check for two NetworkVariableDeltaMessages
yield return WaitForConditionOrTimeOut(() => CheckForClientInstance<WorkingUserNetworkVariableComponent>());
AssertOnTimeout($"Timed out waiting for the client side object to spawn!");
// Get server and client instances of the test component
var clientInstance = WorkingUserNetworkVariableComponentBase.GetRelativeInstance<WorkingUserNetworkVariableComponent>(m_ClientNetworkManagers[0].LocalClientId);
var serverInstance = serverNetworkObject.GetComponent<WorkingUserNetworkVariableComponent>();
// Set the server side value
serverInstance.NetworkVariable.Value = new MyTypeOne { Value = 20 };
// Wait for the NetworkVariableDeltaMessage
yield return NetcodeIntegrationTestHelpers.WaitForMessageOfTypeReceived<NetworkVariableDeltaMessage>(m_ClientNetworkManagers[0]);
// Wait for the client side value to be updated to the server side value (can take an additional frame)
yield return WaitForConditionOrTimeOut(() => clientInstance.NetworkVariable.Value.Value == serverInstance.NetworkVariable.Value.Value);
Assert.AreEqual(serverNetworkObject.GetComponent<WorkingUserNetworkVariableComponent>().NetworkVariable.Value.Value, clientInstance.NetworkVariable.Value.Value);
Assert.AreEqual(20, clientInstance.NetworkVariable.Value.Value);
}
[UnityTest]
public IEnumerator WhenUsingAUserSerializableNetworkVariableWithUserSerializationViaExtensionMethod_ReplicationWorks()
{
UserNetworkVariableSerialization<MyTypeTwo>.WriteValue = NetworkVariableUserSerializableTypesTestsExtensionMethods.WriteValueSafe;
UserNetworkVariableSerialization<MyTypeTwo>.ReadValue = NetworkVariableUserSerializableTypesTestsExtensionMethods.ReadValueSafe;
var serverObject = SpawnObject(m_ExtensionMethodPrefab, m_ServerNetworkManager);
var serverNetworkObject = serverObject.GetComponent<NetworkObject>();
// Wait for the client instance to be spawned, which removes the need to check for two NetworkVariableDeltaMessages
yield return WaitForConditionOrTimeOut(() => CheckForClientInstance<WorkingUserNetworkVariableComponentUsingExtensionMethod>());
AssertOnTimeout($"Timed out waiting for the client side object to spawn!");
// Get server and client instances of the test component
var clientInstance = WorkingUserNetworkVariableComponentBase.GetRelativeInstance<WorkingUserNetworkVariableComponentUsingExtensionMethod>(m_ClientNetworkManagers[0].LocalClientId);
var serverInstance = serverNetworkObject.GetComponent<WorkingUserNetworkVariableComponentUsingExtensionMethod>();
// Set the server side value
serverInstance.NetworkVariable.Value = new MyTypeTwo { Value = 20 };
// Wait for the NetworkVariableDeltaMessage
yield return NetcodeIntegrationTestHelpers.WaitForMessageOfTypeReceived<NetworkVariableDeltaMessage>(m_ClientNetworkManagers[0]);
// Wait for the client side value to be updated to the server side value (can take an additional frame)
yield return WaitForConditionOrTimeOut(() => clientInstance.NetworkVariable.Value.Value == serverInstance.NetworkVariable.Value.Value);
AssertOnTimeout($"Timed out waiting for the client side object's value ({clientInstance.NetworkVariable.Value.Value}) to equal the server side objects value ({serverInstance.NetworkVariable.Value.Value})!");
Assert.AreEqual(serverInstance.NetworkVariable.Value.Value, clientInstance.NetworkVariable.Value.Value);
Assert.AreEqual(20, clientInstance.NetworkVariable.Value.Value);
}
[Test]
public void WhenUsingAUserSerializableNetworkVariableWithoutUserSerialization_ReplicationFails()
{
var serverObject = Object.Instantiate(m_NonWorkingPrefab);
var serverNetworkObject = serverObject.GetComponent<NetworkObject>();
serverNetworkObject.NetworkManagerOwner = m_ServerNetworkManager;
Assert.Throws<ArgumentException>(
() =>
{
serverNetworkObject.Spawn();
}
);
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: a1195640cf744e85b58c5af6d11eeb34
timeCreated: 1652907276

View File

@@ -2,6 +2,7 @@ using System;
using System.Collections;
using System.Collections.Generic;
using NUnit.Framework;
using Unity.Collections;
using UnityEngine.TestTools;
using Unity.Netcode.TestHelpers.Runtime;
using UnityEngine;
@@ -14,7 +15,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<Vector3, Vector3[], FixedString32Bytes> OnTypedServer_Rpc;
public event Action OnClient_Rpc;
[ServerRpc]
@@ -30,9 +31,9 @@ namespace Unity.Netcode.RuntimeTests
}
[ServerRpc]
public void MyTypedServerRpc(Vector3 param1, Vector3[] param2)
public void MyTypedServerRpc(Vector3 param1, Vector3[] param2, FixedString32Bytes param3)
{
OnTypedServer_Rpc(param1, param2);
OnTypedServer_Rpc(param1, param2, param3);
}
}
@@ -87,13 +88,16 @@ namespace Unity.Netcode.RuntimeTests
hasReceivedClientRpcLocally = true;
};
serverClientRpcTestNB.OnTypedServer_Rpc += (param1, param2) =>
var str = new FixedString32Bytes("abcdefg");
serverClientRpcTestNB.OnTypedServer_Rpc += (param1, param2, param3) =>
{
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]);
Assert.AreEqual(param3, str);
hasReceivedTypedServerRpc = true;
};
@@ -101,7 +105,7 @@ namespace Unity.Netcode.RuntimeTests
localClienRpcTestNB.MyServerRpc(m_ClientNetworkManagers[0].LocalClientId);
// Send TypedServerRpc
localClienRpcTestNB.MyTypedServerRpc(vector3, vector3s);
localClienRpcTestNB.MyTypedServerRpc(vector3, vector3s, str);
// Send ClientRpc
serverClientRpcTestNB.MyClientRpc();

View File

@@ -57,6 +57,9 @@ namespace Unity.Netcode.RuntimeTests
Assert.AreEqual(testNetworkBehaviour, testNetworkBehaviour.RpcReceivedBehaviour);
}
[UnityTest]
public IEnumerator TestRpcImplicitNetworkBehaviour()
{
@@ -149,4 +152,44 @@ namespace Unity.Netcode.RuntimeTests
NetworkManagerHelper.StartNetworkManager(out _);
}
}
/// <summary>
/// Integration tests for NetworkBehaviourReference
/// </summary>
public class NetworkBehaviourReferenceIntegrationTests : NetcodeIntegrationTest
{
protected override int NumberOfClients => 1;
internal class FakeMissingComponent : NetworkBehaviour
{
}
internal class TestAddedComponent : NetworkBehaviour
{
}
protected override void OnCreatePlayerPrefab()
{
m_PlayerPrefab.AddComponent<TestAddedComponent>();
base.OnCreatePlayerPrefab();
}
/// <summary>
/// This test validates that if a component does not exist the NetworkBehaviourReference will not throw an
/// invalid cast exception.
/// (It is a full integration test to assure the NetworkObjects are spawned)
/// </summary>
[UnityTest]
public IEnumerator TestTryGetWithAndWithOutExistingComponent()
{
var networkBehaviourReference = new NetworkBehaviourReference(m_ClientNetworkManagers[0].LocalClient.PlayerObject.GetComponent<TestAddedComponent>());
var missingComponent = (FakeMissingComponent)null;
var testBehaviour = (TestAddedComponent)null;
Assert.IsFalse(networkBehaviourReference.TryGet(out missingComponent));
Assert.IsTrue(networkBehaviourReference.TryGet(out testBehaviour));
yield return null;
}
}
}

View File

@@ -145,6 +145,7 @@ namespace Unity.Netcode.RuntimeTests
// Wait for connection on client and server side
yield return WaitForClientsConnectedOrTimeOut();
AssertOnTimeout($"Timed-out waiting for all clients to connect!");
}
private readonly struct NetworkTimeState : IEquatable<NetworkTimeState>

View File

@@ -33,11 +33,7 @@ namespace Unity.Netcode.RuntimeTests
// Move the nested object on the server
if (IsMoving)
{
var y = Time.realtimeSinceStartup;
while (y > 10.0f)
{
y -= 10.0f;
}
var y = Time.realtimeSinceStartup % 10.0f;
// change the space between local and global every second
GetComponent<NetworkTransform>().InLocalSpace = ((int)y % 2 == 0);
@@ -119,6 +115,7 @@ namespace Unity.Netcode.RuntimeTests
baseObject.GetComponent<TransformInterpolationObject>().IsFixed = true;
spawnedObject.GetComponent<TransformInterpolationObject>().IsMoving = true;
spawnedObject.GetComponent<NetworkTransform>().SetMaxInterpolationBound(1.0f);
const float maxPlacementError = 0.01f;
@@ -131,6 +128,7 @@ namespace Unity.Netcode.RuntimeTests
yield return new WaitForSeconds(0.01f);
}
m_SpawnedObjectOnClient.GetComponent<NetworkTransform>().SetMaxInterpolationBound(1.0f);
m_SpawnedObjectOnClient.GetComponent<TransformInterpolationObject>().CheckPosition = true;
// Test that interpolation works correctly for 10 seconds