diff --git a/com.unity.netcode.gameobjects/Runtime/Core/NetworkManager.cs b/com.unity.netcode.gameobjects/Runtime/Core/NetworkManager.cs index b5a042c843..d2d1e34fea 100644 --- a/com.unity.netcode.gameobjects/Runtime/Core/NetworkManager.cs +++ b/com.unity.netcode.gameobjects/Runtime/Core/NetworkManager.cs @@ -1123,7 +1123,7 @@ internal void Initialize(bool server) UpdateTopology(); //DANGOEXP TODO: Remove this before finalizing the experimental release - NetworkConfig.AutoSpawnPlayerPrefabClientSide = DistributedAuthorityMode; + //NetworkConfig.AutoSpawnPlayerPrefabClientSide = DistributedAuthorityMode; // Make sure the ServerShutdownState is reset when initializing if (server) diff --git a/com.unity.netcode.gameobjects/Runtime/NetworkVariable/NetworkVariableBase.cs b/com.unity.netcode.gameobjects/Runtime/NetworkVariable/NetworkVariableBase.cs index a048cea2ca..75ce48aa1c 100644 --- a/com.unity.netcode.gameobjects/Runtime/NetworkVariable/NetworkVariableBase.cs +++ b/com.unity.netcode.gameobjects/Runtime/NetworkVariable/NetworkVariableBase.cs @@ -187,7 +187,9 @@ public virtual void SetDirty(bool isDirty) internal bool CanSend() { - var timeSinceLastUpdate = m_NetworkBehaviour.NetworkManager.NetworkTimeSystem.LocalTime - LastUpdateSent; + // When connected to a service or not the server, always use the synchronized server time as opposed to the local time + var time = m_InternalNetworkManager.CMBServiceConnection || !m_InternalNetworkManager.IsServer ? m_NetworkBehaviour.NetworkManager.ServerTime.Time : m_NetworkBehaviour.NetworkManager.NetworkTimeSystem.LocalTime; + var timeSinceLastUpdate = time - LastUpdateSent; return ( UpdateTraits.MaxSecondsBetweenUpdates > 0 && @@ -201,7 +203,8 @@ internal bool CanSend() internal void UpdateLastSentTime() { - LastUpdateSent = m_NetworkBehaviour.NetworkManager.NetworkTimeSystem.LocalTime; + // When connected to a service or not the server, always use the synchronized server time as opposed to the local time + LastUpdateSent = m_InternalNetworkManager.CMBServiceConnection || !m_InternalNetworkManager.IsServer ? m_NetworkBehaviour.NetworkManager.ServerTime.Time : m_NetworkBehaviour.NetworkManager.NetworkTimeSystem.LocalTime; } internal static bool IgnoreInitializeWarning; diff --git a/com.unity.netcode.gameobjects/Runtime/SceneManagement/NetworkSceneManager.cs b/com.unity.netcode.gameobjects/Runtime/SceneManagement/NetworkSceneManager.cs index 975697862b..4a7ef4a19c 100644 --- a/com.unity.netcode.gameobjects/Runtime/SceneManagement/NetworkSceneManager.cs +++ b/com.unity.netcode.gameobjects/Runtime/SceneManagement/NetworkSceneManager.cs @@ -2011,7 +2011,8 @@ internal void SynchronizeNetworkObjects(ulong clientId) // NetworkSceneManager does not synchronize scenes that are not loaded by NetworkSceneManager // unless the scene in question is the currently active scene. - if (ExcludeSceneFromSychronization != null && !ExcludeSceneFromSychronization(scene)) + if (ExcludeSceneFromSychronization != null && !ExcludeSceneFromSychronization(scene) && + (!NetworkManager.CMBServiceConnection || (NetworkManager.CMBServiceConnection && clientId != 0))) { continue; } @@ -2025,7 +2026,8 @@ internal void SynchronizeNetworkObjects(ulong clientId) // If we are the base scene, then we set the root scene index; if (activeScene == scene) { - if (!ValidateSceneBeforeLoading(scene.buildIndex, scene.name, sceneEventData.LoadSceneMode)) + if (!ValidateSceneBeforeLoading(scene.buildIndex, scene.name, sceneEventData.LoadSceneMode) && + (!NetworkManager.CMBServiceConnection || (NetworkManager.CMBServiceConnection && clientId != 0))) { continue; } @@ -2042,7 +2044,8 @@ internal void SynchronizeNetworkObjects(ulong clientId) sceneEventData.SceneHandle = scene.handle; } } - else if (!ValidateSceneBeforeLoading(scene.buildIndex, scene.name, LoadSceneMode.Additive)) + else if (!ValidateSceneBeforeLoading(scene.buildIndex, scene.name, LoadSceneMode.Additive) && + (!NetworkManager.CMBServiceConnection || (NetworkManager.CMBServiceConnection && clientId != 0))) { continue; } diff --git a/com.unity.netcode.gameobjects/TestHelpers/Runtime/NetcodeIntegrationTest.cs b/com.unity.netcode.gameobjects/TestHelpers/Runtime/NetcodeIntegrationTest.cs index 216569355c..4a0654aefe 100644 --- a/com.unity.netcode.gameobjects/TestHelpers/Runtime/NetcodeIntegrationTest.cs +++ b/com.unity.netcode.gameobjects/TestHelpers/Runtime/NetcodeIntegrationTest.cs @@ -128,6 +128,27 @@ public enum HostOrServer protected NetworkManager m_ServerNetworkManager; protected NetworkManager[] m_ClientNetworkManagers; + /// + /// When using a client-server network topology, it will always return the m_ServerNetworkManager. + /// When using a distributed authority network topology: + /// - If running a DAHost it will return m_ServerNetworkManager + /// - If using a comb-server connection, it will return the client that is the currently assigned session owner. + /// + /// + protected NetworkManager GetSessionOwner() + { + if (!UseCMBService()) + { + return m_ServerNetworkManager; + } + if (m_ClientNetworkManagers.Length > 0) + { + var sessionOwnerId = m_ClientNetworkManagers[0].CurrentSessionOwner; + return m_ClientNetworkManagers.Where((c) => c.LocalClientId == sessionOwnerId).FirstOrDefault(); + } + return null; + } + /// /// Contains each client relative set of player NetworkObject instances /// [Client Relative set of player instances][The player instance ClientId][The player instance's NetworkObject] @@ -141,9 +162,10 @@ public enum HostOrServer protected bool m_DistributedAuthority; protected NetworkTopologyTypes m_NetworkTopologyType = NetworkTopologyTypes.ClientServer; + public static bool UseCMBServiceForDATests; protected virtual bool UseCMBService() { - return false; + return UseCMBServiceForDATests ? m_DistributedAuthority : false; } protected virtual NetworkTopologyTypes OnGetNetworkTopologyType() @@ -531,7 +553,7 @@ protected IEnumerator CreateAndStartNewClient() AssertOnTimeout($"{nameof(CreateAndStartNewClient)} timed out waiting for the new client to be connected!\n {m_InternalErrorLog}"); ClientNetworkManagerPostStart(networkManager); - if (networkManager.DistributedAuthorityMode) + if (networkManager.DistributedAuthorityMode && networkManager.NetworkConfig.AutoSpawnPlayerPrefabClientSide) { yield return WaitForConditionOrTimeOut(() => AllPlayerObjectClonesSpawned(networkManager)); AssertOnTimeout($"{nameof(CreateAndStartNewClient)} timed out waiting for all sessions to spawn Client-{networkManager.LocalClientId}'s player object!"); @@ -546,19 +568,22 @@ private bool AllPlayerObjectClonesSpawned(NetworkManager joinedClient) m_InternalErrorLog.Clear(); // Continue to populate the PlayerObjects list until all player object (local and clone) are found ClientNetworkManagerPostStart(joinedClient); - - var playerObjectRelative = m_ServerNetworkManager.SpawnManager.PlayerObjects.Where((c) => c.OwnerClientId == joinedClient.LocalClientId).FirstOrDefault(); - if (playerObjectRelative == null) + var playerObjectRelative = (NetworkObject)null; + if (!UseCMBService()) { - m_InternalErrorLog.Append($"[AllPlayerObjectClonesSpawned][Server-Side] Joining Client-{joinedClient.LocalClientId} was not populated in the {nameof(NetworkSpawnManager.PlayerObjects)} list!"); - return false; - } - else - { - // Go ahead and create an entry for this new client - if (!m_PlayerNetworkObjects[m_ServerNetworkManager.LocalClientId].ContainsKey(joinedClient.LocalClientId)) + playerObjectRelative = m_ServerNetworkManager.SpawnManager.PlayerObjects.Where((c) => c.OwnerClientId == joinedClient.LocalClientId).FirstOrDefault(); + if (playerObjectRelative == null) + { + m_InternalErrorLog.Append($"[AllPlayerObjectClonesSpawned][Server-Side] Joining Client-{joinedClient.LocalClientId} was not populated in the {nameof(NetworkSpawnManager.PlayerObjects)} list!"); + return false; + } + else { - m_PlayerNetworkObjects[m_ServerNetworkManager.LocalClientId].Add(joinedClient.LocalClientId, playerObjectRelative); + // Go ahead and create an entry for this new client + if (!m_PlayerNetworkObjects[m_ServerNetworkManager.LocalClientId].ContainsKey(joinedClient.LocalClientId)) + { + m_PlayerNetworkObjects[m_ServerNetworkManager.LocalClientId].Add(joinedClient.LocalClientId, playerObjectRelative); + } } } @@ -770,6 +795,11 @@ protected virtual void OnTimeTravelServerAndClientsConnected() private void ClientNetworkManagerPostStart(NetworkManager networkManager) { + if (m_DistributedAuthority && !networkManager.NetworkConfig.AutoSpawnPlayerPrefabClientSide) + { + return; + } + networkManager.name = $"NetworkManager - Client - {networkManager.LocalClientId}"; Assert.NotNull(networkManager.LocalClient.PlayerObject, $"{nameof(StartServerAndClients)} detected that client {networkManager.LocalClientId} does not have an assigned player NetworkObject!"); @@ -818,14 +848,19 @@ private void ClientNetworkManagerPostStart(NetworkManager networkManager) protected void ClientNetworkManagerPostStartInit() { + // Creates a dictionary for all player instances client and server relative // This provides a simpler way to get a specific player instance relative to a client instance foreach (var networkManager in m_ClientNetworkManagers) { + if (networkManager.DistributedAuthorityMode && !networkManager.AutoSpawnPlayerPrefabClientSide) + { + continue; + } ClientNetworkManagerPostStart(networkManager); } - if (m_UseHost) + if (m_UseHost && !UseCMBService()) { #if UNITY_2023_1_OR_NEWER var clientSideServerPlayerClones = Object.FindObjectsByType(FindObjectsSortMode.None).Where((c) => c.IsPlayerObject && c.OwnerClientId == m_ServerNetworkManager.LocalClientId); @@ -901,7 +936,7 @@ protected IEnumerator StartServerAndClients() AssertOnTimeout($"{nameof(StartServerAndClients)} timed out waiting for all clients to be connected!\n {m_InternalErrorLog}"); - if (m_UseHost || m_ServerNetworkManager.IsHost) + if (!UseCMBService() && (m_UseHost || m_ServerNetworkManager.IsHost)) { #if UNITY_2023_1_OR_NEWER // Add the server player instance to all m_ClientSidePlayerNetworkObjects entries @@ -926,13 +961,13 @@ protected IEnumerator StartServerAndClients() //AssertOnTimeout($"{nameof(CreateAndStartNewClient)} timed out waiting for all sessions to spawn all player objects!"); foreach (var networkManager in m_ClientNetworkManagers) { - if (networkManager.DistributedAuthorityMode) + if (networkManager.DistributedAuthorityMode && networkManager.AutoSpawnPlayerPrefabClientSide) { yield return WaitForConditionOrTimeOut(() => AllPlayerObjectClonesSpawned(networkManager)); AssertOnTimeout($"{nameof(CreateAndStartNewClient)} timed out waiting for all sessions to spawn Client-{networkManager.LocalClientId}'s player object!\n {m_InternalErrorLog}"); } } - if (m_ServerNetworkManager != null) + if (m_ServerNetworkManager != null && !UseCMBService()) { yield return WaitForConditionOrTimeOut(() => AllPlayerObjectClonesSpawned(m_ServerNetworkManager)); AssertOnTimeout($"{nameof(CreateAndStartNewClient)} timed out waiting for all sessions to spawn Client-{m_ServerNetworkManager.LocalClientId}'s player object!\n {m_InternalErrorLog}"); @@ -1459,7 +1494,7 @@ private bool CheckClientsConnected(NetworkManager[] clientsToCheck) { m_InternalErrorLog.Clear(); var allClientsConnected = true; - + var actualConnected = 0; for (int i = 0; i < clientsToCheck.Length; i++) { if (!clientsToCheck[i].IsConnectedClient) @@ -1467,14 +1502,21 @@ private bool CheckClientsConnected(NetworkManager[] clientsToCheck) allClientsConnected = false; m_InternalErrorLog.AppendLine($"[Client-{i + 1}] Client is not connected!"); } + else + { + actualConnected++; + } } - var expectedCount = m_ServerNetworkManager.IsHost ? clientsToCheck.Length + 1 : clientsToCheck.Length; - var currentCount = m_ServerNetworkManager.ConnectedClients.Count; - if (currentCount != expectedCount) + var expectedCount = m_ServerNetworkManager.IsHost && !UseCMBService() && !m_ServerNetworkManager.IsConnectedClient ? clientsToCheck.Length + 1 : clientsToCheck.Length; + + + if (expectedCount != actualConnected) { + var currentCount = GetSessionOwner().ConnectedClients.Count; + var logErrorHeader = !UseCMBService() ? "[Server-Side]" : "[SessionOwner-Side]"; allClientsConnected = false; - m_InternalErrorLog.AppendLine($"[Server-Side] Expected {expectedCount} clients to connect but only {currentCount} connected!"); + m_InternalErrorLog.AppendLine($"{logErrorHeader} Expected {expectedCount} clients to connect but only {actualConnected} connected with a total of {currentCount} connected clients!"); } return allClientsConnected; diff --git a/com.unity.netcode.gameobjects/Tests/Runtime/DistributedAuthority/DeferredDespawningTests.cs b/com.unity.netcode.gameobjects/Tests/Runtime/DistributedAuthority/DeferredDespawningTests.cs index faba405079..f2c9390212 100644 --- a/com.unity.netcode.gameobjects/Tests/Runtime/DistributedAuthority/DeferredDespawningTests.cs +++ b/com.unity.netcode.gameobjects/Tests/Runtime/DistributedAuthority/DeferredDespawningTests.cs @@ -1,6 +1,7 @@ using System; using System.Collections; using System.Collections.Generic; +using System.Text; using NUnit.Framework; using Unity.Netcode.TestHelpers.Runtime; using UnityEngine; @@ -9,14 +10,16 @@ namespace Unity.Netcode.RuntimeTests { + [TestFixture(HostOrServer.DAHost)] internal class DeferredDespawningTests : IntegrationTestWithApproximation { private const int k_DaisyChainedCount = 5; protected override int NumberOfClients => 2; private List m_DaisyChainedDespawnObjects = new List(); private List m_HasReachedEnd = new List(); + private NetworkManager m_SessionOwner; - public DeferredDespawningTests() : base(HostOrServer.DAHost) + public DeferredDespawningTests(HostOrServer hostOrServer) : base(hostOrServer) { } @@ -33,6 +36,7 @@ protected override void OnServerAndClientsCreated() daisyChainPrevious.PrefabToSpawnWhenDespawned = daisyChainBehaviour.gameObject; } m_DaisyChainedDespawnObjects.Add(daisyChainNode); + daisyChainNode.SetActive(false); daisyChainPrevious = daisyChainBehaviour; } @@ -40,22 +44,25 @@ protected override void OnServerAndClientsCreated() base.OnServerAndClientsCreated(); } - - [UnityTest] public IEnumerator DeferredDespawning() { - DeferredDespawnDaisyChained.EnableVerbose = m_EnableVerboseDebug; - var rootInstance = SpawnObject(m_DaisyChainedDespawnObjects[0], m_ServerNetworkManager); + DeferredDespawnDaisyChained.TestFailed.Clear(); + m_SessionOwner = GetSessionOwner(); + foreach (var daisyChaingedObject in m_DaisyChainedDespawnObjects) + { + daisyChaingedObject.SetActive(true); + } + var rootInstance = SpawnObject(m_DaisyChainedDespawnObjects[0], m_SessionOwner); DeferredDespawnDaisyChained.ReachedLastChainInstance = ReachedLastChainObject; - var timeoutHelper = new TimeoutHelper(300); + var timeoutHelper = new TimeoutHelper(30); yield return WaitForConditionOrTimeOut(HaveAllClientsReachedEndOfChain, timeoutHelper); - AssertOnTimeout($"Timed out waiting for all children to reach the end of their chained deferred despawns!", timeoutHelper); + AssertOnTimeout($"Timed out waiting for all children to reach the end of their chained deferred despawns! {DeferredDespawnDaisyChained.TestFailed.ToString()}", timeoutHelper); } private bool HaveAllClientsReachedEndOfChain() { - if (!m_HasReachedEnd.Contains(m_ServerNetworkManager.LocalClientId)) + if (!m_HasReachedEnd.Contains(m_SessionOwner.LocalClientId)) { return false; } @@ -111,9 +118,11 @@ private void PingInstance() private DeferredDespawnDaisyChained m_NextNodeSpawned = null; + public static StringBuilder TestFailed = new StringBuilder(); + private void FailTest(string msg) { - Assert.Fail($"[{nameof(DeferredDespawnDaisyChained)}][Client-{NetworkManager.LocalClientId}] {msg}"); + TestFailed.AppendLine($"[{nameof(DeferredDespawnDaisyChained)}][Client-{NetworkManager.LocalClientId}] {msg}"); } public override void OnNetworkSpawn() @@ -134,6 +143,7 @@ public override void OnNetworkSpawn() if (!HasAuthority) { m_ValidateDirtyNetworkVarUpdate.OnValueChanged += OnValidateDirtyChanged; + m_ValidateDirtyNetworkVarUpdate.Value.TryGet(out m_NextNodeSpawned, NetworkManager); } if (HasAuthority && IsRoot) @@ -146,6 +156,7 @@ public override void OnNetworkSpawn() private void OnValidateDirtyChanged(NetworkBehaviourReference previous, NetworkBehaviourReference current) { + Log($"[OnValidateDirtyChanged] Getting NetworkBehaviour component...."); if (!HasAuthority) { if (!current.TryGet(out m_NextNodeSpawned, NetworkManager)) @@ -157,6 +168,11 @@ private void OnValidateDirtyChanged(NetworkBehaviourReference previous, NetworkB { FailTest($"[{nameof(NetworkManager)}][{nameof(NetworkBehaviourReference.TryGet)}] The {nameof(NetworkManager)} of {nameof(m_NextNodeSpawned)} does not match the local relative {nameof(NetworkManager)} instance!"); } + + if (m_NextNodeSpawned != null) + { + Log($"[OnValidateDirtyChanged] m_NextNodeSpawned set -- {m_NextNodeSpawned.name}!"); + } } } @@ -164,8 +180,19 @@ public override void OnNetworkDespawn() { if (!HasAuthority && !NetworkManager.ShutdownInProgress) { + Log($"[OnNetworkDespawn] despawning... "); if (PrefabToSpawnWhenDespawned != null) { + if (m_NextNodeSpawned == null) + { + Log($"[OnNetworkDespawn] No m_NextNodeSpawned set!!!"); + if (!m_ValidateDirtyNetworkVarUpdate.Value.TryGet(out m_NextNodeSpawned, NetworkManager)) + { + FailTest($"[{nameof(OnValidateDirtyChanged)}][{nameof(NetworkBehaviourReference)}] Failed to get the {nameof(DeferredDespawnDaisyChained)} behaviour from the {nameof(NetworkBehaviourReference)}!"); + return; + } + } + Log($"[OnNetworkDespawn] Pinging {m_NextNodeSpawned.name}..."); m_NextNodeSpawned.PingInstance(); } else @@ -178,11 +205,13 @@ public override void OnNetworkDespawn() private void InvokeDespawn() { + Log($"Despawn with defer started! DeferDespawnTick = {DeferDespawnTick}"); if (!HasAuthority) { FailTest($"[{nameof(InvokeDespawn)}] Client is not the authority but this was invoked (integration test logic issue)!"); } NetworkObject.DeferDespawn(DeferDespawnTick); + Log($"Should despawn on tick {DeferDespawnTick + NetworkManager.ServerTime.Tick}..."); } public override void OnDeferringDespawn(int despawnTick) @@ -196,13 +225,13 @@ public override void OnDeferringDespawn(int despawnTick) { FailTest($"[{nameof(OnDeferringDespawn)}] The passed in {despawnTick} parameter ({despawnTick}) does not equal the expected value of ({DeferDespawnTick + NetworkManager.ServerTime.Tick})!"); } - + Log($"[OnDeferringDespawn] Deferring despawn..."); if (PrefabToSpawnWhenDespawned != null) { var deferNetworkObject = PrefabToSpawnWhenDespawned.GetComponent().InstantiateAndSpawn(NetworkManager); var deferComponent = deferNetworkObject.GetComponent(); // Slowly increment the despawn tick count as we process the chain of deferred despawns - deferComponent.DeferDespawnTick = DeferDespawnTick + 1; + deferComponent.DeferDespawnTick = k_StartingDeferTick + 1; // This should get updated on all non-authority instances before they despawn m_ValidateDirtyNetworkVarUpdate.Value = new NetworkBehaviourReference(deferComponent); } @@ -214,13 +243,17 @@ public override void OnDeferringDespawn(int despawnTick) } private bool m_DeferredDespawn; + private bool m_InstantiatedObject; + private float m_TickDelay; + + private DeferredDespawnDaisyChained m_DeferredComponent; + private NetworkObject m_DeferredObject; private void Update() { if (!IsSpawned || !HasAuthority || m_DeferredDespawn) { return; } - // Wait until all clients have this instance foreach (var clientId in NetworkManager.ConnectedClientsIds) { @@ -248,8 +281,6 @@ private void Update() return; } } - - // If we made it here, then defer despawn this instance InvokeDespawn(); m_DeferredDespawn = true; } @@ -260,7 +291,7 @@ private void Log(string message) { return; } - Debug.Log($"[{name}][Client-{NetworkManager.LocalClientId}][{NetworkObjectId}] {message}"); + Debug.Log($"[{name}][Client-{NetworkManager.LocalClientId}][{NetworkObjectId}][{NetworkManager.ServerTime.Tick}][DD: {NetworkManager.ServerTime.Tick + DeferDespawnTick}] {message}"); } } } diff --git a/com.unity.netcode.gameobjects/Tests/Runtime/DistributedAuthority/DistributeObjectsTests.cs b/com.unity.netcode.gameobjects/Tests/Runtime/DistributedAuthority/DistributeObjectsTests.cs index 7957e6cf0c..8c018e0f00 100644 --- a/com.unity.netcode.gameobjects/Tests/Runtime/DistributedAuthority/DistributeObjectsTests.cs +++ b/com.unity.netcode.gameobjects/Tests/Runtime/DistributedAuthority/DistributeObjectsTests.cs @@ -6,7 +6,6 @@ using NUnit.Framework; using Unity.Netcode.Components; using Unity.Netcode.TestHelpers.Runtime; -using Unity.Netcode.Transports.UTP; using UnityEngine; using UnityEngine.TestTools; using Random = UnityEngine.Random; @@ -17,6 +16,7 @@ namespace Unity.Netcode.RuntimeTests /// Validates that distributable NetworkObjects are distributed upon /// a client connecting or disconnecting. /// + [TestFixture(HostOrServer.DAHost)] internal class DistributeObjectsTests : IntegrationTestWithApproximation { private GameObject m_DistributeObject; @@ -26,8 +26,11 @@ internal class DistributeObjectsTests : IntegrationTestWithApproximation private const int k_LateJoinClientCount = 4; protected override int NumberOfClients => 0; - public DistributeObjectsTests() : base(HostOrServer.DAHost) + private NetworkManager m_SessionOwner; + + public DistributeObjectsTests(HostOrServer hostOrServer) : base(hostOrServer) { + } protected override IEnumerator OnSetup() @@ -38,9 +41,7 @@ protected override IEnumerator OnSetup() protected override void OnServerAndClientsCreated() { - var serverTransport = m_ServerNetworkManager.NetworkConfig.NetworkTransport as UnityTransport; - // I hate having to add time to our tests, but in case a VM is running slow the disconnect timeout needs to be reasonably high - serverTransport.DisconnectTimeoutMS = 1000; + m_DistributeObject = CreateNetworkObjectPrefab("DisObject"); m_DistributeObject.AddComponent(); m_DistributeObject.AddComponent(); @@ -54,8 +55,12 @@ protected override void OnServerAndClientsCreated() protected override IEnumerator OnServerAndClientsConnected() { - m_ServerNetworkManager.SpawnManager.EnableDistributeLogging = m_EnableVerboseDebug; - m_ServerNetworkManager.ConnectionManager.EnableDistributeLogging = m_EnableVerboseDebug; + if (!UseCMBService()) + { + m_ServerNetworkManager.SpawnManager.EnableDistributeLogging = m_EnableVerboseDebug; + m_ServerNetworkManager.ConnectionManager.EnableDistributeLogging = m_EnableVerboseDebug; + } + return base.OnServerAndClientsConnected(); } @@ -67,9 +72,9 @@ private bool ValidateObjectSpawnedOnAllClients() var networkObjectId = m_ObjectToValidate.NetworkObjectId; var name = m_ObjectToValidate.name; - if (!UseCMBService() && !m_ServerNetworkManager.SpawnManager.SpawnedObjects.ContainsKey(networkObjectId)) + if (!UseCMBService() && !m_SessionOwner.SpawnManager.SpawnedObjects.ContainsKey(networkObjectId)) { - m_ErrorLog.Append($"Client-{m_ServerNetworkManager.LocalClientId} has not spawned {name}!"); + m_ErrorLog.Append($"Client-{m_SessionOwner.LocalClientId} has not spawned {name}!"); return false; } @@ -89,7 +94,7 @@ private bool ValidateObjectSpawnedOnAllClients() private bool ValidateDistributedObjectsSpawned(bool lateJoining) { m_ErrorLog.Clear(); - var hostId = m_ServerNetworkManager.LocalClientId; + var hostId = m_SessionOwner.LocalClientId; if (!DistributeObjectsTestHelper.DistributedObjects.ContainsKey(hostId)) { m_ErrorLog.AppendLine($"[Client-{hostId}] Does not have an entry in the root of the {nameof(DistributeObjectsTestHelper.DistributedObjects)} table!"); @@ -104,13 +109,14 @@ private bool ValidateDistributedObjectsSpawned(bool lateJoining) var daHostObjects = daHostObjectTracking[hostId]; var expected = 0; + var offset = UseCMBService() ? 0 : 1; if (lateJoining) { - expected = k_ObjectCount / (m_ClientNetworkManagers.Count() + 1); + expected = k_ObjectCount / (m_ClientNetworkManagers.Count() + offset); } else { - expected = k_ObjectCount / (m_ClientNetworkManagers.Where((c) => c.IsConnectedClient).Count() + 1); + expected = k_ObjectCount / (m_ClientNetworkManagers.Where((c) => c.IsConnectedClient).Count() + offset); } // It should theoretically be the expected or... @@ -140,8 +146,9 @@ private bool ValidateDistributedObjectsSpawned(bool lateJoining) private bool ValidateOwnershipTablesMatch() { m_ErrorLog.Clear(); - var hostId = m_ServerNetworkManager.LocalClientId; - var expectedEntries = m_ClientNetworkManagers.Where((c) => c.IsListening && c.IsConnectedClient).Count() + 1; + var hostId = m_SessionOwner.LocalClientId; + var offset = UseCMBService() ? 0 : 1; + var expectedEntries = m_ClientNetworkManagers.Where((c) => c.IsListening && c.IsConnectedClient).Count() + offset; // Make sure all clients have an table created if (DistributeObjectsTestHelper.DistributedObjects.Count < expectedEntries) { @@ -160,16 +167,22 @@ private bool ValidateOwnershipTablesMatch() m_ErrorLog.AppendLine($"[Client-{hostId}] Does not have a local an entry in the {nameof(DistributeObjectsTestHelper.DistributedObjects)} table!"); return false; } - var clients = m_ServerNetworkManager.ConnectedClientsIds.ToList(); + var clients = m_SessionOwner.ConnectedClientsIds.ToList(); clients.Remove(0); - // Cycle through each client's entry on the DAHost to run a comparison + // Cycle through each client's entry on the session owner side to run a comparison foreach (var hostClientEntry in daHostEntries) { foreach (var ownerEntry in hostClientEntry.Value) { foreach (var client in clients) { + if (!DistributeObjectsTestHelper.DistributedObjects.ContainsKey(client)) + { + m_ErrorLog.AppendLine($"[Client-{client}] Does not have a local an entry in the {nameof(DistributeObjectsTestHelper.DistributedObjects)} table!"); + return false; + } + var clientOwnerTable = DistributeObjectsTestHelper.DistributedObjects[client]; if (!clientOwnerTable.ContainsKey(hostClientEntry.Key)) { @@ -206,9 +219,9 @@ private bool ValidateOwnershipTablesMatch() private bool ValidateTransformsMatch() { m_ErrorLog.Clear(); - var hostId = m_ServerNetworkManager.LocalClientId; + var hostId = m_SessionOwner.LocalClientId; var daHostEntries = DistributeObjectsTestHelper.DistributedObjects[hostId]; - var clients = m_ServerNetworkManager.ConnectedClientsIds.ToList(); + var clients = m_SessionOwner.ConnectedClientsIds.ToList(); foreach (var clientOwner in daHostEntries.Keys) { // Cycle through the owner's objects @@ -237,23 +250,27 @@ private bool ValidateTransformsMatch() protected override void OnNewClientCreated(NetworkManager networkManager) { - networkManager.NetworkConfig.Prefabs = m_ServerNetworkManager.NetworkConfig.Prefabs; + if (UseCMBService() && m_SessionOwner == null) + { + networkManager.NetworkConfig.Prefabs = m_ServerNetworkManager.NetworkConfig.Prefabs; + } + else + { + networkManager.NetworkConfig.Prefabs = m_SessionOwner.NetworkConfig.Prefabs; + } + //networkManager.NetworkConfig.AutoSpawnPlayerPrefabClientSide = false; + //networkManager.NetworkConfig.EnableSceneManagement = false; + + base.OnNewClientCreated(networkManager); } private bool SpawnCountsMatch() { var passed = true; - var spawnCount = 0; m_ErrorLog.Clear(); - if (!UseCMBService()) - { - spawnCount = m_ServerNetworkManager.SpawnManager.SpawnedObjects.Count; - } - else - { - spawnCount = m_ClientNetworkManagers[0].SpawnManager.SpawnedObjects.Count; - } + var spawnCount = m_SessionOwner.SpawnManager.SpawnedObjects.Count; + foreach (var client in m_ClientNetworkManagers) { var clientCount = client.SpawnManager.SpawnedObjects.Count; @@ -276,13 +293,21 @@ private bool SpawnCountsMatch() [UnityTest] public IEnumerator DistributeNetworkObjects() { + var clientIndexOffset = 0; + if (UseCMBService()) + { + clientIndexOffset++; + yield return CreateAndStartNewClient(); + } + + m_SessionOwner = GetSessionOwner(); for (int i = 0; i < k_ObjectCount; i++) { - SpawnObject(m_DistributeObject, m_ServerNetworkManager); + SpawnObject(m_DistributeObject, m_SessionOwner); } // Validate NetworkObjects get redistributed properly when a client joins - for (int j = 0; j < k_LateJoinClientCount; j++) + for (int j = clientIndexOffset; j < k_LateJoinClientCount + clientIndexOffset; j++) { yield return CreateAndStartNewClient(); @@ -303,10 +328,16 @@ public IEnumerator DistributeNetworkObjects() AssertOnTimeout($"[Spawn Count Mismatch] {m_ErrorLog}"); } + var clientStartIndex = m_ClientNetworkManagers.Length; + // Validate NetworkObjects get redistributed properly when a client disconnects - for (int j = k_LateJoinClientCount - 1; j >= 0; j--) + for (int j = k_LateJoinClientCount - 1 + clientIndexOffset; j >= 0; j--) { var client = m_ClientNetworkManagers[j]; + if (UseCMBService() && client.LocalClient.IsSessionOwner) + { + continue; + } // Remove the client from the other clients' ownership tracking table DistributeObjectsTestHelper.RemoveClient(client.LocalClientId); @@ -314,8 +345,6 @@ public IEnumerator DistributeNetworkObjects() // Disconnect the client yield return StopOneClient(client, true); - //yield return new WaitForSeconds(0.1f); - // Validate all tables match yield return WaitForConditionOrTimeOut(ValidateOwnershipTablesMatch); @@ -338,7 +367,8 @@ public IEnumerator DistributeNetworkObjects() private void DisplayOwnership() { m_ErrorLog.Clear(); - var daHostEntries = DistributeObjectsTestHelper.DistributedObjects[0]; + var startingIndex = (ulong)(UseCMBService() ? 1 : 0); + var daHostEntries = DistributeObjectsTestHelper.DistributedObjects[startingIndex]; foreach (var entry in daHostEntries) { diff --git a/com.unity.netcode.gameobjects/Tests/Runtime/DistributedAuthority/NetworkClientAndPlayerObjectTests.cs b/com.unity.netcode.gameobjects/Tests/Runtime/DistributedAuthority/NetworkClientAndPlayerObjectTests.cs index d7890c202f..289f611485 100644 --- a/com.unity.netcode.gameobjects/Tests/Runtime/DistributedAuthority/NetworkClientAndPlayerObjectTests.cs +++ b/com.unity.netcode.gameobjects/Tests/Runtime/DistributedAuthority/NetworkClientAndPlayerObjectTests.cs @@ -22,7 +22,6 @@ internal class NetworkClientAndPlayerObjectTests : NetcodeIntegrationTest private List m_PlayerPrefabs = new List(); private Dictionary m_ChangedPlayerPrefabs = new Dictionary(); - public NetworkClientAndPlayerObjectTests(HostOrServer hostOrServer) : base(hostOrServer) { } @@ -45,7 +44,8 @@ protected override void OnServerAndClientsCreated() protected override void OnNewClientCreated(NetworkManager networkManager) { - networkManager.NetworkConfig.Prefabs = m_ServerNetworkManager.NetworkConfig.Prefabs; + var sessionOwner = GetSessionOwner(); + networkManager.NetworkConfig.Prefabs = sessionOwner.NetworkConfig.Prefabs; if (m_DistributedAuthority) { networkManager.OnFetchLocalPlayerPrefabToSpawn = FetchPlayerPrefabToSpawn; @@ -101,7 +101,7 @@ private bool ValidateNetworkManagerNetworkClients(NetworkManager networkManager) m_ErrorLogLevel2.Clear(); // Number of connected clients plus the DAHost - var expectedCount = m_ClientNetworkManagers.Length + (m_UseHost ? 1 : 0); + var expectedCount = UseCMBService() ? m_ClientNetworkManagers.Length : m_ClientNetworkManagers.Length + (m_UseHost ? 1 : 0); if (networkManager.ConnectedClients.Count != expectedCount) { @@ -265,7 +265,7 @@ public IEnumerator ValidatePlayerObjects() m_ChangedPlayerPrefabs.Clear(); var playerInstance = (GameObject)null; var playerPrefabToSpawn = (NetworkObject)null; - if (m_UseHost) + if (m_UseHost && !UseCMBService()) { playerPrefabToSpawn = GetRandomPlayerPrefab(); playerInstance = SpawnPlayerObject(playerPrefabToSpawn.gameObject, m_ServerNetworkManager); diff --git a/com.unity.netcode.gameobjects/Tests/Runtime/DistributedAuthority/OwnershipPermissionsTests.cs b/com.unity.netcode.gameobjects/Tests/Runtime/DistributedAuthority/OwnershipPermissionsTests.cs index beccbdd9db..0f6e45b14d 100644 --- a/com.unity.netcode.gameobjects/Tests/Runtime/DistributedAuthority/OwnershipPermissionsTests.cs +++ b/com.unity.netcode.gameobjects/Tests/Runtime/DistributedAuthority/OwnershipPermissionsTests.cs @@ -6,18 +6,22 @@ using Unity.Netcode.TestHelpers.Runtime; using UnityEngine; using UnityEngine.TestTools; +using Object = UnityEngine.Object; namespace Unity.Netcode.RuntimeTests { + [TestFixture(HostOrServer.DAHost)] internal class OwnershipPermissionsTests : IntegrationTestWithApproximation { private GameObject m_PermissionsObject; private StringBuilder m_ErrorLog = new StringBuilder(); + private NetworkManager m_SessionOwner; + protected override int NumberOfClients => 4; - public OwnershipPermissionsTests() : base(HostOrServer.DAHost) + public OwnershipPermissionsTests(HostOrServer hostOrServer) : base(hostOrServer) { } @@ -28,11 +32,20 @@ protected override IEnumerator OnSetup() return base.OnSetup(); } + /// + /// This is where the client NetworkManagers are configured + /// protected override void OnServerAndClientsCreated() { m_PermissionsObject = CreateNetworkObjectPrefab("PermObject"); m_PermissionsObject.AddComponent(); - + Object.DontDestroyOnLoad(m_PermissionsObject); + m_PermissionsObject.gameObject.SetActive(false); + foreach (var client in m_ClientNetworkManagers) + { + client.NetworkConfig.NetworkTopology = NetworkTopologyTypes.DistributedAuthority; + client.NetworkConfig.UseCMBService = UseCMBServiceForDATests; + } base.OnServerAndClientsCreated(); } @@ -44,9 +57,9 @@ private bool ValidateObjectSpawnedOnAllClients() var networkObjectId = m_ObjectToValidate.NetworkObjectId; var name = m_ObjectToValidate.name; - if (!UseCMBService() && !m_ServerNetworkManager.SpawnManager.SpawnedObjects.ContainsKey(networkObjectId)) + if (!UseCMBService() && !m_SessionOwner.SpawnManager.SpawnedObjects.ContainsKey(networkObjectId)) { - m_ErrorLog.Append($"Client-{m_ServerNetworkManager.LocalClientId} has not spawned {name}!"); + m_ErrorLog.Append($"Client-{m_SessionOwner.LocalClientId} has not spawned {name}!"); return false; } @@ -70,10 +83,10 @@ private bool ValidatePermissionsOnAllClients() m_ErrorLog.Clear(); if (!UseCMBService()) { - otherPermissions = (ushort)m_ServerNetworkManager.SpawnManager.SpawnedObjects[networkObjectId].Ownership; + otherPermissions = (ushort)m_SessionOwner.SpawnManager.SpawnedObjects[networkObjectId].Ownership; if (currentPermissions != otherPermissions) { - m_ErrorLog.Append($"Client-{m_ServerNetworkManager.LocalClientId} permissions for {objectName} is {otherPermissions} when it should be {currentPermissions}!"); + m_ErrorLog.Append($"Client-{m_SessionOwner.LocalClientId} permissions for {objectName} is {otherPermissions} when it should be {currentPermissions}!"); return false; } } @@ -97,10 +110,10 @@ private bool ValidateAllInstancesAreOwnedByClient(ulong clientId) m_ErrorLog.Clear(); if (!UseCMBService()) { - otherNetworkObject = m_ServerNetworkManager.SpawnManager.SpawnedObjects[networkObjectId]; + otherNetworkObject = m_SessionOwner.SpawnManager.SpawnedObjects[networkObjectId]; if (otherNetworkObject.OwnerClientId != clientId) { - m_ErrorLog.Append($"[Client-{m_ServerNetworkManager.LocalClientId}][{otherNetworkObject.name}] Expected owner to be {clientId} but it was {otherNetworkObject.OwnerClientId}!"); + m_ErrorLog.Append($"[Client-{m_SessionOwner.LocalClientId}][{otherNetworkObject.name}] Expected owner to be {clientId} but it was {otherNetworkObject.OwnerClientId}!"); return false; } } @@ -120,7 +133,11 @@ private bool ValidateAllInstancesAreOwnedByClient(ulong clientId) [UnityTest] public IEnumerator ValidateOwnershipPermissionsTest() { - var firstInstance = SpawnObject(m_PermissionsObject, m_ClientNetworkManagers[0]).GetComponent(); + m_SessionOwner = GetSessionOwner(); + + m_PermissionsObject.gameObject.SetActive(true); + yield return null; + var firstInstance = SpawnObject(m_PermissionsObject, m_SessionOwner).GetComponent(); OwnershipPermissionsTestHelper.CurrentOwnedInstance = firstInstance; var firstInstanceHelper = firstInstance.GetComponent(); var networkObjectId = firstInstance.NetworkObjectId; @@ -243,12 +260,12 @@ public IEnumerator ValidateOwnershipPermissionsTest() // Get the 3rd client to send a request at the "relatively" same time var thirdInstance = m_ClientNetworkManagers[2].SpawnManager.SpawnedObjects[networkObjectId]; var thirdInstanceHelper = thirdInstance.GetComponent(); - + yield return null; // At the same time send a request by the third client. requestStatus = thirdInstance.RequestOwnership(); // We expect the 3rd client's request should be able to be sent at this time as well (i.e. creates the race condition between two clients) - Assert.True(requestStatus == NetworkObject.OwnershipRequestStatus.RequestSent, $"Client-{m_ServerNetworkManager.LocalClientId} was unabled to send a request for ownership because: {requestStatus}!"); + Assert.True(requestStatus == NetworkObject.OwnershipRequestStatus.RequestSent, $"Client-{m_SessionOwner.LocalClientId} was unabled to send a request for ownership because: {requestStatus}!"); // We expect the first requesting client to be given ownership yield return WaitForConditionOrTimeOut(() => firstInstance.IsOwner); @@ -256,7 +273,8 @@ public IEnumerator ValidateOwnershipPermissionsTest() m_ObjectToValidate = OwnershipPermissionsTestHelper.CurrentOwnedInstance; // Just do a sanity check to assure ownership has changed on all clients. - yield return WaitForConditionOrTimeOut(() => ValidateAllInstancesAreOwnedByClient(firstInstance.NetworkManager.LocalClientId)); + yield return WaitForConditionOrTimeOut(() => ValidateAllInstancesAreOwnedByClient(firstInstance.NetworkManager.LocalClientId)); // <---- Failes here + AssertOnTimeout($"[Ownership Mismatch] {firstInstance.name}: \n {m_ErrorLog}"); // Now, the third client should get a RequestInProgress returned as their request response @@ -304,32 +322,30 @@ public IEnumerator ValidateOwnershipPermissionsTest() // Test for targeted ownership request: /////////////////////////////////////////////// - // Now get the DAHost's client's instance - var daHostInstance = m_ServerNetworkManager.SpawnManager.SpawnedObjects[networkObjectId]; - var daHostInstanceHelper = daHostInstance.GetComponent(); + var targetApprovedNetworkObject = firstInstance; + var targetApprovedTestHelper = firstInstanceHelper; + firstInstanceHelper = null; secondInstanceHelper.AllowOwnershipRequest = true; secondInstanceHelper.OnlyAllowTargetClientId = true; - secondInstanceHelper.ClientToAllowOwnership = daHostInstance.NetworkManager.LocalClientId; + secondInstanceHelper.ClientToAllowOwnership = targetApprovedNetworkObject.NetworkManager.LocalClientId; - // Send out a request from all three clients - requestStatus = firstInstance.RequestOwnership(); - Assert.True(requestStatus == NetworkObject.OwnershipRequestStatus.RequestSent, $"Client-{firstInstance.NetworkManager.LocalClientId} was unabled to send a request for ownership because: {requestStatus}!"); requestStatus = thirdInstance.RequestOwnership(); Assert.True(requestStatus == NetworkObject.OwnershipRequestStatus.RequestSent, $"Client-{thirdInstance.NetworkManager.LocalClientId} was unabled to send a request for ownership because: {requestStatus}!"); requestStatus = fourthInstance.RequestOwnership(); Assert.True(requestStatus == NetworkObject.OwnershipRequestStatus.RequestSent, $"Client-{fourthInstance.NetworkManager.LocalClientId} was unabled to send a request for ownership because: {requestStatus}!"); - requestStatus = daHostInstance.RequestOwnership(); - Assert.True(requestStatus == NetworkObject.OwnershipRequestStatus.RequestSent, $"Client-{daHostInstance.NetworkManager.LocalClientId} was unabled to send a request for ownership because: {requestStatus}!"); + requestStatus = targetApprovedNetworkObject.RequestOwnership(); + Assert.True(requestStatus == NetworkObject.OwnershipRequestStatus.RequestSent, $"Client-{targetApprovedNetworkObject.NetworkManager.LocalClientId} was unabled to send a request for ownership because: {requestStatus}!"); - // The server and the 2nd client should be denied and the third client should be approved yield return WaitForConditionOrTimeOut(() => - (firstInstanceHelper.OwnershipRequestResponseStatus == NetworkObject.OwnershipRequestResponseStatus.Denied) && - (thirdInstanceHelper.OwnershipRequestResponseStatus == NetworkObject.OwnershipRequestResponseStatus.Denied) && - (fourthInstanceHelper.OwnershipRequestResponseStatus == NetworkObject.OwnershipRequestResponseStatus.Denied) && - (daHostInstanceHelper.OwnershipRequestResponseStatus == NetworkObject.OwnershipRequestResponseStatus.Approved) + (thirdInstanceHelper.OwnershipRequestResponseStatus == NetworkObject.OwnershipRequestResponseStatus.Denied || thirdInstanceHelper.OwnershipRequestResponseStatus == NetworkObject.OwnershipRequestResponseStatus.RequestInProgress) && + (fourthInstanceHelper.OwnershipRequestResponseStatus == NetworkObject.OwnershipRequestResponseStatus.Denied || fourthInstanceHelper.OwnershipRequestResponseStatus == NetworkObject.OwnershipRequestResponseStatus.RequestInProgress) && + (targetApprovedTestHelper.OwnershipRequestResponseStatus == NetworkObject.OwnershipRequestResponseStatus.Approved) ); - AssertOnTimeout($"[Targeted Owner] Client-{daHostInstance.NetworkManager.LocalClientId} did not get the right request reponse: {daHostInstanceHelper.OwnershipRequestResponseStatus} Expecting: {NetworkObject.OwnershipRequestResponseStatus.Approved}!"); + + AssertOnTimeout($"[Targeted Owner] Client-{targetApprovedTestHelper.NetworkManager.LocalClientId} did not get the right request reponse: {targetApprovedTestHelper.OwnershipRequestResponseStatus} Expecting: {NetworkObject.OwnershipRequestResponseStatus.Approved}!"); + + yield return s_DefaultWaitForTick; } internal class OwnershipPermissionsTestHelper : NetworkBehaviour diff --git a/com.unity.netcode.gameobjects/Tests/Runtime/DistributedAuthority/RpcProxyMessageTesting.cs b/com.unity.netcode.gameobjects/Tests/Runtime/DistributedAuthority/RpcProxyMessageTesting.cs index 9a7a9f8557..a741d23a69 100644 --- a/com.unity.netcode.gameobjects/Tests/Runtime/DistributedAuthority/RpcProxyMessageTesting.cs +++ b/com.unity.netcode.gameobjects/Tests/Runtime/DistributedAuthority/RpcProxyMessageTesting.cs @@ -3,6 +3,7 @@ using System.Text; using NUnit.Framework; using Unity.Netcode.TestHelpers.Runtime; +using UnityEngine.TestTools; namespace Unity.Netcode.RuntimeTests { @@ -13,14 +14,13 @@ namespace Unity.Netcode.RuntimeTests /// so we can validate these issues. While this test does /// partially validate it we still need to manually validate /// with a service connection. - /// - [TestFixture(HostOrServer.Host)] + /// [TestFixture(HostOrServer.DAHost)] public class RpcProxyMessageTesting : NetcodeIntegrationTest { - protected override int NumberOfClients => 2; + protected override int NumberOfClients => 4; - private List m_ProxyTestInstances = new List(); + private List m_ProxyTestInstances = new List(); private StringBuilder m_ValidationLogger = new StringBuilder(); @@ -34,7 +34,7 @@ protected override IEnumerator OnSetup() protected override void OnCreatePlayerPrefab() { - m_PlayerPrefab.AddComponent(); + m_PlayerPrefab.AddComponent(); base.OnCreatePlayerPrefab(); } @@ -44,28 +44,38 @@ private bool ValidateRpcProxyRpcs() m_ValidationLogger.Clear(); foreach (var proxy in m_ProxyTestInstances) { - if (proxy.ReceivedRpc.Count < NumberOfClients) + foreach (var client in m_ClientNetworkManagers) { - m_ValidationLogger.AppendLine($"Not all clients received RPC from Client-{proxy.OwnerClientId}!"); - } - foreach (var clientId in proxy.ReceivedRpc) - { - if (clientId == proxy.OwnerClientId) + if (client.LocalClientId == proxy.OwnerClientId) { - m_ValidationLogger.AppendLine($"Client-{proxy.OwnerClientId} sent itself an Rpc!"); + continue; } + var playerClone = m_PlayerNetworkObjects[client.LocalClientId][proxy.OwnerClientId]; + var proxyClone = playerClone.GetComponent(); + if (proxyClone.ReceivedRpc.Count != 1) + { + m_ValidationLogger.AppendLine($"[Client-{client.LocalClientId}] Did not receive an RPC from Client-{proxy.OwnerClientId}!"); + } + } + if (proxy.ReceivedRpc.Contains(proxy.OwnerClientId)) + { + m_ValidationLogger.AppendLine($"Client-{proxy.OwnerClientId} sent itself an Rpc!"); } } return m_ValidationLogger.Length == 0; } - + [UnityTest] public IEnumerator ProxyDoesNotInvokeOnSender() { - m_ProxyTestInstances.Add(m_ServerNetworkManager.LocalClient.PlayerObject.GetComponent()); + if (!UseCMBService()) + { + m_ProxyTestInstances.Add(m_ServerNetworkManager.LocalClient.PlayerObject.GetComponent()); + } + foreach (var client in m_ClientNetworkManagers) { - m_ProxyTestInstances.Add(client.LocalClient.PlayerObject.GetComponent()); + m_ProxyTestInstances.Add(client.LocalClient.PlayerObject.GetComponent()); } foreach (var clientProxyTest in m_ProxyTestInstances) @@ -77,7 +87,7 @@ public IEnumerator ProxyDoesNotInvokeOnSender() AssertOnTimeout(m_ValidationLogger.ToString()); } - public class RpcProxyText : NetworkBehaviour + public class RpcProxyTest : NetworkBehaviour { public List ReceivedRpc = new List(); diff --git a/testproject/Assets/Tests/Runtime/NetworkSceneManager/NetworkSceneManagerEventNotifications.cs b/testproject/Assets/Tests/Runtime/NetworkSceneManager/NetworkSceneManagerEventNotifications.cs index 34a2078499..90cf111146 100644 --- a/testproject/Assets/Tests/Runtime/NetworkSceneManager/NetworkSceneManagerEventNotifications.cs +++ b/testproject/Assets/Tests/Runtime/NetworkSceneManager/NetworkSceneManagerEventNotifications.cs @@ -72,7 +72,10 @@ protected override IEnumerator OnTearDown() protected override IEnumerator OnStartedServerAndClients() { - m_ServerNetworkManager.SceneManager.OnSceneEvent += ServerSceneManager_OnSceneEvent; + if (!UseCMBService()) + { + m_ServerNetworkManager.SceneManager.OnSceneEvent += ServerSceneManager_OnSceneEvent; + } foreach (var client in m_ClientNetworkManagers) { client.SceneManager.ClientSynchronizationMode = m_LoadSceneMode; @@ -90,7 +93,7 @@ private void ClientSceneManager_OnSceneEvent(SceneEvent sceneEvent) { var matchedClient = m_ClientNetworkManagers.Where(c => c.LocalClientId == sceneEvent.ClientId); Assert.True(matchedClient.Count() > 0, $"Found no client {nameof(NetworkManager)}s that had a {nameof(NetworkManager.LocalClientId)} of {sceneEvent.ClientId}"); - Assert.AreEqual(matchedClient.First().SceneManager.ClientSynchronizationMode, m_ServerNetworkManager.SceneManager.ClientSynchronizationMode); + Assert.AreEqual(matchedClient.First().SceneManager.ClientSynchronizationMode, m_SessionOwner.SceneManager.ClientSynchronizationMode); break; } } @@ -98,6 +101,7 @@ private void ClientSceneManager_OnSceneEvent(SceneEvent sceneEvent) private void ServerSceneManager_OnSceneEvent(SceneEvent sceneEvent) { + var clientCompleted = UseCMBService() ? m_ClientNetworkManagers[1] : m_ClientNetworkManagers[0]; VerboseDebug($"[SceneEvent] ClientId:{sceneEvent.ClientId} | EventType: {sceneEvent.SceneEventType}"); switch (sceneEvent.SceneEventType) { @@ -120,12 +124,13 @@ private void ServerSceneManager_OnSceneEvent(SceneEvent sceneEvent) } case SceneEventType.LoadComplete: { - if (sceneEvent.ClientId == NetworkManager.ServerClientId) + if (sceneEvent.ClientId == m_SessionOwner.LocalClientId) { var scene = sceneEvent.Scene; m_CurrentScene = scene; } - if (sceneEvent.ClientId == m_ClientNetworkManagers[0].LocalClientId) + + if (sceneEvent.ClientId == clientCompleted.LocalClientId) { if (!m_ScenesLoaded.Contains(sceneEvent.SceneName)) { @@ -156,10 +161,10 @@ private void ServerSceneManager_OnSceneEvent(SceneEvent sceneEvent) // If we are a server and this is being processed by the server, then add the server to the completed list // to validate that the event completed on all clients (and the server). - if (!m_ServerNetworkManager.IsHost && sceneEvent.ClientId == m_ServerNetworkManager.LocalClientId && - !sceneEvent.ClientsThatCompleted.Contains(m_ServerNetworkManager.LocalClientId)) + if (!m_SessionOwner.IsServer && sceneEvent.ClientId == m_SessionOwner.LocalClientId && + !sceneEvent.ClientsThatCompleted.Contains(m_SessionOwner.LocalClientId)) { - sceneEvent.ClientsThatCompleted.Add(m_ServerNetworkManager.LocalClientId); + sceneEvent.ClientsThatCompleted.Add(m_SessionOwner.LocalClientId); } if (sceneEvent.SceneEventType == SceneEventType.LoadEventCompleted) { @@ -213,6 +218,7 @@ protected override bool CanStartServerAndClients() return m_CanStartServerOrClients; } + private NetworkManager m_SessionOwner; /// /// Tests the different types of NetworkSceneManager notifications (including exceptions) generated /// Also tests invalid loading scenarios (i.e. client trying to load a scene) @@ -220,6 +226,7 @@ protected override bool CanStartServerAndClients() [UnityTest] public IEnumerator SceneLoadingAndNotifications([Values] LoadSceneMode loadSceneMode) { + m_SessionOwner = UseCMBService() ? m_ClientNetworkManagers[0] : m_ServerNetworkManager; m_LoadSceneMode = loadSceneMode; m_CurrentSceneName = k_SceneToLoad; @@ -237,9 +244,9 @@ public IEnumerator SceneLoadingAndNotifications([Values] LoadSceneMode loadScene // Test loading scenes and the associated event messaging and notification pipelines ResetWait(); - Assert.AreEqual(m_ServerNetworkManager.SceneManager.LoadScene(m_CurrentSceneName, loadSceneMode), SceneEventProgressStatus.Started); + Assert.AreEqual(m_SessionOwner.SceneManager.LoadScene(m_CurrentSceneName, loadSceneMode), SceneEventProgressStatus.Started); // Check error status for trying to load during an already in progress scene event - Assert.AreEqual(m_ServerNetworkManager.SceneManager.LoadScene(m_CurrentSceneName, loadSceneMode), SceneEventProgressStatus.SceneEventInProgress); + Assert.AreEqual(m_SessionOwner.SceneManager.LoadScene(m_CurrentSceneName, loadSceneMode), SceneEventProgressStatus.SceneEventInProgress); // Wait for all clients to load the scene yield return WaitForConditionOrTimeOut(ConditionPassed); @@ -256,7 +263,7 @@ public IEnumerator SceneLoadingAndNotifications([Values] LoadSceneMode loadScene m_CurrentSceneName = k_InSceneNetworkObject; ResetWait(); - Assert.AreEqual(m_ServerNetworkManager.SceneManager.LoadScene(k_InSceneNetworkObject, LoadSceneMode.Additive), SceneEventProgressStatus.Started); + Assert.AreEqual(m_SessionOwner.SceneManager.LoadScene(k_InSceneNetworkObject, LoadSceneMode.Additive), SceneEventProgressStatus.Started); // Wait for all clients to additively load this additional scene yield return WaitForConditionOrTimeOut(ConditionPassed); @@ -266,7 +273,7 @@ public IEnumerator SceneLoadingAndNotifications([Values] LoadSceneMode loadScene // Now single mode load a new scene (i.e. "scene switch") m_CurrentSceneName = k_BaseUnitTestSceneName; ResetWait(); - Assert.AreEqual(m_ServerNetworkManager.SceneManager.LoadScene(m_CurrentSceneName, loadSceneMode), SceneEventProgressStatus.Started); + Assert.AreEqual(m_SessionOwner.SceneManager.LoadScene(m_CurrentSceneName, loadSceneMode), SceneEventProgressStatus.Started); // Wait for all clients to perform scene switch yield return WaitForConditionOrTimeOut(ConditionPassed); AssertOnTimeout($"Timed out waiting for all clients to switch to scene {m_CurrentSceneName}!"); @@ -288,18 +295,18 @@ public IEnumerator SceneLoadingAndNotifications([Values] LoadSceneMode loadScene // Test unloading additive scenes and the associated event messaging and notification pipelines ResetWait(); - Assert.AreEqual(m_ServerNetworkManager.SceneManager.UnloadScene(m_CurrentScene), SceneEventProgressStatus.Started); + Assert.AreEqual(m_SessionOwner.SceneManager.UnloadScene(m_CurrentScene), SceneEventProgressStatus.Started); yield return WaitForConditionOrTimeOut(ConditionPassed); AssertOnTimeout($"Timed out waiting for all clients to unload {m_CurrentSceneName}!"); // Check error status for trying to unloading something not loaded ResetWait(); - Assert.AreEqual(m_ServerNetworkManager.SceneManager.UnloadScene(m_CurrentScene), SceneEventProgressStatus.SceneNotLoaded); + Assert.AreEqual(m_SessionOwner.SceneManager.UnloadScene(m_CurrentScene), SceneEventProgressStatus.SceneNotLoaded); // Check error status for trying to load an invalid scene name LogAssert.Expect(LogType.Error, $"Scene '{k_InvalidSceneName}' couldn't be loaded because it has not been added to the build settings scenes in build list."); - Assert.AreEqual(m_ServerNetworkManager.SceneManager.LoadScene(k_InvalidSceneName, LoadSceneMode.Additive), SceneEventProgressStatus.InvalidSceneName); + Assert.AreEqual(m_SessionOwner.SceneManager.LoadScene(k_InvalidSceneName, LoadSceneMode.Additive), SceneEventProgressStatus.InvalidSceneName); }