Gems/AWSGameLift/Code/AWSGameLiftClient/Source/AWSGameLiftClientLocalTicketTracker.cpp (167 lines of code) (raw):

/* * Copyright (c) Contributors to the Open 3D Engine Project. * For complete copyright and license terms please see the LICENSE at the root of this distribution. * * SPDX-License-Identifier: Apache-2.0 OR MIT * */ #include <AzCore/Interface/Interface.h> #include <AzCore/std/bind/bind.h> #include <AzCore/std/smart_ptr/shared_ptr.h> #include <Multiplayer/Session/ISessionHandlingRequests.h> #include <Multiplayer/Session/MatchmakingNotifications.h> #include <AWSGameLiftClientLocalTicketTracker.h> #include <AWSGameLiftSessionConstants.h> #include <Request/IAWSGameLiftInternalRequests.h> #include <aws/core/utils/Outcome.h> #include <aws/gamelift/GameLiftClient.h> #include <aws/gamelift/model/DescribeMatchmakingRequest.h> namespace AWSGameLift { AWSGameLiftClientLocalTicketTracker::AWSGameLiftClientLocalTicketTracker() : m_status(TicketTrackerStatus::Idle) , m_pollingPeriodInMS(AWSGameLiftClientDefaultPollingPeriodInMS) { } void AWSGameLiftClientLocalTicketTracker::ActivateTracker() { AZ::Interface<IAWSGameLiftMatchmakingEventRequests>::Register(this); AWSGameLiftMatchmakingEventRequestBus::Handler::BusConnect(); } void AWSGameLiftClientLocalTicketTracker::DeactivateTracker() { AWSGameLiftMatchmakingEventRequestBus::Handler::BusDisconnect(); AZ::Interface<IAWSGameLiftMatchmakingEventRequests>::Unregister(this); StopPolling(); } void AWSGameLiftClientLocalTicketTracker::StartPolling( const AZStd::string& ticketId, const AZStd::string& playerId) { AZStd::lock_guard<AZStd::mutex> lock(m_trackerMutex); if (m_status == TicketTrackerStatus::Running) { AZ_TracePrintf(AWSGameLiftClientLocalTicketTrackerName, "Matchmaking ticket tracker is running."); return; } // Make sure thread and wait event are both in clean state before starting new one m_waitEvent.release(); if (m_trackerThread.joinable()) { m_trackerThread.join(); } m_waitEvent.acquire(); m_status = TicketTrackerStatus::Running; m_trackerThread = AZStd::thread(AZStd::bind( &AWSGameLiftClientLocalTicketTracker::ProcessPolling, this, ticketId, playerId)); } void AWSGameLiftClientLocalTicketTracker::StopPolling() { AZStd::lock_guard<AZStd::mutex> lock(m_trackerMutex); m_status = TicketTrackerStatus::Idle; m_waitEvent.release(); if (m_trackerThread.joinable()) { m_trackerThread.join(); } } void AWSGameLiftClientLocalTicketTracker::ProcessPolling( const AZStd::string& ticketId, const AZStd::string& playerId) { while (m_status == TicketTrackerStatus::Running) { auto gameliftClient = AZ::Interface<IAWSGameLiftInternalRequests>::Get()->GetGameLiftClient(); if (gameliftClient) { Aws::GameLift::Model::DescribeMatchmakingRequest request; request.AddTicketIds(ticketId.c_str()); auto describeMatchmakingOutcome = gameliftClient->DescribeMatchmaking(request); if (describeMatchmakingOutcome.IsSuccess()) { if (describeMatchmakingOutcome.GetResult().GetTicketList().size() == 1) { auto ticket = describeMatchmakingOutcome.GetResult().GetTicketList().front(); if (ticket.GetStatus() == Aws::GameLift::Model::MatchmakingConfigurationStatus::COMPLETED) { AZ_TracePrintf(AWSGameLiftClientLocalTicketTrackerName, "Matchmaking ticket %s is complete.", ticket.GetTicketId().c_str()); RequestPlayerJoinMatch(ticket, playerId); Multiplayer::MatchmakingNotificationBus::Broadcast(&Multiplayer::MatchmakingNotifications::OnMatchComplete); m_status = TicketTrackerStatus::Idle; return; } else if (ticket.GetStatus() == Aws::GameLift::Model::MatchmakingConfigurationStatus::TIMED_OUT || ticket.GetStatus() == Aws::GameLift::Model::MatchmakingConfigurationStatus::FAILED || ticket.GetStatus() == Aws::GameLift::Model::MatchmakingConfigurationStatus::CANCELLED) { AZ_Warning(AWSGameLiftClientLocalTicketTrackerName, false, "Matchmaking ticket %s is not complete, %s", ticket.GetTicketId().c_str(), ticket.GetStatusMessage().c_str()); Multiplayer::MatchmakingNotificationBus::Broadcast(&Multiplayer::MatchmakingNotifications::OnMatchFailure); m_status = TicketTrackerStatus::Idle; return; } else if (ticket.GetStatus() == Aws::GameLift::Model::MatchmakingConfigurationStatus::REQUIRES_ACCEPTANCE) { AZ_TracePrintf(AWSGameLiftClientLocalTicketTrackerName, "Matchmaking ticket %s is pending on acceptance, %s.", ticket.GetTicketId().c_str(), ticket.GetStatusMessage().c_str()); Multiplayer::MatchmakingNotificationBus::Broadcast(&Multiplayer::MatchmakingNotifications::OnMatchAcceptance); } else { AZ_TracePrintf(AWSGameLiftClientLocalTicketTrackerName, "Matchmaking ticket %s is processing, %s.", ticket.GetTicketId().c_str(), ticket.GetStatusMessage().c_str()); } } else { AZ_Error(AWSGameLiftClientLocalTicketTrackerName, false, "Unable to find expected ticket with id %s", ticketId.c_str()); Multiplayer::MatchmakingNotificationBus::Broadcast(&Multiplayer::MatchmakingNotifications::OnMatchError); } } else { AZ_Error(AWSGameLiftClientLocalTicketTrackerName, false, AWSGameLiftErrorMessageTemplate, describeMatchmakingOutcome.GetError().GetExceptionName().c_str(), describeMatchmakingOutcome.GetError().GetMessage().c_str()); Multiplayer::MatchmakingNotificationBus::Broadcast(&Multiplayer::MatchmakingNotifications::OnMatchError); } } else { AZ_Error(AWSGameLiftClientLocalTicketTrackerName, false, AWSGameLiftClientMissingErrorMessage); Multiplayer::MatchmakingNotificationBus::Broadcast(&Multiplayer::MatchmakingNotifications::OnMatchError); } m_waitEvent.try_acquire_for(AZStd::chrono::milliseconds(m_pollingPeriodInMS)); } } void AWSGameLiftClientLocalTicketTracker::RequestPlayerJoinMatch( const Aws::GameLift::Model::MatchmakingTicket& ticket, const AZStd::string& playerId) { auto connectionInfo = ticket.GetGameSessionConnectionInfo(); Multiplayer::SessionConnectionConfig sessionConnectionConfig; sessionConnectionConfig.m_ipAddress = connectionInfo.GetIpAddress().c_str(); for (auto matchedPlayer : connectionInfo.GetMatchedPlayerSessions()) { if (playerId.compare(matchedPlayer.GetPlayerId().c_str()) == 0) { sessionConnectionConfig.m_playerSessionId = matchedPlayer.GetPlayerSessionId().c_str(); break; } } sessionConnectionConfig.m_port = static_cast<uint16_t>(connectionInfo.GetPort()); if (!sessionConnectionConfig.m_playerSessionId.empty()) { AZ_TracePrintf(AWSGameLiftClientLocalTicketTrackerName, "Requesting and validating player session %s to connect to the match ...", sessionConnectionConfig.m_playerSessionId.c_str()); bool result = AZ::Interface<Multiplayer::ISessionHandlingClientRequests>::Get()->RequestPlayerJoinSession(sessionConnectionConfig); if (result) { AZ_TracePrintf(AWSGameLiftClientLocalTicketTrackerName, "Started connection process, and connection validation is in process."); } else { AZ_Error(AWSGameLiftClientLocalTicketTrackerName, false, "Failed to start connection process."); } } else { AZ_Error(AWSGameLiftClientLocalTicketTrackerName, false, "Player session id is missing for player % to join the match.", playerId.c_str()); } } }