com.unity.netcode.gameobjects@1.2.0

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

Additional documentation and release notes are available at [Multiplayer Documentation](https://docs-multiplayer.unity3d.com).

## [1.2.0] - 2022-11-21

### Added

- Added protected method `NetworkBehaviour.OnSynchronize` which is invoked during the initial `NetworkObject` synchronization process. This provides users the ability to include custom serialization information that will be applied to the `NetworkBehaviour` prior to the `NetworkObject` being spawned. (#2298)
- Added support for different versions of the SDK to talk to each other in circumstances where changes permit it. Starting with this version and into future versions, patch versions should be compatible as long as the minor version is the same. (#2290)
- Added `NetworkObject` auto-add helper and Multiplayer Tools install reminder settings to Project Settings. (#2285)
- Added `public string DisconnectReason` getter to `NetworkManager` and `string Reason` to `ConnectionApprovalResponse`. Allows connection approval to communicate back a reason. Also added `public void DisconnectClient(ulong clientId, string reason)` allowing setting a disconnection reason, when explicitly disconnecting a client. (#2280)

### Changed

- Changed 3rd-party `XXHash` (32 & 64) implementation with an in-house reimplementation (#2310)
- When `NetworkConfig.EnsureNetworkVariableLengthSafety` is disabled `NetworkVariable` fields do not write the additional `ushort` size value (_which helps to reduce the total synchronization message size_), but when enabled it still writes the additional `ushort` value. (#2298)
- Optimized bandwidth usage by encoding most integer fields using variable-length encoding. (#2276)

### Fixed

- Fixed issue where `NetworkTransform` components nested under a parent with a `NetworkObject` component  (i.e. network prefab) would not have their associated `GameObject`'s transform synchronized. (#2298)
- Fixed issue where `NetworkObject`s that failed to instantiate could cause the entire synchronization pipeline to be disrupted/halted for a connecting client. (#2298)
- Fixed issue where in-scene placed `NetworkObject`s nested under a `GameObject` would be added to the orphaned children list causing continual console warning log messages. (#2298)
- Custom messages are now properly received by the local client when they're sent while running in host mode. (#2296)
- Fixed issue where the host would receive more than one event completed notification when loading or unloading a scene only when no clients were connected. (#2292)
- Fixed an issue in `UnityTransport` where an error would be logged if the 'Use Encryption' flag was enabled with a Relay configuration that used a secure protocol. (#2289)
- Fixed issue where in-scene placed `NetworkObjects` were not honoring the `AutoObjectParentSync` property. (#2281)
- Fixed the issue where `NetworkManager.OnClientConnectedCallback` was being invoked before in-scene placed `NetworkObject`s had been spawned when starting `NetworkManager` as a host. (#2277)
- Creating a `FastBufferReader` with `Allocator.None` will not result in extra memory being allocated for the buffer (since it's owned externally in that scenario). (#2265)

### Removed

- Removed the `NetworkObject` auto-add and Multiplayer Tools install reminder settings from the Menu interface. (#2285)
This commit is contained in:
Unity Technologies
2022-11-21 00:00:00 +00:00
parent 1e7078c160
commit fe02ca682e
96 changed files with 4522 additions and 2088 deletions

View File

@@ -50,7 +50,7 @@ namespace Unity.Netcode
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void WriteValuePacked(FastBufferWriter writer, float value)
{
WriteUInt32Packed(writer, ToUint(value));
WriteValueBitPacked(writer, ToUint(value));
}
/// <summary>
@@ -61,7 +61,7 @@ namespace Unity.Netcode
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void WriteValuePacked(FastBufferWriter writer, double value)
{
WriteUInt64Packed(writer, ToUlong(value));
WriteValueBitPacked(writer, ToUlong(value));
}
/// <summary>
@@ -98,7 +98,7 @@ namespace Unity.Netcode
/// <param name="writer">The writer to write to</param>
/// <param name="value">Value to write</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void WriteValuePacked(FastBufferWriter writer, short value) => WriteUInt32Packed(writer, (ushort)Arithmetic.ZigZagEncode(value));
public static void WriteValuePacked(FastBufferWriter writer, short value) => WriteValueBitPacked(writer, value);
/// <summary>
/// Write an unsigned short (UInt16) as a varint to the buffer.
@@ -109,7 +109,7 @@ namespace Unity.Netcode
/// <param name="writer">The writer to write to</param>
/// <param name="value">Value to write</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void WriteValuePacked(FastBufferWriter writer, ushort value) => WriteUInt32Packed(writer, value);
public static void WriteValuePacked(FastBufferWriter writer, ushort value) => WriteValueBitPacked(writer, value);
/// <summary>
/// Write a two-byte character as a varint to the buffer.
@@ -120,7 +120,7 @@ namespace Unity.Netcode
/// <param name="writer">The writer to write to</param>
/// <param name="c">Value to write</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void WriteValuePacked(FastBufferWriter writer, char c) => WriteUInt32Packed(writer, c);
public static void WriteValuePacked(FastBufferWriter writer, char c) => WriteValueBitPacked(writer, c);
/// <summary>
/// Write a signed int (Int32) as a ZigZag encoded varint to the buffer.
@@ -128,7 +128,7 @@ namespace Unity.Netcode
/// <param name="writer">The writer to write to</param>
/// <param name="value">Value to write</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void WriteValuePacked(FastBufferWriter writer, int value) => WriteUInt32Packed(writer, (uint)Arithmetic.ZigZagEncode(value));
public static void WriteValuePacked(FastBufferWriter writer, int value) => WriteValueBitPacked(writer, value);
/// <summary>
/// Write an unsigned int (UInt32) to the buffer.
@@ -136,7 +136,7 @@ namespace Unity.Netcode
/// <param name="writer">The writer to write to</param>
/// <param name="value">Value to write</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void WriteValuePacked(FastBufferWriter writer, uint value) => WriteUInt32Packed(writer, value);
public static void WriteValuePacked(FastBufferWriter writer, uint value) => WriteValueBitPacked(writer, value);
/// <summary>
/// Write an unsigned long (UInt64) to the buffer.
@@ -144,7 +144,7 @@ namespace Unity.Netcode
/// <param name="writer">The writer to write to</param>
/// <param name="value">Value to write</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void WriteValuePacked(FastBufferWriter writer, ulong value) => WriteUInt64Packed(writer, value);
public static void WriteValuePacked(FastBufferWriter writer, ulong value) => WriteValueBitPacked(writer, value);
/// <summary>
/// Write a signed long (Int64) as a ZigZag encoded varint to the buffer.
@@ -152,7 +152,7 @@ namespace Unity.Netcode
/// <param name="writer">The writer to write to</param>
/// <param name="value">Value to write</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void WriteValuePacked(FastBufferWriter writer, long value) => WriteUInt64Packed(writer, Arithmetic.ZigZagEncode(value));
public static void WriteValuePacked(FastBufferWriter writer, long value) => WriteValueBitPacked(writer, value);
/// <summary>
/// Convenience method that writes two packed Vector3 from the ray to the buffer
@@ -282,231 +282,183 @@ namespace Unity.Netcode
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void WriteValueBitPacked<T>(FastBufferWriter writer, T value) where T: unmanaged => writer.WriteValueSafe(value);
#else
/// <summary>
/// Maximum serializable value for a BitPacked ushort (minimum for unsigned is 0)
/// Obsolete value that no longer carries meaning. Do not use.
/// </summary>
public const ushort BitPackedUshortMax = (1 << 15) - 1;
/// <summary>
/// Maximum serializable value for a BitPacked short
/// Obsolete value that no longer carries meaning. Do not use.
/// </summary>
public const short BitPackedShortMax = (1 << 14) - 1;
/// <summary>
/// Minimum serializable value size for a BitPacked ushort
/// Obsolete value that no longer carries meaning. Do not use.
/// </summary>
public const short BitPackedShortMin = -(1 << 14);
/// <summary>
/// Maximum serializable value for a BitPacked uint (minimum for unsigned is 0)
/// Obsolete value that no longer carries meaning. Do not use.
/// </summary>
public const uint BitPackedUintMax = (1 << 30) - 1;
/// <summary>
/// Maximum serializable value for a BitPacked int
/// Obsolete value that no longer carries meaning. Do not use.
/// </summary>
public const int BitPackedIntMax = (1 << 29) - 1;
/// <summary>
/// Minimum serializable value size for a BitPacked int
/// Obsolete value that no longer carries meaning. Do not use.
/// </summary>
public const int BitPackedIntMin = -(1 << 29);
/// <summary>
/// Maximum serializable value for a BitPacked ulong (minimum for unsigned is 0)
/// Obsolete value that no longer carries meaning. Do not use.
/// </summary>
public const ulong BitPackedULongMax = (1L << 61) - 1;
/// <summary>
/// Maximum serializable value for a BitPacked long
/// Obsolete value that no longer carries meaning. Do not use.
/// </summary>
public const long BitPackedLongMax = (1L << 60) - 1;
/// <summary>
/// Minimum serializable value size for a BitPacked long
/// Obsolete value that no longer carries meaning. Do not use.
/// </summary>
public const long BitPackedLongMin = -(1L << 60);
/// <summary>
/// Writes a 14-bit signed short to the buffer in a bit-encoded packed format.
/// The first bit indicates whether the value is 1 byte or 2.
/// The sign bit takes up another bit.
/// That leaves 14 bits for the value.
/// A value greater than 2^14-1 or less than -2^14 will throw an exception in editor and development builds.
/// In release builds builds the exception is not thrown and the value is truncated by losing its two
/// most significant bits after zig-zag encoding.
/// Writes a 16-bit signed short to the buffer in a bit-encoded packed format.
/// Zig-zag encoding is used to move the sign bit to the least significant bit, so that negative values
/// are still able to be compressed.
/// The first two bits indicate whether the value is 1, 2, or 3 bytes.
/// If the value uses 14 bits or less, the remaining 14 bits contain the value.
/// For performance, reasons, if the value is 15 bits or more, there will be six 0 bits, followed
/// by the original unmodified 16-bit value in the next 2 bytes.
/// </summary>
/// <param name="writer">The writer to write to</param>
/// <param name="value">The value to pack</param>
public static void WriteValueBitPacked(FastBufferWriter writer, short value) => WriteValueBitPacked(writer, (ushort)Arithmetic.ZigZagEncode(value));
/// <summary>
/// Writes a 15-bit unsigned short to the buffer in a bit-encoded packed format.
/// The first bit indicates whether the value is 1 byte or 2.
/// That leaves 15 bits for the value.
/// A value greater than 2^15-1 will throw an exception in editor and development builds.
/// In release builds builds the exception is not thrown and the value is truncated by losing its
/// most significant bit.
/// Writes a 16-bit unsigned short to the buffer in a bit-encoded packed format.
/// The first two bits indicate whether the value is 1, 2, or 3 bytes.
/// If the value uses 14 bits or less, the remaining 14 bits contain the value.
/// For performance, reasons, if the value is 15 bits or more, there will be six 0 bits, followed
/// by the original unmodified 16-bit value in the next 2 bytes.
/// </summary>
/// <param name="writer">The writer to write to</param>
/// <param name="value">The value to pack</param>
public static void WriteValueBitPacked(FastBufferWriter writer, ushort value)
{
#if DEVELOPMENT_BUILD || UNITY_EDITOR
if (value >= BitPackedUshortMax)
if (value > (1 << 14) - 1)
{
throw new ArgumentException("BitPacked ushorts must be <= 15 bits");
}
#endif
if (value <= 0b0111_1111)
{
if (!writer.TryBeginWriteInternal(1))
if (!writer.TryBeginWriteInternal(3))
{
throw new OverflowException("Writing past the end of the buffer");
}
writer.WriteByte((byte)(value << 1));
writer.WriteByte(3);
writer.WriteValue(value);
return;
}
if (!writer.TryBeginWriteInternal(2))
{
throw new OverflowException("Writing past the end of the buffer");
}
writer.WriteValue((ushort)((value << 1) | 0b1));
}
/// <summary>
/// Writes a 29-bit signed int to the buffer in a bit-encoded packed format.
/// The first two bits indicate whether the value is 1, 2, 3, or 4 bytes.
/// The sign bit takes up another bit.
/// That leaves 29 bits for the value.
/// A value greater than 2^29-1 or less than -2^29 will throw an exception in editor and development builds.
/// In release builds builds the exception is not thrown and the value is truncated by losing its three
/// most significant bits after zig-zag encoding.
/// </summary>
/// <param name="writer">The writer to write to</param>
/// <param name="value">The value to pack</param>
public static void WriteValueBitPacked(FastBufferWriter writer, int value) => WriteValueBitPacked(writer, (uint)Arithmetic.ZigZagEncode(value));
/// <summary>
/// Writes a 30-bit unsigned int to the buffer in a bit-encoded packed format.
/// The first two bits indicate whether the value is 1, 2, 3, or 4 bytes.
/// That leaves 30 bits for the value.
/// A value greater than 2^30-1 will throw an exception in editor and development builds.
/// In release builds builds the exception is not thrown and the value is truncated by losing its two
/// most significant bits.
/// </summary>
/// <param name="writer">The writer to write to</param>
/// <param name="value">The value to pack</param>
public static void WriteValueBitPacked(FastBufferWriter writer, uint value)
{
#if DEVELOPMENT_BUILD || UNITY_EDITOR
if (value > BitPackedUintMax)
{
throw new ArgumentException("BitPacked uints must be <= 30 bits");
}
#endif
value <<= 2;
var numBytes = BitCounter.GetUsedByteCount(value);
if (!writer.TryBeginWriteInternal(numBytes))
{
throw new OverflowException("Writing past the end of the buffer");
}
writer.WritePartialValue(value | (uint)(numBytes - 1), numBytes);
writer.WritePartialValue(value | (ushort)(numBytes), numBytes);
}
/// <summary>
/// Writes a 60-bit signed long to the buffer in a bit-encoded packed format.
/// The first three bits indicate whether the value is 1, 2, 3, 4, 5, 6, 7, or 8 bytes.
/// The sign bit takes up another bit.
/// That leaves 60 bits for the value.
/// A value greater than 2^60-1 or less than -2^60 will throw an exception in editor and development builds.
/// In release builds builds the exception is not thrown and the value is truncated by losing its four
/// most significant bits after zig-zag encoding.
/// Writes a 32-bit signed int to the buffer in a bit-encoded packed format.
/// Zig-zag encoding is used to move the sign bit to the least significant bit, so that negative values
/// are still able to be compressed.
/// The first three bits indicate whether the value is 1, 2, 3, 4, or 5 bytes.
/// If the value uses 29 bits or less, the remaining 29 bits contain the value.
/// For performance, reasons, if the value is 30 bits or more, there will be five 0 bits, followed
/// by the original unmodified 32-bit value in the next 4 bytes.
/// </summary>
/// <param name="writer">The writer to write to</param>
/// <param name="value">The value to pack</param>
public static void WriteValueBitPacked(FastBufferWriter writer, long value) => WriteValueBitPacked(writer, Arithmetic.ZigZagEncode(value));
public static void WriteValueBitPacked(FastBufferWriter writer, int value) => WriteValueBitPacked(writer, (uint)Arithmetic.ZigZagEncode(value));
/// <summary>
/// Writes a 61-bit unsigned long to the buffer in a bit-encoded packed format.
/// The first three bits indicate whether the value is 1, 2, 3, 4, 5, 6, 7, or 8 bytes.
/// That leaves 31 bits for the value.
/// A value greater than 2^61-1 will throw an exception in editor and development builds.
/// In release builds builds the exception is not thrown and the value is truncated by losing its three
/// most significant bits.
/// Writes a 32-bit unsigned int to the buffer in a bit-encoded packed format.
/// The first three bits indicate whether the value is 1, 2, 3, 4, or 5 bytes.
/// If the value uses 29 bits or less, the remaining 29 bits contain the value.
/// For performance, reasons, if the value is 30 bits or more, there will be five 0 bits, followed
/// by the original unmodified 32-bit value in the next 4 bytes.
/// </summary>
/// <param name="writer">The writer to write to</param>
/// <param name="value">The value to pack</param>
public static void WriteValueBitPacked(FastBufferWriter writer, ulong value)
public static void WriteValueBitPacked(FastBufferWriter writer, uint value)
{
#if DEVELOPMENT_BUILD || UNITY_EDITOR
if (value > BitPackedULongMax)
if (value > (1 << 29) - 1)
{
throw new ArgumentException("BitPacked ulongs must be <= 61 bits");
if (!writer.TryBeginWriteInternal(5))
{
throw new OverflowException("Writing past the end of the buffer");
}
writer.WriteByte(5);
writer.WriteValue(value);
return;
}
#endif
value <<= 3;
var numBytes = BitCounter.GetUsedByteCount(value);
if (!writer.TryBeginWriteInternal(numBytes))
{
throw new OverflowException("Writing past the end of the buffer");
}
writer.WritePartialValue(value | (uint)(numBytes - 1), numBytes);
writer.WritePartialValue(value | (uint)(numBytes), numBytes);
}
/// <summary>
/// Writes a 64-bit signed long to the buffer in a bit-encoded packed format.
/// Zig-zag encoding is used to move the sign bit to the least significant bit, so that negative values
/// are still able to be compressed.
/// The first four bits indicate whether the value is 1, 2, 3, 4, 5, 6, 7, 8, or 9 bytes.
/// If the value uses 60 bits or less, the remaining 60 bits contain the value.
/// For performance, reasons, if the value is 61 bits or more, there will be four 0 bits, followed
/// by the original unmodified 64-bit value in the next 8 bytes.
/// </summary>
/// <param name="writer">The writer to write to</param>
/// <param name="value">The value to pack</param>
public static void WriteValueBitPacked(FastBufferWriter writer, long value) => WriteValueBitPacked(writer, Arithmetic.ZigZagEncode(value));
/// <summary>
/// Writes a 64-bit unsigned long to the buffer in a bit-encoded packed format.
/// The first four bits indicate whether the value is 1, 2, 3, 4, 5, 6, 7, 8, or 9 bytes.
/// If the value uses 60 bits or less, the remaining 60 bits contain the value.
/// For performance, reasons, if the value is 61 bits or more, there will be four 0 bits, followed
/// by the original unmodified 64-bit value in the next 8 bytes.
/// </summary>
/// <param name="writer">The writer to write to</param>
/// <param name="value">The value to pack</param>
public static void WriteValueBitPacked(FastBufferWriter writer, ulong value)
{
if (value > (1L << 60) - 1)
{
if (!writer.TryBeginWriteInternal(9))
{
throw new OverflowException("Writing past the end of the buffer");
}
writer.WriteByte(9);
writer.WriteValue(value);
return;
}
value <<= 4;
var numBytes = BitCounter.GetUsedByteCount(value);
if (!writer.TryBeginWriteInternal(numBytes))
{
throw new OverflowException("Writing past the end of the buffer");
}
writer.WritePartialValue(value | (uint)(numBytes), numBytes);
}
#endif
private static void WriteUInt64Packed(FastBufferWriter writer, ulong value)
{
if (value <= 240)
{
writer.WriteByteSafe((byte)value);
return;
}
if (value <= 2287)
{
writer.WriteByteSafe((byte)(((value - 240) >> 8) + 241));
writer.WriteByteSafe((byte)(value - 240));
return;
}
var writeBytes = BitCounter.GetUsedByteCount(value);
if (!writer.TryBeginWriteInternal(writeBytes + 1))
{
throw new OverflowException("Writing past the end of the buffer");
}
writer.WriteByte((byte)(247 + writeBytes));
writer.WritePartialValue(value, writeBytes);
}
// Looks like the same code as WriteUInt64Packed?
// It's actually different because it will call the more efficient 32-bit version
// of BytewiseUtility.GetUsedByteCount().
private static void WriteUInt32Packed(FastBufferWriter writer, uint value)
{
if (value <= 240)
{
writer.WriteByteSafe((byte)value);
return;
}
if (value <= 2287)
{
writer.WriteByteSafe((byte)(((value - 240) >> 8) + 241));
writer.WriteByteSafe((byte)(value - 240));
return;
}
var writeBytes = BitCounter.GetUsedByteCount(value);
if (!writer.TryBeginWriteInternal(writeBytes + 1))
{
throw new OverflowException("Writing past the end of the buffer");
}
writer.WriteByte((byte)(247 + writeBytes));
writer.WritePartialValue(value, writeBytes);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static unsafe uint ToUint<T>(T value) where T : unmanaged
{

View File

@@ -11,7 +11,6 @@ namespace Unity.Netcode
/// </summary>
public static class ByteUnpacker
{
#if UNITY_NETCODE_DEBUG_NO_PACKING
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -58,7 +57,7 @@ namespace Unity.Netcode
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void ReadValuePacked(FastBufferReader reader, out float value)
{
ReadUInt32Packed(reader, out uint asUInt);
ReadValueBitPacked(reader, out uint asUInt);
value = ToSingle(asUInt);
}
@@ -70,7 +69,7 @@ namespace Unity.Netcode
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void ReadValuePacked(FastBufferReader reader, out double value)
{
ReadUInt64Packed(reader, out ulong asULong);
ReadValueBitPacked(reader, out ulong asULong);
value = ToDouble(asULong);
}
@@ -109,11 +108,7 @@ namespace Unity.Netcode
/// <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)
{
ReadUInt32Packed(reader, out uint readValue);
value = (short)Arithmetic.ZigZagDecode(readValue);
}
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.
@@ -121,11 +116,7 @@ namespace Unity.Netcode
/// <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)
{
ReadUInt32Packed(reader, out uint readValue);
value = (ushort)readValue;
}
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.
@@ -135,7 +126,7 @@ namespace Unity.Netcode
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void ReadValuePacked(FastBufferReader reader, out char c)
{
ReadUInt32Packed(reader, out uint readValue);
ReadValueBitPacked(reader, out ushort readValue);
c = (char)readValue;
}
@@ -145,11 +136,7 @@ namespace Unity.Netcode
/// <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)
{
ReadUInt32Packed(reader, out uint readValue);
value = (int)Arithmetic.ZigZagDecode(readValue);
}
public static void ReadValuePacked(FastBufferReader reader, out int value) => ReadValueBitPacked(reader, out value);
/// <summary>
/// Read an unsigned int (UInt32) from the stream.
@@ -157,7 +144,7 @@ namespace Unity.Netcode
/// <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) => ReadUInt32Packed(reader, out value);
public static void ReadValuePacked(FastBufferReader reader, out uint value) => ReadValueBitPacked(reader, out value);
/// <summary>
/// Read an unsigned long (UInt64) from the stream.
@@ -165,7 +152,7 @@ namespace Unity.Netcode
/// <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) => ReadUInt64Packed(reader, out value);
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.
@@ -175,8 +162,7 @@ namespace Unity.Netcode
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void ReadValuePacked(FastBufferReader reader, out long value)
{
ReadUInt64Packed(reader, out ulong readValue);
value = Arithmetic.ZigZagDecode(readValue);
ReadValueBitPacked(reader, out value);
}
/// <summary>
@@ -341,7 +327,9 @@ namespace Unity.Netcode
ushort returnValue = 0;
byte* ptr = ((byte*)&returnValue);
byte* data = reader.GetUnsafePtrAtCurrentPosition();
int numBytes = (data[0] & 0b1) + 1;
// 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");
@@ -350,17 +338,23 @@ namespace Unity.Netcode
switch (numBytes)
{
case 1:
*ptr = *data;
ptr[0] = data[0];
break;
case 2:
*ptr = *data;
*(ptr + 1) = *(data + 1);
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 >> 1);
value = (ushort)(returnValue >> 2);
}
/// <summary>
@@ -386,7 +380,8 @@ namespace Unity.Netcode
uint returnValue = 0;
byte* ptr = ((byte*)&returnValue);
byte* data = reader.GetUnsafePtrAtCurrentPosition();
int numBytes = (data[0] & 0b11) + 1;
// 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");
@@ -395,26 +390,34 @@ namespace Unity.Netcode
switch (numBytes)
{
case 1:
*ptr = *data;
ptr[0] = data[0];
break;
case 2:
*ptr = *data;
*(ptr + 1) = *(data + 1);
ptr[0] = data[0];
ptr[1] = data[1];
break;
case 3:
*ptr = *data;
*(ptr + 1) = *(data + 1);
*(ptr + 2) = *(data + 2);
ptr[0] = data[0];
ptr[1] = data[1];
ptr[2] = data[2];
break;
case 4:
*ptr = *data;
*(ptr + 1) = *(data + 1);
*(ptr + 2) = *(data + 2);
*(ptr + 3) = *(data + 3);
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 >> 2;
value = returnValue >> 3;
}
/// <summary>
@@ -440,7 +443,8 @@ namespace Unity.Netcode
ulong returnValue = 0;
byte* ptr = ((byte*)&returnValue);
byte* data = reader.GetUnsafePtrAtCurrentPosition();
int numBytes = (data[0] & 0b111) + 1;
// 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");
@@ -449,109 +453,74 @@ namespace Unity.Netcode
switch (numBytes)
{
case 1:
*ptr = *data;
ptr[0] = data[0];
break;
case 2:
*ptr = *data;
*(ptr + 1) = *(data + 1);
ptr[0] = data[0];
ptr[1] = data[1];
break;
case 3:
*ptr = *data;
*(ptr + 1) = *(data + 1);
*(ptr + 2) = *(data + 2);
ptr[0] = data[0];
ptr[1] = data[1];
ptr[2] = data[2];
break;
case 4:
*ptr = *data;
*(ptr + 1) = *(data + 1);
*(ptr + 2) = *(data + 2);
*(ptr + 3) = *(data + 3);
ptr[0] = data[0];
ptr[1] = data[1];
ptr[2] = data[2];
ptr[3] = data[3];
break;
case 5:
*ptr = *data;
*(ptr + 1) = *(data + 1);
*(ptr + 2) = *(data + 2);
*(ptr + 3) = *(data + 3);
*(ptr + 4) = *(data + 4);
ptr[0] = data[0];
ptr[1] = data[1];
ptr[2] = data[2];
ptr[3] = data[3];
ptr[4] = data[4];
break;
case 6:
*ptr = *data;
*(ptr + 1) = *(data + 1);
*(ptr + 2) = *(data + 2);
*(ptr + 3) = *(data + 3);
*(ptr + 4) = *(data + 4);
*(ptr + 5) = *(data + 5);
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 = *data;
*(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[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 = *data;
*(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);
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 >> 3;
value = returnValue >> 4;
}
#endif
private static void ReadUInt64Packed(FastBufferReader reader, out ulong value)
{
reader.ReadByteSafe(out byte firstByte);
if (firstByte <= 240)
{
value = firstByte;
return;
}
if (firstByte <= 248)
{
reader.ReadByteSafe(out byte secondByte);
value = 240UL + ((firstByte - 241UL) << 8) + secondByte;
return;
}
var numBytes = firstByte - 247;
if (!reader.TryBeginReadInternal(numBytes))
{
throw new OverflowException("Reading past the end of the buffer");
}
reader.ReadPartialValue(out value, numBytes);
}
private static void ReadUInt32Packed(FastBufferReader reader, out uint value)
{
reader.ReadByteSafe(out byte firstByte);
if (firstByte <= 240)
{
value = firstByte;
return;
}
if (firstByte <= 248)
{
reader.ReadByteSafe(out byte secondByte);
value = 240U + ((firstByte - 241U) << 8) + secondByte;
return;
}
var numBytes = firstByte - 247;
if (!reader.TryBeginReadInternal(numBytes))
{
throw new OverflowException("Reading past the end of the buffer");
}
reader.ReadPartialValue(out value, numBytes);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static unsafe float ToSingle<T>(T value) where T : unmanaged

View File

@@ -0,0 +1,58 @@
using System.Runtime.CompilerServices;
namespace Unity.Netcode
{
internal class ByteUtility
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static unsafe byte ToByte(bool b) => *(byte*)&b;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static bool GetBit(byte bitField, ushort bitPosition)
{
return (bitField & (1 << bitPosition)) != 0;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static void SetBit(ref byte bitField, ushort bitPosition, bool value)
{
bitField = (byte)((bitField & ~(1 << bitPosition)) | (ToByte(value) << bitPosition));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static bool GetBit(ushort bitField, ushort bitPosition)
{
return (bitField & (1 << bitPosition)) != 0;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static void SetBit(ref ushort bitField, ushort bitPosition, bool value)
{
bitField = (ushort)((bitField & ~(1 << bitPosition)) | (ToByte(value) << bitPosition));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static bool GetBit(uint bitField, ushort bitPosition)
{
return (bitField & (1 << bitPosition)) != 0;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static void SetBit(ref uint bitField, ushort bitPosition, bool value)
{
bitField = (uint)((bitField & ~(1 << bitPosition)) | ((uint)ToByte(value) << bitPosition));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static bool GetBit(ulong bitField, ushort bitPosition)
{
return (bitField & (ulong)(1 << bitPosition)) != 0;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static void SetBit(ref ulong bitField, ushort bitPosition, bool value)
{
bitField = ((bitField & (ulong)~(1 << bitPosition)) | ((ulong)ToByte(value) << bitPosition));
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 25bb0dd7157c423b8cfe0ecf06e15ae5
timeCreated: 1666711082

View File

@@ -65,7 +65,7 @@ namespace Unity.Netcode
ReaderHandle* readerHandle = null;
if (copyAllocator == Allocator.None)
{
readerHandle = (ReaderHandle*)UnsafeUtility.Malloc(sizeof(ReaderHandle) + length, UnsafeUtility.AlignOf<byte>(), internalAllocator);
readerHandle = (ReaderHandle*)UnsafeUtility.Malloc(sizeof(ReaderHandle), UnsafeUtility.AlignOf<byte>(), internalAllocator);
readerHandle->BufferPointer = buffer;
readerHandle->Position = offset;
}