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:
@@ -51,7 +51,7 @@ namespace Unity.Netcode
|
||||
/// </summary>
|
||||
public static void SetDefaults()
|
||||
{
|
||||
SetDefault<IDeferredMessageManager>(networkManager => new DeferredMessageManager(networkManager));
|
||||
SetDefault<IDeferredNetworkMessageManager>(networkManager => new DeferredMessageManager(networkManager));
|
||||
|
||||
SetDefault<IRealTimeProvider>(networkManager => new RealTimeProvider());
|
||||
}
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using Unity.Collections;
|
||||
using UnityEngine;
|
||||
|
||||
@@ -65,7 +63,7 @@ namespace Unity.Netcode
|
||||
networkDelivery = NetworkDelivery.ReliableFragmentedSequenced;
|
||||
break;
|
||||
case RpcDelivery.Unreliable:
|
||||
if (bufferWriter.Length > MessagingSystem.NON_FRAGMENTED_MESSAGE_MAX_SIZE)
|
||||
if (bufferWriter.Length > NetworkManager.MessageManager.NonFragmentedMessageMaxSize)
|
||||
{
|
||||
throw new OverflowException("RPC parameters are too large for unreliable delivery.");
|
||||
}
|
||||
@@ -86,7 +84,7 @@ namespace Unity.Netcode
|
||||
SystemOwner = NetworkManager,
|
||||
// header information isn't valid since it's not a real message.
|
||||
// RpcMessage doesn't access this stuff so it's just left empty.
|
||||
Header = new MessageHeader(),
|
||||
Header = new NetworkMessageHeader(),
|
||||
SerializedHeaderSize = 0,
|
||||
MessageSize = 0
|
||||
};
|
||||
@@ -96,7 +94,7 @@ namespace Unity.Netcode
|
||||
}
|
||||
else
|
||||
{
|
||||
rpcWriteSize = NetworkManager.SendMessage(ref serverRpcMessage, networkDelivery, NetworkManager.ServerClientId);
|
||||
rpcWriteSize = NetworkManager.ConnectionManager.SendMessage(ref serverRpcMessage, networkDelivery, NetworkManager.ServerClientId);
|
||||
}
|
||||
|
||||
bufferWriter.Dispose();
|
||||
@@ -146,7 +144,7 @@ namespace Unity.Netcode
|
||||
networkDelivery = NetworkDelivery.ReliableFragmentedSequenced;
|
||||
break;
|
||||
case RpcDelivery.Unreliable:
|
||||
if (bufferWriter.Length > MessagingSystem.NON_FRAGMENTED_MESSAGE_MAX_SIZE)
|
||||
if (bufferWriter.Length > NetworkManager.MessageManager.NonFragmentedMessageMaxSize)
|
||||
{
|
||||
throw new OverflowException("RPC parameters are too large for unreliable delivery.");
|
||||
}
|
||||
@@ -176,7 +174,7 @@ namespace Unity.Netcode
|
||||
}
|
||||
}
|
||||
|
||||
rpcWriteSize = NetworkManager.SendMessage(ref clientRpcMessage, networkDelivery, in clientRpcParams.Send.TargetClientIds);
|
||||
rpcWriteSize = NetworkManager.ConnectionManager.SendMessage(ref clientRpcMessage, networkDelivery, in clientRpcParams.Send.TargetClientIds);
|
||||
}
|
||||
else if (clientRpcParams.Send.TargetClientIdsNativeArray != null)
|
||||
{
|
||||
@@ -195,7 +193,7 @@ namespace Unity.Netcode
|
||||
}
|
||||
}
|
||||
|
||||
rpcWriteSize = NetworkManager.SendMessage(ref clientRpcMessage, networkDelivery, clientRpcParams.Send.TargetClientIdsNativeArray.Value);
|
||||
rpcWriteSize = NetworkManager.ConnectionManager.SendMessage(ref clientRpcMessage, networkDelivery, clientRpcParams.Send.TargetClientIdsNativeArray.Value);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -208,7 +206,7 @@ namespace Unity.Netcode
|
||||
shouldSendToHost = true;
|
||||
continue;
|
||||
}
|
||||
rpcWriteSize = NetworkManager.MessagingSystem.SendMessage(ref clientRpcMessage, networkDelivery, observerEnumerator.Current);
|
||||
rpcWriteSize = NetworkManager.ConnectionManager.SendMessage(ref clientRpcMessage, networkDelivery, observerEnumerator.Current);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -223,7 +221,7 @@ namespace Unity.Netcode
|
||||
SystemOwner = NetworkManager,
|
||||
// header information isn't valid since it's not a real message.
|
||||
// RpcMessage doesn't access this stuff so it's just left empty.
|
||||
Header = new MessageHeader(),
|
||||
Header = new NetworkMessageHeader(),
|
||||
SerializedHeaderSize = 0,
|
||||
MessageSize = 0
|
||||
};
|
||||
@@ -277,6 +275,14 @@ namespace Unity.Netcode
|
||||
#endif
|
||||
}
|
||||
|
||||
#pragma warning disable IDE1006 // disable naming rule violation check
|
||||
// RuntimeAccessModifiersILPP will make this `protected`
|
||||
internal static NativeList<T> __createNativeList<T>() where T : unmanaged
|
||||
#pragma warning restore IDE1006 // restore naming rule violation check
|
||||
{
|
||||
return new NativeList<T>(Allocator.Temp);
|
||||
}
|
||||
|
||||
internal string GenerateObserverErrorMessage(ClientRpcParams clientRpcParams, ulong targetClientId)
|
||||
{
|
||||
var containerNameHoldingId = clientRpcParams.Send.TargetClientIds != null ? nameof(ClientRpcParams.Send.TargetClientIds) : nameof(ClientRpcParams.Send.TargetClientIdsNativeArray);
|
||||
@@ -551,35 +557,25 @@ namespace Unity.Netcode
|
||||
|
||||
private readonly List<HashSet<int>> m_DeliveryMappedNetworkVariableIndices = new List<HashSet<int>>();
|
||||
private readonly List<NetworkDelivery> m_DeliveryTypesForNetworkVariableGroups = new List<NetworkDelivery>();
|
||||
|
||||
// RuntimeAccessModifiersILPP will make this `protected`
|
||||
internal readonly List<NetworkVariableBase> NetworkVariableFields = new List<NetworkVariableBase>();
|
||||
|
||||
private static Dictionary<Type, FieldInfo[]> s_FieldTypes = new Dictionary<Type, FieldInfo[]>();
|
||||
|
||||
private static FieldInfo[] GetFieldInfoForType(Type type)
|
||||
#pragma warning disable IDE1006 // disable naming rule violation check
|
||||
// RuntimeAccessModifiersILPP will make this `protected`
|
||||
internal virtual void __initializeVariables()
|
||||
#pragma warning restore IDE1006 // restore naming rule violation check
|
||||
{
|
||||
if (!s_FieldTypes.ContainsKey(type))
|
||||
{
|
||||
s_FieldTypes.Add(type, GetFieldInfoForTypeRecursive(type));
|
||||
}
|
||||
|
||||
return s_FieldTypes[type];
|
||||
// ILPP generates code for all NetworkBehaviour subtypes to initialize each type's network variables.
|
||||
}
|
||||
|
||||
private static FieldInfo[] GetFieldInfoForTypeRecursive(Type type, List<FieldInfo> list = null)
|
||||
#pragma warning disable IDE1006 // disable naming rule violation check
|
||||
// RuntimeAccessModifiersILPP will make this `protected`
|
||||
// Using this method here because ILPP doesn't seem to let us do visibility modification on properties.
|
||||
internal void __nameNetworkVariable(NetworkVariableBase variable, string varName)
|
||||
#pragma warning restore IDE1006 // restore naming rule violation check
|
||||
{
|
||||
if (list == null)
|
||||
{
|
||||
list = new List<FieldInfo>();
|
||||
}
|
||||
|
||||
list.AddRange(type.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly));
|
||||
|
||||
if (type.BaseType != null && type.BaseType != typeof(NetworkBehaviour))
|
||||
{
|
||||
return GetFieldInfoForTypeRecursive(type.BaseType, list);
|
||||
}
|
||||
|
||||
return list.OrderBy(x => x.Name, StringComparer.Ordinal).ToArray();
|
||||
variable.Name = varName;
|
||||
}
|
||||
|
||||
internal void InitializeVariables()
|
||||
@@ -591,22 +587,7 @@ namespace Unity.Netcode
|
||||
|
||||
m_VarInit = true;
|
||||
|
||||
var sortedFields = GetFieldInfoForType(GetType());
|
||||
for (int i = 0; i < sortedFields.Length; i++)
|
||||
{
|
||||
var fieldType = sortedFields[i].FieldType;
|
||||
if (fieldType.IsSubclassOf(typeof(NetworkVariableBase)))
|
||||
{
|
||||
var instance = (NetworkVariableBase)sortedFields[i].GetValue(this) ?? throw new Exception($"{GetType().FullName}.{sortedFields[i].Name} cannot be null. All {nameof(NetworkVariableBase)} instances must be initialized.");
|
||||
instance.Initialize(this);
|
||||
|
||||
var instanceNameProperty = fieldType.GetProperty(nameof(NetworkVariableBase.Name));
|
||||
var sanitizedVariableName = sortedFields[i].Name.Replace("<", string.Empty).Replace(">k__BackingField", string.Empty);
|
||||
instanceNameProperty?.SetValue(instance, sanitizedVariableName);
|
||||
|
||||
NetworkVariableFields.Add(instance);
|
||||
}
|
||||
}
|
||||
__initializeVariables();
|
||||
|
||||
{
|
||||
// Create index map for delivery types
|
||||
@@ -718,7 +699,7 @@ namespace Unity.Netcode
|
||||
// so we don't have to do this serialization work if we're not going to use the result.
|
||||
if (IsServer && targetClientId == NetworkManager.ServerClientId)
|
||||
{
|
||||
var tmpWriter = new FastBufferWriter(MessagingSystem.NON_FRAGMENTED_MESSAGE_MAX_SIZE, Allocator.Temp, MessagingSystem.FRAGMENTED_MESSAGE_MAX_SIZE);
|
||||
var tmpWriter = new FastBufferWriter(NetworkManager.MessageManager.NonFragmentedMessageMaxSize, Allocator.Temp, NetworkManager.MessageManager.FragmentedMessageMaxSize);
|
||||
using (tmpWriter)
|
||||
{
|
||||
message.Serialize(tmpWriter, message.Version);
|
||||
@@ -726,7 +707,7 @@ namespace Unity.Netcode
|
||||
}
|
||||
else
|
||||
{
|
||||
NetworkManager.SendMessage(ref message, m_DeliveryTypesForNetworkVariableGroups[j], targetClientId);
|
||||
NetworkManager.ConnectionManager.SendMessage(ref message, m_DeliveryTypesForNetworkVariableGroups[j], targetClientId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,8 @@ namespace Unity.Netcode
|
||||
/// </summary>
|
||||
public class NetworkBehaviourUpdater
|
||||
{
|
||||
private NetworkManager m_NetworkManager;
|
||||
private NetworkConnectionManager m_ConnectionManager;
|
||||
private HashSet<NetworkObject> m_DirtyNetworkObjects = new HashSet<NetworkObject>();
|
||||
|
||||
#if DEVELOPMENT_BUILD || UNITY_EDITOR
|
||||
@@ -19,7 +21,7 @@ namespace Unity.Netcode
|
||||
m_DirtyNetworkObjects.Add(networkObject);
|
||||
}
|
||||
|
||||
internal void NetworkBehaviourUpdate(NetworkManager networkManager)
|
||||
internal void NetworkBehaviourUpdate()
|
||||
{
|
||||
#if DEVELOPMENT_BUILD || UNITY_EDITOR
|
||||
m_NetworkBehaviourUpdate.Begin();
|
||||
@@ -30,7 +32,7 @@ namespace Unity.Netcode
|
||||
// trying to process them, even if they were previously marked as dirty.
|
||||
m_DirtyNetworkObjects.RemoveWhere((sobj) => sobj == null);
|
||||
|
||||
if (networkManager.IsServer)
|
||||
if (m_ConnectionManager.LocalClient.IsServer)
|
||||
{
|
||||
foreach (var dirtyObj in m_DirtyNetworkObjects)
|
||||
{
|
||||
@@ -39,9 +41,9 @@ namespace Unity.Netcode
|
||||
dirtyObj.ChildNetworkBehaviours[k].PreVariableUpdate();
|
||||
}
|
||||
|
||||
for (int i = 0; i < networkManager.ConnectedClientsList.Count; i++)
|
||||
for (int i = 0; i < m_ConnectionManager.ConnectedClientsList.Count; i++)
|
||||
{
|
||||
var client = networkManager.ConnectedClientsList[i];
|
||||
var client = m_ConnectionManager.ConnectedClientsList[i];
|
||||
|
||||
if (dirtyObj.IsNetworkVisibleTo(client.ClientId))
|
||||
{
|
||||
@@ -104,5 +106,26 @@ namespace Unity.Netcode
|
||||
}
|
||||
}
|
||||
|
||||
internal void Initialize(NetworkManager networkManager)
|
||||
{
|
||||
m_NetworkManager = networkManager;
|
||||
m_ConnectionManager = networkManager.ConnectionManager;
|
||||
m_NetworkManager.NetworkTickSystem.Tick += NetworkBehaviourUpdater_Tick;
|
||||
}
|
||||
|
||||
internal void Shutdown()
|
||||
{
|
||||
m_NetworkManager.NetworkTickSystem.Tick -= NetworkBehaviourUpdater_Tick;
|
||||
}
|
||||
|
||||
// TODO 2023-Q2: Order of operations requires NetworkVariable updates first then showing NetworkObjects
|
||||
private void NetworkBehaviourUpdater_Tick()
|
||||
{
|
||||
// First update NetworkVariables
|
||||
NetworkBehaviourUpdate();
|
||||
|
||||
// Then show any NetworkObjects queued to be made visible/shown
|
||||
m_NetworkManager.SpawnManager.HandleNetworkObjectShow();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -188,6 +188,12 @@ namespace Unity.Netcode
|
||||
/// </remarks>
|
||||
public Action OnMigratedToNewScene;
|
||||
|
||||
/// <summary>
|
||||
/// When set to false, the NetworkObject will be spawned with no observers initially (other than the server)
|
||||
/// </summary>
|
||||
[Tooltip("When false, the NetworkObject will spawn with no observers initially. (default is true)")]
|
||||
public bool SpawnWithObservers = true;
|
||||
|
||||
/// <summary>
|
||||
/// Delegate type for checking visibility
|
||||
/// </summary>
|
||||
@@ -361,8 +367,7 @@ namespace Unity.Netcode
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
NetworkManager.MarkObjectForShowingTo(this, clientId);
|
||||
NetworkManager.SpawnManager.MarkObjectForShowingTo(this, clientId);
|
||||
Observers.Add(clientId);
|
||||
}
|
||||
|
||||
@@ -452,7 +457,7 @@ namespace Unity.Netcode
|
||||
throw new VisibilityChangeException("Cannot hide an object from the server");
|
||||
}
|
||||
|
||||
if (!NetworkManager.RemoveObjectFromShowingTo(this, clientId))
|
||||
if (!NetworkManager.SpawnManager.RemoveObjectFromShowingTo(this, clientId))
|
||||
{
|
||||
if (!Observers.Contains(clientId))
|
||||
{
|
||||
@@ -466,7 +471,7 @@ namespace Unity.Netcode
|
||||
DestroyGameObject = !IsSceneObject.Value
|
||||
};
|
||||
// Send destroy call
|
||||
var size = NetworkManager.SendMessage(ref message, NetworkDelivery.ReliableSequenced, clientId);
|
||||
var size = NetworkManager.ConnectionManager.SendMessage(ref message, NetworkDelivery.ReliableSequenced, clientId);
|
||||
NetworkManager.NetworkMetrics.TrackObjectDestroySent(clientId, this, size);
|
||||
}
|
||||
}
|
||||
@@ -532,14 +537,30 @@ namespace Unity.Netcode
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
if (NetworkManager != null && NetworkManager.IsListening && NetworkManager.IsServer == false && IsSpawned &&
|
||||
(IsSceneObject == null || (IsSceneObject.Value != true)))
|
||||
// If no NetworkManager is assigned, then just exit early
|
||||
if (!NetworkManager)
|
||||
{
|
||||
throw new NotServerException($"Destroy a spawned {nameof(NetworkObject)} on a non-host client is not valid. Call {nameof(Destroy)} or {nameof(Despawn)} on the server/host instead.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (NetworkManager != null && NetworkManager.SpawnManager != null &&
|
||||
NetworkManager.SpawnManager.SpawnedObjects.TryGetValue(NetworkObjectId, out var networkObject))
|
||||
if (NetworkManager.IsListening && !NetworkManager.IsServer && IsSpawned &&
|
||||
(IsSceneObject == null || (IsSceneObject.Value != true)))
|
||||
{
|
||||
// Clients should not despawn NetworkObjects while connected to a session, but we don't want to destroy the current call stack
|
||||
// if this happens. Instead, we should just generate a network log error and exit early (as long as we are not shutting down).
|
||||
if (!NetworkManager.ShutdownInProgress)
|
||||
{
|
||||
// Since we still have a session connection, log locally and on the server to inform user of this issue.
|
||||
if (NetworkManager.LogLevel <= LogLevel.Error)
|
||||
{
|
||||
NetworkLog.LogErrorServer($"Destroy a spawned {nameof(NetworkObject)} on a non-host client is not valid. Call {nameof(Destroy)} or {nameof(Despawn)} on the server/host instead.");
|
||||
}
|
||||
return;
|
||||
}
|
||||
// Otherwise, clients can despawn NetworkObjects while shutting down and should not generate any messages when this happens
|
||||
}
|
||||
|
||||
if (NetworkManager.SpawnManager != null && NetworkManager.SpawnManager.SpawnedObjects.TryGetValue(NetworkObjectId, out var networkObject))
|
||||
{
|
||||
if (this == networkObject)
|
||||
{
|
||||
@@ -898,7 +919,7 @@ namespace Unity.Netcode
|
||||
}
|
||||
}
|
||||
|
||||
NetworkManager.SendMessage(ref message, NetworkDelivery.ReliableSequenced, clientIds, idx);
|
||||
NetworkManager.ConnectionManager.SendMessage(ref message, NetworkDelivery.ReliableSequenced, clientIds, idx);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user