Skip to content

Commit 6d37247

Browse files
fix: NetworkObject.NetworkHide destroys client-side in-scene placed NetworkObjects [MTT-4211] (#2086)
* fix MTT-4211 This fixes the issue where in-scene placed NetworkObjects were being destroyed when NetworkHide is invoked. * test MTT-4211 This adds an additional check for NetworkHide and NetworkShow towards the end of the in-scene placed NetworkObject synchronization test. * style whitespace fix * style Adjusting comments and adding additional API XML Documentation for readability and clarification purposes. * update MTT-4211 Updating the changelog. * update improving the logic used for readability purposes since we know IsSceneObject will be valid. * style migrating the majority of the comments into remarks. * style Adding space within all added <br/> tags so they look like this: <br /> This is to see if the version of docusaurus we are using will not crash when it runs across this markdown syntax.
1 parent 11922a0 commit 6d37247

File tree

3 files changed

+70
-14
lines changed

3 files changed

+70
-14
lines changed

com.unity.netcode.gameobjects/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ Additional documentation and release notes are available at [Multiplayer Documen
1212
- When using `UnityTransport`, _reliable_ payloads are now allowed to exceed the configured 'Max Payload Size'. Unreliable payloads remain bounded by this setting. (#2081)
1313

1414
### Fixed
15+
- Fixed issue where `NetworkObject.NetworkHide` was despawning and destroying, as opposed to only despawning, in-scene placed `NetworkObject`s. (#2086)
1516
- Fixed issue where `NetworkAnimator` would not synchronize a looping animation for late joining clients if it was at the very end of its loop. (#2076)
1617
- Fixed issue where `NetworkAnimator` was not removing its subscription from `OnClientConnectedCallback` when despawned during the shutdown sequence. (#2074)
1718
- Fixed IsServer and IsClient being set to false before object despawn during the shutdown sequence. (#2074)

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

Lines changed: 55 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -235,9 +235,19 @@ private void Awake()
235235
}
236236

237237
/// <summary>
238-
/// Shows a previously hidden <see cref="NetworkObject"/> to a client
238+
/// Makes the previously hidden <see cref="NetworkObject"/> "netcode visible" to the targeted client.
239239
/// </summary>
240-
/// <param name="clientId">The client to show the <see cref="NetworkObject"/> to</param>
240+
/// <remarks>
241+
/// Usage: Use to start sending updates for a previously hidden <see cref="NetworkObject"/> to the targeted client.<br />
242+
/// <br />
243+
/// Dynamically Spawned: <see cref="NetworkObject"/>s will be instantiated and spawned on the targeted client side.<br />
244+
/// In-Scene Placed: The instantiated but despawned <see cref="NetworkObject"/>s will be spawned on the targeted client side.<br />
245+
/// <br />
246+
/// See Also:<br />
247+
/// <see cref="NetworkShow(ulong)"/><br />
248+
/// <see cref="NetworkHide(ulong)"/> or <see cref="NetworkHide(List{NetworkObject}, ulong)"/><br />
249+
/// </remarks>
250+
/// <param name="clientId">The targeted client</param>
241251
public void NetworkShow(ulong clientId)
242252
{
243253
if (!IsSpawned)
@@ -260,11 +270,22 @@ public void NetworkShow(ulong clientId)
260270
NetworkManager.SpawnManager.SendSpawnCallForObject(clientId, this);
261271
}
262272

273+
263274
/// <summary>
264-
/// Shows a list of previously hidden <see cref="NetworkObject"/>s to a client
275+
/// Makes a list of previously hidden <see cref="NetworkObject"/>s "netcode visible" for the client specified.
265276
/// </summary>
266-
/// <param name="networkObjects">The <see cref="NetworkObject"/>s to show</param>
267-
/// <param name="clientId">The client to show the objects to</param>
277+
/// <remarks>
278+
/// Usage: Use to start sending updates for previously hidden <see cref="NetworkObject"/>s to the targeted client.<br />
279+
/// <br />
280+
/// Dynamically Spawned: <see cref="NetworkObject"/>s will be instantiated and spawned on the targeted client's side.<br />
281+
/// In-Scene Placed: Already instantiated but despawned <see cref="NetworkObject"/>s will be spawned on the targeted client's side.<br />
282+
/// <br />
283+
/// See Also:<br />
284+
/// <see cref="NetworkShow(ulong)"/><br />
285+
/// <see cref="NetworkHide(ulong)"/> or <see cref="NetworkHide(List{NetworkObject}, ulong)"/><br />
286+
/// </remarks>
287+
/// <param name="networkObjects">The objects to become "netcode visible" to the targeted client</param>
288+
/// <param name="clientId">The targeted client</param>
268289
public static void NetworkShow(List<NetworkObject> networkObjects, ulong clientId)
269290
{
270291
if (networkObjects == null || networkObjects.Count == 0)
@@ -305,9 +326,19 @@ public static void NetworkShow(List<NetworkObject> networkObjects, ulong clientI
305326
}
306327

307328
/// <summary>
308-
/// Hides a object from a specific client
329+
/// Hides the <see cref="NetworkObject"/> from the targeted client.
309330
/// </summary>
310-
/// <param name="clientId">The client to hide the object for</param>
331+
/// <remarks>
332+
/// Usage: Use to stop sending updates to the targeted client, "netcode invisible", for a currently visible <see cref="NetworkObject"/>.<br />
333+
/// <br />
334+
/// Dynamically Spawned: <see cref="NetworkObject"/>s will be despawned and destroyed on the targeted client's side.<br />
335+
/// In-Scene Placed: <see cref="NetworkObject"/>s will only be despawned on the targeted client's side.<br />
336+
/// <br />
337+
/// See Also:<br />
338+
/// <see cref="NetworkHide(List{NetworkObject}, ulong)"/><br />
339+
/// <see cref="NetworkShow(ulong)"/> or <see cref="NetworkShow(List{NetworkObject}, ulong)"/><br />
340+
/// </remarks>
341+
/// <param name="clientId">The targeted client</param>
311342
public void NetworkHide(ulong clientId)
312343
{
313344
if (!IsSpawned)
@@ -335,18 +366,28 @@ public void NetworkHide(ulong clientId)
335366
var message = new DestroyObjectMessage
336367
{
337368
NetworkObjectId = NetworkObjectId,
338-
DestroyGameObject = true
369+
DestroyGameObject = !IsSceneObject.Value
339370
};
340371
// Send destroy call
341372
var size = NetworkManager.SendMessage(ref message, NetworkDelivery.ReliableSequenced, clientId);
342373
NetworkManager.NetworkMetrics.TrackObjectDestroySent(clientId, this, size);
343374
}
344375

345376
/// <summary>
346-
/// Hides a list of objects from a client
377+
/// Hides a list of <see cref="NetworkObject"/>s from the targeted client.
347378
/// </summary>
348-
/// <param name="networkObjects">The objects to hide</param>
349-
/// <param name="clientId">The client to hide the objects from</param>
379+
/// <remarks>
380+
/// Usage: Use to stop sending updates to the targeted client, "netcode invisible", for the currently visible <see cref="NetworkObject"/>s.<br />
381+
/// <br />
382+
/// Dynamically Spawned: <see cref="NetworkObject"/>s will be despawned and destroyed on the targeted client's side.<br />
383+
/// In-Scene Placed: <see cref="NetworkObject"/>s will only be despawned on the targeted client's side.<br />
384+
/// <br />
385+
/// See Also:<br />
386+
/// <see cref="NetworkHide(ulong)"/><br />
387+
/// <see cref="NetworkShow(ulong)"/> or <see cref="NetworkShow(List{NetworkObject}, ulong)"/><br />
388+
/// </remarks>
389+
/// <param name="networkObjects">The <see cref="NetworkObject"/>s that will become "netcode invisible" to the targeted client</param>
390+
/// <param name="clientId">The targeted client</param>
350391
public static void NetworkHide(List<NetworkObject> networkObjects, ulong clientId)
351392
{
352393
if (networkObjects == null || networkObjects.Count == 0)
@@ -455,8 +496,8 @@ public void SpawnWithOwnership(ulong clientId, bool destroyWithScene = false)
455496
/// <summary>
456497
/// Spawns a <see cref="NetworkObject"/> across the network and makes it the player object for the given client
457498
/// </summary>
458-
/// <param name="clientId">The clientId whos player object this is</param>
459-
/// <param name="destroyWithScene">Should the object be destroyd when the scene is changed</param>
499+
/// <param name="clientId">The clientId who's player object this is</param>
500+
/// <param name="destroyWithScene">Should the object be destroyed when the scene is changed</param>
460501
public void SpawnAsPlayerObject(ulong clientId, bool destroyWithScene = false)
461502
{
462503
SpawnInternal(destroyWithScene, clientId, true);
@@ -697,7 +738,7 @@ private void OnTransformParentChanged()
697738
// For instance, if we're spawning NetworkObject 5 and its parent is 10, what should happen if we do not have 10 yet?
698739
// let's say 10 is on the way to be replicated in a few frames and we could fix that parent-child relationship later.
699740
//
700-
// If you couldn't find your parent, we put you into OrphanChildren set and everytime we spawn another NetworkObject locally due to replication,
741+
// If you couldn't find your parent, we put you into OrphanChildren set and every time we spawn another NetworkObject locally due to replication,
701742
// we call CheckOrphanChildren() method and quickly iterate over OrphanChildren set and see if we can reparent/adopt one.
702743
internal static HashSet<NetworkObject> OrphanChildren = new HashSet<NetworkObject>();
703744

testproject/Assets/Tests/Runtime/NetworkSceneManager/InScenePlacedNetworkObjectTests.cs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,20 @@ public IEnumerator InSceneNetworkObjectSynchAndSpawn()
102102

103103
yield return WaitForConditionOrTimeOut(() => NetworkObjectTestComponent.SpawnedInstances.Count == TotalClients);
104104
AssertOnTimeout($"Timed out waiting for all in-scene instances to be spawned! Current spawned count: {NetworkObjectTestComponent.SpawnedInstances.Count()} | Expected spawn count: {TotalClients}");
105+
106+
// Test NetworkHide on the first client
107+
var firstClientId = m_ClientNetworkManagers[0].LocalClientId;
108+
109+
serverObject.NetworkHide(firstClientId);
110+
111+
yield return WaitForConditionOrTimeOut(() => NetworkObjectTestComponent.SpawnedInstances.Count == TotalClients - 1);
112+
AssertOnTimeout($"[NetworkHide] Timed out waiting for Client-{firstClientId} to despawn the in-scene placed NetworkObject! Current spawned count: {NetworkObjectTestComponent.SpawnedInstances.Count()} | Expected spawn count: {TotalClients - 1}");
113+
114+
// Validate that the first client can spawn the "netcode hidden" in-scene placed NetworkObject
115+
serverObject.NetworkShow(firstClientId);
116+
yield return WaitForConditionOrTimeOut(() => NetworkObjectTestComponent.SpawnedInstances.Count == TotalClients);
117+
AssertOnTimeout($"[NetworkShow] Timed out waiting for Client-{firstClientId} to spawn the in-scene placed NetworkObject! Current spawned count: {NetworkObjectTestComponent.SpawnedInstances.Count()} | Expected spawn count: {TotalClients}");
118+
105119
CleanUpLoadedScene();
106120
}
107121

0 commit comments

Comments
 (0)