com.unity.netcode.gameobjects@1.5.1

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.5.1] - 2023-06-07

### Added

- Added support for serializing `NativeArray<>` and `NativeList<>` in `FastBufferReader`/`FastBufferWriter`, `BufferSerializer`, `NetworkVariable`, and RPCs. (To use `NativeList<>`, add `UNITY_NETCODE_NATIVE_COLLECTION_SUPPORT` to your Scripting Define Symbols in `Project Settings > Player`) (#2375)
- The location of the automatically-created default network prefab list can now be configured (#2544)
- Added: Message size limits (max single message and max fragmented message) can now be set using NetworkManager.MaximumTransmissionUnitSize and NetworkManager.MaximumFragmentedMessageSize for transports that don't work with the default values (#2530)
- Added `NetworkObject.SpawnWithObservers` property (default is true) that when set to false will spawn a `NetworkObject` with no observers and will not be spawned on any client until `NetworkObject.NetworkShow` is invoked. (#2568)

### Fixed

- Fixed: Fixed a null reference in codegen in some projects (#2581)
- Fixed issue where the `OnClientDisconnected` client identifier was incorrect after a pending client connection was denied. (#2569)
- Fixed warning "Runtime Network Prefabs was not empty at initialization time." being erroneously logged when no runtime network prefabs had been added (#2565)
- Fixed issue where some temporary debug console logging was left in a merged PR. (#2562)
- Fixed the "Generate Default Network Prefabs List" setting not loading correctly and always reverting to being checked. (#2545)
- Fixed issue where users could not use NetworkSceneManager.VerifySceneBeforeLoading to exclude runtime generated scenes from client synchronization. (#2550)
- Fixed missing value on `NetworkListEvent` for `EventType.RemoveAt` events.  (#2542,#2543)
- Fixed issue where parenting a NetworkTransform under a transform with a scale other than Vector3.one would result in incorrect values on non-authoritative instances. (#2538)
- Fixed issue where a server would include scene migrated and then despawned NetworkObjects to a client that was being synchronized. (#2532)
- Fixed the inspector throwing exceptions when attempting to render `NetworkVariable`s of enum types. (#2529)
- Making a `NetworkVariable` with an `INetworkSerializable` type that doesn't meet the `new()` constraint will now create a compile-time error instead of an editor crash (#2528)
- Fixed Multiplayer Tools package installation docs page link on the NetworkManager popup. (#2526)
- Fixed an exception and error logging when two different objects are shown and hidden on the same frame (#2524)
- Fixed a memory leak in `UnityTransport` that occurred if `StartClient` failed. (#2518)
- Fixed issue where a client could throw an exception if abruptly disconnected from a network session with one or more spawned `NetworkObject`(s). (#2510)
- Fixed issue where invalid endpoint addresses were not being detected and returning false from NGO UnityTransport. (#2496)
- Fixed some errors that could occur if a connection is lost and the loss is detected when attempting to write to the socket. (#2495)

## Changed

- Adding network prefabs before NetworkManager initialization is now supported. (#2565)
- Connecting clients being synchronized now switch to the server's active scene before spawning and synchronizing NetworkObjects. (#2532)
- Updated `UnityTransport` dependency on `com.unity.transport` to 1.3.4. (#2533)
- Improved performance of NetworkBehaviour initialization by replacing reflection when initializing NetworkVariables with compile-time code generation, which should help reduce hitching during additive scene loads. (#2522)
This commit is contained in:
Unity Technologies
2023-06-07 00:00:00 +00:00
parent b5abc3ff7c
commit 4d70c198bd
119 changed files with 11328 additions and 3164 deletions

View File

@@ -75,7 +75,7 @@ namespace Unity.Netcode
return;
}
m_NetworkBehaviour.NetworkManager.MarkNetworkObjectDirty(m_NetworkBehaviour.NetworkObject);
m_NetworkBehaviour.NetworkManager.BehaviourUpdater.AddForUpdate(m_NetworkBehaviour.NetworkObject);
}
/// <inheritdoc />
@@ -490,12 +490,14 @@ namespace Unity.Netcode
throw new InvalidOperationException("Client is not allowed to write to this NetworkList");
}
var value = m_List[index];
m_List.RemoveAt(index);
var listEvent = new NetworkListEvent<T>()
{
Type = NetworkListEvent<T>.EventType.RemoveAt,
Index = index
Index = index,
Value = value
};
HandleAddListEvent(listEvent);

View File

@@ -33,6 +33,13 @@ namespace Unity.Netcode
: base(readPerm, writePerm)
{
m_InternalValue = value;
// Since we start with IsDirty = true, this doesn't need to be duplicated
// right away. It won't get read until after ResetDirty() is called, and
// the duplicate will be made there. Avoiding calling
// NetworkVariableSerialization<T>.Duplicate() is important because calling
// it in the constructor might not give users enough time to set the
// DuplicateValue callback if they're using UserNetworkVariableSerialization
m_PreviousValue = default;
}
/// <summary>
@@ -41,6 +48,11 @@ namespace Unity.Netcode
[SerializeField]
private protected T m_InternalValue;
private protected T m_PreviousValue;
private bool m_HasPreviousValue;
private bool m_IsDisposed;
/// <summary>
/// The value of the NetworkVariable container
/// </summary>
@@ -61,9 +73,83 @@ namespace Unity.Netcode
}
Set(value);
m_IsDisposed = false;
}
}
internal ref T RefValue()
{
return ref m_InternalValue;
}
public override void Dispose()
{
if (m_IsDisposed)
{
return;
}
m_IsDisposed = true;
if (m_InternalValue is IDisposable internalValueDisposable)
{
internalValueDisposable.Dispose();
}
m_InternalValue = default;
if (m_HasPreviousValue && m_PreviousValue is IDisposable previousValueDisposable)
{
m_HasPreviousValue = false;
previousValueDisposable.Dispose();
}
m_PreviousValue = default;
}
~NetworkVariable()
{
Dispose();
}
/// <summary>
/// Gets Whether or not the container is dirty
/// </summary>
/// <returns>Whether or not the container is dirty</returns>
public override bool IsDirty()
{
// For most cases we can use the dirty flag.
// This doesn't work for cases where we're wrapping more complex types
// like INetworkSerializable, NativeList, NativeArray, etc.
// Changes to the values in those types don't call the Value.set method,
// so we can't catch those changes and need to compare the current value
// against the previous one.
if (base.IsDirty())
{
return true;
}
// Cache the dirty value so we don't perform this again if we already know we're dirty
// Unfortunately we can't cache the NOT dirty state, because that might change
// in between to checks... but the DIRTY state won't change until ResetDirty()
// is called.
var dirty = !NetworkVariableSerialization<T>.AreEqual(ref m_PreviousValue, ref m_InternalValue);
SetDirty(dirty);
return dirty;
}
/// <summary>
/// Resets the dirty state and marks the variable as synced / clean
/// </summary>
public override void ResetDirty()
{
base.ResetDirty();
// Resetting the dirty value declares that the current value is not dirty
// Therefore, we set the m_PreviousValue field to a duplicate of the current
// field, so that our next dirty check is made against the current "not dirty"
// value.
m_HasPreviousValue = true;
NetworkVariableSerialization<T>.Serializer.Duplicate(m_InternalValue, ref m_PreviousValue);
}
/// <summary>
/// Sets the <see cref="Value"/>, marks the <see cref="NetworkVariable{T}"/> dirty, and invokes the <see cref="OnValueChanged"/> callback
/// if there are subscribers to that event.

View File

@@ -94,7 +94,8 @@ namespace Unity.Netcode
"Are you modifying a NetworkVariable before the NetworkObject is spawned?");
return;
}
m_NetworkBehaviour.NetworkManager.MarkNetworkObjectDirty(m_NetworkBehaviour.NetworkObject);
m_NetworkBehaviour.NetworkManager.BehaviourUpdater.AddForUpdate(m_NetworkBehaviour.NetworkObject);
}
}

View File

@@ -20,6 +20,8 @@ namespace Unity.Netcode
// of it to pass it as a ref parameter.
public void Write(FastBufferWriter writer, ref T value);
public void Read(FastBufferReader reader, ref T value);
internal void ReadWithAllocator(FastBufferReader reader, out T value, Allocator allocator);
public void Duplicate(in T value, ref T duplicatedValue);
}
/// <summary>
@@ -35,6 +37,16 @@ namespace Unity.Netcode
{
ByteUnpacker.ReadValueBitPacked(reader, out value);
}
void INetworkVariableSerializer<short>.ReadWithAllocator(FastBufferReader reader, out short value, Allocator allocator)
{
throw new NotImplementedException();
}
public void Duplicate(in short value, ref short duplicatedValue)
{
duplicatedValue = value;
}
}
/// <summary>
@@ -50,6 +62,16 @@ namespace Unity.Netcode
{
ByteUnpacker.ReadValueBitPacked(reader, out value);
}
void INetworkVariableSerializer<ushort>.ReadWithAllocator(FastBufferReader reader, out ushort value, Allocator allocator)
{
throw new NotImplementedException();
}
public void Duplicate(in ushort value, ref ushort duplicatedValue)
{
duplicatedValue = value;
}
}
/// <summary>
@@ -65,6 +87,16 @@ namespace Unity.Netcode
{
ByteUnpacker.ReadValueBitPacked(reader, out value);
}
void INetworkVariableSerializer<int>.ReadWithAllocator(FastBufferReader reader, out int value, Allocator allocator)
{
throw new NotImplementedException();
}
public void Duplicate(in int value, ref int duplicatedValue)
{
duplicatedValue = value;
}
}
/// <summary>
@@ -80,6 +112,16 @@ namespace Unity.Netcode
{
ByteUnpacker.ReadValueBitPacked(reader, out value);
}
void INetworkVariableSerializer<uint>.ReadWithAllocator(FastBufferReader reader, out uint value, Allocator allocator)
{
throw new NotImplementedException();
}
public void Duplicate(in uint value, ref uint duplicatedValue)
{
duplicatedValue = value;
}
}
/// <summary>
@@ -95,6 +137,16 @@ namespace Unity.Netcode
{
ByteUnpacker.ReadValueBitPacked(reader, out value);
}
void INetworkVariableSerializer<long>.ReadWithAllocator(FastBufferReader reader, out long value, Allocator allocator)
{
throw new NotImplementedException();
}
public void Duplicate(in long value, ref long duplicatedValue)
{
duplicatedValue = value;
}
}
/// <summary>
@@ -110,6 +162,16 @@ namespace Unity.Netcode
{
ByteUnpacker.ReadValueBitPacked(reader, out value);
}
void INetworkVariableSerializer<ulong>.ReadWithAllocator(FastBufferReader reader, out ulong value, Allocator allocator)
{
throw new NotImplementedException();
}
public void Duplicate(in ulong value, ref ulong duplicatedValue)
{
duplicatedValue = value;
}
}
/// <summary>
@@ -130,8 +192,84 @@ namespace Unity.Netcode
{
reader.ReadUnmanagedSafe(out value);
}
void INetworkVariableSerializer<T>.ReadWithAllocator(FastBufferReader reader, out T value, Allocator allocator)
{
throw new NotImplementedException();
}
public void Duplicate(in T value, ref T duplicatedValue)
{
duplicatedValue = value;
}
}
internal class UnmanagedArraySerializer<T> : INetworkVariableSerializer<NativeArray<T>> where T : unmanaged
{
public void Write(FastBufferWriter writer, ref NativeArray<T> value)
{
writer.WriteUnmanagedSafe(value);
}
public void Read(FastBufferReader reader, ref NativeArray<T> value)
{
value.Dispose();
reader.ReadUnmanagedSafe(out value, Allocator.Persistent);
}
void INetworkVariableSerializer<NativeArray<T>>.ReadWithAllocator(FastBufferReader reader, out NativeArray<T> value, Allocator allocator)
{
reader.ReadUnmanagedSafe(out value, allocator);
}
public void Duplicate(in NativeArray<T> value, ref NativeArray<T> duplicatedValue)
{
if (!duplicatedValue.IsCreated || duplicatedValue.Length != value.Length)
{
if (duplicatedValue.IsCreated)
{
duplicatedValue.Dispose();
}
duplicatedValue = new NativeArray<T>(value.Length, Allocator.Persistent, NativeArrayOptions.UninitializedMemory);
}
duplicatedValue.CopyFrom(value);
}
}
#if UNITY_NETCODE_NATIVE_COLLECTION_SUPPORT
internal class UnmanagedListSerializer<T> : INetworkVariableSerializer<NativeList<T>> where T : unmanaged
{
public void Write(FastBufferWriter writer, ref NativeList<T> value)
{
writer.WriteUnmanagedSafe(value);
}
public void Read(FastBufferReader reader, ref NativeList<T> value)
{
reader.ReadUnmanagedSafeInPlace(ref value);
}
void INetworkVariableSerializer<NativeList<T>>.ReadWithAllocator(FastBufferReader reader, out NativeList<T> value, Allocator allocator)
{
throw new NotImplementedException();
}
public void Duplicate(in NativeList<T> value, ref NativeList<T> duplicatedValue)
{
if (!duplicatedValue.IsCreated)
{
duplicatedValue = new NativeList<T>(value.Length, Allocator.Persistent);
}
else if (value.Length != duplicatedValue.Length)
{
duplicatedValue.ResizeUninitialized(value.Length);
}
duplicatedValue.CopyFrom(value);
}
}
#endif
/// <summary>
/// Serializer for FixedStrings
/// </summary>
@@ -146,8 +284,92 @@ namespace Unity.Netcode
{
reader.ReadValueSafeInPlace(ref value);
}
void INetworkVariableSerializer<T>.ReadWithAllocator(FastBufferReader reader, out T value, Allocator allocator)
{
throw new NotImplementedException();
}
public void Duplicate(in T value, ref T duplicatedValue)
{
duplicatedValue = value;
}
}
/// <summary>
/// Serializer for FixedStrings
/// </summary>
/// <typeparam name="T"></typeparam>
internal class FixedStringArraySerializer<T> : INetworkVariableSerializer<NativeArray<T>> where T : unmanaged, INativeList<byte>, IUTF8Bytes
{
public void Write(FastBufferWriter writer, ref NativeArray<T> value)
{
writer.WriteValueSafe(value);
}
public void Read(FastBufferReader reader, ref NativeArray<T> value)
{
value.Dispose();
reader.ReadValueSafe(out value, Allocator.Persistent);
}
void INetworkVariableSerializer<NativeArray<T>>.ReadWithAllocator(FastBufferReader reader, out NativeArray<T> value, Allocator allocator)
{
reader.ReadValueSafe(out value, allocator);
}
public void Duplicate(in NativeArray<T> value, ref NativeArray<T> duplicatedValue)
{
if (!duplicatedValue.IsCreated || duplicatedValue.Length != value.Length)
{
if (duplicatedValue.IsCreated)
{
duplicatedValue.Dispose();
}
duplicatedValue = new NativeArray<T>(value.Length, Allocator.Persistent, NativeArrayOptions.UninitializedMemory);
}
duplicatedValue.CopyFrom(value);
}
}
#if UNITY_NETCODE_NATIVE_COLLECTION_SUPPORT
/// <summary>
/// Serializer for FixedStrings
/// </summary>
/// <typeparam name="T"></typeparam>
internal class FixedStringListSerializer<T> : INetworkVariableSerializer<NativeList<T>> where T : unmanaged, INativeList<byte>, IUTF8Bytes
{
public void Write(FastBufferWriter writer, ref NativeList<T> value)
{
writer.WriteValueSafe(value);
}
public void Read(FastBufferReader reader, ref NativeList<T> value)
{
reader.ReadValueSafeInPlace(ref value);
}
void INetworkVariableSerializer<NativeList<T>>.ReadWithAllocator(FastBufferReader reader, out NativeList<T> value, Allocator allocator)
{
throw new NotImplementedException();
}
public void Duplicate(in NativeList<T> value, ref NativeList<T> duplicatedValue)
{
if (!duplicatedValue.IsCreated)
{
duplicatedValue = new NativeList<T>(value.Length, Allocator.Persistent);
}
else if (value.Length != duplicatedValue.Length)
{
duplicatedValue.ResizeUninitialized(value.Length);
}
duplicatedValue.CopyFrom(value);
}
}
#endif
/// <summary>
/// Serializer for unmanaged INetworkSerializable types
/// </summary>
@@ -163,10 +385,93 @@ namespace Unity.Netcode
{
var bufferSerializer = new BufferSerializer<BufferSerializerReader>(new BufferSerializerReader(reader));
value.NetworkSerialize(bufferSerializer);
}
void INetworkVariableSerializer<T>.ReadWithAllocator(FastBufferReader reader, out T value, Allocator allocator)
{
throw new NotImplementedException();
}
public void Duplicate(in T value, ref T duplicatedValue)
{
duplicatedValue = value;
}
}
/// <summary>
/// Serializer for unmanaged INetworkSerializable types
/// </summary>
/// <typeparam name="T"></typeparam>
internal class UnmanagedNetworkSerializableArraySerializer<T> : INetworkVariableSerializer<NativeArray<T>> where T : unmanaged, INetworkSerializable
{
public void Write(FastBufferWriter writer, ref NativeArray<T> value)
{
writer.WriteNetworkSerializable(value);
}
public void Read(FastBufferReader reader, ref NativeArray<T> value)
{
value.Dispose();
reader.ReadNetworkSerializable(out value, Allocator.Persistent);
}
void INetworkVariableSerializer<NativeArray<T>>.ReadWithAllocator(FastBufferReader reader, out NativeArray<T> value, Allocator allocator)
{
reader.ReadNetworkSerializable(out value, allocator);
}
public void Duplicate(in NativeArray<T> value, ref NativeArray<T> duplicatedValue)
{
if (!duplicatedValue.IsCreated || duplicatedValue.Length != value.Length)
{
if (duplicatedValue.IsCreated)
{
duplicatedValue.Dispose();
}
duplicatedValue = new NativeArray<T>(value.Length, Allocator.Persistent, NativeArrayOptions.UninitializedMemory);
}
duplicatedValue.CopyFrom(value);
}
}
#if UNITY_NETCODE_NATIVE_COLLECTION_SUPPORT
/// <summary>
/// Serializer for unmanaged INetworkSerializable types
/// </summary>
/// <typeparam name="T"></typeparam>
internal class UnmanagedNetworkSerializableListSerializer<T> : INetworkVariableSerializer<NativeList<T>> where T : unmanaged, INetworkSerializable
{
public void Write(FastBufferWriter writer, ref NativeList<T> value)
{
writer.WriteNetworkSerializable(value);
}
public void Read(FastBufferReader reader, ref NativeList<T> value)
{
reader.ReadNetworkSerializableInPlace(ref value);
}
void INetworkVariableSerializer<NativeList<T>>.ReadWithAllocator(FastBufferReader reader, out NativeList<T> value, Allocator allocator)
{
throw new NotImplementedException();
}
public void Duplicate(in NativeList<T> value, ref NativeList<T> duplicatedValue)
{
if (!duplicatedValue.IsCreated)
{
duplicatedValue = new NativeList<T>(value.Length, Allocator.Persistent);
}
else if (value.Length != duplicatedValue.Length)
{
duplicatedValue.ResizeUninitialized(value.Length);
}
duplicatedValue.CopyFrom(value);
}
}
#endif
/// <summary>
/// Serializer for managed INetworkSerializable types, which differs from the unmanaged implementation in that it
/// has to be null-aware
@@ -201,6 +506,21 @@ namespace Unity.Netcode
value.NetworkSerialize(bufferSerializer);
}
}
void INetworkVariableSerializer<T>.ReadWithAllocator(FastBufferReader reader, out T value, Allocator allocator)
{
throw new NotImplementedException();
}
public void Duplicate(in T value, ref T duplicatedValue)
{
using var writer = new FastBufferWriter(256, Allocator.Temp);
var refValue = value;
Write(writer, ref refValue);
using var reader = new FastBufferReader(writer, Allocator.None);
Read(reader, ref duplicatedValue);
}
}
/// <summary>
@@ -227,14 +547,26 @@ namespace Unity.Netcode
public delegate void ReadValueDelegate(FastBufferReader reader, out T value);
/// <summary>
/// The <see cref="WriteValueDelegate"/> delegate handler declaration
/// The read value delegate handler definition
/// </summary>
/// <param name="reader">The <see cref="FastBufferReader"/> to read the value of type `T`</param>
/// <param name="value">The value of type `T` to be read</param>
public delegate void DuplicateValueDelegate(in T value, ref T duplicatedValue);
/// <summary>
/// Callback to write a value
/// </summary>
public static WriteValueDelegate WriteValue;
/// <summary>
/// The <see cref="ReadValueDelegate"/> delegate handler declaration
/// Callback to read a value
/// </summary>
public static ReadValueDelegate ReadValue;
/// <summary>
/// Callback to create a duplicate of a value, used to check for dirty status.
/// </summary>
public static DuplicateValueDelegate DuplicateValue;
}
/// <summary>
@@ -250,20 +582,34 @@ namespace Unity.Netcode
{
public void Write(FastBufferWriter writer, ref T value)
{
if (UserNetworkVariableSerialization<T>.ReadValue == null || UserNetworkVariableSerialization<T>.WriteValue == null)
if (UserNetworkVariableSerialization<T>.ReadValue == null || UserNetworkVariableSerialization<T>.WriteValue == null || UserNetworkVariableSerialization<T>.DuplicateValue == null)
{
throw new ArgumentException($"Type {typeof(T).FullName} is not supported by {typeof(NetworkVariable<>).Name}. If this is a type you can change, then either implement {nameof(INetworkSerializable)} or mark it as serializable by memcpy by adding {nameof(INetworkSerializeByMemcpy)} to its interface list. If not, assign serialization code to {nameof(UserNetworkVariableSerialization<T>)}.{nameof(UserNetworkVariableSerialization<T>.WriteValue)} and {nameof(UserNetworkVariableSerialization<T>)}.{nameof(UserNetworkVariableSerialization<T>.ReadValue)}, or if it's serializable by memcpy (contains no pointers), wrap it in {typeof(ForceNetworkSerializeByMemcpy<>).Name}.");
throw new ArgumentException($"Type {typeof(T).FullName} is not supported by {typeof(NetworkVariable<>).Name}. If this is a type you can change, then either implement {nameof(INetworkSerializable)} or mark it as serializable by memcpy by adding {nameof(INetworkSerializeByMemcpy)} to its interface list. If not, assign serialization code to {nameof(UserNetworkVariableSerialization<T>)}.{nameof(UserNetworkVariableSerialization<T>.WriteValue)}, {nameof(UserNetworkVariableSerialization<T>)}.{nameof(UserNetworkVariableSerialization<T>.ReadValue)}, and {nameof(UserNetworkVariableSerialization<T>)}.{nameof(UserNetworkVariableSerialization<T>.DuplicateValue)}, or if it's serializable by memcpy (contains no pointers), wrap it in {typeof(ForceNetworkSerializeByMemcpy<>).Name}.");
}
UserNetworkVariableSerialization<T>.WriteValue(writer, value);
}
public void Read(FastBufferReader reader, ref T value)
{
if (UserNetworkVariableSerialization<T>.ReadValue == null || UserNetworkVariableSerialization<T>.WriteValue == null)
if (UserNetworkVariableSerialization<T>.ReadValue == null || UserNetworkVariableSerialization<T>.WriteValue == null || UserNetworkVariableSerialization<T>.DuplicateValue == null)
{
throw new ArgumentException($"Type {typeof(T).FullName} is not supported by {typeof(NetworkVariable<>).Name}. If this is a type you can change, then either implement {nameof(INetworkSerializable)} or mark it as serializable by memcpy by adding {nameof(INetworkSerializeByMemcpy)} to its interface list. If not, assign serialization code to {nameof(UserNetworkVariableSerialization<T>)}.{nameof(UserNetworkVariableSerialization<T>.WriteValue)} and {nameof(UserNetworkVariableSerialization<T>)}.{nameof(UserNetworkVariableSerialization<T>.ReadValue)}, or if it's serializable by memcpy (contains no pointers), wrap it in {typeof(ForceNetworkSerializeByMemcpy<>).Name}.");
throw new ArgumentException($"Type {typeof(T).FullName} is not supported by {typeof(NetworkVariable<>).Name}. If this is a type you can change, then either implement {nameof(INetworkSerializable)} or mark it as serializable by memcpy by adding {nameof(INetworkSerializeByMemcpy)} to its interface list. If not, assign serialization code to {nameof(UserNetworkVariableSerialization<T>)}.{nameof(UserNetworkVariableSerialization<T>.WriteValue)}, {nameof(UserNetworkVariableSerialization<T>)}.{nameof(UserNetworkVariableSerialization<T>.ReadValue)}, and {nameof(UserNetworkVariableSerialization<T>)}.{nameof(UserNetworkVariableSerialization<T>.DuplicateValue)}, or if it's serializable by memcpy (contains no pointers), wrap it in {typeof(ForceNetworkSerializeByMemcpy<>).Name}.");
}
UserNetworkVariableSerialization<T>.ReadValue(reader, out value);
}
void INetworkVariableSerializer<T>.ReadWithAllocator(FastBufferReader reader, out T value, Allocator allocator)
{
throw new NotImplementedException();
}
public void Duplicate(in T value, ref T duplicatedValue)
{
if (UserNetworkVariableSerialization<T>.ReadValue == null || UserNetworkVariableSerialization<T>.WriteValue == null || UserNetworkVariableSerialization<T>.DuplicateValue == null)
{
throw new ArgumentException($"Type {typeof(T).FullName} is not supported by {typeof(NetworkVariable<>).Name}. If this is a type you can change, then either implement {nameof(INetworkSerializable)} or mark it as serializable by memcpy by adding {nameof(INetworkSerializeByMemcpy)} to its interface list. If not, assign serialization code to {nameof(UserNetworkVariableSerialization<T>)}.{nameof(UserNetworkVariableSerialization<T>.WriteValue)}, {nameof(UserNetworkVariableSerialization<T>)}.{nameof(UserNetworkVariableSerialization<T>.ReadValue)}, and {nameof(UserNetworkVariableSerialization<T>)}.{nameof(UserNetworkVariableSerialization<T>.DuplicateValue)}, or if it's serializable by memcpy (contains no pointers), wrap it in {typeof(ForceNetworkSerializeByMemcpy<>).Name}.");
}
UserNetworkVariableSerialization<T>.DuplicateValue(value, ref duplicatedValue);
}
}
/// <summary>
@@ -309,6 +655,26 @@ namespace Unity.Netcode
NetworkVariableSerialization<T>.Serializer = new UnmanagedTypeSerializer<T>();
}
/// <summary>
/// Registeres an unmanaged type that will be serialized by a direct memcpy into a buffer
/// </summary>
/// <typeparam name="T"></typeparam>
public static void InitializeSerializer_UnmanagedByMemcpyArray<T>() where T : unmanaged
{
NetworkVariableSerialization<NativeArray<T>>.Serializer = new UnmanagedArraySerializer<T>();
}
#if UNITY_NETCODE_NATIVE_COLLECTION_SUPPORT
/// <summary>
/// Registeres an unmanaged type that will be serialized by a direct memcpy into a buffer
/// </summary>
/// <typeparam name="T"></typeparam>
public static void InitializeSerializer_UnmanagedByMemcpyList<T>() where T : unmanaged
{
NetworkVariableSerialization<NativeList<T>>.Serializer = new UnmanagedListSerializer<T>();
}
#endif
/// <summary>
/// Registers an unmanaged type that implements INetworkSerializable and will be serialized through a call to
/// NetworkSerialize
@@ -319,6 +685,28 @@ namespace Unity.Netcode
NetworkVariableSerialization<T>.Serializer = new UnmanagedNetworkSerializableSerializer<T>();
}
/// <summary>
/// Registers an unmanaged type that implements INetworkSerializable and will be serialized through a call to
/// NetworkSerialize
/// </summary>
/// <typeparam name="T"></typeparam>
public static void InitializeSerializer_UnmanagedINetworkSerializableArray<T>() where T : unmanaged, INetworkSerializable
{
NetworkVariableSerialization<NativeArray<T>>.Serializer = new UnmanagedNetworkSerializableArraySerializer<T>();
}
#if UNITY_NETCODE_NATIVE_COLLECTION_SUPPORT
/// <summary>
/// Registers an unmanaged type that implements INetworkSerializable and will be serialized through a call to
/// NetworkSerialize
/// </summary>
/// <typeparam name="T"></typeparam>
public static void InitializeSerializer_UnmanagedINetworkSerializableList<T>() where T : unmanaged, INetworkSerializable
{
NetworkVariableSerialization<NativeList<T>>.Serializer = new UnmanagedNetworkSerializableListSerializer<T>();
}
#endif
/// <summary>
/// Registers a managed type that implements INetworkSerializable and will be serialized through a call to
/// NetworkSerialize
@@ -339,6 +727,28 @@ namespace Unity.Netcode
NetworkVariableSerialization<T>.Serializer = new FixedStringSerializer<T>();
}
/// <summary>
/// Registers a FixedString type that will be serialized through FastBufferReader/FastBufferWriter's FixedString
/// serializers
/// </summary>
/// <typeparam name="T"></typeparam>
public static void InitializeSerializer_FixedStringArray<T>() where T : unmanaged, INativeList<byte>, IUTF8Bytes
{
NetworkVariableSerialization<NativeArray<T>>.Serializer = new FixedStringArraySerializer<T>();
}
#if UNITY_NETCODE_NATIVE_COLLECTION_SUPPORT
/// <summary>
/// Registers a FixedString type that will be serialized through FastBufferReader/FastBufferWriter's FixedString
/// serializers
/// </summary>
/// <typeparam name="T"></typeparam>
public static void InitializeSerializer_FixedStringList<T>() where T : unmanaged, INativeList<byte>, IUTF8Bytes
{
NetworkVariableSerialization<NativeList<T>>.Serializer = new FixedStringListSerializer<T>();
}
#endif
/// <summary>
/// Registers a managed type that will be checked for equality using T.Equals()
/// </summary>
@@ -357,6 +767,26 @@ namespace Unity.Netcode
NetworkVariableSerialization<T>.AreEqual = NetworkVariableSerialization<T>.EqualityEquals;
}
/// <summary>
/// Registers an unmanaged type that will be checked for equality using T.Equals()
/// </summary>
/// <typeparam name="T"></typeparam>
public static void InitializeEqualityChecker_UnmanagedIEquatableArray<T>() where T : unmanaged, IEquatable<T>
{
NetworkVariableSerialization<NativeArray<T>>.AreEqual = NetworkVariableSerialization<T>.EqualityEqualsArray;
}
#if UNITY_NETCODE_NATIVE_COLLECTION_SUPPORT
/// <summary>
/// Registers an unmanaged type that will be checked for equality using T.Equals()
/// </summary>
/// <typeparam name="T"></typeparam>
public static void InitializeEqualityChecker_UnmanagedIEquatableList<T>() where T : unmanaged, IEquatable<T>
{
NetworkVariableSerialization<NativeList<T>>.AreEqual = NetworkVariableSerialization<T>.EqualityEqualsList;
}
#endif
/// <summary>
/// Registers an unmanaged type that will be checked for equality using memcmp and only considered
/// equal if they are bitwise equivalent in memory
@@ -367,6 +797,28 @@ namespace Unity.Netcode
NetworkVariableSerialization<T>.AreEqual = NetworkVariableSerialization<T>.ValueEquals;
}
/// <summary>
/// Registers an unmanaged type that will be checked for equality using memcmp and only considered
/// equal if they are bitwise equivalent in memory
/// </summary>
/// <typeparam name="T"></typeparam>
public static void InitializeEqualityChecker_UnmanagedValueEqualsArray<T>() where T : unmanaged
{
NetworkVariableSerialization<NativeArray<T>>.AreEqual = NetworkVariableSerialization<T>.ValueEqualsArray;
}
#if UNITY_NETCODE_NATIVE_COLLECTION_SUPPORT
/// <summary>
/// Registers an unmanaged type that will be checked for equality using memcmp and only considered
/// equal if they are bitwise equivalent in memory
/// </summary>
/// <typeparam name="T"></typeparam>
public static void InitializeEqualityChecker_UnmanagedValueEqualsList<T>() where T : unmanaged
{
NetworkVariableSerialization<NativeList<T>>.AreEqual = NetworkVariableSerialization<T>.ValueEqualsList;
}
#endif
/// <summary>
/// Registers a managed type that will be checked for equality using the == operator
/// </summary>
@@ -405,6 +857,58 @@ namespace Unity.Netcode
return UnsafeUtility.MemCmp(aptr, bptr, sizeof(TValueType)) == 0;
}
#if UNITY_NETCODE_NATIVE_COLLECTION_SUPPORT
// Compares two values of the same unmanaged type by underlying memory
// Ignoring any overridden value checks
// Size is fixed
internal static unsafe bool ValueEqualsList<TValueType>(ref NativeList<TValueType> a, ref NativeList<TValueType> b) where TValueType : unmanaged
{
if (a.IsCreated != b.IsCreated)
{
return false;
}
if (!a.IsCreated)
{
return true;
}
if (a.Length != b.Length)
{
return false;
}
var aptr = (TValueType*)a.GetUnsafePtr();
var bptr = (TValueType*)b.GetUnsafePtr();
return UnsafeUtility.MemCmp(aptr, bptr, sizeof(TValueType) * a.Length) == 0;
}
#endif
// Compares two values of the same unmanaged type by underlying memory
// Ignoring any overridden value checks
// Size is fixed
internal static unsafe bool ValueEqualsArray<TValueType>(ref NativeArray<TValueType> a, ref NativeArray<TValueType> b) where TValueType : unmanaged
{
if (a.IsCreated != b.IsCreated)
{
return false;
}
if (!a.IsCreated)
{
return true;
}
if (a.Length != b.Length)
{
return false;
}
var aptr = (TValueType*)a.GetUnsafePtr();
var bptr = (TValueType*)b.GetUnsafePtr();
return UnsafeUtility.MemCmp(aptr, bptr, sizeof(TValueType) * a.Length) == 0;
}
internal static bool EqualityEqualsObject<TValueType>(ref TValueType a, ref TValueType b) where TValueType : class, IEquatable<TValueType>
{
if (a == null)
@@ -425,6 +929,74 @@ namespace Unity.Netcode
return a.Equals(b);
}
#if UNITY_NETCODE_NATIVE_COLLECTION_SUPPORT
// Compares two values of the same unmanaged type by underlying memory
// Ignoring any overridden value checks
// Size is fixed
internal static unsafe bool EqualityEqualsList<TValueType>(ref NativeList<TValueType> a, ref NativeList<TValueType> b) where TValueType : unmanaged, IEquatable<TValueType>
{
if (a.IsCreated != b.IsCreated)
{
return false;
}
if (!a.IsCreated)
{
return true;
}
if (a.Length != b.Length)
{
return false;
}
var aptr = (TValueType*)a.GetUnsafePtr();
var bptr = (TValueType*)b.GetUnsafePtr();
for (var i = 0; i < a.Length; ++i)
{
if (!EqualityEquals(ref aptr[i], ref bptr[i]))
{
return false;
}
}
return true;
}
#endif
// Compares two values of the same unmanaged type by underlying memory
// Ignoring any overridden value checks
// Size is fixed
internal static unsafe bool EqualityEqualsArray<TValueType>(ref NativeArray<TValueType> a, ref NativeArray<TValueType> b) where TValueType : unmanaged, IEquatable<TValueType>
{
if (a.IsCreated != b.IsCreated)
{
return false;
}
if (!a.IsCreated)
{
return true;
}
if (a.Length != b.Length)
{
return false;
}
var aptr = (TValueType*)a.GetUnsafePtr();
var bptr = (TValueType*)b.GetUnsafePtr();
for (var i = 0; i < a.Length; ++i)
{
if (!EqualityEquals(ref aptr[i], ref bptr[i]))
{
return false;
}
}
return true;
}
internal static bool ClassEquals<TValueType>(ref TValueType a, ref TValueType b) where TValueType : class
{
return a == b;