// -------------------------------------------------------------------------------------------------------------------- // // Copyright (c) VRMADA, All rights reserved. // // -------------------------------------------------------------------------------------------------------------------- using System; using System.Collections.Generic; using System.IO; using System.Runtime.Serialization; using UltimateXR.Core.Math; using UltimateXR.Core.Serialization; using UltimateXR.Core.Unique; using UltimateXR.Exceptions; using UnityEngine; namespace UltimateXR.Extensions.System.IO { /// /// extensions. /// public static class BinaryReaderExt { #region Public Methods /// /// Reads a 32-bit integer in compressed format, using only the amount of bytes that are necessary. /// /// Reader /// The serialization version, to provide backwards compatibility /// A 32-bit integer /// The compressed data is corrupt public static int ReadCompressedInt32(this BinaryReader reader, int serializationVersion) { return (int)ReadCompressedUInt32(reader, serializationVersion); } /// /// Reads a 32-bit unsigned integer in compressed format, using only the amount of bytes that are necessary. /// /// Reader /// The serialization version, to provide backwards compatibility /// A 32-bit unsigned integer /// The compressed data is corrupt public static uint ReadCompressedUInt32(this BinaryReader reader, int serializationVersion) { uint num1 = 0; int num2 = 0; while (num2 != 35) { byte num3 = reader.ReadByte(); num1 |= (uint)(num3 & sbyte.MaxValue) << num2; num2 += 7; if ((num3 & 128) == 0) { return num1; } } throw new FormatException("ReadCompressedInt32()/ReadCompressedUInt32() found bad format"); } /// /// Reads a 64-bit integer in compressed format, using only the amount of bytes that are necessary. /// /// Reader /// The serialization version, to provide backwards compatibility /// A 64-bit integer /// The compressed data is corrupt public static long ReadCompressedInt64(this BinaryReader reader, int serializationVersion) { return (long)ReadCompressedUInt64(reader, serializationVersion); } /// /// Reads a 64-bit unsigned integer in compressed format, using only the amount of bytes that are necessary. /// /// Reader /// The serialization version, to provide backwards compatibility /// A 64-bit unsigned integer /// The compressed data is corrupt public static ulong ReadCompressedUInt64(this BinaryReader reader, int serializationVersion) { ulong num1 = 0; int num2 = 0; while (num2 != 63) { byte num3 = reader.ReadByte(); num1 |= (ulong)(num3 & sbyte.MaxValue) << num2; num2 += 7; if ((num3 & 128) == 0) { return num1; } } throw new FormatException("ReadCompressedInt64()/ReadCompressedUInt64() found bad format"); } /// /// Reads an enum value. /// /// Reader /// The serialization version, to provide backwards compatibility /// Enum object public static T ReadEnum(this BinaryReader reader, int serializationVersion) { return (T)Enum.ToObject(typeof(T), reader.ReadCompressedInt32(serializationVersion)); } /// /// Reads a string written using . /// /// Reader /// The serialization version, to provide backwards compatibility /// String or null public static string ReadStringWithNullCheck(this BinaryReader reader) { // Serialized as: null-check (bool), string bool nullCheck = reader.ReadBoolean(); if (!nullCheck) { return null; } return reader.ReadString(); } /// /// Reads a type, which has been serialized as two strings: the full type name plus the assembly. If the type is from /// the same assembly as UltimateXR, the assembly will be an empty string. /// /// Reader /// The serialization version, to provide backwards compatibility /// The type public static Type ReadType(this BinaryReader reader, int serializationVersion) { return reader.ReadType(serializationVersion, out string _, out string _); } /// /// Reads a type, which has been serialized as two strings: the full type name plus the assembly. If the type is from /// the same assembly as UltimateXR, the assembly will be an empty string. /// /// Reader /// The serialization version, to provide backwards compatibility /// Returns the type name /// Returns the type assembly or null/empty if the type is in the same assembly as UltimateXR /// The type public static Type ReadType(this BinaryReader reader, int serializationVersion, out string typeName, out string assembly) { typeName = reader.ReadString(); if (typeName != string.Empty) { assembly = reader.ReadString(); return TypeExt.GetType(typeName, assembly); } assembly = string.Empty; return null; } /// /// Reads a Guid, which has been serialized as a 16 byte array. /// /// Reader /// The serialization version, to provide backwards compatibility /// The Guid public static Guid ReadGuid(this BinaryReader reader, int serializationVersion) { return new Guid(reader.ReadBytes(16)); } /// /// Reads a tuple. /// /// Reader /// The serialization version, to provide backwards compatibility /// The tuple public static (T1, T2) ReadTuple(this BinaryReader reader, int serializationVersion) { return ((T1, T2))(reader.Read(serializationVersion), reader.Read(serializationVersion)); } /// /// Reads an array. /// /// Reader /// The serialization version, to provide backwards compatibility /// The type of elements in the array /// The array /// A type is not supported /// The compressed data is corrupt /// An was not found when deserializing /// /// A class that implements the /// interface was not found when deserializing /// public static T[] ReadArray(this BinaryReader reader, int serializationVersion) { // Serialized as: null-check (bool), count (int32), elements bool nullCheck = reader.ReadBoolean(); if (!nullCheck) { return null; } T[] array = new T[reader.ReadCompressedInt32(serializationVersion)]; for (int i = 0; i < array.Length; ++i) { array[i] = (T)reader.Read(serializationVersion); } return array; } /// /// Reads an array of objects where each element can be of a different type. /// /// Reader /// The serialization version, to provide backwards compatibility /// The object array /// A type is not supported /// The compressed data is corrupt /// An was not found when deserializing /// /// A class that implements the /// interface was not found when deserializing /// public static object[] ReadObjectArray(this BinaryReader reader, int serializationVersion) { // Serialized as: null-check (bool), count (int32), elements bool nullCheck = reader.ReadBoolean(); if (!nullCheck) { return null; } object[] array = new object[reader.ReadCompressedInt32(serializationVersion)]; Exception firstException = null; for (int i = 0; i < array.Length; ++i) { try { array[i] = reader.ReadAnyVar(serializationVersion); } catch (Exception e) { if (firstException == null) { firstException = e; } } } if (firstException != null) { // This helps debugging UxrMethodInvokedSyncEventArgs. We keep deserializing event parameters even if there are errors. throw firstException; } return array; } /// /// Reads a list. /// /// Reader /// The serialization version, to provide backwards compatibility /// The type of elements in the list /// The list /// A type is not supported /// The compressed data is corrupt /// An was not found when deserializing /// /// A class that implements the /// interface was not found when deserializing /// public static List ReadList(this BinaryReader reader, int serializationVersion) { // Serialized as: null-check (bool), count (int32), elements bool nullCheck = reader.ReadBoolean(); if (!nullCheck) { return null; } List list = new List(); int count = reader.ReadCompressedInt32(serializationVersion); for (int i = 0; i < count; ++i) { list.Add((T)reader.Read(serializationVersion)); } return list; } /// /// Reads a list of objects where each element can be of a different type. /// /// Reader /// The serialization version, to provide backwards compatibility /// The list /// A type is not supported /// The compressed data is corrupt /// An was not found when deserializing /// /// A class that implements the /// interface was not found when deserializing /// public static List ReadObjectList(this BinaryReader reader, int serializationVersion) { // Serialized as: null-check (bool), count (int32), elements bool nullCheck = reader.ReadBoolean(); if (!nullCheck) { return null; } List list = new List(); int count = reader.ReadCompressedInt32(serializationVersion); for (int i = 0; i < count; ++i) { list.Add(reader.ReadAnyVar(serializationVersion)); } return list; } /// /// Reads a dictionary. /// /// Reader /// The serialization version, to provide backwards compatibility /// The dictionary /// A type is not supported /// The compressed data is corrupt /// An was not found when deserializing /// /// A class that implements the /// interface was not found when deserializing /// public static Dictionary ReadDictionary(this BinaryReader reader, int serializationVersion) { // Serialized as: null-check (bool), count (int32), elements bool nullCheck = reader.ReadBoolean(); if (!nullCheck) { return null; } Dictionary dictionary = new Dictionary(); int count = reader.ReadCompressedInt32(serializationVersion); for (int i = 0; i < count; ++i) { TKey key = (TKey)reader.Read(serializationVersion); TValue value = (TValue)reader.Read(serializationVersion); dictionary.Add(key, value); } return dictionary; } /// /// Reads a HashSet. /// /// Reader /// The serialization version, to provide backwards compatibility /// The type of elements in the HashSet /// The hash set /// A type is not supported /// The compressed data is corrupt /// An was not found when deserializing /// /// A class that implements the /// interface was not found when deserializing /// public static HashSet ReadHashSet(this BinaryReader reader, int serializationVersion) { // Serialized as: null-check (bool), count (int32), elements bool nullCheck = reader.ReadBoolean(); if (!nullCheck) { return null; } HashSet hashSet = new HashSet(); int count = reader.ReadCompressedInt32(serializationVersion); for (int i = 0; i < count; ++i) { hashSet.Add((T)reader.Read(serializationVersion)); } return hashSet; } /// /// Reads a hash set of objects where each element can be of a different type. /// /// Reader /// The serialization version, to provide backwards compatibility /// The hash set /// A type is not supported /// The compressed data is corrupt /// An was not found when deserializing /// /// A class that implements the /// interface was not found when deserializing /// public static HashSet ReadObjectHashSet(this BinaryReader reader, int serializationVersion) { // Serialized as: null-check (bool), count (int32), elements bool nullCheck = reader.ReadBoolean(); if (!nullCheck) { return null; } HashSet hashSet = new HashSet(); int count = reader.ReadCompressedInt32(serializationVersion); for (int i = 0; i < count; ++i) { hashSet.Add(reader.ReadAnyVar(serializationVersion)); } return hashSet; } /// /// Reads a . /// /// Reader /// The serialization version, to provide backwards compatibility /// DateTime public static DateTime ReadDateTime(this BinaryReader reader, int serializationVersion) { // Read ticks (64 bits) return new DateTime(reader.ReadCompressedInt64(serializationVersion)); } /// /// Reads a . /// /// Reader /// The serialization version, to provide backwards compatibility /// TimeSpan public static TimeSpan ReadTimeSpan(this BinaryReader reader, int serializationVersion) { // Read ticks (64 bits) return new TimeSpan(reader.ReadCompressedInt64(serializationVersion)); } /// /// Reads a . /// /// Reader /// The serialization version, to provide backwards compatibility /// Vector public static Vector2 ReadVector2(this BinaryReader reader, int serializationVersion) { return new Vector2(reader.ReadSingle(), reader.ReadSingle()); } /// /// Reads a . /// /// Reader /// The serialization version, to provide backwards compatibility /// Vector public static Vector3 ReadVector3(this BinaryReader reader, int serializationVersion) { return new Vector3(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle()); } /// /// Reads a . /// /// Reader /// The serialization version, to provide backwards compatibility /// Vector public static Vector4 ReadVector4(this BinaryReader reader, int serializationVersion) { return new Vector4(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle()); } /// /// Reads a . /// /// Reader /// The serialization version, to provide backwards compatibility /// Color public static Color ReadColor(this BinaryReader reader, int serializationVersion) { return new Color(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle()); } /// /// Reads a . /// /// Reader /// The serialization version, to provide backwards compatibility /// Color32 public static Color32 ReadColor32(this BinaryReader reader, int serializationVersion) { return new Color32(reader.ReadByte(), reader.ReadByte(), reader.ReadByte(), reader.ReadByte()); } /// /// Reads a . /// /// Reader /// The serialization version, to provide backwards compatibility /// Quaternion public static Quaternion ReadQuaternion(this BinaryReader reader, int serializationVersion) { return new Quaternion(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle()); } /// /// Reads a . /// /// Reader /// The serialization version, to provide backwards compatibility /// Matrix public static Matrix4x4 ReadMatrix(this BinaryReader reader, int serializationVersion) { Matrix4x4 matrix; matrix.m00 = reader.ReadSingle(); matrix.m10 = reader.ReadSingle(); matrix.m20 = reader.ReadSingle(); matrix.m30 = reader.ReadSingle(); matrix.m01 = reader.ReadSingle(); matrix.m11 = reader.ReadSingle(); matrix.m21 = reader.ReadSingle(); matrix.m31 = reader.ReadSingle(); matrix.m02 = reader.ReadSingle(); matrix.m12 = reader.ReadSingle(); matrix.m22 = reader.ReadSingle(); matrix.m32 = reader.ReadSingle(); matrix.m03 = reader.ReadSingle(); matrix.m13 = reader.ReadSingle(); matrix.m23 = reader.ReadSingle(); matrix.m33 = reader.ReadSingle(); return matrix; } /// /// Reads a component that implements . Only the unique ID (string) will be read. /// The component will be retrieved using the ID with . /// /// Reader /// The serialization version, to provide backwards compatibility /// Component that implements the interface /// The given component could not be found using the Id public static IUxrUniqueId ReadUniqueComponent(this BinaryReader reader, int serializationVersion) { // Serialized as: null-check (bool), Guid bool nullCheck = reader.ReadBoolean(); if (!nullCheck) { return null; } Guid componentId = reader.ReadGuid(serializationVersion); if (componentId == default) { return null; } if (UxrUniqueIdImplementer.TryGetComponentById(componentId, out IUxrUniqueId component)) { return component; } throw new UxrComponentNotFoundException(componentId); } /// /// Reads a component that implements . Only the unique ID (string) will be read. /// The component will be retrieved using the ID with . /// /// Reader /// The serialization version, to provide backwards compatibility /// Component that implements the interface /// The given component could not be found using the Id public static T ReadUniqueComponent(this BinaryReader reader, int serializationVersion) where T : Component, IUxrUniqueId { return ReadUniqueComponent(reader, serializationVersion) as T; } /// /// Reads an object that implements the interface. It has support for null references. /// /// Reader /// The serialization version, to provide backwards compatibility /// Object with the IUxrSerializable interface, which can be casted to the correct type /// A type is not supported /// The compressed data is corrupt /// An was not found when deserializing /// /// A class that implements the /// interface was not found when deserializing /// public static IUxrSerializable ReadUxrSerializable(this BinaryReader reader, int serializationVersion) { bool hasData = reader.ReadBoolean(); if (!hasData) { return null; } int version = reader.ReadCompressedInt32(serializationVersion); Type type = reader.ReadType(serializationVersion, out string typeName, out string assemblyName); object newObject = type != null ? FormatterServices.GetUninitializedObject(type) : null; if (newObject == null) { throw new UxrSerializableClassNotFoundException(typeName, assemblyName, $"GetUninitializedObject({TypeExt.GetTypeString(typeName, assemblyName)}) returned null"); } if (newObject is IUxrSerializable serializable) { serializable.Serialize(new UxrBinarySerializer(reader, serializationVersion), version); return serializable; } throw new UxrSerializableClassNotFoundException(typeName, assemblyName, $"Object {typeName} does not implement {nameof(IUxrSerializable)} interface"); } /// /// Reads an object that implements the interface. It has support for null references. /// /// Reader /// The serialization version, to provide backwards compatibility /// Object with the IUxrSerializable interface, which can be casted to the correct type /// A type is not supported /// The compressed data is corrupt /// An was not found when deserializing /// /// A class that implements the /// interface was not found when deserializing /// /// /// Failed to cast the value to . /// public static T ReadUxrSerializable(this BinaryReader reader, int serializationVersion) where T : IUxrSerializable { IUxrSerializable serializable = ReadUxrSerializable(reader, serializationVersion); if (serializable is T typedSerializable) { return typedSerializable; } throw new InvalidCastException($"Failed to cast {typeof(T).Name} to {nameof(IUxrSerializable)}"); } /// /// Reads an value. /// /// Reader /// The serialization version, to provide backwards compatibility /// Axis value /// A type is not supported /// The compressed data is corrupt public static UxrAxis ReadAxis(this BinaryReader reader, int serializationVersion) { return ReadCompressedInt32(reader, serializationVersion); } /// /// Reads an supported by . This is used together with /// to serialize/deserialize variables whose type are unknown at compile /// time. /// /// Reader /// The serialization version, to provide backwards compatibility /// Returns the type of the object found, or /// /// Object or null. Null can be both because the object is unsupported or the object itself is null. Check /// to tell between the two cases /// /// A type is not supported /// The compressed data is corrupt /// An was not found when deserializing /// /// A class that implements the /// interface was not found when deserializing /// /// /// Failed to cast the value to . /// public static object ReadAnyVar(this BinaryReader reader, int serializationVersion) { return reader.ReadAnyVar(serializationVersion, out UxrVarType _); } /// /// Reads an supported by . This is used together with /// to serialize/deserialize variables whose type are unknown at compile /// time. /// /// Reader /// The serialization version, to provide backwards compatibility /// Returns the type of the object found, or /// /// Object or null. Null can be both because the object is unknown or the object itself is null. Check /// to tell between the two cases /// /// A type is not supported /// The compressed data is corrupt /// An was not found when deserializing /// /// A class that implements the /// interface was not found when deserializing /// /// /// Failed to cast the value to . /// public static object ReadAnyVar(this BinaryReader reader, int serializationVersion, out UxrVarType varType) { varType = (UxrVarType)reader.ReadByte(); if (varType == UxrVarType.Unknown) { return null; } if (varType is UxrVarType.Bool) { return reader.ReadBoolean(); } if (varType is UxrVarType.SignedByte) { return reader.ReadSByte(); } if (varType is UxrVarType.Byte) { return reader.ReadByte(); } if (varType is UxrVarType.Char) { return reader.ReadChar(); } if (varType is UxrVarType.Int) { return reader.ReadCompressedInt32(serializationVersion); } if (varType is UxrVarType.UnsignedInt) { return reader.ReadCompressedUInt32(serializationVersion); } if (varType is UxrVarType.Long) { return reader.ReadCompressedInt64(serializationVersion); } if (varType is UxrVarType.UnsignedLong) { return reader.ReadCompressedUInt64(serializationVersion); } if (varType is UxrVarType.Float) { return reader.ReadSingle(); } if (varType is UxrVarType.Double) { return reader.ReadDouble(); } if (varType is UxrVarType.Decimal) { return reader.ReadDecimal(); } if (varType is UxrVarType.String) { return reader.ReadString(); } if (varType is UxrVarType.Enum) { Type enumType = reader.ReadType(serializationVersion); return typeof(BinaryReaderExt).GetMethod(nameof(ReadEnum)).MakeGenericMethod(enumType).Invoke(reader, new object[] { reader, serializationVersion }); } if (varType is UxrVarType.Type) { return reader.ReadType(serializationVersion); } if (varType is UxrVarType.Guid) { return reader.ReadGuid(serializationVersion); } if (varType is UxrVarType.Tuple) { Type typeItem1 = reader.ReadType(serializationVersion); Type typeItem2 = reader.ReadType(serializationVersion); return typeof(BinaryReaderExt).GetMethod(nameof(ReadTuple)).MakeGenericMethod(typeItem1, typeItem2).Invoke(reader, new object[] { reader, serializationVersion }); } if (varType is UxrVarType.Array) { Type elementType = reader.ReadType(serializationVersion); return typeof(BinaryReaderExt).GetMethod(nameof(ReadArray)).MakeGenericMethod(elementType).Invoke(reader, new object[] { reader, serializationVersion }); } if (varType is UxrVarType.ObjectArray) { return reader.ReadObjectArray(serializationVersion); } if (varType is UxrVarType.List) { Type elementType = reader.ReadType(serializationVersion); return typeof(BinaryReaderExt).GetMethod(nameof(ReadList)).MakeGenericMethod(elementType).Invoke(reader, new object[] { reader, serializationVersion }); } if (varType is UxrVarType.ObjectList) { return reader.ReadObjectList(serializationVersion); } if (varType is UxrVarType.Dictionary) { Type keyType = reader.ReadType(serializationVersion); Type elementType = reader.ReadType(serializationVersion); return typeof(BinaryReaderExt).GetMethod(nameof(ReadDictionary)).MakeGenericMethod(keyType, elementType).Invoke(reader, new object[] { reader, serializationVersion }); } if (varType is UxrVarType.HashSet) { Type elementType = reader.ReadType(serializationVersion); return typeof(BinaryReaderExt).GetMethod(nameof(ReadHashSet)).MakeGenericMethod(elementType).Invoke(reader, new object[] { reader, serializationVersion }); } if (varType is UxrVarType.ObjectHashSet) { return reader.ReadObjectHashSet(serializationVersion); } if (varType is UxrVarType.DateTime) { return reader.ReadDateTime(serializationVersion); } if (varType is UxrVarType.TimeSpan) { return reader.ReadTimeSpan(serializationVersion); } if (varType is UxrVarType.Vector2) { return reader.ReadVector2(serializationVersion); } if (varType is UxrVarType.Vector3) { return reader.ReadVector3(serializationVersion); } if (varType is UxrVarType.Vector4) { return reader.ReadVector4(serializationVersion); } if (varType is UxrVarType.Color) { return reader.ReadColor(serializationVersion); } if (varType is UxrVarType.Color32) { return reader.ReadColor32(serializationVersion); } if (varType is UxrVarType.Quaternion) { return reader.ReadQuaternion(serializationVersion); } if (varType is UxrVarType.Matrix4x4) { return reader.ReadMatrix(serializationVersion); } if (varType is UxrVarType.IUxrUnique) { return reader.ReadUniqueComponent(serializationVersion); } if (varType is UxrVarType.IUxrSerializable) { return reader.ReadUxrSerializable(serializationVersion); } if (varType is UxrVarType.UxrAxis) { return reader.ReadAxis(serializationVersion); } throw new ArgumentOutOfRangeException(nameof(varType), varType, $"Deserializing unknown {nameof(UxrVarType)} ({varType})"); } #endregion #region Private Methods /// /// Reads an object supported by . /// /// Reader /// The type of the object /// The object /// A type is not supported /// The compressed data is corrupt /// An was not found when deserializing /// /// A class that implements the /// interface was not found when deserializing /// /// /// Failed to cast the value to . /// private static object Read(this BinaryReader reader, int serializationVersion) { Type type = typeof(T); if (type == typeof(bool)) { return reader.ReadBoolean(); } if (type == typeof(sbyte)) { return reader.ReadSByte(); } if (type == typeof(byte)) { return reader.ReadByte(); } if (type == typeof(char)) { return reader.ReadChar(); } if (type == typeof(int)) { return reader.ReadCompressedInt32(serializationVersion); } if (type == typeof(uint)) { return reader.ReadCompressedUInt32(serializationVersion); } if (type == typeof(long)) { return reader.ReadCompressedInt64(serializationVersion); } if (type == typeof(ulong)) { return reader.ReadCompressedUInt64(serializationVersion); } if (type == typeof(float)) { return reader.ReadSingle(); } if (type == typeof(double)) { return reader.ReadDouble(); } if (type == typeof(decimal)) { return reader.ReadDecimal(); } if (type == typeof(string)) { return reader.ReadString(); } if (type.IsEnum) { return reader.ReadEnum(serializationVersion); } if (type == typeof(Type)) { return reader.ReadType(serializationVersion); } if (type == typeof(Guid)) { return reader.ReadGuid(serializationVersion); } if (type.IsGenericType && (type.GetGenericTypeDefinition() == typeof(Tuple<,>) || type.GetGenericTypeDefinition() == typeof(ValueTuple<,>))) { Type typeItem1 = type.GetGenericArguments()[0]; Type typeItem2 = type.GetGenericArguments()[1]; return typeof(BinaryReaderExt).GetMethod(nameof(ReadTuple)).MakeGenericMethod(typeItem1, typeItem2).Invoke(reader, new object[] { reader, serializationVersion }); } if (type.IsArray) { if (type.GetElementType() == typeof(object)) { return reader.ReadObjectArray(serializationVersion); } return reader.ReadArray(serializationVersion); } if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(List<>)) { Type elementType = type.GetElementType(); if (elementType == typeof(object)) { return reader.ReadObjectList(serializationVersion); } typeof(BinaryReaderExt).GetMethod(nameof(ReadList)).MakeGenericMethod(elementType).Invoke(reader, new object[] { reader, serializationVersion }); } if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Dictionary<,>)) { Type keyType = type.GetGenericArguments()[0]; Type valueType = type.GetGenericArguments()[1]; return typeof(BinaryReaderExt).GetMethod(nameof(ReadDictionary)).MakeGenericMethod(keyType, valueType).Invoke(reader, new object[] { reader, serializationVersion }); } if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(HashSet<>)) { Type elementType = type.GetElementType(); if (elementType == typeof(object)) { return reader.ReadObjectHashSet(serializationVersion); } typeof(BinaryReaderExt).GetMethod(nameof(ReadHashSet)).MakeGenericMethod(elementType).Invoke(reader, new object[] { reader, serializationVersion }); } if (type == typeof(Vector2)) { return reader.ReadVector2(serializationVersion); } if (type == typeof(Vector3)) { return reader.ReadVector3(serializationVersion); } if (type == typeof(Vector4)) { return reader.ReadVector4(serializationVersion); } if (type == typeof(Color)) { return reader.ReadColor(serializationVersion); } if (type == typeof(Color32)) { return reader.ReadColor32(serializationVersion); } if (type == typeof(Quaternion)) { return reader.ReadQuaternion(serializationVersion); } if (type == typeof(Matrix4x4)) { return reader.ReadMatrix(serializationVersion); } if (type == typeof(Matrix4x4)) { return reader.ReadMatrix(serializationVersion); } if (typeof(IUxrUniqueId).IsAssignableFrom(type)) { return reader.ReadUniqueComponent(serializationVersion); } if (typeof(IUxrSerializable).IsAssignableFrom(type)) { return reader.ReadUxrSerializable(serializationVersion); } if (type == typeof(UxrAxis)) { return reader.ReadAxis(serializationVersion); } throw new ArgumentOutOfRangeException(nameof(T), typeof(T).FullName, $"Deserializing to unknown target type ({typeof(T).FullName}"); } #endregion } }