@@ -18,6 +18,12 @@ internal class NetworkObjectDontDestroyWithOwnerTests : NetcodeIntegrationTest
1818 private const int k_NumberObjectsToSpawn = 16 ;
1919 protected override int NumberOfClients => 3 ;
2020
21+ public enum ParentedPass
22+ {
23+ NoParent ,
24+ HasParent
25+ }
26+
2127 protected GameObject m_DestroyWithOwnerPrefab ;
2228 protected GameObject m_DontDestroyWithOwnerPrefab ;
2329 protected GameObject m_PrefabNoObserversSpawn ;
@@ -95,6 +101,63 @@ private void SpawnAllObjects(bool dontDestroyWithOwner)
95101 }
96102 }
97103
104+ /// <summary>
105+ /// Validates that the dont destroy with owner object is parented under
106+ /// the destroy with owner object.
107+ /// </summary>
108+ private bool HaveAllObjectInstancesParented ( StringBuilder errorLog )
109+ {
110+ foreach ( var networkManager in m_NetworkManagers )
111+ {
112+ var relativeSpawnedObjects = networkManager . SpawnManager . SpawnedObjects ;
113+ for ( int i = 0 ; i < k_NumberObjectsToSpawn ; i ++ )
114+ {
115+ var dontDestroyObjectId = m_DontDestroyObjectIds [ i ] ;
116+ var destroyObjectId = m_DestroyObjectIds [ i ] ;
117+ var dontDestroyObject = ( NetworkObject ) null ;
118+ var destroyObject = ( NetworkObject ) null ;
119+ if ( ! relativeSpawnedObjects . ContainsKey ( dontDestroyObjectId ) )
120+ {
121+ errorLog . AppendLine ( $ "[Client-{ networkManager . LocalClientId } ][DontDestroyWithOwner] Has not spawned { nameof ( NetworkObject ) } -{ dontDestroyObjectId } !") ;
122+ }
123+ else
124+ {
125+ dontDestroyObject = relativeSpawnedObjects [ dontDestroyObjectId ] ;
126+ }
127+ if ( ! relativeSpawnedObjects . ContainsKey ( destroyObjectId ) )
128+ {
129+ errorLog . AppendLine ( $ "[Client-{ networkManager . LocalClientId } ][DestroyWithOwner] Has not spawned { nameof ( NetworkObject ) } -{ destroyObjectId } !") ;
130+ }
131+ else
132+ {
133+ destroyObject = relativeSpawnedObjects [ destroyObjectId ] ;
134+ }
135+
136+ if ( dontDestroyObject != null && destroyObject != null && dontDestroyObject . transform . parent != destroyObject . transform )
137+ {
138+ errorLog . AppendLine ( $ "[Client-{ networkManager . LocalClientId } ][Not Parented] { destroyObject . name } is not parented under { dontDestroyObject . name } !") ;
139+ }
140+ }
141+ }
142+ return errorLog . Length == 0 ;
143+ }
144+
145+ /// <summary>
146+ /// Parents the dont destroy with owner objects under the destroy with owner objects for the parenting portion of the test.
147+ /// </summary>
148+ private void ParentObjects ( )
149+ {
150+ var networkManager = ! m_DistributedAuthority ? GetAuthorityNetworkManager ( ) : m_NetworkManagers . Where ( ( c ) => c . LocalClientId == m_NonAuthorityClientId ) . First ( ) ;
151+ for ( int i = 0 ; i < k_NumberObjectsToSpawn ; i ++ )
152+ {
153+ var dontDestroyObjectId = m_DontDestroyObjectIds [ i ] ;
154+ var destroyObjectId = m_DestroyObjectIds [ i ] ;
155+ var dontDestroyObject = networkManager . SpawnManager . SpawnedObjects [ dontDestroyObjectId ] ;
156+ var destroyObject = networkManager . SpawnManager . SpawnedObjects [ destroyObjectId ] ;
157+ Assert . IsTrue ( dontDestroyObject . TrySetParent ( destroyObject ) , $ "[Client-{ networkManager . LocalClientId } ][Parent Failure] Could not parent { destroyObject . name } under { dontDestroyObject . name } !") ;
158+ }
159+ }
160+
98161 /// <summary>
99162 /// Validates that the non-authority owner client disconnection
100163 /// was registered on all clients.
@@ -144,13 +207,39 @@ private bool ValidateDontDestroyWithOwner(StringBuilder errorLog)
144207 return errorLog . Length == 0 ;
145208 }
146209
210+ /// <summary>
211+ /// The primary parented validation for the <see cref="DontDestroyWithOwnerTest"/>.
212+ /// This validates that:
213+ /// - Spawned objects that are set to destroy with the owner gets destroyed/despawned when the owning client disconnects.
214+ /// - Spawned objects that are set to not destroy with the owner and parented under a spawned object set to destroy with owner that
215+ /// the objects that are set to not destroy with the owner are not destroyed/despawned when the owning client disconnects.
216+ /// </summary>
217+ private bool ValidateParentedDontDestroyWithOwnerId ( StringBuilder errorLog )
218+ {
219+ foreach ( var networkManager in m_NetworkManagers )
220+ {
221+ var relativeSpawnedObjects = networkManager . SpawnManager . SpawnedObjects ;
222+ for ( int i = 0 ; i < k_NumberObjectsToSpawn ; i ++ )
223+ {
224+ var dontDestroyObjectId = m_DontDestroyObjectIds [ i ] ;
225+ var dontDestroyObjectOwnerId = relativeSpawnedObjects [ dontDestroyObjectId ] . OwnerClientId ;
226+
227+ if ( dontDestroyObjectOwnerId == m_NonAuthorityClientId )
228+ {
229+ errorLog . AppendLine ( $ "[Client-{ networkManager . LocalClientId } ][DontDestroyWithOwner][!Owner!] { nameof ( NetworkObject ) } -{ dontDestroyObjectId } should not still belong to Client-{ m_NonAuthorityClientId } !") ;
230+ }
231+ }
232+ }
233+ return errorLog . Length == 0 ;
234+ }
235+
147236 /// <summary>
148237 /// This validates that:
149238 /// - Spawned objects that are set to destroy with the owner gets destroyed/despawned when the owning client disconnects.
150239 /// - Spawned objects that are set to not destroy with the owner are not destroyed/despawned when the owning client disconnects.
151240 /// </summary>
152241 [ UnityTest ]
153- public IEnumerator DontDestroyWithOwnerTest ( )
242+ public IEnumerator DontDestroyWithOwnerTest ( [ Values ] ParentedPass parentedPass )
154243 {
155244 var authority = GetAuthorityNetworkManager ( ) ;
156245 var nonAuthority = GetNonAuthorityNetworkManager ( ) ;
@@ -164,13 +253,26 @@ public IEnumerator DontDestroyWithOwnerTest()
164253 yield return WaitForConditionOrTimeOut ( HaveAllObjectInstancesSpawned ) ;
165254 AssertOnTimeout ( $ "Timed out waiting for all clients to spawn objects!") ;
166255
256+ if ( parentedPass == ParentedPass . HasParent )
257+ {
258+ ParentObjects ( ) ;
259+ yield return WaitForConditionOrTimeOut ( HaveAllObjectInstancesParented ) ;
260+ AssertOnTimeout ( $ "Timed out waiting for all DontDestroy objects to be parented under the Destroy objects!") ;
261+ }
262+
167263 yield return StopOneClient ( nonAuthority ) ;
168264
169265 yield return WaitForConditionOrTimeOut ( NonAuthorityHasDisconnected ) ;
170266 AssertOnTimeout ( $ "Timed out waiting for all clients to register that Client-{ m_NonAuthorityClientId } has disconnected!") ;
171267
172268 yield return WaitForConditionOrTimeOut ( ValidateDontDestroyWithOwner ) ;
173- AssertOnTimeout ( $ "Timed out while validating the DontDestroyWithOwnerTest results!") ;
269+ AssertOnTimeout ( $ "Timed out while validating the base-line DontDestroyWithOwnerTest results!") ;
270+
271+ if ( parentedPass == ParentedPass . HasParent )
272+ {
273+ yield return WaitForConditionOrTimeOut ( ValidateParentedDontDestroyWithOwnerId ) ;
274+ AssertOnTimeout ( $ "Timed out while validating the parented don't destroy objects do not still belong to disconnected Client-{ m_NonAuthorityClientId } !") ;
275+ }
174276 }
175277
176278 [ UnityTest ]
0 commit comments