@@ -25,6 +25,7 @@ public AttachableBehaviourTests(HostOrServer hostOrServer) : base(hostOrServer)
2525 /// <summary>
2626 /// All of the below instances belong to the authority
2727 /// </summary>
28+ private ulong m_TargetInstanceId ;
2829 private NetworkObject m_SourceInstance ;
2930 private NetworkObject m_TargetInstance ;
3031 private NetworkObject m_TargetInstanceB ;
@@ -47,6 +48,7 @@ protected override void OnServerAndClientsCreated()
4748 // The source prefab contains the nested NetworkBehaviour that
4849 // will be parented under the target prefab.
4950 m_SourcePrefab = CreateNetworkObjectPrefab ( "Source" ) ;
51+ m_SourcePrefab . GetComponent < NetworkObject > ( ) . DontDestroyWithOwner = true ;
5052 // The target prefab that the source prefab will attach
5153 // will be parented under the target prefab.
5254 m_TargetPrefabA = CreateNetworkObjectPrefab ( "TargetA" ) ;
@@ -94,8 +96,11 @@ private bool ResetAllStates()
9496 {
9597 m_ErrorLog . Clear ( ) ;
9698 var target = GetTargetInstance ( ) ;
99+
100+
97101 // The attachable can move between the two spawned instances.
98102 var currentAttachableRoot = m_AttachableBehaviourInstance . State == AttachableBehaviour . AttachState . Attached ? target : m_SourceInstance ;
103+
99104 foreach ( var networkManager in m_NetworkManagers )
100105 {
101106 // Source
@@ -110,7 +115,7 @@ private bool ResetAllStates()
110115 }
111116
112117 // Target
113- if ( ! networkManager . SpawnManager . SpawnedObjects . ContainsKey ( m_TargetInstance . NetworkObjectId ) )
118+ if ( m_TargetInstance && ! networkManager . SpawnManager . SpawnedObjects . ContainsKey ( m_TargetInstance . NetworkObjectId ) )
114119 {
115120 m_ErrorLog . AppendLine ( $ "[Client-{ networkManager . LocalClientId } ] Has no spawned instance of { m_TargetInstance . name } !") ;
116121 }
@@ -121,7 +126,7 @@ private bool ResetAllStates()
121126 }
122127
123128 // Target B
124- if ( ! networkManager . SpawnManager . SpawnedObjects . ContainsKey ( m_TargetInstanceB . NetworkObjectId ) )
129+ if ( m_TargetInstanceB && ! networkManager . SpawnManager . SpawnedObjects . ContainsKey ( m_TargetInstanceB . NetworkObjectId ) )
125130 {
126131 m_ErrorLog . AppendLine ( $ "[Client-{ networkManager . LocalClientId } ] Has no spawned instance of { m_TargetInstanceB . name } !") ;
127132 }
@@ -134,10 +139,11 @@ private bool ResetAllStates()
134139 return m_ErrorLog . Length == 0 ;
135140 }
136141
137- private bool AllInstancesAttachedStateChanged ( bool checkAttached )
142+ private bool AllInstancesAttachedStateChanged ( bool checkAttached , bool ignoreIfDespawned = false )
138143 {
139144 m_ErrorLog . Clear ( ) ;
140145 var target = GetTargetInstance ( ) ;
146+ var targetId = target == null ? m_TargetInstanceId : target . NetworkObjectId ;
141147 // The attachable can move between the two spawned instances so we have to use the appropriate one depending upon the authority's current state.
142148 var currentAttachableRoot = m_AttachableBehaviourInstance . State == AttachableBehaviour . AttachState . Attached ? target : m_SourceInstance ;
143149 var attachable = ( TestAttachable ) null ;
@@ -146,7 +152,10 @@ private bool AllInstancesAttachedStateChanged(bool checkAttached)
146152 {
147153 if ( ! networkManager . SpawnManager . SpawnedObjects . ContainsKey ( currentAttachableRoot . NetworkObjectId ) )
148154 {
149- m_ErrorLog . AppendLine ( $ "[Client-{ networkManager . LocalClientId } ] Has no spawned instance of { currentAttachableRoot . name } !") ;
155+ if ( ! ignoreIfDespawned )
156+ {
157+ m_ErrorLog . AppendLine ( $ "[Client-{ networkManager . LocalClientId } ] Has no spawned instance of { currentAttachableRoot . name } !") ;
158+ }
150159 continue ;
151160 }
152161 else
@@ -156,7 +165,7 @@ private bool AllInstancesAttachedStateChanged(bool checkAttached)
156165
157166 if ( ! attachable )
158167 {
159- attachable = networkManager . SpawnManager . SpawnedObjects [ m_TargetInstance . NetworkObjectId ] . GetComponentInChildren < TestAttachable > ( ) ;
168+ attachable = networkManager . SpawnManager . SpawnedObjects [ m_TargetInstanceId ] . GetComponentInChildren < TestAttachable > ( ) ;
160169 if ( ! attachable )
161170 {
162171 attachable = networkManager . SpawnManager . SpawnedObjects [ m_TargetInstanceB . NetworkObjectId ] . GetComponentInChildren < TestAttachable > ( ) ;
@@ -168,14 +177,23 @@ private bool AllInstancesAttachedStateChanged(bool checkAttached)
168177 continue ;
169178 }
170179
171- if ( ! networkManager . SpawnManager . SpawnedObjects . ContainsKey ( target . NetworkObjectId ) )
180+ if ( ! networkManager . SpawnManager . SpawnedObjects . ContainsKey ( targetId ) )
172181 {
173- m_ErrorLog . AppendLine ( $ "[Client-{ networkManager . LocalClientId } ] Has no spawned instance of { target . name } !") ;
182+ if ( ! ignoreIfDespawned )
183+ {
184+ m_ErrorLog . AppendLine ( $ "[Client-{ networkManager . LocalClientId } ] Has no spawned instance of { target . name } !") ;
185+ }
174186 continue ;
175187 }
176188 else
177189 {
178- node = networkManager . SpawnManager . SpawnedObjects [ target . NetworkObjectId ] . GetComponentInChildren < TestNode > ( ) ;
190+ node = networkManager . SpawnManager . SpawnedObjects [ targetId ] . GetComponentInChildren < TestNode > ( ) ;
191+ }
192+
193+ if ( ! node && ignoreIfDespawned )
194+ {
195+ VerboseDebug ( "Skipping check during despawn." ) ;
196+ continue ;
179197 }
180198
181199 if ( ! attachable . CheckStateChangedOverride ( checkAttached , false , node ) )
@@ -202,13 +220,26 @@ private bool AllInstancesAttachedStateChanged(bool checkAttached)
202220 return m_ErrorLog . Length == 0 ;
203221 }
204222
223+ private bool AllInstancesDespawned ( )
224+ {
225+ foreach ( var networkManager in m_NetworkManagers )
226+ {
227+ if ( networkManager . SpawnManager != null && networkManager . SpawnManager . SpawnedObjects . ContainsKey ( m_TargetInstanceId ) )
228+ {
229+ return false ;
230+ }
231+ }
232+ return true ;
233+ }
234+
205235 [ UnityTest ]
206236 public IEnumerator AttachAndDetachTests ( )
207237 {
208238 var authority = GetAuthorityNetworkManager ( ) ;
209239 m_SourceInstance = SpawnObject ( m_SourcePrefab , authority ) . GetComponent < NetworkObject > ( ) ;
210240 m_TargetInstance = SpawnObject ( m_TargetPrefabA , authority ) . GetComponent < NetworkObject > ( ) ;
211241 m_TargetInstanceB = SpawnObject ( m_TargetPrefabB , authority ) . GetComponent < NetworkObject > ( ) ;
242+ m_TargetInstanceId = m_TargetInstance . NetworkObjectId ;
212243 yield return WaitForConditionOrTimeOut ( AllClientsSpawnedInstances ) ;
213244 AssertOnTimeout ( $ "Timed out waiting for all clients to spawn { m_SourceInstance . name } and { m_TargetInstance . name } !\n { m_ErrorLog } ") ;
214245
@@ -262,6 +293,26 @@ public IEnumerator AttachAndDetachTests()
262293 m_AttachableBehaviourInstance . Detach ( ) ;
263294 yield return WaitForConditionOrTimeOut ( ( ) => AllInstancesAttachedStateChanged ( false ) ) ;
264295 AssertOnTimeout ( $ "Timed out waiting for all clients to detach { m_AttachableBehaviourInstance . name } from { m_AttachableNodeInstance . name } !\n { m_ErrorLog } ") ;
296+
297+ // Finally, re-attach to the original spawned instance
298+ Assert . True ( ResetAllStates ( ) , $ "Failed to reset all states!\n { m_ErrorLog } ") ;
299+ m_AttachableBehaviourInstance . Attach ( m_AttachableNodeInstance ) ;
300+
301+ // Switch back to using the first target attachable node
302+ m_UseTargetB = false ;
303+
304+ yield return WaitForConditionOrTimeOut ( ( ) => AllInstancesAttachedStateChanged ( true ) ) ;
305+ AssertOnTimeout ( $ "[Despawn Detach Phase] Timed out waiting for all clients to attach { m_AttachableBehaviourInstance . name } to { m_AttachableNodeInstance . name } !\n { m_ErrorLog } ") ;
306+
307+ var targetInstanceName = m_TargetInstance . name ;
308+ VerboseDebug ( "======== DESPAWN & DETACH ========" ) ;
309+ m_TargetInstance . Despawn ( ) ;
310+ m_TargetInstance = null ;
311+ yield return WaitForConditionOrTimeOut ( ( ) => AllInstancesAttachedStateChanged ( false , true ) ) ;
312+ AssertOnTimeout ( $ "[Despawn Detach Phase] Timed out waiting for all clients to detach { m_AttachableBehaviourInstance . name } from { targetInstanceName } !\n { m_ErrorLog } ") ;
313+
314+ yield return WaitForConditionOrTimeOut ( AllInstancesDespawned ) ;
315+ AssertOnTimeout ( $ "[Despawn Detach Phase] Timed out waiting for all clients to despawn { targetInstanceName } !") ;
265316 }
266317
267318 /// <summary>
@@ -317,7 +368,6 @@ public bool CheckStateChangedOverride(bool checkAttached, bool checkEvent, Attac
317368 var tableToCheck = checkEvent ? m_StateUpdateEvents : m_StateUpdates ;
318369 var checkStatus = checkAttached ? ( tableToCheck . ContainsKey ( AttachState . Attaching ) && tableToCheck . ContainsKey ( AttachState . Attached ) ) :
319370 ( tableToCheck . ContainsKey ( AttachState . Detaching ) && tableToCheck . ContainsKey ( AttachState . Detached ) ) ;
320-
321371 if ( checkStatus )
322372 {
323373 foreach ( var entry in tableToCheck )
@@ -341,7 +391,9 @@ public bool CheckStateChangedOverride(bool checkAttached, bool checkEvent, Attac
341391 }
342392 else if ( entry . Value != attachableNode )
343393 {
344- Log ( $ "[{ entry . Key } ][Value] The value { entry . Value . name } is not the same as { attachableNode . name } !") ;
394+ var attachableName = attachableNode == null ? "null" : attachableNode . name ;
395+ var entryName = entry . Value == null ? "null" : entry . Value . name ;
396+ Log ( $ "[{ entry . Key } ][Value] The value { entryName } is not the same as { attachableName } !") ;
345397 checkStatus = false ;
346398 break ;
347399 }
0 commit comments