MultiplayerSystemTests.cpp 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583
  1. /*
  2. * Copyright (c) Contributors to the Open 3D Engine Project.
  3. * For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0 OR MIT
  6. *
  7. */
  8. #include <CommonBenchmarkSetup.h>
  9. #include <CommonHierarchySetup.h>
  10. #include <MockInterfaces.h>
  11. #include <AzCore/Jobs/JobManagerComponent.h>
  12. #include <AzCore/UnitTest/TestTypes.h>
  13. #include <AzCore/UnitTest/UnitTest.h>
  14. #include <AzCore/Name/NameDictionary.h>
  15. #include <AzCore/Name/Name.h>
  16. #include <AzCore/RTTI/BehaviorContext.h>
  17. #include <AzFramework/Components/TransformComponent.h>
  18. #include <AzFramework/Spawnable/SpawnableSystemComponent.h>
  19. #include <AzNetworking/UdpTransport/UdpPacketHeader.h>
  20. #include <AzNetworking/Framework/NetworkingSystemComponent.h>
  21. #include <AzTest/AzTest.h>
  22. #include <MultiplayerSystemComponent.h>
  23. #include <IMultiplayerConnectionMock.h>
  24. #include <IMultiplayerSpawnerMock.h>
  25. #include <ConnectionData/ServerToClientConnectionData.h>
  26. #include <ReplicationWindows/ServerToClientReplicationWindow.h>
  27. #include <Multiplayer/Components/NetBindComponent.h>
  28. #include <Multiplayer/MultiplayerConstants.h>
  29. #include <Multiplayer/Session/SessionConfig.h>
  30. namespace Multiplayer
  31. {
  32. AZ_CVAR_EXTERNED(AZ::CVarFixedString, sv_map);
  33. AZ_CVAR_EXTERNED(bool, sv_versionMismatch_autoDisconnect);
  34. AZ_CVAR_EXTERNED(bool, sv_versionMismatch_sendManifestToClient);
  35. class MultiplayerSystemTests : public LeakDetectionFixture
  36. {
  37. public:
  38. void SetUp() override
  39. {
  40. AZ::NameDictionary::Create();
  41. m_ComponentApplicationRequests = AZStd::make_unique<BenchmarkComponentApplicationRequests>();
  42. AZ::Interface<AZ::ComponentApplicationRequests>::Register(m_ComponentApplicationRequests.get());
  43. m_mockTime = AZStd::make_unique<AZ::NiceTimeSystemMock>();
  44. m_mockLevelSystem = AZStd::make_unique<MockLevelSystemLifecycle>();
  45. m_console.reset(aznew AZ::Console());
  46. AZ::Interface<AZ::IConsole>::Register(m_console.get());
  47. // register components involved in testing
  48. m_serializeContext = AZStd::make_unique<AZ::SerializeContext>();
  49. m_behaviorContext = AZStd::make_unique<AZ::BehaviorContext>();
  50. m_transformDescriptor.reset(AzFramework::TransformComponent::CreateDescriptor());
  51. m_transformDescriptor->Reflect(m_serializeContext.get());
  52. m_netBindDescriptor.reset(NetBindComponent::CreateDescriptor());
  53. m_netBindDescriptor->Reflect(m_serializeContext.get());
  54. m_jobComponentDescriptor.reset(AZ::JobManagerComponent::CreateDescriptor());
  55. m_jobComponentDescriptor->Reflect(m_serializeContext.get());
  56. m_netComponent = new AzNetworking::NetworkingSystemComponent();
  57. m_mpComponent = new Multiplayer::MultiplayerSystemComponent();
  58. m_mpComponent->Reflect(m_serializeContext.get());
  59. m_mpComponent->Reflect(m_behaviorContext.get());
  60. m_connAcquiredHandler = Multiplayer::ConnectionAcquiredEvent::Handler(
  61. [this](Multiplayer::MultiplayerAgentDatum value)
  62. {
  63. TestConnectionAcquiredEvent(value);
  64. });
  65. m_mpComponent->AddConnectionAcquiredHandler(m_connAcquiredHandler);
  66. m_endpointDisconnectedHandler = Multiplayer::EndpointDisconnectedEvent::Handler(
  67. [this](Multiplayer::MultiplayerAgentType value)
  68. {
  69. TestEndpointDisconnectedEvent(value);
  70. });
  71. m_mpComponent->AddEndpointDisconnectedHandler(m_endpointDisconnectedHandler);
  72. m_mpComponent->Activate();
  73. m_systemEntity = AZStd::make_unique<AZ::Entity>(AZ::EntityId(0));
  74. m_systemEntity->CreateComponent<AZ::JobManagerComponent>(); // Needed by Job system when @sv_multithreadedConnectionUpdates is on.
  75. m_systemEntity->Init();
  76. m_systemEntity->Activate();
  77. }
  78. void TearDown() override
  79. {
  80. m_systemEntity->Deactivate();
  81. m_systemEntity.reset();
  82. m_mpComponent->Deactivate();
  83. delete m_mpComponent;
  84. delete m_netComponent;
  85. AZ::Interface<AZ::IConsole>::Unregister(m_console.get());
  86. m_console.reset();
  87. m_mockTime.reset();
  88. m_mockLevelSystem.reset();
  89. AZ::Interface<AZ::ComponentApplicationRequests>::Unregister(m_ComponentApplicationRequests.get());
  90. m_ComponentApplicationRequests.reset();
  91. AZ::NameDictionary::Destroy();
  92. m_jobComponentDescriptor.reset();
  93. m_transformDescriptor.reset();
  94. m_netBindDescriptor.reset();
  95. m_serializeContext.reset();
  96. m_behaviorContext.reset();
  97. }
  98. void TestConnectionAcquiredEvent(Multiplayer::MultiplayerAgentDatum& datum)
  99. {
  100. m_connectionAcquiredCount += aznumeric_cast<uint32_t>(datum.m_id);
  101. }
  102. void TestEndpointDisconnectedEvent([[maybe_unused]] Multiplayer::MultiplayerAgentType value)
  103. {
  104. ++m_endpointDisconnectedCount;
  105. }
  106. void CreateAndRegisterNetBindComponent(
  107. AZ::Entity& playerEntity, NetworkEntityTracker& playerNetworkEntityTracker, NetEntityRole netEntityRole)
  108. {
  109. playerEntity.CreateComponent<AzFramework::TransformComponent>();
  110. const auto playerNetBindComponent = playerEntity.CreateComponent<NetBindComponent>();
  111. playerNetBindComponent->m_netEntityRole = netEntityRole;
  112. playerNetworkEntityTracker.RegisterNetBindComponent(&playerEntity, playerNetBindComponent);
  113. playerEntity.Init();
  114. playerEntity.Activate();
  115. }
  116. AZStd::unique_ptr<AZ::SerializeContext> m_serializeContext;
  117. AZStd::unique_ptr<AZ::BehaviorContext> m_behaviorContext;
  118. AZStd::unique_ptr<AZ::ComponentDescriptor> m_transformDescriptor;
  119. AZStd::unique_ptr<AZ::ComponentDescriptor> m_netBindDescriptor;
  120. AZStd::unique_ptr<AZ::ComponentDescriptor> m_jobComponentDescriptor;
  121. AZStd::unique_ptr<AZ::IConsole> m_console;
  122. AZStd::unique_ptr<AZ::NiceTimeSystemMock> m_mockTime;
  123. AZStd::unique_ptr<AZ::Entity> m_systemEntity;
  124. class MockLevelSystemLifecycle : public AzFramework::ILevelSystemLifecycle
  125. {
  126. public:
  127. MockLevelSystemLifecycle()
  128. {
  129. AZ::Interface<AzFramework::ILevelSystemLifecycle>::Register(this);
  130. }
  131. ~MockLevelSystemLifecycle() override
  132. {
  133. AZ::Interface<AzFramework::ILevelSystemLifecycle>::Unregister(this);
  134. }
  135. const char* GetCurrentLevelName() const override
  136. {
  137. return m_levelName.c_str();
  138. }
  139. bool IsLevelLoaded() const override
  140. {
  141. return true;
  142. }
  143. AZStd::string m_levelName = "MockedMultiplayerLevelName";
  144. };
  145. AZStd::unique_ptr<MockLevelSystemLifecycle> m_mockLevelSystem;
  146. uint32_t m_connectionAcquiredCount = 0;
  147. uint32_t m_endpointDisconnectedCount = 0;
  148. Multiplayer::ConnectionAcquiredEvent::Handler m_connAcquiredHandler;
  149. Multiplayer::EndpointDisconnectedEvent::Handler m_endpointDisconnectedHandler;
  150. AzNetworking::NetworkingSystemComponent* m_netComponent = nullptr;
  151. Multiplayer::MultiplayerSystemComponent* m_mpComponent = nullptr;
  152. AZStd::unique_ptr<BenchmarkComponentApplicationRequests> m_ComponentApplicationRequests;
  153. IMultiplayerSpawnerMock m_mpSpawnerMock;
  154. };
  155. TEST_F(MultiplayerSystemTests, TestShutdownEvent)
  156. {
  157. m_mpComponent->InitializeMultiplayer(Multiplayer::MultiplayerAgentType::DedicatedServer);
  158. IMultiplayerConnectionMock connMock1 =
  159. IMultiplayerConnectionMock(AzNetworking::ConnectionId(), AzNetworking::IpAddress(), AzNetworking::ConnectionRole::Acceptor);
  160. IMultiplayerConnectionMock connMock2 =
  161. IMultiplayerConnectionMock(AzNetworking::ConnectionId(), AzNetworking::IpAddress(), AzNetworking::ConnectionRole::Connector);
  162. m_mpComponent->OnDisconnect(&connMock1, AzNetworking::DisconnectReason::None, AzNetworking::TerminationEndpoint::Local);
  163. m_mpComponent->OnDisconnect(&connMock2, AzNetworking::DisconnectReason::None, AzNetworking::TerminationEndpoint::Local);
  164. EXPECT_EQ(m_endpointDisconnectedCount, 2);
  165. }
  166. TEST_F(MultiplayerSystemTests, TestConnectionDatum)
  167. {
  168. using namespace testing;
  169. NiceMock<IMultiplayerConnectionMock> connMock1(
  170. aznumeric_cast<AzNetworking::ConnectionId>(10), AzNetworking::IpAddress(), AzNetworking::ConnectionRole::Acceptor);
  171. NiceMock<IMultiplayerConnectionMock> connMock2(
  172. aznumeric_cast<AzNetworking::ConnectionId>(15), AzNetworking::IpAddress(), AzNetworking::ConnectionRole::Acceptor);
  173. m_mpComponent->OnConnect(&connMock1);
  174. m_mpComponent->OnConnect(&connMock2);
  175. EXPECT_EQ(m_connectionAcquiredCount, 25);
  176. // Clean up connection data
  177. m_mpComponent->OnDisconnect(&connMock1, AzNetworking::DisconnectReason::None, AzNetworking::TerminationEndpoint::Local);
  178. m_mpComponent->OnDisconnect(&connMock2, AzNetworking::DisconnectReason::None, AzNetworking::TerminationEndpoint::Local);
  179. EXPECT_EQ(m_endpointDisconnectedCount, 2);
  180. }
  181. TEST_F(MultiplayerSystemTests, TestSpawnerEvents)
  182. {
  183. AZ::Interface<Multiplayer::IMultiplayerSpawner>::Register(&m_mpSpawnerMock);
  184. m_mpComponent->InitializeMultiplayer(Multiplayer::MultiplayerAgentType::ClientServer);
  185. AZ_TEST_START_TRACE_SUPPRESSION;
  186. // Setup mock connection and dummy connection data, this should raise two errors around entity validity
  187. Multiplayer::NetworkEntityHandle controlledEntity;
  188. IMultiplayerConnectionMock connMock =
  189. IMultiplayerConnectionMock(AzNetworking::ConnectionId(), AzNetworking::IpAddress(), AzNetworking::ConnectionRole::Acceptor);
  190. Multiplayer::ServerToClientConnectionData* connectionData =
  191. new Multiplayer::ServerToClientConnectionData(&connMock, *m_mpComponent);
  192. connectionData->GetReplicationManager().SetReplicationWindow(
  193. AZStd::make_unique<Multiplayer::ServerToClientReplicationWindow>(controlledEntity, &connMock));
  194. connMock.SetUserData(connectionData);
  195. m_mpComponent->OnDisconnect(&connMock, AzNetworking::DisconnectReason::None, AzNetworking::TerminationEndpoint::Local);
  196. AZ_TEST_STOP_TRACE_SUPPRESSION(2);
  197. EXPECT_EQ(m_endpointDisconnectedCount, 1);
  198. EXPECT_EQ(m_mpSpawnerMock.m_playerCount, 0);
  199. AZ::Interface<Multiplayer::IMultiplayerSpawner>::Unregister(&m_mpSpawnerMock);
  200. }
  201. TEST_F(MultiplayerSystemTests, TestClientServerConnectingWithoutPlayerEntity)
  202. {
  203. AZ::Interface<IMultiplayerSpawner>::Register(&m_mpSpawnerMock);
  204. m_mpSpawnerMock.m_networkEntityHandle = NetworkEntityHandle();
  205. EXPECT_FALSE(m_mpSpawnerMock.m_networkEntityHandle.Exists());
  206. m_mpComponent->InitializeMultiplayer(MultiplayerAgentType::ClientServer);
  207. EXPECT_EQ(m_mpSpawnerMock.m_playerEntityRequestedCount, 1);
  208. // We don't have a player entity yet, so MultiplayerSystemComponent should request another player entity when root spawnable (a new
  209. // level) is finished loading
  210. AzFramework::RootSpawnableNotificationBus::Broadcast(
  211. &AzFramework::RootSpawnableNotificationBus::Events::OnRootSpawnableReady, AZ::Data::Asset<AzFramework::Spawnable>(), 0);
  212. EXPECT_EQ(m_mpSpawnerMock.m_playerEntityRequestedCount, 2);
  213. AZ::Interface<IMultiplayerSpawner>::Unregister(&m_mpSpawnerMock);
  214. }
  215. TEST_F(MultiplayerSystemTests, TestClientServerConnectingWithPlayerEntity)
  216. {
  217. AZ::Interface<IMultiplayerSpawner>::Register(&m_mpSpawnerMock);
  218. // Setup a net player entity
  219. AZ::Entity playerEntity;
  220. NetworkEntityTracker playerNetworkEntityTracker;
  221. CreateAndRegisterNetBindComponent(playerEntity, playerNetworkEntityTracker, NetEntityRole::Authority);
  222. m_mpSpawnerMock.m_networkEntityHandle = NetworkEntityHandle(&playerEntity, &playerNetworkEntityTracker);
  223. EXPECT_TRUE(m_mpSpawnerMock.m_networkEntityHandle.Exists());
  224. // Initialize the ClientServer (this will also spawn a player for the host)
  225. m_mpComponent->InitializeMultiplayer(MultiplayerAgentType::ClientServer);
  226. EXPECT_EQ(m_mpSpawnerMock.m_playerEntityRequestedCount, 1);
  227. // Send a connection request. This should cause another player to be spawned.
  228. MultiplayerPackets::Connect connectPacket(
  229. 0, 1, "connect_ticket", GetMultiplayerComponentRegistry()->GetSystemVersionHash());
  230. IMultiplayerConnectionMock connection(
  231. ConnectionId{ 1 }, IpAddress("127.0.0.1", DefaultServerPort, ProtocolType::Udp), ConnectionRole::Connector);
  232. ServerToClientConnectionData connectionUserData(&connection, *m_mpComponent);
  233. connection.SetUserData(&connectionUserData);
  234. m_mpComponent->HandleRequest(&connection, UdpPacketHeader(), connectPacket);
  235. EXPECT_EQ(m_mpSpawnerMock.m_playerEntityRequestedCount, 2);
  236. // Players should already be created and we should not request another player entity when root spawnable (a new
  237. // level) is finished loading
  238. AzFramework::RootSpawnableNotificationBus::Broadcast(
  239. &AzFramework::RootSpawnableNotificationBus::Events::OnRootSpawnableReady, AZ::Data::Asset<AzFramework::Spawnable>(), 0);
  240. EXPECT_EQ(m_mpSpawnerMock.m_playerEntityRequestedCount, 2); // player count is still 2 (stays the same)
  241. AZ::Interface<IMultiplayerSpawner>::Unregister(&m_mpSpawnerMock);
  242. }
  243. TEST_F(MultiplayerSystemTests, TestMultiplayerTick)
  244. {
  245. m_mpComponent->InitializeMultiplayer(MultiplayerAgentType::DedicatedServer);
  246. EXPECT_EQ(m_mpComponent->GetAgentType(), MultiplayerAgentType::DedicatedServer);
  247. IMultiplayerConnectionMock connection(
  248. ConnectionId{ 1 }, IpAddress("127.0.0.1", DefaultServerPort, ProtocolType::Udp), ConnectionRole::Connector);
  249. ServerToClientConnectionData connectionUserData(&connection, *m_mpComponent);
  250. connection.SetUserData(&connectionUserData);
  251. m_mpComponent->OnTick(1, AZ::ScriptTimePoint());
  252. }
  253. TEST_F(MultiplayerSystemTests, TestHandleAccept)
  254. {
  255. m_mpComponent->InitializeMultiplayer(MultiplayerAgentType::Client);
  256. EXPECT_EQ(m_mpComponent->GetAgentType(), MultiplayerAgentType::Client);
  257. IMultiplayerConnectionMock connection(
  258. ConnectionId{ 1 }, IpAddress("127.0.0.1", DefaultServerPort, ProtocolType::Udp), ConnectionRole::Connector);
  259. ServerToClientConnectionData connectionUserData(&connection, *m_mpComponent);
  260. connection.SetUserData(&connectionUserData);
  261. MultiplayerPackets::Accept accept;
  262. EXPECT_TRUE(m_mpComponent->HandleRequest(&connection, UdpPacketHeader(), accept));
  263. MultiplayerPackets::ClientMigration clientMigration;
  264. clientMigration.SetTemporaryUserIdentifier(1);
  265. EXPECT_TRUE(m_mpComponent->HandleRequest(&connection, UdpPacketHeader(), clientMigration));
  266. EXPECT_TRUE(m_mpComponent->HandleRequest(&connection, UdpPacketHeader(), accept));
  267. m_mpComponent->RequestPlayerLeaveSession();
  268. m_netComponent->ForceUpdate();
  269. }
  270. TEST_F(MultiplayerSystemTests, TestHandleReadyForEntityUpdate)
  271. {
  272. m_mpComponent->InitializeMultiplayer(MultiplayerAgentType::Client);
  273. EXPECT_EQ(m_mpComponent->GetAgentType(), MultiplayerAgentType::Client);
  274. IMultiplayerConnectionMock connection(
  275. ConnectionId{ 1 }, IpAddress("127.0.0.1", DefaultServerPort, ProtocolType::Udp), ConnectionRole::Connector);
  276. MultiplayerPackets::ReadyForEntityUpdates readyForEntityUpdates;
  277. EXPECT_FALSE(m_mpComponent->HandleRequest(&connection, UdpPacketHeader(), readyForEntityUpdates));
  278. ServerToClientConnectionData connectionUserData(&connection, *m_mpComponent);
  279. connection.SetUserData(&connectionUserData);
  280. EXPECT_TRUE(m_mpComponent->HandleRequest(&connection, UdpPacketHeader(), readyForEntityUpdates));
  281. }
  282. TEST_F(MultiplayerSystemTests, TestHandleClientMigrationFailOnServer)
  283. {
  284. m_mpComponent->InitializeMultiplayer(MultiplayerAgentType::DedicatedServer);
  285. EXPECT_EQ(m_mpComponent->GetAgentType(), MultiplayerAgentType::DedicatedServer);
  286. IMultiplayerConnectionMock connection(
  287. ConnectionId{ 1 }, IpAddress("127.0.0.1", DefaultServerPort, ProtocolType::Udp), ConnectionRole::Connector);
  288. MultiplayerPackets::ClientMigration clientMigration;
  289. EXPECT_FALSE(m_mpComponent->HandleRequest(&connection, UdpPacketHeader(), clientMigration));
  290. }
  291. TEST_F(MultiplayerSystemTests, TestHandleSyncConsole)
  292. {
  293. m_mpComponent->InitializeMultiplayer(MultiplayerAgentType::DedicatedServer);
  294. EXPECT_EQ(m_mpComponent->GetAgentType(), MultiplayerAgentType::DedicatedServer);
  295. IMultiplayerConnectionMock connection(
  296. ConnectionId{ 1 }, IpAddress("127.0.0.1", DefaultServerPort, ProtocolType::Udp), ConnectionRole::Connector);
  297. MultiplayerPackets::SyncConsole syncConsole;
  298. EXPECT_FALSE(m_mpComponent->HandleRequest(&connection, UdpPacketHeader(), syncConsole));
  299. m_mpComponent->InitializeMultiplayer(MultiplayerAgentType::Client);
  300. EXPECT_EQ(m_mpComponent->GetAgentType(), MultiplayerAgentType::Client);
  301. EXPECT_TRUE(m_mpComponent->HandleRequest(&connection, UdpPacketHeader(), syncConsole));
  302. }
  303. TEST_F(MultiplayerSystemTests, TestHandleConsoleCommand)
  304. {
  305. m_mpComponent->InitializeMultiplayer(MultiplayerAgentType::DedicatedServer);
  306. EXPECT_EQ(m_mpComponent->GetAgentType(), MultiplayerAgentType::DedicatedServer);
  307. IMultiplayerConnectionMock connection(
  308. ConnectionId{ 1 }, IpAddress("127.0.0.1", DefaultServerPort, ProtocolType::Udp), ConnectionRole::Connector);
  309. MultiplayerPackets::ConsoleCommand consoleCommand;
  310. EXPECT_TRUE(m_mpComponent->HandleRequest(&connection, UdpPacketHeader(), consoleCommand));
  311. m_mpComponent->InitializeMultiplayer(MultiplayerAgentType::Client);
  312. EXPECT_EQ(m_mpComponent->GetAgentType(), MultiplayerAgentType::Client);
  313. EXPECT_TRUE(m_mpComponent->HandleRequest(&connection, UdpPacketHeader(), consoleCommand));
  314. }
  315. TEST_F(MultiplayerSystemTests, TestHandleEntityUpdates)
  316. {
  317. m_mpComponent->InitializeMultiplayer(MultiplayerAgentType::Client);
  318. EXPECT_EQ(m_mpComponent->GetAgentType(), MultiplayerAgentType::Client);
  319. IMultiplayerConnectionMock connection(
  320. ConnectionId{ 1 }, IpAddress("127.0.0.1", DefaultServerPort, ProtocolType::Udp), ConnectionRole::Connector);
  321. MultiplayerPackets::EntityUpdates entityUpdates;
  322. EXPECT_TRUE(m_mpComponent->HandleRequest(&connection, UdpPacketHeader(), entityUpdates));
  323. ServerToClientConnectionData connectionUserData(&connection, *m_mpComponent);
  324. connection.SetUserData(&connectionUserData);
  325. entityUpdates.SetHostFrameId(HostFrameId(100));
  326. NetworkEntityUpdateVector entityUpdateVector;
  327. NetworkEntityUpdateMessage entityUpdateMessage;
  328. entityUpdateVector.push_back(entityUpdateMessage);
  329. entityUpdates.SetEntityMessages(entityUpdateVector);
  330. AZ_TEST_START_TRACE_SUPPRESSION;
  331. EXPECT_FALSE(m_mpComponent->HandleRequest(&connection, UdpPacketHeader(), entityUpdates));
  332. AZ_TEST_STOP_TRACE_SUPPRESSION(2);
  333. }
  334. TEST_F(MultiplayerSystemTests, TestHandleEntityRpcs)
  335. {
  336. m_mpComponent->InitializeMultiplayer(MultiplayerAgentType::Client);
  337. EXPECT_EQ(m_mpComponent->GetAgentType(), MultiplayerAgentType::Client);
  338. IMultiplayerConnectionMock connection(
  339. ConnectionId{ 1 }, IpAddress("127.0.0.1", DefaultServerPort, ProtocolType::Udp), ConnectionRole::Connector);
  340. MultiplayerPackets::EntityRpcs entityRpcs;
  341. EXPECT_TRUE(m_mpComponent->HandleRequest(&connection, UdpPacketHeader(), entityRpcs));
  342. ServerToClientConnectionData connectionUserData(&connection, *m_mpComponent);
  343. connection.SetUserData(&connectionUserData);
  344. EXPECT_TRUE(m_mpComponent->HandleRequest(&connection, UdpPacketHeader(), entityRpcs));
  345. }
  346. TEST_F(MultiplayerSystemTests, TestHandleRequestReplicatorReset)
  347. {
  348. m_mpComponent->InitializeMultiplayer(MultiplayerAgentType::Client);
  349. EXPECT_EQ(m_mpComponent->GetAgentType(), MultiplayerAgentType::Client);
  350. IMultiplayerConnectionMock connection(
  351. ConnectionId{ 1 }, IpAddress("127.0.0.1", DefaultServerPort, ProtocolType::Udp), ConnectionRole::Connector);
  352. MultiplayerPackets::RequestReplicatorReset replicatorReset;
  353. EXPECT_TRUE(m_mpComponent->HandleRequest(&connection, UdpPacketHeader(), replicatorReset));
  354. ServerToClientConnectionData connectionUserData(&connection, *m_mpComponent);
  355. connection.SetUserData(&connectionUserData);
  356. EXPECT_TRUE(m_mpComponent->HandleRequest(&connection, UdpPacketHeader(), replicatorReset));
  357. }
  358. TEST_F(MultiplayerSystemTests, TestGetTime)
  359. {
  360. m_mpComponent->InitializeMultiplayer(MultiplayerAgentType::Client);
  361. EXPECT_EQ(m_mpComponent->GetAgentType(), MultiplayerAgentType::Client);
  362. EXPECT_EQ(m_mpComponent->GetCurrentHostTimeMs(), AZ::Time::ZeroTimeMs);
  363. m_mpComponent->InitializeMultiplayer(MultiplayerAgentType::DedicatedServer);
  364. EXPECT_EQ(m_mpComponent->GetAgentType(), MultiplayerAgentType::DedicatedServer);
  365. EXPECT_EQ(m_mpComponent->GetCurrentHostTimeMs(), AZ::Time::ZeroTimeMs);
  366. EXPECT_EQ(m_mpComponent->GetNetworkTime()->GetHostTimeMs(), AZ::Time::ZeroTimeMs);
  367. }
  368. // Useful matchers to help sniff packets
  369. MATCHER_P(IsMultiplayerPacketType, packetType, "Checks an IPacket's packet type")
  370. {
  371. *result_listener << "where the packet type id is "
  372. << ToString(static_cast<MultiplayerPackets::PacketType>(arg.GetPacketType())).data();
  373. return arg.GetPacketType() == packetType;
  374. }
  375. MATCHER_P(IsMismatchPacketWithComponentCount, totalComponentCount, "Checks how many multiplayer component versions are inside the VersionMismatch packet.")
  376. {
  377. if (arg.GetPacketType() != MultiplayerPackets::VersionMismatch::Type)
  378. {
  379. *result_listener << "where the packet is NOT a VersionMismatch packet";
  380. return false;
  381. }
  382. const uint32_t packetComponentCount = aznumeric_cast<uint32_t>(static_cast<const MultiplayerPackets::VersionMismatch&>(arg).GetComponentVersions().size());
  383. *result_listener << "where the packet is a VersionMismatch packet with component count " << packetComponentCount;
  384. return packetComponentCount == totalComponentCount;
  385. }
  386. TEST_F(MultiplayerSystemTests, TestConnectingWithoutLevelLoaded)
  387. {
  388. m_mpComponent->InitializeMultiplayer(MultiplayerAgentType::DedicatedServer);
  389. MultiplayerPackets::Connect connectPacket(
  390. 0, 1, "connect_ticket", GetMultiplayerComponentRegistry()->GetSystemVersionHash());
  391. IMultiplayerConnectionMock connection(
  392. ConnectionId{ 1 }, IpAddress("127.0.0.1", DefaultServerPort, ProtocolType::Udp), ConnectionRole::Acceptor);
  393. ServerToClientConnectionData connectionUserData(&connection, *m_mpComponent);
  394. connection.SetUserData(&connectionUserData);
  395. // server doesn't have a level loaded, expect a disconnect
  396. EXPECT_CALL(connection, Disconnect(DisconnectReason::ServerNoLevelLoaded, TerminationEndpoint::Local));
  397. m_mockLevelSystem->m_levelName = "";
  398. m_mpComponent->HandleRequest(&connection, UdpPacketHeader(), connectPacket);
  399. AZ::Interface<IMultiplayerSpawner>::Unregister(&m_mpSpawnerMock);
  400. }
  401. TEST_F(MultiplayerSystemTests, TestConnectingWithMatchingComponentHash)
  402. {
  403. m_mpComponent->InitializeMultiplayer(MultiplayerAgentType::DedicatedServer);
  404. MultiplayerPackets::Connect connectPacket(
  405. 0, 1, "connect_ticket", GetMultiplayerComponentRegistry()->GetSystemVersionHash());
  406. IMultiplayerConnectionMock connection(
  407. ConnectionId{ 1 }, IpAddress("127.0.0.1", DefaultServerPort, ProtocolType::Udp), ConnectionRole::Acceptor);
  408. ServerToClientConnectionData connectionUserData(&connection, *m_mpComponent);
  409. connection.SetUserData(&connectionUserData);
  410. // no mismatch, expect an acceptance packet
  411. m_mockLevelSystem->m_levelName = "dummylevel";
  412. EXPECT_CALL(connection, SendReliablePacket(IsMultiplayerPacketType(MultiplayerPackets::Accept::Type)));
  413. m_mpComponent->HandleRequest(&connection, UdpPacketHeader(), connectPacket);
  414. AZ::Interface<IMultiplayerSpawner>::Unregister(&m_mpSpawnerMock);
  415. }
  416. TEST_F(MultiplayerSystemTests, TestConnectingWithMismatchComponentHash)
  417. {
  418. // cvars affecting mismatch behavior:
  419. // 1. sv_versionMismatch_autoDisconnect
  420. // 2. sv_versionMismatch_sendManifestToClient
  421. m_mockLevelSystem->m_levelName = "dummylevel";
  422. m_mpComponent->InitializeMultiplayer(MultiplayerAgentType::DedicatedServer);
  423. // Send a connection request with a different component hash to trigger a mismatch
  424. const AZ::HashValue64 differentMultiplayerComponentHash = AZ::HashValue64{ 42 };
  425. MultiplayerPackets::Connect connectPacket(0, 1, "connect_ticket", differentMultiplayerComponentHash);
  426. IMultiplayerConnectionMock connection(
  427. ConnectionId{ 1 }, IpAddress("127.0.0.1", DefaultServerPort, ProtocolType::Udp), ConnectionRole::Acceptor);
  428. ServerToClientConnectionData connectionUserData(&connection, *m_mpComponent);
  429. connection.SetUserData(&connectionUserData);
  430. // Mismatch, send client a mismatch packet will all our components
  431. sv_versionMismatch_sendManifestToClient = true;
  432. const auto ourMultiplayerComponentCount = aznumeric_cast<uint32_t>(GetMultiplayerComponentRegistry()->GetMultiplayerComponentVersionHashes().size());
  433. EXPECT_CALL(connection, SendReliablePacket(IsMismatchPacketWithComponentCount(ourMultiplayerComponentCount))).Times(1);
  434. m_mpComponent->HandleRequest(&connection, UdpPacketHeader(), connectPacket);
  435. // Mismatch, send client a mismatch packet but don't send all our components to the client
  436. sv_versionMismatch_sendManifestToClient = false;
  437. EXPECT_CALL(connection, SendReliablePacket(IsMismatchPacketWithComponentCount(uint32_t{ 0 }))).Times(1);
  438. m_mpComponent->HandleRequest(&connection, UdpPacketHeader(), connectPacket);
  439. // Test the client sending components back to the server
  440. // Receive a multiplayer version mismatch packet and disconnect
  441. sv_versionMismatch_autoDisconnect = true;
  442. MultiplayerPackets::VersionMismatch mismatchPacket;
  443. EXPECT_CALL(connection, Disconnect(DisconnectReason::VersionMismatch, TerminationEndpoint::Local)).Times(1);
  444. m_mpComponent->HandleRequest(&connection, UdpPacketHeader(), mismatchPacket);
  445. // Receive a multiplayer version mismatch packet and but don't disconnect and instead accept
  446. sv_versionMismatch_autoDisconnect = false;
  447. EXPECT_CALL(connection, Disconnect).Times(0);
  448. EXPECT_CALL(connection, SendReliablePacket(IsMultiplayerPacketType(MultiplayerPackets::Accept::Type))).Times(1);
  449. m_mpComponent->HandleRequest(&connection, UdpPacketHeader(), mismatchPacket);
  450. AZ::Interface<IMultiplayerSpawner>::Unregister(&m_mpSpawnerMock);
  451. }
  452. TEST_F(MultiplayerSystemTests, TestMiscellaneous)
  453. {
  454. m_mpComponent->DumpStats({});
  455. m_mpComponent->SetShouldSpawnNetworkEntities(true);
  456. EXPECT_TRUE(m_mpComponent->GetShouldSpawnNetworkEntities());
  457. EXPECT_EQ(m_mpComponent->GetTickOrder(), AZ::TICK_PLACEMENT + 1);
  458. EXPECT_TRUE(m_mpComponent->OnSessionHealthCheck());
  459. m_mpComponent->RegisterPlayerIdentifierForRejoin(0, NetEntityId(0));
  460. m_mpComponent->OnCreateSessionEnd();
  461. m_mpComponent->OnDestroySessionEnd();
  462. Multiplayer::SessionConfig sessionConfig;
  463. m_mpComponent->OnUpdateSessionBegin(sessionConfig, "");
  464. m_mpComponent->OnUpdateSessionEnd();
  465. EXPECT_EQ(m_mpComponent->GetCurrentBlendFactor(), 0.0f);
  466. IMultiplayerConnectionMock connection(
  467. ConnectionId{ 1 }, IpAddress("127.0.0.1", DefaultServerPort, ProtocolType::Udp), ConnectionRole::Connector);
  468. ServerToClientConnectionData connectionUserData(&connection, *m_mpComponent);
  469. connection.SetUserData(&connectionUserData);
  470. EXPECT_FALSE(m_mpComponent->IsHandshakeComplete(&connection));
  471. }
  472. } // namespace Multiplayer