@@ -261,23 +261,30 @@ internal void ForceDetach()
261261 ForceComponentChange ( false , true ) ;
262262
263263 InternalDetach ( ) ;
264- // Notify of the changed attached state
265- NotifyAttachedStateChanged ( m_AttachState , m_AttachableNode ) ;
266-
267- m_AttachedNodeReference = new NetworkBehaviourReference ( null ) ;
268264
269- // When detaching, we want to make our final action
270- // the invocation of the AttachableNode's Detach method.
271- if ( m_AttachableNode )
265+ if ( m_AttachableNode != null && ! m_AttachableNode . IsDestroying )
272266 {
267+ // Notify of the changed attached state
268+ NotifyAttachedStateChanged ( m_AttachState , m_AttachableNode ) ;
269+ // Only notify of the detach if the node is still valid.
273270 m_AttachableNode . Detach ( this ) ;
274- m_AttachableNode = null ;
275271 }
272+
273+ m_AttachedNodeReference = new NetworkBehaviourReference ( null ) ;
274+ m_AttachableNode = null ;
276275 }
277276
278277 /// <inheritdoc/>
279278 public override void OnNetworkPreDespawn ( )
280279 {
280+ // If the NetworkObject is being destroyed and not completely detached, then destroy the GameObject for
281+ // this attachable since the associated default parent is being destroyed.
282+ if ( IsDestroying && m_AttachState != AttachState . Detached )
283+ {
284+ Destroy ( gameObject ) ;
285+ return ;
286+ }
287+
281288 if ( NetworkManager . ShutdownInProgress || AutoDetach . HasFlag ( AutoDetachTypes . OnDespawn ) )
282289 {
283290 ForceDetach ( ) ;
@@ -286,7 +293,7 @@ public override void OnNetworkPreDespawn()
286293 }
287294
288295 /// <summary>
289- /// This will apply the final attach or detatch state based on the current value of <see cref="m_AttachedNodeReference"/>.
296+ /// This will apply the final attach or detach state based on the current value of <see cref="m_AttachedNodeReference"/>.
290297 /// </summary>
291298 [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
292299 private void UpdateAttachedState ( )
@@ -304,16 +311,18 @@ private void UpdateAttachedState()
304311 return ;
305312 }
306313
307- // If we are attached to some other AttachableNode, then detach from that before attaching to a new one.
314+ // If we are attaching and already attached to some other AttachableNode,
315+ // then detach from that before attaching to a new one.
308316 if ( isAttaching && m_AttachableNode != null && m_AttachState == AttachState . Attached )
309317 {
310- // Run through the same process without being triggerd by a NetVar update.
318+ // Detach the current attachable
311319 NotifyAttachedStateChanged ( AttachState . Detaching , m_AttachableNode ) ;
312320 InternalDetach ( ) ;
313321 NotifyAttachedStateChanged ( AttachState . Detached , m_AttachableNode ) ;
314-
315322 m_AttachableNode . Detach ( this ) ;
316323 m_AttachableNode = null ;
324+
325+ // Now attach the new attachable
317326 }
318327
319328 // Change the state to attaching or detaching
@@ -392,7 +401,8 @@ internal void ForceComponentChange(bool isAttaching, bool forcedChange)
392401
393402 foreach ( var componentControllerEntry in ComponentControllers )
394403 {
395- if ( componentControllerEntry . AutoTrigger . HasFlag ( triggerType ) )
404+ // Only if the component controller still exists and has the appropriate flag.
405+ if ( componentControllerEntry . ComponentController && componentControllerEntry . AutoTrigger . HasFlag ( triggerType ) )
396406 {
397407 componentControllerEntry . ComponentController . ForceChangeEnabled ( componentControllerEntry . EnableOnAttach ? isAttaching : ! isAttaching , forcedChange ) ;
398408 }
@@ -457,7 +467,9 @@ public void Attach(AttachableNode attachableNode)
457467 /// </summary>
458468 internal void InternalDetach ( )
459469 {
460- if ( m_AttachableNode )
470+ // If this instance is not in the middle of being destroyed, the attachable node is not null, and the node is not destroying
471+ // =or= the scene it is located in is in the middle of being unloaded, then re-parent under the default parent.
472+ if ( ! IsDestroying && m_AttachableNode && ( ! m_AttachableNode . IsDestroying || m_AttachableNode . gameObject . scene . isLoaded ) )
461473 {
462474 if ( m_DefaultParent )
463475 {
@@ -553,12 +565,33 @@ private void UpdateAttachStateRpc(NetworkBehaviourReference attachedNodeReferenc
553565 /// </summary>
554566 internal void OnAttachNodeDestroy ( )
555567 {
556- // If this instance should force a detach on destroy
557- if ( AutoDetach . HasFlag ( AutoDetachTypes . OnAttachNodeDestroy ) )
568+ // We force a detach on destroy if there is a flag =or= if we are attached to a node that is being destroyed.
569+ if ( AutoDetach . HasFlag ( AutoDetachTypes . OnAttachNodeDestroy ) ||
570+ ( AutoDetach . HasFlag ( AutoDetachTypes . OnDespawn ) && m_AttachState == AttachState . Attached && m_AttachableNode && m_AttachableNode . IsDestroying ) )
571+ {
572+ ForceDetach ( ) ;
573+ }
574+ }
575+
576+
577+ /// <summary>
578+ /// When we know this instance is being destroyed or will be destroyed
579+ /// by something outside of NGO's realm of control, this gets invoked.
580+ /// We should detach from any AttachableNode when this is invoked.
581+ /// </summary>
582+ protected internal override void OnIsDestroying ( )
583+ {
584+ // If we are not already marked as being destroyed, attached, this instance is the authority instance, and the node we are attached
585+ // to is not in the middle of being destroyed...detach normally.
586+ if ( ! IsDestroying && HasAuthority && m_AttachState == AttachState . Attached && m_AttachableNode && ! m_AttachableNode . IsDestroying )
587+ {
588+ Detach ( ) ;
589+ }
590+ else // Otherwise force the detach.
558591 {
559- // Force a detach
560592 ForceDetach ( ) ;
561593 }
594+ base . OnIsDestroying ( ) ;
562595 }
563596 }
564597}
0 commit comments