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
This commit is contained in:
MrGadget 2021-11-27 04:31:16 -05:00 committed by GitHub
parent 8b363d11e9
commit 52111d1cb8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 241 additions and 55 deletions

View File

@ -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;
/// <exception cref="T:System.ArgumentException">if an invalid utf8 string is sent</exception>
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;
}
/// <exception cref="T:OverflowException">if count is invalid</exception>
public static ArraySegment<byte> ReadBytesAndSizeSegment(this NetworkReader reader)
{
@ -234,24 +259,38 @@ public static ArraySegment<byte> 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<T> ReadList<T>(this NetworkReader reader)
{
int length = reader.ReadInt();

View File

@ -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<byte> 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<T>(this NetworkWriter writer, ArraySegment<T> segment)
{
// buffer might be null, so we can't use .Length in that case
writer.WriteBytesAndSize(buffer, 0, buffer != null ? buffer.Length : 0);
int length = segment.Count;
writer.WriteInt(length);
for (int i = 0; i < length; i++)
{
writer.Write(segment.Array[segment.Offset + i]);
}
public static void WriteBytesAndSizeSegment(this NetworkWriter writer, ArraySegment<byte> buffer)
{
writer.WriteBytesAndSize(buffer.Array, buffer.Offset, buffer.Count);
}
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);
@ -276,7 +404,6 @@ public static void WriteColor(this NetworkWriter writer, Color value)
writer.WriteFloat(value.a);
}
// TODO add nullable support to weaver instead
public static void WriteColorNullable(this NetworkWriter writer, Color? value)
{
writer.WriteBool(value.HasValue);
@ -292,7 +419,6 @@ public static void WriteColor32(this NetworkWriter writer, Color32 value)
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<T>(this NetworkWriter writer, List<T> list)
{
if (list is null)
@ -450,14 +605,9 @@ public static void WriteArray<T>(this NetworkWriter writer, T[] array)
writer.Write(array[i]);
}
public static void WriteArraySegment<T>(this NetworkWriter writer, ArraySegment<T> 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());
}
}
}