using System.Collections; using NUnit.Framework; using Unity.Netcode.TestHelpers.Runtime; using UnityEngine.TestTools; namespace Unity.Netcode.RuntimeTests { [TestFixture(HostOrServer.DAHost)] [TestFixture(HostOrServer.Host)] internal class NetworkSpawnManagerTests : NetcodeIntegrationTest { private ulong serverSideClientId => NetworkManager.ServerClientId; private ulong clientSideClientId => m_ClientNetworkManagers[0].LocalClientId; private ulong otherClientSideClientId => m_ClientNetworkManagers[1].LocalClientId; protected override int NumberOfClients => 2; public NetworkSpawnManagerTests(HostOrServer hostOrServer) : base(hostOrServer) { } [Test] public void TestServerCanAccessItsOwnPlayer() { // server can access its own player var serverSideServerPlayerObject = m_ServerNetworkManager.SpawnManager.GetPlayerNetworkObject(serverSideClientId); Assert.NotNull(serverSideServerPlayerObject); Assert.AreEqual(serverSideClientId, serverSideServerPlayerObject.OwnerClientId); } /// /// Test was converted from a Test to UnityTest so distributed authority mode will pass this test. /// In distributed authority mode, client-side player spawning is enabled by default which requires /// all client (including DAHost) instances to wait for all players to be spawned. /// [UnityTest] public IEnumerator TestServerCanAccessOtherPlayers() { yield return null; // server can access other players var serverSideClientPlayerObject = m_ServerNetworkManager.SpawnManager.GetPlayerNetworkObject(clientSideClientId); Assert.NotNull(serverSideClientPlayerObject); Assert.AreEqual(clientSideClientId, serverSideClientPlayerObject.OwnerClientId); var serverSideOtherClientPlayerObject = m_ServerNetworkManager.SpawnManager.GetPlayerNetworkObject(otherClientSideClientId); Assert.NotNull(serverSideOtherClientPlayerObject); Assert.AreEqual(otherClientSideClientId, serverSideOtherClientPlayerObject.OwnerClientId); } [Test] public void TestClientCantAccessServerPlayer() { if (m_DistributedAuthority) { VerboseDebug($"Ignoring test: Clients have access to other player objects in {m_NetworkTopologyType} mode."); return; } // client can't access server player Assert.Throws(() => { m_ClientNetworkManagers[0].SpawnManager.GetPlayerNetworkObject(serverSideClientId); }); } [Test] public void TestClientCanAccessOwnPlayer() { // client can access own player var clientSideClientPlayerObject = m_ClientNetworkManagers[0].SpawnManager.GetPlayerNetworkObject(clientSideClientId); Assert.NotNull(clientSideClientPlayerObject); Assert.AreEqual(clientSideClientId, clientSideClientPlayerObject.OwnerClientId); } [Test] public void TestClientCanAccessOtherPlayer() { if (!m_DistributedAuthority) { VerboseDebug($"Ignoring test: Clients do not have access to other player objects in {m_NetworkTopologyType} mode."); return; } var otherClientPlayer = m_ClientNetworkManagers[0].SpawnManager.GetPlayerNetworkObject(otherClientSideClientId); Assert.NotNull(otherClientPlayer, $"Failed to obtain Client{otherClientSideClientId}'s player object!"); } [Test] public void TestClientCantAccessOtherPlayer() { if (m_DistributedAuthority) { VerboseDebug($"Ignoring test: Clients have access to other player objects in {m_NetworkTopologyType} mode."); return; } // client can't access other player Assert.Throws(() => { m_ClientNetworkManagers[0].SpawnManager.GetPlayerNetworkObject(otherClientSideClientId); }); } [Test] public void TestServerGetsNullValueIfInvalidId() { // server gets null value if invalid id var nullPlayer = m_ServerNetworkManager.SpawnManager.GetPlayerNetworkObject(9999); Assert.Null(nullPlayer); } [Test] public void TestServerCanUseGetLocalPlayerObject() { // test server can use GetLocalPlayerObject var serverSideServerPlayerObject = m_ServerNetworkManager.SpawnManager.GetLocalPlayerObject(); Assert.NotNull(serverSideServerPlayerObject); Assert.AreEqual(serverSideClientId, serverSideServerPlayerObject.OwnerClientId); } [Test] public void TestClientCanUseGetLocalPlayerObject() { // test client can use GetLocalPlayerObject var clientSideClientPlayerObject = m_ClientNetworkManagers[0].SpawnManager.GetLocalPlayerObject(); Assert.NotNull(clientSideClientPlayerObject); Assert.AreEqual(clientSideClientId, clientSideClientPlayerObject.OwnerClientId); } private bool m_ClientDisconnected; [UnityTest] public IEnumerator TestConnectAndDisconnect() { // test when client connects, player object is now available yield return CreateAndStartNewClient(); var newClientNetworkManager = m_ClientNetworkManagers[NumberOfClients]; var newClientLocalClientId = newClientNetworkManager.LocalClientId; // test new client can get that itself locally var newPlayerObject = newClientNetworkManager.SpawnManager.GetLocalPlayerObject(); Assert.NotNull(newPlayerObject); Assert.AreEqual(newClientLocalClientId, newPlayerObject.OwnerClientId); // test server can get that new client locally var serverSideNewClientPlayer = m_ServerNetworkManager.SpawnManager.GetPlayerNetworkObject(newClientLocalClientId); Assert.NotNull(serverSideNewClientPlayer); Assert.AreEqual(newClientLocalClientId, serverSideNewClientPlayer.OwnerClientId); // test when client disconnects, player object no longer available. var nbConnectedClients = m_ServerNetworkManager.ConnectedClients.Count; m_ClientDisconnected = false; newClientNetworkManager.OnClientDisconnectCallback += ClientNetworkManager_OnClientDisconnectCallback; m_ServerNetworkManager.DisconnectClient(newClientLocalClientId); yield return WaitForConditionOrTimeOut(() => m_ClientDisconnected); Assert.IsFalse(s_GlobalTimeoutHelper.TimedOut, "Timed out waiting for client to disconnect"); // Call this to clean up NetcodeIntegrationTestHelpers NetcodeIntegrationTestHelpers.StopOneClient(newClientNetworkManager); Assert.AreEqual(m_ServerNetworkManager.ConnectedClients.Count, nbConnectedClients - 1); serverSideNewClientPlayer = m_ServerNetworkManager.SpawnManager.GetPlayerNetworkObject(newClientLocalClientId); Assert.Null(serverSideNewClientPlayer); } private void ClientNetworkManager_OnClientDisconnectCallback(ulong obj) { m_ClientDisconnected = true; } } }