Skip to content

Commit 18f3d05

Browse files
Merge branch 'develop-2.0.0' into codecov-integration
2 parents 3114ac7 + f966e07 commit 18f3d05

File tree

14 files changed

+372
-97
lines changed

14 files changed

+372
-97
lines changed

com.unity.netcode.gameobjects/CHANGELOG.md

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,16 +10,25 @@ Additional documentation and release notes are available at [Multiplayer Documen
1010

1111
### Added
1212

13+
- Added `NetworkPrefabInstanceHandlerWithData<T>`, a variant of `INetworkPrefabInstanceHandler` that provides access to custom instantiation data directly within the `Instantiate()` method. (#3430)
14+
15+
### Fixed
16+
17+
- Fixed distributed authority related issue where enabling the `NetworkObject.DestroyWithScene` would cause errors when a destroying non-authority instances due to loading (single mode) or unloading scene events. (#3500)
18+
19+
### Changed
20+
21+
22+
## [2.4.2] - 2025-06-13
1323

1424
### Fixed
1525

26+
- Fixed `NullReferenceException` on `NetworkList` when used without a NetworkManager in scene. (#3503)
1627
- Fixed issue where `NetworkClient` could persist some settings if re-using the same `NetworkManager` instance. (#3491)
1728
- Fixed issue where a pooled `NetworkObject` was not resetting the internal latest parent property when despawned. (#3491)
1829
- Fixed issue where the initial client synchronization pre-serialization process was not excluding spawned `NetworkObject` instances that already had pending visibility for the client being synchronized. (#3488)
1930
- Fixed issue where there was a potential for a small memory leak in the `ConnectionApprovedMessage`. (#3486)
2031

21-
### Changed
22-
2332

2433
## [2.4.1] - 2025-06-11
2534

@@ -39,7 +48,7 @@ Additional documentation and release notes are available at [Multiplayer Documen
3948

4049
- Added `SinglePlayerTransport` that provides the ability to start as a host for a single player network session. (#3473)
4150
- When using UnityTransport >=2.4 and Unity >= 6000.1.0a1, SetConnectionData will accept a fully qualified hostname instead of an IP as a connect address on the client side. (#3441)
42-
- Added `NetworkPrefabInstanceHandlerWithData<T>`, a variant of `INetworkPrefabInstanceHandler` that provides access to custom instantiation data directly within the `Instantiate()` method. (#3430)
51+
4352

4453
### Fixed
4554

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

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1200,6 +1200,7 @@ public void SetSceneObjectStatus(bool isSceneObject = false)
12001200
/// Gets whether or not the object should be automatically removed when the scene is unloaded.
12011201
/// </summary>
12021202
public bool DestroyWithScene { get; set; }
1203+
internal bool DestroyPendingSceneEvent;
12031204

12041205
/// <summary>
12051206
/// When set to true and the active scene is changed, this will automatically migrate the <see cref="NetworkObject"/>
@@ -1720,10 +1721,11 @@ private void OnDestroy()
17201721
return;
17211722
}
17221723

1723-
// Authority is the server (client-server) and the owner or DAHost (distributed authority) when destroying a NetworkObject
1724-
var isAuthority = HasAuthority || NetworkManager.DAHost;
1724+
// An authorized destroy is when done by the authority instance or done due to a scene event and the NetworkObject
1725+
// was marked as destroy pending scene event (which means the destroy with scene property was set).
1726+
var isAuthorityDestroy = HasAuthority || NetworkManager.DAHost || DestroyPendingSceneEvent;
17251727

1726-
if (NetworkManager.IsListening && !isAuthority && IsSpawned &&
1728+
if (NetworkManager.IsListening && !isAuthorityDestroy && IsSpawned &&
17271729
(IsSceneObject == null || (IsSceneObject.Value != true)))
17281730
{
17291731
// If we destroyed a GameObject with a NetworkObject component on the non-authority side, handle cleaning up the SceneMigrationSynchronization.

com.unity.netcode.gameobjects/Runtime/Messaging/Messages/NetworkVariableDeltaMessage.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -144,9 +144,9 @@ public void Serialize(FastBufferWriter writer, int targetVersion)
144144
var startingSize = writer.Length;
145145
var networkVariable = NetworkBehaviour.NetworkVariableFields[i];
146146
var shouldWrite = networkVariable.IsDirty() &&
147-
networkVariable.CanClientRead(TargetClientId) &&
148-
(networkManager.IsServer || networkVariable.CanClientWrite(networkManager.LocalClientId)) &&
149-
networkVariable.CanSend();
147+
networkVariable.CanClientRead(TargetClientId)
148+
&& (networkManager.IsServer ||
149+
(networkVariable.CanWrite && networkVariable.CanSend()));
150150

151151
// Prevent the server from writing to the client that owns a given NetworkVariable
152152
// Allowing the write would send an old value to the client and cause jitter

com.unity.netcode.gameobjects/Runtime/NetworkVariable/AnticipatedNetworkVariable.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -217,7 +217,7 @@ public void Anticipate(T value)
217217
m_LastAnticipationCounter = m_NetworkBehaviour.NetworkManager.AnticipationSystem.AnticipationCounter;
218218
m_AnticipatedValue = value;
219219
NetworkVariableSerialization<T>.Duplicate(m_AnticipatedValue, ref m_PreviousAnticipatedValue);
220-
if (CanClientWrite(m_NetworkBehaviour.NetworkManager.LocalClientId))
220+
if (CanWrite)
221221
{
222222
AuthoritativeValue = value;
223223
}

com.unity.netcode.gameobjects/Runtime/NetworkVariable/Collections/NetworkList.cs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -428,7 +428,7 @@ public IEnumerator<T> GetEnumerator()
428428
public void Add(T item)
429429
{
430430
// check write permissions
431-
if (!CanClientWrite(m_NetworkManager.LocalClientId))
431+
if (CannotWrite)
432432
{
433433
LogWritePermissionError();
434434
return;
@@ -455,7 +455,7 @@ public void Add(T item)
455455
public void Clear()
456456
{
457457
// check write permissions
458-
if (!CanClientWrite(m_NetworkManager.LocalClientId))
458+
if (CannotWrite)
459459
{
460460
LogWritePermissionError();
461461
return;
@@ -493,7 +493,7 @@ public bool Contains(T item)
493493
public bool Remove(T item)
494494
{
495495
// check write permissions
496-
if (!CanClientWrite(m_NetworkManager.LocalClientId))
496+
if (CannotWrite)
497497
{
498498
LogWritePermissionError();
499499
return false;
@@ -542,7 +542,7 @@ public int IndexOf(T item)
542542
public void Insert(int index, T item)
543543
{
544544
// check write permissions
545-
if (!CanClientWrite(m_NetworkManager.LocalClientId))
545+
if (CannotWrite)
546546
{
547547
LogWritePermissionError();
548548
return;
@@ -578,7 +578,7 @@ public void Insert(int index, T item)
578578
public void RemoveAt(int index)
579579
{
580580
// check write permissions
581-
if (!CanClientWrite(m_NetworkManager.LocalClientId))
581+
if (CannotWrite)
582582
{
583583
throw new InvalidOperationException("Client is not allowed to write to this NetworkList");
584584
}
@@ -610,7 +610,7 @@ public T this[int index]
610610
set
611611
{
612612
// check write permissions
613-
if (!CanClientWrite(m_NetworkManager.LocalClientId))
613+
if (CannotWrite)
614614
{
615615
LogWritePermissionError();
616616
return;

com.unity.netcode.gameobjects/Runtime/NetworkVariable/NetworkVariable.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ public virtual T Value
128128
get => m_InternalValue;
129129
set
130130
{
131-
if (m_NetworkManager && !CanClientWrite(m_NetworkManager.LocalClientId))
131+
if (CannotWrite)
132132
{
133133
LogWritePermissionError();
134134
return;
@@ -162,7 +162,7 @@ public bool CheckDirtyState(bool forceCheck = false)
162162
var isDirty = base.IsDirty();
163163

164164
// A client without permissions invoking this method should only check to assure the current value is equal to the last known current value
165-
if (m_NetworkManager && !CanClientWrite(m_NetworkManager.LocalClientId))
165+
if (CannotWrite)
166166
{
167167
// If modifications are detected, then revert back to the last known current value
168168
if (!NetworkVariableSerialization<T>.AreEqual(ref m_InternalValue, ref m_InternalOriginalValue))
@@ -245,7 +245,7 @@ public override bool IsDirty()
245245
{
246246
// If the client does not have write permissions but the internal value is determined to be locally modified and we are applying updates, then we should revert
247247
// to the original collection value prior to applying updates (primarily for collections).
248-
if (!NetworkUpdaterCheck && m_NetworkManager && !CanClientWrite(m_NetworkManager.LocalClientId) && !NetworkVariableSerialization<T>.AreEqual(ref m_InternalValue, ref m_InternalOriginalValue))
248+
if (!NetworkUpdaterCheck && CannotWrite && !NetworkVariableSerialization<T>.AreEqual(ref m_InternalValue, ref m_InternalOriginalValue))
249249
{
250250
NetworkVariableSerialization<T>.Duplicate(m_InternalOriginalValue, ref m_InternalValue);
251251
return true;
@@ -307,7 +307,7 @@ public override void ReadDelta(FastBufferReader reader, bool keepDirtyDelta)
307307
{
308308
// If the client does not have write permissions but the internal value is determined to be locally modified and we are applying updates, then we should revert
309309
// to the original collection value prior to applying updates (primarily for collections).
310-
if (m_NetworkManager && !CanClientWrite(m_NetworkManager.LocalClientId) && !NetworkVariableSerialization<T>.AreEqual(ref m_InternalOriginalValue, ref m_InternalValue))
310+
if (CannotWrite && !NetworkVariableSerialization<T>.AreEqual(ref m_InternalOriginalValue, ref m_InternalValue))
311311
{
312312
NetworkVariableSerialization<T>.Duplicate(m_InternalOriginalValue, ref m_InternalValue);
313313
}
@@ -349,7 +349,7 @@ public override void ReadField(FastBufferReader reader)
349349
{
350350
// If the client does not have write permissions but the internal value is determined to be locally modified and we are applying updates, then we should revert
351351
// to the original collection value prior to applying updates (primarily for collections).
352-
if (m_NetworkManager && !CanClientWrite(m_NetworkManager.LocalClientId) && !NetworkVariableSerialization<T>.AreEqual(ref m_InternalOriginalValue, ref m_InternalValue))
352+
if (CannotWrite && !NetworkVariableSerialization<T>.AreEqual(ref m_InternalOriginalValue, ref m_InternalValue))
353353
{
354354
NetworkVariableSerialization<T>.Duplicate(m_InternalOriginalValue, ref m_InternalValue);
355355
}

com.unity.netcode.gameobjects/Runtime/NetworkVariable/NetworkVariableBase.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -381,6 +381,16 @@ public bool CanClientWrite(ulong clientId)
381381
}
382382
}
383383

384+
/// <summary>
385+
/// Returns true if the current <see cref="NetworkManager.LocalClientId"/> can write to this variable; otherwise false.
386+
/// </summary>
387+
internal bool CanWrite => m_NetworkManager && CanClientWrite(m_NetworkManager.LocalClientId);
388+
389+
/// <summary>
390+
/// Returns false if the current <see cref="NetworkManager.LocalClientId"/> can write to this variable; otherwise true.
391+
/// </summary>
392+
internal bool CannotWrite => m_NetworkManager && !CanClientWrite(m_NetworkManager.LocalClientId);
393+
384394
/// <summary>
385395
/// Returns the ClientId of the owning client
386396
/// </summary>

com.unity.netcode.gameobjects/Runtime/SceneManagement/DefaultSceneManagerHandler.cs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -293,13 +293,20 @@ public void MoveObjectsFromSceneToDontDestroyOnLoad(ref NetworkManager networkMa
293293
// Create a local copy of the spawned objects list since the spawn manager will adjust the list as objects
294294
// are despawned.
295295
var localSpawnedObjectsHashSet = new HashSet<NetworkObject>(networkManager.SpawnManager.SpawnedObjectsList);
296+
var distributedAuthority = networkManager.DistributedAuthorityMode;
296297
foreach (var networkObject in localSpawnedObjectsHashSet)
297298
{
298299
if (networkObject == null || (networkObject != null && networkObject.gameObject.scene.handle != scene.handle))
299300
{
300301
continue;
301302
}
302303

304+
// Check to determine if we need to allow destroying a non-authority instance
305+
if (distributedAuthority && networkObject.DestroyWithScene && !networkObject.HasAuthority)
306+
{
307+
networkObject.DestroyPendingSceneEvent = true;
308+
}
309+
303310
// Only NetworkObjects marked to not be destroyed with the scene and are not already in the DDOL are preserved
304311
if (!networkObject.DestroyWithScene && networkObject.gameObject.scene != networkManager.SceneManager.DontDestroyOnLoadScene)
305312
{
@@ -309,7 +316,7 @@ public void MoveObjectsFromSceneToDontDestroyOnLoad(ref NetworkManager networkMa
309316
UnityEngine.Object.DontDestroyOnLoad(networkObject.gameObject);
310317
}
311318
}
312-
else if (networkManager.IsServer)
319+
else if (networkObject.HasAuthority)
313320
{
314321
networkObject.Despawn();
315322
}

com.unity.netcode.gameobjects/Runtime/SceneManagement/NetworkSceneManager.cs

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1062,7 +1062,8 @@ internal NetworkObject GetSceneRelativeInSceneNetworkObject(uint globalObjectIdH
10621062
/// <param name="targetClientIds">array of client identifiers to receive the scene event message</param>
10631063
private void SendSceneEventData(uint sceneEventId, ulong[] targetClientIds)
10641064
{
1065-
if (targetClientIds.Length == 0 && !NetworkManager.DistributedAuthorityMode)
1065+
var distributedAuthority = NetworkManager.DistributedAuthorityMode;
1066+
if (targetClientIds.Length == 0 && !distributedAuthority)
10661067
{
10671068
// This would be the Host/Server with no clients connected
10681069
// Silently return as there is nothing to be done
@@ -1072,7 +1073,7 @@ private void SendSceneEventData(uint sceneEventId, ulong[] targetClientIds)
10721073
sceneEvent.SenderClientId = NetworkManager.LocalClientId;
10731074

10741075
// Send related message to the CMB service
1075-
if (NetworkManager.DistributedAuthorityMode && NetworkManager.CMBServiceConnection && HasSceneAuthority())
1076+
if (distributedAuthority && NetworkManager.CMBServiceConnection && HasSceneAuthority())
10761077
{
10771078
sceneEvent.TargetClientId = NetworkManager.ServerClientId;
10781079
var message = new SceneEventMessage
@@ -1092,7 +1093,7 @@ private void SendSceneEventData(uint sceneEventId, ulong[] targetClientIds)
10921093
{
10931094
EventData = sceneEvent,
10941095
};
1095-
var sendTarget = NetworkManager.CMBServiceConnection ? NetworkManager.ServerClientId : clientId;
1096+
var sendTarget = distributedAuthority && !NetworkManager.DAHost ? NetworkManager.ServerClientId : clientId;
10961097
var size = NetworkManager.ConnectionManager.SendMessage(ref message, k_DeliveryType, sendTarget);
10971098
NetworkManager.NetworkMetrics.TrackSceneEventSent(clientId, (uint)sceneEvent.SceneEventType, SceneNameFromHash(sceneEvent.SceneHash), size);
10981099
}
@@ -2679,13 +2680,20 @@ internal void MoveObjectsToDontDestroyOnLoad()
26792680
// Create a local copy of the spawned objects list since the spawn manager will adjust the list as objects
26802681
// are despawned.
26812682
var localSpawnedObjectsHashSet = new HashSet<NetworkObject>(NetworkManager.SpawnManager.SpawnedObjectsList);
2683+
var distributedAuthority = NetworkManager.DistributedAuthorityMode;
26822684
foreach (var networkObject in localSpawnedObjectsHashSet)
26832685
{
26842686
if (networkObject == null || (networkObject != null && networkObject.gameObject.scene == DontDestroyOnLoadScene))
26852687
{
26862688
continue;
26872689
}
26882690

2691+
// Check to determine if we need to allow destroying a non-authority instance
2692+
if (distributedAuthority && networkObject.DestroyWithScene && !networkObject.HasAuthority)
2693+
{
2694+
networkObject.DestroyPendingSceneEvent = true;
2695+
}
2696+
26892697
// Only NetworkObjects marked to not be destroyed with the scene
26902698
if (!networkObject.DestroyWithScene)
26912699
{

0 commit comments

Comments
 (0)