Add GameLift matchmaking backfill server support (#4622)

* Add GameLift matchmaking backfill server support

Signed-off-by: onecent1101 <liug@amazon.com>
This commit is contained in:
Vincent Liu
2021-10-13 16:59:37 -07:00
committed by GitHub
parent 2474ffc5a1
commit 6823ea2274
25 changed files with 1194 additions and 92 deletions
@@ -17,6 +17,9 @@
#include <AzCore/IO/SystemFile.h>
#include <AzCore/Jobs/JobFunction.h>
#include <AzCore/Jobs/JobManagerBus.h>
#include <AzCore/JSON/error/en.h>
#include <AzCore/JSON/stringbuffer.h>
#include <AzCore/JSON/writer.h>
#include <AzCore/std/bind/bind.h>
#include <AzFramework/Session/SessionNotifications.h>
@@ -112,6 +115,7 @@ namespace AWSGameLift
{
propertiesOutput = propertiesOutput.substr(0, propertiesOutput.size() - 1); // Trim last comma to fit array format
}
sessionConfig.m_matchmakingData = gameSession.GetMatchmakerData().c_str();
sessionConfig.m_sessionId = gameSession.GetGameSessionId().c_str();
sessionConfig.m_ipAddress = gameSession.GetIpAddress().c_str();
sessionConfig.m_maxPlayer = gameSession.GetMaximumPlayerSessionCount();
@@ -133,6 +137,276 @@ namespace AWSGameLift
return sessionConfig;
}
bool AWSGameLiftServerManager::BuildServerMatchBackfillPlayer(
const AWSGameLiftPlayer& player, Aws::GameLift::Server::Model::Player& outBackfillPlayer)
{
outBackfillPlayer.SetPlayerId(player.m_playerId.c_str());
outBackfillPlayer.SetTeam(player.m_team.c_str());
for (auto latencyPair : player.m_latencyInMs)
{
outBackfillPlayer.AddLatencyInMs(latencyPair.first.c_str(), latencyPair.second);
}
for (auto attributePair : player.m_playerAttributes)
{
Aws::GameLift::Server::Model::AttributeValue playerAttribute;
rapidjson::Document attributeDocument;
rapidjson::ParseResult parseResult = attributeDocument.Parse(attributePair.second.c_str());
// player attribute json content should always be a single member object
if (parseResult && attributeDocument.IsObject() && attributeDocument.MemberCount() == 1)
{
if ((attributeDocument.HasMember(AWSGameLiftMatchmakingPlayerAttributeSTypeName) ||
attributeDocument.HasMember(AWSGameLiftMatchmakingPlayerAttributeSServerTypeName)) &&
attributeDocument.MemberBegin()->value.IsString())
{
playerAttribute = Aws::GameLift::Server::Model::AttributeValue(
attributeDocument.MemberBegin()->value.GetString());
}
else if ((attributeDocument.HasMember(AWSGameLiftMatchmakingPlayerAttributeNTypeName) ||
attributeDocument.HasMember(AWSGameLiftMatchmakingPlayerAttributeNServerTypeName)) &&
attributeDocument.MemberBegin()->value.IsNumber())
{
playerAttribute = Aws::GameLift::Server::Model::AttributeValue(
attributeDocument.MemberBegin()->value.GetDouble());
}
else if ((attributeDocument.HasMember(AWSGameLiftMatchmakingPlayerAttributeSDMTypeName) ||
attributeDocument.HasMember(AWSGameLiftMatchmakingPlayerAttributeSDMServerTypeName)) &&
attributeDocument.MemberBegin()->value.IsObject())
{
playerAttribute = Aws::GameLift::Server::Model::AttributeValue::ConstructStringDoubleMap();
for (auto iter = attributeDocument.MemberBegin()->value.MemberBegin();
iter != attributeDocument.MemberBegin()->value.MemberEnd(); iter++)
{
if (iter->name.IsString() && iter->value.IsNumber())
{
playerAttribute.AddStringAndDouble(iter->name.GetString(), iter->value.GetDouble());
}
else
{
AZ_Error(AWSGameLiftServerManagerName, false, AWSGameLiftMatchmakingPlayerAttributeInvalidErrorMessage,
player.m_playerId.c_str(), "String double map key must be string type and value must be number type");
return false;
}
}
}
else if ((attributeDocument.HasMember(AWSGameLiftMatchmakingPlayerAttributeSLTypeName) ||
attributeDocument.HasMember(AWSGameLiftMatchmakingPlayerAttributeSLServerTypeName)) &&
attributeDocument.MemberBegin()->value.IsArray())
{
playerAttribute = Aws::GameLift::Server::Model::AttributeValue::ConstructStringList();
for (auto iter = attributeDocument.MemberBegin()->value.Begin();
iter != attributeDocument.MemberBegin()->value.End(); iter++)
{
if (iter->IsString())
{
playerAttribute.AddString(iter->GetString());
}
else
{
AZ_Error(AWSGameLiftServerManagerName, false, AWSGameLiftMatchmakingPlayerAttributeInvalidErrorMessage,
player.m_playerId.c_str(), "String list element must be string type");
return false;
}
}
}
else
{
AZ_Error(AWSGameLiftServerManagerName, false, AWSGameLiftMatchmakingPlayerAttributeInvalidErrorMessage,
player.m_playerId.c_str(), "S, N, SDM or SLM is expected as attribute type.");
return false;
}
}
else
{
AZ_Error(AWSGameLiftServerManagerName, false, AWSGameLiftMatchmakingPlayerAttributeInvalidErrorMessage,
player.m_playerId.c_str(), rapidjson::GetParseError_En(parseResult.Code()));
return false;
}
outBackfillPlayer.AddPlayerAttribute(attributePair.first.c_str(), playerAttribute);
}
return true;
}
AZStd::vector<AWSGameLiftPlayer> AWSGameLiftServerManager::GetActiveServerMatchBackfillPlayers()
{
AZStd::vector<AWSGameLiftPlayer> activePlayers;
// Keep processing only when game session has matchmaking data
if (IsMatchmakingDataValid())
{
auto activePlayerSessions = GetActivePlayerSessions();
for (auto playerSession : activePlayerSessions)
{
AWSGameLiftPlayer player;
if (BuildActiveServerMatchBackfillPlayer(playerSession.GetPlayerId().c_str(), player))
{
activePlayers.push_back(player);
}
}
}
return activePlayers;
}
bool AWSGameLiftServerManager::IsMatchmakingDataValid()
{
return m_matchmakingData.IsObject() &&
m_matchmakingData.HasMember(AWSGameLiftMatchmakingConfigurationKeyName) &&
m_matchmakingData.HasMember(AWSGameLiftMatchmakingTeamsKeyName);
}
AZStd::vector<Aws::GameLift::Server::Model::PlayerSession> AWSGameLiftServerManager::GetActivePlayerSessions()
{
Aws::GameLift::Server::Model::DescribePlayerSessionsRequest describeRequest;
describeRequest.SetGameSessionId(m_gameSession.GetGameSessionId());
describeRequest.SetPlayerSessionStatusFilter(
Aws::GameLift::Server::Model::PlayerSessionStatusMapper::GetNameForPlayerSessionStatus(
Aws::GameLift::Server::Model::PlayerSessionStatus::ACTIVE));
int maxPlayerSession = m_gameSession.GetMaximumPlayerSessionCount();
AZStd::vector<Aws::GameLift::Server::Model::PlayerSession> activePlayerSessions;
if (maxPlayerSession <= AWSGameLiftDescribePlayerSessionsPageSize)
{
describeRequest.SetLimit(maxPlayerSession);
auto outcome = m_gameLiftServerSDKWrapper->DescribePlayerSessions(describeRequest);
if (outcome.IsSuccess())
{
for (auto playerSession : outcome.GetResult().GetPlayerSessions())
{
activePlayerSessions.push_back(playerSession);
}
}
else
{
AZ_Error(AWSGameLiftServerManagerName, false, AWSGameLiftDescribePlayerSessionsErrorMessage,
outcome.GetError().GetErrorMessage().c_str());
}
}
else
{
describeRequest.SetLimit(AWSGameLiftDescribePlayerSessionsPageSize);
while (true)
{
auto outcome = m_gameLiftServerSDKWrapper->DescribePlayerSessions(describeRequest);
if (outcome.IsSuccess())
{
for (auto playerSession : outcome.GetResult().GetPlayerSessions())
{
activePlayerSessions.push_back(playerSession);
}
if (outcome.GetResult().GetNextToken().empty())
{
break;
}
else
{
describeRequest.SetNextToken(outcome.GetResult().GetNextToken());
}
}
else
{
activePlayerSessions.clear();
AZ_Error(AWSGameLiftServerManagerName, false, AWSGameLiftDescribePlayerSessionsErrorMessage,
outcome.GetError().GetErrorMessage().c_str());
break;
}
}
}
return activePlayerSessions;
}
bool AWSGameLiftServerManager::BuildActiveServerMatchBackfillPlayer(const AZStd::string& playerId, AWSGameLiftPlayer& outPlayer)
{
// As data is from GameLift service, assume it is always in correct format
rapidjson::Value& teams = m_matchmakingData[AWSGameLiftMatchmakingTeamsKeyName];
// Iterate through teams to find target player
for (rapidjson::SizeType teamIndex = 0; teamIndex < teams.Size(); ++teamIndex)
{
rapidjson::Value& players = teams[teamIndex][AWSGameLiftMatchmakingPlayersKeyName];
// Iterate through players under the team to find target player
for (rapidjson::SizeType playerIndex = 0; playerIndex < players.Size(); ++playerIndex)
{
if (std::strcmp(players[playerIndex][AWSGameLiftMatchmakingPlayerIdKeyName].GetString(), playerId.c_str()) == 0)
{
outPlayer.m_playerId = playerId;
outPlayer.m_team = teams[teamIndex][AWSGameLiftMatchmakingTeamNameKeyName].GetString();
// Get player attributes if target player has
if (players[playerIndex].HasMember(AWSGameLiftMatchmakingPlayerAttributesKeyName))
{
BuildServerMatchBackfillPlayerAttributes(
players[playerIndex][AWSGameLiftMatchmakingPlayerAttributesKeyName], outPlayer);
}
}
else
{
return false;
}
}
}
return true;
}
void AWSGameLiftServerManager::BuildServerMatchBackfillPlayerAttributes(
const rapidjson::Value& playerAttributes, AWSGameLiftPlayer& outPlayer)
{
for (auto iter = playerAttributes.MemberBegin(); iter != playerAttributes.MemberEnd(); iter++)
{
AZStd::string attributeName = iter->name.GetString();
rapidjson::StringBuffer jsonStringBuffer;
rapidjson::Writer<rapidjson::StringBuffer> writer(jsonStringBuffer);
iter->value[AWSGameLiftMatchmakingPlayerAttributeValueKeyName].Accept(writer);
AZStd::string attributeType = iter->value[AWSGameLiftMatchmakingPlayerAttributeTypeKeyName].GetString();
AZStd::string attributeValue = AZStd::string::format("{\"%s\": %s}",
attributeType.c_str(), jsonStringBuffer.GetString());
outPlayer.m_playerAttributes.emplace(attributeName, attributeValue);
}
}
bool AWSGameLiftServerManager::BuildStartMatchBackfillRequest(
const AZStd::string& ticketId,
const AZStd::vector<AWSGameLiftPlayer>& players,
Aws::GameLift::Server::Model::StartMatchBackfillRequest& outRequest)
{
outRequest.SetGameSessionArn(m_gameSession.GetGameSessionId());
outRequest.SetMatchmakingConfigurationArn(m_matchmakingData[AWSGameLiftMatchmakingConfigurationKeyName].GetString());
if (!ticketId.empty())
{
outRequest.SetTicketId(ticketId.c_str());
}
AZStd::vector<AWSGameLiftPlayer> requestPlayers(players);
if (players.size() == 0)
{
requestPlayers = GetActiveServerMatchBackfillPlayers();
}
for (auto player : requestPlayers)
{
Aws::GameLift::Server::Model::Player backfillPlayer;
if (BuildServerMatchBackfillPlayer(player, backfillPlayer))
{
outRequest.AddPlayer(backfillPlayer);
}
else
{
return false;
}
}
return true;
}
void AWSGameLiftServerManager::BuildStopMatchBackfillRequest(
const AZStd::string& ticketId, Aws::GameLift::Server::Model::StopMatchBackfillRequest& outRequest)
{
outRequest.SetGameSessionArn(m_gameSession.GetGameSessionId());
outRequest.SetMatchmakingConfigurationArn(m_matchmakingData[AWSGameLiftMatchmakingConfigurationKeyName].GetString());
if (!ticketId.empty())
{
outRequest.SetTicketId(ticketId.c_str());
}
}
AZ::IO::Path AWSGameLiftServerManager::GetExternalSessionCertificate()
{
// TODO: Add support to get TLS cert file path
@@ -238,7 +512,7 @@ namespace AWSGameLift
Aws::GameLift::Server::ProcessParameters processReadyParameter = Aws::GameLift::Server::ProcessParameters(
AZStd::bind(&AWSGameLiftServerManager::OnStartGameSession, this, AZStd::placeholders::_1),
AZStd::bind(&AWSGameLiftServerManager::OnUpdateGameSession, this),
AZStd::bind(&AWSGameLiftServerManager::OnUpdateGameSession, this, AZStd::placeholders::_1),
AZStd::bind(&AWSGameLiftServerManager::OnProcessTerminate, this),
AZStd::bind(&AWSGameLiftServerManager::OnHealthCheck, this), desc.m_port,
Aws::GameLift::Server::LogParameters(logPaths));
@@ -260,6 +534,7 @@ namespace AWSGameLift
void AWSGameLiftServerManager::OnStartGameSession(const Aws::GameLift::Server::Model::GameSession& gameSession)
{
UpdateGameSessionData(gameSession);
AzFramework::SessionConfig sessionConfig = BuildSessionConfig(gameSession);
bool createSessionResult = true;
@@ -311,10 +586,19 @@ namespace AWSGameLift
return m_serverSDKInitialized && healthCheckResult;
}
void AWSGameLiftServerManager::OnUpdateGameSession()
void AWSGameLiftServerManager::OnUpdateGameSession(const Aws::GameLift::Server::Model::UpdateGameSession& updateGameSession)
{
// TODO: Perform game-specific tasks to prep for newly matched players
return;
Aws::GameLift::Server::Model::UpdateReason updateReason = updateGameSession.GetUpdateReason();
if (updateReason == Aws::GameLift::Server::Model::UpdateReason::MATCHMAKING_DATA_UPDATED)
{
UpdateGameSessionData(updateGameSession.GetGameSession());
}
AzFramework::SessionConfig sessionConfig = BuildSessionConfig(updateGameSession.GetGameSession());
AzFramework::SessionNotificationBus::Broadcast(
&AzFramework::SessionNotifications::OnUpdateSessionBegin,
sessionConfig,
Aws::GameLift::Server::Model::UpdateReasonMapper::GetNameForUpdateReason(updateReason).c_str());
}
bool AWSGameLiftServerManager::RemoveConnectedPlayer(uint32_t playerConnectionId, AZStd::string& outPlayerSessionId)
@@ -340,6 +624,92 @@ namespace AWSGameLift
m_gameLiftServerSDKWrapper = AZStd::move(gameLiftServerSDKWrapper);
}
bool AWSGameLiftServerManager::StartMatchBackfill(const AZStd::string& ticketId, const AZStd::vector<AWSGameLiftPlayer>& players)
{
if (!m_serverSDKInitialized)
{
AZ_Error(AWSGameLiftServerManagerName, false, AWSGameLiftServerSDKNotInitErrorMessage);
return false;
}
if (!IsMatchmakingDataValid())
{
AZ_Error(AWSGameLiftServerManagerName, false, AWSGameLiftMatchmakingDataMissingErrorMessage);
return false;
}
Aws::GameLift::Server::Model::StartMatchBackfillRequest request;
if (!BuildStartMatchBackfillRequest(ticketId, players, request))
{
return false;
}
AZ_TracePrintf(AWSGameLiftServerManagerName, "Starting match backfill %s ...", ticketId.c_str());
auto outcome = m_gameLiftServerSDKWrapper->StartMatchBackfill(request);
if (!outcome.IsSuccess())
{
AZ_Error(AWSGameLiftServerManagerName, false, AWSGameLiftStartMatchBackfillErrorMessage,
outcome.GetError().GetErrorMessage().c_str());
return false;
}
else
{
AZ_TracePrintf(AWSGameLiftServerManagerName, "StartMatchBackfill request against Amazon GameLift service is complete.");
return true;
}
}
bool AWSGameLiftServerManager::StopMatchBackfill(const AZStd::string& ticketId)
{
if (!m_serverSDKInitialized)
{
AZ_Error(AWSGameLiftServerManagerName, false, AWSGameLiftServerSDKNotInitErrorMessage);
return false;
}
if (!IsMatchmakingDataValid())
{
AZ_Error(AWSGameLiftServerManagerName, false, AWSGameLiftMatchmakingDataMissingErrorMessage);
return false;
}
Aws::GameLift::Server::Model::StopMatchBackfillRequest request;
BuildStopMatchBackfillRequest(ticketId, request);
AZ_TracePrintf(AWSGameLiftServerManagerName, "Stopping match backfill %s ...", ticketId.c_str());
auto outcome = m_gameLiftServerSDKWrapper->StopMatchBackfill(request);
if (!outcome.IsSuccess())
{
AZ_Error(AWSGameLiftServerManagerName, false, AWSGameLiftStopMatchBackfillErrorMessage,
outcome.GetError().GetErrorMessage().c_str());
return false;
}
else
{
AZ_TracePrintf(AWSGameLiftServerManagerName, "StopMatchBackfill request against Amazon GameLift service is complete.");
return true;
}
}
void AWSGameLiftServerManager::UpdateGameSessionData(const Aws::GameLift::Server::Model::GameSession& gameSession)
{
AZ_TracePrintf(AWSGameLiftServerManagerName, "Lazy loading game session and matchmaking data from Amazon GameLift service ...");
m_gameSession = Aws::GameLift::Server::Model::GameSession(gameSession);
if (m_gameSession.GetMatchmakerData().empty())
{
m_matchmakingData.Parse("{}");
}
else
{
rapidjson::ParseResult parseResult = m_matchmakingData.Parse(m_gameSession.GetMatchmakerData().c_str());
if (!parseResult)
{
AZ_Error(AWSGameLiftServerManagerName, false,
AWSGameLiftMatchmakingDataInvalidErrorMessage, rapidjson::GetParseError_En(parseResult.Code()));
}
}
}
bool AWSGameLiftServerManager::ValidatePlayerJoinSession(const AzFramework::PlayerConnectionConfig& playerConnectionConfig)
{
uint32_t playerConnectionId = playerConnectionConfig.m_playerConnectionId;
@@ -11,11 +11,15 @@
#include <aws/gamelift/server/GameLiftServerAPI.h>
#include <aws/gamelift/server/model/GameSession.h>
#include <AzCore/JSON/rapidjson.h>
#include <AzCore/JSON/document.h>
#include <AzCore/std/containers/vector.h>
#include <AzCore/std/string/string.h>
#include <AzCore/std/smart_ptr/unique_ptr.h>
#include <AzFramework/Session/ISessionHandlingRequests.h>
#include <AzFramework/Session/SessionConfig.h>
#include <AWSGameLiftPlayer.h>
#include <Request/IAWSGameLiftServerRequests.h>
namespace AWSGameLift
@@ -66,6 +70,36 @@ namespace AWSGameLift
"Invalid player connection config, player connection id: %d, player session id: %s";
static constexpr const char AWSGameLiftServerRemovePlayerSessionErrorMessage[] =
"Failed to notify GameLift that the player with the player session id %s has disconnected from the server process. ErrorMessage: %s";
static constexpr const char AWSGameLiftMatchmakingDataInvalidErrorMessage[] =
"Failed to parse GameLift matchmaking data. ErrorMessage: %s";
static constexpr const char AWSGameLiftMatchmakingDataMissingErrorMessage[] =
"GameLift matchmaking data is missing or invalid to parse.";
static constexpr const char AWSGameLiftMatchmakingPlayerAttributeInvalidErrorMessage[] =
"Failed to build player %s attributes. ErrorMessage: %s";
static constexpr const char AWSGameLiftDescribePlayerSessionsErrorMessage[] =
"Failed to describe player sessions. ErrorMessage: %s";
static constexpr const char AWSGameLiftStartMatchBackfillErrorMessage[] =
"Failed to start match backfill. ErrorMessage: %s";
static constexpr const char AWSGameLiftStopMatchBackfillErrorMessage[] =
"Failed to stop match backfill. ErrorMessage: %s";
static constexpr const char AWSGameLiftMatchmakingConfigurationKeyName[] = "matchmakingConfigurationArn";
static constexpr const char AWSGameLiftMatchmakingTeamsKeyName[] = "teams";
static constexpr const char AWSGameLiftMatchmakingTeamNameKeyName[] = "name";
static constexpr const char AWSGameLiftMatchmakingPlayersKeyName[] = "players";
static constexpr const char AWSGameLiftMatchmakingPlayerIdKeyName[] = "playerId";
static constexpr const char AWSGameLiftMatchmakingPlayerAttributesKeyName[] = "attributes";
static constexpr const char AWSGameLiftMatchmakingPlayerAttributeTypeKeyName[] = "attributeType";
static constexpr const char AWSGameLiftMatchmakingPlayerAttributeValueKeyName[] = "valueAttribute";
static constexpr const char AWSGameLiftMatchmakingPlayerAttributeSTypeName[] = "S";
static constexpr const char AWSGameLiftMatchmakingPlayerAttributeSServerTypeName[] = "STRING";
static constexpr const char AWSGameLiftMatchmakingPlayerAttributeNTypeName[] = "N";
static constexpr const char AWSGameLiftMatchmakingPlayerAttributeNServerTypeName[] = "NUMBER";
static constexpr const char AWSGameLiftMatchmakingPlayerAttributeSLTypeName[] = "SL";
static constexpr const char AWSGameLiftMatchmakingPlayerAttributeSLServerTypeName[] = "STRING_LIST";
static constexpr const char AWSGameLiftMatchmakingPlayerAttributeSDMTypeName[] = "SDM";
static constexpr const char AWSGameLiftMatchmakingPlayerAttributeSDMServerTypeName[] = "STRING_DOUBLE_MAP";
static constexpr const uint16_t AWSGameLiftDescribePlayerSessionsPageSize = 30;
AWSGameLiftServerManager();
virtual ~AWSGameLiftServerManager();
@@ -78,6 +112,8 @@ namespace AWSGameLift
// AWSGameLiftServerRequestBus interface implementation
bool NotifyGameLiftProcessReady() override;
bool StartMatchBackfill(const AZStd::string& ticketId, const AZStd::vector<AWSGameLiftPlayer>& players) override;
bool StopMatchBackfill(const AZStd::string& ticketId) override;
// ISessionHandlingProviderRequests interface implementation
void HandleDestroySession() override;
@@ -92,18 +128,48 @@ namespace AWSGameLift
//! Add connected player session id.
bool AddConnectedPlayer(const AzFramework::PlayerConnectionConfig& playerConnectionConfig);
//! Get active server player data from lazy loaded game session for server match backfill
AZStd::vector<AWSGameLiftPlayer> GetActiveServerMatchBackfillPlayers();
//! Update local game session data to latest one
void UpdateGameSessionData(const Aws::GameLift::Server::Model::GameSession& gameSession);
private:
//! Build the serverProcessDesc with appropriate server port number and log paths.
GameLiftServerProcessDesc BuildGameLiftServerProcessDesc();
//! Build active server player data from lazy loaded game session based on player id
bool BuildActiveServerMatchBackfillPlayer(const AZStd::string& playerId, AWSGameLiftPlayer& outPlayer);
//! Build server player attribute data from lazy load matchmaking data
void BuildServerMatchBackfillPlayerAttributes(const rapidjson::Value& playerAttributes, AWSGameLiftPlayer& outPlayer);
//! Build server player data for server match backfill
bool BuildServerMatchBackfillPlayer(const AWSGameLiftPlayer& player, Aws::GameLift::Server::Model::Player& outBackfillPlayer);
//! Build start match backfill request for StartMatchBackfill operation
bool BuildStartMatchBackfillRequest(
const AZStd::string& ticketId,
const AZStd::vector<AWSGameLiftPlayer>& players,
Aws::GameLift::Server::Model::StartMatchBackfillRequest& outRequest);
//! Build stop match backfill request for StopMatchBackfill operation
void BuildStopMatchBackfillRequest(const AZStd::string& ticketId, Aws::GameLift::Server::Model::StopMatchBackfillRequest& outRequest);
//! Build session config by using AWS GameLift Server GameSession Model.
AzFramework::SessionConfig BuildSessionConfig(const Aws::GameLift::Server::Model::GameSession& gameSession);
//! Check whether matchmaking data is in proper format
bool IsMatchmakingDataValid();
//! Fetch active player sessions in game session.
AZStd::vector<Aws::GameLift::Server::Model::PlayerSession> GetActivePlayerSessions();
//! Callback function that the GameLift service invokes to activate a new game session.
void OnStartGameSession(const Aws::GameLift::Server::Model::GameSession& gameSession);
//! Callback function that the GameLift service invokes to pass an updated game session object to the server process.
void OnUpdateGameSession();
void OnUpdateGameSession(const Aws::GameLift::Server::Model::UpdateGameSession& updateGameSession);
//! Callback function that the server process or GameLift service invokes to force the server process to shut down.
void OnProcessTerminate();
@@ -125,5 +191,12 @@ namespace AWSGameLift
using PlayerConnectionId = uint32_t;
using PlayerSessionId = AZStd::string;
AZStd::unordered_map<PlayerConnectionId, PlayerSessionId> m_connectedPlayers;
// Lazy loaded game session and matchmaking data
Aws::GameLift::Server::Model::GameSession m_gameSession;
// Matchmaking data contains a unique match ID, it identifies the matchmaker that created the match
// and describes the teams, team assignments, and players.
// Reference https://docs.aws.amazon.com/gamelift/latest/flexmatchguide/match-server.html#match-server-data
rapidjson::Document m_matchmakingData;
};
} // namespace AWSGameLift
@@ -22,6 +22,12 @@ namespace AWSGameLift
return Aws::GameLift::Server::ActivateGameSession();
}
Aws::GameLift::DescribePlayerSessionsOutcome GameLiftServerSDKWrapper::DescribePlayerSessions(
const Aws::GameLift::Server::Model::DescribePlayerSessionsRequest& describePlayerSessionsRequest)
{
return Aws::GameLift::Server::DescribePlayerSessions(describePlayerSessionsRequest);
}
Aws::GameLift::Server::InitSDKOutcome GameLiftServerSDKWrapper::InitSDK()
{
return Aws::GameLift::Server::InitSDK();
@@ -69,4 +75,17 @@ namespace AWSGameLift
{
return Aws::GameLift::Server::RemovePlayerSession(playerSessionId.c_str());
}
Aws::GameLift::StartMatchBackfillOutcome GameLiftServerSDKWrapper::StartMatchBackfill(
const Aws::GameLift::Server::Model::StartMatchBackfillRequest& startMatchBackfillRequest)
{
return Aws::GameLift::Server::StartMatchBackfill(startMatchBackfillRequest);
}
Aws::GameLift::GenericOutcome GameLiftServerSDKWrapper::StopMatchBackfill(
const Aws::GameLift::Server::Model::StopMatchBackfillRequest& stopMatchBackfillRequest)
{
return Aws::GameLift::Server::StopMatchBackfill(stopMatchBackfillRequest);
}
} // namespace AWSGameLift
@@ -33,6 +33,14 @@ namespace AWSGameLift
//! @return Returns a generic outcome consisting of success or failure with an error message.
virtual Aws::GameLift::GenericOutcome ActivateGameSession();
//! Retrieves player session data, including settings, session metadata, and player data.
//! Use this action to get information for a single player session,
//! for all player sessions in a game session, or for all player sessions associated with a single player ID.
//! @param describePlayerSessionsRequest The request object describing which player sessions to retrieve.
//! @return If successful, returns a DescribePlayerSessionsOutcome object containing a set of player session objects that fit the request parameters.
virtual Aws::GameLift::DescribePlayerSessionsOutcome DescribePlayerSessions(
const Aws::GameLift::Server::Model::DescribePlayerSessionsRequest& describePlayerSessionsRequest);
//! Initializes the GameLift SDK.
//! Should be called when the server starts, before any GameLift-dependent initialization happens.
//! @return If successful, returns an InitSdkOutcome object indicating that the server process is ready to call ProcessReady().
@@ -56,5 +64,16 @@ namespace AWSGameLift
//! @param playerSessionId Unique ID issued by the Amazon GameLift service in response to a call to the AWS SDK Amazon GameLift API action CreatePlayerSession.
//! @return Returns a generic outcome consisting of success or failure with an error message.
virtual Aws::GameLift::GenericOutcome RemovePlayerSession(const AZStd::string& playerSessionId);
//! Sends a request to find new players for open slots in a game session created with FlexMatch.
//! When the match has been successfully, backfilled updated matchmaker data will be sent to the OnUpdateGameSession callback.
//! @param startMatchBackfillRequest This data type is used to send a matchmaking backfill request.
//! @return Returns a StartMatchBackfillOutcome object with the match backfill ticket or failure with an error message.
virtual Aws::GameLift::StartMatchBackfillOutcome StartMatchBackfill(const Aws::GameLift::Server::Model::StartMatchBackfillRequest& startMatchBackfillRequest);
//! Cancels an active match backfill request that was created with StartMatchBackfill
//! @param stopMatchBackfillRequest This data type is used to cancel a matchmaking backfill request.
//! @return Returns a generic outcome consisting of success or failure with an error message.
virtual Aws::GameLift::GenericOutcome StopMatchBackfill(const Aws::GameLift::Server::Model::StopMatchBackfillRequest& stopMatchBackfillRequest);
};
} // namespace AWSGameLift