您最多选择25个主题
主题必须以中文或者字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
539 行
22 KiB
539 行
22 KiB
using System;
|
|
using System.Runtime.CompilerServices;
|
|
using UnityEngine;
|
|
|
|
namespace Unity.Netcode
|
|
{
|
|
/// <summary>
|
|
/// Byte Unpacking Helper Class
|
|
/// Use this class to unpack values during deserialization for values that were packed.
|
|
/// <seealso cref="BytePacker"/> to pack unpacked values
|
|
/// </summary>
|
|
public static class ByteUnpacker
|
|
{
|
|
#if UNITY_NETCODE_DEBUG_NO_PACKING
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public void ReadValuePacked<T>(FastBufferReader reader, out T value) where T: unmanaged => reader.ReadValueSafe(out value);
|
|
#else
|
|
/// <summary>
|
|
/// Read a packed enum value
|
|
/// </summary>
|
|
/// <param name="reader">The reader to read from</param>
|
|
/// <param name="value">The value that's read</param>
|
|
/// <typeparam name="TEnum">Type of enum to read</typeparam>
|
|
/// <exception cref="InvalidOperationException">Throws InvalidOperationException if an enum somehow ends up not being the size of a byte, short, int, or long (which should be impossible)</exception>
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static unsafe void ReadValuePacked<TEnum>(FastBufferReader reader, out TEnum value) where TEnum : unmanaged, Enum
|
|
{
|
|
switch (sizeof(TEnum))
|
|
{
|
|
case sizeof(int):
|
|
ReadValuePacked(reader, out int asInt);
|
|
value = *(TEnum*)&asInt;
|
|
break;
|
|
case sizeof(byte):
|
|
ReadValuePacked(reader, out byte asByte);
|
|
value = *(TEnum*)&asByte;
|
|
break;
|
|
case sizeof(short):
|
|
ReadValuePacked(reader, out short asShort);
|
|
value = *(TEnum*)&asShort;
|
|
break;
|
|
case sizeof(long):
|
|
ReadValuePacked(reader, out long asLong);
|
|
value = *(TEnum*)&asLong;
|
|
break;
|
|
default:
|
|
throw new InvalidOperationException("Enum is a size that cannot exist?!");
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Read single-precision floating point value from the stream as a varint
|
|
/// </summary>
|
|
/// <param name="reader">The reader to read from</param>
|
|
/// <param name="value">Value to read</param>
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static void ReadValuePacked(FastBufferReader reader, out float value)
|
|
{
|
|
ReadValueBitPacked(reader, out uint asUInt);
|
|
value = ToSingle(asUInt);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Read double-precision floating point value from the stream as a varint
|
|
/// </summary>
|
|
/// <param name="reader">The reader to read from</param>
|
|
/// <param name="value">Value to read</param>
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static void ReadValuePacked(FastBufferReader reader, out double value)
|
|
{
|
|
ReadValueBitPacked(reader, out ulong asULong);
|
|
value = ToDouble(asULong);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Read a byte from the stream.
|
|
/// </summary>
|
|
/// <param name="reader">The reader to read from</param>
|
|
/// <param name="value">Value to read</param>
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static void ReadValuePacked(FastBufferReader reader, out byte value) => reader.ReadByteSafe(out value);
|
|
|
|
/// <summary>
|
|
/// Read a signed byte from the stream.
|
|
/// </summary>
|
|
/// <param name="reader">The reader to read from</param>
|
|
/// <param name="value">Value to read</param>
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static void ReadValuePacked(FastBufferReader reader, out sbyte value)
|
|
{
|
|
reader.ReadByteSafe(out byte byteVal);
|
|
value = (sbyte)byteVal;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Read a boolean from the stream.
|
|
/// </summary>
|
|
/// <param name="reader">The reader to read from</param>
|
|
/// <param name="value">Value to read</param>
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static void ReadValuePacked(FastBufferReader reader, out bool value) => reader.ReadValueSafe(out value);
|
|
|
|
|
|
/// <summary>
|
|
/// Read an usigned short (Int16) as a varint from the stream.
|
|
/// </summary>
|
|
/// <param name="reader">The reader to read from</param>
|
|
/// <param name="value">Value to read</param>
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static void ReadValuePacked(FastBufferReader reader, out short value) => ReadValueBitPacked(reader, out value);
|
|
|
|
/// <summary>
|
|
/// Read an unsigned short (UInt16) as a varint from the stream.
|
|
/// </summary>
|
|
/// <param name="reader">The reader to read from</param>
|
|
/// <param name="value">Value to read</param>
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static void ReadValuePacked(FastBufferReader reader, out ushort value) => ReadValueBitPacked(reader, out value);
|
|
|
|
/// <summary>
|
|
/// Read a two-byte character as a varint from the stream.
|
|
/// </summary>
|
|
/// <param name="reader">The reader to read from</param>
|
|
/// <param name="c">Value to read</param>
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static void ReadValuePacked(FastBufferReader reader, out char c)
|
|
{
|
|
ReadValueBitPacked(reader, out ushort readValue);
|
|
c = (char)readValue;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Read a signed int (Int32) as a ZigZag encoded varint from the stream.
|
|
/// </summary>
|
|
/// <param name="reader">The reader to read from</param>
|
|
/// <param name="value">Value to read</param>
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static void ReadValuePacked(FastBufferReader reader, out int value) => ReadValueBitPacked(reader, out value);
|
|
|
|
/// <summary>
|
|
/// Read an unsigned int (UInt32) from the stream.
|
|
/// </summary>
|
|
/// <param name="reader">The reader to read from</param>
|
|
/// <param name="value">Value to read</param>
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static void ReadValuePacked(FastBufferReader reader, out uint value) => ReadValueBitPacked(reader, out value);
|
|
|
|
/// <summary>
|
|
/// Read an unsigned long (UInt64) from the stream.
|
|
/// </summary>
|
|
/// <param name="reader">The reader to read from</param>
|
|
/// <param name="value">Value to read</param>
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static void ReadValuePacked(FastBufferReader reader, out ulong value) => ReadValueBitPacked(reader, out value);
|
|
|
|
/// <summary>
|
|
/// Read a signed long (Int64) as a ZigZag encoded varint from the stream.
|
|
/// </summary>
|
|
/// <param name="reader">The reader to read from</param>
|
|
/// <param name="value">Value to read</param>
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static void ReadValuePacked(FastBufferReader reader, out long value)
|
|
{
|
|
ReadValueBitPacked(reader, out value);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Convenience method that reads two packed Vector3 from the ray from the stream
|
|
/// </summary>
|
|
/// <param name="reader">The reader to read from</param>
|
|
/// <param name="ray">Ray to read</param>
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static void ReadValuePacked(FastBufferReader reader, out Ray ray)
|
|
{
|
|
ReadValuePacked(reader, out Vector3 origin);
|
|
ReadValuePacked(reader, out Vector3 direction);
|
|
ray = new Ray(origin, direction);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Convenience method that reads two packed Vector2 from the ray from the stream
|
|
/// </summary>
|
|
/// <param name="reader">The reader to read from</param>
|
|
/// <param name="ray2d">Ray2D to read</param>
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static void ReadValuePacked(FastBufferReader reader, out Ray2D ray2d)
|
|
{
|
|
ReadValuePacked(reader, out Vector2 origin);
|
|
ReadValuePacked(reader, out Vector2 direction);
|
|
ray2d = new Ray2D(origin, direction);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Convenience method that reads four varint floats from the color from the stream
|
|
/// </summary>
|
|
/// <param name="reader">The reader to read from</param>
|
|
/// <param name="color">Color to read</param>
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static void ReadValuePacked(FastBufferReader reader, out Color color)
|
|
{
|
|
color = new Color();
|
|
ReadValuePacked(reader, out color.r);
|
|
ReadValuePacked(reader, out color.g);
|
|
ReadValuePacked(reader, out color.b);
|
|
ReadValuePacked(reader, out color.a);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Convenience method that reads four varint floats from the color from the stream
|
|
/// </summary>
|
|
/// <param name="reader">The reader to read from</param>
|
|
/// <param name="color">Color to read</param>
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static void ReadValuePacked(FastBufferReader reader, out Color32 color)
|
|
{
|
|
color = new Color32();
|
|
ReadValuePacked(reader, out color.r);
|
|
ReadValuePacked(reader, out color.g);
|
|
ReadValuePacked(reader, out color.b);
|
|
ReadValuePacked(reader, out color.a);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Convenience method that reads two varint floats from the vector from the stream
|
|
/// </summary>
|
|
/// <param name="reader">The reader to read from</param>
|
|
/// <param name="vector2">Vector to read</param>
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static void ReadValuePacked(FastBufferReader reader, out Vector2 vector2)
|
|
{
|
|
vector2 = new Vector2();
|
|
ReadValuePacked(reader, out vector2.x);
|
|
ReadValuePacked(reader, out vector2.y);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Convenience method that reads three varint floats from the vector from the stream
|
|
/// </summary>
|
|
/// <param name="reader">The reader to read from</param>
|
|
/// <param name="vector3">Vector to read</param>
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static void ReadValuePacked(FastBufferReader reader, out Vector3 vector3)
|
|
{
|
|
vector3 = new Vector3();
|
|
ReadValuePacked(reader, out vector3.x);
|
|
ReadValuePacked(reader, out vector3.y);
|
|
ReadValuePacked(reader, out vector3.z);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Convenience method that reads four varint floats from the vector from the stream
|
|
/// </summary>
|
|
/// <param name="reader">The reader to read from</param>
|
|
/// <param name="vector4">Vector to read</param>
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static void ReadValuePacked(FastBufferReader reader, out Vector4 vector4)
|
|
{
|
|
vector4 = new Vector4();
|
|
ReadValuePacked(reader, out vector4.x);
|
|
ReadValuePacked(reader, out vector4.y);
|
|
ReadValuePacked(reader, out vector4.z);
|
|
ReadValuePacked(reader, out vector4.w);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Reads the rotation from the stream.
|
|
/// </summary>
|
|
/// <param name="reader">The reader to read from</param>
|
|
/// <param name="rotation">Rotation to read</param>
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static void ReadValuePacked(FastBufferReader reader, out Quaternion rotation)
|
|
{
|
|
rotation = new Quaternion();
|
|
ReadValuePacked(reader, out rotation.x);
|
|
ReadValuePacked(reader, out rotation.y);
|
|
ReadValuePacked(reader, out rotation.z);
|
|
ReadValuePacked(reader, out rotation.w);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Reads a string in a packed format
|
|
/// </summary>
|
|
/// <param name="reader">The reader to read from</param>
|
|
/// <param name="s"></param>
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static unsafe void ReadValuePacked(FastBufferReader reader, out string s)
|
|
{
|
|
ReadValuePacked(reader, out uint length);
|
|
s = "".PadRight((int)length);
|
|
int target = s.Length;
|
|
fixed (char* c = s)
|
|
{
|
|
for (int i = 0; i < target; ++i)
|
|
{
|
|
ReadValuePacked(reader, out c[i]);
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#if UNITY_NETCODE_DEBUG_NO_PACKING
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public void ReadValueBitPacked<T>(FastBufferReader reader, T value) where T: unmanaged => reader.ReadValueSafe(out value);
|
|
#else
|
|
/// <summary>
|
|
/// Read a bit-packed 14-bit signed short from the stream.
|
|
/// See BytePacker.cs for a description of the format.
|
|
/// </summary>
|
|
/// <param name="reader">The reader to read from</param>
|
|
/// <param name="value">The value to read</param>
|
|
public static void ReadValueBitPacked(FastBufferReader reader, out short value)
|
|
{
|
|
ReadValueBitPacked(reader, out ushort readValue);
|
|
value = (short)Arithmetic.ZigZagDecode(readValue);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Read a bit-packed 15-bit unsigned short from the stream.
|
|
/// See BytePacker.cs for a description of the format.
|
|
/// </summary>
|
|
/// <param name="reader">The reader to read from</param>
|
|
/// <param name="value">The value to read</param>
|
|
public static unsafe void ReadValueBitPacked(FastBufferReader reader, out ushort value)
|
|
{
|
|
ushort returnValue = 0;
|
|
byte* ptr = ((byte*)&returnValue);
|
|
byte* data = reader.GetUnsafePtrAtCurrentPosition();
|
|
// Mask out the first two bits - they contain the total byte count
|
|
// (1, 2, or 3)
|
|
int numBytes = (data[0] & 0b11);
|
|
if (!reader.TryBeginReadInternal(numBytes))
|
|
{
|
|
throw new OverflowException("Reading past the end of the buffer");
|
|
}
|
|
reader.MarkBytesRead(numBytes);
|
|
switch (numBytes)
|
|
{
|
|
case 1:
|
|
ptr[0] = data[0];
|
|
break;
|
|
case 2:
|
|
ptr[0] = data[0];
|
|
ptr[1] = data[1];
|
|
break;
|
|
case 3:
|
|
// First byte contains no data, it's just a marker. The data is in the remaining two bytes.
|
|
ptr[0] = data[1];
|
|
ptr[1] = data[2];
|
|
value = returnValue;
|
|
return;
|
|
default:
|
|
throw new InvalidOperationException("Could not read bit-packed value: impossible byte count");
|
|
}
|
|
|
|
value = (ushort)(returnValue >> 2);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Read a bit-packed 29-bit signed int from the stream.
|
|
/// See BytePacker.cs for a description of the format.
|
|
/// </summary>
|
|
/// <param name="reader">The reader to read from</param>
|
|
/// <param name="value">The value to read</param>
|
|
public static void ReadValueBitPacked(FastBufferReader reader, out int value)
|
|
{
|
|
ReadValueBitPacked(reader, out uint readValue);
|
|
value = (int)Arithmetic.ZigZagDecode(readValue);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Read a bit-packed 30-bit unsigned int from the stream.
|
|
/// See BytePacker.cs for a description of the format.
|
|
/// </summary>
|
|
/// <param name="reader">The reader to read from</param>
|
|
/// <param name="value">The value to read</param>
|
|
public static unsafe void ReadValueBitPacked(FastBufferReader reader, out uint value)
|
|
{
|
|
uint returnValue = 0;
|
|
byte* ptr = ((byte*)&returnValue);
|
|
byte* data = reader.GetUnsafePtrAtCurrentPosition();
|
|
// Mask out the first three bits - they contain the total byte count (1-5)
|
|
int numBytes = (data[0] & 0b111);
|
|
if (!reader.TryBeginReadInternal(numBytes))
|
|
{
|
|
throw new OverflowException("Reading past the end of the buffer");
|
|
}
|
|
reader.MarkBytesRead(numBytes);
|
|
switch (numBytes)
|
|
{
|
|
case 1:
|
|
ptr[0] = data[0];
|
|
break;
|
|
case 2:
|
|
ptr[0] = data[0];
|
|
ptr[1] = data[1];
|
|
break;
|
|
case 3:
|
|
ptr[0] = data[0];
|
|
ptr[1] = data[1];
|
|
ptr[2] = data[2];
|
|
break;
|
|
case 4:
|
|
ptr[0] = data[0];
|
|
ptr[1] = data[1];
|
|
ptr[2] = data[2];
|
|
ptr[3] = data[3];
|
|
break;
|
|
case 5:
|
|
// First byte contains no data, it's just a marker. The data is in the remaining two bytes.
|
|
ptr[0] = data[1];
|
|
ptr[1] = data[2];
|
|
ptr[2] = data[3];
|
|
ptr[3] = data[4];
|
|
value = returnValue;
|
|
return;
|
|
}
|
|
|
|
value = returnValue >> 3;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Read a bit-packed 60-bit signed long from the stream.
|
|
/// See BytePacker.cs for a description of the format.
|
|
/// </summary>
|
|
/// <param name="reader">The reader to read from</param>
|
|
/// <param name="value">The value to read</param>
|
|
public static void ReadValueBitPacked(FastBufferReader reader, out long value)
|
|
{
|
|
ReadValueBitPacked(reader, out ulong readValue);
|
|
value = Arithmetic.ZigZagDecode(readValue);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Read a bit-packed 61-bit signed long from the stream.
|
|
/// See BytePacker.cs for a description of the format.
|
|
/// </summary>
|
|
/// <param name="reader">The reader to read from</param>
|
|
/// <param name="value">The value to read</param>
|
|
public static unsafe void ReadValueBitPacked(FastBufferReader reader, out ulong value)
|
|
{
|
|
ulong returnValue = 0;
|
|
byte* ptr = ((byte*)&returnValue);
|
|
byte* data = reader.GetUnsafePtrAtCurrentPosition();
|
|
// Mask out the first four bits - they contain the total byte count (1-9)
|
|
int numBytes = (data[0] & 0b1111);
|
|
if (!reader.TryBeginReadInternal(numBytes))
|
|
{
|
|
throw new OverflowException("Reading past the end of the buffer");
|
|
}
|
|
reader.MarkBytesRead(numBytes);
|
|
switch (numBytes)
|
|
{
|
|
case 1:
|
|
ptr[0] = data[0];
|
|
break;
|
|
case 2:
|
|
ptr[0] = data[0];
|
|
ptr[1] = data[1];
|
|
break;
|
|
case 3:
|
|
ptr[0] = data[0];
|
|
ptr[1] = data[1];
|
|
ptr[2] = data[2];
|
|
break;
|
|
case 4:
|
|
ptr[0] = data[0];
|
|
ptr[1] = data[1];
|
|
ptr[2] = data[2];
|
|
ptr[3] = data[3];
|
|
break;
|
|
case 5:
|
|
ptr[0] = data[0];
|
|
ptr[1] = data[1];
|
|
ptr[2] = data[2];
|
|
ptr[3] = data[3];
|
|
ptr[4] = data[4];
|
|
break;
|
|
case 6:
|
|
ptr[0] = data[0];
|
|
ptr[1] = data[1];
|
|
ptr[2] = data[2];
|
|
ptr[3] = data[3];
|
|
ptr[4] = data[4];
|
|
ptr[5] = data[5];
|
|
break;
|
|
case 7:
|
|
ptr[0] = data[0];
|
|
ptr[1] = data[1];
|
|
ptr[2] = data[2];
|
|
ptr[3] = data[3];
|
|
ptr[4] = data[4];
|
|
ptr[5] = data[5];
|
|
ptr[6] = data[6];
|
|
break;
|
|
case 8:
|
|
ptr[0] = data[0];
|
|
ptr[1] = data[1];
|
|
ptr[2] = data[2];
|
|
ptr[3] = data[3];
|
|
ptr[4] = data[4];
|
|
ptr[5] = data[5];
|
|
ptr[6] = data[6];
|
|
ptr[7] = data[7];
|
|
break;
|
|
case 9:
|
|
// First byte contains no data, it's just a marker. The data is in the remaining two bytes.
|
|
ptr[0] = data[1];
|
|
ptr[1] = data[2];
|
|
ptr[2] = data[3];
|
|
ptr[3] = data[4];
|
|
ptr[4] = data[5];
|
|
ptr[5] = data[6];
|
|
ptr[6] = data[7];
|
|
ptr[7] = data[8];
|
|
value = returnValue;
|
|
return;
|
|
}
|
|
|
|
value = returnValue >> 4;
|
|
}
|
|
#endif
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
private static unsafe float ToSingle<T>(T value) where T : unmanaged
|
|
{
|
|
float* asFloat = (float*)&value;
|
|
return *asFloat;
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
private static unsafe double ToDouble<T>(T value) where T : unmanaged
|
|
{
|
|
double* asDouble = (double*)&value;
|
|
return *asDouble;
|
|
}
|
|
}
|
|
}
|