com.unity.netcode.gameobjects@1.0.0-pre.8
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.0.0-pre.8] - 2022-04-27 ### Changed - `unmanaged` structs are no longer universally accepted as RPC parameters because some structs (i.e., structs with pointers in them, such as `NativeList<T>`) can't be supported by the default memcpy struct serializer. Structs that are intended to be serialized across the network must add `INetworkSerializeByMemcpy` to the interface list (i.e., `struct Foo : INetworkSerializeByMemcpy`). This interface is empty and just serves to mark the struct as compatible with memcpy serialization. For external structs you can't edit, you can pass them to RPCs by wrapping them in `ForceNetworkSerializeByMemcpy<T>`. (#1901) ### Removed - Removed `SIPTransport` (#1870) - Removed `ClientNetworkTransform` from the package samples and moved to Boss Room's Utilities package which can be found [here](https://github.com/Unity-Technologies/com.unity.multiplayer.samples.coop/blob/main/Packages/com.unity.multiplayer.samples.coop/Utilities/Net/ClientAuthority/ClientNetworkTransform.cs). ### Fixed - Fixed `NetworkTransform` generating false positive rotation delta checks when rolling over between 0 and 360 degrees. (#1890) - Fixed client throwing an exception if it has messages in the outbound queue when processing the `NetworkEvent.Disconnect` event and is using UTP. (#1884) - Fixed issue during client synchronization if 'ValidateSceneBeforeLoading' returned false it would halt the client synchronization process resulting in a client that was approved but not synchronized or fully connected with the server. (#1883) - Fixed an issue where UNetTransport.StartServer would return success even if the underlying transport failed to start (#854) - Passing generic types to RPCs no longer causes a native crash (#1901) - Fixed an issue where calling `Shutdown` on a `NetworkManager` that was already shut down would cause an immediate shutdown the next time it was started (basically the fix makes `Shutdown` idempotent). (#1877)
This commit is contained in:
@@ -2,6 +2,7 @@ using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using Unity.Collections;
|
||||
using Unity.Collections.LowLevel.Unsafe;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Unity.Netcode
|
||||
{
|
||||
@@ -528,60 +529,6 @@ namespace Unity.Netcode
|
||||
return sizeof(int) + sizeInBytes;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes an unmanaged array
|
||||
/// </summary>
|
||||
/// <param name="array">The array to write</param>
|
||||
/// <param name="count">The amount of elements to write</param>
|
||||
/// <param name="offset">Where in the array to start</param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public unsafe void WriteValue<T>(T[] array, int count = -1, int offset = 0) where T : unmanaged
|
||||
{
|
||||
int sizeInTs = count != -1 ? count : array.Length - offset;
|
||||
int sizeInBytes = sizeInTs * sizeof(T);
|
||||
WriteValue(sizeInTs);
|
||||
fixed (T* native = array)
|
||||
{
|
||||
byte* bytes = (byte*)(native + offset);
|
||||
WriteBytes(bytes, sizeInBytes);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes an unmanaged array
|
||||
///
|
||||
/// "Safe" version - automatically performs bounds checking. Less efficient than bounds checking
|
||||
/// for multiple writes at once by calling TryBeginWrite.
|
||||
/// </summary>
|
||||
/// <param name="array">The array to write</param>
|
||||
/// <param name="count">The amount of elements to write</param>
|
||||
/// <param name="offset">Where in the array to start</param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public unsafe void WriteValueSafe<T>(T[] array, int count = -1, int offset = 0) where T : unmanaged
|
||||
{
|
||||
#if DEVELOPMENT_BUILD || UNITY_EDITOR
|
||||
if (Handle->InBitwiseContext)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
"Cannot use BufferWriter in bytewise mode while in a bitwise context.");
|
||||
}
|
||||
#endif
|
||||
|
||||
int sizeInTs = count != -1 ? count : array.Length - offset;
|
||||
int sizeInBytes = sizeInTs * sizeof(T);
|
||||
|
||||
if (!TryBeginWriteInternal(sizeInBytes + sizeof(int)))
|
||||
{
|
||||
throw new OverflowException("Writing past the end of the buffer");
|
||||
}
|
||||
WriteValue(sizeInTs);
|
||||
fixed (T* native = array)
|
||||
{
|
||||
byte* bytes = (byte*)(native + offset);
|
||||
WriteBytes(bytes, sizeInBytes);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write a partial value. The specified number of bytes is written from the value and the rest is ignored.
|
||||
/// </summary>
|
||||
@@ -790,68 +737,170 @@ namespace Unity.Netcode
|
||||
return sizeof(T);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write a value of any unmanaged type (including unmanaged structs) to the buffer.
|
||||
/// It will be copied into the buffer exactly as it exists in memory.
|
||||
/// </summary>
|
||||
/// <param name="value">The value to copy</param>
|
||||
/// <typeparam name="T">Any unmanaged type</typeparam>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public unsafe void WriteValue<T>(in T value) where T : unmanaged
|
||||
private unsafe void WriteUnmanaged<T>(in T value) where T : unmanaged
|
||||
{
|
||||
int len = sizeof(T);
|
||||
|
||||
#if DEVELOPMENT_BUILD || UNITY_EDITOR
|
||||
if (Handle->InBitwiseContext)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
"Cannot use BufferWriter in bytewise mode while in a bitwise context.");
|
||||
}
|
||||
if (Handle->Position + len > Handle->AllowedWriteMark)
|
||||
{
|
||||
throw new OverflowException($"Attempted to write without first calling {nameof(TryBeginWrite)}()");
|
||||
}
|
||||
#endif
|
||||
|
||||
fixed (T* ptr = &value)
|
||||
{
|
||||
UnsafeUtility.MemCpy(Handle->BufferPointer + Handle->Position, (byte*)ptr, len);
|
||||
byte* bytes = (byte*)ptr;
|
||||
WriteBytes(bytes, sizeof(T));
|
||||
}
|
||||
Handle->Position += len;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write a value of any unmanaged type (including unmanaged structs) to the buffer.
|
||||
/// It will be copied into the buffer exactly as it exists in memory.
|
||||
///
|
||||
/// "Safe" version - automatically performs bounds checking. Less efficient than bounds checking
|
||||
/// for multiple writes at once by calling TryBeginWrite.
|
||||
/// </summary>
|
||||
/// <param name="value">The value to copy</param>
|
||||
/// <typeparam name="T">Any unmanaged type</typeparam>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public unsafe void WriteValueSafe<T>(in T value) where T : unmanaged
|
||||
private unsafe void WriteUnmanagedSafe<T>(in T value) where T : unmanaged
|
||||
{
|
||||
int len = sizeof(T);
|
||||
|
||||
#if DEVELOPMENT_BUILD || UNITY_EDITOR
|
||||
if (Handle->InBitwiseContext)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
"Cannot use BufferWriter in bytewise mode while in a bitwise context.");
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!TryBeginWriteInternal(len))
|
||||
{
|
||||
throw new OverflowException("Writing past the end of the buffer");
|
||||
}
|
||||
|
||||
fixed (T* ptr = &value)
|
||||
{
|
||||
UnsafeUtility.MemCpy(Handle->BufferPointer + Handle->Position, (byte*)ptr, len);
|
||||
byte* bytes = (byte*)ptr;
|
||||
WriteBytesSafe(bytes, sizeof(T));
|
||||
}
|
||||
Handle->Position += len;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private unsafe void WriteUnmanaged<T>(T[] value) where T : unmanaged
|
||||
{
|
||||
WriteUnmanaged(value.Length);
|
||||
fixed (T* ptr = value)
|
||||
{
|
||||
byte* bytes = (byte*)ptr;
|
||||
WriteBytes(bytes, sizeof(T) * value.Length);
|
||||
}
|
||||
}
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private unsafe void WriteUnmanagedSafe<T>(T[] value) where T : unmanaged
|
||||
{
|
||||
WriteUnmanagedSafe(value.Length);
|
||||
fixed (T* ptr = value)
|
||||
{
|
||||
byte* bytes = (byte*)ptr;
|
||||
WriteBytesSafe(bytes, sizeof(T) * value.Length);
|
||||
}
|
||||
}
|
||||
|
||||
// These structs enable overloading of WriteValue with different generic constraints.
|
||||
// The compiler's actually able to distinguish between overloads based on generic constraints.
|
||||
// But at the bytecode level, the constraints aren't included in the method signature.
|
||||
// By adding a second parameter with a defaulted value, the signatures of each generic are different,
|
||||
// thus allowing overloads of methods based on the first parameter meeting constraints.
|
||||
public struct ForPrimitives
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public struct ForEnums
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public struct ForStructs
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public struct ForNetworkSerializable
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void WriteValue<T>(in T value, ForPrimitives unused = default) where T : unmanaged, IComparable, IConvertible, IComparable<T>, IEquatable<T> => WriteUnmanaged(value);
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void WriteValue<T>(T[] value, ForPrimitives unused = default) where T : unmanaged, IComparable, IConvertible, IComparable<T>, IEquatable<T> => WriteUnmanaged(value);
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void WriteValueSafe<T>(in T value, ForPrimitives unused = default) where T : unmanaged, IComparable, IConvertible, IComparable<T>, IEquatable<T> => WriteUnmanagedSafe(value);
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void WriteValueSafe<T>(T[] value, ForPrimitives unused = default) where T : unmanaged, IComparable, IConvertible, IComparable<T>, IEquatable<T> => WriteUnmanagedSafe(value);
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void WriteValue<T>(in T value, ForEnums unused = default) where T : unmanaged, Enum => WriteUnmanaged(value);
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void WriteValue<T>(T[] value, ForEnums unused = default) where T : unmanaged, Enum => WriteUnmanaged(value);
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void WriteValueSafe<T>(in T value, ForEnums unused = default) where T : unmanaged, Enum => WriteUnmanagedSafe(value);
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void WriteValueSafe<T>(T[] value, ForEnums unused = default) where T : unmanaged, Enum => WriteUnmanagedSafe(value);
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void WriteValue<T>(in T value, ForStructs unused = default) where T : unmanaged, INetworkSerializeByMemcpy => WriteUnmanaged(value);
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void WriteValue<T>(T[] value, ForStructs unused = default) where T : unmanaged, INetworkSerializeByMemcpy => WriteUnmanaged(value);
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void WriteValueSafe<T>(in T value, ForStructs unused = default) where T : unmanaged, INetworkSerializeByMemcpy => WriteUnmanagedSafe(value);
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void WriteValueSafe<T>(T[] value, ForStructs unused = default) where T : unmanaged, INetworkSerializeByMemcpy => WriteUnmanagedSafe(value);
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void WriteValue<T>(in T value, ForNetworkSerializable unused = default) where T : INetworkSerializable => WriteNetworkSerializable(value);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void WriteValue<T>(T[] value, ForNetworkSerializable unused = default) where T : INetworkSerializable => WriteNetworkSerializable(value);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void WriteValueSafe<T>(in T value, ForNetworkSerializable unused = default) where T : INetworkSerializable => WriteNetworkSerializable(value);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void WriteValueSafe<T>(T[] value, ForNetworkSerializable unused = default) where T : INetworkSerializable => WriteNetworkSerializable(value);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void WriteValue(in Vector2 value) => WriteUnmanaged(value);
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void WriteValue(Vector2[] value) => WriteUnmanaged(value);
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void WriteValue(in Vector3 value) => WriteUnmanaged(value);
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void WriteValue(Vector3[] value) => WriteUnmanaged(value);
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void WriteValue(in Vector4 value) => WriteUnmanaged(value);
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void WriteValue(Vector4[] value) => WriteUnmanaged(value);
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void WriteValue(in Quaternion value) => WriteUnmanaged(value);
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void WriteValue(Quaternion[] value) => WriteUnmanaged(value);
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void WriteValue(in Color value) => WriteUnmanaged(value);
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void WriteValue(Color[] value) => WriteUnmanaged(value);
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void WriteValue(in Color32 value) => WriteUnmanaged(value);
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void WriteValue(Color32[] value) => WriteUnmanaged(value);
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void WriteValue(in Ray value) => WriteUnmanaged(value);
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void WriteValue(Ray[] value) => WriteUnmanaged(value);
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void WriteValue(in Ray2D value) => WriteUnmanaged(value);
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void WriteValue(Ray2D[] value) => WriteUnmanaged(value);
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void WriteValueSafe(in Vector2 value) => WriteUnmanagedSafe(value);
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void WriteValueSafe(Vector2[] value) => WriteUnmanagedSafe(value);
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void WriteValueSafe(in Vector3 value) => WriteUnmanagedSafe(value);
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void WriteValueSafe(Vector3[] value) => WriteUnmanagedSafe(value);
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void WriteValueSafe(in Vector4 value) => WriteUnmanagedSafe(value);
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void WriteValueSafe(Vector4[] value) => WriteUnmanagedSafe(value);
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void WriteValueSafe(in Quaternion value) => WriteUnmanagedSafe(value);
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void WriteValueSafe(Quaternion[] value) => WriteUnmanagedSafe(value);
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void WriteValueSafe(in Color value) => WriteUnmanagedSafe(value);
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void WriteValueSafe(Color[] value) => WriteUnmanagedSafe(value);
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void WriteValueSafe(in Color32 value) => WriteUnmanagedSafe(value);
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void WriteValueSafe(Color32[] value) => WriteUnmanagedSafe(value);
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void WriteValueSafe(in Ray value) => WriteUnmanagedSafe(value);
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void WriteValueSafe(Ray[] value) => WriteUnmanagedSafe(value);
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void WriteValueSafe(in Ray2D value) => WriteUnmanagedSafe(value);
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void WriteValueSafe(Ray2D[] value) => WriteUnmanagedSafe(value);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user