From 3eb0fad8926397b75402c5c6aff36e9bcac28f98 Mon Sep 17 00:00:00 2001 From: PitouGames Date: Sat, 19 Apr 2025 11:01:06 +0200 Subject: [PATCH 1/3] feat: Add built-in serialization for UnityEngine.Pose (#2675) --- .../Editor/CodeGen/CodeGenHelpers.cs | 6 + .../Editor/CodeGen/NetworkBehaviourILPP.cs | 1 + .../Runtime/Serialization/BufferSerializer.cs | 30 ++++ .../Serialization/BufferSerializerReader.cs | 6 + .../Serialization/BufferSerializerWriter.cs | 6 + .../Runtime/Serialization/BytePacker.cs | 17 +++ .../Runtime/Serialization/ByteUnpacker.cs | 18 +++ .../Runtime/Serialization/FastBufferReader.cs | 34 +++++ .../Runtime/Serialization/FastBufferWriter.cs | 34 +++++ .../Runtime/Serialization/IReaderWriter.cs | 30 ++++ .../BaseFastBufferReaderWriterTest.cs | 46 ++++++ .../Editor/Serialization/BytePackerTests.cs | 11 +- .../Serialization/FastBufferReaderTests.cs | 9 +- .../Serialization/FastBufferWriterTests.cs | 8 +- .../NetworkVariableTestComponent.cs | 13 ++ .../NetworkVariable/NetworkVariableTests.cs | 136 ++++++++++++++++-- .../NetworkVariableTestsHelperTypes.cs | 17 +++ .../Runtime/RpcTypeSerializationTests.cs | 58 +++++++- 18 files changed, 457 insertions(+), 23 deletions(-) diff --git a/com.unity.netcode.gameobjects/Editor/CodeGen/CodeGenHelpers.cs b/com.unity.netcode.gameobjects/Editor/CodeGen/CodeGenHelpers.cs index 75387fa8db..8d29e112f0 100644 --- a/com.unity.netcode.gameobjects/Editor/CodeGen/CodeGenHelpers.cs +++ b/com.unity.netcode.gameobjects/Editor/CodeGen/CodeGenHelpers.cs @@ -44,6 +44,7 @@ internal static class CodeGenHelpers public static readonly string UnityVector3_FullName = typeof(Vector3).FullName; public static readonly string UnityVector4_FullName = typeof(Vector4).FullName; public static readonly string UnityQuaternion_FullName = typeof(Quaternion).FullName; + public static readonly string UnityPose_FullName = typeof(Pose).FullName; public static readonly string UnityRay_FullName = typeof(Ray).FullName; public static readonly string UnityRay2D_FullName = typeof(Ray2D).FullName; @@ -308,6 +309,11 @@ public static bool IsSerializable(this TypeReference typeReference) return true; } + if (typeReference.FullName == UnityPose_FullName) + { + return true; + } + if (typeReference.FullName == UnityRay_FullName) { return true; diff --git a/com.unity.netcode.gameobjects/Editor/CodeGen/NetworkBehaviourILPP.cs b/com.unity.netcode.gameobjects/Editor/CodeGen/NetworkBehaviourILPP.cs index e67ee0ef81..a95c9ec1d6 100644 --- a/com.unity.netcode.gameobjects/Editor/CodeGen/NetworkBehaviourILPP.cs +++ b/com.unity.netcode.gameobjects/Editor/CodeGen/NetworkBehaviourILPP.cs @@ -563,6 +563,7 @@ private void CreateNetworkVariableTypeInitializers(AssemblyDefinition assembly, typeof(Vector3Int), typeof(Vector4), typeof(Quaternion), + typeof(Pose), typeof(Color), typeof(Color32), typeof(Ray), diff --git a/com.unity.netcode.gameobjects/Runtime/Serialization/BufferSerializer.cs b/com.unity.netcode.gameobjects/Runtime/Serialization/BufferSerializer.cs index faf4c960fa..155f32eff6 100644 --- a/com.unity.netcode.gameobjects/Runtime/Serialization/BufferSerializer.cs +++ b/com.unity.netcode.gameobjects/Runtime/Serialization/BufferSerializer.cs @@ -231,6 +231,18 @@ public FastBufferWriter GetFastBufferWriter() /// The values to read/write public void SerializeValue(ref Quaternion[] value) => m_Implementation.SerializeValue(ref value); + /// + /// Read or write a Pose value + /// + /// The value to read/write + public void SerializeValue(ref Pose value) => m_Implementation.SerializeValue(ref value); + + /// + /// Read or write an array of Pose values + /// + /// The values to read/write + public void SerializeValue(ref Pose[] value) => m_Implementation.SerializeValue(ref value); + /// /// Read or write a Color value /// @@ -553,6 +565,24 @@ public bool PreCheck(int amount) /// The value to read/write public void SerializeValuePreChecked(ref Quaternion[] value) => m_Implementation.SerializeValuePreChecked(ref value); + /// + /// Serialize a Pose, "pre-checked", which skips buffer checks. + /// In debug and editor builds, a check is made to ensure you've called "PreCheck" before + /// calling this. In release builds, calling this without calling "PreCheck" may read or write + /// past the end of the buffer, which will cause memory corruption and undefined behavior. + /// + /// The value to read/write + public void SerializeValuePreChecked(ref Pose value) => m_Implementation.SerializeValuePreChecked(ref value); + + /// + /// Serialize a Pose array, "pre-checked", which skips buffer checks. + /// In debug and editor builds, a check is made to ensure you've called "PreCheck" before + /// calling this. In release builds, calling this without calling "PreCheck" may read or write + /// past the end of the buffer, which will cause memory corruption and undefined behavior. + /// + /// The value to read/write + public void SerializeValuePreChecked(ref Pose[] value) => m_Implementation.SerializeValuePreChecked(ref value); + /// /// Serialize a Color, "pre-checked", which skips buffer checks. /// In debug and editor builds, a check is made to ensure you've called "PreCheck" before diff --git a/com.unity.netcode.gameobjects/Runtime/Serialization/BufferSerializerReader.cs b/com.unity.netcode.gameobjects/Runtime/Serialization/BufferSerializerReader.cs index d41d81b160..ffaa2ea9c6 100644 --- a/com.unity.netcode.gameobjects/Runtime/Serialization/BufferSerializerReader.cs +++ b/com.unity.netcode.gameobjects/Runtime/Serialization/BufferSerializerReader.cs @@ -71,6 +71,9 @@ public void SerializeValue(ref T value, FastBufferWriter.ForFixedStrings unus public void SerializeValue(ref Quaternion value) => m_Reader.ReadValueSafe(out value); public void SerializeValue(ref Quaternion[] value) => m_Reader.ReadValueSafe(out value); + public void SerializeValue(ref Pose value) => m_Reader.ReadValueSafe(out value); + public void SerializeValue(ref Pose[] value) => m_Reader.ReadValueSafe(out value); + public void SerializeValue(ref Color value) => m_Reader.ReadValueSafe(out value); public void SerializeValue(ref Color[] value) => m_Reader.ReadValueSafe(out value); @@ -127,6 +130,9 @@ public void SerializeValuePreChecked(ref T value, FastBufferWriter.ForFixedSt public void SerializeValuePreChecked(ref Quaternion value) => m_Reader.ReadValue(out value); public void SerializeValuePreChecked(ref Quaternion[] value) => m_Reader.ReadValue(out value); + public void SerializeValuePreChecked(ref Pose value) => m_Reader.ReadValue(out value); + public void SerializeValuePreChecked(ref Pose[] value) => m_Reader.ReadValue(out value); + public void SerializeValuePreChecked(ref Color value) => m_Reader.ReadValue(out value); public void SerializeValuePreChecked(ref Color[] value) => m_Reader.ReadValue(out value); diff --git a/com.unity.netcode.gameobjects/Runtime/Serialization/BufferSerializerWriter.cs b/com.unity.netcode.gameobjects/Runtime/Serialization/BufferSerializerWriter.cs index fd3b0c68fb..4c3b338009 100644 --- a/com.unity.netcode.gameobjects/Runtime/Serialization/BufferSerializerWriter.cs +++ b/com.unity.netcode.gameobjects/Runtime/Serialization/BufferSerializerWriter.cs @@ -70,6 +70,9 @@ public void SerializeValue(ref T value, FastBufferWriter.ForFixedStrings unus public void SerializeValue(ref Quaternion value) => m_Writer.WriteValueSafe(value); public void SerializeValue(ref Quaternion[] value) => m_Writer.WriteValueSafe(value); + public void SerializeValue(ref Pose value) => m_Writer.WriteValueSafe(value); + public void SerializeValue(ref Pose[] value) => m_Writer.WriteValueSafe(value); + public void SerializeValue(ref Color value) => m_Writer.WriteValueSafe(value); public void SerializeValue(ref Color[] value) => m_Writer.WriteValueSafe(value); @@ -128,6 +131,9 @@ public void SerializeValuePreChecked(ref T value, FastBufferWriter.ForFixedSt public void SerializeValuePreChecked(ref Quaternion value) => m_Writer.WriteValue(value); public void SerializeValuePreChecked(ref Quaternion[] value) => m_Writer.WriteValue(value); + public void SerializeValuePreChecked(ref Pose value) => m_Writer.WriteValue(value); + public void SerializeValuePreChecked(ref Pose[] value) => m_Writer.WriteValue(value); + public void SerializeValuePreChecked(ref Color value) => m_Writer.WriteValue(value); public void SerializeValuePreChecked(ref Color[] value) => m_Writer.WriteValue(value); diff --git a/com.unity.netcode.gameobjects/Runtime/Serialization/BytePacker.cs b/com.unity.netcode.gameobjects/Runtime/Serialization/BytePacker.cs index b064f2dbce..6e45f2b5b8 100644 --- a/com.unity.netcode.gameobjects/Runtime/Serialization/BytePacker.cs +++ b/com.unity.netcode.gameobjects/Runtime/Serialization/BytePacker.cs @@ -259,6 +259,23 @@ public static void WriteValuePacked(FastBufferWriter writer, Quaternion rotation WriteValuePacked(writer, rotation.w); } + /// + /// Writes the pose to the buffer. + /// + /// The writer to write to + /// Pose to write + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void WriteValuePacked(FastBufferWriter writer, Pose pose) + { + WriteValuePacked(writer, pose.position.x); + WriteValuePacked(writer, pose.position.y); + WriteValuePacked(writer, pose.position.z); + WriteValuePacked(writer, pose.rotation.x); + WriteValuePacked(writer, pose.rotation.y); + WriteValuePacked(writer, pose.rotation.z); + WriteValuePacked(writer, pose.rotation.w); + } + /// /// Writes a string in a packed format /// diff --git a/com.unity.netcode.gameobjects/Runtime/Serialization/ByteUnpacker.cs b/com.unity.netcode.gameobjects/Runtime/Serialization/ByteUnpacker.cs index 2c84fff991..d215bebe33 100644 --- a/com.unity.netcode.gameobjects/Runtime/Serialization/ByteUnpacker.cs +++ b/com.unity.netcode.gameobjects/Runtime/Serialization/ByteUnpacker.cs @@ -278,6 +278,24 @@ public static void ReadValuePacked(FastBufferReader reader, out Quaternion rotat ReadValuePacked(reader, out rotation.w); } + /// + /// Reads the pose from the stream. + /// + /// The reader to read from + /// Pose to read + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void ReadValuePacked(FastBufferReader reader, out Pose pose) + { + pose = new Pose(); + ReadValuePacked(reader, out pose.position.x); + ReadValuePacked(reader, out pose.position.y); + ReadValuePacked(reader, out pose.position.z); + ReadValuePacked(reader, out pose.rotation.x); + ReadValuePacked(reader, out pose.rotation.y); + ReadValuePacked(reader, out pose.rotation.z); + ReadValuePacked(reader, out pose.rotation.w); + } + /// /// Reads a string in a packed format /// diff --git a/com.unity.netcode.gameobjects/Runtime/Serialization/FastBufferReader.cs b/com.unity.netcode.gameobjects/Runtime/Serialization/FastBufferReader.cs index c856a6197b..d0dfdca7cd 100644 --- a/com.unity.netcode.gameobjects/Runtime/Serialization/FastBufferReader.cs +++ b/com.unity.netcode.gameobjects/Runtime/Serialization/FastBufferReader.cs @@ -1359,6 +1359,20 @@ internal void ReadValueSafeInPlace(ref NativeHashMap val [MethodImpl(MethodImplOptions.AggressiveInlining)] public void ReadValue(out Quaternion[] value) => ReadUnmanaged(out value); + /// + /// Read a Pose + /// + /// the value to read + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ReadValue(out Pose value) => ReadUnmanaged(out value); + + /// + /// Read a Pose array + /// + /// the values to read + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ReadValue(out Pose[] value) => ReadUnmanaged(out value); + /// /// Read a Color /// @@ -1536,6 +1550,26 @@ internal void ReadValueSafeInPlace(ref NativeHashMap val [MethodImpl(MethodImplOptions.AggressiveInlining)] public void ReadValueSafe(out Quaternion[] value) => ReadUnmanagedSafe(out value); + /// + /// Read a Pose + /// + /// "Safe" version - automatically performs bounds checking. Less efficient than bounds checking + /// for multiple reads at once by calling TryBeginRead. + /// + /// the value to read + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ReadValueSafe(out Pose value) => ReadUnmanagedSafe(out value); + + /// + /// Read a Pose array + /// + /// "Safe" version - automatically performs bounds checking. Less efficient than bounds checking + /// for multiple reads at once by calling TryBeginRead. + /// + /// the values to read + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ReadValueSafe(out Pose[] value) => ReadUnmanagedSafe(out value); + /// /// Read a Color /// diff --git a/com.unity.netcode.gameobjects/Runtime/Serialization/FastBufferWriter.cs b/com.unity.netcode.gameobjects/Runtime/Serialization/FastBufferWriter.cs index 381c92f625..bea537965e 100644 --- a/com.unity.netcode.gameobjects/Runtime/Serialization/FastBufferWriter.cs +++ b/com.unity.netcode.gameobjects/Runtime/Serialization/FastBufferWriter.cs @@ -1488,6 +1488,20 @@ public void WriteValueSafe(NativeList value, ForGeneric unused = default) [MethodImpl(MethodImplOptions.AggressiveInlining)] public void WriteValue(Quaternion[] value) => WriteUnmanaged(value); + /// + /// Write a Pose + /// + /// the value to write + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void WriteValue(in Pose value) => WriteUnmanaged(value); + + /// + /// Write a Pose array + /// + /// the values to write + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void WriteValue(Pose[] value) => WriteUnmanaged(value); + /// /// Write a Color /// @@ -1664,6 +1678,26 @@ public void WriteValueSafe(NativeList value, ForGeneric unused = default) [MethodImpl(MethodImplOptions.AggressiveInlining)] public void WriteValueSafe(Quaternion[] value) => WriteUnmanagedSafe(value); + /// + /// Write a Pose + /// + /// "Safe" version - automatically performs bounds checking. Less efficient than bounds checking + /// for multiple writes at once by calling TryBeginWrite. + /// + /// the value to write + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void WriteValueSafe(in Pose value) => WriteUnmanagedSafe(value); + + /// + /// Write a Pose array + /// + /// "Safe" version - automatically performs bounds checking. Less efficient than bounds checking + /// for multiple writes at once by calling TryBeginWrite. + /// + /// the values to write + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void WriteValueSafe(Pose[] value) => WriteUnmanagedSafe(value); + /// /// Write a Color /// diff --git a/com.unity.netcode.gameobjects/Runtime/Serialization/IReaderWriter.cs b/com.unity.netcode.gameobjects/Runtime/Serialization/IReaderWriter.cs index 2ec4f7b95d..676d09cf69 100644 --- a/com.unity.netcode.gameobjects/Runtime/Serialization/IReaderWriter.cs +++ b/com.unity.netcode.gameobjects/Runtime/Serialization/IReaderWriter.cs @@ -231,6 +231,18 @@ void SerializeValue(ref NativeList value) /// The values to read/write void SerializeValue(ref Quaternion[] value); + /// + /// Read or write a Pose value + /// + /// The value to read/write + void SerializeValue(ref Pose value); + + /// + /// Read or write an array of Pose values + /// + /// The values to read/write + void SerializeValue(ref Pose[] value); + /// /// Read or write a Color value /// @@ -530,6 +542,24 @@ void SerializeValuePreChecked(ref T value, FastBufferWriter.ForFixedStrings u /// The value to read/write void SerializeValuePreChecked(ref Quaternion[] value); + /// + /// Serialize a Pose, "pre-checked", which skips buffer checks. + /// In debug and editor builds, a check is made to ensure you've called "PreCheck" before + /// calling this. In release builds, calling this without calling "PreCheck" may read or write + /// past the end of the buffer, which will cause memory corruption and undefined behavior. + /// + /// The value to read/write + void SerializeValuePreChecked(ref Pose value); + + /// + /// Serialize a Pose array, "pre-checked", which skips buffer checks. + /// In debug and editor builds, a check is made to ensure you've called "PreCheck" before + /// calling this. In release builds, calling this without calling "PreCheck" may read or write + /// past the end of the buffer, which will cause memory corruption and undefined behavior. + /// + /// The value to read/write + void SerializeValuePreChecked(ref Pose[] value); + /// /// Serialize a Color, "pre-checked", which skips buffer checks. /// In debug and editor builds, a check is made to ensure you've called "PreCheck" before diff --git a/com.unity.netcode.gameobjects/Tests/Editor/Serialization/BaseFastBufferReaderWriterTest.cs b/com.unity.netcode.gameobjects/Tests/Editor/Serialization/BaseFastBufferReaderWriterTest.cs index 53e72cfba1..b6234001c8 100644 --- a/com.unity.netcode.gameobjects/Tests/Editor/Serialization/BaseFastBufferReaderWriterTest.cs +++ b/com.unity.netcode.gameobjects/Tests/Editor/Serialization/BaseFastBufferReaderWriterTest.cs @@ -239,6 +239,10 @@ public void BaseTypeTest(Type testType, WriteType writeType) { RunTestWithWriteType(new Quaternion((float)random.NextDouble(), (float)random.NextDouble(), (float)random.NextDouble(), (float)random.NextDouble()), writeType); } + else if (testType == typeof(Pose)) + { + RunTestWithWriteType(new Pose(new Vector3((float)random.NextDouble(), (float)random.NextDouble(), (float)random.NextDouble()), new Quaternion((float)random.NextDouble(), (float)random.NextDouble(), (float)random.NextDouble(), (float)random.NextDouble())), writeType); + } else if (testType == typeof(Color)) { RunTestWithWriteType(new Color((float)random.NextDouble(), (float)random.NextDouble(), (float)random.NextDouble(), (float)random.NextDouble()), writeType); @@ -544,6 +548,20 @@ void RunTypeTestLocal(T[] val, WriteType wt) where T : unmanaged (float) random.NextDouble(), (float) random.NextDouble()), }, writeType); } + else if (testType == typeof(Pose)) + { + RunTypeTestLocal(new[]{ + new Pose(new Vector3((float) random.NextDouble(), (float) random.NextDouble(), (float) random.NextDouble()), + new Quaternion((float) random.NextDouble(), (float) random.NextDouble(), + (float) random.NextDouble(), (float) random.NextDouble())), + new Pose(new Vector3((float) random.NextDouble(), (float) random.NextDouble(), (float) random.NextDouble()), + new Quaternion((float) random.NextDouble(), (float) random.NextDouble(), + (float) random.NextDouble(), (float) random.NextDouble())), + new Pose(new Vector3((float) random.NextDouble(), (float) random.NextDouble(), (float) random.NextDouble()), + new Quaternion((float) random.NextDouble(), (float) random.NextDouble(), + (float) random.NextDouble(), (float) random.NextDouble())), + }, writeType); + } else if (testType == typeof(Color)) { RunTypeTestLocal(new[]{ @@ -886,6 +904,20 @@ void RunTypeTestLocal(NativeArray val, WriteType wt) where T : unmanaged (float) random.NextDouble(), (float) random.NextDouble()), }, Allocator.Temp), writeType); } + else if (testType == typeof(Pose)) + { + RunTypeTestLocal(new NativeArray(new[]{ + new Pose(new Vector3((float) random.NextDouble(), (float) random.NextDouble(), (float) random.NextDouble()), + new Quaternion((float) random.NextDouble(), (float) random.NextDouble(), + (float) random.NextDouble(), (float) random.NextDouble())), + new Pose(new Vector3((float) random.NextDouble(), (float) random.NextDouble(), (float) random.NextDouble()), + new Quaternion((float) random.NextDouble(), (float) random.NextDouble(), + (float) random.NextDouble(), (float) random.NextDouble())), + new Pose(new Vector3((float) random.NextDouble(), (float) random.NextDouble(), (float) random.NextDouble()), + new Quaternion((float) random.NextDouble(), (float) random.NextDouble(), + (float) random.NextDouble(), (float) random.NextDouble())), + }, Allocator.Temp), writeType); + } else if (testType == typeof(Color)) { RunTypeTestLocal(new NativeArray(new[]{ @@ -1233,6 +1265,20 @@ void RunTypeTestLocal(NativeArray val, WriteType wt) where T : unmanaged (float) random.NextDouble(), (float) random.NextDouble()), }, Allocator.Temp), writeType); } + else if (testType == typeof(Pose)) + { + RunTypeTestLocal(new NativeArray(new[]{ + new Pose(new Vector3((float) random.NextDouble(), (float) random.NextDouble(), (float) random.NextDouble()), + new Quaternion((float) random.NextDouble(), (float) random.NextDouble(), + (float) random.NextDouble(), (float) random.NextDouble())), + new Pose(new Vector3((float) random.NextDouble(), (float) random.NextDouble(), (float) random.NextDouble()), + new Quaternion((float) random.NextDouble(), (float) random.NextDouble(), + (float) random.NextDouble(), (float) random.NextDouble())), + new Pose(new Vector3((float) random.NextDouble(), (float) random.NextDouble(), (float) random.NextDouble()), + new Quaternion((float) random.NextDouble(), (float) random.NextDouble(), + (float) random.NextDouble(), (float) random.NextDouble())), + }, Allocator.Temp), writeType); + } else if (testType == typeof(Color)) { RunTypeTestLocal(new NativeArray(new[]{ diff --git a/com.unity.netcode.gameobjects/Tests/Editor/Serialization/BytePackerTests.cs b/com.unity.netcode.gameobjects/Tests/Editor/Serialization/BytePackerTests.cs index 192f0db30d..1bd197997f 100644 --- a/com.unity.netcode.gameobjects/Tests/Editor/Serialization/BytePackerTests.cs +++ b/com.unity.netcode.gameobjects/Tests/Editor/Serialization/BytePackerTests.cs @@ -555,7 +555,7 @@ public void TestPackingBasicTypes( 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(Quaternion), typeof(Pose), typeof(Color), typeof(Color32), typeof(Ray), typeof(Ray2D))] Type testType, [Values] WriteType writeType) { @@ -758,6 +758,15 @@ public void TestPackingBasicTypes( RunTypeTest(v); } } + else if (testType == typeof(Pose)) + { + var v = new Pose(new Vector3((float)random.NextDouble(), (float)random.NextDouble(), (float)random.NextDouble()), + new Quaternion((float)random.NextDouble(), (float)random.NextDouble(), (float)random.NextDouble(), (float)random.NextDouble())); + if (writeType == WriteType.WriteDirect) + { + RunTypeTest(v); + } + } else if (testType == typeof(Color)) { var v = new Color((float)random.NextDouble(), (float)random.NextDouble(), (float)random.NextDouble(), (float)random.NextDouble()); diff --git a/com.unity.netcode.gameobjects/Tests/Editor/Serialization/FastBufferReaderTests.cs b/com.unity.netcode.gameobjects/Tests/Editor/Serialization/FastBufferReaderTests.cs index 020f7e6902..49659e9a0c 100644 --- a/com.unity.netcode.gameobjects/Tests/Editor/Serialization/FastBufferReaderTests.cs +++ b/com.unity.netcode.gameobjects/Tests/Editor/Serialization/FastBufferReaderTests.cs @@ -460,6 +460,7 @@ protected override unsafe void RunTypeTest(T valueToTest) } } } + protected override unsafe void RunTypeTestSafe(T valueToTest) { var writeSize = FastBufferWriter.GetWriteSize(valueToTest); @@ -682,7 +683,7 @@ public void GivenFastBufferWriterContainingValue_WhenReadingUnmanagedType_ValueM 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(Vector2Int), typeof(Vector3Int), typeof(Vector4), typeof(Quaternion), typeof(Color), + typeof(Vector2Int), typeof(Vector3Int), typeof(Vector4), typeof(Quaternion), typeof(Pose), typeof(Color), typeof(Color32), typeof(Ray), typeof(Ray2D), typeof(TestStruct))] Type testType, [Values] WriteType writeType) @@ -696,7 +697,7 @@ public void GivenFastBufferWriterContainingValue_WhenReadingArrayOfUnmanagedElem 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(Vector2Int), typeof(Vector3Int), typeof(Vector4), typeof(Quaternion), typeof(Color), + typeof(Vector2Int), typeof(Vector3Int), typeof(Vector4), typeof(Quaternion), typeof(Pose), typeof(Color), typeof(Color32), typeof(Ray), typeof(Ray2D), typeof(TestStruct))] Type testType, [Values] WriteType writeType) @@ -710,7 +711,7 @@ public void GivenFastBufferWriterContainingValue_WhenReadingNativeArrayOfUnmanag 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(Vector2Int), typeof(Vector3Int), typeof(Vector4), typeof(Quaternion), typeof(Color), + typeof(Vector2Int), typeof(Vector3Int), typeof(Vector4), typeof(Quaternion), typeof(Pose), typeof(Color), typeof(Color32), typeof(Ray), typeof(Ray2D), typeof(TestStruct))] Type testType, [Values] WriteType writeType) @@ -725,7 +726,7 @@ public void GivenFastBufferWriterContainingValue_WhenReadingNativeListOfUnmanage 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(Vector2Int), typeof(Vector3Int), typeof(Vector4), typeof(Quaternion), typeof(Color), + typeof(Vector2Int), typeof(Vector3Int), typeof(Vector4), typeof(Quaternion), typeof(Pose), typeof(Color), typeof(Color32), typeof(Ray), typeof(Ray2D), typeof(TestStruct))] Type testType, [Values] WriteType writeType) diff --git a/com.unity.netcode.gameobjects/Tests/Editor/Serialization/FastBufferWriterTests.cs b/com.unity.netcode.gameobjects/Tests/Editor/Serialization/FastBufferWriterTests.cs index 53673d5742..32e580c66f 100644 --- a/com.unity.netcode.gameobjects/Tests/Editor/Serialization/FastBufferWriterTests.cs +++ b/com.unity.netcode.gameobjects/Tests/Editor/Serialization/FastBufferWriterTests.cs @@ -459,7 +459,7 @@ public void WhenWritingUnmanagedType_ValueIsWrittenCorrectly( 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(Vector2Int), typeof(Vector3Int), typeof(Vector4), typeof(Quaternion), typeof(Color), + typeof(Vector2Int), typeof(Vector3Int), typeof(Vector4), typeof(Quaternion), typeof(Pose), typeof(Color), typeof(Color32), typeof(Ray), typeof(Ray2D), typeof(TestStruct))] Type testType, [Values] WriteType writeType) @@ -473,7 +473,7 @@ public void WhenWritingArrayOfUnmanagedElementType_ArrayIsWrittenCorrectly( 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(Vector2Int), typeof(Vector3Int), typeof(Vector4), typeof(Quaternion), typeof(Color), + typeof(Vector2Int), typeof(Vector3Int), typeof(Vector4), typeof(Quaternion), typeof(Pose), typeof(Color), typeof(Color32), typeof(Ray), typeof(Ray2D), typeof(TestStruct))] Type testType, [Values] WriteType writeType) @@ -487,7 +487,7 @@ public void WhenWritingNativeArrayOfUnmanagedElementType_NativeArrayIsWrittenCor 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(Vector2Int), typeof(Vector3Int), typeof(Vector4), typeof(Quaternion), typeof(Color), + typeof(Vector2Int), typeof(Vector3Int), typeof(Vector4), typeof(Quaternion), typeof(Pose), typeof(Color), typeof(Color32), typeof(Ray), typeof(Ray2D), typeof(TestStruct))] Type testType, [Values] WriteType writeType) @@ -502,7 +502,7 @@ public void WhenWritingNativeListOfUnmanagedElementType_NativeListIsWrittenCorre 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(Vector2Int), typeof(Vector3Int), typeof(Vector4), typeof(Quaternion), typeof(Color), + typeof(Vector2Int), typeof(Vector3Int), typeof(Vector4), typeof(Quaternion), typeof(Pose), typeof(Color), typeof(Color32), typeof(Ray), typeof(Ray2D), typeof(TestStruct))] Type testType, [Values] WriteType writeType) diff --git a/com.unity.netcode.gameobjects/Tests/Runtime/Components/NetworkVariableTestComponent.cs b/com.unity.netcode.gameobjects/Tests/Runtime/Components/NetworkVariableTestComponent.cs index 346b908a17..c217331e8d 100644 --- a/com.unity.netcode.gameobjects/Tests/Runtime/Components/NetworkVariableTestComponent.cs +++ b/com.unity.netcode.gameobjects/Tests/Runtime/Components/NetworkVariableTestComponent.cs @@ -191,6 +191,7 @@ internal class NetworkVariableTestComponent : NetworkBehaviour private NetworkVariable m_NetworkVariableLong = new NetworkVariable(); private NetworkVariable m_NetworkVariableSByte = new NetworkVariable(); private NetworkVariable m_NetworkVariableQuaternion = new NetworkVariable(); + private NetworkVariable m_NetworkVariablePose = new NetworkVariable(); private NetworkVariable m_NetworkVariableShort = new NetworkVariable(); private NetworkVariable m_NetworkVariableVector4 = new NetworkVariable(); private NetworkVariable m_NetworkVariableVector3 = new NetworkVariable(); @@ -217,6 +218,7 @@ internal class NetworkVariableTestComponent : NetworkBehaviour public NetworkVariableHelper Long_Var; public NetworkVariableHelper Sbyte_Var; public NetworkVariableHelper Quaternion_Var; + public NetworkVariableHelper Pose_Var; public NetworkVariableHelper Short_Var; public NetworkVariableHelper Vector4_Var; public NetworkVariableHelper Vector3_Var; @@ -253,6 +255,7 @@ private void InitializeTest() m_NetworkVariableLong = new NetworkVariable(); m_NetworkVariableSByte = new NetworkVariable(); m_NetworkVariableQuaternion = new NetworkVariable(); + m_NetworkVariablePose = new NetworkVariable(); m_NetworkVariableShort = new NetworkVariable(); m_NetworkVariableVector4 = new NetworkVariable(); m_NetworkVariableVector3 = new NetworkVariable(); @@ -280,6 +283,7 @@ private void InitializeTest() m_NetworkVariableLong = new NetworkVariable(1); m_NetworkVariableSByte = new NetworkVariable(0); m_NetworkVariableQuaternion = new NetworkVariable(Quaternion.identity); + m_NetworkVariablePose = new NetworkVariable(Pose.identity); m_NetworkVariableShort = new NetworkVariable(256); m_NetworkVariableVector4 = new NetworkVariable(new Vector4(1, 1, 1, 1)); m_NetworkVariableVector3 = new NetworkVariable(new Vector3(1, 1, 1)); @@ -312,6 +316,7 @@ private void InitializeTest() Long_Var = new NetworkVariableHelper(m_NetworkVariableLong); Sbyte_Var = new NetworkVariableHelper(m_NetworkVariableSByte); Quaternion_Var = new NetworkVariableHelper(m_NetworkVariableQuaternion); + Pose_Var = new NetworkVariableHelper(m_NetworkVariablePose); Short_Var = new NetworkVariableHelper(m_NetworkVariableShort); Vector4_Var = new NetworkVariableHelper(m_NetworkVariableVector4); Vector3_Var = new NetworkVariableHelper(m_NetworkVariableVector3); @@ -376,6 +381,13 @@ public void AssertAllValuesAreCorrect() Assert.AreEqual(100, m_NetworkVariableQuaternion.Value.x); Assert.AreEqual(100, m_NetworkVariableQuaternion.Value.y); Assert.AreEqual(100, m_NetworkVariableQuaternion.Value.z); + Assert.AreEqual(100, m_NetworkVariablePose.Value.position.x); + Assert.AreEqual(100, m_NetworkVariablePose.Value.position.y); + Assert.AreEqual(100, m_NetworkVariablePose.Value.position.z); + Assert.AreEqual(100, m_NetworkVariablePose.Value.rotation.w); + Assert.AreEqual(100, m_NetworkVariablePose.Value.rotation.x); + Assert.AreEqual(100, m_NetworkVariablePose.Value.rotation.y); + Assert.AreEqual(100, m_NetworkVariablePose.Value.rotation.z); Assert.AreEqual(short.MaxValue, m_NetworkVariableShort.Value); Assert.AreEqual(1000, m_NetworkVariableVector4.Value.w); Assert.AreEqual(1000, m_NetworkVariableVector4.Value.x); @@ -435,6 +447,7 @@ private void Update() m_NetworkVariableLong.Value = 100000; m_NetworkVariableSByte.Value = -127; m_NetworkVariableQuaternion.Value = new Quaternion(100, 100, 100, 100); + m_NetworkVariablePose.Value = new Pose(new Vector3(100, 100, 100), new Quaternion(100, 100, 100, 100)); m_NetworkVariableShort.Value = short.MaxValue; m_NetworkVariableVector4.Value = new Vector4(1000, 1000, 1000, 1000); m_NetworkVariableVector3.Value = new Vector3(1000, 1000, 1000); diff --git a/com.unity.netcode.gameobjects/Tests/Runtime/NetworkVariable/NetworkVariableTests.cs b/com.unity.netcode.gameobjects/Tests/Runtime/NetworkVariable/NetworkVariableTests.cs index 9ed5854b4e..757550a1e3 100644 --- a/com.unity.netcode.gameobjects/Tests/Runtime/NetworkVariable/NetworkVariableTests.cs +++ b/com.unity.netcode.gameobjects/Tests/Runtime/NetworkVariable/NetworkVariableTests.cs @@ -1737,7 +1737,7 @@ public void WhenSerializingAndDeserializingValueTypeNetworkVariables_ValuesAreSe 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(Vector2Int), typeof(Vector3Int), typeof(Vector4), typeof(Quaternion), typeof(Color), + typeof(Vector2Int), typeof(Vector3Int), typeof(Vector4), typeof(Quaternion), typeof(Pose), typeof(Color), typeof(Color32), typeof(Ray), typeof(Ray2D), typeof(NetworkVariableTestStruct), typeof(FixedString32Bytes))] Type testType) { @@ -1857,6 +1857,12 @@ public void WhenSerializingAndDeserializingValueTypeNetworkVariables_ValuesAreSe new Quaternion(5, 10, 15, 20), new Quaternion(25, 30, 35, 40)); } + else if (testType == typeof(Pose)) + { + TestValueType( + new Pose(new Vector3(5, 10, 15), new Quaternion(20, 25, 30, 35)), + new Pose(new Vector3(40, 45, 50), new Quaternion(55, 60, 65, 70))); + } else if (testType == typeof(Color)) { TestValueType( @@ -1898,7 +1904,7 @@ public void WhenSerializingAndDeserializingValueTypeNativeArrayNetworkVariables_ 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(Vector2Int), typeof(Vector3Int), typeof(Vector4), typeof(Quaternion), typeof(Color), + typeof(Vector2Int), typeof(Vector3Int), typeof(Vector4), typeof(Quaternion), typeof(Pose), typeof(Color), typeof(Color32), typeof(Ray), typeof(Ray2D), typeof(NetworkVariableTestStruct), typeof(FixedString32Bytes))] Type testType) { @@ -2058,6 +2064,12 @@ public void WhenSerializingAndDeserializingValueTypeNativeArrayNetworkVariables_ new NativeArray(new Quaternion[] { new Quaternion(5, 10, 15, 20), new Quaternion(25, 30, 35, 40) }, Allocator.Temp), new NativeArray(new Quaternion[] { new Quaternion(45, 50, 55, 60), new Quaternion(65, 70, 75, 80), new Quaternion(85, 90, 95, 100) }, Allocator.Temp)); } + else if (testType == typeof(Pose)) + { + TestValueTypeNativeArray( + new NativeArray(new Pose[] { new Pose(new Vector3(5, 10, 15), new Quaternion(20, 25, 30, 35)), new Pose(new Vector3(40, 45, 50), new Quaternion(55, 60, 65, 70)) }, Allocator.Temp), + new NativeArray(new Pose[] { new Pose(new Vector3(75, 80, 85), new Quaternion(90, 95, 100, 105)), new Pose(new Vector3(110, 115, 120), new Quaternion(125, 130, 135, 140)), new Pose(new Vector3(145, 150, 155), new Quaternion(160, 165, 170, 175)) }, Allocator.Temp)); + } else if (testType == typeof(Color)) { TestValueTypeNativeArray( @@ -2234,7 +2246,7 @@ public void WhenSerializingAndDeserializingVeryLargeValueTypeNativeArrayNetworkV [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(Vector2), typeof(Vector3), typeof(Vector2Int), typeof(Vector3Int), typeof(Vector4), - typeof(Quaternion), typeof(Color), typeof(Color32), typeof(Ray), typeof(Ray2D), + typeof(Quaternion), typeof(Pose), typeof(Color), typeof(Color32), typeof(Ray), typeof(Ray2D), typeof(NetworkVariableTestStruct), typeof(FixedString32Bytes))] Type testType) { @@ -2358,6 +2370,14 @@ public void WhenSerializingAndDeserializingVeryLargeValueTypeNativeArrayNetworkV TestValueTypeNativeArray(original, changed); TestValueTypeNativeArray(original2, changed2); } + else if (testType == typeof(Pose)) + { + (var original, var original2, var changed, var changed2) = GetArarys( + (rand) => new Pose(new Vector3((float)rand.NextDouble(), (float)rand.NextDouble(), (float)rand.NextDouble()), new Quaternion((float)rand.NextDouble(), (float)rand.NextDouble(), (float)rand.NextDouble(), (float)rand.NextDouble())) + ); + TestValueTypeNativeArray(original, changed); + TestValueTypeNativeArray(original2, changed2); + } else if (testType == typeof(Color)) { (var original, var original2, var changed, var changed2) = GetArarys( @@ -2688,7 +2708,7 @@ public void WhenSerializingAndDeserializingVeryLargeListNetworkVariables_ValuesA [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(Vector2), typeof(Vector3), typeof(Vector2Int), typeof(Vector3Int), typeof(Vector4), - typeof(Quaternion), typeof(Color), typeof(Color32), typeof(Ray), typeof(Ray2D), + typeof(Quaternion), typeof(Pose), typeof(Color), typeof(Color32), typeof(Ray), typeof(Ray2D), typeof(NetworkVariableTestClass), typeof(FixedString32Bytes))] Type testType) { @@ -2812,6 +2832,14 @@ public void WhenSerializingAndDeserializingVeryLargeListNetworkVariables_ValuesA TestList(original, changed); TestList(original2, changed2); } + else if (testType == typeof(Pose)) + { + (var original, var original2, var changed, var changed2) = GetLists( + (rand) => new Pose(new Vector3((float)rand.NextDouble(), (float)rand.NextDouble(), (float)rand.NextDouble()), new Quaternion((float)rand.NextDouble(), (float)rand.NextDouble(), (float)rand.NextDouble(), (float)rand.NextDouble())) + ); + TestList(original, changed); + TestList(original2, changed2); + } else if (testType == typeof(Color)) { (var original, var original2, var changed, var changed2) = GetLists( @@ -2875,7 +2903,7 @@ public void WhenSerializingAndDeserializingVeryLargeHashSetNetworkVariables_Valu [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(Vector2), typeof(Vector3), typeof(Vector2Int), typeof(Vector3Int), typeof(Vector4), - typeof(Quaternion), typeof(HashableNetworkVariableTestClass), typeof(FixedString32Bytes))] + typeof(Quaternion), typeof(Pose), typeof(HashableNetworkVariableTestClass), typeof(FixedString32Bytes))] Type testType) { if (testType == typeof(byte)) @@ -2998,6 +3026,14 @@ public void WhenSerializingAndDeserializingVeryLargeHashSetNetworkVariables_Valu TestHashSet(original, changed); TestHashSet(original2, changed2); } + else if (testType == typeof(Pose)) + { + (var original, var original2, var changed, var changed2) = GetHashSets( + (rand) => new Pose(new Vector3((float)rand.NextDouble(), (float)rand.NextDouble(), (float)rand.NextDouble()), new Quaternion((float)rand.NextDouble(), (float)rand.NextDouble(), (float)rand.NextDouble(), (float)rand.NextDouble())) + ); + TestHashSet(original, changed); + TestHashSet(original2, changed2); + } else if (testType == typeof(Color)) { (var original, var original2, var changed, var changed2) = GetHashSets( @@ -3032,7 +3068,7 @@ public void WhenSerializingAndDeserializingVeryLargeDictionaryNetworkVariables_V [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(Vector2), typeof(Vector3), typeof(Vector2Int), typeof(Vector3Int), typeof(Vector4), - typeof(Quaternion), typeof(HashMapValClass), typeof(FixedString32Bytes))] + typeof(Quaternion), typeof(Pose), typeof(HashMapValClass), typeof(FixedString32Bytes))] Type valType) { if (valType == typeof(byte)) @@ -3557,6 +3593,35 @@ public void WhenSerializingAndDeserializingVeryLargeDictionaryNetworkVariables_V TestDictionary(original2, changed2); } } + else if (valType == typeof(Pose)) + { + if (keyType == typeof(byte)) + { + (var original, var original2, var changed, var changed2) = GetDictionaries(RandGenBytes, (rand) => new Pose(new Vector3((float)rand.NextDouble(), (float)rand.NextDouble(), (float)rand.NextDouble()), new Quaternion((float)rand.NextDouble(), (float)rand.NextDouble(), (float)rand.NextDouble(), (float)rand.NextDouble()))); + TestDictionary(original, changed); + TestDictionary(original2, changed2); + + } + else if (keyType == typeof(ulong)) + { + (var original, var original2, var changed, var changed2) = GetDictionaries(RandGenBytes, (rand) => new Pose(new Vector3((float)rand.NextDouble(), (float)rand.NextDouble(), (float)rand.NextDouble()), new Quaternion((float)rand.NextDouble(), (float)rand.NextDouble(), (float)rand.NextDouble(), (float)rand.NextDouble()))); + TestDictionary(original, changed); + TestDictionary(original2, changed2); + } + else if (keyType == typeof(Vector2)) + { + (var original, var original2, var changed, var changed2) = GetDictionaries((rand) => new Vector2((float)rand.NextDouble(), (float)rand.NextDouble()), (rand) => new Pose(new Vector3((float)rand.NextDouble(), (float)rand.NextDouble(), (float)rand.NextDouble()), new Quaternion((float)rand.NextDouble(), (float)rand.NextDouble(), (float)rand.NextDouble(), (float)rand.NextDouble()))); + TestDictionary(original, changed); + TestDictionary(original2, changed2); + + } + else if (keyType == typeof(HashMapKeyClass)) + { + (var original, var original2, var changed, var changed2) = GetDictionaries((rand) => new HashMapKeyClass { Data = RandGenBytes(rand) }, (rand) => new Quaternion((float)rand.NextDouble(), (float)rand.NextDouble(), (float)rand.NextDouble(), (float)rand.NextDouble())); + TestDictionary(original, changed); + TestDictionary(original2, changed2); + } + } else if (valType == typeof(HashMapValClass)) { if (keyType == typeof(byte)) @@ -3626,7 +3691,7 @@ public void WhenSerializingAndDeserializingValueTypeNativeListNetworkVariables_V 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(Vector2Int), typeof(Vector3Int), typeof(Vector4), typeof(Quaternion), typeof(Color), + typeof(Vector2Int), typeof(Vector3Int), typeof(Vector4), typeof(Quaternion), typeof(Pose), typeof(Color), typeof(Color32), typeof(Ray), typeof(Ray2D), typeof(NetworkVariableTestStruct), typeof(FixedString32Bytes))] Type testType) { @@ -3786,6 +3851,12 @@ public void WhenSerializingAndDeserializingValueTypeNativeListNetworkVariables_V new NativeList(Allocator.Temp) { new Quaternion(5, 10, 15, 20), new Quaternion(25, 30, 35, 40) }, new NativeList(Allocator.Temp) { new Quaternion(45, 50, 55, 60), new Quaternion(65, 70, 75, 80), new Quaternion(85, 90, 95, 100) }); } + else if (testType == typeof(Pose)) + { + TestValueTypeNativeList( + new NativeList(Allocator.Temp) { new Pose(new Vector3(5, 10, 15), new Quaternion(20, 25, 30, 35)), new Pose(new Vector3(40, 45, 50), new Quaternion(55, 60, 65, 70)) }, + new NativeList(Allocator.Temp) { new Pose(new Vector3(75, 80, 85), new Quaternion(90, 95, 100, 105)), new Pose(new Vector3(110, 115, 120), new Quaternion(125, 130, 135, 140)), new Pose(new Vector3(145, 150, 155), new Quaternion(160, 165, 170, 175)) }); + } else if (testType == typeof(Color)) { TestValueTypeNativeList( @@ -4138,7 +4209,7 @@ public void WhenSerializingAndDeserializingVeryLargeValueTypeNativeListNetworkVa [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(Vector2), typeof(Vector3), typeof(Vector2Int), typeof(Vector3Int), typeof(Vector4), - typeof(Quaternion), typeof(Color), typeof(Color32), typeof(Ray), typeof(Ray2D), + typeof(Quaternion), typeof(Pose),typeof(Color), typeof(Color32), typeof(Ray), typeof(Ray2D), typeof(NetworkVariableTestStruct), typeof(FixedString32Bytes))] Type testType) { @@ -4262,6 +4333,14 @@ public void WhenSerializingAndDeserializingVeryLargeValueTypeNativeListNetworkVa TestValueTypeNativeList(original, changed); TestValueTypeNativeList(original2, changed2); } + else if (testType == typeof(Pose)) + { + (var original, var original2, var changed, var changed2) = GetNativeLists( + (rand) => new Pose(new Vector3((float)rand.NextDouble(), (float)rand.NextDouble(), (float)rand.NextDouble()), new Quaternion((float)rand.NextDouble(), (float)rand.NextDouble(), (float)rand.NextDouble(), (float)rand.NextDouble())) + ); + TestValueTypeNativeList(original, changed); + TestValueTypeNativeList(original2, changed2); + } else if (testType == typeof(Color)) { (var original, var original2, var changed, var changed2) = GetNativeLists( @@ -4321,7 +4400,7 @@ public void WhenSerializingAndDeserializingVeryLargeValueTypeNativeHashSetNetwor [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(Vector2), typeof(Vector3), typeof(Vector2Int), typeof(Vector3Int), typeof(Vector4), - typeof(Quaternion), typeof(HashableNetworkVariableTestStruct), typeof(FixedString32Bytes))] + typeof(Quaternion), typeof(Pose), typeof(HashableNetworkVariableTestStruct), typeof(FixedString32Bytes))] Type testType) { if (testType == typeof(byte)) @@ -4444,6 +4523,14 @@ public void WhenSerializingAndDeserializingVeryLargeValueTypeNativeHashSetNetwor TestValueTypeNativeHashSet(original, changed); TestValueTypeNativeHashSet(original2, changed2); } + else if (testType == typeof(Pose)) + { + (var original, var original2, var changed, var changed2) = GetNativeHashSets( + (rand) => new Pose(new Vector3((float)rand.NextDouble(), (float)rand.NextDouble(), (float)rand.NextDouble()), new Quaternion((float)rand.NextDouble(), (float)rand.NextDouble(), (float)rand.NextDouble(), (float)rand.NextDouble())) + ); + TestValueTypeNativeHashSet(original, changed); + TestValueTypeNativeHashSet(original2, changed2); + } else if (testType == typeof(Color)) { (var original, var original2, var changed, var changed2) = GetNativeHashSets( @@ -4474,7 +4561,7 @@ public void WhenSerializingAndDeserializingVeryLargeValueTypeNativeHashMapNetwor [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(Vector2), typeof(Vector3), typeof(Vector2Int), typeof(Vector3Int), typeof(Vector4), - typeof(Quaternion), typeof(HashMapValStruct), typeof(FixedString32Bytes))] + typeof(Quaternion), typeof(Pose), typeof(HashMapValStruct), typeof(FixedString32Bytes))] Type valType) { if (valType == typeof(byte)) @@ -4999,6 +5086,35 @@ public void WhenSerializingAndDeserializingVeryLargeValueTypeNativeHashMapNetwor TestValueTypeNativeHashMap(original2, changed2); } } + else if (valType == typeof(Pose)) + { + if (keyType == typeof(byte)) + { + (var original, var original2, var changed, var changed2) = GetMaps(RandGenBytes, (rand) => new Pose(new Vector3((float)rand.NextDouble(), (float)rand.NextDouble(), (float)rand.NextDouble()), new Quaternion((float)rand.NextDouble(), (float)rand.NextDouble(), (float)rand.NextDouble(), (float)rand.NextDouble()))); + TestValueTypeNativeHashMap(original, changed); + TestValueTypeNativeHashMap(original2, changed2); + + } + else if (keyType == typeof(ulong)) + { + (var original, var original2, var changed, var changed2) = GetMaps(RandGenBytes, (rand) => new Pose(new Vector3((float)rand.NextDouble(), (float)rand.NextDouble(), (float)rand.NextDouble()), new Quaternion((float)rand.NextDouble(), (float)rand.NextDouble(), (float)rand.NextDouble(), (float)rand.NextDouble()))); + TestValueTypeNativeHashMap(original, changed); + TestValueTypeNativeHashMap(original2, changed2); + } + else if (keyType == typeof(Vector2)) + { + (var original, var original2, var changed, var changed2) = GetMaps((rand) => new Vector2((float)rand.NextDouble(), (float)rand.NextDouble()), (rand) => new Pose(new Vector3((float)rand.NextDouble(), (float)rand.NextDouble(), (float)rand.NextDouble()), new Quaternion((float)rand.NextDouble(), (float)rand.NextDouble(), (float)rand.NextDouble(), (float)rand.NextDouble()))); + TestValueTypeNativeHashMap(original, changed); + TestValueTypeNativeHashMap(original2, changed2); + + } + else if (keyType == typeof(HashMapKeyStruct)) + { + (var original, var original2, var changed, var changed2) = GetMaps(RandGenBytes, (rand) => new Pose(new Vector3((float)rand.NextDouble(), (float)rand.NextDouble(), (float)rand.NextDouble()), new Quaternion((float)rand.NextDouble(), (float)rand.NextDouble(), (float)rand.NextDouble(), (float)rand.NextDouble()))); + TestValueTypeNativeHashMap(original, changed); + TestValueTypeNativeHashMap(original2, changed2); + } + } else if (valType == typeof(HashMapValStruct)) { if (keyType == typeof(byte)) diff --git a/com.unity.netcode.gameobjects/Tests/Runtime/NetworkVariable/NetworkVariableTestsHelperTypes.cs b/com.unity.netcode.gameobjects/Tests/Runtime/NetworkVariable/NetworkVariableTestsHelperTypes.cs index 1a0fdd6bc3..46fb27f76b 100644 --- a/com.unity.netcode.gameobjects/Tests/Runtime/NetworkVariable/NetworkVariableTestsHelperTypes.cs +++ b/com.unity.netcode.gameobjects/Tests/Runtime/NetworkVariable/NetworkVariableTestsHelperTypes.cs @@ -802,6 +802,23 @@ internal class NetVarILPPClassForTests : NetworkBehaviour public NetworkVariable> Vector2QuaternionDictionaryVar; public NetworkVariable> HashMapKeyClassQuaternionDictionaryVar; + public NetworkVariable PoseVar; + public NetworkVariable> PoseArrayVar; + public NetworkVariable> PoseManagedListVar; + public NetworkVariable> PoseManagedHashSetVar; +#if UNITY_NETCODE_NATIVE_COLLECTION_SUPPORT + public NetworkVariable> PoseListVar; + public NetworkVariable> PoseHashSetVar; + public NetworkVariable> BytePoseHashMapVar; + public NetworkVariable> ULongPoseHashMapVar; + public NetworkVariable> Vector2PoseHashMapVar; + public NetworkVariable> HashMapKeyStructPoseHashMapVar; +#endif + public NetworkVariable> BytePoseDictionaryVar; + public NetworkVariable> ULongPoseDictionaryVar; + public NetworkVariable> Vector2PoseDictionaryVar; + public NetworkVariable> HashMapKeyClassPoseDictionaryVar; + public NetworkVariable ColorVar; public NetworkVariable> ColorArrayVar; public NetworkVariable> ColorManagedListVar; diff --git a/com.unity.netcode.gameobjects/Tests/Runtime/RpcTypeSerializationTests.cs b/com.unity.netcode.gameobjects/Tests/Runtime/RpcTypeSerializationTests.cs index 8da15ccbe8..ca1ce942ae 100644 --- a/com.unity.netcode.gameobjects/Tests/Runtime/RpcTypeSerializationTests.cs +++ b/com.unity.netcode.gameobjects/Tests/Runtime/RpcTypeSerializationTests.cs @@ -702,6 +702,32 @@ public void QuaternionNativeListClientRpc(NativeList value) } #endif + [ClientRpc] + public void PoseClientRpc(Pose value) + { + OnReceived(value); + } + + [ClientRpc] + public void PoseArrayClientRpc(Pose[] value) + { + OnReceived(value); + } + + [ClientRpc] + public void PoseNativeArrayClientRpc(NativeArray value) + { + OnReceived(value); + } + +#if UNITY_NETCODE_NATIVE_COLLECTION_SUPPORT + [ClientRpc] + public void PoseNativeListClientRpc(NativeList value) + { + OnReceived(value); + } +#endif + [ClientRpc] public void ColorClientRpc(Color value) { @@ -1105,7 +1131,7 @@ public IEnumerator WhenSendingAValueTypeOverAnRpc_ValuesAreSerializedCorrectly( 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(Vector2Int), typeof(Vector3Int), typeof(Vector4), typeof(Quaternion), typeof(Color), + typeof(Vector2Int), typeof(Vector3Int), typeof(Vector4), typeof(Quaternion), typeof(Pose), typeof(Color), typeof(Color32), typeof(Ray), typeof(Ray2D), typeof(NetworkVariableTestStruct), typeof(FixedString32Bytes))] Type testType) { @@ -1225,6 +1251,12 @@ public IEnumerator WhenSendingAValueTypeOverAnRpc_ValuesAreSerializedCorrectly( new Quaternion(5, 10, 15, 20), new Quaternion(25, 30, 35, 40)); } + else if (testType == typeof(Pose)) + { + TestValueType( + new Pose(new Vector3(5, 10, 15), new Quaternion(20, 25, 30, 35)), + new Pose(new Vector3(40, 45, 50), new Quaternion(55, 60, 65, 70))); + } else if (testType == typeof(Color)) { yield return TestValueType( @@ -1266,7 +1298,7 @@ public IEnumerator WhenSendingAnArrayOfValueTypesOverAnRpc_ValuesAreSerializedCo 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(Vector2Int), typeof(Vector3Int), typeof(Vector4), typeof(Quaternion), typeof(Color), + typeof(Vector2Int), typeof(Vector3Int), typeof(Vector4), typeof(Quaternion), typeof(Pose), typeof(Color), typeof(Color32), typeof(Ray), typeof(Ray2D), typeof(NetworkVariableTestStruct), typeof(FixedString32Bytes))] Type testType) { @@ -1426,6 +1458,12 @@ public IEnumerator WhenSendingAnArrayOfValueTypesOverAnRpc_ValuesAreSerializedCo new Quaternion[] { new Quaternion(5, 10, 15, 20), new Quaternion(25, 30, 35, 40) }, new Quaternion[] { new Quaternion(45, 50, 55, 60), new Quaternion(65, 70, 75, 80), new Quaternion(85, 90, 95, 100) }); } + else if (testType == typeof(Pose)) + { + TestValueTypeArray( + new Pose[] { new Pose(new Vector3(5, 10, 15), new Quaternion(20, 25, 30, 35)), new Pose(new Vector3(40, 45, 50), new Quaternion(55, 60, 65, 70)) }, + new Pose[] { new Pose(new Vector3(75, 80, 85), new Quaternion(90, 95, 100, 105)), new Pose(new Vector3(110, 115, 120), new Quaternion(125, 130, 135, 140)), new Pose(new Vector3(145, 150, 155), new Quaternion(160, 165, 170, 175)) }); + } else if (testType == typeof(Color)) { yield return TestValueTypeArray( @@ -1507,7 +1545,7 @@ public IEnumerator WhenSendingANativeArrayOfValueTypesOverAnRpc_ValuesAreSeriali 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(Vector2Int), typeof(Vector3Int), typeof(Vector4), typeof(Quaternion), typeof(Color), + typeof(Vector2Int), typeof(Vector3Int), typeof(Vector4), typeof(Quaternion), typeof(Pose), typeof(Color), typeof(Color32), typeof(Ray), typeof(Ray2D), typeof(NetworkVariableTestStruct), typeof(FixedString32Bytes))] Type testType) { @@ -1667,6 +1705,12 @@ public IEnumerator WhenSendingANativeArrayOfValueTypesOverAnRpc_ValuesAreSeriali new NativeArray(new Quaternion[] { new Quaternion(5, 10, 15, 20), new Quaternion(25, 30, 35, 40) }, Allocator.Persistent), new NativeArray(new Quaternion[] { new Quaternion(45, 50, 55, 60), new Quaternion(65, 70, 75, 80), new Quaternion(85, 90, 95, 100) }, Allocator.Persistent)); } + else if (testType == typeof(Pose)) + { + TestValueTypeNativeArray( + new NativeArray(new Pose[] { new Pose(new Vector3(5, 10, 15), new Quaternion(20, 25, 30, 35)), new Pose(new Vector3(40, 45, 50), new Quaternion(55, 60, 65, 70)) }, Allocator.Persistent), + new NativeArray(new Pose[] { new Pose(new Vector3(75, 80, 85), new Quaternion(90, 95, 100, 105)), new Pose(new Vector3(110, 115, 120), new Quaternion(125, 130, 135, 140)), new Pose(new Vector3(145, 150, 155), new Quaternion(160, 165, 170, 175)) }, Allocator.Persistent)); + } else if (testType == typeof(Color)) { yield return TestValueTypeNativeArray( @@ -1749,7 +1793,7 @@ public IEnumerator WhenSendingANativeListOfValueTypesOverAnRpc_ValuesAreSerializ 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(Vector2Int), typeof(Vector3Int), typeof(Vector4), typeof(Quaternion), typeof(Color), + typeof(Vector2Int), typeof(Vector3Int), typeof(Vector4), typeof(Quaternion), typeof(Pose), typeof(Color), typeof(Color32), typeof(Ray), typeof(Ray2D), typeof(NetworkVariableTestStruct), typeof(FixedString32Bytes))] Type testType) { @@ -1909,6 +1953,12 @@ public IEnumerator WhenSendingANativeListOfValueTypesOverAnRpc_ValuesAreSerializ new NativeList(Allocator.Persistent) { new Quaternion(5, 10, 15, 20), new Quaternion(25, 30, 35, 40) }, new NativeList(Allocator.Persistent) { new Quaternion(45, 50, 55, 60), new Quaternion(65, 70, 75, 80), new Quaternion(85, 90, 95, 100) }); } + else if (testType == typeof(Pose)) + { + TestValueTypeNativeList( + new NativeList(Allocator.Persistent) { new Pose(new Vector3(5, 10, 15), new Quaternion(20, 25, 30, 35)), new Pose(new Vector3(40, 45, 50), new Quaternion(55, 60, 65, 70)) }, + new NativeList(Allocator.Persistent) { new Pose(new Vector3(75, 80, 85), new Quaternion(90, 95, 100, 105)), new Pose(new Vector3(110, 115, 120), new Quaternion(125, 130, 135, 140)), new Pose(new Vector3(145, 150, 155), new Quaternion(160, 165, 170, 175)) }); + } else if (testType == typeof(Color)) { yield return TestValueTypeNativeList( From cf61ae7ca70ca9d07acf15a41854e2f15e53b955 Mon Sep 17 00:00:00 2001 From: Emma Date: Thu, 10 Jul 2025 17:48:24 -0400 Subject: [PATCH 2/3] serialize the Vector3 and Quaternion directly --- .../Runtime/Serialization/BytePacker.cs | 9 ++------- .../Runtime/Serialization/ByteUnpacker.cs | 11 +++-------- .../Editor/Serialization/FastBufferReaderTests.cs | 2 +- .../Components/NetworkVariableTestComponent.cs | 2 +- 4 files changed, 7 insertions(+), 17 deletions(-) diff --git a/com.unity.netcode.gameobjects/Runtime/Serialization/BytePacker.cs b/com.unity.netcode.gameobjects/Runtime/Serialization/BytePacker.cs index 6e45f2b5b8..a823c154cf 100644 --- a/com.unity.netcode.gameobjects/Runtime/Serialization/BytePacker.cs +++ b/com.unity.netcode.gameobjects/Runtime/Serialization/BytePacker.cs @@ -267,13 +267,8 @@ public static void WriteValuePacked(FastBufferWriter writer, Quaternion rotation [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void WriteValuePacked(FastBufferWriter writer, Pose pose) { - WriteValuePacked(writer, pose.position.x); - WriteValuePacked(writer, pose.position.y); - WriteValuePacked(writer, pose.position.z); - WriteValuePacked(writer, pose.rotation.x); - WriteValuePacked(writer, pose.rotation.y); - WriteValuePacked(writer, pose.rotation.z); - WriteValuePacked(writer, pose.rotation.w); + WriteValuePacked(writer, pose.position); + WriteValuePacked(writer, pose.rotation); } /// diff --git a/com.unity.netcode.gameobjects/Runtime/Serialization/ByteUnpacker.cs b/com.unity.netcode.gameobjects/Runtime/Serialization/ByteUnpacker.cs index d215bebe33..310ba46c6b 100644 --- a/com.unity.netcode.gameobjects/Runtime/Serialization/ByteUnpacker.cs +++ b/com.unity.netcode.gameobjects/Runtime/Serialization/ByteUnpacker.cs @@ -286,14 +286,9 @@ public static void ReadValuePacked(FastBufferReader reader, out Quaternion rotat [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void ReadValuePacked(FastBufferReader reader, out Pose pose) { - pose = new Pose(); - ReadValuePacked(reader, out pose.position.x); - ReadValuePacked(reader, out pose.position.y); - ReadValuePacked(reader, out pose.position.z); - ReadValuePacked(reader, out pose.rotation.x); - ReadValuePacked(reader, out pose.rotation.y); - ReadValuePacked(reader, out pose.rotation.z); - ReadValuePacked(reader, out pose.rotation.w); + ReadValuePacked(reader, out Vector3 position); + ReadValuePacked(reader, out Quaternion rotation); + pose = new Pose(position, rotation); } /// diff --git a/com.unity.netcode.gameobjects/Tests/Editor/Serialization/FastBufferReaderTests.cs b/com.unity.netcode.gameobjects/Tests/Editor/Serialization/FastBufferReaderTests.cs index 49659e9a0c..85aabbb52e 100644 --- a/com.unity.netcode.gameobjects/Tests/Editor/Serialization/FastBufferReaderTests.cs +++ b/com.unity.netcode.gameobjects/Tests/Editor/Serialization/FastBufferReaderTests.cs @@ -460,7 +460,7 @@ protected override unsafe void RunTypeTest(T valueToTest) } } } - + protected override unsafe void RunTypeTestSafe(T valueToTest) { var writeSize = FastBufferWriter.GetWriteSize(valueToTest); diff --git a/com.unity.netcode.gameobjects/Tests/Runtime/Components/NetworkVariableTestComponent.cs b/com.unity.netcode.gameobjects/Tests/Runtime/Components/NetworkVariableTestComponent.cs index c217331e8d..3e77d9762b 100644 --- a/com.unity.netcode.gameobjects/Tests/Runtime/Components/NetworkVariableTestComponent.cs +++ b/com.unity.netcode.gameobjects/Tests/Runtime/Components/NetworkVariableTestComponent.cs @@ -283,7 +283,7 @@ private void InitializeTest() m_NetworkVariableLong = new NetworkVariable(1); m_NetworkVariableSByte = new NetworkVariable(0); m_NetworkVariableQuaternion = new NetworkVariable(Quaternion.identity); - m_NetworkVariablePose = new NetworkVariable(Pose.identity); + m_NetworkVariablePose = new NetworkVariable(new Pose(new Vector3(1, 1, 1), Quaternion.identity)); m_NetworkVariableShort = new NetworkVariable(256); m_NetworkVariableVector4 = new NetworkVariable(new Vector4(1, 1, 1, 1)); m_NetworkVariableVector3 = new NetworkVariable(new Vector3(1, 1, 1)); From 7f8f17e1d7a1942469cd9282f5c018d08d12b400 Mon Sep 17 00:00:00 2001 From: Emma Date: Fri, 11 Jul 2025 16:46:42 -0400 Subject: [PATCH 3/3] update the changelog --- com.unity.netcode.gameobjects/CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/com.unity.netcode.gameobjects/CHANGELOG.md b/com.unity.netcode.gameobjects/CHANGELOG.md index 622dea8323..cfcc2c5293 100644 --- a/com.unity.netcode.gameobjects/CHANGELOG.md +++ b/com.unity.netcode.gameobjects/CHANGELOG.md @@ -10,6 +10,7 @@ Additional documentation and release notes are available at [Multiplayer Documen ### Added +- Added serializer for `Pose` (#3546) - Added methods `GetDefaultNetworkSettings` and `GetDefaultPipelineConfigurations` to `UnityTransport`. These can be used to retrieve the default settings and pipeline stages that are used by `UnityTransport`. This is useful when providing a custom driver constructor through `UnityTransport.s_DriverConstructor`, since it allows reusing or tuning the existing configuration instead of trying to recreate it. This means a transport with a custom driver can now easily benefit from most of the features of `UnityTransport`, like integration with the Network Simulator and Network Profiler from the multiplayer tools package. (#3501) - Added mappings between `ClientId` and `TransportId`. (#3516) - Added `NetworkPrefabInstanceHandlerWithData`, a variant of `INetworkPrefabInstanceHandler` that provides access to custom instantiation data directly within the `Instantiate()` method. (#3430)