Skip to content

Commit 842b67b

Browse files
fix
The actual fix for the issue with additional handling when an attachable's NetworkObject is destroyed while it is still attached to something else.
1 parent 21ff894 commit 842b67b

File tree

3 files changed

+49
-21
lines changed

3 files changed

+49
-21
lines changed

com.unity.netcode.gameobjects/Runtime/Components/Helpers/AttachableBehaviour.cs

Lines changed: 35 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,8 @@ public enum AttachState
205205
private Vector3 m_OriginalLocalPosition;
206206
private Quaternion m_OriginalLocalRotation;
207207

208+
internal bool IsDestroying { get; private set; }
209+
208210
/// <inheritdoc/>
209211
protected override void OnSynchronize<T>(ref BufferSerializer<T> serializer)
210212
{
@@ -238,6 +240,37 @@ protected virtual void Awake()
238240
OnAwake();
239241
}
240242

243+
protected override void OnNetworkPreSpawn(ref NetworkManager networkManager)
244+
{
245+
IsDestroying = false;
246+
// When attached to something else, the attachable needs to know if the
247+
// default parent has been destroyed in order to not attempt to re-parent
248+
// when detached (especially if it is being detatched because it should be destroyed).
249+
NetworkObject.OnDestroying += OnDefaultParentDestroying;
250+
251+
base.OnNetworkPreSpawn(ref networkManager);
252+
}
253+
254+
private void OnDefaultParentDestroying()
255+
{
256+
NetworkObject.OnDestroying -= OnDefaultParentDestroying;
257+
// Exit early if we are already being destroyed
258+
if (IsDestroying)
259+
{
260+
return;
261+
}
262+
IsDestroying = true;
263+
// Just destroy the GameObject for this attachable since
264+
// the associated NetworkObject is being destroyed.
265+
Destroy(gameObject);
266+
}
267+
268+
internal override void InternalOnDestroy()
269+
{
270+
IsDestroying = true;
271+
base.InternalOnDestroy();
272+
}
273+
241274
/// <inheritdoc/>
242275
/// <remarks>
243276
/// If you create a custom <see cref="AttachableBehaviour"/> and override this method, you will want to
@@ -458,16 +491,9 @@ public void Attach(AttachableNode attachableNode)
458491
/// </summary>
459492
internal void InternalDetach()
460493
{
461-
if (m_AttachableNode)
494+
if (!IsDestroying && m_AttachableNode && !m_AttachableNode.IsDestroying)
462495
{
463-
// TODO-FIX: We might track if something has been "destroyed" in order
464-
// to be able to be 100% sure in the event a user disables the world item
465-
// when detatched. Otherwise, we keep this in place and make note of it
466-
// in documentation.
467-
// Issue:
468-
// Edge-case where the parent could be in the middle of being destroyed.
469-
// If not active in the hierarchy, then don't attempt to set the parent.
470-
if (m_DefaultParent && m_DefaultParent.activeInHierarchy)
496+
if (m_DefaultParent)
471497
{
472498
// Set the original parent and origianl local position and rotation
473499
transform.SetParent(m_DefaultParent.transform, false);

com.unity.netcode.gameobjects/Runtime/Components/Helpers/AttachableNode.cs

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ public class AttachableNode : NetworkBehaviour
2424
/// </summary>
2525
public bool DetachOnDespawn = true;
2626

27+
internal bool IsDestroying { get; private set; }
28+
2729
/// <summary>
2830
/// A <see cref="List{T}"/> of the currently attached <see cref="AttachableBehaviour"/>s.
2931
/// </summary>
@@ -32,6 +34,7 @@ public class AttachableNode : NetworkBehaviour
3234
/// <inheritdoc/>
3335
protected override void OnNetworkPreSpawn(ref NetworkManager networkManager)
3436
{
37+
IsDestroying = false;
3538
m_AttachedBehaviours.Clear();
3639
base.OnNetworkPreSpawn(ref networkManager);
3740
}
@@ -84,23 +87,15 @@ public override void OnNetworkPreDespawn()
8487
}
8588
else
8689
{
87-
// TODO-FIX: We might track if something has been "destroyed" in order
88-
// to be able to be 100% sure this is specific to being destroyed.
89-
// Otherwise, we keep this in place and make note of it
90-
// in documentation that you cannot detatch from something already despawned.
91-
// Issue: When trying to detatch if the thing attached is no longer
92-
// spawned. Instantiation order recently changed such that
93-
// the attachable =or= the attach node target could be despawned
94-
// and in the middle of being destroyed. Resolution for this
95-
// is to skip over destroyed object (default) and then only sort
96-
// through the things the local NetworkManager instance has authority
97-
// over. Even then, we have to check if the attached object is still
98-
// spawned before attempting to detatch it.
9990
if (attachable.IsSpawned)
10091
{
10192
// Detach the normal way with authority
10293
attachable.Detach();
10394
}
95+
else if (!attachable.IsDestroying)
96+
{
97+
attachable.ForceDetach();
98+
}
10499
}
105100
}
106101
}
@@ -109,6 +104,7 @@ public override void OnNetworkPreDespawn()
109104

110105
internal override void InternalOnDestroy()
111106
{
107+
IsDestroying = true;
112108
// Notify any attached behaviours that this node is being destroyed.
113109
for (int i = m_AttachedBehaviours.Count - 1; i >= 0; i--)
114110
{

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1688,8 +1688,14 @@ public static void NetworkHide(List<NetworkObject> networkObjects, ulong clientI
16881688
}
16891689
}
16901690

1691+
/// <summary>
1692+
/// Invoked when the NetworkObject is destroyed.
1693+
/// </summary>
1694+
internal event Action OnDestroying;
1695+
16911696
private void OnDestroy()
16921697
{
1698+
OnDestroying?.Invoke();
16931699
var networkManager = NetworkManager;
16941700
// If no NetworkManager is assigned, then just exit early
16951701
if (!networkManager)

0 commit comments

Comments
 (0)