com.unity.netcode.gameobjects@1.7.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.7.0] - 2023-10-11 ### Added - exposed NetworkObject.GetNetworkBehaviourAtOrderIndex as a public API (#2724) - Added context menu tool that provides users with the ability to quickly update the GlobalObjectIdHash value for all in-scene placed prefab instances that were created prior to adding a NetworkObject component to it. (#2707) - Added methods NetworkManager.SetPeerMTU and NetworkManager.GetPeerMTU to be able to set MTU sizes per-peer (#2676) - Added `GenerateSerializationForGenericParameterAttribute`, which can be applied to user-created Network Variable types to ensure the codegen generates serialization for the generic types they wrap. (#2694) - Added `GenerateSerializationForTypeAttribute`, which can be applied to any class or method to ensure the codegen generates serialization for the specific provided type. (#2694) - Exposed `NetworkVariableSerialization<T>.Read`, `NetworkVariableSerialization<T>.Write`, `NetworkVariableSerialization<T>.AreEqual`, and `NetworkVariableSerialization<T>.Duplicate` to further support the creation of user-created network variables by allowing users to access the generated serialization methods and serialize generic types efficiently without boxing. (#2694) - Added `NetworkVariableBase.MarkNetworkBehaviourDirty` so that user-created network variable types can mark their containing `NetworkBehaviour` to be processed by the update loop. (#2694) ### Fixed - Fixed issue where the server side `NetworkSceneManager` instance was not adding the currently active scene to its list of scenes loaded. (#2723) - Generic NetworkBehaviour types no longer result in compile errors or runtime errors (#2720) - Rpcs within Generic NetworkBehaviour types can now serialize parameters of the class's generic types (but may not have generic types of their own) (#2720) - Errors are no longer thrown when entering play mode with domain reload disabled (#2720) - NetworkSpawn is now correctly called each time when entering play mode with scene reload disabled (#2720) - NetworkVariables of non-integer types will no longer break the inspector (#2714) - NetworkVariables with NonSerializedAttribute will not appear in the inspector (#2714) - Fixed issue where `UnityTransport` would attempt to establish WebSocket connections even if using UDP/DTLS Relay allocations when the build target was WebGL. This only applied to working in the editor since UDP/DTLS can't work in the browser. (#2695) - Fixed issue where a `NetworkBehaviour` component's `OnNetworkDespawn` was not being invoked on the host-server side for an in-scene placed `NetworkObject` when a scene was unloaded (during a scene transition) and the `NetworkBehaviour` component was positioned/ordered before the `NetworkObject` component. (#2685) - Fixed issue where `SpawnWithObservers` was not being honored when `NetworkConfig.EnableSceneManagement` was disabled. (#2682) - Fixed issue where `NetworkAnimator` was not internally tracking changes to layer weights which prevented proper layer weight synchronization back to the original layer weight value. (#2674) - Fixed "writing past the end of the buffer" error when calling ResetDirty() on managed network variables that are larger than 256 bytes when serialized. (#2670) - Fixed issue where generation of the `DefaultNetworkPrefabs` asset was not enabled by default. (#2662) - Fixed issue where the `GlobalObjectIdHash` value could be updated but the asset not marked as dirty. (#2662) - Fixed issue where the `GlobalObjectIdHash` value of a (network) prefab asset could be assigned an incorrect value when editing the prefab in a temporary scene. (#2662) - Fixed issue where the `GlobalObjectIdHash` value generated after creating a (network) prefab from an object constructed within the scene would not be the correct final value in a stand alone build. (#2662) ### Changed - Updated dependency on `com.unity.transport` to version 1.4.0. (#2716)
This commit is contained in:
@@ -1,7 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Unity.Collections;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Unity.Netcode
|
||||
{
|
||||
@@ -9,6 +8,7 @@ namespace Unity.Netcode
|
||||
/// Event based NetworkVariable container for syncing Lists
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type for the list</typeparam>
|
||||
[GenerateSerializationForGenericParameter(0)]
|
||||
public class NetworkList<T> : NetworkVariableBase where T : unmanaged, IEquatable<T>
|
||||
{
|
||||
private NativeList<T> m_List = new NativeList<T>(64, Allocator.Persistent);
|
||||
@@ -68,14 +68,7 @@ namespace Unity.Netcode
|
||||
|
||||
internal void MarkNetworkObjectDirty()
|
||||
{
|
||||
if (m_NetworkBehaviour == null)
|
||||
{
|
||||
Debug.LogWarning($"NetworkList is written to, but doesn't know its NetworkBehaviour yet. " +
|
||||
"Are you modifying a NetworkList before the NetworkObject is spawned?");
|
||||
return;
|
||||
}
|
||||
|
||||
m_NetworkBehaviour.NetworkManager.BehaviourUpdater.AddForUpdate(m_NetworkBehaviour.NetworkObject);
|
||||
MarkNetworkBehaviourDirty();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
||||
@@ -8,6 +8,7 @@ namespace Unity.Netcode
|
||||
/// </summary>
|
||||
/// <typeparam name="T">the unmanaged type for <see cref="NetworkVariable{T}"/> </typeparam>
|
||||
[Serializable]
|
||||
[GenerateSerializationForGenericParameter(0)]
|
||||
public class NetworkVariable<T> : NetworkVariableBase
|
||||
{
|
||||
/// <summary>
|
||||
@@ -146,8 +147,11 @@ namespace Unity.Netcode
|
||||
// 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);
|
||||
if (!m_HasPreviousValue || !NetworkVariableSerialization<T>.AreEqual(ref m_InternalValue, ref m_PreviousValue))
|
||||
{
|
||||
m_HasPreviousValue = true;
|
||||
NetworkVariableSerialization<T>.Duplicate(m_InternalValue, ref m_PreviousValue);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -88,17 +88,22 @@ namespace Unity.Netcode
|
||||
|
||||
if (m_IsDirty)
|
||||
{
|
||||
if (m_NetworkBehaviour == null)
|
||||
{
|
||||
Debug.LogWarning($"NetworkVariable is written to, but doesn't know its NetworkBehaviour yet. " +
|
||||
"Are you modifying a NetworkVariable before the NetworkObject is spawned?");
|
||||
return;
|
||||
}
|
||||
|
||||
m_NetworkBehaviour.NetworkManager.BehaviourUpdater.AddForUpdate(m_NetworkBehaviour.NetworkObject);
|
||||
MarkNetworkBehaviourDirty();
|
||||
}
|
||||
}
|
||||
|
||||
protected void MarkNetworkBehaviourDirty()
|
||||
{
|
||||
if (m_NetworkBehaviour == null)
|
||||
{
|
||||
Debug.LogWarning($"NetworkVariable is written to, but doesn't know its NetworkBehaviour yet. " +
|
||||
"Are you modifying a NetworkVariable before the NetworkObject is spawned?");
|
||||
return;
|
||||
}
|
||||
|
||||
m_NetworkBehaviour.NetworkManager.BehaviourUpdater.AddForUpdate(m_NetworkBehaviour.NetworkObject);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resets the dirty state and marks the variable as synced / clean
|
||||
/// </summary>
|
||||
|
||||
@@ -514,7 +514,7 @@ namespace Unity.Netcode
|
||||
|
||||
public void Duplicate(in T value, ref T duplicatedValue)
|
||||
{
|
||||
using var writer = new FastBufferWriter(256, Allocator.Temp);
|
||||
using var writer = new FastBufferWriter(256, Allocator.Temp, int.MaxValue);
|
||||
var refValue = value;
|
||||
Write(writer, ref refValue);
|
||||
|
||||
@@ -580,11 +580,16 @@ namespace Unity.Netcode
|
||||
/// <typeparam name="T"></typeparam>
|
||||
internal class FallbackSerializer<T> : INetworkVariableSerializer<T>
|
||||
{
|
||||
private void ThrowArgumentError()
|
||||
{
|
||||
throw new ArgumentException($"Serialization has not been generated for type {typeof(T).FullName}. This can be addressed by adding a [{nameof(GenerateSerializationForGenericParameterAttribute)}] to your generic class that serializes this value (if you are using one), adding [{nameof(GenerateSerializationForTypeAttribute)}(typeof({typeof(T).FullName})] to the class or method that is attempting to serialize it, or creating a field on a {nameof(NetworkBehaviour)} of type {nameof(NetworkVariable<T>)}. If this error continues to appear after doing one of those things and 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 to enable automatic serialization generation. 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}.");
|
||||
}
|
||||
|
||||
public void Write(FastBufferWriter writer, ref T value)
|
||||
{
|
||||
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}.");
|
||||
ThrowArgumentError();
|
||||
}
|
||||
UserNetworkVariableSerialization<T>.WriteValue(writer, value);
|
||||
}
|
||||
@@ -592,7 +597,7 @@ namespace Unity.Netcode
|
||||
{
|
||||
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}.");
|
||||
ThrowArgumentError();
|
||||
}
|
||||
UserNetworkVariableSerialization<T>.ReadValue(reader, out value);
|
||||
}
|
||||
@@ -606,7 +611,7 @@ namespace Unity.Netcode
|
||||
{
|
||||
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}.");
|
||||
ThrowArgumentError();
|
||||
}
|
||||
UserNetworkVariableSerialization<T>.DuplicateValue(value, ref duplicatedValue);
|
||||
}
|
||||
@@ -841,8 +846,95 @@ namespace Unity.Netcode
|
||||
{
|
||||
internal static INetworkVariableSerializer<T> Serializer = new FallbackSerializer<T>();
|
||||
|
||||
internal delegate bool EqualsDelegate(ref T a, ref T b);
|
||||
internal static EqualsDelegate AreEqual;
|
||||
/// <summary>
|
||||
/// A callback to check if two values are equal.
|
||||
/// </summary>
|
||||
public delegate bool EqualsDelegate(ref T a, ref T b);
|
||||
|
||||
/// <summary>
|
||||
/// Uses the most efficient mechanism for a given type to determine if two values are equal.
|
||||
/// For types that implement <see cref="IEquatable{T}"/>, it will call the Equals() method.
|
||||
/// For unmanaged types, it will do a bytewise memory comparison.
|
||||
/// For other types, it will call the == operator.
|
||||
/// <br/>
|
||||
/// <br/>
|
||||
/// Note: If you are using this in a custom generic class, please make sure your class is
|
||||
/// decorated with <see cref="GenerateSerializationForGenericParameterAttribute"/> so that codegen can
|
||||
/// initialize the serialization mechanisms correctly. If your class is NOT
|
||||
/// generic, it is better to check their equality yourself.
|
||||
/// </summary>
|
||||
public static EqualsDelegate AreEqual { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Serialize a value using the best-known serialization method for a generic value.
|
||||
/// Will reliably serialize any value that is passed to it correctly with no boxing.
|
||||
/// <br/>
|
||||
/// <br/>
|
||||
/// Note: If you are using this in a custom generic class, please make sure your class is
|
||||
/// decorated with <see cref="GenerateSerializationForGenericParameterAttribute"/> so that codegen can
|
||||
/// initialize the serialization mechanisms correctly. If your class is NOT
|
||||
/// generic, it is better to use FastBufferWriter directly.
|
||||
/// <br/>
|
||||
/// <br/>
|
||||
/// If the codegen is unable to determine a serializer for a type,
|
||||
/// <see cref="UserNetworkVariableSerialization{T}"/>.<see cref="UserNetworkVariableSerialization{T}.WriteValue"/> is called, which, by default,
|
||||
/// will throw an exception, unless you have assigned a user serialization callback to it at runtime.
|
||||
/// </summary>
|
||||
/// <param name="writer"></param>
|
||||
/// <param name="value"></param>
|
||||
public static void Write(FastBufferWriter writer, ref T value)
|
||||
{
|
||||
Serializer.Write(writer, ref value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deserialize a value using the best-known serialization method for a generic value.
|
||||
/// Will reliably deserialize any value that is passed to it correctly with no boxing.
|
||||
/// For types whose deserialization can be determined by codegen (which is most types),
|
||||
/// GC will only be incurred if the type is a managed type and the ref value passed in is `null`,
|
||||
/// in which case a new value is created; otherwise, it will be deserialized in-place.
|
||||
/// <br/>
|
||||
/// <br/>
|
||||
/// Note: If you are using this in a custom generic class, please make sure your class is
|
||||
/// decorated with <see cref="GenerateSerializationForGenericParameterAttribute"/> so that codegen can
|
||||
/// initialize the serialization mechanisms correctly. If your class is NOT
|
||||
/// generic, it is better to use FastBufferReader directly.
|
||||
/// <br/>
|
||||
/// <br/>
|
||||
/// If the codegen is unable to determine a serializer for a type,
|
||||
/// <see cref="UserNetworkVariableSerialization{T}"/>.<see cref="UserNetworkVariableSerialization{T}.ReadValue"/> is called, which, by default,
|
||||
/// will throw an exception, unless you have assigned a user deserialization callback to it at runtime.
|
||||
/// </summary>
|
||||
/// <param name="reader"></param>
|
||||
/// <param name="value"></param>
|
||||
public static void Read(FastBufferReader reader, ref T value)
|
||||
{
|
||||
Serializer.Read(reader, ref value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Duplicates a value using the most efficient means of creating a complete copy.
|
||||
/// For most types this is a simple assignment or memcpy.
|
||||
/// For managed types, this is will serialize and then deserialize the value to ensure
|
||||
/// a correct copy.
|
||||
/// <br/>
|
||||
/// <br/>
|
||||
/// Note: If you are using this in a custom generic class, please make sure your class is
|
||||
/// decorated with <see cref="GenerateSerializationForGenericParameterAttribute"/> so that codegen can
|
||||
/// initialize the serialization mechanisms correctly. If your class is NOT
|
||||
/// generic, it is better to duplicate it directly.
|
||||
/// <br/>
|
||||
/// <br/>
|
||||
/// If the codegen is unable to determine a serializer for a type,
|
||||
/// <see cref="UserNetworkVariableSerialization{T}"/>.<see cref="UserNetworkVariableSerialization{T}.DuplicateValue"/> is called, which, by default,
|
||||
/// will throw an exception, unless you have assigned a user duplication callback to it at runtime.
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
/// <param name="duplicatedValue"></param>
|
||||
public static void Duplicate(in T value, ref T duplicatedValue)
|
||||
{
|
||||
Serializer.Duplicate(value, ref duplicatedValue);
|
||||
}
|
||||
|
||||
// Compares two values of the same unmanaged type by underlying memory
|
||||
// Ignoring any overridden value checks
|
||||
@@ -1001,15 +1093,21 @@ namespace Unity.Netcode
|
||||
{
|
||||
return a == b;
|
||||
}
|
||||
}
|
||||
|
||||
internal static void Write(FastBufferWriter writer, ref T value)
|
||||
// RuntimeAccessModifiersILPP will make this `public`
|
||||
// This is just pass-through to NetworkVariableSerialization<T> but is here becaues I could not get ILPP
|
||||
// to generate code that would successfully call Type<T>.Method(T), but it has no problem calling Type.Method<T>(T)
|
||||
internal class RpcFallbackSerialization
|
||||
{
|
||||
public static void Write<T>(FastBufferWriter writer, ref T value)
|
||||
{
|
||||
Serializer.Write(writer, ref value);
|
||||
NetworkVariableSerialization<T>.Write(writer, ref value);
|
||||
}
|
||||
|
||||
internal static void Read(FastBufferReader reader, ref T value)
|
||||
public static void Read<T>(FastBufferReader reader, ref T value)
|
||||
{
|
||||
Serializer.Read(reader, ref value);
|
||||
NetworkVariableSerialization<T>.Read(reader, ref value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user