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.7.0] - 2023-10-11 ### Added - exposed NetworkObject.GetNetworkBehaviourAtOrderIndex as a public API (#2724) - Added context menu tool that provides users with the ability to quickly update the GlobalObjectIdHash value for all in-scene placed prefab instances that were created prior to adding a NetworkObject component to it. (#2707) - Added methods NetworkManager.SetPeerMTU and NetworkManager.GetPeerMTU to be able to set MTU sizes per-peer (#2676) - Added `GenerateSerializationForGenericParameterAttribute`, which can be applied to user-created Network Variable types to ensure the codegen generates serialization for the generic types they wrap. (#2694) - Added `GenerateSerializationForTypeAttribute`, which can be applied to any class or method to ensure the codegen generates serialization for the specific provided type. (#2694) - Exposed `NetworkVariableSerialization<T>.Read`, `NetworkVariableSerialization<T>.Write`, `NetworkVariableSerialization<T>.AreEqual`, and `NetworkVariableSerialization<T>.Duplicate` to further support the creation of user-created network variables by allowing users to access the generated serialization methods and serialize generic types efficiently without boxing. (#2694) - Added `NetworkVariableBase.MarkNetworkBehaviourDirty` so that user-created network variable types can mark their containing `NetworkBehaviour` to be processed by the update loop. (#2694) ### Fixed - Fixed issue where the server side `NetworkSceneManager` instance was not adding the currently active scene to its list of scenes loaded. (#2723) - Generic NetworkBehaviour types no longer result in compile errors or runtime errors (#2720) - Rpcs within Generic NetworkBehaviour types can now serialize parameters of the class's generic types (but may not have generic types of their own) (#2720) - Errors are no longer thrown when entering play mode with domain reload disabled (#2720) - NetworkSpawn is now correctly called each time when entering play mode with scene reload disabled (#2720) - NetworkVariables of non-integer types will no longer break the inspector (#2714) - NetworkVariables with NonSerializedAttribute will not appear in the inspector (#2714) - Fixed issue where `UnityTransport` would attempt to establish WebSocket connections even if using UDP/DTLS Relay allocations when the build target was WebGL. This only applied to working in the editor since UDP/DTLS can't work in the browser. (#2695) - Fixed issue where a `NetworkBehaviour` component's `OnNetworkDespawn` was not being invoked on the host-server side for an in-scene placed `NetworkObject` when a scene was unloaded (during a scene transition) and the `NetworkBehaviour` component was positioned/ordered before the `NetworkObject` component. (#2685) - Fixed issue where `SpawnWithObservers` was not being honored when `NetworkConfig.EnableSceneManagement` was disabled. (#2682) - Fixed issue where `NetworkAnimator` was not internally tracking changes to layer weights which prevented proper layer weight synchronization back to the original layer weight value. (#2674) - Fixed "writing past the end of the buffer" error when calling ResetDirty() on managed network variables that are larger than 256 bytes when serialized. (#2670) - Fixed issue where generation of the `DefaultNetworkPrefabs` asset was not enabled by default. (#2662) - Fixed issue where the `GlobalObjectIdHash` value could be updated but the asset not marked as dirty. (#2662) - Fixed issue where the `GlobalObjectIdHash` value of a (network) prefab asset could be assigned an incorrect value when editing the prefab in a temporary scene. (#2662) - Fixed issue where the `GlobalObjectIdHash` value generated after creating a (network) prefab from an object constructed within the scene would not be the correct final value in a stand alone build. (#2662) ### Changed - Updated dependency on `com.unity.transport` to version 1.4.0. (#2716)
366 lines
13 KiB
C#
366 lines
13 KiB
C#
using System;
|
|
using NUnit.Framework;
|
|
using Unity.Collections;
|
|
using Unity.Netcode.Transports.UTP;
|
|
using Unity.Networking.Transport;
|
|
|
|
namespace Unity.Netcode.EditorTests
|
|
{
|
|
public class BatchedSendQueueTests
|
|
{
|
|
private const int k_TestQueueCapacity = 16 * 1024;
|
|
private const int k_TestMessageSize = 1020;
|
|
private const int k_NumMessagesToFillQueue = k_TestQueueCapacity / (k_TestMessageSize + BatchedSendQueue.PerMessageOverhead);
|
|
|
|
private ArraySegment<byte> m_TestMessage;
|
|
|
|
private void AssertIsTestMessage(NativeArray<byte> data)
|
|
{
|
|
var reader = new DataStreamReader(data);
|
|
Assert.AreEqual(k_TestMessageSize, reader.ReadInt());
|
|
for (int i = 0; i < k_TestMessageSize; i++)
|
|
{
|
|
Assert.AreEqual(m_TestMessage.Array[i], reader.ReadByte());
|
|
}
|
|
}
|
|
|
|
[OneTimeSetUp]
|
|
public void InitializeTestMessage()
|
|
{
|
|
var data = new byte[k_TestMessageSize];
|
|
for (int i = 0; i < k_TestMessageSize; i++)
|
|
{
|
|
data[i] = (byte)i;
|
|
}
|
|
m_TestMessage = new ArraySegment<byte>(data);
|
|
}
|
|
|
|
[Test]
|
|
public void BatchedSendQueue_EmptyOnCreation()
|
|
{
|
|
using var q = new BatchedSendQueue(k_TestQueueCapacity);
|
|
|
|
Assert.AreEqual(0, q.Length);
|
|
Assert.True(q.IsEmpty);
|
|
}
|
|
|
|
[Test]
|
|
public void BatchedSendQueue_NotCreatedAfterDispose()
|
|
{
|
|
var q = new BatchedSendQueue(k_TestQueueCapacity);
|
|
q.Dispose();
|
|
Assert.False(q.IsCreated);
|
|
}
|
|
|
|
[Test]
|
|
public void BatchedSendQueue_InitialCapacityLessThanMaximum()
|
|
{
|
|
using var q = new BatchedSendQueue(k_TestQueueCapacity);
|
|
Assert.AreEqual(q.Capacity, BatchedSendQueue.MinimumMinimumCapacity);
|
|
}
|
|
|
|
[Test]
|
|
public void BatchedSendQueue_PushMessage_ReturnValue()
|
|
{
|
|
// Will fit a single test message, but not two (with overhead included).
|
|
var queueCapacity = (k_TestMessageSize * 2) + BatchedSendQueue.PerMessageOverhead;
|
|
|
|
using var q = new BatchedSendQueue(queueCapacity);
|
|
|
|
Assert.True(q.PushMessage(m_TestMessage));
|
|
Assert.False(q.PushMessage(m_TestMessage));
|
|
}
|
|
|
|
[Test]
|
|
public void BatchedSendQueue_PushMessage_IncreasesLength()
|
|
{
|
|
using var q = new BatchedSendQueue(k_TestQueueCapacity);
|
|
|
|
q.PushMessage(m_TestMessage);
|
|
Assert.AreEqual(k_TestMessageSize + BatchedSendQueue.PerMessageOverhead, q.Length);
|
|
}
|
|
|
|
[Test]
|
|
public void BatchedSendQueue_PushMessage_SucceedsAfterConsume()
|
|
{
|
|
var messageLength = k_TestMessageSize + BatchedSendQueue.PerMessageOverhead;
|
|
var queueCapacity = messageLength * 2;
|
|
|
|
using var q = new BatchedSendQueue(queueCapacity);
|
|
|
|
q.PushMessage(m_TestMessage);
|
|
q.PushMessage(m_TestMessage);
|
|
|
|
q.Consume(messageLength);
|
|
Assert.IsTrue(q.PushMessage(m_TestMessage));
|
|
Assert.AreEqual(queueCapacity, q.Length);
|
|
}
|
|
|
|
[Test]
|
|
public void BatchedSendQueue_PushMessage_GrowsDataIfNeeded()
|
|
{
|
|
using var q = new BatchedSendQueue(k_TestQueueCapacity);
|
|
var messageLength = k_TestMessageSize + BatchedSendQueue.PerMessageOverhead;
|
|
|
|
Assert.AreEqual(q.Capacity, BatchedSendQueue.MinimumMinimumCapacity);
|
|
|
|
var numMessagesToFillMinimum = BatchedSendQueue.MinimumMinimumCapacity / messageLength;
|
|
for (int i = 0; i < numMessagesToFillMinimum; i++)
|
|
{
|
|
q.PushMessage(m_TestMessage);
|
|
}
|
|
|
|
Assert.AreEqual(q.Capacity, BatchedSendQueue.MinimumMinimumCapacity);
|
|
|
|
q.PushMessage(m_TestMessage);
|
|
|
|
Assert.AreEqual(q.Capacity, BatchedSendQueue.MinimumMinimumCapacity * 2);
|
|
}
|
|
|
|
[Test]
|
|
public void BatchedSendQueue_PushMessage_DoesNotGrowDataPastMaximum()
|
|
{
|
|
using var q = new BatchedSendQueue(k_TestQueueCapacity);
|
|
|
|
for (int i = 0; i < k_NumMessagesToFillQueue; i++)
|
|
{
|
|
Assert.IsTrue(q.PushMessage(m_TestMessage));
|
|
}
|
|
|
|
Assert.AreEqual(q.Capacity, k_TestQueueCapacity);
|
|
Assert.IsFalse(q.PushMessage(m_TestMessage));
|
|
Assert.AreEqual(q.Capacity, k_TestQueueCapacity);
|
|
}
|
|
|
|
[Test]
|
|
public void BatchedSendQueue_PushMessage_TrimsDataAfterGrowing()
|
|
{
|
|
using var q = new BatchedSendQueue(k_TestQueueCapacity);
|
|
var messageLength = k_TestMessageSize + BatchedSendQueue.PerMessageOverhead;
|
|
|
|
for (int i = 0; i < k_NumMessagesToFillQueue; i++)
|
|
{
|
|
Assert.IsTrue(q.PushMessage(m_TestMessage));
|
|
}
|
|
|
|
Assert.AreEqual(q.Capacity, k_TestQueueCapacity);
|
|
q.Consume(messageLength * (k_NumMessagesToFillQueue - 1));
|
|
Assert.IsTrue(q.PushMessage(m_TestMessage));
|
|
Assert.AreEqual(messageLength * 2, q.Length);
|
|
Assert.AreEqual(q.Capacity, BatchedSendQueue.MinimumMinimumCapacity * 2);
|
|
}
|
|
|
|
[Test]
|
|
public void BatchedSendQueue_FillWriterWithMessages_ReturnValue()
|
|
{
|
|
using var q = new BatchedSendQueue(k_TestQueueCapacity);
|
|
using var data = new NativeArray<byte>(k_TestQueueCapacity, Allocator.Temp);
|
|
|
|
q.PushMessage(m_TestMessage);
|
|
|
|
var writer = new DataStreamWriter(data);
|
|
var filled = q.FillWriterWithMessages(ref writer);
|
|
Assert.AreEqual(k_TestMessageSize + BatchedSendQueue.PerMessageOverhead, filled);
|
|
}
|
|
|
|
[Test]
|
|
public void BatchedSendQueue_FillWriterWithMessages_NoopIfNoPushedMessages()
|
|
{
|
|
using var q = new BatchedSendQueue(k_TestQueueCapacity);
|
|
using var data = new NativeArray<byte>(k_TestQueueCapacity, Allocator.Temp);
|
|
|
|
var writer = new DataStreamWriter(data);
|
|
Assert.AreEqual(0, q.FillWriterWithMessages(ref writer));
|
|
}
|
|
|
|
[Test]
|
|
public void BatchedSendQueue_FillWriterWithMessages_NoopIfNotEnoughCapacity()
|
|
{
|
|
using var q = new BatchedSendQueue(k_TestQueueCapacity);
|
|
using var data = new NativeArray<byte>(2, Allocator.Temp);
|
|
|
|
q.PushMessage(m_TestMessage);
|
|
|
|
var writer = new DataStreamWriter(data);
|
|
Assert.AreEqual(0, q.FillWriterWithMessages(ref writer));
|
|
}
|
|
|
|
[Test]
|
|
public void BatchedSendQueue_FillWriterWithMessages_SinglePushedMessage()
|
|
{
|
|
using var q = new BatchedSendQueue(k_TestQueueCapacity);
|
|
using var data = new NativeArray<byte>(k_TestQueueCapacity, Allocator.Temp);
|
|
|
|
q.PushMessage(m_TestMessage);
|
|
|
|
var writer = new DataStreamWriter(data);
|
|
q.FillWriterWithMessages(ref writer);
|
|
AssertIsTestMessage(data);
|
|
}
|
|
|
|
[Test]
|
|
public void BatchedSendQueue_FillWriterWithMessages_MultiplePushedMessages()
|
|
{
|
|
using var q = new BatchedSendQueue(k_TestQueueCapacity);
|
|
using var data = new NativeArray<byte>(k_TestQueueCapacity, Allocator.Temp);
|
|
|
|
q.PushMessage(m_TestMessage);
|
|
q.PushMessage(m_TestMessage);
|
|
|
|
var writer = new DataStreamWriter(data);
|
|
q.FillWriterWithMessages(ref writer);
|
|
|
|
var messageLength = k_TestMessageSize + BatchedSendQueue.PerMessageOverhead;
|
|
AssertIsTestMessage(data);
|
|
AssertIsTestMessage(data.GetSubArray(messageLength, messageLength));
|
|
}
|
|
|
|
[Test]
|
|
public void BatchedSendQueue_FillWriterWithMessages_PartialPushedMessages()
|
|
{
|
|
var messageLength = k_TestMessageSize + BatchedSendQueue.PerMessageOverhead;
|
|
|
|
using var q = new BatchedSendQueue(k_TestQueueCapacity);
|
|
using var data = new NativeArray<byte>(messageLength, Allocator.Temp);
|
|
|
|
q.PushMessage(m_TestMessage);
|
|
q.PushMessage(m_TestMessage);
|
|
|
|
var writer = new DataStreamWriter(data);
|
|
Assert.AreEqual(messageLength, q.FillWriterWithMessages(ref writer));
|
|
AssertIsTestMessage(data);
|
|
|
|
q.Consume(messageLength);
|
|
|
|
writer = new DataStreamWriter(data);
|
|
Assert.AreEqual(messageLength, q.FillWriterWithMessages(ref writer));
|
|
AssertIsTestMessage(data);
|
|
}
|
|
|
|
[Test]
|
|
public void BatchedSendQueue_FillWriterWithBytes_NoopIfNoData()
|
|
{
|
|
using var q = new BatchedSendQueue(k_TestQueueCapacity);
|
|
using var data = new NativeArray<byte>(k_TestQueueCapacity, Allocator.Temp);
|
|
|
|
var writer = new DataStreamWriter(data);
|
|
Assert.AreEqual(0, q.FillWriterWithBytes(ref writer));
|
|
}
|
|
|
|
[Test]
|
|
public void BatchedSendQueue_FillWriterWithBytes_WriterCapacityMoreThanLength()
|
|
{
|
|
var dataLength = k_TestMessageSize + BatchedSendQueue.PerMessageOverhead;
|
|
|
|
using var q = new BatchedSendQueue(k_TestQueueCapacity);
|
|
using var data = new NativeArray<byte>(k_TestQueueCapacity, Allocator.Temp);
|
|
|
|
q.PushMessage(m_TestMessage);
|
|
|
|
var writer = new DataStreamWriter(data);
|
|
Assert.AreEqual(dataLength, q.FillWriterWithBytes(ref writer));
|
|
AssertIsTestMessage(data);
|
|
}
|
|
|
|
[Test]
|
|
public void BatchedSendQueue_FillWriterWithBytes_WriterCapacityLessThanLength()
|
|
{
|
|
var dataLength = k_TestMessageSize + BatchedSendQueue.PerMessageOverhead;
|
|
|
|
using var q = new BatchedSendQueue(k_TestQueueCapacity);
|
|
using var data = new NativeArray<byte>(dataLength, Allocator.Temp);
|
|
|
|
q.PushMessage(m_TestMessage);
|
|
q.PushMessage(m_TestMessage);
|
|
|
|
var writer = new DataStreamWriter(data);
|
|
Assert.AreEqual(dataLength, q.FillWriterWithBytes(ref writer));
|
|
AssertIsTestMessage(data);
|
|
}
|
|
|
|
[Test]
|
|
public void BatchedSendQueue_FillWriterWithBytes_WriterCapacityEqualToLength()
|
|
{
|
|
var dataLength = k_TestMessageSize + BatchedSendQueue.PerMessageOverhead;
|
|
|
|
using var q = new BatchedSendQueue(k_TestQueueCapacity);
|
|
using var data = new NativeArray<byte>(dataLength, Allocator.Temp);
|
|
|
|
q.PushMessage(m_TestMessage);
|
|
|
|
var writer = new DataStreamWriter(data);
|
|
Assert.AreEqual(dataLength, q.FillWriterWithBytes(ref writer));
|
|
AssertIsTestMessage(data);
|
|
}
|
|
|
|
[Test]
|
|
public void BatchedSendQueue_FillWriterWithBytes_MaxBytesGreaterThanCapacity()
|
|
{
|
|
var dataLength = k_TestMessageSize + BatchedSendQueue.PerMessageOverhead;
|
|
|
|
using var q = new BatchedSendQueue(k_TestQueueCapacity);
|
|
using var data = new NativeArray<byte>(dataLength, Allocator.Temp);
|
|
|
|
q.PushMessage(m_TestMessage);
|
|
q.PushMessage(m_TestMessage);
|
|
|
|
var writer = new DataStreamWriter(data);
|
|
Assert.AreEqual(dataLength, q.FillWriterWithBytes(ref writer, dataLength * 2));
|
|
AssertIsTestMessage(data);
|
|
Assert.False(writer.HasFailedWrites);
|
|
}
|
|
|
|
[Test]
|
|
public void BatchedSendQueue_Consume_LessThanLength()
|
|
{
|
|
using var q = new BatchedSendQueue(k_TestQueueCapacity);
|
|
|
|
q.PushMessage(m_TestMessage);
|
|
q.PushMessage(m_TestMessage);
|
|
|
|
var messageLength = k_TestMessageSize + BatchedSendQueue.PerMessageOverhead;
|
|
q.Consume(messageLength);
|
|
Assert.AreEqual(messageLength, q.Length);
|
|
}
|
|
|
|
[Test]
|
|
public void BatchedSendQueue_Consume_ExactLength()
|
|
{
|
|
using var q = new BatchedSendQueue(k_TestQueueCapacity);
|
|
|
|
q.PushMessage(m_TestMessage);
|
|
|
|
q.Consume(k_TestMessageSize + BatchedSendQueue.PerMessageOverhead);
|
|
Assert.AreEqual(0, q.Length);
|
|
Assert.True(q.IsEmpty);
|
|
}
|
|
|
|
[Test]
|
|
public void BatchedSendQueue_Consume_MoreThanLength()
|
|
{
|
|
using var q = new BatchedSendQueue(k_TestQueueCapacity);
|
|
|
|
q.PushMessage(m_TestMessage);
|
|
|
|
q.Consume(k_TestQueueCapacity);
|
|
Assert.AreEqual(0, q.Length);
|
|
Assert.True(q.IsEmpty);
|
|
}
|
|
|
|
[Test]
|
|
public void BatchedSendQueue_Consume_TrimsDataOnEmpty()
|
|
{
|
|
using var q = new BatchedSendQueue(k_TestQueueCapacity);
|
|
|
|
for (int i = 0; i < k_NumMessagesToFillQueue; i++)
|
|
{
|
|
q.PushMessage(m_TestMessage);
|
|
}
|
|
|
|
Assert.AreEqual(q.Capacity, k_TestQueueCapacity);
|
|
q.Consume(k_TestQueueCapacity);
|
|
Assert.AreEqual(q.Capacity, BatchedSendQueue.MinimumMinimumCapacity);
|
|
}
|
|
}
|
|
}
|