From 52111d1cb8271ce55b43128136f5dcf886991f4e Mon Sep 17 00:00:00 2001 From: MrGadget <9826063+MrGadget1024@users.noreply.github.com> Date: Sat, 27 Nov 2021 04:31:16 -0500 Subject: [PATCH] feat: Support more nullable types (#3005) * feat: Support more nullable types - NetworkWriter was also slightly rearraged to match NetworkReader * fixed code smells * fixed WriteVector4Nullable * Got some of them working * Couple more * Couple more * Added the rest * reverted accidental change --- Assets/Mirror/Runtime/NetworkReader.cs | 84 +++++++--- Assets/Mirror/Runtime/NetworkWriter.cs | 212 +++++++++++++++++++++---- 2 files changed, 241 insertions(+), 55 deletions(-) diff --git a/Assets/Mirror/Runtime/NetworkReader.cs b/Assets/Mirror/Runtime/NetworkReader.cs index 2ed074739..e7d768357 100644 --- a/Assets/Mirror/Runtime/NetworkReader.cs +++ b/Assets/Mirror/Runtime/NetworkReader.cs @@ -127,10 +127,19 @@ public static class NetworkReaderExtensions static readonly UTF8Encoding encoding = new UTF8Encoding(false, true); public static byte ReadByte(this NetworkReader reader) => reader.ReadByte(); + public static byte? ReadByteNullable(this NetworkReader reader) => reader.ReadBool() ? ReadByte(reader) : default; + public static sbyte ReadSByte(this NetworkReader reader) => (sbyte)reader.ReadByte(); + public static sbyte? ReadSByteNullable(this NetworkReader reader) => reader.ReadBool() ? ReadSByte(reader) : default; + public static char ReadChar(this NetworkReader reader) => (char)reader.ReadUShort(); + public static char? ReadCharNullable(this NetworkReader reader) => reader.ReadBool() ? ReadChar(reader) : default; + public static bool ReadBool(this NetworkReader reader) => reader.ReadByte() != 0; + public static bool? ReadBoolNullable(this NetworkReader reader) => reader.ReadBool() ? ReadBool(reader) : default; + public static short ReadShort(this NetworkReader reader) => (short)reader.ReadUShort(); + public static short? ReadShortNullable(this NetworkReader reader) => reader.ReadBool() ? ReadShort(reader) : default; public static ushort ReadUShort(this NetworkReader reader) { @@ -139,8 +148,10 @@ public static ushort ReadUShort(this NetworkReader reader) value |= (ushort)(reader.ReadByte() << 8); return value; } + public static ushort? ReadUShortNullable(this NetworkReader reader) => reader.ReadBool() ? ReadUShort(reader) : default; public static int ReadInt(this NetworkReader reader) => (int)reader.ReadUInt(); + public static int? ReadIntNullable(this NetworkReader reader) => reader.ReadBool() ? ReadInt(reader) : default; public static uint ReadUInt(this NetworkReader reader) { @@ -151,8 +162,10 @@ public static uint ReadUInt(this NetworkReader reader) value |= (uint)(reader.ReadByte() << 24); return value; } + public static uint? ReadUIntNullable(this NetworkReader reader) => reader.ReadBool() ? ReadUInt(reader) : default; public static long ReadLong(this NetworkReader reader) => (long)reader.ReadULong(); + public static long? ReadLongNullable(this NetworkReader reader) => reader.ReadBool() ? ReadLong(reader) : default; public static ulong ReadULong(this NetworkReader reader) { @@ -167,6 +180,7 @@ public static ulong ReadULong(this NetworkReader reader) value |= ((ulong)reader.ReadByte()) << 56; return value; } + public static ulong? ReadULongNullable(this NetworkReader reader) => reader.ReadBool() ? ReadULong(reader) : default; public static float ReadFloat(this NetworkReader reader) { @@ -174,6 +188,7 @@ public static float ReadFloat(this NetworkReader reader) converter.intValue = reader.ReadUInt(); return converter.floatValue; } + public static float? ReadFloatNullable(this NetworkReader reader) => reader.ReadBool() ? ReadFloat(reader) : default; public static double ReadDouble(this NetworkReader reader) { @@ -181,6 +196,8 @@ public static double ReadDouble(this NetworkReader reader) converter.longValue = reader.ReadULong(); return converter.doubleValue; } + public static double? ReadDoubleNullable(this NetworkReader reader) => reader.ReadBool() ? ReadDouble(reader) : default; + public static decimal ReadDecimal(this NetworkReader reader) { UIntDecimal converter = new UIntDecimal(); @@ -188,6 +205,7 @@ public static decimal ReadDecimal(this NetworkReader reader) converter.longValue2 = reader.ReadULong(); return converter.decimalValue; } + public static decimal? ReadDecimalNullable(this NetworkReader reader) => reader.ReadBool() ? ReadDecimal(reader) : default; /// if an invalid utf8 string is sent public static string ReadString(this NetworkReader reader) @@ -223,6 +241,13 @@ public static byte[] ReadBytesAndSize(this NetworkReader reader) return count == 0 ? null : reader.ReadBytes(checked((int)(count - 1u))); } + public static byte[] ReadBytes(this NetworkReader reader, int count) + { + byte[] bytes = new byte[count]; + reader.ReadBytes(bytes, count); + return bytes; + } + /// if count is invalid public static ArraySegment ReadBytesAndSizeSegment(this NetworkReader reader) { @@ -234,24 +259,38 @@ public static ArraySegment ReadBytesAndSizeSegment(this NetworkReader read } public static Vector2 ReadVector2(this NetworkReader reader) => new Vector2(reader.ReadFloat(), reader.ReadFloat()); + public static Vector2? ReadVector2Nullable(this NetworkReader reader) => reader.ReadBool() ? ReadVector2(reader) : default; + public static Vector3 ReadVector3(this NetworkReader reader) => new Vector3(reader.ReadFloat(), reader.ReadFloat(), reader.ReadFloat()); - // TODO add nullable support to weaver instead public static Vector3? ReadVector3Nullable(this NetworkReader reader) => reader.ReadBool() ? ReadVector3(reader) : default; + public static Vector4 ReadVector4(this NetworkReader reader) => new Vector4(reader.ReadFloat(), reader.ReadFloat(), reader.ReadFloat(), reader.ReadFloat()); + public static Vector4? ReadVector4Nullable(this NetworkReader reader) => reader.ReadBool() ? ReadVector4(reader) : default; + public static Vector2Int ReadVector2Int(this NetworkReader reader) => new Vector2Int(reader.ReadInt(), reader.ReadInt()); + public static Vector2Int? ReadVector2IntNullable(this NetworkReader reader) => reader.ReadBool() ? ReadVector2Int(reader) : default; + public static Vector3Int ReadVector3Int(this NetworkReader reader) => new Vector3Int(reader.ReadInt(), reader.ReadInt(), reader.ReadInt()); + public static Vector3Int? ReadVector3IntNullable(this NetworkReader reader) => reader.ReadBool() ? ReadVector3Int(reader) : default; + public static Color ReadColor(this NetworkReader reader) => new Color(reader.ReadFloat(), reader.ReadFloat(), reader.ReadFloat(), reader.ReadFloat()); - // TODO add nullable support to weaver instead public static Color? ReadColorNullable(this NetworkReader reader) => reader.ReadBool() ? new Color(reader.ReadFloat(), reader.ReadFloat(), reader.ReadFloat(), reader.ReadFloat()) : default; + public static Color32 ReadColor32(this NetworkReader reader) => new Color32(reader.ReadByte(), reader.ReadByte(), reader.ReadByte(), reader.ReadByte()); - // TODO add nullable support to weaver instead public static Color32? ReadColor32Nullable(this NetworkReader reader) => reader.ReadBool() ? new Color32(reader.ReadByte(), reader.ReadByte(), reader.ReadByte(), reader.ReadByte()) : default; + public static Quaternion ReadQuaternion(this NetworkReader reader) => new Quaternion(reader.ReadFloat(), reader.ReadFloat(), reader.ReadFloat(), reader.ReadFloat()); - // TODO add nullable support to weaver instead public static Quaternion? ReadQuaternionNullable(this NetworkReader reader) => reader.ReadBool() ? ReadQuaternion(reader) : default; + public static Rect ReadRect(this NetworkReader reader) => new Rect(reader.ReadFloat(), reader.ReadFloat(), reader.ReadFloat(), reader.ReadFloat()); + public static Rect? ReadRectNullable(this NetworkReader reader) => reader.ReadBool() ? ReadRect(reader) : default; + public static Plane ReadPlane(this NetworkReader reader) => new Plane(reader.ReadVector3(), reader.ReadFloat()); + public static Plane? ReadPlaneNullable(this NetworkReader reader) => reader.ReadBool() ? ReadPlane(reader) : default; + public static Ray ReadRay(this NetworkReader reader) => new Ray(reader.ReadVector3(), reader.ReadVector3()); + public static Ray? ReadRayNullable(this NetworkReader reader) => reader.ReadBool() ? ReadRay(reader) : default; + public static Matrix4x4 ReadMatrix4x4(this NetworkReader reader) { return new Matrix4x4 @@ -274,27 +313,10 @@ public static Matrix4x4 ReadMatrix4x4(this NetworkReader reader) m33 = reader.ReadFloat() }; } - public static byte[] ReadBytes(this NetworkReader reader, int count) - { - byte[] bytes = new byte[count]; - reader.ReadBytes(bytes, count); - return bytes; - } + public static Matrix4x4? ReadMatrix4x4Nullable(this NetworkReader reader) => reader.ReadBool() ? ReadMatrix4x4(reader) : default; + public static Guid ReadGuid(this NetworkReader reader) => new Guid(reader.ReadBytes(16)); - - public static Transform ReadTransform(this NetworkReader reader) - { - // Don't use null propagation here as it could lead to MissingReferenceException - NetworkIdentity networkIdentity = reader.ReadNetworkIdentity(); - return networkIdentity != null ? networkIdentity.transform : null; - } - - public static GameObject ReadGameObject(this NetworkReader reader) - { - // Don't use null propagation here as it could lead to MissingReferenceException - NetworkIdentity networkIdentity = reader.ReadNetworkIdentity(); - return networkIdentity != null ? networkIdentity.gameObject : null; - } + public static Guid? ReadGuidNullable(this NetworkReader reader) => reader.ReadBool() ? ReadGuid(reader) : Guid.Empty; public static NetworkIdentity ReadNetworkIdentity(this NetworkReader reader) { @@ -355,6 +377,20 @@ public static NetworkBehaviour.NetworkBehaviourSyncVar ReadNetworkBehaviourSyncV return new NetworkBehaviour.NetworkBehaviourSyncVar(netId, componentIndex); } + public static Transform ReadTransform(this NetworkReader reader) + { + // Don't use null propagation here as it could lead to MissingReferenceException + NetworkIdentity networkIdentity = reader.ReadNetworkIdentity(); + return networkIdentity != null ? networkIdentity.transform : null; + } + + public static GameObject ReadGameObject(this NetworkReader reader) + { + // Don't use null propagation here as it could lead to MissingReferenceException + NetworkIdentity networkIdentity = reader.ReadNetworkIdentity(); + return networkIdentity != null ? networkIdentity.gameObject : null; + } + public static List ReadList(this NetworkReader reader) { int length = reader.ReadInt(); diff --git a/Assets/Mirror/Runtime/NetworkWriter.cs b/Assets/Mirror/Runtime/NetworkWriter.cs index f1f956c88..111aa36e3 100644 --- a/Assets/Mirror/Runtime/NetworkWriter.cs +++ b/Assets/Mirror/Runtime/NetworkWriter.cs @@ -101,19 +101,70 @@ public static class NetworkWriterExtensions public static void WriteByte(this NetworkWriter writer, byte value) => writer.WriteByte(value); + public static void WriteByteNullable(this NetworkWriter writer, byte? value) + { + writer.WriteBool(value.HasValue); + if (value.HasValue) + writer.WriteByte(value.Value); + } + public static void WriteSByte(this NetworkWriter writer, sbyte value) => writer.WriteByte((byte)value); + public static void WriteSByteNullable(this NetworkWriter writer, sbyte? value) + { + writer.WriteBool(value.HasValue); + if (value.HasValue) + writer.WriteSByte(value.Value); + } + public static void WriteChar(this NetworkWriter writer, char value) => writer.WriteUShort(value); + public static void WriteCharNullable(this NetworkWriter writer, char? value) + { + writer.WriteBool(value.HasValue); + if (value.HasValue) + writer.WriteChar(value.Value); + } + public static void WriteBool(this NetworkWriter writer, bool value) => writer.WriteByte((byte)(value ? 1 : 0)); + public static void WriteBoolNullable(this NetworkWriter writer, bool? value) + { + writer.WriteBool(value.HasValue); + if (value.HasValue) + writer.WriteBool(value.Value); + } + + public static void WriteShort(this NetworkWriter writer, short value) => writer.WriteUShort((ushort)value); + + public static void WriteShortNullable(this NetworkWriter writer, short? value) + { + writer.WriteBool(value.HasValue); + if (value.HasValue) + writer.WriteShort(value.Value); + } + public static void WriteUShort(this NetworkWriter writer, ushort value) { writer.WriteByte((byte)value); writer.WriteByte((byte)(value >> 8)); } - public static void WriteShort(this NetworkWriter writer, short value) => writer.WriteUShort((ushort)value); + public static void WriteUShortNullable(this NetworkWriter writer, ushort? value) + { + writer.WriteBool(value.HasValue); + if (value.HasValue) + writer.WriteUShort(value.Value); + } + + public static void WriteInt(this NetworkWriter writer, int value) => writer.WriteUInt((uint)value); + + public static void WriteIntNullable(this NetworkWriter writer, int? value) + { + writer.WriteBool(value.HasValue); + if (value.HasValue) + writer.WriteInt(value.Value); + } public static void WriteUInt(this NetworkWriter writer, uint value) { @@ -123,7 +174,21 @@ public static void WriteUInt(this NetworkWriter writer, uint value) writer.WriteByte((byte)(value >> 24)); } - public static void WriteInt(this NetworkWriter writer, int value) => writer.WriteUInt((uint)value); + public static void WriteUIntNullable(this NetworkWriter writer, uint? value) + { + writer.WriteBool(value.HasValue); + if (value.HasValue) + writer.WriteUInt(value.Value); + } + + public static void WriteLong(this NetworkWriter writer, long value) => writer.WriteULong((ulong)value); + + public static void WriteLongNullable(this NetworkWriter writer, long? value) + { + writer.WriteBool(value.HasValue); + if (value.HasValue) + writer.WriteLong(value.Value); + } public static void WriteULong(this NetworkWriter writer, ulong value) { @@ -137,7 +202,12 @@ public static void WriteULong(this NetworkWriter writer, ulong value) writer.WriteByte((byte)(value >> 56)); } - public static void WriteLong(this NetworkWriter writer, long value) => writer.WriteULong((ulong)value); + public static void WriteULongNullable(this NetworkWriter writer, ulong? value) + { + writer.WriteBool(value.HasValue); + if (value.HasValue) + writer.WriteULong(value.Value); + } public static void WriteFloat(this NetworkWriter writer, float value) { @@ -148,6 +218,13 @@ public static void WriteFloat(this NetworkWriter writer, float value) writer.WriteUInt(converter.intValue); } + public static void WriteFloatNullable(this NetworkWriter writer, float? value) + { + writer.WriteBool(value.HasValue); + if (value.HasValue) + writer.WriteFloat(value.Value); + } + public static void WriteDouble(this NetworkWriter writer, double value) { UIntDouble converter = new UIntDouble @@ -157,6 +234,13 @@ public static void WriteDouble(this NetworkWriter writer, double value) writer.WriteULong(converter.longValue); } + public static void WriteDoubleNullable(this NetworkWriter writer, double? value) + { + writer.WriteBool(value.HasValue); + if (value.HasValue) + writer.WriteDouble(value.Value); + } + public static void WriteDecimal(this NetworkWriter writer, decimal value) { // the only way to read it without allocations is to both read and @@ -170,6 +254,13 @@ public static void WriteDecimal(this NetworkWriter writer, decimal value) writer.WriteULong(converter.longValue2); } + public static void WriteDecimalNullable(this NetworkWriter writer, decimal? value) + { + writer.WriteBool(value.HasValue); + if (value.HasValue) + writer.WriteDecimal(value.Value); + } + public static void WriteString(this NetworkWriter writer, string value) { // write 0 for null support, increment real size by 1 @@ -197,6 +288,19 @@ public static void WriteString(this NetworkWriter writer, string value) writer.WriteBytes(stringBuffer, 0, size); } + public static void WriteBytesAndSizeSegment(this NetworkWriter writer, ArraySegment buffer) + { + writer.WriteBytesAndSize(buffer.Array, buffer.Offset, buffer.Count); + } + + // Weaver needs a write function with just one byte[] parameter + // (we don't name it .Write(byte[]) because it's really a WriteBytesAndSize since we write size / null info too) + public static void WriteBytesAndSize(this NetworkWriter writer, byte[] buffer) + { + // buffer might be null, so we can't use .Length in that case + writer.WriteBytesAndSize(buffer, 0, buffer != null ? buffer.Length : 0); + } + // for byte arrays with dynamic size, where the reader doesn't know how many will come // (like an inventory with different items etc.) public static void WriteBytesAndSize(this NetworkWriter writer, byte[] buffer, int offset, int count) @@ -213,17 +317,14 @@ public static void WriteBytesAndSize(this NetworkWriter writer, byte[] buffer, i writer.WriteBytes(buffer, offset, count); } - // Weaver needs a write function with just one byte[] parameter - // (we don't name it .Write(byte[]) because it's really a WriteBytesAndSize since we write size / null info too) - public static void WriteBytesAndSize(this NetworkWriter writer, byte[] buffer) + public static void WriteArraySegment(this NetworkWriter writer, ArraySegment segment) { - // buffer might be null, so we can't use .Length in that case - writer.WriteBytesAndSize(buffer, 0, buffer != null ? buffer.Length : 0); - } - - public static void WriteBytesAndSizeSegment(this NetworkWriter writer, ArraySegment buffer) - { - writer.WriteBytesAndSize(buffer.Array, buffer.Offset, buffer.Count); + int length = segment.Count; + writer.WriteInt(length); + for (int i = 0; i < length; i++) + { + writer.Write(segment.Array[segment.Offset + i]); + } } public static void WriteVector2(this NetworkWriter writer, Vector2 value) @@ -232,6 +333,13 @@ public static void WriteVector2(this NetworkWriter writer, Vector2 value) writer.WriteFloat(value.y); } + public static void WriteVector2Nullable(this NetworkWriter writer, Vector2? value) + { + writer.WriteBool(value.HasValue); + if (value.HasValue) + writer.WriteVector2(value.Value); + } + public static void WriteVector3(this NetworkWriter writer, Vector3 value) { writer.WriteFloat(value.x); @@ -239,7 +347,6 @@ public static void WriteVector3(this NetworkWriter writer, Vector3 value) writer.WriteFloat(value.z); } - // TODO add nullable support to weaver instead public static void WriteVector3Nullable(this NetworkWriter writer, Vector3? value) { writer.WriteBool(value.HasValue); @@ -255,12 +362,26 @@ public static void WriteVector4(this NetworkWriter writer, Vector4 value) writer.WriteFloat(value.w); } + public static void WriteVector4Nullable(this NetworkWriter writer, Vector4? value) + { + writer.WriteBool(value.HasValue); + if (value.HasValue) + writer.WriteVector4(value.Value); + } + public static void WriteVector2Int(this NetworkWriter writer, Vector2Int value) { writer.WriteInt(value.x); writer.WriteInt(value.y); } + public static void WriteVector2IntNullable(this NetworkWriter writer, Vector2Int? value) + { + writer.WriteBool(value.HasValue); + if (value.HasValue) + writer.WriteVector2Int(value.Value); + } + public static void WriteVector3Int(this NetworkWriter writer, Vector3Int value) { writer.WriteInt(value.x); @@ -268,6 +389,13 @@ public static void WriteVector3Int(this NetworkWriter writer, Vector3Int value) writer.WriteInt(value.z); } + public static void WriteVector3IntNullable(this NetworkWriter writer, Vector3Int? value) + { + writer.WriteBool(value.HasValue); + if (value.HasValue) + writer.WriteVector3Int(value.Value); + } + public static void WriteColor(this NetworkWriter writer, Color value) { writer.WriteFloat(value.r); @@ -275,8 +403,7 @@ public static void WriteColor(this NetworkWriter writer, Color value) writer.WriteFloat(value.b); writer.WriteFloat(value.a); } - - // TODO add nullable support to weaver instead + public static void WriteColorNullable(this NetworkWriter writer, Color? value) { writer.WriteBool(value.HasValue); @@ -291,8 +418,7 @@ public static void WriteColor32(this NetworkWriter writer, Color32 value) writer.WriteByte(value.b); writer.WriteByte(value.a); } - - // TODO add nullable support to weaver instead + public static void WriteColor32Nullable(this NetworkWriter writer, Color32? value) { writer.WriteBool(value.HasValue); @@ -308,7 +434,6 @@ public static void WriteQuaternion(this NetworkWriter writer, Quaternion value) writer.WriteFloat(value.w); } - // TODO add nullable support to weaver instead public static void WriteQuaternionNullable(this NetworkWriter writer, Quaternion? value) { writer.WriteBool(value.HasValue); @@ -324,18 +449,39 @@ public static void WriteRect(this NetworkWriter writer, Rect value) writer.WriteFloat(value.height); } + public static void WriteRectNullable(this NetworkWriter writer, Rect? value) + { + writer.WriteBool(value.HasValue); + if (value.HasValue) + writer.WriteRect(value.Value); + } + public static void WritePlane(this NetworkWriter writer, Plane value) { writer.WriteVector3(value.normal); writer.WriteFloat(value.distance); } + public static void WritePlaneNullable(this NetworkWriter writer, Plane? value) + { + writer.WriteBool(value.HasValue); + if (value.HasValue) + writer.WritePlane(value.Value); + } + public static void WriteRay(this NetworkWriter writer, Ray value) { writer.WriteVector3(value.origin); writer.WriteVector3(value.direction); } + public static void WriteRayNullable(this NetworkWriter writer, Ray? value) + { + writer.WriteBool(value.HasValue); + if (value.HasValue) + writer.WriteRay(value.Value); + } + public static void WriteMatrix4x4(this NetworkWriter writer, Matrix4x4 value) { writer.WriteFloat(value.m00); @@ -356,12 +502,26 @@ public static void WriteMatrix4x4(this NetworkWriter writer, Matrix4x4 value) writer.WriteFloat(value.m33); } + public static void WriteMatrix4x4Nullable(this NetworkWriter writer, Matrix4x4? value) + { + writer.WriteBool(value.HasValue); + if (value.HasValue) + writer.WriteMatrix4x4(value.Value); + } + public static void WriteGuid(this NetworkWriter writer, Guid value) { byte[] data = value.ToByteArray(); writer.WriteBytes(data, 0, data.Length); } + public static void WriteGuidNullable(this NetworkWriter writer, Guid? value) + { + writer.WriteBool(value.HasValue); + if (value.HasValue) + writer.WriteGuid(value.Value); + } + public static void WriteNetworkIdentity(this NetworkWriter writer, NetworkIdentity value) { if (value == null) @@ -421,11 +581,6 @@ public static void WriteGameObject(this NetworkWriter writer, GameObject value) } } - public static void WriteUri(this NetworkWriter writer, Uri uri) - { - writer.WriteString(uri?.ToString()); - } - public static void WriteList(this NetworkWriter writer, List list) { if (list is null) @@ -450,14 +605,9 @@ public static void WriteArray(this NetworkWriter writer, T[] array) writer.Write(array[i]); } - public static void WriteArraySegment(this NetworkWriter writer, ArraySegment segment) + public static void WriteUri(this NetworkWriter writer, Uri uri) { - int length = segment.Count; - writer.WriteInt(length); - for (int i = 0; i < length; i++) - { - writer.Write(segment.Array[segment.Offset + i]); - } + writer.WriteString(uri?.ToString()); } } }