AWSGameLiftClientLocalTicketTracker.cpp 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  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 <AzCore/Interface/Interface.h>
  9. #include <AzCore/std/bind/bind.h>
  10. #include <AzCore/std/smart_ptr/shared_ptr.h>
  11. #include <Multiplayer/Session/ISessionHandlingRequests.h>
  12. #include <Multiplayer/Session/MatchmakingNotifications.h>
  13. #include <AWSGameLiftClientLocalTicketTracker.h>
  14. #include <AWSGameLiftSessionConstants.h>
  15. #include <Request/IAWSGameLiftInternalRequests.h>
  16. #include <aws/core/utils/Outcome.h>
  17. #include <aws/gamelift/GameLiftClient.h>
  18. #include <aws/gamelift/model/DescribeMatchmakingRequest.h>
  19. namespace AWSGameLift
  20. {
  21. AWSGameLiftClientLocalTicketTracker::AWSGameLiftClientLocalTicketTracker()
  22. : m_status(TicketTrackerStatus::Idle)
  23. , m_pollingPeriodInMS(AWSGameLiftClientDefaultPollingPeriodInMS)
  24. {
  25. }
  26. void AWSGameLiftClientLocalTicketTracker::ActivateTracker()
  27. {
  28. AZ::Interface<IAWSGameLiftMatchmakingEventRequests>::Register(this);
  29. AWSGameLiftMatchmakingEventRequestBus::Handler::BusConnect();
  30. }
  31. void AWSGameLiftClientLocalTicketTracker::DeactivateTracker()
  32. {
  33. AWSGameLiftMatchmakingEventRequestBus::Handler::BusDisconnect();
  34. AZ::Interface<IAWSGameLiftMatchmakingEventRequests>::Unregister(this);
  35. StopPolling();
  36. }
  37. void AWSGameLiftClientLocalTicketTracker::StartPolling(
  38. const AZStd::string& ticketId, const AZStd::string& playerId)
  39. {
  40. AZStd::lock_guard<AZStd::mutex> lock(m_trackerMutex);
  41. if (m_status == TicketTrackerStatus::Running)
  42. {
  43. AZ_TracePrintf(AWSGameLiftClientLocalTicketTrackerName, "Matchmaking ticket tracker is running.");
  44. return;
  45. }
  46. // Make sure thread and wait event are both in clean state before starting new one
  47. m_waitEvent.release();
  48. if (m_trackerThread.joinable())
  49. {
  50. m_trackerThread.join();
  51. }
  52. m_waitEvent.acquire();
  53. m_status = TicketTrackerStatus::Running;
  54. m_trackerThread = AZStd::thread(AZStd::bind(
  55. &AWSGameLiftClientLocalTicketTracker::ProcessPolling, this, ticketId, playerId));
  56. }
  57. void AWSGameLiftClientLocalTicketTracker::StopPolling()
  58. {
  59. AZStd::lock_guard<AZStd::mutex> lock(m_trackerMutex);
  60. m_status = TicketTrackerStatus::Idle;
  61. m_waitEvent.release();
  62. if (m_trackerThread.joinable())
  63. {
  64. m_trackerThread.join();
  65. }
  66. }
  67. void AWSGameLiftClientLocalTicketTracker::ProcessPolling(
  68. const AZStd::string& ticketId, const AZStd::string& playerId)
  69. {
  70. while (m_status == TicketTrackerStatus::Running)
  71. {
  72. auto gameliftClient = AZ::Interface<IAWSGameLiftInternalRequests>::Get()->GetGameLiftClient();
  73. if (gameliftClient)
  74. {
  75. Aws::GameLift::Model::DescribeMatchmakingRequest request;
  76. request.AddTicketIds(ticketId.c_str());
  77. auto describeMatchmakingOutcome = gameliftClient->DescribeMatchmaking(request);
  78. if (describeMatchmakingOutcome.IsSuccess())
  79. {
  80. if (describeMatchmakingOutcome.GetResult().GetTicketList().size() == 1)
  81. {
  82. auto ticket = describeMatchmakingOutcome.GetResult().GetTicketList().front();
  83. if (ticket.GetStatus() == Aws::GameLift::Model::MatchmakingConfigurationStatus::COMPLETED)
  84. {
  85. AZ_TracePrintf(AWSGameLiftClientLocalTicketTrackerName,
  86. "Matchmaking ticket %s is complete.", ticket.GetTicketId().c_str());
  87. RequestPlayerJoinMatch(ticket, playerId);
  88. Multiplayer::MatchmakingNotificationBus::Broadcast(&Multiplayer::MatchmakingNotifications::OnMatchComplete);
  89. m_status = TicketTrackerStatus::Idle;
  90. return;
  91. }
  92. else if (ticket.GetStatus() == Aws::GameLift::Model::MatchmakingConfigurationStatus::TIMED_OUT ||
  93. ticket.GetStatus() == Aws::GameLift::Model::MatchmakingConfigurationStatus::FAILED ||
  94. ticket.GetStatus() == Aws::GameLift::Model::MatchmakingConfigurationStatus::CANCELLED)
  95. {
  96. AZ_Warning(AWSGameLiftClientLocalTicketTrackerName, false, "Matchmaking ticket %s is not complete, %s",
  97. ticket.GetTicketId().c_str(), ticket.GetStatusMessage().c_str());
  98. Multiplayer::MatchmakingNotificationBus::Broadcast(&Multiplayer::MatchmakingNotifications::OnMatchFailure);
  99. m_status = TicketTrackerStatus::Idle;
  100. return;
  101. }
  102. else if (ticket.GetStatus() == Aws::GameLift::Model::MatchmakingConfigurationStatus::REQUIRES_ACCEPTANCE)
  103. {
  104. AZ_TracePrintf(AWSGameLiftClientLocalTicketTrackerName, "Matchmaking ticket %s is pending on acceptance, %s.",
  105. ticket.GetTicketId().c_str(), ticket.GetStatusMessage().c_str());
  106. Multiplayer::MatchmakingNotificationBus::Broadcast(&Multiplayer::MatchmakingNotifications::OnMatchAcceptance);
  107. }
  108. else
  109. {
  110. AZ_TracePrintf(AWSGameLiftClientLocalTicketTrackerName, "Matchmaking ticket %s is processing, %s.",
  111. ticket.GetTicketId().c_str(), ticket.GetStatusMessage().c_str());
  112. }
  113. }
  114. else
  115. {
  116. AZ_Error(AWSGameLiftClientLocalTicketTrackerName, false, "Unable to find expected ticket with id %s", ticketId.c_str());
  117. Multiplayer::MatchmakingNotificationBus::Broadcast(&Multiplayer::MatchmakingNotifications::OnMatchError);
  118. }
  119. }
  120. else
  121. {
  122. AZ_Error(AWSGameLiftClientLocalTicketTrackerName, false, AWSGameLiftErrorMessageTemplate,
  123. describeMatchmakingOutcome.GetError().GetExceptionName().c_str(),
  124. describeMatchmakingOutcome.GetError().GetMessage().c_str());
  125. Multiplayer::MatchmakingNotificationBus::Broadcast(&Multiplayer::MatchmakingNotifications::OnMatchError);
  126. }
  127. }
  128. else
  129. {
  130. AZ_Error(AWSGameLiftClientLocalTicketTrackerName, false, AWSGameLiftClientMissingErrorMessage);
  131. Multiplayer::MatchmakingNotificationBus::Broadcast(&Multiplayer::MatchmakingNotifications::OnMatchError);
  132. }
  133. m_waitEvent.try_acquire_for(AZStd::chrono::milliseconds(m_pollingPeriodInMS));
  134. }
  135. }
  136. void AWSGameLiftClientLocalTicketTracker::RequestPlayerJoinMatch(
  137. const Aws::GameLift::Model::MatchmakingTicket& ticket, const AZStd::string& playerId)
  138. {
  139. auto connectionInfo = ticket.GetGameSessionConnectionInfo();
  140. Multiplayer::SessionConnectionConfig sessionConnectionConfig;
  141. sessionConnectionConfig.m_ipAddress = connectionInfo.GetIpAddress().c_str();
  142. for (auto matchedPlayer : connectionInfo.GetMatchedPlayerSessions())
  143. {
  144. if (playerId.compare(matchedPlayer.GetPlayerId().c_str()) == 0)
  145. {
  146. sessionConnectionConfig.m_playerSessionId = matchedPlayer.GetPlayerSessionId().c_str();
  147. break;
  148. }
  149. }
  150. sessionConnectionConfig.m_port = static_cast<uint16_t>(connectionInfo.GetPort());
  151. if (!sessionConnectionConfig.m_playerSessionId.empty())
  152. {
  153. AZ_TracePrintf(AWSGameLiftClientLocalTicketTrackerName,
  154. "Requesting and validating player session %s to connect to the match ...",
  155. sessionConnectionConfig.m_playerSessionId.c_str());
  156. bool result =
  157. AZ::Interface<Multiplayer::ISessionHandlingClientRequests>::Get()->RequestPlayerJoinSession(sessionConnectionConfig);
  158. if (result)
  159. {
  160. AZ_TracePrintf(AWSGameLiftClientLocalTicketTrackerName,
  161. "Started connection process, and connection validation is in process.");
  162. }
  163. else
  164. {
  165. AZ_Error(AWSGameLiftClientLocalTicketTrackerName, false,
  166. "Failed to start connection process.");
  167. }
  168. }
  169. else
  170. {
  171. AZ_Error(AWSGameLiftClientLocalTicketTrackerName, false,
  172. "Player session id is missing for player % to join the match.", playerId.c_str());
  173. }
  174. }
  175. }