123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319 |
- /*
- * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
- * its licensors.
- *
- * For complete copyright and license terms please see the LICENSE at the root of this
- * distribution (the "License"). All use of this software is governed by the License,
- * or, if provided, by the license below or the license accompanying this file. Do not
- * remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *
- */
- #include <AWSGameLiftServerManager.h>
- #include <AWSGameLiftSessionConstants.h>
- #include <GameLiftServerSDKWrapper.h>
- #include <AzCore/Debug/Trace.h>
- #include <AzCore/Interface/Interface.h>
- #include <AzCore/Jobs/JobFunction.h>
- #include <AzCore/Jobs/JobManagerBus.h>
- #include <AzCore/std/bind/bind.h>
- #include <AzFramework/Session/SessionNotifications.h>
- namespace AWSGameLift
- {
- AWSGameLiftServerManager::AWSGameLiftServerManager()
- : m_serverSDKInitialized(false)
- , m_gameLiftServerSDKWrapper(AZStd::make_unique<GameLiftServerSDKWrapper>())
- , m_connectedPlayers()
- {
- }
- AWSGameLiftServerManager::~AWSGameLiftServerManager()
- {
- m_gameLiftServerSDKWrapper.reset();
- m_connectedPlayers.clear();
- }
- bool AWSGameLiftServerManager::AddConnectedPlayer(const AzFramework::PlayerConnectionConfig& playerConnectionConfig)
- {
- AZStd::lock_guard<AZStd::mutex> lock(m_gameliftMutex);
- if (m_connectedPlayers.contains(playerConnectionConfig.m_playerConnectionId))
- {
- if (m_connectedPlayers[playerConnectionConfig.m_playerConnectionId] != playerConnectionConfig.m_playerSessionId)
- {
- AZ_Error(AWSGameLiftServerManagerName, false, AWSGameLiftServerPlayerConnectionRegisteredErrorMessage,
- playerConnectionConfig.m_playerConnectionId, playerConnectionConfig.m_playerSessionId.c_str());
- }
- return false;
- }
- else
- {
- m_connectedPlayers.emplace(playerConnectionConfig.m_playerConnectionId, playerConnectionConfig.m_playerSessionId);
- return true;
- }
- }
- AzFramework::SessionConfig AWSGameLiftServerManager::BuildSessionConfig(const Aws::GameLift::Server::Model::GameSession& gameSession)
- {
- AzFramework::SessionConfig sessionConfig;
- sessionConfig.m_dnsName = gameSession.GetDnsName().c_str();
- AZStd::string propertiesOutput = "";
- for (const auto& gameProperty : gameSession.GetGameProperties())
- {
- sessionConfig.m_sessionProperties.emplace(gameProperty.GetKey().c_str(), gameProperty.GetValue().c_str());
- propertiesOutput += AZStd::string::format("{Key=%s,Value=%s},", gameProperty.GetKey().c_str(), gameProperty.GetValue().c_str());
- }
- if (!propertiesOutput.empty())
- {
- propertiesOutput = propertiesOutput.substr(0, propertiesOutput.size() - 1); // Trim last comma to fit array format
- }
- sessionConfig.m_sessionId = gameSession.GetGameSessionId().c_str();
- sessionConfig.m_ipAddress = gameSession.GetIpAddress().c_str();
- sessionConfig.m_maxPlayer = gameSession.GetMaximumPlayerSessionCount();
- sessionConfig.m_sessionName = gameSession.GetName().c_str();
- sessionConfig.m_port = gameSession.GetPort();
- sessionConfig.m_status = AWSGameLiftSessionStatusNames[(int)gameSession.GetStatus()];
- AZ_TracePrintf(AWSGameLiftServerManagerName,
- "Built SessionConfig with Name=%s, Id=%s, Status=%s, DnsName=%s, IpAddress=%s, Port=%d, MaxPlayer=%d and Properties=%s",
- sessionConfig.m_sessionName.c_str(),
- sessionConfig.m_sessionId.c_str(),
- sessionConfig.m_status.c_str(),
- sessionConfig.m_dnsName.c_str(),
- sessionConfig.m_ipAddress.c_str(),
- sessionConfig.m_port,
- sessionConfig.m_maxPlayer,
- AZStd::string::format("[%s]", propertiesOutput.c_str()).c_str());
- return sessionConfig;
- }
- AZ::IO::Path AWSGameLiftServerManager::GetExternalSessionCertificate()
- {
- // TODO: Add support to get TLS cert file path
- return AZ::IO::Path();
- }
- AZ::IO::Path AWSGameLiftServerManager::GetInternalSessionCertificate()
- {
- // GameLift doesn't support it, return empty path
- return AZ::IO::Path();
- }
- bool AWSGameLiftServerManager::InitializeGameLiftServerSDK()
- {
- if (m_serverSDKInitialized)
- {
- AZ_Error(AWSGameLiftServerManagerName, false, AWSGameLiftServerSDKAlreadyInitErrorMessage);
- return false;
- }
- AZ_TracePrintf(AWSGameLiftServerManagerName, "Initiating Amazon GameLift Server SDK...");
- Aws::GameLift::Server::InitSDKOutcome initOutcome = m_gameLiftServerSDKWrapper->InitSDK();
- m_serverSDKInitialized = initOutcome.IsSuccess();
- AZ_Error(AWSGameLiftServerManagerName, m_serverSDKInitialized,
- AWSGameLiftServerInitSDKErrorMessage, initOutcome.GetError().GetErrorMessage().c_str());
- return m_serverSDKInitialized;
- }
- void AWSGameLiftServerManager::HandleDestroySession()
- {
- // No further request should be handled by GameLift server manager at this point
- if (AZ::Interface<AzFramework::ISessionHandlingProviderRequests>::Get())
- {
- AZ::Interface<AzFramework::ISessionHandlingProviderRequests>::Unregister(this);
- }
- AZ_TracePrintf(AWSGameLiftServerManagerName, "Server process is scheduled to be shut down at %s",
- m_gameLiftServerSDKWrapper->GetTerminationTime().c_str());
- // Send notifications to handler(s) to gracefully shut down the server process.
- bool destroySessionResult = true;
- AZ::EBusReduceResult<bool&, AZStd::logical_and<bool>> result(destroySessionResult);
- AzFramework::SessionNotificationBus::BroadcastResult(result, &AzFramework::SessionNotifications::OnDestroySessionBegin);
- if (!destroySessionResult)
- {
- AZ_Error("AWSGameLift", destroySessionResult, AWSGameLiftServerGameSessionDestroyErrorMessage);
- return;
- }
- AZ_TracePrintf(AWSGameLiftServerManagerName, "Notifying GameLift server process is ending...");
- Aws::GameLift::GenericOutcome processEndingOutcome = m_gameLiftServerSDKWrapper->ProcessEnding();
- bool processEndingIsSuccess = processEndingOutcome.IsSuccess();
- AZ_Error(AWSGameLiftServerManagerName, processEndingIsSuccess, AWSGameLiftServerProcessEndingErrorMessage,
- processEndingOutcome.GetError().GetErrorMessage().c_str());
- }
- void AWSGameLiftServerManager::HandlePlayerLeaveSession(const AzFramework::PlayerConnectionConfig& playerConnectionConfig)
- {
- AZStd::string playerSessionId = "";
- RemoveConnectedPlayer(playerConnectionConfig.m_playerConnectionId, playerSessionId);
- if (playerSessionId.empty())
- {
- return;
- }
- Aws::GameLift::GenericOutcome disconnectOutcome = m_gameLiftServerSDKWrapper->RemovePlayerSession(playerSessionId);
- AZ_Error(AWSGameLiftServerManagerName, disconnectOutcome.IsSuccess(), AWSGameLiftServerRemovePlayerSessionErrorMessage,
- playerSessionId.c_str(), disconnectOutcome.GetError().GetErrorMessage().c_str());
- }
- bool AWSGameLiftServerManager::NotifyGameLiftProcessReady(const GameLiftServerProcessDesc& desc)
- {
- if (!m_serverSDKInitialized)
- {
- AZ_Error(AWSGameLiftServerManagerName, false, AWSGameLiftServerSDKNotInitErrorMessage);
- return false;
- }
- AZ_Warning(AWSGameLiftServerManagerName, desc.m_port != 0, AWSGameLiftServerTempPortErrorMessage);
- AZ::JobContext* jobContext = nullptr;
- AZ::JobManagerBus::BroadcastResult(jobContext, &AZ::JobManagerEvents::GetGlobalContext);
- AZ::Job* processReadyJob = AZ::CreateJobFunction(
- [this, desc]() {
- // The GameLift ProcessParameters object expects an vector (std::vector) of standard strings (std::string) as the log paths.
- std::vector<std::string> logPaths;
- for (const AZStd::string& path : desc.m_logPaths)
- {
- logPaths.push_back(path.c_str());
- }
- 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::OnProcessTerminate, this),
- AZStd::bind(&AWSGameLiftServerManager::OnHealthCheck, this), desc.m_port,
- Aws::GameLift::Server::LogParameters(logPaths));
- AZ_TracePrintf(AWSGameLiftServerManagerName, "Notifying GameLift server process is ready...");
- auto processReadyOutcome = m_gameLiftServerSDKWrapper->ProcessReady(processReadyParameter);
- if (!processReadyOutcome.IsSuccess())
- {
- AZ_Error(AWSGameLiftServerManagerName, false,
- AWSGameLiftServerProcessReadyErrorMessage, processReadyOutcome.GetError().GetErrorMessage().c_str());
- this->HandleDestroySession();
- }
- }, true, jobContext);
- processReadyJob->Start();
- return true;
- }
- void AWSGameLiftServerManager::OnStartGameSession(const Aws::GameLift::Server::Model::GameSession& gameSession)
- {
- AzFramework::SessionConfig sessionConfig = BuildSessionConfig(gameSession);
- bool createSessionResult = true;
- AZ::EBusReduceResult<bool&, AZStd::logical_and<bool>> result(createSessionResult);
- AzFramework::SessionNotificationBus::BroadcastResult(
- result, &AzFramework::SessionNotifications::OnCreateSessionBegin, sessionConfig);
- if (createSessionResult)
- {
- AZ_TracePrintf(AWSGameLiftServerManagerName, "Activating GameLift game session...");
- Aws::GameLift::GenericOutcome activationOutcome = m_gameLiftServerSDKWrapper->ActivateGameSession();
- if (activationOutcome.IsSuccess())
- {
- // Register server manager as handler once game session has been activated
- if (!AZ::Interface<AzFramework::ISessionHandlingProviderRequests>::Get())
- {
- AZ::Interface<AzFramework::ISessionHandlingProviderRequests>::Register(this);
- }
- }
- else
- {
- AZ_Error(AWSGameLiftServerManagerName, false, AWSGameLiftServerActivateGameSessionErrorMessage,
- activationOutcome.GetError().GetErrorMessage().c_str());
- HandleDestroySession();
- }
- }
- else
- {
- AZ_Error(AWSGameLiftServerManagerName, false, AWSGameLiftServerGameInitErrorMessage);
- HandleDestroySession();
- }
- }
- void AWSGameLiftServerManager::OnProcessTerminate()
- {
- AZ_TracePrintf(AWSGameLiftServerManagerName, "GameLift is shutting down server process...");
- HandleDestroySession();
- }
- bool AWSGameLiftServerManager::OnHealthCheck()
- {
- bool healthCheckResult = true;
- AZ::EBusReduceResult<bool&, AZStd::logical_and<bool>> result(healthCheckResult);
- AzFramework::SessionNotificationBus::BroadcastResult(result, &AzFramework::SessionNotifications::OnSessionHealthCheck);
- return m_serverSDKInitialized && healthCheckResult;
- }
- void AWSGameLiftServerManager::OnUpdateGameSession()
- {
- // TODO: Perform game-specific tasks to prep for newly matched players
- return;
- }
- bool AWSGameLiftServerManager::RemoveConnectedPlayer(uint32_t playerConnectionId, AZStd::string& outPlayerSessionId)
- {
- AZStd::lock_guard<AZStd::mutex> lock(m_gameliftMutex);
- if (m_connectedPlayers.contains(playerConnectionId))
- {
- outPlayerSessionId = m_connectedPlayers[playerConnectionId];
- m_connectedPlayers.erase(playerConnectionId);
- return true;
- }
- else
- {
- outPlayerSessionId = "";
- AZ_Error(AWSGameLiftServerManagerName, false, AWSGameLiftServerPlayerConnectionMissingErrorMessage, playerConnectionId);
- return false;
- }
- }
- void AWSGameLiftServerManager::SetGameLiftServerSDKWrapper(AZStd::unique_ptr<GameLiftServerSDKWrapper> gameLiftServerSDKWrapper)
- {
- m_gameLiftServerSDKWrapper.reset();
- m_gameLiftServerSDKWrapper = AZStd::move(gameLiftServerSDKWrapper);
- }
- bool AWSGameLiftServerManager::ValidatePlayerJoinSession(const AzFramework::PlayerConnectionConfig& playerConnectionConfig)
- {
- uint32_t playerConnectionId = playerConnectionConfig.m_playerConnectionId;
- AZStd::string playerSessionId = playerConnectionConfig.m_playerSessionId;
- if (playerSessionId.empty())
- {
- AZ_Error(AWSGameLiftServerManagerName, false, AWSGameLiftServerInvalidConnectionConfigErrorMessage,
- playerConnectionId, playerSessionId.c_str());
- return false;
- }
- if (!AddConnectedPlayer(playerConnectionConfig))
- {
- return false;
- }
- AZ_TracePrintf(AWSGameLiftServerManagerName, "Attempting to accept player session connection with Amazon GameLift service...");
- auto acceptPlayerSessionOutcome = m_gameLiftServerSDKWrapper->AcceptPlayerSession(playerSessionId.c_str());
- if (!acceptPlayerSessionOutcome.IsSuccess())
- {
- AZ_Error(AWSGameLiftServerManagerName, false, AWSGameLiftServerAcceptPlayerSessionErrorMessage,
- playerSessionId.c_str(), acceptPlayerSessionOutcome.GetError().GetErrorMessage().c_str());
- RemoveConnectedPlayer(playerConnectionId, playerSessionId);
- return false;
- }
- return true;
- }
- } // namespace AWSGameLift
|