Skip to content

Commit 69dce92

Browse files
committed
Merge branch 'develop-2.0.0' into chore/fast-enter-playmode
# Conflicts: # com.unity.netcode.gameobjects/Runtime/Logging/NetworkLog.cs
2 parents 5ab98dc + 214c792 commit 69dce92

34 files changed

Lines changed: 1105 additions & 624 deletions

com.unity.netcode.gameobjects/CHANGELOG.md

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,31 +13,43 @@ Additional documentation and release notes are available at [Multiplayer Documen
1313

1414
### Changed
1515

16-
- Hardened error handling and recovery during `NetworkObject` spawn. (#3941)
17-
- Replaced Debug usage by NetcodeLog on `NetworkSpawnManager` and `NetworkObject`. (#3933)
18-
- Improved performance of `NetworkBehaviour`. (#3915)
19-
- Improved performance of `NetworkTransform`. (#3907)
20-
- Improved performance of `NetworkRigidbodyBase`. (#3906)
21-
- Improved performance of `NetworkAnimator`. (#3905)
2216

2317
### Deprecated
2418

2519

2620
### Removed
2721

28-
- Removed un-needed exceptions on `NetworkSpawnManager`. (#3933)
2922

3023
### Fixed
3124

32-
- Fixed issue where either an `AttachableBehaviour` or an `AttachableNode` can throw an exception if they are attached during a scene unload where one of the two persists the scene unload event and the other does not. (#3931)
33-
- Fixed issue where attempts to use `NetworkLog` when there is no `NetworkManager` instance would result in an exception. (#3917)
3425

3526
### Security
3627

3728

3829
### Obsolete
3930

4031

32+
## [2.11.1] - 2026-04-26
33+
34+
### Changed
35+
36+
- Improve handling of destroyed NetworkBehaviours. (#3953)
37+
- Hardened error handling and recovery during `NetworkObject` spawn. (#3941)
38+
- Replaced Debug usage by NetcodeLog on `NetworkSpawnManager` and `NetworkObject`. (#3933)
39+
- Improved performance of `NetworkBehaviour`. (#3915)
40+
- Improved performance of `NetworkTransform`. (#3907)
41+
- Improved performance of `NetworkRigidbodyBase`. (#3906)
42+
- Improved performance of `NetworkAnimator`. (#3905)
43+
44+
### Removed
45+
46+
- Removed un-needed exceptions on `NetworkSpawnManager`. (#3933)
47+
48+
### Fixed
49+
50+
- Fixed issue where either an `AttachableBehaviour` or an `AttachableNode` can throw an exception if they are attached during a scene unload where one of the two persists the scene unload event and the other does not. (#3931)
51+
- Fixed issue where attempts to use `NetworkLog` when there is no `NetworkManager` instance would result in an exception. (#3917)
52+
4153
## [2.11.0] - 2026-03-19
4254

4355
### Added

com.unity.netcode.gameobjects/Editor/NetworkManagerEditor.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
using System.IO;
44
using System.Linq;
55
using Unity.Netcode.Editor.Configuration;
6+
using Unity.Netcode.Logging;
67
using UnityEditor;
78
using UnityEngine;
89
#if UNITY_6000_5_OR_NEWER
@@ -298,7 +299,7 @@ private void DisplayNetworkManagerProperties()
298299
#else
299300
string path = Path.Combine(directory, $"NetworkPrefabs-{m_NetworkManager.GetInstanceID()}.asset");
300301
#endif
301-
Debug.Log("Saving migrated Network Prefabs List to " + path);
302+
m_NetworkManager.Log.Info(new Context(LogLevel.Normal, "Saving migrated Network Prefabs List").AddInfo("Path", path));
302303
AssetDatabase.CreateAsset(networkPrefabs, path);
303304
EditorUtility.SetDirty(m_NetworkManager);
304305
}

com.unity.netcode.gameobjects/Editor/NetworkManagerHelper.cs

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using System.Collections.Generic;
22
using System.Linq;
33
using Unity.Netcode.Editor.Configuration;
4+
using Unity.Netcode.Logging;
45
using UnityEditor;
56
using UnityEngine;
67
using UnityEngine.SceneManagement;
@@ -162,19 +163,17 @@ public void CheckAndNotifyUserNetworkObjectRemoved(NetworkManager networkManager
162163

163164
if (!EditorApplication.isPlaying && !editorTest)
164165
{
165-
EditorUtility.DisplayDialog($"Removing {nameof(NetworkObject)}", NetworkManagerAndNetworkObjectNotAllowedMessage(), "OK");
166+
EditorUtility.DisplayDialog($"Removing {nameof(NetworkObject)}", k_NetworkManagerAndNetworkObjectNotAllowedMessage, "OK");
166167
}
167168
else
168169
{
169-
Debug.LogError(NetworkManagerAndNetworkObjectNotAllowedMessage());
170+
networkManager.Log.Error(new Context(LogLevel.Error, k_NetworkManagerAndNetworkObjectNotAllowedMessage));
170171
}
171172
}
172173
}
173174

174-
public string NetworkManagerAndNetworkObjectNotAllowedMessage()
175-
{
176-
return $"A {nameof(GameObject)} cannot have both a {nameof(NetworkManager)} and {nameof(NetworkObject)} assigned to it or any children under it.";
177-
}
175+
private static readonly string k_NetworkManagerAndNetworkObjectNotAllowedMessage = $"A {nameof(GameObject)} cannot have both a {nameof(NetworkManager)} and {nameof(NetworkObject)} assigned to it or any children under it.";
176+
public string NetworkManagerAndNetworkObjectNotAllowedMessage() => k_NetworkManagerAndNetworkObjectNotAllowedMessage;
178177

179178
/// <summary>
180179
/// Handles notifying the user, via display dialog window, that they have nested a NetworkManager.
@@ -215,7 +214,7 @@ public bool NotifyUserOfNestedNetworkManager(NetworkManager networkManager, bool
215214
}
216215
else
217216
{
218-
Debug.LogError(message);
217+
networkManager.Log.Error(new Context(LogLevel.Error, message));
219218
}
220219

221220
if (!s_LastKnownNetworkManagerParents.ContainsKey(networkManager) && isParented)

com.unity.netcode.gameobjects/Runtime/Connection/NetworkConnectionManager.cs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1343,7 +1343,14 @@ internal void OnClientDisconnectFromServer(ulong clientId)
13431343
}
13441344
else if (!NetworkManager.ShutdownInProgress)
13451345
{
1346-
playerObject.RemoveOwnership();
1346+
if (NetworkManager.DistributedAuthorityMode)
1347+
{
1348+
NetworkManager.SpawnManager.ChangeOwnership(playerObject, NetworkManager.LocalClientId, true);
1349+
}
1350+
else
1351+
{
1352+
playerObject.RemoveOwnership();
1353+
}
13471354
}
13481355
}
13491356

com.unity.netcode.gameobjects/Runtime/Core/NetworkBehaviour.cs

Lines changed: 31 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -379,41 +379,21 @@ internal void __endSendRpc(ref FastBufferWriter bufferWriter, uint rpcMethodId,
379379

380380
if (rpcParams.Send.Target == null)
381381
{
382-
switch (defaultTarget)
382+
rpcParams.Send.Target = defaultTarget switch
383383
{
384-
case SendTo.Everyone:
385-
rpcParams.Send.Target = RpcTarget.Everyone;
386-
break;
387-
case SendTo.Owner:
388-
rpcParams.Send.Target = RpcTarget.Owner;
389-
break;
390-
case SendTo.Server:
391-
rpcParams.Send.Target = RpcTarget.Server;
392-
break;
393-
case SendTo.NotServer:
394-
rpcParams.Send.Target = RpcTarget.NotServer;
395-
break;
396-
case SendTo.NotMe:
397-
rpcParams.Send.Target = RpcTarget.NotMe;
398-
break;
399-
case SendTo.NotOwner:
400-
rpcParams.Send.Target = RpcTarget.NotOwner;
401-
break;
402-
case SendTo.Me:
403-
rpcParams.Send.Target = RpcTarget.Me;
404-
break;
405-
case SendTo.ClientsAndHost:
406-
rpcParams.Send.Target = RpcTarget.ClientsAndHost;
407-
break;
408-
case SendTo.Authority:
409-
rpcParams.Send.Target = RpcTarget.Authority;
410-
break;
411-
case SendTo.NotAuthority:
412-
rpcParams.Send.Target = RpcTarget.NotAuthority;
413-
break;
414-
case SendTo.SpecifiedInParams:
415-
throw new RpcException("This method requires a runtime-specified send target.");
416-
}
384+
SendTo.Everyone => RpcTarget.Everyone,
385+
SendTo.Owner => RpcTarget.Owner,
386+
SendTo.Server => RpcTarget.Server,
387+
SendTo.NotServer => RpcTarget.NotServer,
388+
SendTo.NotMe => RpcTarget.NotMe,
389+
SendTo.NotOwner => RpcTarget.NotOwner,
390+
SendTo.Me => RpcTarget.Me,
391+
SendTo.ClientsAndHost => RpcTarget.ClientsAndHost,
392+
SendTo.Authority => RpcTarget.Authority,
393+
SendTo.NotAuthority => RpcTarget.NotAuthority,
394+
SendTo.SpecifiedInParams => throw new RpcException("This method requires a runtime-specified send target."),
395+
_ => throw new RpcException("This method requires a runtime-specified send target."),
396+
};
417397
}
418398
else if (defaultTarget != SendTo.SpecifiedInParams && !attributeParams.AllowTargetOverride)
419399
{
@@ -473,15 +453,8 @@ public NetworkManager NetworkManager
473453
#pragma warning disable IDE0001
474454
/// <summary>
475455
/// Provides access to the various <see cref="SendTo"/> targets at runtime, as well as
476-
/// runtime-bound targets like <see cref="Unity.Netcode.RpcTarget.Single"/>,
477-
/// <see cref="Unity.Netcode.RpcTarget.Group(NativeArray{ulong})"/>,
478-
/// <see cref="Unity.Netcode.RpcTarget.Group(NativeList{ulong})"/>,
479-
/// <see cref="Unity.Netcode.RpcTarget.Group(ulong[])"/>,
480-
/// <see cref="Unity.Netcode.RpcTarget.Group{T}(T)"/>, <see cref="Unity.Netcode.RpcTarget.Not(ulong)"/>,
481-
/// <see cref="Unity.Netcode.RpcTarget.Not(NativeArray{ulong})"/>,
482-
/// <see cref="Unity.Netcode.RpcTarget.Not(NativeList{ulong})"/>,
483-
/// <see cref="Unity.Netcode.RpcTarget.Not(ulong[])"/>, and
484-
/// <see cref="Unity.Netcode.RpcTarget.Not{T}(T)"/>.
456+
/// runtime-bound targets like <see cref="RpcTarget.Single"/>, <see cref="RpcTarget.Group{T}"/>, and
457+
/// <see cref="RpcTarget.Not{T}"/>.
485458
/// </summary>
486459
#pragma warning restore IDE0001
487460
public RpcTarget RpcTarget { get; private set; }
@@ -623,11 +596,6 @@ public NetworkObject NetworkObject
623596
/// </summary>
624597
public ushort NetworkBehaviourId { get; internal set; }
625598

626-
/// <summary>
627-
/// Internally caches the Id of this behaviour in a NetworkObject. Makes look-up faster
628-
/// </summary>
629-
internal ushort NetworkBehaviourIdCache = 0;
630-
631599
/// <summary>
632600
/// Returns the NetworkBehaviour with a given BehaviourId for the current NetworkObject.
633601
/// </summary>
@@ -789,7 +757,7 @@ internal virtual void InternalOnNetworkPreSpawn(ref NetworkManager networkManage
789757
/// <summary>
790758
/// Handles pre-spawn related initializations.
791759
/// Invokes any <see cref="InternalOnNetworkPreSpawn"/> subscriptions.
792-
/// Finally invokes <see cref="OnNetworkPreSpawn(ref NetworkManager)"/>.
760+
/// Finally invokes <see cref="OnNetworkPreSpawn"/>.
793761
/// </summary>
794762
internal void NetworkPreSpawn(ref NetworkManager networkManager, NetworkObject networkObject)
795763
{
@@ -1137,14 +1105,14 @@ internal void InitializeVariables()
11371105
// placed NetworkObject in an already loaded scene that has already been
11381106
// used within a network session =or= if this is a pooled NetworkObject
11391107
// that is being repurposed.
1140-
for (int i = 0; i < NetworkVariableFields.Count; i++)
1108+
foreach (var variable in NetworkVariableFields)
11411109
{
11421110
// If already initialized, then skip
1143-
if (NetworkVariableFields[i].HasBeenInitialized)
1111+
if (variable.HasBeenInitialized)
11441112
{
11451113
continue;
11461114
}
1147-
NetworkVariableFields[i].Initialize(this);
1115+
variable.Initialize(this);
11481116
}
11491117
// Exit early as we don't need to run through the rest of this initialization
11501118
// process
@@ -1172,9 +1140,8 @@ internal void InitializeVariables()
11721140
for (int i = 0; i < NetworkVariableFields.Count; i++)
11731141
{
11741142
var networkDelivery = MessageDeliveryType<NetworkVariableDeltaMessage>.DefaultDelivery;
1175-
if (!firstLevelIndex.ContainsKey(networkDelivery))
1143+
if (firstLevelIndex.TryAdd(networkDelivery, secondLevelCounter))
11761144
{
1177-
firstLevelIndex.Add(networkDelivery, secondLevelCounter);
11781145
m_DeliveryTypesForNetworkVariableGroups.Add(networkDelivery);
11791146
secondLevelCounter++;
11801147
}
@@ -1202,9 +1169,8 @@ internal void PostNetworkVariableWrite(bool forced = false)
12021169
{
12031170
// Mark every variable as no longer dirty. We just spawned the object and whatever the game code did
12041171
// during OnNetworkSpawn has been sent and needs to be cleared
1205-
for (int i = 0; i < NetworkVariableFields.Count; i++)
1172+
foreach (var networkVariable in NetworkVariableFields)
12061173
{
1207-
var networkVariable = NetworkVariableFields[i];
12081174
if (networkVariable.IsDirty())
12091175
{
12101176
if (networkVariable.CanSend())
@@ -1336,9 +1302,8 @@ internal void NetworkVariableUpdate(ulong targetClientId, bool forceSend = false
13361302
private bool CouldHaveDirtyNetworkVariables()
13371303
{
13381304
// TODO: There should be a better way by reading one dirty variable vs. 'n'
1339-
for (int i = 0; i < NetworkVariableFields.Count; i++)
1305+
foreach (var networkVariable in NetworkVariableFields)
13401306
{
1341-
var networkVariable = NetworkVariableFields[i];
13421307
if (networkVariable.IsDirty())
13431308
{
13441309
if (networkVariable.CanSend())
@@ -1364,12 +1329,12 @@ private bool CouldHaveDirtyNetworkVariables()
13641329
/// </remarks>
13651330
internal void UpdateNetworkVariableOnOwnershipChanged()
13661331
{
1367-
for (int j = 0; j < NetworkVariableFields.Count; j++)
1332+
foreach (var variable in NetworkVariableFields)
13681333
{
13691334
// Only invoke OnInitialize on NetworkVariables the owner can write to
1370-
if (NetworkVariableFields[j].CanClientWrite(OwnerClientId))
1335+
if (variable.CanClientWrite(OwnerClientId))
13711336
{
1372-
NetworkVariableFields[j].OnInitialize();
1337+
variable.OnInitialize();
13731338
}
13741339
}
13751340
}
@@ -1389,15 +1354,15 @@ internal void MarkVariablesDirty(bool dirty)
13891354
/// </summary>
13901355
internal void MarkOwnerReadDirtyAndCheckOwnerWriteIsDirty()
13911356
{
1392-
for (int j = 0; j < NetworkVariableFields.Count; j++)
1357+
foreach (var variable in NetworkVariableFields)
13931358
{
1394-
if (NetworkVariableFields[j].ReadPerm == NetworkVariableReadPermission.Owner)
1359+
if (variable.ReadPerm == NetworkVariableReadPermission.Owner)
13951360
{
1396-
NetworkVariableFields[j].SetDirty(true);
1361+
variable.SetDirty(true);
13971362
}
1398-
if (NetworkVariableFields[j].WritePerm == NetworkVariableWritePermission.Owner)
1363+
if (variable.WritePerm == NetworkVariableWritePermission.Owner)
13991364
{
1400-
NetworkVariableFields[j].OnCheckIsDirtyState();
1365+
variable.OnCheckIsDirtyState();
14011366
}
14021367
}
14031368
}

com.unity.netcode.gameobjects/Runtime/Core/NetworkBehaviourUpdater.cs

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -56,9 +56,9 @@ internal void ProcessDirtyObjectServer(NetworkObject dirtyObj, bool forceSend)
5656
if (m_NetworkManager.DistributedAuthorityMode || dirtyObj.IsNetworkVisibleTo(client.ClientId))
5757
{
5858
// Sync just the variables for just the objects this client sees
59-
for (int k = 0; k < dirtyObj.ChildNetworkBehaviours.Count; k++)
59+
foreach (var behaviour in dirtyObj.ChildNetworkBehaviours.Values)
6060
{
61-
dirtyObj.ChildNetworkBehaviours[k].NetworkVariableUpdate(client.ClientId, forceSend);
61+
behaviour.NetworkVariableUpdate(client.ClientId, forceSend);
6262
}
6363
}
6464
}
@@ -73,9 +73,9 @@ internal void ProcessDirtyObjectServer(NetworkObject dirtyObj, bool forceSend)
7373
[MethodImpl(MethodImplOptions.AggressiveInlining)]
7474
internal void ProcessDirtyObjectClient(NetworkObject dirtyObj, bool forceSend)
7575
{
76-
for (int k = 0; k < dirtyObj.ChildNetworkBehaviours.Count; k++)
76+
foreach (var behaviour in dirtyObj.ChildNetworkBehaviours.Values)
7777
{
78-
dirtyObj.ChildNetworkBehaviours[k].NetworkVariableUpdate(NetworkManager.ServerClientId, forceSend);
78+
behaviour.NetworkVariableUpdate(NetworkManager.ServerClientId, forceSend);
7979
}
8080
}
8181

@@ -86,9 +86,8 @@ internal void ProcessDirtyObjectClient(NetworkObject dirtyObj, bool forceSend)
8686
[MethodImpl(MethodImplOptions.AggressiveInlining)]
8787
internal void PostProcessDirtyObject(NetworkObject dirtyObj)
8888
{
89-
for (int k = 0; k < dirtyObj.ChildNetworkBehaviours.Count; k++)
89+
foreach (var behaviour in dirtyObj.ChildNetworkBehaviours.Values)
9090
{
91-
var behaviour = dirtyObj.ChildNetworkBehaviours[k];
9291
for (int i = 0; i < behaviour.NetworkVariableFields.Count; i++)
9392
{
9493
// Set to true for NetworkVariable to ignore duplication of the
@@ -114,7 +113,7 @@ internal void PostProcessDirtyObject(NetworkObject dirtyObj)
114113
[MethodImpl(MethodImplOptions.AggressiveInlining)]
115114
internal void ResetDirtyObject(NetworkObject dirtyObj, bool forceSend)
116115
{
117-
foreach (var behaviour in dirtyObj.ChildNetworkBehaviours)
116+
foreach (var behaviour in dirtyObj.ChildNetworkBehaviours.Values)
118117
{
119118
behaviour.PostNetworkVariableWrite(forceSend);
120119
}
@@ -164,9 +163,9 @@ internal void ProcessDirtyObject(NetworkObject networkObject, bool forceSend)
164163
}
165164

166165
// Pre-variable update
167-
for (int k = 0; k < networkObject.ChildNetworkBehaviours.Count; k++)
166+
foreach (var behaviour in networkObject.ChildNetworkBehaviours.Values)
168167
{
169-
networkObject.ChildNetworkBehaviours[k].PreVariableUpdate();
168+
behaviour.PreVariableUpdate();
170169
}
171170

172171
// Server sends updates to all clients where a client sends updates

0 commit comments

Comments
 (0)