You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
190 lines
8.8 KiB
C++
190 lines
8.8 KiB
C++
/*
|
|
* 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());
|
|
}
|
|
}
|
|
}
|