Merge 'gameliftfeature' branch into 'development' branch (#1534)

This commit is contained in:
Vincent Liu
2021-06-24 09:13:35 -07:00
committed by GitHub
parent 5ec274d800
commit 149cb2e2f2
70 changed files with 5914 additions and 0 deletions
@@ -0,0 +1,319 @@
/*
* 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
@@ -0,0 +1,128 @@
/*
* 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.
*
*/
#pragma once
#include <aws/gamelift/server/GameLiftServerAPI.h>
#include <aws/gamelift/server/model/GameSession.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>
namespace AWSGameLift
{
class GameLiftServerSDKWrapper;
//! GameLift server process settings.
struct GameLiftServerProcessDesc
{
AZStd::vector<AZStd::string> m_logPaths; //!< Log paths the servers will write to. Both relative to the game root folder and absolute paths supported.
uint16_t m_port = 0; //!< The port the server will be listening on.
};
//! Manage the server process for hosting game sessions via GameLiftServerSDK.
class AWSGameLiftServerManager
: public AzFramework::ISessionHandlingProviderRequests
{
public:
static constexpr const char AWSGameLiftServerManagerName[] = "AWSGameLiftServerManager";
static constexpr const char AWSGameLiftServerSDKNotInitErrorMessage[] =
"Amazon GameLift Server SDK is not initialized yet.";
static constexpr const char AWSGameLiftServerSDKAlreadyInitErrorMessage[] =
"Amazon GameLift Server SDK has already been initialized.";
static constexpr const char AWSGameLiftServerTempPortErrorMessage[] =
"No server port specified, server will be listening on ephemeral port.";
static constexpr const char AWSGameLiftServerGameInitErrorMessage[] =
"Failed to process game dependent initialization during OnStartGameSession.";
static constexpr const char AWSGameLiftServerGameSessionDestroyErrorMessage[] =
"Failed to destroy game session during OnProcessTerminate.";
static constexpr const char AWSGameLiftServerPlayerConnectionRegisteredErrorMessage[] =
"Player connection id %d is already registered to player session id %s. Remove connected player first.";
static constexpr const char AWSGameLiftServerPlayerConnectionMissingErrorMessage[] =
"Player connection id %d does not exist.";
static constexpr const char AWSGameLiftServerInitSDKErrorMessage[] =
"Failed to initialize Amazon GameLift Server SDK. ErrorMessage: %s";
static constexpr const char AWSGameLiftServerProcessReadyErrorMessage[] =
"Failed to notify GameLift server process ready. ErrorMessage: %s";
static constexpr const char AWSGameLiftServerActivateGameSessionErrorMessage[] =
"Failed to activate GameLift game session. ErrorMessage: %s";
static constexpr const char AWSGameLiftServerProcessEndingErrorMessage[] =
"Failed to notify GameLift server process ending. ErrorMessage: %s";
static constexpr const char AWSGameLiftServerAcceptPlayerSessionErrorMessage[] =
"Failed to validate player session connection with id %s. ErrorMessage: %s";
static constexpr const char AWSGameLiftServerInvalidConnectionConfigErrorMessage[] =
"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";
AWSGameLiftServerManager();
virtual ~AWSGameLiftServerManager();
//! Initialize GameLift API client by calling InitSDK().
//! @return Whether the initialization is successful.
bool InitializeGameLiftServerSDK();
//! Notify GameLift that the server process is ready to host a game session.
//! @param desc GameLift server process settings.
//! @return Whether the ProcessReady notification is sent to GameLift.
bool NotifyGameLiftProcessReady(const GameLiftServerProcessDesc& desc);
// ISessionHandlingProviderRequests interface implementation
void HandleDestroySession() override;
bool ValidatePlayerJoinSession(const AzFramework::PlayerConnectionConfig& playerConnectionConfig) override;
void HandlePlayerLeaveSession(const AzFramework::PlayerConnectionConfig& playerConnectionConfig) override;
AZ::IO::Path GetExternalSessionCertificate() override;
AZ::IO::Path GetInternalSessionCertificate() override;
protected:
void SetGameLiftServerSDKWrapper(AZStd::unique_ptr<GameLiftServerSDKWrapper> gameLiftServerSDKWrapper);
//! Add connected player session id.
bool AddConnectedPlayer(const AzFramework::PlayerConnectionConfig& playerConnectionConfig);
private:
//! Build session config by using AWS GameLift Server GameSession Model.
AzFramework::SessionConfig BuildSessionConfig(const Aws::GameLift::Server::Model::GameSession& gameSession);
//! 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();
//! Callback function that the server process or GameLift service invokes to force the server process to shut down.
void OnProcessTerminate();
//! Callback function that the GameLift service invokes to request a health status report from the server process.
//! @return Whether the server process is healthy.
bool OnHealthCheck();
//! Remove connected player session id.
//! @param playerConnectionId Connection id of the player to remove.
//! @param outPlayerSessionId Session id of the removed player. Empty if the player cannot be removed.
//! @return Whether the player is removed successfully.
bool RemoveConnectedPlayer(uint32_t playerConnectionId, AZStd::string& outPlayerSessionId);
AZStd::unique_ptr<GameLiftServerSDKWrapper> m_gameLiftServerSDKWrapper;
bool m_serverSDKInitialized;
AZStd::mutex m_gameliftMutex;
using PlayerConnectionId = uint32_t;
using PlayerSessionId = AZStd::string;
AZStd::unordered_map<PlayerConnectionId, PlayerSessionId> m_connectedPlayers;
};
} // namespace AWSGameLift
@@ -0,0 +1,49 @@
/*
* 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 <AzCore/Memory/SystemAllocator.h>
#include <AzCore/Module/Module.h>
#include <AWSGameLiftServerSystemComponent.h>
namespace AWSGameLift
{
//! Provide the entry point for the gem and register the system component.
class AWSGameLiftServerModule
: public AZ::Module
{
public:
AZ_RTTI(AWSGameLiftServerModule, "{898416ca-dc11-4731-87de-afe285aedb04}", AZ::Module);
AZ_CLASS_ALLOCATOR(AWSGameLiftServerModule, AZ::SystemAllocator, 0);
AWSGameLiftServerModule()
: AZ::Module()
{
// Push results of [MyComponent]::CreateDescriptor() into m_descriptors here.
m_descriptors.insert(m_descriptors.end(), {
AWSGameLiftServerSystemComponent::CreateDescriptor(),
});
}
/**
* Add required SystemComponents to the SystemEntity.
*/
AZ::ComponentTypeList GetRequiredSystemComponents() const override
{
return AZ::ComponentTypeList {
azrtti_typeid<AWSGameLiftServerSystemComponent>(),
};
}
};
}// namespace AWSGameLift
AZ_DECLARE_MODULE_CLASS(Gem_AWSGameLift_Server, AWSGameLift::AWSGameLiftServerModule)
@@ -0,0 +1,129 @@
/*
* 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 <AWSGameLiftServerSystemComponent.h>
#include <AWSGameLiftServerManager.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/Serialization/EditContext.h>
#include <AzCore/Serialization/EditContextConstants.inl>
#include <AzCore/Console/IConsole.h>
#include <AzCore/Interface/Interface.h>
#include <AzCore/IO/FileIO.h>
#include <AzCore/IO/SystemFile.h>
namespace AWSGameLift
{
AWSGameLiftServerSystemComponent::AWSGameLiftServerSystemComponent()
: m_gameLiftServerManager(AZStd::make_unique<AWSGameLiftServerManager>())
{
}
AWSGameLiftServerSystemComponent::~AWSGameLiftServerSystemComponent()
{
m_gameLiftServerManager.reset();
}
void AWSGameLiftServerSystemComponent::Reflect(AZ::ReflectContext* context)
{
if (AZ::SerializeContext* serialize = azrtti_cast<AZ::SerializeContext*>(context))
{
serialize->Class<AWSGameLiftServerSystemComponent, AZ::Component>()
->Version(0)
;
if (AZ::EditContext* ec = serialize->GetEditContext())
{
ec->Class<AWSGameLiftServerSystemComponent>("AWSGameLiftServer", "Create the GameLift server manager which manages the server process for hosting a game session via GameLiftServerSDK.")
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC_CE("System"))
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
;
}
}
}
void AWSGameLiftServerSystemComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)
{
provided.push_back(AZ_CRC_CE("AWSGameLiftServerService"));
}
void AWSGameLiftServerSystemComponent::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible)
{
incompatible.push_back(AZ_CRC_CE("AWSGameLiftServerService"));
}
void AWSGameLiftServerSystemComponent::GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required)
{
AZ_UNUSED(required);
}
void AWSGameLiftServerSystemComponent::GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& dependent)
{
AZ_UNUSED(dependent);
}
void AWSGameLiftServerSystemComponent::Init()
{
}
void AWSGameLiftServerSystemComponent::Activate()
{
if (m_gameLiftServerManager->InitializeGameLiftServerSDK())
{
GameLiftServerProcessDesc serverProcessDesc;
UpdateGameLiftServerProcessDesc(serverProcessDesc);
m_gameLiftServerManager->NotifyGameLiftProcessReady(serverProcessDesc);
}
}
void AWSGameLiftServerSystemComponent::Deactivate()
{
m_gameLiftServerManager->HandleDestroySession();
}
void AWSGameLiftServerSystemComponent::UpdateGameLiftServerProcessDesc(GameLiftServerProcessDesc& serverProcessDesc)
{
AZ::IO::FileIOBase* fileIO = AZ::IO::FileIOBase::GetDirectInstance();
if (fileIO)
{
const char pathToLogFolder[] = "@log@/";
char resolvedPath[AZ_MAX_PATH_LEN];
if (fileIO->ResolvePath(pathToLogFolder, resolvedPath, AZ_ARRAY_SIZE(resolvedPath)))
{
serverProcessDesc.m_logPaths.push_back(resolvedPath);
}
else
{
AZ_Error("AWSGameLift", false, "Failed to resolve the path to the log folder.");
}
}
else
{
AZ_Error("AWSGameLift", false, "Failed to get File IO.");
}
if (auto console = AZ::Interface<AZ::IConsole>::Get(); console != nullptr)
{
AZ::GetValueResult getCvarResult = console->GetCvarValue("sv_port", serverProcessDesc.m_port);
AZ_Error(
"AWSGameLift", getCvarResult == AZ::GetValueResult::Success, "Lookup of 'sv_port' console variable failed with error %s",
AZ::GetEnumString(getCvarResult));
}
}
void AWSGameLiftServerSystemComponent::SetGameLiftServerManager(AZStd::unique_ptr<AWSGameLiftServerManager> gameLiftServerManager)
{
m_gameLiftServerManager.reset();
m_gameLiftServerManager = AZStd::move(gameLiftServerManager);
}
} // namespace AWSGameLift
@@ -0,0 +1,57 @@
/*
* 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.
*
*/
#pragma once
#include <AzCore/Component/Component.h>
namespace AWSGameLift
{
struct GameLiftServerProcessDesc;
class AWSGameLiftServerManager;
//! Gem server system component. Responsible for managing the server process for hosting game sessions via the GameLift server manager.
class AWSGameLiftServerSystemComponent
: public AZ::Component
{
public:
AZ_COMPONENT(AWSGameLiftServerSystemComponent, "{fa2b46d6-82a9-408d-abab-62bae5ab38c9}");
AWSGameLiftServerSystemComponent();
virtual ~AWSGameLiftServerSystemComponent();
static void Reflect(AZ::ReflectContext* context);
static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided);
static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible);
static void GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required);
static void GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& dependent);
protected:
////////////////////////////////////////////////////////////////////////
// AZ::Component interface implementation
void Init() override;
void Activate() override;
void Deactivate() override;
////////////////////////////////////////////////////////////////////////
void SetGameLiftServerManager(AZStd::unique_ptr<AWSGameLiftServerManager> gameLiftServerManager);
private:
//! Update the serverProcessDesc with appropriate server port number and log paths.
//! @param serverProcessDesc Desc object to update.
void UpdateGameLiftServerProcessDesc(GameLiftServerProcessDesc& serverProcessDesc);
AZStd::unique_ptr<AWSGameLiftServerManager> m_gameLiftServerManager;
};
} // namespace AWSGameLift
@@ -0,0 +1,72 @@
/*
* 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 <GameLiftServerSDKWrapper.h>
#include <ctime>
#pragma warning(disable : 4996)
namespace AWSGameLift
{
Aws::GameLift::GenericOutcome GameLiftServerSDKWrapper::AcceptPlayerSession(const std::string& playerSessionId)
{
return Aws::GameLift::Server::AcceptPlayerSession(playerSessionId);
}
Aws::GameLift::GenericOutcome GameLiftServerSDKWrapper::ActivateGameSession()
{
return Aws::GameLift::Server::ActivateGameSession();
}
Aws::GameLift::Server::InitSDKOutcome GameLiftServerSDKWrapper::InitSDK()
{
return Aws::GameLift::Server::InitSDK();
}
Aws::GameLift::GenericOutcome GameLiftServerSDKWrapper::ProcessReady(
const Aws::GameLift::Server::ProcessParameters& processParameters)
{
return Aws::GameLift::Server::ProcessReady(processParameters);
}
Aws::GameLift::GenericOutcome GameLiftServerSDKWrapper::ProcessEnding()
{
return Aws::GameLift::Server::ProcessEnding();
}
AZStd::string GameLiftServerSDKWrapper::GetTerminationTime()
{
// Timestamp format is using the UTC ISO8601 format
std::time_t terminationTime;
Aws::GameLift::AwsLongOutcome GetTerminationTimeOutcome = Aws::GameLift::Server::GetTerminationTime();
if (GetTerminationTimeOutcome.IsSuccess())
{
terminationTime = GetTerminationTimeOutcome.GetResult();
}
else
{
// Use the current system time if the termination time is not available from GameLift.
time(&terminationTime);
}
char buffer[50];
strftime(buffer, sizeof(buffer), "%FT%TZ", gmtime(&terminationTime));
return AZStd::string(buffer);
}
Aws::GameLift::GenericOutcome GameLiftServerSDKWrapper::RemovePlayerSession(const AZStd::string& playerSessionId)
{
return Aws::GameLift::Server::RemovePlayerSession(playerSessionId.c_str());
}
} // namespace AWSGameLift
@@ -0,0 +1,64 @@
/*
* 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.
*
*/
#pragma once
#include <aws/gamelift/server/GameLiftServerAPI.h>
#include <AzCore/std/string/string.h>
namespace AWSGameLift
{
/* Wrapper to use to GameLift Server SDK.
*/
class GameLiftServerSDKWrapper
{
public:
GameLiftServerSDKWrapper() = default;
virtual ~GameLiftServerSDKWrapper() = default;
//! Processes and validates a player session connection.
//! This method should be called when a client requests a connection to the server.
//! @param playerSessionId the ID of the joining player's session.
//! @return Returns a generic outcome consisting of success or failure with an error message.
virtual Aws::GameLift::GenericOutcome AcceptPlayerSession(const std::string& playerSessionId);
//! Reports to GameLift that the server process is now ready to receive player sessions.
//! Should be called once all GameSession initialization has finished.
//! @return Returns a generic outcome consisting of success or failure with an error message.
virtual Aws::GameLift::GenericOutcome ActivateGameSession();
//! 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().
virtual Aws::GameLift::Server::InitSDKOutcome InitSDK();
//! Notifies the GameLift service that the server process is ready to host game sessions.
//! @param processParameters A ProcessParameters object communicating the names of callback methods, port number and game
//! session-specific log files about the server process.
//! @return Returns a generic outcome consisting of success or failure with an error message.
virtual Aws::GameLift::GenericOutcome ProcessReady(const Aws::GameLift::Server::ProcessParameters& processParameters);
//! Notifies the GameLift service that the server process is shutting down.
//! @return Returns a generic outcome consisting of success or failure with an error message.
virtual Aws::GameLift::GenericOutcome ProcessEnding();
//! Returns the time that a server process is scheduled to be shut down.
//! @return Timestamp using the UTC ISO8601 format.
virtual AZStd::string GetTerminationTime();
//! Notifies the GameLift service that a player with the specified player session ID has disconnected from the server process.
//! @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);
};
} // namespace AWSGameLift