@@ -27,6 +27,12 @@ public NetworkListTests(HostOrServer host) : base(host) { }
2727
2828 private ulong m_TestObjectId ;
2929
30+ protected override IEnumerator OnSetup ( )
31+ {
32+ IsOwnerWriteTest = false ;
33+ return base . OnSetup ( ) ;
34+ }
35+
3036 protected override void OnServerAndClientsCreated ( )
3137 {
3238 m_ListObjectPrefab = CreateNetworkObjectPrefab ( "ListObject" ) ;
@@ -285,13 +291,169 @@ private int[] Shuffle(List<int> list)
285291 // This will do a shuffle of the list
286292 return list . OrderBy ( _ => rng . Next ( ) ) . ToArray ( ) ;
287293 }
294+
295+ private List < NetworkObject > m_SpawnedObjects = new List < NetworkObject > ( ) ;
296+ internal const int ValueCount = 10 ;
297+ internal static bool IsOwnerWriteTest ;
298+ internal NetworkManager LateJoinedClient ;
299+ internal static List < int > OwnerWriteExpectedValues = new List < int > ( ) ;
300+
301+ protected override void OnNewClientCreated ( NetworkManager networkManager )
302+ {
303+ if ( IsOwnerWriteTest )
304+ {
305+ LateJoinedClient = networkManager ;
306+ }
307+ else
308+ {
309+ LateJoinedClient = null ;
310+ }
311+ base . OnNewClientCreated ( networkManager ) ;
312+ }
313+
314+ [ UnityTest ]
315+ public IEnumerator OwnerWriteTests ( )
316+ {
317+ IsOwnerWriteTest = true ;
318+ var authorityNetworkManager = GetAuthorityNetworkManager ( ) ;
319+ m_SpawnedObjects . Clear ( ) ;
320+ OwnerWriteExpectedValues . Clear ( ) ;
321+ // Set our initial expected values as 0 - 9
322+ for ( int i = 0 ; i < ValueCount ; i ++ )
323+ {
324+ OwnerWriteExpectedValues . Add ( i ) ;
325+ }
326+
327+ // Each spawned instance will be owned by each NetworkManager instance in order
328+ // to validate owner write NetworkLists.
329+ foreach ( var networkManager in m_NetworkManagers )
330+ {
331+ m_SpawnedObjects . Add ( SpawnObject ( m_ListObjectPrefab , networkManager ) . GetComponent < NetworkObject > ( ) ) ;
332+ }
333+
334+ // Verify all NetworkManager instances spawned the objects
335+ yield return WaitForSpawnedOnAllOrTimeOut ( m_SpawnedObjects ) ;
336+ AssertOnTimeout ( "Not all instances were spawned on all clients!" ) ;
337+
338+ // Verify all spawned object instances have the expected owner write NetworkList values
339+ yield return WaitForConditionOrTimeOut ( OnVerifyOwnerWriteData ) ;
340+ AssertOnTimeout ( "Detected invalid count or value on one of the spawned instances!" ) ;
341+
342+ // Late join a client
343+ yield return CreateAndStartNewClient ( ) ;
344+
345+ // Spawn an instance with the new client being the owner
346+ m_SpawnedObjects . Add ( SpawnObject ( m_ListObjectPrefab , LateJoinedClient ) . GetComponent < NetworkObject > ( ) ) ;
347+
348+ // Verify all NetworkManager instances spawned the objects
349+ yield return WaitForSpawnedOnAllOrTimeOut ( m_SpawnedObjects ) ;
350+ AssertOnTimeout ( "Not all instances were spawned on all clients!" ) ;
351+
352+ // Verify all spawned object instances have the expected owner write NetworkList values
353+ yield return WaitForConditionOrTimeOut ( OnVerifyOwnerWriteData ) ;
354+ AssertOnTimeout ( "Detected invalid count or value on one of the spawned instances!" ) ;
355+
356+ // Now have all of the clients update their list values to randomly assigned values
357+ // in order to verify changes to owner write NetworkLists are synchronized properly.
358+ OwnerWriteExpectedValues . Clear ( ) ;
359+ for ( int i = 0 ; i < ValueCount ; i ++ )
360+ {
361+ OwnerWriteExpectedValues . Add ( Random . Range ( 10 , 100 ) ) ;
362+ }
363+ UpdateOwnerWriteValues ( ) ;
364+
365+ // Verify all spawned object instances have the expected owner write NetworkList values
366+ yield return WaitForConditionOrTimeOut ( OnVerifyOwnerWriteData ) ;
367+ AssertOnTimeout ( "Detected invalid count or value on one of the spawned instances!" ) ;
368+
369+ // Verifies that spawning with ownership in distributed authority mode work properly.
370+ // Where:
371+ // Client-A spawns with ownership assigned to Client-B
372+ // Client-B applies values at spawn.
373+ // All clients then should be updated with those new values applied.
374+ if ( m_DistributedAuthority )
375+ {
376+ var prefabNetworkObject = m_ListObjectPrefab . GetComponent < NetworkObject > ( ) ;
377+ foreach ( var networkManager in m_NetworkManagers )
378+ {
379+ var instance = Object . Instantiate ( m_ListObjectPrefab ) . GetComponent < NetworkObject > ( ) ;
380+ SpawnInstanceWithOwnership ( instance , authorityNetworkManager , networkManager . LocalClientId ) ;
381+ m_SpawnedObjects . Add ( instance ) ;
382+ }
383+
384+ // Verify all NetworkManager instances spawned the objects
385+ yield return WaitForSpawnedOnAllOrTimeOut ( m_SpawnedObjects ) ;
386+ AssertOnTimeout ( "Not all instances were spawned on all clients!" ) ;
387+
388+ // Verify all spawned object instances have the expected owner write NetworkList values
389+ yield return WaitForConditionOrTimeOut ( OnVerifyOwnerWriteData ) ;
390+ AssertOnTimeout ( "Detected invalid count or value on one of the spawned instances!" ) ;
391+ }
392+ }
393+
394+ private void UpdateOwnerWriteValues ( )
395+ {
396+ foreach ( var spawnedObject in m_SpawnedObjects )
397+ {
398+ var owningNetworkManager = m_NetworkManagers . Where ( ( c ) => c . LocalClientId == spawnedObject . OwnerClientId ) . First ( ) ;
399+ var networkObjectId = spawnedObject . NetworkObjectId ;
400+ var listComponent = owningNetworkManager . SpawnManager . SpawnedObjects [ networkObjectId ] . GetComponent < NetworkListTest > ( ) ;
401+ for ( int i = 0 ; i < ValueCount ; i ++ )
402+ {
403+ listComponent . OwnerWriteList [ i ] = OwnerWriteExpectedValues [ i ] ;
404+ }
405+ }
406+ }
407+
408+ private bool OnVerifyOwnerWriteData ( StringBuilder errorLog )
409+ {
410+ foreach ( var spawnedObject in m_SpawnedObjects )
411+ {
412+ var networkObjectId = spawnedObject . NetworkObjectId ;
413+ foreach ( var networkManager in m_NetworkManagers )
414+ {
415+ if ( ! networkManager . SpawnManager . SpawnedObjects . ContainsKey ( networkObjectId ) )
416+ {
417+ errorLog . Append ( $ "[Client-{ networkManager . LocalClientId } ] Does not have an instance of spawned object NetworkObjectId: { networkObjectId } ") ;
418+ return false ;
419+ }
420+ var listComponent = networkManager . SpawnManager . SpawnedObjects [ networkObjectId ] . GetComponent < NetworkListTest > ( ) ;
421+
422+ if ( listComponent == null )
423+ {
424+ errorLog . Append ( $ "[Client-{ networkManager . LocalClientId } ] List component was not found") ;
425+ return false ;
426+ }
427+
428+ if ( listComponent . OwnerWriteList . Count != ValueCount )
429+ {
430+ errorLog . Append ( $ "[Client-{ networkManager . LocalClientId } ] List component has the incorrect number of items. Expected: { ValueCount } , Have: { listComponent . TheList . Count } ") ;
431+ return false ;
432+ }
433+
434+ for ( int i = 0 ; i < ValueCount ; i ++ )
435+ {
436+ var actual = listComponent . OwnerWriteList [ i ] ;
437+ var expected = OwnerWriteExpectedValues [ i ] ;
438+ if ( expected != actual )
439+ {
440+ errorLog . Append ( $ "[Client-{ networkManager . LocalClientId } ] Incorrect value at index { i } , expected: { expected } , actual: { actual } ") ;
441+ return false ;
442+ }
443+ }
444+ }
445+ }
446+
447+ return true ;
448+ }
288449 }
289450
290451 internal class NetworkListTest : NetworkBehaviour
291452 {
292453 public readonly NetworkList < int > TheList = new ( ) ;
293454 public readonly NetworkList < StructUsedOnlyInNetworkList > TheStructList = new ( ) ;
294455 public readonly NetworkList < FixedString128Bytes > TheLargeList = new ( ) ;
456+ public readonly NetworkList < int > OwnerWriteList = new NetworkList < int > ( default , NetworkVariableReadPermission . Everyone , NetworkVariableWritePermission . Owner ) ;
295457
296458 private void ListChanged ( NetworkListEvent < int > e )
297459 {
@@ -309,6 +471,18 @@ public override void OnDestroy()
309471 base . OnDestroy ( ) ;
310472 }
311473
474+ public override void OnNetworkSpawn ( )
475+ {
476+ if ( NetworkListTests . IsOwnerWriteTest && IsOwner )
477+ {
478+ for ( int i = 0 ; i < NetworkListTests . ValueCount ; i ++ )
479+ {
480+ OwnerWriteList . Add ( NetworkListTests . OwnerWriteExpectedValues [ i ] ) ;
481+ }
482+ }
483+ base . OnNetworkSpawn ( ) ;
484+ }
485+
312486 public bool ListDelegateTriggered ;
313487 }
314488
@@ -325,8 +499,6 @@ internal class NetworkListTestPredicate : ConditionalPredicateBase
325499
326500 private readonly NetworkListTest m_NonAuthorityInstance ;
327501
328- private string m_TestStageFailedMessage ;
329-
330502 /// <summary>
331503 /// Determines if the condition has been reached for the current NetworkListTestState
332504 /// </summary>
0 commit comments