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)
227 lines
8.4 KiB
C#
227 lines
8.4 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using NUnit.Framework;
|
|
using NUnit.Framework.Internal;
|
|
using Unity.Collections;
|
|
using Unity.Collections.LowLevel.Unsafe;
|
|
|
|
namespace Unity.Netcode.EditorTests
|
|
{
|
|
public class MessageReceivingTests
|
|
{
|
|
private struct TestMessage : INetworkMessage, INetworkSerializeByMemcpy
|
|
{
|
|
public int A;
|
|
public int B;
|
|
public int C;
|
|
public static bool Deserialized;
|
|
public static bool Handled;
|
|
public static List<TestMessage> DeserializedValues = new List<TestMessage>();
|
|
|
|
public void Serialize(FastBufferWriter writer)
|
|
{
|
|
writer.WriteValueSafe(this);
|
|
}
|
|
|
|
public bool Deserialize(FastBufferReader reader, ref NetworkContext context)
|
|
{
|
|
Deserialized = true;
|
|
reader.ReadValueSafe(out this);
|
|
return true;
|
|
}
|
|
|
|
public void Handle(ref NetworkContext context)
|
|
{
|
|
Handled = true;
|
|
DeserializedValues.Add(this);
|
|
}
|
|
}
|
|
|
|
private class TestMessageProvider : IMessageProvider
|
|
{
|
|
public List<MessagingSystem.MessageWithHandler> GetMessages()
|
|
{
|
|
return new List<MessagingSystem.MessageWithHandler>
|
|
{
|
|
new MessagingSystem.MessageWithHandler
|
|
{
|
|
MessageType = typeof(TestMessage),
|
|
Handler = MessagingSystem.ReceiveMessage<TestMessage>
|
|
}
|
|
};
|
|
}
|
|
}
|
|
|
|
private MessagingSystem m_MessagingSystem;
|
|
|
|
[SetUp]
|
|
public void SetUp()
|
|
{
|
|
TestMessage.Deserialized = false;
|
|
TestMessage.Handled = false;
|
|
TestMessage.DeserializedValues.Clear();
|
|
|
|
m_MessagingSystem = new MessagingSystem(new NopMessageSender(), this, new TestMessageProvider());
|
|
}
|
|
|
|
[TearDown]
|
|
public void TearDown()
|
|
{
|
|
m_MessagingSystem.Dispose();
|
|
}
|
|
|
|
private TestMessage GetMessage()
|
|
{
|
|
var random = new Random();
|
|
return new TestMessage
|
|
{
|
|
A = random.Next(),
|
|
B = random.Next(),
|
|
C = random.Next(),
|
|
};
|
|
}
|
|
|
|
[Test]
|
|
public void WhenHandlingAMessage_ReceiveMethodIsCalled()
|
|
{
|
|
var messageHeader = new MessageHeader
|
|
{
|
|
MessageSize = (ushort)UnsafeUtility.SizeOf<TestMessage>(),
|
|
MessageType = m_MessagingSystem.GetMessageType(typeof(TestMessage)),
|
|
};
|
|
var message = GetMessage();
|
|
|
|
var writer = new FastBufferWriter(1300, Allocator.Temp);
|
|
using (writer)
|
|
{
|
|
writer.TryBeginWrite(FastBufferWriter.GetWriteSize(message));
|
|
writer.WriteValue(message);
|
|
|
|
var reader = new FastBufferReader(writer, Allocator.Temp);
|
|
using (reader)
|
|
{
|
|
m_MessagingSystem.HandleMessage(messageHeader, reader, 0, 0, 0);
|
|
Assert.IsTrue(TestMessage.Deserialized);
|
|
Assert.IsTrue(TestMessage.Handled);
|
|
Assert.AreEqual(1, TestMessage.DeserializedValues.Count);
|
|
Assert.AreEqual(message, TestMessage.DeserializedValues[0]);
|
|
}
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void WhenHandlingIncomingData_ReceiveIsNotCalledBeforeProcessingIncomingMessageQueue()
|
|
{
|
|
var batchHeader = new BatchHeader
|
|
{
|
|
BatchSize = 1
|
|
};
|
|
var messageHeader = new MessageHeader
|
|
{
|
|
MessageSize = (ushort)UnsafeUtility.SizeOf<TestMessage>(),
|
|
MessageType = m_MessagingSystem.GetMessageType(typeof(TestMessage)),
|
|
};
|
|
var message = GetMessage();
|
|
|
|
var writer = new FastBufferWriter(1300, Allocator.Temp);
|
|
using (writer)
|
|
{
|
|
writer.TryBeginWrite(FastBufferWriter.GetWriteSize(batchHeader) +
|
|
FastBufferWriter.GetWriteSize(messageHeader) +
|
|
FastBufferWriter.GetWriteSize(message));
|
|
writer.WriteValue(batchHeader);
|
|
writer.WriteValue(messageHeader);
|
|
writer.WriteValue(message);
|
|
|
|
var reader = new FastBufferReader(writer, Allocator.Temp);
|
|
using (reader)
|
|
{
|
|
m_MessagingSystem.HandleIncomingData(0, new ArraySegment<byte>(writer.ToArray()), 0);
|
|
Assert.IsFalse(TestMessage.Deserialized);
|
|
Assert.IsFalse(TestMessage.Handled);
|
|
Assert.IsEmpty(TestMessage.DeserializedValues);
|
|
}
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void WhenReceivingAMessageAndProcessingMessageQueue_ReceiveMethodIsCalled()
|
|
{
|
|
var batchHeader = new BatchHeader
|
|
{
|
|
BatchSize = 1
|
|
};
|
|
var messageHeader = new MessageHeader
|
|
{
|
|
MessageSize = (uint)UnsafeUtility.SizeOf<TestMessage>(),
|
|
MessageType = m_MessagingSystem.GetMessageType(typeof(TestMessage)),
|
|
};
|
|
var message = GetMessage();
|
|
|
|
var writer = new FastBufferWriter(1300, Allocator.Temp);
|
|
using (writer)
|
|
{
|
|
writer.WriteValueSafe(batchHeader);
|
|
BytePacker.WriteValueBitPacked(writer, messageHeader.MessageType);
|
|
BytePacker.WriteValueBitPacked(writer, messageHeader.MessageSize);
|
|
writer.WriteValueSafe(message);
|
|
|
|
var reader = new FastBufferReader(writer, Allocator.Temp);
|
|
using (reader)
|
|
{
|
|
m_MessagingSystem.HandleIncomingData(0, new ArraySegment<byte>(writer.ToArray()), 0);
|
|
m_MessagingSystem.ProcessIncomingMessageQueue();
|
|
Assert.IsTrue(TestMessage.Deserialized);
|
|
Assert.IsTrue(TestMessage.Handled);
|
|
Assert.AreEqual(1, TestMessage.DeserializedValues.Count);
|
|
Assert.AreEqual(message, TestMessage.DeserializedValues[0]);
|
|
}
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void WhenReceivingMultipleMessagesAndProcessingMessageQueue_ReceiveMethodIsCalledMultipleTimes()
|
|
{
|
|
var batchHeader = new BatchHeader
|
|
{
|
|
BatchSize = 2
|
|
};
|
|
var messageHeader = new MessageHeader
|
|
{
|
|
MessageSize = (ushort)UnsafeUtility.SizeOf<TestMessage>(),
|
|
MessageType = m_MessagingSystem.GetMessageType(typeof(TestMessage)),
|
|
};
|
|
var message = GetMessage();
|
|
var message2 = GetMessage();
|
|
|
|
var writer = new FastBufferWriter(1300, Allocator.Temp);
|
|
using (writer)
|
|
{
|
|
writer.WriteValueSafe(batchHeader);
|
|
BytePacker.WriteValueBitPacked(writer, messageHeader.MessageType);
|
|
BytePacker.WriteValueBitPacked(writer, messageHeader.MessageSize);
|
|
writer.WriteValueSafe(message);
|
|
BytePacker.WriteValueBitPacked(writer, messageHeader.MessageType);
|
|
BytePacker.WriteValueBitPacked(writer, messageHeader.MessageSize);
|
|
writer.WriteValueSafe(message2);
|
|
|
|
var reader = new FastBufferReader(writer, Allocator.Temp);
|
|
using (reader)
|
|
{
|
|
m_MessagingSystem.HandleIncomingData(0, new ArraySegment<byte>(writer.ToArray()), 0);
|
|
Assert.IsFalse(TestMessage.Deserialized);
|
|
Assert.IsFalse(TestMessage.Handled);
|
|
Assert.IsEmpty(TestMessage.DeserializedValues);
|
|
|
|
m_MessagingSystem.ProcessIncomingMessageQueue();
|
|
Assert.IsTrue(TestMessage.Deserialized);
|
|
Assert.IsTrue(TestMessage.Handled);
|
|
Assert.AreEqual(2, TestMessage.DeserializedValues.Count);
|
|
Assert.AreEqual(message, TestMessage.DeserializedValues[0]);
|
|
Assert.AreEqual(message2, TestMessage.DeserializedValues[1]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|