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

Signed-off-by: John <jonawals@amazon.com>
monroegm-disable-blank-issue-2
Vincent Liu 5 years ago committed by John
parent 497a93014b
commit 4c65fecb57

@ -12,6 +12,7 @@
#pragma once #pragma once
#include <AzCore/IO/Path/Path.h>
#include <AzCore/RTTI/RTTI.h> #include <AzCore/RTTI/RTTI.h>
#include <AzCore/std/string/string.h> #include <AzCore/std/string/string.h>

@ -0,0 +1,12 @@
#
# 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.
#
add_subdirectory(Code)

@ -0,0 +1,89 @@
#
# 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.
#
set(awsgameliftclient_compile_definition $<IF:$<CONFIG:release>,AWSGAMELIFT_RELEASE,AWSGAMELIFT_DEV>)
ly_add_target(
NAME AWSGameLift.Client.Static STATIC
NAMESPACE Gem
FILES_CMAKE
awsgamelift_client_files.cmake
INCLUDE_DIRECTORIES
PUBLIC
Include
PRIVATE
Source
../AWSGameLiftCommon/Source
COMPILE_DEFINITIONS
PRIVATE
${awsgameliftclient_compile_definition}
BUILD_DEPENDENCIES
PRIVATE
AZ::AzCore
AZ::AzFramework
Gem::AWSCore
3rdParty::AWSNativeSDK::GameLiftClient
)
ly_add_target(
NAME AWSGameLift.Clients ${PAL_TRAIT_MONOLITHIC_DRIVEN_MODULE_TYPE}
NAMESPACE Gem
FILES_CMAKE
awsgamelift_client_shared_files.cmake
INCLUDE_DIRECTORIES
PRIVATE
Source
BUILD_DEPENDENCIES
PRIVATE
AZ::AzCore
3rdParty::AWSNativeSDK::GameLiftClient
PUBLIC
Gem::AWSGameLift.Client.Static
RUNTIME_DEPENDENCIES
Gem::AWSCore
)
# Load the "Gem::AWSGameLift" module in all types of applications.
if (PAL_TRAIT_BUILD_HOST_TOOLS)
ly_create_alias(NAME AWSGameLift.Tools NAMESPACE Gem TARGETS Gem::AWSGameLift.Clients)
ly_create_alias(NAME AWSGameLift.Builders NAMESPACE Gem TARGETS Gem::AWSGameLift.Clients)
endif()
################################################################################
# Tests
################################################################################
if(PAL_TRAIT_BUILD_TESTS_SUPPORTED)
ly_add_target(
NAME AWSGameLift.Client.Tests ${PAL_TRAIT_TEST_TARGET_TYPE}
NAMESPACE Gem
FILES_CMAKE
awsgamelift_client_tests_files.cmake
INCLUDE_DIRECTORIES
PRIVATE
Include
Tests
Source
../AWSGameLiftCommon/Source
BUILD_DEPENDENCIES
PRIVATE
AZ::AzCore
AZ::AzFramework
AZ::AzTest
Gem::AWSCore
Gem::AWSGameLift.Client.Static
3rdParty::AWSNativeSDK::GameLiftClient
AZ::AWSNativeSDKInit
)
# Add AWSGameLift.Client.Tests to googletest
ly_add_googletest(
NAME Gem::AWSGameLift.Client.Tests
)
endif()

@ -0,0 +1,39 @@
/*
* 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 <AzFramework/Session/ISessionRequests.h>
namespace AWSGameLift
{
//! AWSGameLiftCreateSessionOnQueueRequest
//! GameLift create session on queue request which corresponds to Amazon GameLift
//! StartGameSessionPlacement
struct AWSGameLiftCreateSessionOnQueueRequest
: public AzFramework::CreateSessionRequest
{
public:
AZ_RTTI(AWSGameLiftCreateSessionOnQueueRequest, "{2B99E594-CE81-4EB0-8888-74EF4242B59F}", AzFramework::CreateSessionRequest);
static void Reflect(AZ::ReflectContext* context);
AWSGameLiftCreateSessionOnQueueRequest() = default;
virtual ~AWSGameLiftCreateSessionOnQueueRequest() = default;
// Name of the queue to use to place the new game session. You can use either the queue name or ARN value.
AZStd::string m_queueName;
// A unique identifier to assign to the new game session placement. This value is developer-defined.
// The value must be unique across all Regions and cannot be reused unless you are resubmitting a canceled or timed-out placement request.
AZStd::string m_placementId;
};
} // namespace AWSGameLift

@ -0,0 +1,42 @@
/*
* 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 <AzFramework/Session/ISessionRequests.h>
namespace AWSGameLift
{
//! AWSGameLiftCreateSessionRequest
//! GameLift create session on fleet request which corresponds to Amazon GameLift
//! CreateGameSessionRequest
struct AWSGameLiftCreateSessionRequest
: public AzFramework::CreateSessionRequest
{
public:
AZ_RTTI(AWSGameLiftCreateSessionRequest, "{69612D5D-F899-4DEB-AD63-4C497ABC5C0D}", AzFramework::CreateSessionRequest);
static void Reflect(AZ::ReflectContext* context);
AWSGameLiftCreateSessionRequest() = default;
virtual ~AWSGameLiftCreateSessionRequest() = default;
// A unique identifier for the alias associated with the fleet to create a game session in.
AZStd::string m_aliasId;
// A unique identifier for the fleet to create a game session in.
AZStd::string m_fleetId;
// Custom string that uniquely identifies the new game session request.
// This is useful for ensuring that game session requests with the same idempotency token are processed only once.
AZStd::string m_idempotencyToken;
};
} // namespace AWSGameLift

@ -0,0 +1,33 @@
/*
* 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 <AzFramework/Session/ISessionRequests.h>
namespace AWSGameLift
{
//! AWSGameLiftJoinSessionRequest
//! GameLift join session request which corresponds to Amazon GameLift CreatePlayerSessionRequest.
//! Once player session has been created successfully in game session, gamelift client manager will
//! signal Multiplayer Gem to setup networking connection.
struct AWSGameLiftJoinSessionRequest
: public AzFramework::JoinSessionRequest
{
public:
AZ_RTTI(AWSGameLiftJoinSessionRequest, "{6EED6D15-531A-4956-90D0-2EDA31AC9CBA}", AzFramework::JoinSessionRequest);
static void Reflect(AZ::ReflectContext* context);
AWSGameLiftJoinSessionRequest() = default;
virtual ~AWSGameLiftJoinSessionRequest() = default;
};
} // namespace AWSGameLift

@ -0,0 +1,42 @@
/*
* 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 <AzFramework/Session/ISessionRequests.h>
namespace AWSGameLift
{
//! AWSGameLiftSearchSessionsRequest
//! GameLift search sessions request which corresponds to Amazon GameLift
//! SearchSessionsRequest
struct AWSGameLiftSearchSessionsRequest
: public AzFramework::SearchSessionsRequest
{
public:
AZ_RTTI(AWSGameLiftSearchSessionsRequest, "{864C91C0-CA53-4585-BF07-066C0DF3E198}", AzFramework::SearchSessionsRequest);
static void Reflect(AZ::ReflectContext* context);
AWSGameLiftSearchSessionsRequest() = default;
virtual ~AWSGameLiftSearchSessionsRequest() = default;
// A unique identifier for the alias associated with the fleet to search for active game sessions.
AZStd::string m_aliasId;
// A unique identifier for the fleet to search for active game sessions.
AZStd::string m_fleetId;
// A fleet location to search for game sessions.
AZStd::string m_location;
};
} // namespace AWSGameLift

@ -0,0 +1,78 @@
/*
* 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/EBus/EBus.h>
#include <AzCore/RTTI/BehaviorContext.h>
#include <AzCore/std/string/string.h>
#include <AzFramework/Session/ISessionRequests.h>
namespace AWSGameLift
{
//! IAWSGameLiftRequests
//! GameLift Gem interfaces to configure client manager
class IAWSGameLiftRequests
{
public:
AZ_RTTI(IAWSGameLiftRequests, "{494167AD-1185-4AF3-8BF9-C8C37FC9C199}");
IAWSGameLiftRequests() = default;
virtual ~IAWSGameLiftRequests() = default;
//! ConfigureGameLiftClient
//! Configure GameLift client to interact with Amazon GameLift service
//! @param region Specifies the AWS region to use
//! @return True if client configuration succeeds, false otherwise
virtual bool ConfigureGameLiftClient(const AZStd::string& region) = 0;
//! CreatePlayerId
//! Create a new, random ID number for every player in every new game session.
//! @param includeBrackets Whether includes brackets in player id
//! @param includeDashes Whether includes dashes in player id
//! @return The player id to use in game session
virtual AZStd::string CreatePlayerId(bool includeBrackets, bool includeDashes) = 0;
};
// IAWSGameLiftRequests EBus wrapper for scripting
class AWSGameLiftRequests
: public AZ::EBusTraits
{
public:
using MutexType = AZStd::recursive_mutex;
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single;
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single;
};
using AWSGameLiftRequestBus = AZ::EBus<IAWSGameLiftRequests, AWSGameLiftRequests>;
// ISessionAsyncRequests EBus wrapper for scripting
class AWSGameLiftSessionAsyncRequests
: public AZ::EBusTraits
{
public:
using MutexType = AZStd::recursive_mutex;
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single;
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single;
};
using AWSGameLiftSessionAsyncRequestBus = AZ::EBus<AzFramework::ISessionAsyncRequests, AWSGameLiftSessionAsyncRequests>;
// ISessionRequests EBus wrapper for scripting
class AWSGameLiftSessionRequests
: public AZ::EBusTraits
{
public:
using MutexType = AZStd::recursive_mutex;
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single;
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single;
};
using AWSGameLiftSessionRequestBus = AZ::EBus<AzFramework::ISessionRequests, AWSGameLiftSessionRequests>;
} // namespace AWSGameLift

@ -0,0 +1,360 @@
/*
* 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/Console/IConsole.h>
#include <AzCore/Interface/Interface.h>
#include <AzCore/Jobs/JobFunction.h>
#include <AzCore/std/smart_ptr/make_shared.h>
#include <AzFramework/Session/SessionConfig.h>
#include <AWSCoreBus.h>
#include <Credential/AWSCredentialBus.h>
#include <ResourceMapping/AWSResourceMappingBus.h>
#include <AWSGameLiftClientManager.h>
#include <Activity/AWSGameLiftCreateSessionActivity.h>
#include <Activity/AWSGameLiftCreateSessionOnQueueActivity.h>
#include <Activity/AWSGameLiftJoinSessionActivity.h>
#include <Activity/AWSGameLiftLeaveSessionActivity.h>
#include <Activity/AWSGameLiftSearchSessionsActivity.h>
#include <aws/core/auth/AWSCredentialsProvider.h>
namespace AWSGameLift
{
#if defined(AWSGAMELIFT_DEV)
AZ_CVAR(AZ::CVarFixedString, cl_gameliftLocalEndpoint, "", nullptr, AZ::ConsoleFunctorFlags::Null, "The local endpoint to test with GameLiftLocal SDK.");
#endif
AWSGameLiftClientManager::AWSGameLiftClientManager()
{
m_gameliftClient.reset();
}
void AWSGameLiftClientManager::ActivateManager()
{
AZ::Interface<IAWSGameLiftRequests>::Register(this);
AWSGameLiftRequestBus::Handler::BusConnect();
AZ::Interface<AzFramework::ISessionAsyncRequests>::Register(this);
AWSGameLiftSessionAsyncRequestBus::Handler::BusConnect();
AZ::Interface<AzFramework::ISessionRequests>::Register(this);
AWSGameLiftSessionRequestBus::Handler::BusConnect();
}
void AWSGameLiftClientManager::DeactivateManager()
{
AWSGameLiftSessionRequestBus::Handler::BusDisconnect();
AZ::Interface<AzFramework::ISessionRequests>::Unregister(this);
AWSGameLiftSessionAsyncRequestBus::Handler::BusDisconnect();
AZ::Interface<AzFramework::ISessionAsyncRequests>::Unregister(this);
AWSGameLiftRequestBus::Handler::BusDisconnect();
AZ::Interface<IAWSGameLiftRequests>::Unregister(this);
}
bool AWSGameLiftClientManager::ConfigureGameLiftClient(const AZStd::string& region)
{
m_gameliftClient.reset();
Aws::Client::ClientConfiguration clientConfig;
// Set up client endpoint or region
AZStd::string localEndpoint = "";
#if defined(AWSGAMELIFT_DEV)
localEndpoint = static_cast<AZ::CVarFixedString>(cl_gameliftLocalEndpoint);
#endif
if (!localEndpoint.empty())
{
// The attribute needs to override to interact with GameLiftLocal
clientConfig.endpointOverride = localEndpoint.c_str();
}
else if (!region.empty())
{
clientConfig.region = region.c_str();
}
else
{
AZStd::string clientRegion;
AWSCore::AWSResourceMappingRequestBus::BroadcastResult(clientRegion, &AWSCore::AWSResourceMappingRequests::GetDefaultRegion);
if (clientRegion.empty())
{
AZ_Error(AWSGameLiftClientManagerName, false, AWSGameLiftClientRegionMissingErrorMessage);
return false;
}
clientConfig.region = clientRegion.c_str();
}
// Fetch AWS credential for client
AWSCore::AWSCredentialResult credentialResult;
AWSCore::AWSCredentialRequestBus::BroadcastResult(credentialResult, &AWSCore::AWSCredentialRequests::GetCredentialsProvider);
if (!localEndpoint.empty())
{
credentialResult.result = std::make_shared<Aws::Auth::AnonymousAWSCredentialsProvider>();
}
else if (!credentialResult.result)
{
AZ_Error(AWSGameLiftClientManagerName, false, AWSGameLiftClientCredentialMissingErrorMessage);
return false;
}
m_gameliftClient = AZStd::make_shared<Aws::GameLift::GameLiftClient>(credentialResult.result, clientConfig);
return true;
}
AZStd::string AWSGameLiftClientManager::CreatePlayerId(bool includeBrackets, bool includeDashes)
{
return AZ::Uuid::CreateRandom().ToString<AZStd::string>(includeBrackets, includeDashes);
}
AZStd::string AWSGameLiftClientManager::CreateSession(const AzFramework::CreateSessionRequest& createSessionRequest)
{
AZStd::string result = "";
if (CreateSessionActivity::ValidateCreateSessionRequest(createSessionRequest))
{
const AWSGameLiftCreateSessionRequest& gameliftCreateSessionRequest =
static_cast<const AWSGameLiftCreateSessionRequest&>(createSessionRequest);
result = CreateSessionHelper(gameliftCreateSessionRequest);
}
else if (CreateSessionOnQueueActivity::ValidateCreateSessionOnQueueRequest(createSessionRequest))
{
const AWSGameLiftCreateSessionOnQueueRequest& gameliftCreateSessionOnQueueRequest =
static_cast<const AWSGameLiftCreateSessionOnQueueRequest&>(createSessionRequest);
result = CreateSessionOnQueueHelper(gameliftCreateSessionOnQueueRequest);
}
else
{
AZ_Error(AWSGameLiftClientManagerName, false, AWSGameLiftCreateSessionRequestInvalidErrorMessage);
}
return result;
}
void AWSGameLiftClientManager::CreateSessionAsync(const AzFramework::CreateSessionRequest& createSessionRequest)
{
if (CreateSessionActivity::ValidateCreateSessionRequest(createSessionRequest))
{
const AWSGameLiftCreateSessionRequest& gameliftCreateSessionRequest =
static_cast<const AWSGameLiftCreateSessionRequest&>(createSessionRequest);
AZ::JobContext* jobContext = nullptr;
AWSCore::AWSCoreRequestBus::BroadcastResult(jobContext, &AWSCore::AWSCoreRequests::GetDefaultJobContext);
AZ::Job* createSessionJob = AZ::CreateJobFunction(
[this, gameliftCreateSessionRequest]()
{
AZStd::string result = CreateSessionHelper(gameliftCreateSessionRequest);
AzFramework::SessionAsyncRequestNotificationBus::Broadcast(
&AzFramework::SessionAsyncRequestNotifications::OnCreateSessionAsyncComplete, result);
},
true, jobContext);
createSessionJob->Start();
}
else if (CreateSessionOnQueueActivity::ValidateCreateSessionOnQueueRequest(createSessionRequest))
{
const AWSGameLiftCreateSessionOnQueueRequest& gameliftCreateSessionOnQueueRequest =
static_cast<const AWSGameLiftCreateSessionOnQueueRequest&>(createSessionRequest);
AZ::JobContext* jobContext = nullptr;
AWSCore::AWSCoreRequestBus::BroadcastResult(jobContext, &AWSCore::AWSCoreRequests::GetDefaultJobContext);
AZ::Job* createSessionOnQueueJob = AZ::CreateJobFunction(
[this, gameliftCreateSessionOnQueueRequest]()
{
AZStd::string result = CreateSessionOnQueueHelper(gameliftCreateSessionOnQueueRequest);
AzFramework::SessionAsyncRequestNotificationBus::Broadcast(
&AzFramework::SessionAsyncRequestNotifications::OnCreateSessionAsyncComplete, result);
},
true, jobContext);
createSessionOnQueueJob->Start();
}
else
{
AZ_Error(AWSGameLiftClientManagerName, false, AWSGameLiftCreateSessionRequestInvalidErrorMessage);
AzFramework::SessionAsyncRequestNotificationBus::Broadcast(
&AzFramework::SessionAsyncRequestNotifications::OnCreateSessionAsyncComplete, "");
}
}
AZStd::string AWSGameLiftClientManager::CreateSessionHelper(
const AWSGameLiftCreateSessionRequest& createSessionRequest)
{
AZStd::shared_ptr<Aws::GameLift::GameLiftClient> gameLiftClient = m_gameliftClient;
AZStd::string result = "";
if (!gameLiftClient)
{
AZ_Error(AWSGameLiftClientManagerName, false, AWSGameLiftClientMissingErrorMessage);
}
else
{
result = CreateSessionActivity::CreateSession(*gameLiftClient, createSessionRequest);
}
return result;
}
AZStd::string AWSGameLiftClientManager::CreateSessionOnQueueHelper(
const AWSGameLiftCreateSessionOnQueueRequest& createSessionOnQueueRequest)
{
AZStd::shared_ptr<Aws::GameLift::GameLiftClient> gameliftClient = m_gameliftClient;
AZStd::string result;
if (!gameliftClient)
{
AZ_Error(AWSGameLiftClientManagerName, false, AWSGameLiftClientMissingErrorMessage);
}
else
{
result = CreateSessionOnQueueActivity::CreateSessionOnQueue(*gameliftClient, createSessionOnQueueRequest);
}
return result;
}
bool AWSGameLiftClientManager::JoinSession(const AzFramework::JoinSessionRequest& joinSessionRequest)
{
bool result = false;
if (JoinSessionActivity::ValidateJoinSessionRequest(joinSessionRequest))
{
const AWSGameLiftJoinSessionRequest& gameliftJoinSessionRequest =
static_cast<const AWSGameLiftJoinSessionRequest&>(joinSessionRequest);
result = JoinSessionHelper(gameliftJoinSessionRequest);
}
return result;
}
void AWSGameLiftClientManager::JoinSessionAsync(const AzFramework::JoinSessionRequest& joinSessionRequest)
{
if (!JoinSessionActivity::ValidateJoinSessionRequest(joinSessionRequest))
{
AzFramework::SessionAsyncRequestNotificationBus::Broadcast(
&AzFramework::SessionAsyncRequestNotifications::OnJoinSessionAsyncComplete, false);
return;
}
const AWSGameLiftJoinSessionRequest& gameliftJoinSessionRequest =
static_cast<const AWSGameLiftJoinSessionRequest&>(joinSessionRequest);
AZ::JobContext* jobContext = nullptr;
AWSCore::AWSCoreRequestBus::BroadcastResult(jobContext, &AWSCore::AWSCoreRequests::GetDefaultJobContext);
AZ::Job* joinSessionJob = AZ::CreateJobFunction(
[this, gameliftJoinSessionRequest]()
{
bool result = JoinSessionHelper(gameliftJoinSessionRequest);
AzFramework::SessionAsyncRequestNotificationBus::Broadcast(
&AzFramework::SessionAsyncRequestNotifications::OnJoinSessionAsyncComplete, result);
},
true, jobContext);
joinSessionJob->Start();
}
bool AWSGameLiftClientManager::JoinSessionHelper(const AWSGameLiftJoinSessionRequest& joinSessionRequest)
{
AZStd::shared_ptr<Aws::GameLift::GameLiftClient> gameliftClient = m_gameliftClient;
bool result = false;
if (!gameliftClient)
{
AZ_Error(AWSGameLiftClientManagerName, false, AWSGameLiftClientMissingErrorMessage);
}
else
{
auto createPlayerSessionOutcome = JoinSessionActivity::CreatePlayerSession(*gameliftClient, joinSessionRequest);
result = JoinSessionActivity::RequestPlayerJoinSession(createPlayerSessionOutcome);
}
return result;
}
void AWSGameLiftClientManager::LeaveSession()
{
AWSGameLift::LeaveSessionActivity::LeaveSession();
}
void AWSGameLiftClientManager::LeaveSessionAsync()
{
AZ::JobContext* jobContext = nullptr;
AWSCore::AWSCoreRequestBus::BroadcastResult(jobContext, &AWSCore::AWSCoreRequests::GetDefaultJobContext);
AZ::Job* leaveSessionJob = AZ::CreateJobFunction(
[this]()
{
LeaveSession();
AzFramework::SessionAsyncRequestNotificationBus::Broadcast(
&AzFramework::SessionAsyncRequestNotifications::OnLeaveSessionAsyncComplete);
},
true, jobContext);
leaveSessionJob->Start();
}
AzFramework::SearchSessionsResponse AWSGameLiftClientManager::SearchSessions(
const AzFramework::SearchSessionsRequest& searchSessionsRequest) const
{
AzFramework::SearchSessionsResponse response;
if (SearchSessionsActivity::ValidateSearchSessionsRequest(searchSessionsRequest))
{
const AWSGameLiftSearchSessionsRequest& gameliftSearchSessionsRequest =
static_cast<const AWSGameLiftSearchSessionsRequest&>(searchSessionsRequest);
response = SearchSessionsHelper(gameliftSearchSessionsRequest);
}
return response;
}
void AWSGameLiftClientManager::SearchSessionsAsync(const AzFramework::SearchSessionsRequest& searchSessionsRequest) const
{
if (!SearchSessionsActivity::ValidateSearchSessionsRequest(searchSessionsRequest))
{
AzFramework::SessionAsyncRequestNotificationBus::Broadcast(
&AzFramework::SessionAsyncRequestNotifications::OnSearchSessionsAsyncComplete, AzFramework::SearchSessionsResponse());
return;
}
const AWSGameLiftSearchSessionsRequest& gameliftSearchSessionsRequest =
static_cast<const AWSGameLiftSearchSessionsRequest&>(searchSessionsRequest);
AZ::JobContext* jobContext = nullptr;
AWSCore::AWSCoreRequestBus::BroadcastResult(jobContext, &AWSCore::AWSCoreRequests::GetDefaultJobContext);
AZ::Job* searchSessionsJob = AZ::CreateJobFunction(
[this, gameliftSearchSessionsRequest]()
{
AzFramework::SearchSessionsResponse response = SearchSessionsHelper(gameliftSearchSessionsRequest);
AzFramework::SessionAsyncRequestNotificationBus::Broadcast(
&AzFramework::SessionAsyncRequestNotifications::OnSearchSessionsAsyncComplete, response);
},
true, jobContext);
searchSessionsJob->Start();
}
AzFramework::SearchSessionsResponse AWSGameLiftClientManager::SearchSessionsHelper(
const AWSGameLiftSearchSessionsRequest& searchSessionsRequest) const
{
AZStd::shared_ptr<Aws::GameLift::GameLiftClient> gameliftClient = m_gameliftClient;
AzFramework::SearchSessionsResponse response;
if (!gameliftClient)
{
AZ_Error(AWSGameLiftClientManagerName, false, AWSGameLiftClientMissingErrorMessage);
}
else
{
response = SearchSessionsActivity::SearchSessions(*gameliftClient, searchSessionsRequest);
}
return response;
}
void AWSGameLiftClientManager::SetGameLiftClient(AZStd::shared_ptr<Aws::GameLift::GameLiftClient> gameliftClient)
{
m_gameliftClient.swap(gameliftClient);
}
} // namespace AWSGameLift

@ -0,0 +1,122 @@
/*
* 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/std/smart_ptr/shared_ptr.h>
#include <Request/IAWSGameLiftRequests.h>
namespace Aws
{
namespace GameLift
{
class GameLiftClient;
}
}
namespace AWSGameLift
{
struct AWSGameLiftCreateSessionRequest;
struct AWSGameLiftCreateSessionOnQueueRequest;
struct AWSGameLiftJoinSessionRequest;
struct AWSGameLiftSearchSessionsRequest;
// SessionAsyncRequestNotificationBus EBus handler for scripting
class AWSGameLiftSessionAsyncRequestNotificationBusHandler
: public AzFramework::SessionAsyncRequestNotificationBus::Handler
, public AZ::BehaviorEBusHandler
{
public:
AZ_EBUS_BEHAVIOR_BINDER(
AWSGameLiftSessionAsyncRequestNotificationBusHandler,
"{6E13FC73-53DC-4B6B-AEA7-9038DE4C9635}",
AZ::SystemAllocator,
OnCreateSessionAsyncComplete,
OnSearchSessionsAsyncComplete,
OnJoinSessionAsyncComplete,
OnLeaveSessionAsyncComplete);
void OnCreateSessionAsyncComplete(const AZStd::string& createSessionReponse) override
{
Call(FN_OnCreateSessionAsyncComplete, createSessionReponse);
}
void OnSearchSessionsAsyncComplete(const AzFramework::SearchSessionsResponse& searchSessionsResponse) override
{
Call(FN_OnSearchSessionsAsyncComplete, searchSessionsResponse);
}
void OnJoinSessionAsyncComplete(bool joinSessionsResponse) override
{
Call(FN_OnJoinSessionAsyncComplete, joinSessionsResponse);
}
void OnLeaveSessionAsyncComplete() override
{
Call(FN_OnLeaveSessionAsyncComplete);
}
};
//! AWSGameLiftClientManager
//! GameLift client manager to support game and player session related client requests
class AWSGameLiftClientManager
: public AWSGameLiftRequestBus::Handler
, public AWSGameLiftSessionAsyncRequestBus::Handler
, public AWSGameLiftSessionRequestBus::Handler
{
public:
static constexpr const char AWSGameLiftClientManagerName[] = "AWSGameLiftClientManager";
static constexpr const char AWSGameLiftClientRegionMissingErrorMessage[] =
"Missing AWS region for GameLift client.";
static constexpr const char AWSGameLiftClientCredentialMissingErrorMessage[] =
"Missing AWS credential for GameLift client.";
static constexpr const char AWSGameLiftClientMissingErrorMessage[] =
"GameLift client is not configured yet.";
static constexpr const char AWSGameLiftCreateSessionRequestInvalidErrorMessage[] =
"Invalid GameLift CreateSession or CreateSessionOnQueue request.";
AWSGameLiftClientManager();
virtual ~AWSGameLiftClientManager() = default;
virtual void ActivateManager();
virtual void DeactivateManager();
// AWSGameLiftRequestBus interface implementation
bool ConfigureGameLiftClient(const AZStd::string& region) override;
AZStd::string CreatePlayerId(bool includeBrackets, bool includeDashes) override;
// AWSGameLiftSessionAsyncRequestBus interface implementation
void CreateSessionAsync(const AzFramework::CreateSessionRequest& createSessionRequest) override;
void JoinSessionAsync(const AzFramework::JoinSessionRequest& joinSessionRequest) override;
void SearchSessionsAsync(const AzFramework::SearchSessionsRequest& searchSessionsRequest) const override;
void LeaveSessionAsync() override;
// AWSGameLiftSessionRequestBus interface implementation
AZStd::string CreateSession(const AzFramework::CreateSessionRequest& createSessionRequest) override;
bool JoinSession(const AzFramework::JoinSessionRequest& joinSessionRequest) override;
AzFramework::SearchSessionsResponse SearchSessions(const AzFramework::SearchSessionsRequest& searchSessionsRequest) const override;
void LeaveSession() override;
protected:
// Use for automation tests only to inject mock objects.
void SetGameLiftClient(AZStd::shared_ptr<Aws::GameLift::GameLiftClient> gameliftClient);
private:
AZStd::string CreateSessionHelper(const AWSGameLiftCreateSessionRequest& createSessionRequest);
AZStd::string CreateSessionOnQueueHelper(const AWSGameLiftCreateSessionOnQueueRequest& createSessionOnQueueRequest);
bool JoinSessionHelper(const AWSGameLiftJoinSessionRequest& joinSessionRequest);
AzFramework::SearchSessionsResponse SearchSessionsHelper(const AWSGameLiftSearchSessionsRequest& searchSessionsRequest) const;
AZStd::shared_ptr<Aws::GameLift::GameLiftClient> m_gameliftClient;
};
} // 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 <AWSGameLiftClientSystemComponent.h>
namespace AWSGameLift
{
//! Provide the entry point for the gem and register the system component.
class AWSGameLiftClientModule
: public AZ::Module
{
public:
AZ_RTTI(AWSGameLiftClientModule, "{7b920f3e-2b23-482e-a1b6-16bd278d126c}", AZ::Module);
AZ_CLASS_ALLOCATOR(AWSGameLiftClientModule, AZ::SystemAllocator, 0);
AWSGameLiftClientModule()
: AZ::Module()
{
// Push results of [MyComponent]::CreateDescriptor() into m_descriptors here.
m_descriptors.insert(m_descriptors.end(), {
AWSGameLiftClientSystemComponent::CreateDescriptor(),
});
}
/**
* Add required SystemComponents to the SystemEntity.
*/
AZ::ComponentTypeList GetRequiredSystemComponents() const override
{
return AZ::ComponentTypeList {
azrtti_typeid<AWSGameLiftClientSystemComponent>(),
};
}
};
}// namespace AWSGameLift
AZ_DECLARE_MODULE_CLASS(Gem_AWSGameLift_Client, AWSGameLift::AWSGameLiftClientModule)

@ -0,0 +1,186 @@
/*
* 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/Serialization/SerializeContext.h>
#include <AzCore/Serialization/EditContext.h>
#include <AzCore/Serialization/EditContextConstants.inl>
#include <AzFramework/Session/SessionConfig.h>
#include <AWSGameLiftClientManager.h>
#include <AWSGameLiftClientSystemComponent.h>
#include <Request/AWSGameLiftCreateSessionOnQueueRequest.h>
#include <Request/AWSGameLiftCreateSessionRequest.h>
#include <Request/AWSGameLiftJoinSessionRequest.h>
#include <Request/AWSGameLiftSearchSessionsRequest.h>
#include <aws/gamelift/GameLiftClient.h>
namespace AWSGameLift
{
AWSGameLiftClientSystemComponent::AWSGameLiftClientSystemComponent()
{
m_gameliftClientManager = AZStd::make_unique<AWSGameLiftClientManager>();
}
void AWSGameLiftClientSystemComponent::Reflect(AZ::ReflectContext* context)
{
ReflectCreateSessionRequest(context);
AWSGameLiftCreateSessionOnQueueRequest::Reflect(context);
AWSGameLiftCreateSessionRequest::Reflect(context);
AWSGameLiftJoinSessionRequest::Reflect(context);
AWSGameLiftSearchSessionsRequest::Reflect(context);
ReflectSearchSessionsResponse(context);
if (AZ::SerializeContext* serialize = azrtti_cast<AZ::SerializeContext*>(context))
{
serialize->Class<AWSGameLiftClientSystemComponent, AZ::Component>()
->Version(0)
;
if (AZ::EditContext* editContext = serialize->GetEditContext())
{
editContext
->Class<AWSGameLiftClientSystemComponent>(
"AWSGameLiftClient",
"Create the GameLift client manager that handles communication between game clients and the GameLift service.")
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("System"))
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
;
}
}
if (AZ::BehaviorContext* behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context))
{
behaviorContext->EBus<AWSGameLiftRequestBus>("AWSGameLiftRequestBus")
->Attribute(AZ::Script::Attributes::Category, "AWSGameLift")
->Event("ConfigureGameLiftClient", &AWSGameLiftRequestBus::Events::ConfigureGameLiftClient,
{{{"Region", ""}}})
->Event("CreatePlayerId", &AWSGameLiftRequestBus::Events::CreatePlayerId,
{{{"IncludeBrackets", ""},
{"IncludeDashes", ""}}})
;
behaviorContext->EBus<AWSGameLiftSessionAsyncRequestBus>("AWSGameLiftSessionAsyncRequestBus")
->Attribute(AZ::Script::Attributes::Category, "AWSGameLift")
->Event("CreateSessionAsync", &AWSGameLiftSessionAsyncRequestBus::Events::CreateSessionAsync,
{{{"CreateSessionRequest", ""}}})
->Event("JoinSessionAsync", &AWSGameLiftSessionAsyncRequestBus::Events::JoinSessionAsync,
{{{"JoinSessionRequest", ""}}})
->Event("SearchSessionsAsync", &AWSGameLiftSessionAsyncRequestBus::Events::SearchSessionsAsync,
{{{"SearchSessionsRequest", ""}}})
->Event("LeaveSessionAsync", &AWSGameLiftSessionAsyncRequestBus::Events::LeaveSessionAsync)
;
behaviorContext
->EBus<AzFramework::SessionAsyncRequestNotificationBus>("AWSGameLiftSessionAsyncRequestNotificationBus")
->Attribute(AZ::Script::Attributes::Category, "AWSGameLift")
->Handler<AWSGameLiftSessionAsyncRequestNotificationBusHandler>()
;
behaviorContext->EBus<AWSGameLiftSessionRequestBus>("AWSGameLiftSessionRequestBus")
->Attribute(AZ::Script::Attributes::Category, "AWSGameLift")
->Event("CreateSession", &AWSGameLiftSessionRequestBus::Events::CreateSession,
{{{"CreateSessionRequest", ""}}})
->Event("JoinSession", &AWSGameLiftSessionRequestBus::Events::JoinSession,
{{{"JoinSessionRequest", ""}}})
->Event("SearchSessions", &AWSGameLiftSessionRequestBus::Events::SearchSessions,
{{{"SearchSessionsRequest", ""}}})
->Event("LeaveSession", &AWSGameLiftSessionRequestBus::Events::LeaveSession)
;
}
}
void AWSGameLiftClientSystemComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)
{
provided.push_back(AZ_CRC_CE("AWSGameLiftClientService"));
}
void AWSGameLiftClientSystemComponent::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible)
{
incompatible.push_back(AZ_CRC_CE("AWSGameLiftClientService"));
}
void AWSGameLiftClientSystemComponent::GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required)
{
required.push_back(AZ_CRC_CE("AWSCoreService"));
}
void AWSGameLiftClientSystemComponent::GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& dependent)
{
AZ_UNUSED(dependent);
}
void AWSGameLiftClientSystemComponent::Init()
{
}
void AWSGameLiftClientSystemComponent::Activate()
{
m_gameliftClientManager->ActivateManager();
}
void AWSGameLiftClientSystemComponent::Deactivate()
{
m_gameliftClientManager->DeactivateManager();
}
void AWSGameLiftClientSystemComponent::ReflectCreateSessionRequest(AZ::ReflectContext* context)
{
AzFramework::CreateSessionRequest::Reflect(context);
if (AZ::BehaviorContext* behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context))
{
behaviorContext->Class<AzFramework::CreateSessionRequest>("CreateSessionRequest")
->Attribute(AZ::Script::Attributes::Storage, AZ::Script::Attributes::StorageType::Value)
// Expose base type to BehaviorContext, but hide it to be used directly
->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::All)
;
}
}
void AWSGameLiftClientSystemComponent::ReflectSearchSessionsResponse(AZ::ReflectContext* context)
{
// As it is a common response type, reflection could be moved to AzFramework to avoid duplication
AzFramework::SessionConfig::Reflect(context);
AzFramework::SearchSessionsResponse::Reflect(context);
if (AZ::BehaviorContext* behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context))
{
behaviorContext->Class<AzFramework::SessionConfig>("SessionConfig")
->Attribute(AZ::Script::Attributes::Category, "Session")
->Attribute(AZ::Script::Attributes::Storage, AZ::Script::Attributes::StorageType::Value)
->Property("CreationTime", BehaviorValueProperty(&AzFramework::SessionConfig::m_creationTime))
->Property("CreatorId", BehaviorValueProperty(&AzFramework::SessionConfig::m_creatorId))
->Property("CurrentPlayer", BehaviorValueProperty(&AzFramework::SessionConfig::m_currentPlayer))
->Property("DnsName", BehaviorValueProperty(&AzFramework::SessionConfig::m_dnsName))
->Property("IpAddress", BehaviorValueProperty(&AzFramework::SessionConfig::m_ipAddress))
->Property("MaxPlayer", BehaviorValueProperty(&AzFramework::SessionConfig::m_maxPlayer))
->Property("Port", BehaviorValueProperty(&AzFramework::SessionConfig::m_port))
->Property("SessionId", BehaviorValueProperty(&AzFramework::SessionConfig::m_sessionId))
->Property("SessionName", BehaviorValueProperty(&AzFramework::SessionConfig::m_sessionName))
->Property("SessionProperties", BehaviorValueProperty(&AzFramework::SessionConfig::m_sessionProperties))
->Property("Status", BehaviorValueProperty(&AzFramework::SessionConfig::m_status))
->Property("StatusReason", BehaviorValueProperty(&AzFramework::SessionConfig::m_statusReason))
->Property("TerminationTime", BehaviorValueProperty(&AzFramework::SessionConfig::m_terminationTime))
;
behaviorContext->Class<AzFramework::SearchSessionsResponse>("SearchSessionsResponse")
->Attribute(AZ::Script::Attributes::Category, "Session")
->Attribute(AZ::Script::Attributes::Storage, AZ::Script::Attributes::StorageType::Value)
->Property("NextToken", BehaviorValueProperty(&AzFramework::SearchSessionsResponse::m_nextToken))
->Property("SessionConfigs", BehaviorValueProperty(&AzFramework::SearchSessionsResponse::m_sessionConfigs))
;
}
}
void AWSGameLiftClientSystemComponent::SetGameLiftClientManager(AZStd::unique_ptr<AWSGameLiftClientManager> gameliftClientManager)
{
m_gameliftClientManager.reset();
m_gameliftClientManager = AZStd::move(gameliftClientManager);
}
} // namespace AWSGameLift

@ -0,0 +1,56 @@
/*
* 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>
#include <AzCore/std/smart_ptr/unique_ptr.h>
namespace AWSGameLift
{
class AWSGameLiftClientManager;
//! Gem client system component. Responsible for creating the gamelift client manager.
class AWSGameLiftClientSystemComponent
: public AZ::Component
{
public:
AZ_COMPONENT(AWSGameLiftClientSystemComponent, "{d481c15c-732a-4eea-9853-4965ed1bc2be}");
AWSGameLiftClientSystemComponent();
virtual ~AWSGameLiftClientSystemComponent() = default;
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 SetGameLiftClientManager(AZStd::unique_ptr<AWSGameLiftClientManager> gameliftClientManager);
private:
static void ReflectCreateSessionRequest(AZ::ReflectContext* context);
static void ReflectSearchSessionsResponse(AZ::ReflectContext* context);
AZStd::unique_ptr<AWSGameLiftClientManager> m_gameliftClientManager;
};
} // namespace AWSGameLift

@ -0,0 +1,90 @@
/*
* 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 <Activity/AWSGameLiftCreateSessionActivity.h>
#include <AWSGameLiftSessionConstants.h>
namespace AWSGameLift
{
namespace CreateSessionActivity
{
Aws::GameLift::Model::CreateGameSessionRequest BuildAWSGameLiftCreateGameSessionRequest(
const AWSGameLiftCreateSessionRequest& createSessionRequest)
{
Aws::GameLift::Model::CreateGameSessionRequest request;
// Optional attributes
if (!createSessionRequest.m_creatorId.empty())
{
request.SetCreatorId(createSessionRequest.m_creatorId.c_str());
}
if (!createSessionRequest.m_sessionName.empty())
{
request.SetName(createSessionRequest.m_sessionName.c_str());
}
if (!createSessionRequest.m_idempotencyToken.empty())
{
request.SetIdempotencyToken(createSessionRequest.m_idempotencyToken.c_str());
}
for (auto iter = createSessionRequest.m_sessionProperties.begin();
iter != createSessionRequest.m_sessionProperties.end(); iter++)
{
Aws::GameLift::Model::GameProperty sessionProperty;
sessionProperty.SetKey(iter->first.c_str());
sessionProperty.SetValue(iter->second.c_str());
request.AddGameProperties(sessionProperty);
}
// Required attributes
if (!createSessionRequest.m_aliasId.empty())
{
request.SetAliasId(createSessionRequest.m_aliasId.c_str());
}
if (!createSessionRequest.m_fleetId.empty())
{
request.SetFleetId(createSessionRequest.m_fleetId.c_str());
}
request.SetMaximumPlayerSessionCount(createSessionRequest.m_maxPlayer);
return request;
}
AZStd::string CreateSession(
const Aws::GameLift::GameLiftClient& gameliftClient,
const AWSGameLiftCreateSessionRequest& createSessionRequest)
{
AZ_TracePrintf(AWSGameLiftCreateSessionActivityName, "Requesting CreateGameSession against Amazon GameLift service ...");
AZStd::string result = "";
Aws::GameLift::Model::CreateGameSessionRequest request = BuildAWSGameLiftCreateGameSessionRequest(createSessionRequest);
auto createSessionOutcome = gameliftClient.CreateGameSession(request);
if (createSessionOutcome.IsSuccess())
{
result = AZStd::string(createSessionOutcome.GetResult().GetGameSession().GetGameSessionId().c_str());
}
else
{
AZ_Error(AWSGameLiftCreateSessionActivityName, false, AWSGameLiftErrorMessageTemplate,
createSessionOutcome.GetError().GetExceptionName().c_str(), createSessionOutcome.GetError().GetMessage().c_str());
}
return result;
}
bool ValidateCreateSessionRequest(const AzFramework::CreateSessionRequest& createSessionRequest)
{
auto gameliftCreateSessionRequest = azrtti_cast<const AWSGameLiftCreateSessionRequest*>(&createSessionRequest);
return gameliftCreateSessionRequest && gameliftCreateSessionRequest->m_maxPlayer >= 0 &&
(!gameliftCreateSessionRequest->m_aliasId.empty() || !gameliftCreateSessionRequest->m_fleetId.empty());
}
} // namespace CreateSessionActivity
} // namespace AWSGameLift

@ -0,0 +1,39 @@
/*
* 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 <Request/AWSGameLiftCreateSessionRequest.h>
#include <aws/core/utils/Outcome.h>
#include <aws/gamelift/GameLiftClient.h>
#include <aws/gamelift/model/CreateGameSessionRequest.h>
namespace AWSGameLift
{
namespace CreateSessionActivity
{
static constexpr const char AWSGameLiftCreateSessionActivityName[] = "AWSGameLiftCreateSessionActivity";
// Build AWS GameLift CreateGameSessionRequest by using AWSGameLiftCreateSessionRequest
Aws::GameLift::Model::CreateGameSessionRequest BuildAWSGameLiftCreateGameSessionRequest(const AWSGameLiftCreateSessionRequest& createSessionRequest);
// Create CreateGameSessionRequest and make a CreateGameSession call through GameLift client
AZStd::string CreateSession(
const Aws::GameLift::GameLiftClient& gameliftClient,
const AWSGameLiftCreateSessionRequest& createSessionRequest);
// Validate CreateSessionRequest and check required request parameters
bool ValidateCreateSessionRequest(const AzFramework::CreateSessionRequest& createSessionRequest);
} // namespace CreateSessionActivity
} // namespace AWSGameLift

@ -0,0 +1,80 @@
/*
* 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 <AWSGameLiftSessionConstants.h>
#include <Activity/AWSGameLiftCreateSessionOnQueueActivity.h>
namespace AWSGameLift
{
namespace CreateSessionOnQueueActivity
{
Aws::GameLift::Model::StartGameSessionPlacementRequest BuildAWSGameLiftStartGameSessionPlacementRequest(
const AWSGameLiftCreateSessionOnQueueRequest& createSessionOnQueueRequest)
{
Aws::GameLift::Model::StartGameSessionPlacementRequest request;
// Optional attributes
if (!createSessionOnQueueRequest.m_sessionName.empty())
{
request.SetGameSessionName(createSessionOnQueueRequest.m_sessionName.c_str());
}
for (auto iter = createSessionOnQueueRequest.m_sessionProperties.begin();
iter != createSessionOnQueueRequest.m_sessionProperties.end(); iter++)
{
Aws::GameLift::Model::GameProperty sessionProperty;
sessionProperty.SetKey(iter->first.c_str());
sessionProperty.SetValue(iter->second.c_str());
request.AddGameProperties(sessionProperty);
}
// Required attributes
request.SetGameSessionQueueName(createSessionOnQueueRequest.m_queueName.c_str());
request.SetMaximumPlayerSessionCount(createSessionOnQueueRequest.m_maxPlayer);
request.SetPlacementId(createSessionOnQueueRequest.m_placementId.c_str());
return request;
}
AZStd::string CreateSessionOnQueue(
const Aws::GameLift::GameLiftClient& gameliftClient,
const AWSGameLiftCreateSessionOnQueueRequest& createSessionOnQueueRequest)
{
AZ_TracePrintf(AWSGameLiftCreateSessionOnQueueActivityName,
"Requesting StartGameSessionPlacement against Amazon GameLift service ...");
AZStd::string result = "";
Aws::GameLift::Model::StartGameSessionPlacementRequest request =
BuildAWSGameLiftStartGameSessionPlacementRequest(createSessionOnQueueRequest);
auto createSessionOnQueueOutcome = gameliftClient.StartGameSessionPlacement(request);
if (createSessionOnQueueOutcome.IsSuccess())
{
result = AZStd::string(createSessionOnQueueOutcome.GetResult().GetGameSessionPlacement().GetPlacementId().c_str());
}
else
{
AZ_Error(AWSGameLiftCreateSessionOnQueueActivityName, false, AWSGameLiftErrorMessageTemplate,
createSessionOnQueueOutcome.GetError().GetExceptionName().c_str(),
createSessionOnQueueOutcome.GetError().GetMessage().c_str());
}
return result;
}
bool ValidateCreateSessionOnQueueRequest(const AzFramework::CreateSessionRequest& createSessionRequest)
{
auto gameliftCreateSessionOnQueueRequest =
azrtti_cast<const AWSGameLiftCreateSessionOnQueueRequest*>(&createSessionRequest);
return gameliftCreateSessionOnQueueRequest && gameliftCreateSessionOnQueueRequest->m_maxPlayer >= 0 &&
!gameliftCreateSessionOnQueueRequest->m_queueName.empty() && !gameliftCreateSessionOnQueueRequest->m_placementId.empty();
}
} // namespace CreateSessionOnQueueActivity
} // namespace AWSGameLift

@ -0,0 +1,40 @@
/*
* 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 <Request/AWSGameLiftCreateSessionOnQueueRequest.h>
#include <aws/core/utils/Outcome.h>
#include <aws/gamelift/GameLiftClient.h>
#include <aws/gamelift/model/StartGameSessionPlacementRequest.h>
namespace AWSGameLift
{
namespace CreateSessionOnQueueActivity
{
static constexpr const char AWSGameLiftCreateSessionOnQueueActivityName[] = "AWSGameLiftCreateSessionOnQueueActivity";
// Build AWS GameLift StartGameSessionPlacementRequest by using AWSGameLiftCreateSessionOnQueueRequest
Aws::GameLift::Model::StartGameSessionPlacementRequest BuildAWSGameLiftStartGameSessionPlacementRequest(
const AWSGameLiftCreateSessionOnQueueRequest& createSessionOnQueueRequest);
// Create StartGameSessionPlacementRequest and make a CreateGameSession call through GameLift client
AZStd::string CreateSessionOnQueue(
const Aws::GameLift::GameLiftClient& gameliftClient,
const AWSGameLiftCreateSessionOnQueueRequest& createSessionOnQueueRequest);
// Validate CreateSessionOnQueueRequest and check required request parameters
bool ValidateCreateSessionOnQueueRequest(const AzFramework::CreateSessionRequest& createSessionRequest);
} // namespace CreateSessionOnQueueActivity
} // namespace AWSGameLift

@ -0,0 +1,112 @@
/*
* 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/Interface/Interface.h>
#include <AzFramework/Session/ISessionHandlingRequests.h>
#include <Activity/AWSGameLiftJoinSessionActivity.h>
#include <AWSGameLiftSessionConstants.h>
namespace AWSGameLift
{
namespace JoinSessionActivity
{
Aws::GameLift::Model::CreatePlayerSessionRequest BuildAWSGameLiftCreatePlayerSessionRequest(
const AWSGameLiftJoinSessionRequest& joinSessionRequest)
{
Aws::GameLift::Model::CreatePlayerSessionRequest request;
// Optional attributes
if (!joinSessionRequest.m_playerData.empty())
{
request.SetPlayerData(joinSessionRequest.m_playerData.c_str());
}
// Required attributes
request.SetPlayerId(joinSessionRequest.m_playerId.c_str());
request.SetGameSessionId(joinSessionRequest.m_sessionId.c_str());
return request;
}
AzFramework::SessionConnectionConfig BuildSessionConnectionConfig(
const Aws::GameLift::Model::CreatePlayerSessionOutcome& createPlayerSessionOutcome)
{
AzFramework::SessionConnectionConfig sessionConnectionConfig;
auto createPlayerSessionResult = createPlayerSessionOutcome.GetResult();
// TODO: AWSNativeSDK needs to be updated to support this attribute, and it is a must have for TLS certificate enabled fleet
//sessionConnectionConfig.m_dnsName = createPlayerSessionResult.GetPlayerSession().GetDnsName().c_str();
sessionConnectionConfig.m_ipAddress = createPlayerSessionResult.GetPlayerSession().GetIpAddress().c_str();
sessionConnectionConfig.m_playerSessionId = createPlayerSessionResult.GetPlayerSession().GetPlayerSessionId().c_str();
sessionConnectionConfig.m_port = createPlayerSessionResult.GetPlayerSession().GetPort();
return sessionConnectionConfig;
}
Aws::GameLift::Model::CreatePlayerSessionOutcome CreatePlayerSession(
const Aws::GameLift::GameLiftClient& gameliftClient,
const AWSGameLiftJoinSessionRequest& joinSessionRequest)
{
AZ_TracePrintf(AWSGameLiftJoinSessionActivityName,
"Requesting CreatePlayerSession for player %s against Amazon GameLift service ...",
joinSessionRequest.m_playerId.c_str());
Aws::GameLift::Model::CreatePlayerSessionRequest request =
BuildAWSGameLiftCreatePlayerSessionRequest(joinSessionRequest);
auto createPlayerSessionOutcome = gameliftClient.CreatePlayerSession(request);
if (!createPlayerSessionOutcome.IsSuccess())
{
AZ_Error(AWSGameLiftJoinSessionActivityName, false, AWSGameLiftErrorMessageTemplate,
createPlayerSessionOutcome.GetError().GetExceptionName().c_str(),
createPlayerSessionOutcome.GetError().GetMessage().c_str());
}
return createPlayerSessionOutcome;
}
bool RequestPlayerJoinSession(const Aws::GameLift::Model::CreatePlayerSessionOutcome& createPlayerSessionOutcome)
{
bool result = false;
if (createPlayerSessionOutcome.IsSuccess())
{
auto clientRequestHandler = AZ::Interface<AzFramework::ISessionHandlingClientRequests>::Get();
if (clientRequestHandler)
{
AZ_TracePrintf(AWSGameLiftJoinSessionActivityName, "Requesting player to connect to game session ...");
AzFramework::SessionConnectionConfig sessionConnectionConfig =
BuildSessionConnectionConfig(createPlayerSessionOutcome);
result = clientRequestHandler->RequestPlayerJoinSession(sessionConnectionConfig);
}
else
{
AZ_Error(AWSGameLiftJoinSessionActivityName, false, AWSGameLiftJoinSessionMissingRequestHandlerErrorMessage);
}
}
return result;
}
bool ValidateJoinSessionRequest(const AzFramework::JoinSessionRequest& joinSessionRequest)
{
auto gameliftJoinSessionRequest = azrtti_cast<const AWSGameLiftJoinSessionRequest*>(&joinSessionRequest);
if (gameliftJoinSessionRequest &&
!gameliftJoinSessionRequest->m_playerId.empty() &&
!gameliftJoinSessionRequest->m_sessionId.empty())
{
return true;
}
else
{
AZ_Error(AWSGameLiftJoinSessionActivityName, false, AWSGameLiftJoinSessionRequestInvalidErrorMessage);
return false;
}
}
} // namespace JoinSessionActivity
} // namespace AWSGameLift

@ -0,0 +1,54 @@
/*
* 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 <AzFramework/Session/ISessionHandlingRequests.h>
#include <Request/AWSGameLiftJoinSessionRequest.h>
#include <aws/core/utils/Outcome.h>
#include <aws/gamelift/GameLiftClient.h>
#include <aws/gamelift/model/CreatePlayerSessionRequest.h>
namespace AWSGameLift
{
namespace JoinSessionActivity
{
static constexpr const char AWSGameLiftJoinSessionActivityName[] = "AWSGameLiftJoinSessionActivity";
static constexpr const char AWSGameLiftJoinSessionRequestInvalidErrorMessage[] =
"Invalid GameLift JoinSession request.";
static constexpr const char AWSGameLiftJoinSessionMissingRequestHandlerErrorMessage[] =
"Missing GameLift JoinSession request handler, please make sure Multiplayer Gem is enabled and registered as handler.";
// Build AWS GameLift CreatePlayerSessionRequest by using AWSGameLiftJoinSessionRequest
Aws::GameLift::Model::CreatePlayerSessionRequest BuildAWSGameLiftCreatePlayerSessionRequest(
const AWSGameLiftJoinSessionRequest& joinSessionRequest);
// Build session connection config by using CreatePlayerSessionOutcome
AzFramework::SessionConnectionConfig BuildSessionConnectionConfig(
const Aws::GameLift::Model::CreatePlayerSessionOutcome& createPlayerSessionOutcome);
// Create CreatePlayerSessionRequest and make a CreatePlayerSession call through GameLift client
Aws::GameLift::Model::CreatePlayerSessionOutcome CreatePlayerSession(
const Aws::GameLift::GameLiftClient& gameliftClient,
const AWSGameLiftJoinSessionRequest& joinSessionRequest);
// Request to setup networking connection for player
bool RequestPlayerJoinSession(
const Aws::GameLift::Model::CreatePlayerSessionOutcome& createPlayerSessionOutcome);
// Validate JoinSessionRequest and check required request parameters
bool ValidateJoinSessionRequest(const AzFramework::JoinSessionRequest& joinSessionRequest);
} // namespace JoinSessionActivity
} // namespace AWSGameLift

@ -0,0 +1,38 @@
/*
* 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 <Activity/AWSGameLiftLeaveSessionActivity.h>
#include <AzCore/Interface/Interface.h>
#include <AzFramework/Session/ISessionHandlingRequests.h>
namespace AWSGameLift
{
namespace LeaveSessionActivity
{
void LeaveSession()
{
auto clientRequestHandler = AZ::Interface<AzFramework::ISessionHandlingClientRequests>::Get();
if (clientRequestHandler)
{
AZ_TracePrintf(AWSGameLiftLeaveSessionActivityName, "Requesting to leave the current session...");
clientRequestHandler->RequestPlayerLeaveSession();
}
else
{
AZ_Error(AWSGameLiftLeaveSessionActivityName, false, AWSGameLiftLeaveSessionMissingRequestHandlerErrorMessage);
}
}
} // namespace LeaveSessionActivity
} // namespace AWSGameLift

@ -0,0 +1,27 @@
/*
* 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
namespace AWSGameLift
{
namespace LeaveSessionActivity
{
static constexpr const char AWSGameLiftLeaveSessionActivityName[] = "AWSGameLiftLeaveSessionActivity";
static constexpr const char AWSGameLiftLeaveSessionMissingRequestHandlerErrorMessage[] =
"Missing GameLift LeaveSession request handler, please make sure Multiplayer Gem is enabled and registered as handler.";
// Request to leave the current session
void LeaveSession();
} // namespace LeaveSessionActivity
} // namespace AWSGameLift

@ -0,0 +1,130 @@
/*
* 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 <AzFramework/Session/SessionConfig.h>
#include <Activity/AWSGameLiftSearchSessionsActivity.h>
#include <AWSGameLiftSessionConstants.h>
namespace AWSGameLift
{
namespace SearchSessionsActivity
{
Aws::GameLift::Model::SearchGameSessionsRequest BuildAWSGameLiftSearchGameSessionsRequest(
const AWSGameLiftSearchSessionsRequest& searchSessionsRequest)
{
Aws::GameLift::Model::SearchGameSessionsRequest request;
// Optional attributes
if (!searchSessionsRequest.m_filterExpression.empty())
{
request.SetFilterExpression(searchSessionsRequest.m_filterExpression.c_str());
}
if (!searchSessionsRequest.m_sortExpression.empty())
{
request.SetSortExpression(searchSessionsRequest.m_sortExpression.c_str());
}
if (searchSessionsRequest.m_maxResult > 0)
{
request.SetLimit(searchSessionsRequest.m_maxResult);
}
if (!searchSessionsRequest.m_nextToken.empty())
{
request.SetNextToken(searchSessionsRequest.m_nextToken.c_str());
}
// Required attributes
if (!searchSessionsRequest.m_aliasId.empty())
{
request.SetAliasId(searchSessionsRequest.m_aliasId.c_str());
}
if (!searchSessionsRequest.m_fleetId.empty())
{
request.SetFleetId(searchSessionsRequest.m_fleetId.c_str());
}
// TODO: Update the AWS Native SDK to accept the new request parameter.
//request.SetLocation(searchSessionsRequest.m_location.c_str());
return request;
}
AzFramework::SearchSessionsResponse SearchSessions(
const Aws::GameLift::GameLiftClient& gameliftClient,
const AWSGameLiftSearchSessionsRequest& searchSessionsRequest)
{
AZ_TracePrintf(AWSGameLiftSearchSessionsActivityName, "Requesting SearchGameSessions against Amazon GameLift service ...");
AzFramework::SearchSessionsResponse response;
Aws::GameLift::Model::SearchGameSessionsRequest request = BuildAWSGameLiftSearchGameSessionsRequest(searchSessionsRequest);
Aws::GameLift::Model::SearchGameSessionsOutcome outcome = gameliftClient.SearchGameSessions(request);
if (outcome.IsSuccess())
{
response = SearchSessionsActivity::ParseResponse(outcome.GetResult());
}
else
{
AZ_Error(AWSGameLiftSearchSessionsActivityName, false, AWSGameLiftErrorMessageTemplate,
outcome.GetError().GetExceptionName().c_str(), outcome.GetError().GetMessage().c_str());
}
return response;
}
AzFramework::SearchSessionsResponse ParseResponse(
const Aws::GameLift::Model::SearchGameSessionsResult& gameLiftSearchSessionsResult)
{
AzFramework::SearchSessionsResponse response;
response.m_nextToken = gameLiftSearchSessionsResult.GetNextToken().c_str();
for (const Aws::GameLift::Model::GameSession& gameSession : gameLiftSearchSessionsResult.GetGameSessions())
{
AzFramework::SessionConfig session;
session.m_creationTime = gameSession.GetCreationTime().Millis();
session.m_creatorId = gameSession.GetCreatorId().c_str();
session.m_currentPlayer = gameSession.GetCurrentPlayerSessionCount();
session.m_ipAddress = gameSession.GetIpAddress().c_str();
session.m_maxPlayer = gameSession.GetMaximumPlayerSessionCount();
session.m_port = gameSession.GetPort();
session.m_sessionId = gameSession.GetGameSessionId().c_str();
session.m_sessionName = gameSession.GetName().c_str();
session.m_status = AWSGameLiftSessionStatusNames[(int)gameSession.GetStatus()];
session.m_statusReason = AWSGameLiftSessionStatusReasons[(int)gameSession.GetStatusReason()];
session.m_terminationTime = gameSession.GetTerminationTime().Millis();
// TODO: Update the AWS Native SDK to get the new game session attributes.
//session.m_dnsName = gameSession.GetDnsName();
for (const auto& gameProperty : gameSession.GetGameProperties())
{
session.m_sessionProperties[gameProperty.GetKey().c_str()] = gameProperty.GetValue().c_str();
}
response.m_sessionConfigs.emplace_back(AZStd::move(session));
}
return response;
};
bool ValidateSearchSessionsRequest(const AzFramework::SearchSessionsRequest& searchSessionsRequest)
{
auto gameliftSearchSessionsRequest = azrtti_cast<const AWSGameLiftSearchSessionsRequest*>(&searchSessionsRequest);
if (gameliftSearchSessionsRequest &&
(!gameliftSearchSessionsRequest->m_aliasId.empty() || !gameliftSearchSessionsRequest->m_fleetId.empty()))
{
return true;
}
else
{
AZ_Error(AWSGameLiftSearchSessionsActivityName, false, AWSGameLiftSearchSessionsRequestInvalidErrorMessage);
return false;
}
}
}
} // namespace AWSGameLift

@ -0,0 +1,45 @@
/*
* 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 <Request/AWSGameLiftSearchSessionsRequest.h>
#include <aws/core/utils/Outcome.h>
#include <aws/gamelift/GameLiftClient.h>
#include <aws/gamelift/model/SearchGameSessionsRequest.h>
namespace AWSGameLift
{
namespace SearchSessionsActivity
{
static constexpr const char AWSGameLiftSearchSessionsActivityName[] = "AWSGameLiftSearchSessionsActivity";
static constexpr const char AWSGameLiftSearchSessionsRequestInvalidErrorMessage[] =
"Invalid GameLift SearchSessions request.";
// Build AWS GameLift SearchGameSessionsRequest by using AWSGameLiftSearchSessionsRequest
Aws::GameLift::Model::SearchGameSessionsRequest BuildAWSGameLiftSearchGameSessionsRequest(
const AWSGameLiftSearchSessionsRequest& searchSessionsRequest);
// Create SearchGameSessionsRequest and make a SeachGameSessions call through GameLift client
AzFramework::SearchSessionsResponse SearchSessions(
const Aws::GameLift::GameLiftClient& gameliftClient,
const AWSGameLiftSearchSessionsRequest& searchSessionsRequest);
// Convert from Aws::GameLift::Model::SearchGameSessionsResult to AzFramework::SearchSessionsResponse.
AzFramework::SearchSessionsResponse ParseResponse(
const Aws::GameLift::Model::SearchGameSessionsResult& gameLiftSearchSessionsResult);
// Validate SearchSessionsRequest and check required request parameters
bool ValidateSearchSessionsRequest(const AzFramework::SearchSessionsRequest& searchSessionsRequest);
} // namespace SearchSessionsActivity
} // namespace AWSGameLift

@ -0,0 +1,58 @@
/*
* 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/Serialization/EditContext.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <Request/AWSGameLiftCreateSessionOnQueueRequest.h>
namespace AWSGameLift
{
void AWSGameLiftCreateSessionOnQueueRequest::Reflect(AZ::ReflectContext* context)
{
if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
{
serializeContext->Class<AWSGameLiftCreateSessionOnQueueRequest, AzFramework::CreateSessionRequest>()
->Version(0)
->Field("queueName", &AWSGameLiftCreateSessionOnQueueRequest::m_queueName)
->Field("placementId", &AWSGameLiftCreateSessionOnQueueRequest::m_placementId)
;
if (AZ::EditContext* editContext = serializeContext->GetEditContext())
{
editContext->Class<AWSGameLiftCreateSessionOnQueueRequest>("AWSGameLiftCreateSessionOnQueueRequest", "")
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly)
->DataElement(
AZ::Edit::UIHandlers::Default, &AWSGameLiftCreateSessionOnQueueRequest::m_queueName, "QueueName (Required)",
"Name of the queue to use to place the new game session")
->DataElement(
AZ::Edit::UIHandlers::Default, &AWSGameLiftCreateSessionOnQueueRequest::m_placementId, "PlacementId (Required)",
"A unique identifier to assign to the new game session placement")
;
}
}
if (AZ::BehaviorContext* behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context))
{
behaviorContext->Class<AWSGameLiftCreateSessionOnQueueRequest>("AWSGameLiftCreateSessionOnQueueRequest")
->Attribute(AZ::Script::Attributes::Storage, AZ::Script::Attributes::StorageType::Value)
->Property("CreatorId", BehaviorValueProperty(&AWSGameLiftCreateSessionOnQueueRequest::m_creatorId))
->Property("SessionProperties", BehaviorValueProperty(&AWSGameLiftCreateSessionOnQueueRequest::m_sessionProperties))
->Property("SessionName", BehaviorValueProperty(&AWSGameLiftCreateSessionOnQueueRequest::m_sessionName))
->Property("MaxPlayer", BehaviorValueProperty(&AWSGameLiftCreateSessionOnQueueRequest::m_maxPlayer))
->Property("QueueName", BehaviorValueProperty(&AWSGameLiftCreateSessionOnQueueRequest::m_queueName))
->Property("PlacementId", BehaviorValueProperty(&AWSGameLiftCreateSessionOnQueueRequest::m_placementId))
;
}
}
} // namespace AWSGameLift

@ -0,0 +1,63 @@
/*
* 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/Serialization/EditContext.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <Request/AWSGameLiftCreateSessionRequest.h>
namespace AWSGameLift
{
void AWSGameLiftCreateSessionRequest::Reflect(AZ::ReflectContext* context)
{
if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
{
serializeContext->Class<AWSGameLiftCreateSessionRequest, AzFramework::CreateSessionRequest>()
->Version(0)
->Field("aliasId", &AWSGameLiftCreateSessionRequest::m_aliasId)
->Field("fleetId", &AWSGameLiftCreateSessionRequest::m_fleetId)
->Field("idempotencyToken", &AWSGameLiftCreateSessionRequest::m_idempotencyToken)
;
if (AZ::EditContext* editContext = serializeContext->GetEditContext())
{
editContext->Class<AWSGameLiftCreateSessionRequest>("AWSGameLiftCreateSessionRequest", "")
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly)
->DataElement(
AZ::Edit::UIHandlers::Default, &AWSGameLiftCreateSessionRequest::m_aliasId, "AliasId (Required, or FleetId)",
"A unique identifier for the alias associated with the fleet to create a game session in")
->DataElement(
AZ::Edit::UIHandlers::Default, &AWSGameLiftCreateSessionRequest::m_fleetId, "FleetId (Required, or AliasId)",
"A unique identifier for the fleet to create a game session in")
->DataElement(
AZ::Edit::UIHandlers::Default, &AWSGameLiftCreateSessionRequest::m_idempotencyToken, "IdempotencyToken",
"Custom string that uniquely identifies the new game session request")
;
}
}
if (AZ::BehaviorContext* behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context))
{
behaviorContext->Class<AWSGameLiftCreateSessionRequest>("AWSGameLiftCreateSessionRequest")
->Attribute(AZ::Script::Attributes::Storage, AZ::Script::Attributes::StorageType::Value)
->Property("CreatorId", BehaviorValueProperty(&AWSGameLiftCreateSessionRequest::m_creatorId))
->Property("SessionProperties", BehaviorValueProperty(&AWSGameLiftCreateSessionRequest::m_sessionProperties))
->Property("SessionName", BehaviorValueProperty(&AWSGameLiftCreateSessionRequest::m_sessionName))
->Property("MaxPlayer", BehaviorValueProperty(&AWSGameLiftCreateSessionRequest::m_maxPlayer))
->Property("AliasId", BehaviorValueProperty(&AWSGameLiftCreateSessionRequest::m_aliasId))
->Property("FleetId", BehaviorValueProperty(&AWSGameLiftCreateSessionRequest::m_fleetId))
->Property("IdempotencyToken", BehaviorValueProperty(&AWSGameLiftCreateSessionRequest::m_idempotencyToken))
;
}
}
} // namespace AWSGameLift

@ -0,0 +1,54 @@
/*
* 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/Serialization/EditContext.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <Request/AWSGameLiftJoinSessionRequest.h>
namespace AWSGameLift
{
void AWSGameLiftJoinSessionRequest::Reflect(AZ::ReflectContext* context)
{
AzFramework::JoinSessionRequest::Reflect(context);
if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
{
serializeContext->Class<AWSGameLiftJoinSessionRequest, AzFramework::JoinSessionRequest>()
->Version(0)
;
if (AZ::EditContext* editContext = serializeContext->GetEditContext())
{
editContext->Class<AWSGameLiftJoinSessionRequest>("AWSGameLiftJoinSessionRequest", "")
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly)
;
}
}
if (AZ::BehaviorContext* behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context))
{
behaviorContext->Class<AzFramework::JoinSessionRequest>("JoinSessionRequest")
->Attribute(AZ::Script::Attributes::Storage, AZ::Script::Attributes::StorageType::Value)
// Expose base type to BehaviorContext, but hide it to be used directly
->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::All)
;
behaviorContext->Class<AWSGameLiftJoinSessionRequest>("AWSGameLiftJoinSessionRequest")
->Attribute(AZ::Script::Attributes::Storage, AZ::Script::Attributes::StorageType::Value)
->Property("PlayerData", BehaviorValueProperty(&AWSGameLiftJoinSessionRequest::m_playerData))
->Property("PlayerId", BehaviorValueProperty(&AWSGameLiftJoinSessionRequest::m_playerId))
->Property("SessionId", BehaviorValueProperty(&AWSGameLiftJoinSessionRequest::m_sessionId))
;
}
}
} // namespace AWSGameLift

@ -0,0 +1,69 @@
/*
* 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/Serialization/EditContext.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzFramework/Session/SessionConfig.h>
#include <Request/AWSGameLiftSearchSessionsRequest.h>
#include <AWSGameLiftSessionConstants.h>
namespace AWSGameLift
{
void AWSGameLiftSearchSessionsRequest::Reflect(AZ::ReflectContext* context)
{
AzFramework::SearchSessionsRequest::Reflect(context);
if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
{
serializeContext->Class<AWSGameLiftSearchSessionsRequest, AzFramework::SearchSessionsRequest>()
->Version(0)
->Field("aliasId", &AWSGameLiftSearchSessionsRequest::m_aliasId)
->Field("fleetId", &AWSGameLiftSearchSessionsRequest::m_fleetId)
->Field("location", &AWSGameLiftSearchSessionsRequest::m_location);
if (AZ::EditContext* editContext = serializeContext->GetEditContext())
{
editContext->Class<AWSGameLiftSearchSessionsRequest>("AWSGameLiftSearchSessionsRequest", "")
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly)
->DataElement(
AZ::Edit::UIHandlers::Default, &AWSGameLiftSearchSessionsRequest::m_aliasId, "AliasId (Required, or FleetId)",
"A unique identifier for the alias associated with the fleet to search for active game sessions.")
->DataElement(
AZ::Edit::UIHandlers::Default, &AWSGameLiftSearchSessionsRequest::m_fleetId, "FleetId (Required, or AliasId)",
"A unique identifier for the fleet to search for active game sessions.")
->DataElement(
AZ::Edit::UIHandlers::Default, &AWSGameLiftSearchSessionsRequest::m_location, "Location",
"A fleet location to search for game sessions.");
}
}
if (AZ::BehaviorContext* behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context))
{
behaviorContext->Class<AzFramework::SearchSessionsRequest>("SearchSessionsRequest")
->Attribute(AZ::Script::Attributes::Storage, AZ::Script::Attributes::StorageType::Value)
// Expose base type to BehaviorContext, but hide it to be used directly
->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::All);
behaviorContext->Class<AWSGameLiftSearchSessionsRequest>("AWSGameLiftSearchSessionsRequest")
->Attribute(AZ::Script::Attributes::Storage, AZ::Script::Attributes::StorageType::Value)
->Property("FilterExpression", BehaviorValueProperty(&AWSGameLiftSearchSessionsRequest::m_filterExpression))
->Property("SortExpression", BehaviorValueProperty(&AWSGameLiftSearchSessionsRequest::m_sortExpression))
->Property("MaxResult", BehaviorValueProperty(&AWSGameLiftSearchSessionsRequest::m_maxResult))
->Property("NextToken", BehaviorValueProperty(&AWSGameLiftSearchSessionsRequest::m_nextToken))
->Property("AliasId", BehaviorValueProperty(&AWSGameLiftSearchSessionsRequest::m_aliasId))
->Property("FleetId", BehaviorValueProperty(&AWSGameLiftSearchSessionsRequest::m_fleetId))
->Property("Location", BehaviorValueProperty(&AWSGameLiftSearchSessionsRequest::m_location));
}
}
} // namespace AWSGameLift

@ -0,0 +1,63 @@
/*
* 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 <AWSNativeSDKInit/AWSNativeSDKInit.h>
#include <AzCore/Jobs/JobManager.h>
#include <AzCore/Jobs/JobManagerBus.h>
#include <AzCore/Jobs/JobContext.h>
#include <AzCore/Memory/PoolAllocator.h>
#include <AzCore/UnitTest/TestTypes.h>
class AWSGameLiftClientFixture
: public UnitTest::ScopedAllocatorSetupFixture
{
public:
AWSGameLiftClientFixture() {}
virtual ~AWSGameLiftClientFixture() = default;
void SetUp() override
{
AZ::AllocatorInstance<AZ::ThreadPoolAllocator>::Create();
AZ::AllocatorInstance<AZ::PoolAllocator>::Create();
AZ::JobManagerDesc jobManagerDesc;
AZ::JobManagerThreadDesc threadDesc;
m_jobManager.reset(aznew AZ::JobManager(jobManagerDesc));
m_jobCancelGroup.reset(aznew AZ::JobCancelGroup());
jobManagerDesc.m_workerThreads.push_back(threadDesc);
jobManagerDesc.m_workerThreads.push_back(threadDesc);
jobManagerDesc.m_workerThreads.push_back(threadDesc);
m_jobContext.reset(aznew AZ::JobContext(*m_jobManager, *m_jobCancelGroup));
AZ::JobContext::SetGlobalContext(m_jobContext.get());
AWSNativeSDKInit::InitializationManager::InitAwsApi();
}
void TearDown() override
{
AWSNativeSDKInit::InitializationManager::Shutdown();
AZ::JobContext::SetGlobalContext(nullptr);
m_jobContext.reset();
m_jobCancelGroup.reset();
m_jobManager.reset();
AZ::AllocatorInstance<AZ::PoolAllocator>::Destroy();
AZ::AllocatorInstance<AZ::ThreadPoolAllocator>::Destroy();
}
AZStd::unique_ptr<AZ::JobContext> m_jobContext;
AZStd::unique_ptr<AZ::JobCancelGroup> m_jobCancelGroup;
AZStd::unique_ptr<AZ::JobManager> m_jobManager;
};

@ -0,0 +1,773 @@
/*
* 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/Component/ComponentApplication.h>
#include <AzCore/Serialization/EditContext.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/std/smart_ptr/make_shared.h>
#include <AzFramework/Session/SessionConfig.h>
#include <Credential/AWSCredentialBus.h>
#include <ResourceMapping/AWSResourceMappingBus.h>
#include <AWSCoreBus.h>
#include <AWSGameLiftClientFixture.h>
#include <AWSGameLiftClientManager.h>
#include <AWSGameLiftClientMocks.h>
#include <Request/AWSGameLiftCreateSessionOnQueueRequest.h>
#include <Request/AWSGameLiftCreateSessionRequest.h>
#include <Request/AWSGameLiftJoinSessionRequest.h>
#include <Request/AWSGameLiftSearchSessionsRequest.h>
#include <aws/gamelift/GameLiftClient.h>
using namespace AWSGameLift;
MATCHER_P(SearchSessionsResponseMatcher, expectedResponse, "")
{
// Custome matcher for checking the SearchSessionsResponse type argument.
AZ_UNUSED(result_listener);
bool result = arg.m_nextToken == expectedResponse.m_nextToken;
result &= arg.m_sessionConfigs.size() == expectedResponse.m_sessionConfigs.size();
for (int index = 0; index < arg.m_sessionConfigs.size(); ++index)
{
result &= arg.m_sessionConfigs[index].m_creationTime == expectedResponse.m_sessionConfigs[index].m_creationTime;
result &= arg.m_sessionConfigs[index].m_terminationTime == expectedResponse.m_sessionConfigs[index].m_terminationTime;
result &= arg.m_sessionConfigs[index].m_creatorId == expectedResponse.m_sessionConfigs[index].m_creatorId;
result &= arg.m_sessionConfigs[index].m_sessionProperties == expectedResponse.m_sessionConfigs[index].m_sessionProperties;
result &= arg.m_sessionConfigs[index].m_sessionId == expectedResponse.m_sessionConfigs[index].m_sessionId;
result &= arg.m_sessionConfigs[index].m_sessionName == expectedResponse.m_sessionConfigs[index].m_sessionName;
result &= arg.m_sessionConfigs[index].m_dnsName == expectedResponse.m_sessionConfigs[index].m_dnsName;
result &= arg.m_sessionConfigs[index].m_ipAddress == expectedResponse.m_sessionConfigs[index].m_ipAddress;
result &= arg.m_sessionConfigs[index].m_port == expectedResponse.m_sessionConfigs[index].m_port;
result &= arg.m_sessionConfigs[index].m_maxPlayer == expectedResponse.m_sessionConfigs[index].m_maxPlayer;
result &= arg.m_sessionConfigs[index].m_currentPlayer == expectedResponse.m_sessionConfigs[index].m_currentPlayer;
result &= arg.m_sessionConfigs[index].m_status == expectedResponse.m_sessionConfigs[index].m_status;
result &= arg.m_sessionConfigs[index].m_statusReason == expectedResponse.m_sessionConfigs[index].m_statusReason;
}
return result;
}
class AWSResourceMappingRequestsHandlerMock
: public AWSCore::AWSResourceMappingRequestBus::Handler
{
public:
AWSResourceMappingRequestsHandlerMock()
{
AWSCore::AWSResourceMappingRequestBus::Handler::BusConnect();
}
~ AWSResourceMappingRequestsHandlerMock()
{
AWSCore::AWSResourceMappingRequestBus::Handler::BusDisconnect();
}
MOCK_CONST_METHOD0(GetDefaultRegion, AZStd::string());
MOCK_CONST_METHOD0(GetDefaultAccountId, AZStd::string());
MOCK_CONST_METHOD1(GetResourceAccountId, AZStd::string(const AZStd::string&));
MOCK_CONST_METHOD1(GetResourceNameId, AZStd::string(const AZStd::string&));
MOCK_CONST_METHOD1(GetResourceRegion, AZStd::string(const AZStd::string&));
MOCK_CONST_METHOD1(GetResourceType, AZStd::string(const AZStd::string&));
MOCK_CONST_METHOD1(GetServiceUrlByServiceName, AZStd::string(const AZStd::string&));
MOCK_CONST_METHOD2(GetServiceUrlByRESTApiIdAndStage, AZStd::string(const AZStd::string&, const AZStd::string&));
MOCK_METHOD1(ReloadConfigFile, void(bool));
};
class AWSCredentialRequestsHandlerMock
: public AWSCore::AWSCredentialRequestBus::Handler
{
public:
AWSCredentialRequestsHandlerMock()
{
AWSCore::AWSCredentialRequestBus::Handler::BusConnect();
}
~AWSCredentialRequestsHandlerMock()
{
AWSCore::AWSCredentialRequestBus::Handler::BusDisconnect();
}
MOCK_CONST_METHOD0(GetCredentialHandlerOrder, int());
MOCK_METHOD0(GetCredentialsProvider, std::shared_ptr<Aws::Auth::AWSCredentialsProvider>());
};
class AWSCoreRequestsHandlerMock
: public AWSCore::AWSCoreRequestBus::Handler
{
public:
AWSCoreRequestsHandlerMock()
{
AWSCore::AWSCoreRequestBus::Handler::BusConnect();
}
~AWSCoreRequestsHandlerMock()
{
AWSCore::AWSCoreRequestBus::Handler::BusDisconnect();
}
MOCK_METHOD0(GetDefaultJobContext, AZ::JobContext*());
MOCK_METHOD0(GetDefaultConfig, AWSCore::AwsApiJobConfig*());
};
class TestAWSGameLiftClientManager
: public AWSGameLiftClientManager
{
public:
TestAWSGameLiftClientManager()
{
m_gameliftClientMockPtr = nullptr;
}
~TestAWSGameLiftClientManager()
{
m_gameliftClientMockPtr = nullptr;
}
void SetUpMockClient()
{
m_gameliftClientMockPtr = AZStd::make_shared<GameLiftClientMock>();
SetGameLiftClient(m_gameliftClientMockPtr);
}
AZStd::shared_ptr<GameLiftClientMock> m_gameliftClientMockPtr;
};
class AWSGameLiftClientManagerTest
: public AWSGameLiftClientFixture
{
protected:
void SetUp() override
{
AWSGameLiftClientFixture::SetUp();
m_gameliftClientManager = AZStd::make_unique<TestAWSGameLiftClientManager>();
m_gameliftClientManager->SetUpMockClient();
m_gameliftClientManager->ActivateManager();
}
void TearDown() override
{
m_gameliftClientManager->DeactivateManager();
m_gameliftClientManager.reset();
AWSGameLiftClientFixture::TearDown();
}
AWSGameLiftSearchSessionsRequest GetValidSearchSessionsRequest()
{
AWSGameLiftSearchSessionsRequest request;
request.m_aliasId = "dummyAliasId";
request.m_fleetId = "dummyFleetId";
request.m_location = "dummyLocation";
request.m_filterExpression = "dummyFilterExpression";
request.m_sortExpression = "dummySortExpression";
request.m_maxResult = 1;
request.m_nextToken = "dummyNextToken";
return request;
}
Aws::GameLift::Model::SearchGameSessionsOutcome GetValidSearchGameSessionsOutcome()
{
Aws::GameLift::Model::GameProperty gameProperty;
gameProperty.SetKey("dummyKey");
gameProperty.SetValue("dummyValue");
Aws::Vector<Aws::GameLift::Model::GameProperty> gameProperties = { gameProperty };
Aws::GameLift::Model::GameSession gameSession;
gameSession.SetCreationTime(Aws::Utils::DateTime(0.0));
gameSession.SetTerminationTime(Aws::Utils::DateTime(0.0));
gameSession.SetCreatorId("dummyCreatorId");
gameSession.SetGameProperties(gameProperties);
gameSession.SetGameSessionId("dummyGameSessionId");
gameSession.SetName("dummyGameSessionName");
gameSession.SetIpAddress("dummyIpAddress");
gameSession.SetPort(0);
gameSession.SetMaximumPlayerSessionCount(2);
gameSession.SetCurrentPlayerSessionCount(1);
gameSession.SetStatus(Aws::GameLift::Model::GameSessionStatus::TERMINATED);
gameSession.SetStatusReason(Aws::GameLift::Model::GameSessionStatusReason::INTERRUPTED);
// TODO: Update the AWS Native SDK to set the new game session attributes.
// gameSession.SetDnsName("dummyDnsName");
Aws::GameLift::Model::SearchGameSessionsResult result;
result.SetNextToken("dummyNextToken");
result.SetGameSessions({ gameSession });
return Aws::GameLift::Model::SearchGameSessionsOutcome(result);
}
AzFramework::SearchSessionsResponse GetValidSearchSessionsResponse()
{
AzFramework::SessionConfig sessionConfig;
sessionConfig.m_creationTime = 0;
sessionConfig.m_terminationTime = 0;
sessionConfig.m_creatorId = "dummyCreatorId";
sessionConfig.m_sessionProperties["dummyKey"] = "dummyValue";
sessionConfig.m_sessionId = "dummyGameSessionId";
sessionConfig.m_sessionName = "dummyGameSessionName";
sessionConfig.m_ipAddress = "dummyIpAddress";
sessionConfig.m_port = 0;
sessionConfig.m_maxPlayer = 2;
sessionConfig.m_currentPlayer = 1;
sessionConfig.m_status = "Terminated";
sessionConfig.m_statusReason = "Interrupted";
// TODO: Update the AWS Native SDK to set the new game session attributes.
// sessionConfig.m_dnsName = "dummyDnsName";
AzFramework::SearchSessionsResponse response;
response.m_nextToken = "dummyNextToken";
response.m_sessionConfigs = { sessionConfig };
return response;
}
public:
AZStd::unique_ptr<TestAWSGameLiftClientManager> m_gameliftClientManager;
};
TEST_F(AWSGameLiftClientManagerTest, ConfigureGameLiftClient_CallWithoutRegion_GetFalseAsResult)
{
AZ_TEST_START_TRACE_SUPPRESSION;
auto result = m_gameliftClientManager->ConfigureGameLiftClient("");
AZ_TEST_STOP_TRACE_SUPPRESSION(1); // capture 1 error message
EXPECT_FALSE(result);
}
TEST_F(AWSGameLiftClientManagerTest, ConfigureGameLiftClient_CallWithoutCredential_GetFalseAsResult)
{
AWSResourceMappingRequestsHandlerMock handlerMock;
EXPECT_CALL(handlerMock, GetDefaultRegion()).Times(1).WillOnce(::testing::Return("us-west-2"));
AZ_TEST_START_TRACE_SUPPRESSION;
auto result = m_gameliftClientManager->ConfigureGameLiftClient("");
AZ_TEST_STOP_TRACE_SUPPRESSION(1); // capture 1 error message
EXPECT_FALSE(result);
}
TEST_F(AWSGameLiftClientManagerTest, ConfigureGameLiftClient_CallWithRegionAndCredential_GetTrueAsResult)
{
AWSCredentialRequestsHandlerMock handlerMock;
EXPECT_CALL(handlerMock, GetCredentialsProvider())
.Times(1)
.WillOnce(::testing::Return(std::make_shared<Aws::Auth::SimpleAWSCredentialsProvider>("dummyAccess", "dummySecret", "")));
auto result = m_gameliftClientManager->ConfigureGameLiftClient("us-west-2");
EXPECT_TRUE(result);
}
TEST_F(AWSGameLiftClientManagerTest, CreatePlayerId_CreateWithoutBracketsOrDashes_GetExpectedResult)
{
auto result = m_gameliftClientManager->CreatePlayerId(false, false);
EXPECT_FALSE(result.starts_with("{"));
EXPECT_FALSE(result.ends_with("}"));
EXPECT_FALSE(result.contains("-"));
}
TEST_F(AWSGameLiftClientManagerTest, CreatePlayerId_CreateWithBrackets_GetExpectedResult)
{
auto result = m_gameliftClientManager->CreatePlayerId(true, false);
EXPECT_TRUE(result.starts_with("{"));
EXPECT_TRUE(result.ends_with("}"));
EXPECT_FALSE(result.contains("-"));
}
TEST_F(AWSGameLiftClientManagerTest, CreatePlayerId_CreateWithDashes_GetExpectedResult)
{
auto result = m_gameliftClientManager->CreatePlayerId(false, true);
EXPECT_FALSE(result.starts_with("{"));
EXPECT_FALSE(result.ends_with("}"));
EXPECT_TRUE(result.contains("-"));
}
TEST_F(AWSGameLiftClientManagerTest, CreatePlayerId_CreateWithBracketsAndDashes_GetExpectedResult)
{
auto result = m_gameliftClientManager->CreatePlayerId(true, true);
EXPECT_TRUE(result.starts_with("{"));
EXPECT_TRUE(result.ends_with("}"));
EXPECT_TRUE(result.contains("-"));
}
TEST_F(AWSGameLiftClientManagerTest, CreateSession_CallWithoutClientSetup_GetEmptyResponse)
{
AZ_TEST_START_TRACE_SUPPRESSION;
m_gameliftClientManager->ConfigureGameLiftClient("");
AWSGameLiftCreateSessionRequest request;
request.m_aliasId = "dummyAlias";
auto response = m_gameliftClientManager->CreateSession(request);
AZ_TEST_STOP_TRACE_SUPPRESSION(2); // capture 2 error message
EXPECT_TRUE(response == "");
}
TEST_F(AWSGameLiftClientManagerTest, CreateSession_CallWithInvalidRequest_GetEmptyResponse)
{
AZ_TEST_START_TRACE_SUPPRESSION;
auto response = m_gameliftClientManager->CreateSession(AzFramework::CreateSessionRequest());
AZ_TEST_STOP_TRACE_SUPPRESSION(1); // capture 1 error message
EXPECT_TRUE(response == "");
}
TEST_F(AWSGameLiftClientManagerTest, CreateSession_CallWithValidRequest_GetSuccessOutcome)
{
AWSGameLiftCreateSessionRequest request;
request.m_aliasId = "dummyAlias";
Aws::GameLift::Model::CreateGameSessionResult result;
result.SetGameSession(Aws::GameLift::Model::GameSession());
Aws::GameLift::Model::CreateGameSessionOutcome outcome(result);
EXPECT_CALL(*(m_gameliftClientManager->m_gameliftClientMockPtr), CreateGameSession(::testing::_))
.Times(1)
.WillOnce(::testing::Return(outcome));
m_gameliftClientManager->CreateSession(request);
}
TEST_F(AWSGameLiftClientManagerTest, CreateSession_CallWithValidRequest_GetErrorOutcome)
{
AWSGameLiftCreateSessionRequest request;
request.m_aliasId = "dummyAlias";
Aws::Client::AWSError<Aws::GameLift::GameLiftErrors> error;
Aws::GameLift::Model::CreateGameSessionOutcome outcome(error);
EXPECT_CALL(*(m_gameliftClientManager->m_gameliftClientMockPtr), CreateGameSession(::testing::_))
.Times(1)
.WillOnce(::testing::Return(outcome));
AZ_TEST_START_TRACE_SUPPRESSION;
m_gameliftClientManager->CreateSession(request);
AZ_TEST_STOP_TRACE_SUPPRESSION(1); // capture 1 error message
}
TEST_F(AWSGameLiftClientManagerTest, CreateSessionAsync_CallWithInvalidRequest_GetNotificationWithEmptyResponse)
{
AZ_TEST_START_TRACE_SUPPRESSION;
SessionAsyncRequestNotificationsHandlerMock sessionHandlerMock;
EXPECT_CALL(sessionHandlerMock, OnCreateSessionAsyncComplete(AZStd::string())).Times(1);
m_gameliftClientManager->CreateSessionAsync(AzFramework::CreateSessionRequest());
AZ_TEST_STOP_TRACE_SUPPRESSION(1); // capture 1 error message
}
TEST_F(AWSGameLiftClientManagerTest, CreateSessionAsync_CallWithValidRequest_GetNotificationWithSuccessOutcome)
{
AWSCoreRequestsHandlerMock handlerMock;
EXPECT_CALL(handlerMock, GetDefaultJobContext()).Times(1).WillOnce(::testing::Return(m_jobContext.get()));
AWSGameLiftCreateSessionRequest request;
request.m_aliasId = "dummyAlias";
Aws::GameLift::Model::CreateGameSessionResult result;
result.SetGameSession(Aws::GameLift::Model::GameSession());
Aws::GameLift::Model::CreateGameSessionOutcome outcome(result);
EXPECT_CALL(*(m_gameliftClientManager->m_gameliftClientMockPtr), CreateGameSession(::testing::_))
.Times(1)
.WillOnce(::testing::Return(outcome));
SessionAsyncRequestNotificationsHandlerMock sessionHandlerMock;
EXPECT_CALL(sessionHandlerMock, OnCreateSessionAsyncComplete(::testing::_)).Times(1);
m_gameliftClientManager->CreateSessionAsync(request);
}
TEST_F(AWSGameLiftClientManagerTest, CreateSessionAsync_CallWithValidRequest_GetNotificationWithErrorOutcome)
{
AWSCoreRequestsHandlerMock handlerMock;
EXPECT_CALL(handlerMock, GetDefaultJobContext()).Times(1).WillOnce(::testing::Return(m_jobContext.get()));
AWSGameLiftCreateSessionRequest request;
request.m_aliasId = "dummyAlias";
Aws::Client::AWSError<Aws::GameLift::GameLiftErrors> error;
Aws::GameLift::Model::CreateGameSessionOutcome outcome(error);
EXPECT_CALL(*(m_gameliftClientManager->m_gameliftClientMockPtr), CreateGameSession(::testing::_))
.Times(1)
.WillOnce(::testing::Return(outcome));
SessionAsyncRequestNotificationsHandlerMock sessionHandlerMock;
EXPECT_CALL(sessionHandlerMock, OnCreateSessionAsyncComplete(AZStd::string(""))).Times(1);
AZ_TEST_START_TRACE_SUPPRESSION;
m_gameliftClientManager->CreateSessionAsync(request);
AZ_TEST_STOP_TRACE_SUPPRESSION(1); // capture 1 error message
}
TEST_F(AWSGameLiftClientManagerTest, CreateSessionOnQueue_CallWithoutClientSetup_GetEmptyResponse)
{
AZ_TEST_START_TRACE_SUPPRESSION;
m_gameliftClientManager->ConfigureGameLiftClient("");
AWSGameLiftCreateSessionOnQueueRequest request;
request.m_queueName = "dummyQueue";
request.m_placementId = "dummyPlacementId";
auto response = m_gameliftClientManager->CreateSession(request);
AZ_TEST_STOP_TRACE_SUPPRESSION(2); // capture 2 error message
EXPECT_TRUE(response == "");
}
TEST_F(AWSGameLiftClientManagerTest, CreateSessionOnQueue_CallWithValidRequest_GetSuccessOutcome)
{
AWSGameLiftCreateSessionOnQueueRequest request;
request.m_queueName = "dummyQueue";
request.m_placementId = "dummyPlacementId";
Aws::GameLift::Model::StartGameSessionPlacementResult result;
result.SetGameSessionPlacement(Aws::GameLift::Model::GameSessionPlacement());
Aws::GameLift::Model::StartGameSessionPlacementOutcome outcome(result);
EXPECT_CALL(*(m_gameliftClientManager->m_gameliftClientMockPtr), StartGameSessionPlacement(::testing::_))
.Times(1)
.WillOnce(::testing::Return(outcome));
m_gameliftClientManager->CreateSession(request);
}
TEST_F(AWSGameLiftClientManagerTest, CreateSessionOnQueue_CallWithValidRequest_GetErrorOutcome)
{
AWSGameLiftCreateSessionOnQueueRequest request;
request.m_queueName = "dummyQueue";
request.m_placementId = "dummyPlacementId";
Aws::Client::AWSError<Aws::GameLift::GameLiftErrors> error;
Aws::GameLift::Model::StartGameSessionPlacementOutcome outcome(error);
EXPECT_CALL(*(m_gameliftClientManager->m_gameliftClientMockPtr), StartGameSessionPlacement(::testing::_))
.Times(1)
.WillOnce(::testing::Return(outcome));
AZ_TEST_START_TRACE_SUPPRESSION;
m_gameliftClientManager->CreateSession(request);
AZ_TEST_STOP_TRACE_SUPPRESSION(1); // capture 1 error message
}
TEST_F(AWSGameLiftClientManagerTest, CreateSessionOnQueueAsync_CallWithValidRequest_GetNotificationWithSuccessOutcome)
{
AWSCoreRequestsHandlerMock handlerMock;
EXPECT_CALL(handlerMock, GetDefaultJobContext()).Times(1).WillOnce(::testing::Return(m_jobContext.get()));
AWSGameLiftCreateSessionOnQueueRequest request;
request.m_queueName = "dummyQueue";
request.m_placementId = "dummyPlacementId";
Aws::GameLift::Model::StartGameSessionPlacementResult result;
result.SetGameSessionPlacement(Aws::GameLift::Model::GameSessionPlacement());
Aws::GameLift::Model::StartGameSessionPlacementOutcome outcome(result);
EXPECT_CALL(*(m_gameliftClientManager->m_gameliftClientMockPtr), StartGameSessionPlacement(::testing::_))
.Times(1)
.WillOnce(::testing::Return(outcome));
SessionAsyncRequestNotificationsHandlerMock sessionHandlerMock;
EXPECT_CALL(sessionHandlerMock, OnCreateSessionAsyncComplete(::testing::_)).Times(1);
m_gameliftClientManager->CreateSessionAsync(request);
}
TEST_F(AWSGameLiftClientManagerTest, CreateSessionOnQueueAsync_CallWithValidRequest_GetNotificationWithErrorOutcome)
{
AWSCoreRequestsHandlerMock handlerMock;
EXPECT_CALL(handlerMock, GetDefaultJobContext()).Times(1).WillOnce(::testing::Return(m_jobContext.get()));
AWSGameLiftCreateSessionOnQueueRequest request;
request.m_queueName = "dummyQueue";
request.m_placementId = "dummyPlacementId";
Aws::Client::AWSError<Aws::GameLift::GameLiftErrors> error;
Aws::GameLift::Model::StartGameSessionPlacementOutcome outcome(error);
EXPECT_CALL(*(m_gameliftClientManager->m_gameliftClientMockPtr), StartGameSessionPlacement(::testing::_))
.Times(1)
.WillOnce(::testing::Return(outcome));
SessionAsyncRequestNotificationsHandlerMock sessionHandlerMock;
EXPECT_CALL(sessionHandlerMock, OnCreateSessionAsyncComplete(AZStd::string(""))).Times(1);
AZ_TEST_START_TRACE_SUPPRESSION;
m_gameliftClientManager->CreateSessionAsync(request);
AZ_TEST_STOP_TRACE_SUPPRESSION(1); // capture 1 error message
}
TEST_F(AWSGameLiftClientManagerTest, JoinSession_CallWithoutClientSetup_GetFalseResponse)
{
AZ_TEST_START_TRACE_SUPPRESSION;
m_gameliftClientManager->ConfigureGameLiftClient("");
AWSGameLiftJoinSessionRequest request;
request.m_playerId = "dummyPlayerId";
request.m_sessionId = "dummySessionId";
auto response = m_gameliftClientManager->JoinSession(request);
AZ_TEST_STOP_TRACE_SUPPRESSION(2); // capture 2 error message
EXPECT_FALSE(response);
}
TEST_F(AWSGameLiftClientManagerTest, JoinSession_CallWithInvalidRequest_GetFalseResponse)
{
AZ_TEST_START_TRACE_SUPPRESSION;
auto response = m_gameliftClientManager->JoinSession(AzFramework::JoinSessionRequest());
AZ_TEST_STOP_TRACE_SUPPRESSION(1); // capture 1 error message
EXPECT_FALSE(response);
}
TEST_F(AWSGameLiftClientManagerTest, JoinSession_CallWithValidRequestButNoRequestHandler_GetSuccessOutcomeButFalseResponse)
{
AWSGameLiftJoinSessionRequest request;
request.m_sessionId = "dummySessionId";
request.m_playerId = "dummyPlayerId";
Aws::GameLift::Model::CreatePlayerSessionResult result;
result.SetPlayerSession(Aws::GameLift::Model::PlayerSession());
Aws::GameLift::Model::CreatePlayerSessionOutcome outcome(result);
EXPECT_CALL(*(m_gameliftClientManager->m_gameliftClientMockPtr), CreatePlayerSession(::testing::_))
.Times(1)
.WillOnce(::testing::Return(outcome));
AZ_TEST_START_TRACE_SUPPRESSION;
auto response = m_gameliftClientManager->JoinSession(request);
AZ_TEST_STOP_TRACE_SUPPRESSION(1); // capture 1 error message
EXPECT_FALSE(response);
}
TEST_F(AWSGameLiftClientManagerTest, JoinSession_CallWithValidRequest_GetErrorOutcomeAndFalseResponse)
{
AWSGameLiftJoinSessionRequest request;
request.m_sessionId = "dummySessionId";
request.m_playerId = "dummyPlayerId";
Aws::Client::AWSError<Aws::GameLift::GameLiftErrors> error;
Aws::GameLift::Model::CreatePlayerSessionOutcome outcome(error);
EXPECT_CALL(*(m_gameliftClientManager->m_gameliftClientMockPtr), CreatePlayerSession(::testing::_))
.Times(1)
.WillOnce(::testing::Return(outcome));
AZ_TEST_START_TRACE_SUPPRESSION;
auto response = m_gameliftClientManager->JoinSession(request);
AZ_TEST_STOP_TRACE_SUPPRESSION(1); // capture 1 error message
EXPECT_FALSE(response);
}
TEST_F(AWSGameLiftClientManagerTest, JoinSession_CallWithValidRequestAndRequestHandler_GetSuccessOutcomeButFalseResponse)
{
SessionHandlingClientRequestsMock handlerMock;
EXPECT_CALL(handlerMock, RequestPlayerJoinSession(::testing::_)).Times(1).WillOnce(::testing::Return(false));
AWSGameLiftJoinSessionRequest request;
request.m_sessionId = "dummySessionId";
request.m_playerId = "dummyPlayerId";
Aws::GameLift::Model::CreatePlayerSessionResult result;
result.SetPlayerSession(Aws::GameLift::Model::PlayerSession());
Aws::GameLift::Model::CreatePlayerSessionOutcome outcome(result);
EXPECT_CALL(*(m_gameliftClientManager->m_gameliftClientMockPtr), CreatePlayerSession(::testing::_))
.Times(1)
.WillOnce(::testing::Return(outcome));
auto response = m_gameliftClientManager->JoinSession(request);
EXPECT_FALSE(response);
}
TEST_F(AWSGameLiftClientManagerTest, JoinSession_CallWithValidRequestAndRequestHandler_GetSuccessOutcomeAndTrueResponse)
{
SessionHandlingClientRequestsMock handlerMock;
EXPECT_CALL(handlerMock, RequestPlayerJoinSession(::testing::_)).Times(1).WillOnce(::testing::Return(true));
AWSGameLiftJoinSessionRequest request;
request.m_sessionId = "dummySessionId";
request.m_playerId = "dummyPlayerId";
Aws::GameLift::Model::CreatePlayerSessionResult result;
result.SetPlayerSession(Aws::GameLift::Model::PlayerSession());
Aws::GameLift::Model::CreatePlayerSessionOutcome outcome(result);
EXPECT_CALL(*(m_gameliftClientManager->m_gameliftClientMockPtr), CreatePlayerSession(::testing::_))
.Times(1)
.WillOnce(::testing::Return(outcome));
auto response = m_gameliftClientManager->JoinSession(request);
EXPECT_TRUE(response);
}
TEST_F(AWSGameLiftClientManagerTest, JoinSessionAsync_CallWithInvalidRequest_GetNotificationWithFalseResponse)
{
AZ_TEST_START_TRACE_SUPPRESSION;
SessionAsyncRequestNotificationsHandlerMock sessionHandlerMock;
EXPECT_CALL(sessionHandlerMock, OnJoinSessionAsyncComplete(false)).Times(1);
m_gameliftClientManager->JoinSessionAsync(AzFramework::JoinSessionRequest());
AZ_TEST_STOP_TRACE_SUPPRESSION(1); // capture 1 error message
}
TEST_F(AWSGameLiftClientManagerTest, JoinSessionAsync_CallWithValidRequestButNoRequestHandler_GetSuccessOutcomeButNotificationWithFalseResponse)
{
AWSCoreRequestsHandlerMock handlerMock;
EXPECT_CALL(handlerMock, GetDefaultJobContext()).Times(1).WillOnce(::testing::Return(m_jobContext.get()));
AWSGameLiftJoinSessionRequest request;
request.m_sessionId = "dummySessionId";
request.m_playerId = "dummyPlayerId";
Aws::GameLift::Model::CreatePlayerSessionResult result;
result.SetPlayerSession(Aws::GameLift::Model::PlayerSession());
Aws::GameLift::Model::CreatePlayerSessionOutcome outcome(result);
EXPECT_CALL(*(m_gameliftClientManager->m_gameliftClientMockPtr), CreatePlayerSession(::testing::_))
.Times(1)
.WillOnce(::testing::Return(outcome));
SessionAsyncRequestNotificationsHandlerMock sessionHandlerMock;
EXPECT_CALL(sessionHandlerMock, OnJoinSessionAsyncComplete(false)).Times(1);
AZ_TEST_START_TRACE_SUPPRESSION;
m_gameliftClientManager->JoinSessionAsync(request);
AZ_TEST_STOP_TRACE_SUPPRESSION(1); // capture 1 error message
}
TEST_F(AWSGameLiftClientManagerTest, JoinSessionAsync_CallWithValidRequest_GetErrorOutcomeAndNotificationWithFalseResponse)
{
AWSCoreRequestsHandlerMock handlerMock;
EXPECT_CALL(handlerMock, GetDefaultJobContext()).Times(1).WillOnce(::testing::Return(m_jobContext.get()));
AWSGameLiftJoinSessionRequest request;
request.m_sessionId = "dummySessionId";
request.m_playerId = "dummyPlayerId";
Aws::Client::AWSError<Aws::GameLift::GameLiftErrors> error;
Aws::GameLift::Model::CreatePlayerSessionOutcome outcome(error);
EXPECT_CALL(*(m_gameliftClientManager->m_gameliftClientMockPtr), CreatePlayerSession(::testing::_))
.Times(1)
.WillOnce(::testing::Return(outcome));
SessionAsyncRequestNotificationsHandlerMock sessionHandlerMock;
EXPECT_CALL(sessionHandlerMock, OnJoinSessionAsyncComplete(false)).Times(1);
AZ_TEST_START_TRACE_SUPPRESSION;
m_gameliftClientManager->JoinSessionAsync(request);
AZ_TEST_STOP_TRACE_SUPPRESSION(1); // capture 1 error message
}
TEST_F(AWSGameLiftClientManagerTest, JoinSessionAsync_CallWithValidRequestAndRequestHandler_GetSuccessOutcomeButNotificationWithFalseResponse)
{
AWSCoreRequestsHandlerMock coreHandlerMock;
EXPECT_CALL(coreHandlerMock, GetDefaultJobContext()).Times(1).WillOnce(::testing::Return(m_jobContext.get()));
SessionHandlingClientRequestsMock handlerMock;
EXPECT_CALL(handlerMock, RequestPlayerJoinSession(::testing::_)).Times(1).WillOnce(::testing::Return(false));
AWSGameLiftJoinSessionRequest request;
request.m_sessionId = "dummySessionId";
request.m_playerId = "dummyPlayerId";
Aws::GameLift::Model::CreatePlayerSessionResult result;
result.SetPlayerSession(Aws::GameLift::Model::PlayerSession());
Aws::GameLift::Model::CreatePlayerSessionOutcome outcome(result);
EXPECT_CALL(*(m_gameliftClientManager->m_gameliftClientMockPtr), CreatePlayerSession(::testing::_))
.Times(1)
.WillOnce(::testing::Return(outcome));
SessionAsyncRequestNotificationsHandlerMock sessionHandlerMock;
EXPECT_CALL(sessionHandlerMock, OnJoinSessionAsyncComplete(false)).Times(1);
m_gameliftClientManager->JoinSessionAsync(request);
}
TEST_F(AWSGameLiftClientManagerTest, JoinSessionAsync_CallWithValidRequestAndRequestHandler_GetSuccessOutcomeAndNotificationWithTrueResponse)
{
AWSCoreRequestsHandlerMock coreHandlerMock;
EXPECT_CALL(coreHandlerMock, GetDefaultJobContext()).Times(1).WillOnce(::testing::Return(m_jobContext.get()));
SessionHandlingClientRequestsMock handlerMock;
EXPECT_CALL(handlerMock, RequestPlayerJoinSession(::testing::_)).Times(1).WillOnce(::testing::Return(true));
AWSGameLiftJoinSessionRequest request;
request.m_sessionId = "dummySessionId";
request.m_playerId = "dummyPlayerId";
Aws::GameLift::Model::CreatePlayerSessionResult result;
result.SetPlayerSession(Aws::GameLift::Model::PlayerSession());
Aws::GameLift::Model::CreatePlayerSessionOutcome outcome(result);
EXPECT_CALL(*(m_gameliftClientManager->m_gameliftClientMockPtr), CreatePlayerSession(::testing::_))
.Times(1)
.WillOnce(::testing::Return(outcome));
SessionAsyncRequestNotificationsHandlerMock sessionHandlerMock;
EXPECT_CALL(sessionHandlerMock, OnJoinSessionAsyncComplete(true)).Times(1);
m_gameliftClientManager->JoinSessionAsync(request);
}
TEST_F(AWSGameLiftClientManagerTest, SearchSessions_CallWithValidRequestAndErrorOutcome_GetErrorWithEmptyResponse)
{
AWSGameLiftSearchSessionsRequest request = GetValidSearchSessionsRequest();
Aws::Client::AWSError<Aws::GameLift::GameLiftErrors> error;
Aws::GameLift::Model::SearchGameSessionsOutcome outcome(error);
EXPECT_CALL(*(m_gameliftClientManager->m_gameliftClientMockPtr), SearchGameSessions(::testing::_))
.Times(1)
.WillOnce(::testing::Return(outcome));
AZ_TEST_START_TRACE_SUPPRESSION;
auto result = m_gameliftClientManager->SearchSessions(request);
AZ_TEST_STOP_TRACE_SUPPRESSION(1); // capture 1 error message
EXPECT_TRUE(result.m_sessionConfigs.size() == 0);
}
TEST_F(AWSGameLiftClientManagerTest, SearchSessions_CallWithValidRequestAndSuccessOutcome_GetNotificationWithValidResponse)
{
AWSGameLiftSearchSessionsRequest request = GetValidSearchSessionsRequest();
Aws::GameLift::Model::SearchGameSessionsOutcome outcome = GetValidSearchGameSessionsOutcome();
EXPECT_CALL(*(m_gameliftClientManager->m_gameliftClientMockPtr), SearchGameSessions(::testing::_))
.Times(1)
.WillOnce(::testing::Return(outcome));
AzFramework::SearchSessionsResponse expectedResponse = GetValidSearchSessionsResponse();
auto result = m_gameliftClientManager->SearchSessions(request);
EXPECT_TRUE(result.m_sessionConfigs.size() != 0);
}
TEST_F(AWSGameLiftClientManagerTest, SearchSessionsAsync_CallWithoutClientSetup_GetErrorWithEmptyResponse)
{
AZ_TEST_START_TRACE_SUPPRESSION;
EXPECT_FALSE(m_gameliftClientManager->ConfigureGameLiftClient(""));
AZ_TEST_STOP_TRACE_SUPPRESSION(1); // capture 1 error message
AWSGameLiftSearchSessionsRequest request = GetValidSearchSessionsRequest();
SessionAsyncRequestNotificationsHandlerMock sessionHandlerMock;
EXPECT_CALL(sessionHandlerMock,
OnSearchSessionsAsyncComplete(SearchSessionsResponseMatcher(AzFramework::SearchSessionsResponse()))).Times(1);
AZ_TEST_START_TRACE_SUPPRESSION;
m_gameliftClientManager->SearchSessionsAsync(request);
AZ_TEST_STOP_TRACE_SUPPRESSION(1); // capture 1 error message
}
TEST_F(AWSGameLiftClientManagerTest, SearchSessionsAsync_CallWithInvalidRequest_GetErrorWithEmptyResponse)
{
AZ_TEST_START_TRACE_SUPPRESSION;
SessionAsyncRequestNotificationsHandlerMock sessionHandlerMock;
EXPECT_CALL(sessionHandlerMock,
OnSearchSessionsAsyncComplete(SearchSessionsResponseMatcher(AzFramework::SearchSessionsResponse()))).Times(1);
m_gameliftClientManager->SearchSessionsAsync(AzFramework::SearchSessionsRequest());
AZ_TEST_STOP_TRACE_SUPPRESSION(1); // capture 1 error message
}
TEST_F(AWSGameLiftClientManagerTest, SearchSessionsAsync_CallWithValidRequestAndErrorOutcome_GetErrorWithEmptyResponse)
{
AWSGameLiftSearchSessionsRequest request = GetValidSearchSessionsRequest();
AWSCoreRequestsHandlerMock handlerMock;
EXPECT_CALL(handlerMock, GetDefaultJobContext()).Times(1).WillOnce(::testing::Return(m_jobContext.get()));
Aws::Client::AWSError<Aws::GameLift::GameLiftErrors> error;
Aws::GameLift::Model::SearchGameSessionsOutcome outcome(error);
EXPECT_CALL(*(m_gameliftClientManager->m_gameliftClientMockPtr), SearchGameSessions(::testing::_))
.Times(1)
.WillOnce(::testing::Return(outcome));
SessionAsyncRequestNotificationsHandlerMock sessionHandlerMock;
EXPECT_CALL(sessionHandlerMock,
OnSearchSessionsAsyncComplete(SearchSessionsResponseMatcher(AzFramework::SearchSessionsResponse()))).Times(1);
AZ_TEST_START_TRACE_SUPPRESSION;
m_gameliftClientManager->SearchSessionsAsync(request);
AZ_TEST_STOP_TRACE_SUPPRESSION(1); // capture 1 error message
}
TEST_F(AWSGameLiftClientManagerTest, SearchSessionsAsync_CallWithValidRequestAndSuccessOutcome_GetNotificationWithValidResponse)
{
AWSGameLiftSearchSessionsRequest request = GetValidSearchSessionsRequest();
AWSCoreRequestsHandlerMock coreHandlerMock;
EXPECT_CALL(coreHandlerMock, GetDefaultJobContext()).Times(1).WillOnce(::testing::Return(m_jobContext.get()));
Aws::GameLift::Model::SearchGameSessionsOutcome outcome = GetValidSearchGameSessionsOutcome();
EXPECT_CALL(*(m_gameliftClientManager->m_gameliftClientMockPtr), SearchGameSessions(::testing::_))
.Times(1)
.WillOnce(::testing::Return(outcome));
AzFramework::SearchSessionsResponse expectedResponse = GetValidSearchSessionsResponse();
SessionAsyncRequestNotificationsHandlerMock sessionHandlerMock;
EXPECT_CALL(sessionHandlerMock,
OnSearchSessionsAsyncComplete(SearchSessionsResponseMatcher(expectedResponse))).Times(1);
m_gameliftClientManager->SearchSessionsAsync(request);
}
TEST_F(AWSGameLiftClientManagerTest, LeaveSession_CallWithInterfaceNotRegistered_GetExpectedError)
{
AZ_TEST_START_TRACE_SUPPRESSION;
m_gameliftClientManager->LeaveSession();
AZ_TEST_STOP_TRACE_SUPPRESSION(1); // capture 1 error message
}
TEST_F(AWSGameLiftClientManagerTest, LeaveSession_CallWithInterfaceRegistered_LeaveSessionRequestSent)
{
SessionHandlingClientRequestsMock handlerMock;
EXPECT_CALL(handlerMock, RequestPlayerLeaveSession).Times(1);
m_gameliftClientManager->LeaveSession();
}
TEST_F(AWSGameLiftClientManagerTest, LeaveSessionAsync_CallWithInterfaceNotRegistered_GetExpectedError)
{
AZ_TEST_START_TRACE_SUPPRESSION;
m_gameliftClientManager->LeaveSessionAsync();
AZ_TEST_STOP_TRACE_SUPPRESSION(1); // capture 1 error message
}
TEST_F(AWSGameLiftClientManagerTest, LeaveSessionAsync_CallWithInterfaceRegistered_LeaveSessionAsyncRequestSentAndGetNotification)
{
SessionHandlingClientRequestsMock handlerMock;
EXPECT_CALL(handlerMock, RequestPlayerLeaveSession).Times(1);
SessionAsyncRequestNotificationsHandlerMock sessionHandlerMock;
EXPECT_CALL(sessionHandlerMock, OnLeaveSessionAsyncComplete()).Times(1);
m_gameliftClientManager->LeaveSessionAsync();
}

@ -0,0 +1,86 @@
/*
* 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/Interface/Interface.h>
#include <AzFramework/Session/ISessionRequests.h>
#include <AzFramework/Session/ISessionHandlingRequests.h>
#include <AzTest/AzTest.h>
#include <aws/core/auth/AWSCredentialsProvider.h>
#include <aws/core/utils/Outcome.h>
#include <aws/gamelift/GameLiftClient.h>
#include <aws/gamelift/GameLiftErrors.h>
#include <aws/gamelift/model/CreateGameSessionRequest.h>
#include <aws/gamelift/model/CreateGameSessionResult.h>
#include <aws/gamelift/model/CreatePlayerSessionRequest.h>
#include <aws/gamelift/model/CreatePlayerSessionResult.h>
#include <aws/gamelift/model/SearchGameSessionsRequest.h>
#include <aws/gamelift/model/SearchGameSessionsResult.h>
#include <aws/gamelift/model/StartGameSessionPlacementRequest.h>
#include <aws/gamelift/model/StartGameSessionPlacementResult.h>
using namespace Aws::GameLift;
class GameLiftClientMock
: public GameLiftClient
{
public:
GameLiftClientMock()
: GameLiftClient(Aws::Auth::AWSCredentials())
{
}
MOCK_CONST_METHOD1(CreateGameSession, Model::CreateGameSessionOutcome(const Model::CreateGameSessionRequest&));
MOCK_CONST_METHOD1(CreatePlayerSession, Model::CreatePlayerSessionOutcome(const Model::CreatePlayerSessionRequest&));
MOCK_CONST_METHOD1(SearchGameSessions, Model::SearchGameSessionsOutcome(const Model::SearchGameSessionsRequest&));
MOCK_CONST_METHOD1(StartGameSessionPlacement, Model::StartGameSessionPlacementOutcome(const Model::StartGameSessionPlacementRequest&));
};
class SessionAsyncRequestNotificationsHandlerMock
: public AzFramework::SessionAsyncRequestNotificationBus::Handler
{
public:
SessionAsyncRequestNotificationsHandlerMock()
{
AzFramework::SessionAsyncRequestNotificationBus::Handler::BusConnect();
}
~SessionAsyncRequestNotificationsHandlerMock()
{
AzFramework::SessionAsyncRequestNotificationBus::Handler::BusDisconnect();
}
MOCK_METHOD1(OnCreateSessionAsyncComplete, void(const AZStd::string&));
MOCK_METHOD1(OnSearchSessionsAsyncComplete, void(const AzFramework::SearchSessionsResponse&));
MOCK_METHOD1(OnJoinSessionAsyncComplete, void(bool));
MOCK_METHOD0(OnLeaveSessionAsyncComplete, void());
};
class SessionHandlingClientRequestsMock
: public AzFramework::ISessionHandlingClientRequests
{
public:
SessionHandlingClientRequestsMock()
{
AZ::Interface<AzFramework::ISessionHandlingClientRequests>::Register(this);
}
virtual ~SessionHandlingClientRequestsMock()
{
AZ::Interface<AzFramework::ISessionHandlingClientRequests>::Unregister(this);
}
MOCK_METHOD1(RequestPlayerJoinSession, bool(const AzFramework::SessionConnectionConfig&));
MOCK_METHOD0(RequestPlayerLeaveSession, void());
};

@ -0,0 +1,156 @@
/*
* 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/Component/ComponentApplication.h>
#include <AzCore/Serialization/EditContext.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/std/smart_ptr/unique_ptr.h>
#include <AWSGameLiftClientFixture.h>
#include <AWSGameLiftClientManager.h>
#include <AWSGameLiftClientSystemComponent.h>
#include <aws/gamelift/GameLiftClient.h>
using namespace AWSGameLift;
class AWSGameLiftClientManagerMock
: public AWSGameLiftClientManager
{
public:
AWSGameLiftClientManagerMock() = default;
~AWSGameLiftClientManagerMock() = default;
MOCK_METHOD0(ActivateManager, void());
MOCK_METHOD0(DeactivateManager, void());
};
class TestAWSGameLiftClientSystemComponent
: public AWSGameLiftClientSystemComponent
{
public:
TestAWSGameLiftClientSystemComponent()
{
m_gameliftClientManagerMockPtr = nullptr;
}
~TestAWSGameLiftClientSystemComponent()
{
m_gameliftClientManagerMockPtr = nullptr;
}
void SetUpMockManager()
{
AZStd::unique_ptr<AWSGameLiftClientManagerMock> gameliftClientManagerMock = AZStd::make_unique<AWSGameLiftClientManagerMock>();
m_gameliftClientManagerMockPtr = gameliftClientManagerMock.get();
SetGameLiftClientManager(AZStd::move(gameliftClientManagerMock));
}
AWSGameLiftClientManagerMock* m_gameliftClientManagerMockPtr;
};
class AWSCoreSystemComponentMock
: public AZ::Component
{
public:
AZ_COMPONENT(AWSCoreSystemComponentMock, "{52DB1342-30C6-412F-B7CC-B23F8B0629EA}");
static void Reflect(AZ::ReflectContext* context)
{
AZ_UNUSED(context);
}
static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)
{
provided.push_back(AZ_CRC_CE("AWSCoreService"));
}
static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible)
{
AZ_UNUSED(incompatible);
}
static void GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required)
{
AZ_UNUSED(required);
}
static void GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& dependent)
{
AZ_UNUSED(dependent);
}
AWSCoreSystemComponentMock() = default;
~AWSCoreSystemComponentMock() = default;
void Init() override {}
void Activate() override {}
void Deactivate() override {}
};
class AWSGameLiftClientSystemComponentTest
: public AWSGameLiftClientFixture
{
protected:
AZStd::unique_ptr<AZ::SerializeContext> m_serializeContext;
AZStd::unique_ptr<AZ::BehaviorContext> m_behaviorContext;
AZStd::unique_ptr<AZ::ComponentDescriptor> m_coreComponentDescriptor;
AZStd::unique_ptr<AZ::ComponentDescriptor> m_gameliftClientComponentDescriptor;
void SetUp() override
{
AWSGameLiftClientFixture::SetUp();
m_serializeContext = AZStd::make_unique<AZ::SerializeContext>();
m_serializeContext->CreateEditContext();
m_behaviorContext = AZStd::make_unique<AZ::BehaviorContext>();
m_coreComponentDescriptor.reset(AWSCoreSystemComponentMock::CreateDescriptor());
m_gameliftClientComponentDescriptor.reset(TestAWSGameLiftClientSystemComponent::CreateDescriptor());
m_gameliftClientComponentDescriptor->Reflect(m_serializeContext.get());
m_gameliftClientComponentDescriptor->Reflect(m_behaviorContext.get());
m_entity = aznew AZ::Entity();
m_coreSystemComponent = AZStd::make_unique<AWSCoreSystemComponentMock>();
m_entity->AddComponent(m_coreSystemComponent.get());
m_gameliftClientSystemComponent = AZStd::make_unique<TestAWSGameLiftClientSystemComponent>();
m_gameliftClientSystemComponent->SetUpMockManager();
m_entity->AddComponent(m_gameliftClientSystemComponent.get());
}
void TearDown() override
{
m_entity->RemoveComponent(m_gameliftClientSystemComponent.get());
m_gameliftClientSystemComponent.reset();
m_entity->RemoveComponent(m_coreSystemComponent.get());
m_coreSystemComponent.reset();
delete m_entity;
m_entity = nullptr;
m_gameliftClientComponentDescriptor.reset();
m_coreComponentDescriptor.reset();
m_behaviorContext.reset();
m_serializeContext.reset();
AWSGameLiftClientFixture::TearDown();
}
public:
AZStd::unique_ptr<AWSCoreSystemComponentMock> m_coreSystemComponent;
AZStd::unique_ptr<TestAWSGameLiftClientSystemComponent> m_gameliftClientSystemComponent;
AZ::Entity* m_entity;
};
TEST_F(AWSGameLiftClientSystemComponentTest, ActivateDeactivate_Call_GameLiftClientManagerGetsInvoked)
{
m_entity->Init();
EXPECT_CALL(*(m_gameliftClientSystemComponent->m_gameliftClientManagerMockPtr), ActivateManager()).Times(1);
m_entity->Activate();
EXPECT_CALL(*(m_gameliftClientSystemComponent->m_gameliftClientManagerMockPtr), DeactivateManager()).Times(1);
m_entity->Deactivate();
}

@ -0,0 +1,15 @@
/*
* 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 <AzTest/AzTest.h>
AZ_UNIT_TEST_HOOK(DEFAULT_UNIT_TEST_ENV);

@ -0,0 +1,81 @@
/*
* 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 <Activity/AWSGameLiftCreateSessionActivity.h>
#include <AWSGameLiftClientFixture.h>
using namespace AWSGameLift;
using AWSGameLiftCreateSessionActivityTest = AWSGameLiftClientFixture;
TEST_F(AWSGameLiftCreateSessionActivityTest, BuildAWSGameLiftCreateGameSessionRequest_Call_GetExpectedResult)
{
AWSGameLiftCreateSessionRequest request;
request.m_creatorId = "dummyCreatorId";
request.m_sessionName = "dummySessionName";
request.m_maxPlayer = 1;
request.m_sessionProperties.emplace("dummyKey", "dummyValue");
request.m_aliasId = "dummyAliasId";
request.m_fleetId = "dummyFleetId";
request.m_idempotencyToken = "dummyIdempotencyToken";
auto awsRequest = CreateSessionActivity::BuildAWSGameLiftCreateGameSessionRequest(request);
EXPECT_TRUE(strcmp(awsRequest.GetCreatorId().c_str(), request.m_creatorId.c_str()) == 0);
EXPECT_TRUE(strcmp(awsRequest.GetName().c_str(), request.m_sessionName.c_str()) == 0);
EXPECT_TRUE(awsRequest.GetMaximumPlayerSessionCount() == request.m_maxPlayer);
EXPECT_TRUE(strcmp(awsRequest.GetGameProperties()[0].GetKey().c_str(), request.m_sessionProperties.begin()->first.c_str()) == 0);
EXPECT_TRUE(strcmp(awsRequest.GetGameProperties()[0].GetValue().c_str(), request.m_sessionProperties.begin()->second.c_str()) == 0);
EXPECT_TRUE(strcmp(awsRequest.GetAliasId().c_str(), request.m_aliasId.c_str()) == 0);
EXPECT_TRUE(strcmp(awsRequest.GetFleetId().c_str(), request.m_fleetId.c_str()) == 0);
EXPECT_TRUE(strcmp(awsRequest.GetIdempotencyToken().c_str(), request.m_idempotencyToken.c_str()) == 0);
}
TEST_F(AWSGameLiftCreateSessionActivityTest, ValidateCreateSessionRequest_CallWithBaseType_GetFalseResult)
{
auto result = CreateSessionActivity::ValidateCreateSessionRequest(AzFramework::CreateSessionRequest());
EXPECT_FALSE(result);
}
TEST_F(AWSGameLiftCreateSessionActivityTest, ValidateCreateSessionRequest_CallWithNegativeMaxPlayer_GetFalseResult)
{
AWSGameLiftCreateSessionRequest request;
request.m_maxPlayer = -1;
auto result = CreateSessionActivity::ValidateCreateSessionRequest(request);
EXPECT_FALSE(result);
}
TEST_F(AWSGameLiftCreateSessionActivityTest, ValidateCreateSessionRequest_CallWithoutAliasOrFleetId_GetFalseResult)
{
AWSGameLiftCreateSessionRequest request;
request.m_maxPlayer = 1;
auto result = CreateSessionActivity::ValidateCreateSessionRequest(request);
EXPECT_FALSE(result);
}
TEST_F(AWSGameLiftCreateSessionActivityTest, ValidateCreateSessionRequest_CallWithAliasId_GetTrueResult)
{
AWSGameLiftCreateSessionRequest request;
request.m_maxPlayer = 1;
request.m_aliasId = "dummyAliasId";
auto result = CreateSessionActivity::ValidateCreateSessionRequest(request);
EXPECT_TRUE(result);
}
TEST_F(AWSGameLiftCreateSessionActivityTest, ValidateCreateSessionRequest_CallWithFleetId_GetTrueResult)
{
AWSGameLiftCreateSessionRequest request;
request.m_maxPlayer = 1;
request.m_fleetId = "dummyFleetId";
auto result = CreateSessionActivity::ValidateCreateSessionRequest(request);
EXPECT_TRUE(result);
}

@ -0,0 +1,79 @@
/*
* 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 <AWSGameLiftClientFixture.h>
#include <Activity/AWSGameLiftCreateSessionOnQueueActivity.h>
using namespace AWSGameLift;
using AWSGameLiftCreateSessionOnQueueActivityTest = AWSGameLiftClientFixture;
TEST_F(AWSGameLiftCreateSessionOnQueueActivityTest, BuildAWSGameLiftCreateGameSessionRequest_Call_GetExpectedResult)
{
AWSGameLiftCreateSessionOnQueueRequest request;
request.m_sessionName = "dummySessionName";
request.m_maxPlayer = 1;
request.m_sessionProperties.emplace("dummyKey", "dummyValue");
request.m_queueName = "dummyQueueName";
request.m_placementId = "dummyPlacementId";
auto awsRequest = CreateSessionOnQueueActivity::BuildAWSGameLiftStartGameSessionPlacementRequest(request);
EXPECT_TRUE(strcmp(awsRequest.GetGameSessionName().c_str(), request.m_sessionName.c_str()) == 0);
EXPECT_TRUE(awsRequest.GetMaximumPlayerSessionCount() == request.m_maxPlayer);
EXPECT_TRUE(strcmp(awsRequest.GetGameProperties()[0].GetKey().c_str(), request.m_sessionProperties.begin()->first.c_str()) == 0);
EXPECT_TRUE(strcmp(awsRequest.GetGameProperties()[0].GetValue().c_str(), request.m_sessionProperties.begin()->second.c_str()) == 0);
EXPECT_TRUE(strcmp(awsRequest.GetGameSessionQueueName().c_str(), request.m_queueName.c_str()) == 0);
EXPECT_TRUE(strcmp(awsRequest.GetPlacementId().c_str(), request.m_placementId.c_str()) == 0);
}
TEST_F(AWSGameLiftCreateSessionOnQueueActivityTest, ValidateCreateSessionOnQueueRequest_CallWithBaseType_GetFalseResult)
{
auto result = CreateSessionOnQueueActivity::ValidateCreateSessionOnQueueRequest(AzFramework::CreateSessionRequest());
EXPECT_FALSE(result);
}
TEST_F(AWSGameLiftCreateSessionOnQueueActivityTest, ValidateCreateSessionOnQueueRequest_CallWithNegativeMaxPlayer_GetFalseResult)
{
AWSGameLiftCreateSessionOnQueueRequest request;
request.m_maxPlayer = -1;
auto result = CreateSessionOnQueueActivity::ValidateCreateSessionOnQueueRequest(request);
EXPECT_FALSE(result);
}
TEST_F(AWSGameLiftCreateSessionOnQueueActivityTest, ValidateCreateSessionOnQueueRequest_CallWithoutQueueName_GetFalseResult)
{
AWSGameLiftCreateSessionOnQueueRequest request;
request.m_maxPlayer = 1;
request.m_placementId = "dummyPlacementId";
auto result = CreateSessionOnQueueActivity::ValidateCreateSessionOnQueueRequest(request);
EXPECT_FALSE(result);
}
TEST_F(AWSGameLiftCreateSessionOnQueueActivityTest, ValidateCreateSessionOnQueueRequest_CallWithoutPlacementId_GetFalseResult)
{
AWSGameLiftCreateSessionOnQueueRequest request;
request.m_maxPlayer = 1;
request.m_queueName = "dummyQueueName";
auto result = CreateSessionOnQueueActivity::ValidateCreateSessionOnQueueRequest(request);
EXPECT_FALSE(result);
}
TEST_F(AWSGameLiftCreateSessionOnQueueActivityTest, ValidateCreateSessionOnQueueRequest_CallWithValidRequest_GetTrueResult)
{
AWSGameLiftCreateSessionOnQueueRequest request;
request.m_maxPlayer = 1;
request.m_queueName = "dummyQueueName";
request.m_placementId = "dummyPlacementId";
auto result = CreateSessionOnQueueActivity::ValidateCreateSessionOnQueueRequest(request);
EXPECT_TRUE(result);
}

@ -0,0 +1,84 @@
/*
* 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 <AWSGameLiftClientFixture.h>
#include <Activity/AWSGameLiftJoinSessionActivity.h>
using namespace AWSGameLift;
using AWSGameLiftJoinSessionActivityTest = AWSGameLiftClientFixture;
TEST_F(AWSGameLiftJoinSessionActivityTest, BuildAWSGameLiftCreatePlayerSessionRequest_Call_GetExpectedResult)
{
AWSGameLiftJoinSessionRequest request;
request.m_playerData = "dummyPlayerData";
request.m_playerId = "dummyPlayerId";
request.m_sessionId = "dummySessionId";
auto awsRequest = JoinSessionActivity::BuildAWSGameLiftCreatePlayerSessionRequest(request);
EXPECT_TRUE(strcmp(awsRequest.GetPlayerData().c_str(), request.m_playerData.c_str()) == 0);
EXPECT_TRUE(strcmp(awsRequest.GetPlayerId().c_str(), request.m_playerId.c_str()) == 0);
EXPECT_TRUE(strcmp(awsRequest.GetGameSessionId().c_str(), request.m_sessionId.c_str()) == 0);
}
TEST_F(AWSGameLiftJoinSessionActivityTest, BuildSessionConnectionConfig_Call_GetExpectedResult)
{
Aws::GameLift::Model::PlayerSession playerSession;
playerSession.SetIpAddress("dummyIpAddress");
playerSession.SetPlayerSessionId("dummyPlayerSessionId");
playerSession.SetPort(123);
Aws::GameLift::Model::CreatePlayerSessionResult createPlayerSessionResult;
createPlayerSessionResult.SetPlayerSession(playerSession);
Aws::GameLift::Model::CreatePlayerSessionOutcome createPlayerSessionOutcome(createPlayerSessionResult);
auto connectionConfig = JoinSessionActivity::BuildSessionConnectionConfig(createPlayerSessionOutcome);
EXPECT_TRUE(strcmp(connectionConfig.m_ipAddress.c_str(), playerSession.GetIpAddress().c_str()) == 0);
EXPECT_TRUE(strcmp(connectionConfig.m_playerSessionId.c_str(), playerSession.GetPlayerSessionId().c_str()) == 0);
EXPECT_TRUE(connectionConfig.m_port == playerSession.GetPort());
}
TEST_F(AWSGameLiftJoinSessionActivityTest, ValidateJoinSessionRequest_CallWithBaseType_GetFalseResult)
{
AZ_TEST_START_TRACE_SUPPRESSION;
auto result = JoinSessionActivity::ValidateJoinSessionRequest(AzFramework::JoinSessionRequest());
AZ_TEST_STOP_TRACE_SUPPRESSION(1); // capture 1 error message
EXPECT_FALSE(result);
}
TEST_F(AWSGameLiftJoinSessionActivityTest, ValidateJoinSessionRequest_CallWithEmptyPlayerId_GetFalseResult)
{
AWSGameLiftJoinSessionRequest request;
request.m_sessionId = "dummySessionId";
AZ_TEST_START_TRACE_SUPPRESSION;
auto result = JoinSessionActivity::ValidateJoinSessionRequest(request);
AZ_TEST_STOP_TRACE_SUPPRESSION(1); // capture 1 error message
EXPECT_FALSE(result);
}
TEST_F(AWSGameLiftJoinSessionActivityTest, ValidateJoinSessionRequest_CallWithEmptySessionId_GetFalseResult)
{
AWSGameLiftJoinSessionRequest request;
request.m_playerId = "dummyPlayerId";
AZ_TEST_START_TRACE_SUPPRESSION;
auto result = JoinSessionActivity::ValidateJoinSessionRequest(request);
AZ_TEST_STOP_TRACE_SUPPRESSION(1); // capture 1 error message
EXPECT_FALSE(result);
}
TEST_F(AWSGameLiftJoinSessionActivityTest, ValidateJoinSessionRequest_CallWithPlayerAndSessionId_GetTrueResult)
{
AWSGameLiftJoinSessionRequest request;
request.m_playerId = "dummyPlayerId";
request.m_sessionId = "dummySessionId";
auto result = JoinSessionActivity::ValidateJoinSessionRequest(request);
EXPECT_TRUE(result);
}

@ -0,0 +1,126 @@
/*
* 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 <AzFramework/Session/SessionConfig.h>
#include <Activity/AWSGameLiftSearchSessionsActivity.h>
#include <AWSGameLiftClientFixture.h>
#include <AWSGameLiftSessionConstants.h>
using namespace AWSGameLift;
using AWSGameLiftSearchSessionsActivityTest = AWSGameLiftClientFixture;
TEST_F(AWSGameLiftSearchSessionsActivityTest, BuildAWSGameLiftSearchGameSessionsRequest_Call_GetExpectedResult)
{
AWSGameLiftSearchSessionsRequest request;
request.m_aliasId = "dummyAliasId";
request.m_fleetId = "dummyFleetId";
request.m_location = "dummyLocation";
request.m_filterExpression = "dummyFilterExpression";
request.m_sortExpression = "dummySortExpression";
request.m_maxResult = 1;
request.m_nextToken = "dummyNextToken";
auto awsRequest = SearchSessionsActivity::BuildAWSGameLiftSearchGameSessionsRequest(request);
EXPECT_TRUE(strcmp(awsRequest.GetFleetId().c_str(), request.m_fleetId.c_str()) == 0);
EXPECT_TRUE(strcmp(awsRequest.GetAliasId().c_str(), request.m_aliasId.c_str()) == 0);
EXPECT_TRUE(strcmp(awsRequest.GetFilterExpression().c_str(), request.m_filterExpression.c_str()) == 0);
EXPECT_TRUE(strcmp(awsRequest.GetSortExpression().c_str(), request.m_sortExpression.c_str()) == 0);
EXPECT_TRUE(awsRequest.GetLimit() == request.m_maxResult);
EXPECT_TRUE(strcmp(awsRequest.GetNextToken().c_str(), request.m_nextToken.c_str()) == 0);
// TODO: Update the AWS Native SDK to get the new request attributes.
//EXPECT_TRUE(strcmp(awsRequest.GetLocation().c_str(), request.m_location.c_str()) == 0);
}
TEST_F(AWSGameLiftSearchSessionsActivityTest, ValidateSearchSessionsRequest_CallWithBaseType_GetFalseResult)
{
AZ_TEST_START_TRACE_SUPPRESSION;
auto result = SearchSessionsActivity::ValidateSearchSessionsRequest(AzFramework::SearchSessionsRequest());
AZ_TEST_STOP_TRACE_SUPPRESSION(1); // capture 1 error message
EXPECT_FALSE(result);
}
TEST_F(AWSGameLiftSearchSessionsActivityTest, ValidateSearchSessionsRequest_CallWithoutAliasOrFleetId_GetFalseResult)
{
AWSGameLiftSearchSessionsRequest request;
AZ_TEST_START_TRACE_SUPPRESSION;
auto result = SearchSessionsActivity::ValidateSearchSessionsRequest(request);
AZ_TEST_STOP_TRACE_SUPPRESSION(1); // capture 1 error message
EXPECT_FALSE(result);
}
TEST_F(AWSGameLiftSearchSessionsActivityTest, ValidateSearchSessionsRequest_CallWithAliasId_GetTrueResult)
{
AWSGameLiftSearchSessionsRequest request;
request.m_aliasId = "dummyAliasId";
auto result = SearchSessionsActivity::ValidateSearchSessionsRequest(request);
EXPECT_TRUE(result);
}
TEST_F(AWSGameLiftSearchSessionsActivityTest, ValidateSearchSessionsRequest_CallWithFleetId_GetTrueResult)
{
AWSGameLiftSearchSessionsRequest request;
request.m_fleetId = "dummyFleetId";
auto result = SearchSessionsActivity::ValidateSearchSessionsRequest(request);
EXPECT_TRUE(result);
}
TEST_F(AWSGameLiftSearchSessionsActivityTest, ParseResponse_Call_GetExpectedResult)
{
Aws::GameLift::Model::GameProperty gameProperty;
gameProperty.SetKey("dummyKey");
gameProperty.SetValue("dummyValue");
Aws::Vector<Aws::GameLift::Model::GameProperty> gameProperties = { gameProperty };
Aws::GameLift::Model::GameSession gameSession;
gameSession.SetCreationTime(Aws::Utils::DateTime(0.0));
gameSession.SetTerminationTime(Aws::Utils::DateTime(0.0));
gameSession.SetCreatorId("dummyCreatorId");
gameSession.SetGameProperties(gameProperties);
gameSession.SetGameSessionId("dummyGameSessionId");
gameSession.SetName("dummyGameSessionName");
gameSession.SetIpAddress("dummyIpAddress");
gameSession.SetPort(0);
gameSession.SetMaximumPlayerSessionCount(2);
gameSession.SetCurrentPlayerSessionCount(1);
gameSession.SetStatus(Aws::GameLift::Model::GameSessionStatus::TERMINATED);
gameSession.SetStatusReason(Aws::GameLift::Model::GameSessionStatusReason::INTERRUPTED);
// TODO: Update the AWS Native SDK to set the new game session attributes.
//gameSession.SetDnsName("dummyDnsName");
Aws::Vector<Aws::GameLift::Model::GameSession> gameSessions = { gameSession };
Aws::GameLift::Model::SearchGameSessionsResult result;
result.SetNextToken("dummyNextToken");
result.SetGameSessions(gameSessions);
auto response = SearchSessionsActivity::ParseResponse(result);
EXPECT_TRUE(strcmp(response.m_nextToken.c_str(), result.GetNextToken().c_str()) == 0);
EXPECT_EQ(response.m_sessionConfigs.size(), 1);
const auto& sessionConfig = response.m_sessionConfigs[0];
EXPECT_EQ(gameSession.GetCreationTime().Millis(), sessionConfig.m_creationTime);
EXPECT_EQ(gameSession.GetTerminationTime().Millis(), sessionConfig.m_terminationTime);
EXPECT_TRUE(strcmp(gameSession.GetCreatorId().c_str(), sessionConfig.m_creatorId.c_str()) == 0);
EXPECT_TRUE(strcmp(gameSession.GetGameSessionId().c_str(), sessionConfig.m_sessionId.c_str()) == 0);
EXPECT_TRUE(strcmp(gameSession.GetName().c_str(), sessionConfig.m_sessionName.c_str()) == 0);
EXPECT_TRUE(strcmp(gameSession.GetIpAddress().c_str(), sessionConfig.m_ipAddress.c_str()) == 0);
EXPECT_EQ(gameSession.GetPort(), 0);
EXPECT_EQ(gameSession.GetMaximumPlayerSessionCount(), 2);
EXPECT_EQ(gameSession.GetCurrentPlayerSessionCount(), 1);
EXPECT_TRUE(strcmp(AWSGameLiftSessionStatusNames[(int)gameSession.GetStatus()], sessionConfig.m_status.c_str()) == 0);
EXPECT_TRUE(strcmp(AWSGameLiftSessionStatusReasons[(int)gameSession.GetStatusReason()], sessionConfig.m_statusReason.c_str()) == 0);
// TODO: Update the AWS Native SDK to get the new game session attributes.
// EXPECT_TRUE(strcmp(gameSession.GetDnsName().c_str(), sessionConfig.m_dnsName.c_str()) == 0);
}

@ -0,0 +1,36 @@
#
# 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.
#
set(FILES
Include/Request/AWSGameLiftCreateSessionOnQueueRequest.h
Include/Request/AWSGameLiftCreateSessionRequest.h
Include/Request/AWSGameLiftJoinSessionRequest.h
Include/Request/AWSGameLiftSearchSessionsRequest.h
Include/Request/IAWSGameLiftRequests.h
Source/Activity/AWSGameLiftCreateSessionActivity.cpp
Source/Activity/AWSGameLiftCreateSessionActivity.h
Source/Activity/AWSGameLiftCreateSessionOnQueueActivity.cpp
Source/Activity/AWSGameLiftCreateSessionOnQueueActivity.h
Source/Activity/AWSGameLiftJoinSessionActivity.cpp
Source/Activity/AWSGameLiftJoinSessionActivity.h
Source/Activity/AWSGameLiftLeaveSessionActivity.cpp
Source/Activity/AWSGameLiftLeaveSessionActivity.h
Source/Activity/AWSGameLiftSearchSessionsActivity.cpp
Source/Activity/AWSGameLiftSearchSessionsActivity.h
Source/AWSGameLiftClientManager.cpp
Source/AWSGameLiftClientManager.h
Source/AWSGameLiftClientSystemComponent.cpp
Source/AWSGameLiftClientSystemComponent.h
Source/Request/AWSGameLiftCreateSessionOnQueueRequest.cpp
Source/Request/AWSGameLiftCreateSessionRequest.cpp
Source/Request/AWSGameLiftJoinSessionRequest.cpp
Source/Request/AWSGameLiftSearchSessionsRequest.cpp
)

@ -0,0 +1,14 @@
#
# 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.
#
set(FILES
Source/AWSGameLiftClientModule.cpp
)

@ -0,0 +1,22 @@
#
# 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.
#
set(FILES
Tests/Activity/AWSGameLiftCreateSessionActivityTest.cpp
Tests/Activity/AWSGameLiftCreateSessionOnQueueActivityTest.cpp
Tests/Activity/AWSGameLiftJoinSessionActivityTest.cpp
Tests/Activity/AWSGameLiftSearchSessionsActivityTest.cpp
Tests/AWSGameLiftClientFixture.h
Tests/AWSGameLiftClientManagerTest.cpp
Tests/AWSGameLiftClientMocks.h
Tests/AWSGameLiftClientSystemComponentTest.cpp
Tests/AWSGameLiftClientTest.cpp
)

@ -0,0 +1,24 @@
/*
* 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
namespace AWSGameLift
{
// Reference https://sdk.amazonaws.com/cpp/api/LATEST/_game_session_status_8h_source.html
static const char* AWSGameLiftSessionStatusNames[6] = { "NotSet", "Active", "Activating", "Terminated", "Terminating", "Error"};
// Reference https://sdk.amazonaws.com/cpp/api/LATEST/_game_session_status_reason_8h.html
static const char* AWSGameLiftSessionStatusReasons[2] = { "NotSet", "Interrupted" };
static constexpr const char AWSGameLiftErrorMessageTemplate[] = "Exception: %s, Message: %s";
} // 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.
#
if (NOT PAL_TRAIT_BUILD_SERVER_SUPPORTED)
return()
endif()
ly_add_target(
NAME AWSGameLift.Server.Static STATIC
NAMESPACE Gem
FILES_CMAKE
awsgamelift_server_files.cmake
INCLUDE_DIRECTORIES
PRIVATE
../AWSGameLiftCommon/Source
Source
BUILD_DEPENDENCIES
PRIVATE
AZ::AzCore
AZ::AzFramework
3rdParty::AWSGameLiftServerSDK
)
ly_add_target(
NAME AWSGameLift.Servers ${PAL_TRAIT_MONOLITHIC_DRIVEN_MODULE_TYPE}
NAMESPACE Gem
FILES_CMAKE
awsgamelift_server_shared_files.cmake
INCLUDE_DIRECTORIES
PRIVATE
Source
BUILD_DEPENDENCIES
PUBLIC
AZ::AzCore
Gem::AWSGameLift.Server.Static
3rdParty::AWSGameLiftServerSDK
)
################################################################################
# Tests
################################################################################
if(PAL_TRAIT_BUILD_TESTS_SUPPORTED)
ly_add_target(
NAME AWSGameLift.Server.Tests ${PAL_TRAIT_TEST_TARGET_TYPE}
NAMESPACE Gem
FILES_CMAKE
awsgamelift_server_tests_files.cmake
INCLUDE_DIRECTORIES
PRIVATE
Tests
Source
BUILD_DEPENDENCIES
PRIVATE
AZ::AzCore
AZ::AzFramework
AZ::AzTest
Gem::AWSGameLift.Server.Static
3rdParty::AWSGameLiftServerSDK
)
# Add AWSGameLift.Server.Tests to googletest
ly_add_googletest(
NAME Gem::AWSGameLift.Server.Tests
)
endif()

@ -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

@ -0,0 +1,58 @@
/*
* 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/Jobs/JobContext.h>
#include <AzCore/Jobs/JobManager.h>
#include <AzCore/Jobs/JobManagerBus.h>
#include <AzCore/Memory/PoolAllocator.h>
#include <AzCore/UnitTest/TestTypes.h>
class AWSGameLiftServerFixture
: public UnitTest::ScopedAllocatorSetupFixture
{
public:
AWSGameLiftServerFixture() {}
virtual ~AWSGameLiftServerFixture() = default;
void SetUp() override
{
AZ::AllocatorInstance<AZ::ThreadPoolAllocator>::Create();
AZ::AllocatorInstance<AZ::PoolAllocator>::Create();
AZ::JobManagerDesc jobManagerDesc;
AZ::JobManagerThreadDesc threadDesc;
m_jobManager.reset(aznew AZ::JobManager(jobManagerDesc));
m_jobCancelGroup.reset(aznew AZ::JobCancelGroup());
jobManagerDesc.m_workerThreads.push_back(threadDesc);
jobManagerDesc.m_workerThreads.push_back(threadDesc);
jobManagerDesc.m_workerThreads.push_back(threadDesc);
m_jobContext.reset(aznew AZ::JobContext(*m_jobManager, *m_jobCancelGroup));
AZ::JobContext::SetGlobalContext(m_jobContext.get());
}
void TearDown() override
{
AZ::JobContext::SetGlobalContext(nullptr);
m_jobContext.reset();
m_jobCancelGroup.reset();
m_jobManager.reset();
AZ::AllocatorInstance<AZ::PoolAllocator>::Destroy();
AZ::AllocatorInstance<AZ::ThreadPoolAllocator>::Destroy();
}
AZStd::unique_ptr<AZ::JobContext> m_jobContext;
AZStd::unique_ptr<AZ::JobCancelGroup> m_jobCancelGroup;
AZStd::unique_ptr<AZ::JobManager> m_jobManager;
};

@ -0,0 +1,421 @@
/*
* 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 <AWSGameLiftServerFixture.h>
#include <AWSGameLiftServerMocks.h>
#include <AzCore/Interface/Interface.h>
#include <AzFramework/Session/SessionConfig.h>
#include <AzFramework/Session/SessionNotifications.h>
namespace UnitTest
{
class SessionNotificationsHandlerMock
: public AzFramework::SessionNotificationBus::Handler
{
public:
SessionNotificationsHandlerMock()
{
AzFramework::SessionNotificationBus::Handler::BusConnect();
}
~SessionNotificationsHandlerMock()
{
AzFramework::SessionNotificationBus::Handler::BusDisconnect();
}
MOCK_METHOD0(OnSessionHealthCheck, bool());
MOCK_METHOD1(OnCreateSessionBegin, bool(const AzFramework::SessionConfig&));
MOCK_METHOD0(OnDestroySessionBegin, bool());
};
class GameLiftServerManagerTest
: public AWSGameLiftServerFixture
{
public:
void SetUp() override
{
AWSGameLiftServerFixture::SetUp();
GameLiftServerProcessDesc serverDesc;
m_serverManager = AZStd::make_unique<NiceMock<AWSGameLiftServerManagerMock>>();
}
void TearDown() override
{
m_serverManager.reset();
AWSGameLiftServerFixture::TearDown();
}
AZStd::unique_ptr<NiceMock<AWSGameLiftServerManagerMock>> m_serverManager;
};
TEST_F(GameLiftServerManagerTest, InitializeGameLiftServerSDK_InitializeTwice_InitSDKCalledOnce)
{
EXPECT_CALL(*(m_serverManager->m_gameLiftServerSDKWrapperMockPtr), InitSDK()).Times(1);
EXPECT_TRUE(m_serverManager->InitializeGameLiftServerSDK());
AZ_TEST_START_TRACE_SUPPRESSION;
EXPECT_FALSE(m_serverManager->InitializeGameLiftServerSDK());
AZ_TEST_STOP_TRACE_SUPPRESSION(1);
}
TEST_F(GameLiftServerManagerTest, NotifyGameLiftProcessReady_SDKNotInitialized_FailToNotifyGameLift)
{
EXPECT_CALL(*(m_serverManager->m_gameLiftServerSDKWrapperMockPtr), ProcessReady(testing::_)).Times(0);
AZ_TEST_START_TRACE_SUPPRESSION;
EXPECT_FALSE(m_serverManager->NotifyGameLiftProcessReady(GameLiftServerProcessDesc()));
AZ_TEST_STOP_TRACE_SUPPRESSION(1);
}
TEST_F(GameLiftServerManagerTest, NotifyGameLiftProcessReady_SDKInitialized_ProcessReadyNotificationSent)
{
EXPECT_TRUE(m_serverManager->InitializeGameLiftServerSDK());
EXPECT_CALL(*(m_serverManager->m_gameLiftServerSDKWrapperMockPtr), ProcessReady(testing::_)).Times(1);
EXPECT_TRUE(m_serverManager->NotifyGameLiftProcessReady(GameLiftServerProcessDesc()));
}
TEST_F(GameLiftServerManagerTest, NotifyGameLiftProcessReady_ProcessReadyFails_TerminationNotificationSent)
{
EXPECT_TRUE(m_serverManager->InitializeGameLiftServerSDK());
EXPECT_CALL(*(m_serverManager->m_gameLiftServerSDKWrapperMockPtr), ProcessReady(testing::_))
.Times(1)
.WillOnce(testing::Return(Aws::GameLift::GenericOutcome()));
EXPECT_CALL(*(m_serverManager->m_gameLiftServerSDKWrapperMockPtr), ProcessEnding()).Times(1);
AZ_TEST_START_TRACE_SUPPRESSION;
EXPECT_TRUE(m_serverManager->NotifyGameLiftProcessReady(GameLiftServerProcessDesc()));
AZ_TEST_STOP_TRACE_SUPPRESSION(1);
}
TEST_F(GameLiftServerManagerTest, OnProcessTerminate_OnDestroySessionBeginReturnsFalse_FailToNotifyGameLift)
{
m_serverManager->InitializeGameLiftServerSDK();
m_serverManager->NotifyGameLiftProcessReady(GameLiftServerProcessDesc());
if (!AZ::Interface<AzFramework::ISessionHandlingProviderRequests>::Get())
{
AZ::Interface<AzFramework::ISessionHandlingProviderRequests>::Register(m_serverManager.get());
}
SessionNotificationsHandlerMock handlerMock;
EXPECT_CALL(handlerMock, OnDestroySessionBegin()).Times(1).WillOnce(testing::Return(false));
EXPECT_CALL(*(m_serverManager->m_gameLiftServerSDKWrapperMockPtr), GetTerminationTime()).Times(1);
EXPECT_CALL(*(m_serverManager->m_gameLiftServerSDKWrapperMockPtr), ProcessEnding()).Times(0);
AZ_TEST_START_TRACE_SUPPRESSION;
m_serverManager->m_gameLiftServerSDKWrapperMockPtr->m_onProcessTerminateFunc();
AZ_TEST_STOP_TRACE_SUPPRESSION(1);
EXPECT_FALSE(AZ::Interface<AzFramework::ISessionHandlingProviderRequests>::Get());
}
TEST_F(GameLiftServerManagerTest, OnProcessTerminate_OnDestroySessionBeginReturnsTrue_TerminationNotificationSent)
{
m_serverManager->InitializeGameLiftServerSDK();
m_serverManager->NotifyGameLiftProcessReady(GameLiftServerProcessDesc());
if (!AZ::Interface<AzFramework::ISessionHandlingProviderRequests>::Get())
{
AZ::Interface<AzFramework::ISessionHandlingProviderRequests>::Register(m_serverManager.get());
}
SessionNotificationsHandlerMock handlerMock;
EXPECT_CALL(handlerMock, OnDestroySessionBegin()).Times(1).WillOnce(testing::Return(true));
EXPECT_CALL(*(m_serverManager->m_gameLiftServerSDKWrapperMockPtr), GetTerminationTime()).Times(1);
EXPECT_CALL(*(m_serverManager->m_gameLiftServerSDKWrapperMockPtr), ProcessEnding()).Times(1);
m_serverManager->m_gameLiftServerSDKWrapperMockPtr->m_onProcessTerminateFunc();
EXPECT_FALSE(AZ::Interface<AzFramework::ISessionHandlingProviderRequests>::Get());
}
TEST_F(GameLiftServerManagerTest, OnHealthCheck_OnSessionHealthCheckReturnsTrue_CallbackFunctionReturnsTrue)
{
m_serverManager->InitializeGameLiftServerSDK();
m_serverManager->NotifyGameLiftProcessReady(GameLiftServerProcessDesc());
SessionNotificationsHandlerMock handlerMock;
EXPECT_CALL(handlerMock, OnSessionHealthCheck()).Times(1).WillOnce(testing::Return(true));
EXPECT_TRUE(m_serverManager->m_gameLiftServerSDKWrapperMockPtr->m_healthCheckFunc());
}
TEST_F(GameLiftServerManagerTest, OnHealthCheck_OnSessionHealthCheckReturnsFalseAndTrue_CallbackFunctionReturnsFalse)
{
m_serverManager->InitializeGameLiftServerSDK();
m_serverManager->NotifyGameLiftProcessReady(GameLiftServerProcessDesc());
SessionNotificationsHandlerMock handlerMock1;
EXPECT_CALL(handlerMock1, OnSessionHealthCheck()).Times(1).WillOnce(testing::Return(false));
SessionNotificationsHandlerMock handlerMock2;
EXPECT_CALL(handlerMock2, OnSessionHealthCheck()).Times(1).WillOnce(testing::Return(true));
EXPECT_FALSE(m_serverManager->m_gameLiftServerSDKWrapperMockPtr->m_healthCheckFunc());
}
TEST_F(GameLiftServerManagerTest, OnHealthCheck_OnSessionHealthCheckReturnsFalse_CallbackFunctionReturnsFalse)
{
m_serverManager->InitializeGameLiftServerSDK();
m_serverManager->NotifyGameLiftProcessReady(GameLiftServerProcessDesc());
SessionNotificationsHandlerMock handlerMock;
EXPECT_CALL(handlerMock, OnSessionHealthCheck()).Times(1).WillOnce(testing::Return(false));
EXPECT_FALSE(m_serverManager->m_gameLiftServerSDKWrapperMockPtr->m_healthCheckFunc());
}
TEST_F(GameLiftServerManagerTest, OnStartGameSession_OnCreateSessionBeginReturnsFalse_TerminationNotificationSent)
{
m_serverManager->InitializeGameLiftServerSDK();
m_serverManager->NotifyGameLiftProcessReady(GameLiftServerProcessDesc());
SessionNotificationsHandlerMock handlerMock;
EXPECT_CALL(handlerMock, OnCreateSessionBegin(testing::_)).Times(1).WillOnce(testing::Return(false));
EXPECT_CALL(handlerMock, OnDestroySessionBegin()).Times(1).WillOnce(testing::Return(true));
EXPECT_CALL(*(m_serverManager->m_gameLiftServerSDKWrapperMockPtr), ProcessEnding()).Times(1);
AZ_TEST_START_TRACE_SUPPRESSION;
m_serverManager->m_gameLiftServerSDKWrapperMockPtr->m_onStartGameSessionFunc(Aws::GameLift::Server::Model::GameSession());
AZ_TEST_STOP_TRACE_SUPPRESSION(1);
}
TEST_F(GameLiftServerManagerTest, OnStartGameSession_ActivateGameSessionSucceeds_RegisterAsHandler)
{
m_serverManager->InitializeGameLiftServerSDK();
m_serverManager->NotifyGameLiftProcessReady(GameLiftServerProcessDesc());
SessionNotificationsHandlerMock handlerMock;
EXPECT_CALL(handlerMock, OnCreateSessionBegin(testing::_)).Times(1).WillOnce(testing::Return(true));
EXPECT_CALL(handlerMock, OnDestroySessionBegin()).Times(1).WillOnce(testing::Return(true));
EXPECT_CALL(*(m_serverManager->m_gameLiftServerSDKWrapperMockPtr), ActivateGameSession())
.Times(1)
.WillOnce(testing::Return(Aws::GameLift::GenericOutcome(nullptr)));
Aws::GameLift::Server::Model::GameSession testSession;
Aws::GameLift::Server::Model::GameProperty testProperty;
testProperty.SetKey("testKey");
testProperty.SetValue("testValue");
testSession.AddGameProperties(testProperty);
m_serverManager->m_gameLiftServerSDKWrapperMockPtr->m_onStartGameSessionFunc(testSession);
EXPECT_TRUE(AZ::Interface<AzFramework::ISessionHandlingProviderRequests>::Get());
m_serverManager->HandleDestroySession();
}
TEST_F(GameLiftServerManagerTest, OnStartGameSession_ActivateGameSessionFails_TerminationNotificationSent)
{
m_serverManager->InitializeGameLiftServerSDK();
m_serverManager->NotifyGameLiftProcessReady(GameLiftServerProcessDesc());
SessionNotificationsHandlerMock handlerMock;
EXPECT_CALL(handlerMock, OnCreateSessionBegin(testing::_)).Times(1).WillOnce(testing::Return(true));
EXPECT_CALL(handlerMock, OnDestroySessionBegin()).Times(1).WillOnce(testing::Return(true));
EXPECT_CALL(*(m_serverManager->m_gameLiftServerSDKWrapperMockPtr), ActivateGameSession())
.Times(1)
.WillOnce(testing::Return(Aws::GameLift::GenericOutcome()));
EXPECT_CALL(*(m_serverManager->m_gameLiftServerSDKWrapperMockPtr), ProcessEnding()).Times(1);
AZ_TEST_START_TRACE_SUPPRESSION;
m_serverManager->m_gameLiftServerSDKWrapperMockPtr->m_onStartGameSessionFunc(Aws::GameLift::Server::Model::GameSession());
AZ_TEST_STOP_TRACE_SUPPRESSION(1);
}
TEST_F(GameLiftServerManagerTest, ValidatePlayerJoinSession_CallWithInvalidConnectionConfig_GetFalseResultAndExpectedErrorLog)
{
AZ_TEST_START_TRACE_SUPPRESSION;
auto result = m_serverManager->ValidatePlayerJoinSession(AzFramework::PlayerConnectionConfig());
AZ_TEST_STOP_TRACE_SUPPRESSION(1);
EXPECT_FALSE(result);
}
TEST_F(GameLiftServerManagerTest, ValidatePlayerJoinSession_CallWithDuplicatedConnectionId_GetFalseResultAndExpectedErrorLog)
{
AzFramework::PlayerConnectionConfig connectionConfig1;
connectionConfig1.m_playerConnectionId = 123;
connectionConfig1.m_playerSessionId = "dummyPlayerSessionId1";
GenericOutcome successOutcome(nullptr);
EXPECT_CALL(*(m_serverManager->m_gameLiftServerSDKWrapperMockPtr), AcceptPlayerSession(testing::_))
.Times(1)
.WillOnce(Return(successOutcome));
m_serverManager->ValidatePlayerJoinSession(connectionConfig1);
AzFramework::PlayerConnectionConfig connectionConfig2;
connectionConfig2.m_playerConnectionId = 123;
connectionConfig2.m_playerSessionId = "dummyPlayerSessionId2";
AZ_TEST_START_TRACE_SUPPRESSION;
auto result = m_serverManager->ValidatePlayerJoinSession(connectionConfig2);
AZ_TEST_STOP_TRACE_SUPPRESSION(1);
EXPECT_FALSE(result);
}
TEST_F(GameLiftServerManagerTest, ValidatePlayerJoinSession_CallWithValidConnectionConfigButErrorOutcome_GetFalseResultAndExpectedErrorLog)
{
AzFramework::PlayerConnectionConfig connectionConfig;
connectionConfig.m_playerConnectionId = 123;
connectionConfig.m_playerSessionId = "dummyPlayerSessionId1";
EXPECT_CALL(*(m_serverManager->m_gameLiftServerSDKWrapperMockPtr), AcceptPlayerSession(testing::_)).Times(1);
AZ_TEST_START_TRACE_SUPPRESSION;
auto result = m_serverManager->ValidatePlayerJoinSession(connectionConfig);
AZ_TEST_STOP_TRACE_SUPPRESSION(1);
EXPECT_FALSE(result);
}
TEST_F(GameLiftServerManagerTest, ValidatePlayerJoinSession_CallWithValidConnectionConfigAndSuccessOutcome_GetTrueResult)
{
AzFramework::PlayerConnectionConfig connectionConfig;
connectionConfig.m_playerConnectionId = 123;
connectionConfig.m_playerSessionId = "dummyPlayerSessionId1";
GenericOutcome successOutcome(nullptr);
EXPECT_CALL(*(m_serverManager->m_gameLiftServerSDKWrapperMockPtr), AcceptPlayerSession(testing::_))
.Times(1)
.WillOnce(Return(successOutcome));
auto result = m_serverManager->ValidatePlayerJoinSession(connectionConfig);
EXPECT_TRUE(result);
}
TEST_F(GameLiftServerManagerTest, ValidatePlayerJoinSession_CallWithFirstErrorSecondSuccess_GetFirstFalseSecondTrueResult)
{
AzFramework::PlayerConnectionConfig connectionConfig1;
connectionConfig1.m_playerConnectionId = 123;
connectionConfig1.m_playerSessionId = "dummyPlayerSessionId1";
GenericOutcome successOutcome(nullptr);
Aws::GameLift::GameLiftError error;
GenericOutcome errorOutcome(error);
EXPECT_CALL(*(m_serverManager->m_gameLiftServerSDKWrapperMockPtr), AcceptPlayerSession(testing::_))
.Times(2)
.WillOnce(Return(errorOutcome))
.WillOnce(Return(successOutcome));
AZ_TEST_START_TRACE_SUPPRESSION;
auto result = m_serverManager->ValidatePlayerJoinSession(connectionConfig1);
AZ_TEST_STOP_TRACE_SUPPRESSION(1);
EXPECT_FALSE(result);
AzFramework::PlayerConnectionConfig connectionConfig2;
connectionConfig2.m_playerConnectionId = 123;
connectionConfig2.m_playerSessionId = "dummyPlayerSessionId2";
result = m_serverManager->ValidatePlayerJoinSession(connectionConfig2);
EXPECT_TRUE(result);
}
TEST_F(GameLiftServerManagerTest, ValidatePlayerJoinSession_CallWithMultithread_GetFirstTrueAndRestFalse)
{
int testThreadNumber = 5;
GenericOutcome successOutcome(nullptr);
EXPECT_CALL(*(m_serverManager->m_gameLiftServerSDKWrapperMockPtr), AcceptPlayerSession(testing::_))
.Times(1)
.WillOnce(Return(successOutcome));
AZStd::vector<AZStd::thread> testThreadPool;
AZStd::atomic<int> trueCount = 0;
for (int index = 0; index < testThreadNumber; index++)
{
testThreadPool.emplace_back(AZStd::thread([&]() {
AzFramework::PlayerConnectionConfig connectionConfig;
connectionConfig.m_playerConnectionId = 123;
connectionConfig.m_playerSessionId = "dummyPlayerSessionId";
auto result = m_serverManager->ValidatePlayerJoinSession(connectionConfig);
if (result)
{
trueCount++;
}
}));
}
for (auto& testThread : testThreadPool)
{
testThread.join();
}
EXPECT_TRUE(trueCount == 1);
}
TEST_F(GameLiftServerManagerTest, HandlePlayerLeaveSession_CallWithInvalidConnectionConfig_GetExpectedErrorLog)
{
EXPECT_CALL(*(m_serverManager->m_gameLiftServerSDKWrapperMockPtr), RemovePlayerSession(testing::_)).Times(0);
AZ_TEST_START_TRACE_SUPPRESSION;
m_serverManager->HandlePlayerLeaveSession(AzFramework::PlayerConnectionConfig());
AZ_TEST_STOP_TRACE_SUPPRESSION(1);
}
TEST_F(GameLiftServerManagerTest, HandlePlayerLeaveSession_CallWithNonExistentPlayerConnectionId_GetExpectedErrorLog)
{
AzFramework::PlayerConnectionConfig connectionConfig;
connectionConfig.m_playerConnectionId = 123;
connectionConfig.m_playerSessionId = "dummyPlayerSessionId";
auto result = m_serverManager->AddConnectedTestPlayer(connectionConfig);
EXPECT_TRUE(result);
AzFramework::PlayerConnectionConfig connectionConfig1;
connectionConfig1.m_playerConnectionId = 456;
connectionConfig1.m_playerSessionId = "dummyPlayerSessionId";
EXPECT_CALL(*(m_serverManager->m_gameLiftServerSDKWrapperMockPtr), RemovePlayerSession(testing::_)).Times(0);
AZ_TEST_START_TRACE_SUPPRESSION;
m_serverManager->HandlePlayerLeaveSession(connectionConfig1);
AZ_TEST_STOP_TRACE_SUPPRESSION(1);
}
TEST_F(GameLiftServerManagerTest, HandlePlayerLeaveSession_CallWithValidConnectionConfigButErrorOutcome_GetExpectedErrorLog)
{
AzFramework::PlayerConnectionConfig connectionConfig;
connectionConfig.m_playerConnectionId = 123;
connectionConfig.m_playerSessionId = "dummyPlayerSessionId";
auto result = m_serverManager->AddConnectedTestPlayer(connectionConfig);
EXPECT_TRUE(result);
Aws::GameLift::GameLiftError error;
GenericOutcome errorOutcome(error);
EXPECT_CALL(*(m_serverManager->m_gameLiftServerSDKWrapperMockPtr), RemovePlayerSession(testing::_))
.Times(1)
.WillOnce(Return(errorOutcome));
AZ_TEST_START_TRACE_SUPPRESSION;
m_serverManager->HandlePlayerLeaveSession(connectionConfig);
AZ_TEST_STOP_TRACE_SUPPRESSION(1);
}
TEST_F(GameLiftServerManagerTest, HandlePlayerLeaveSession_CallWithValidConnectionConfigAndSuccessOutcome_RemovePlayerSessionNotificationSent)
{
AzFramework::PlayerConnectionConfig connectionConfig;
connectionConfig.m_playerConnectionId = 123;
connectionConfig.m_playerSessionId = "dummyPlayerSessionId";
auto result = m_serverManager->AddConnectedTestPlayer(connectionConfig);
EXPECT_TRUE(result);
GenericOutcome successOutcome(nullptr);
EXPECT_CALL(*(m_serverManager->m_gameLiftServerSDKWrapperMockPtr), RemovePlayerSession(testing::_))
.Times(1)
.WillOnce(Return(successOutcome));
m_serverManager->HandlePlayerLeaveSession(connectionConfig);
}
TEST_F(GameLiftServerManagerTest, HandlePlayerLeaveSession_CallWithMultithread_OnlyOneNotificationIsSent)
{
AzFramework::PlayerConnectionConfig connectionConfig;
connectionConfig.m_playerConnectionId = 123;
connectionConfig.m_playerSessionId = "dummyPlayerSessionId";
auto result = m_serverManager->AddConnectedTestPlayer(connectionConfig);
EXPECT_TRUE(result);
int testThreadNumber = 5;
GenericOutcome successOutcome(nullptr);
EXPECT_CALL(*(m_serverManager->m_gameLiftServerSDKWrapperMockPtr), RemovePlayerSession(testing::_))
.Times(1)
.WillOnce(Return(successOutcome));
AZStd::vector<AZStd::thread> testThreadPool;
AZStd::atomic<int> trueCount = 0;
AZ_TEST_START_TRACE_SUPPRESSION;
for (int index = 0; index < testThreadNumber; index++)
{
testThreadPool.emplace_back(AZStd::thread(
[&]()
{
m_serverManager->HandlePlayerLeaveSession(connectionConfig);
}));
}
for (auto& testThread : testThreadPool)
{
testThread.join();
}
AZ_TEST_STOP_TRACE_SUPPRESSION(testThreadNumber - 1); // The player is only disconnected once.
}
} // namespace UnitTest

@ -0,0 +1,127 @@
/*
* 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 <AWSGameLiftServerSystemComponent.h>
#include <AWSGameLiftServerManager.h>
#include <GameLiftServerSDKWrapper.h>
#include <AzCore/UnitTest/TestTypes.h>
#include <AzCore/std/smart_ptr/make_shared.h>
using namespace Aws::GameLift;
using namespace AWSGameLift;
using testing::_;
using testing::Invoke;
using testing::Return;
using testing::NiceMock;
using testing::Eq;
namespace UnitTest
{
class GameLiftServerSDKWrapperMock
: public GameLiftServerSDKWrapper
{
public:
GameLiftServerSDKWrapperMock()
{
GenericOutcome successOutcome(nullptr);
Server::InitSDKOutcome sdkOutcome(nullptr);
ON_CALL(*this, InitSDK()).WillByDefault(Return(sdkOutcome));
ON_CALL(*this, ProcessReady(_)).WillByDefault(Invoke(this, &GameLiftServerSDKWrapperMock::ProcessReadyMock));
ON_CALL(*this, ProcessEnding()).WillByDefault(Return(successOutcome));
}
MOCK_METHOD1(AcceptPlayerSession, GenericOutcome(const std::string&));
MOCK_METHOD0(ActivateGameSession, GenericOutcome());
MOCK_METHOD0(InitSDK, Server::InitSDKOutcome());
MOCK_METHOD1(ProcessReady, GenericOutcome(const Server::ProcessParameters& processParameters));
MOCK_METHOD0(ProcessEnding, GenericOutcome());
MOCK_METHOD1(RemovePlayerSession, GenericOutcome(const AZStd::string& playerSessionId));
MOCK_METHOD0(GetTerminationTime, AZStd::string());
GenericOutcome ProcessReadyMock(const Server::ProcessParameters& processParameters)
{
m_healthCheckFunc = processParameters.getOnHealthCheck();
m_onStartGameSessionFunc = processParameters.getOnStartGameSession();
m_onProcessTerminateFunc = processParameters.getOnProcessTerminate();
GenericOutcome successOutcome(nullptr);
return successOutcome;
}
AZStd::function<bool()> m_healthCheckFunc;
AZStd::function<void()> m_onProcessTerminateFunc;
AZStd::function<void(Aws::GameLift::Server::Model::GameSession)> m_onStartGameSessionFunc;
};
class AWSGameLiftServerManagerMock
: public AWSGameLiftServerManager
{
public:
AWSGameLiftServerManagerMock()
{
AZStd::unique_ptr<NiceMock<GameLiftServerSDKWrapperMock>> gameLiftServerSDKWrapper =
AZStd::make_unique<NiceMock<GameLiftServerSDKWrapperMock>>();
m_gameLiftServerSDKWrapperMockPtr = gameLiftServerSDKWrapper.get();
SetGameLiftServerSDKWrapper(AZStd::move(gameLiftServerSDKWrapper));
}
~AWSGameLiftServerManagerMock()
{
m_gameLiftServerSDKWrapperMockPtr = nullptr;
}
bool AddConnectedTestPlayer(const AzFramework::PlayerConnectionConfig& playerConnectionConfig)
{
return AddConnectedPlayer(playerConnectionConfig);
}
NiceMock<GameLiftServerSDKWrapperMock>* m_gameLiftServerSDKWrapperMockPtr;
};
class AWSGameLiftServerSystemComponentMock
: public AWSGameLift::AWSGameLiftServerSystemComponent
{
public:
AWSGameLiftServerSystemComponentMock()
{
SetGameLiftServerManager(AZStd::make_unique<NiceMock<AWSGameLiftServerManagerMock>>());
ON_CALL(*this, Init()).WillByDefault(testing::Invoke(this, &AWSGameLiftServerSystemComponentMock::InitMock));
ON_CALL(*this, Activate()).WillByDefault(testing::Invoke(this, &AWSGameLiftServerSystemComponentMock::ActivateMock));
ON_CALL(*this, Deactivate()).WillByDefault(testing::Invoke(this, &AWSGameLiftServerSystemComponentMock::DeactivateMock));
}
void InitMock()
{
AWSGameLift::AWSGameLiftServerSystemComponent::Init();
}
void ActivateMock()
{
AWSGameLift::AWSGameLiftServerSystemComponent::Activate();
}
void DeactivateMock()
{
AWSGameLift::AWSGameLiftServerSystemComponent::Deactivate();
}
MOCK_METHOD0(Init, void());
MOCK_METHOD0(Activate, void());
MOCK_METHOD0(Deactivate, void());
GameLiftServerProcessDesc m_serverProcessDesc;
};
};

@ -0,0 +1,99 @@
/*
* 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 <AWSGameLiftServerFixture.h>
#include <AWSGameLiftServerMocks.h>
#include <AzCore/Component/Entity.h>
#include <AzCore/Serialization/EditContext.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/UnitTest/TestTypes.h>
#include <AzFramework/IO/LocalFileIO.h>
#include <AzTest/AzTest.h>
namespace UnitTest
{
class AWSGameLiftServerSystemComponentTest
: public AWSGameLiftServerFixture
{
public:
void SetUp() override
{
AWSGameLiftServerFixture::SetUp();
m_serializeContext = AZStd::make_unique<AZ::SerializeContext>();
m_serializeContext->CreateEditContext();
m_behaviorContext = AZStd::make_unique<AZ::BehaviorContext>();
m_componentDescriptor.reset(AWSGameLift::AWSGameLiftServerSystemComponent::CreateDescriptor());
m_componentDescriptor->Reflect(m_serializeContext.get());
m_componentDescriptor->Reflect(m_behaviorContext.get());
m_entity = aznew AZ::Entity();
m_AWSGameLiftServerSystemsComponent = aznew NiceMock<AWSGameLiftServerSystemComponentMock>();
m_entity->AddComponent(m_AWSGameLiftServerSystemsComponent);
// Set up the file IO and alias
m_localFileIO = aznew AZ::IO::LocalFileIO();
m_priorFileIO = AZ::IO::FileIOBase::GetInstance();
AZ::IO::FileIOBase::SetInstance(nullptr);
AZ::IO::FileIOBase::SetInstance(m_localFileIO);
m_localFileIO->SetAlias("@log@", AZ_TRAIT_TEST_ROOT_FOLDER);
}
void TearDown() override
{
AZ::IO::FileIOBase::SetInstance(nullptr);
delete m_localFileIO;
AZ::IO::FileIOBase::SetInstance(m_priorFileIO);
m_entity->RemoveComponent(m_AWSGameLiftServerSystemsComponent);
delete m_AWSGameLiftServerSystemsComponent;
delete m_entity;
m_componentDescriptor.reset();
m_behaviorContext.reset();
m_serializeContext.reset();
AWSGameLiftServerFixture::TearDown();
}
AZStd::unique_ptr<AZ::ComponentDescriptor> m_componentDescriptor;
AZStd::unique_ptr<AZ::SerializeContext> m_serializeContext;
AZStd::unique_ptr<AZ::BehaviorContext> m_behaviorContext;
AZ::Entity* m_entity;
NiceMock<AWSGameLiftServerSystemComponentMock>* m_AWSGameLiftServerSystemsComponent;
AZ::IO::FileIOBase* m_priorFileIO;
AZ::IO::FileIOBase* m_localFileIO;
};
TEST_F(AWSGameLiftServerSystemComponentTest, ActivateDeactivateComponent_ExecuteInOrder_Success)
{
testing::Sequence s1, s2;
EXPECT_CALL(*m_AWSGameLiftServerSystemsComponent, Init()).Times(1).InSequence(s1);
EXPECT_CALL(*m_AWSGameLiftServerSystemsComponent, Activate()).Times(1).InSequence(s1);
EXPECT_CALL(*m_AWSGameLiftServerSystemsComponent, Deactivate()).Times(1).InSequence(s2);
// activate component
m_entity->Init();
m_entity->Activate();
// deactivate component
m_entity->Deactivate();
}
} // namespace UnitTest

@ -0,0 +1,15 @@
/*
* 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 <AzTest/AzTest.h>
AZ_UNIT_TEST_HOOK(DEFAULT_UNIT_TEST_ENV);

@ -0,0 +1,20 @@
#
# 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.
#
set(FILES
../AWSGameLiftCommon/Source/AWSGameLiftSessionConstants.h
Source/AWSGameLiftServerManager.cpp
Source/AWSGameLiftServerManager.h
Source/AWSGameLiftServerSystemComponent.cpp
Source/AWSGameLiftServerSystemComponent.h
Source/GameLiftServerSDKWrapper.cpp
Source/GameLiftServerSDKWrapper.h
)

@ -0,0 +1,14 @@
#
# 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.
#
set(FILES
Source/AWSGameLiftServerModule.cpp
)

@ -0,0 +1,18 @@
#
# 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.
#
set(FILES
Tests/AWSGameLiftServerFixture.h
Tests/AWSGameLiftServerMocks.h
Tests/AWSGameLiftServerManagerTest.cpp
Tests/AWSGameLiftServerTest.cpp
Tests/AWSGameLiftServerSystemComponentTest.cpp
)

@ -0,0 +1,13 @@
#
# 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.
#
add_subdirectory(AWSGameLiftClient)
add_subdirectory(AWSGameLiftServer)

@ -0,0 +1,10 @@
*.swp
package-lock.json
__pycache__
.pytest_cache
.env
*.egg-info
# CDK asset staging directory
.cdk.staging
cdk.out

@ -0,0 +1,99 @@
# Welcome to O3DE GameLift Sample Project!
This is an optional CDK application that provides two stacks:
* A GameLift stack that contains all the GameLift resources required to host game servers
* An optional support stack which is used to upload local build files and create GameLift builds
The `cdk.json` file tells the CDK Toolkit how to execute this application.
This project is set up like a standard Python project. The initialization
process also creates a virtualenv within this project, stored under the `.env`
directory. To create the virtualenv it assumes that there is a `python3`
(or `python` for Windows) (Python 3.7+) executable in your path with access to the `venv`
package. If for any reason the automatic creation of the virtualenv fails,
you can create the virtualenv manually.
See https://docs.aws.amazon.com/cdk/latest/guide/getting_started.html about for information about how to set up
the prerequisites for CDK development.
To manually create a virtualenv on MacOS and Linux:
```
$ python -m venv .env
```
Once the virtualenv is created, you can use the following step to activate your virtualenv.
```
$ source .env/bin/activate
```
If you are a Windows platform, you would activate the virtualenv like this:
```
% .env\Scripts\activate.bat
```
Once the virtualenv is activated, you can install the required dependencies.
```
$ pip install -r requirements.txt
```
## Set environment variables or accept defaults
* O3DE_AWS_DEPLOY_REGION*: The region to deploy the stacks into, will default to CDK_DEFAULT_REGION
* O3DE_AWS_DEPLOY_ACCOUNT*: The account to deploy stacks into, will default to CDK_DEFAULT_ACCOUNT
* O3DE_AWS_PROJECT_NAME*: The name of the O3DE project stacks should be deployed for will default to AWS-PROJECT
See https://docs.aws.amazon.com/cdk/latest/guide/environments.html for more information including how to pass parameters
to use for environment variables.
## Edit the sample fleet configurations
Before deploy the CDK application, please update the sample fleet configurations defined in the
[sample fleet configurations](aws_gamelift/fleet_configurations.py)
with project specific settings.
## Synthesize the project
At this point you can now synthesize the CloudFormation template for this code.
```
$ cdk synth
```
## Optional features
To create a game session queue using this CDK application, provide the following context variable
when synthesize the CloudFormation template or deploy the application:
```
$ cdk deploy -c create_game_session_queue=true
```
You can also deploy a support stack which is used to upload local build files to S3 and provide GameLift access
to the S3 objects when create GameLift builds:
```
$ cdk deploy -c upload-with-support-stack=true --all
```
You may need todo a one time bootstrap, once per account, per region. The CDK application will prompt you on this.
To add additional dependencies, for example other CDK libraries, just add
them to your `setup.py` file and rerun the `pip install -r requirements.txt`
command.
## Useful commands
* `cdk ls` list all stacks in the app
* `cdk synth` emits the synthesized CloudFormation template
* `cdk deploy` deploy this stack to your default AWS account/region
* `cdk diff` compare deployed stack with current state
* `cdk docs` open CDK documentation
## GameLift reference and best practise
https://docs.aws.amazon.com/gamelift/index.html

@ -0,0 +1,53 @@
#!/usr/bin/env python3
"""
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.
"""
import os
from aws_cdk import core
from aws_gamelift.aws_gamelift_construct import AWSGameLift
"""Configuration"""
REGION = os.environ.get('O3DE_AWS_DEPLOY_REGION', os.environ.get('CDK_DEFAULT_REGION'))
ACCOUNT = os.environ.get('O3DE_AWS_DEPLOY_ACCOUNT', os.environ.get('CDK_DEFAULT_ACCOUNT'))
# Set the common prefix to group stacks in a project together.
PROJECT_NAME = os.environ.get('O3DE_AWS_PROJECT_NAME', f'O3DE-AWS-PROJECT').upper()
# The name of this feature
FEATURE_NAME = 'AWSGameLift'
# The name of this CDK application
PROJECT_FEATURE_NAME = f'{PROJECT_NAME}-{FEATURE_NAME}'
# Standard Tag Key for project based tags
O3DE_PROJECT_TAG_NAME = 'O3DEProject'
# Standard Tag Key for feature based tags
O3DE_FEATURE_TAG_NAME = 'O3DEFeature'
"""End of Configuration"""
# Set-up regions to deploy stack to, or use default if not set
env = core.Environment(
account=ACCOUNT,
region=REGION)
app = core.App()
feature_struct = AWSGameLift(
app,
id_=PROJECT_FEATURE_NAME,
project_name=PROJECT_NAME,
feature_name=FEATURE_NAME,
tags={O3DE_PROJECT_TAG_NAME: PROJECT_NAME, O3DE_FEATURE_TAG_NAME: FEATURE_NAME},
env=env
)
app.synth()

@ -0,0 +1,10 @@
"""
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.
"""

@ -0,0 +1,59 @@
"""
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.
"""
import copy
from aws_cdk import core
from aws_gamelift.fleet_configurations import FLEET_CONFIGURATIONS
from aws_gamelift.gamelift_stack import GameLiftStack
from aws_gamelift.support_stack import SupportStack
class AWSGameLift(core.Construct):
"""
Orchestrates setting up the AWS GameLift Stack(s)
"""
def __init__(self,
scope: core.Construct,
id_: str,
project_name: str,
feature_name: str,
tags: dict,
env: core.Environment) -> None:
super().__init__(scope, id_)
stack_name = f'{project_name}-{feature_name}-{env.region}'
fleet_configurations = copy.deepcopy(FLEET_CONFIGURATIONS)
if self.node.try_get_context('upload-with-support-stack') == 'true':
# Create an optional support stack for generating GameLift builds with local build files
self._support_stack = SupportStack(
scope,
f'{stack_name}-Support',
stack_name=stack_name,
fleet_configurations=fleet_configurations,
description='(Optional) Contains resources for creating GameLift builds with local files',
tags=tags,
env=env
)
# Create the GameLift Stack
self._feature_stack = GameLiftStack(
scope,
f'{stack_name}',
stack_name=stack_name,
fleet_configurations=fleet_configurations,
create_game_session_queue=self.node.try_get_context('create_game_session_queue') == 'true',
description=f'Contains resources for the AWS GameLift Gem stack as part of the {project_name} project',
tags=tags,
env=env
)

@ -0,0 +1,147 @@
"""
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.
"""
# Configurations for the fleets to deploy.
# Modify the fleet configuration fields below before deploying the CDK application.
# To select the right combination of hosting resources and learn how to configure them to best suit to your application,
# please check: https://docs.aws.amazon.com/gamelift/latest/developerguide/fleets-design.html
FLEET_CONFIGURATIONS = [
{
# (Optional) An alias for an Amazon GameLift fleet destination.
# By using aliases instead of specific fleet IDs, customers can more easily and seamlessly switch
# player traffic from one fleet to another by changing the alias's target location.
'alias_configuration': {
# (Required) A descriptive label that is associated with an alias. Alias names do not need to be unique.
'name': '<alias name>',
# (Conditional) A type of routing strategy for the GameLift fleet alias if exists.
# Required if alias_configuration is provided.
'routing_strategy': {
# The message text to be used with a terminal routing strategy.
# If you specify TERMINAL for the Type property, you must specify this property.
# Required if specify TERMINAL for the Type property,
'message': '<routing strategy message>',
# (Required) A type of routing strategy.
'type': 'SIMPLE | TERMINAL'
}
},
# (Required) Information about a game server build that is installed and
# run on instances in an Amazon GameLift fleet.
'build_configuration': {
# (Conditional) A unique identifier for a build to be deployed on the new fleet.
# This parameter is required unless the parameters build_path and operating_system are defined and
# the conditional variable upload-with-support-stack is set to true
'build_id': '<build id>',
# (Conditional) The disk location of the local build file(zip).
# This parameter is required unless the parameter build_id is defined.
'build_path': '<build path>',
# (Conditional) The operating system that the game server binaries are built to run on.
# This parameter is required if the parameter build_path is defined.
'operating_system': 'AMAZON_LINUX | AMAZON_LINUX_2 | WINDOWS_2012'
},
# (Optional) Information about the use of a TLS/SSL certificate for a fleet.
'certificate_configuration': {
# (Required) Indicates whether a TLS/SSL certificate is generated for the fleet.
'certificate_type': 'DISABLED | GENERATED',
},
# A human-readable description of the fleet.
'description': 'Amazon GameLift fleet to host game servers.',
# (Optional) A range of IP addresses and port settings that allow inbound traffic to connect to
# server processes on an Amazon GameLift server.
# This should be the same port range as the server is configured for.
'ec2_inbound_permissions': [
{
# (Required) A starting value for a range of allowed port numbers.
# 30090 is the default server port defined by the Multiplayer Gem.
'from_port': 30090,
# (Required) A range of allowed IP addresses.
'ip_range': '<ip range>',
# (Required) The network communication protocol used by the fleet.
'protocol': 'UDP',
# (Required) An ending value for a range of allowed port numbers.
'to_port': 30090
},
{
# Open the debug port for remote into a Windows fleet.
'from_port': 3389,
'ip_range': '<external ip range>',
'protocol': 'TCP',
'to_port': 3389
},
{
# Open the debug port for remote into a Linux fleet.
'from_port': 22,
'ip_range': '<external ip range>',
'protocol': 'TCP',
'to_port': 22
}
],
# (Optional) The GameLift-supported EC2 instance type to use for all fleet instances.
'ec2_instance_type': 'c3.2xlarge | c3.4xlarge | c3.8xlarge | c3.large | c3.xlarge | c4.2xlarge | c4.4xlarge |'
' c4.8xlarge | c4.large | c4.xlarge | c5.12xlarge | c5.18xlarge | c5.24xlarge |'
' c5.2xlarge | c5.4xlarge | c5.9xlarge | c5.large | c5.xlarge | c5a.12xlarge |'
' c5a.16xlarge | c5a.24xlarge | c5a.2xlarge | c5a.4xlarge | c5a.8xlarge | c5a.large |'
' c5a.xlarge | m3.2xlarge | m3.large | m3.medium | m3.xlarge | m4.10xlarge | m4.2xlarge |'
' m4.4xlarge | m4.large | m4.xlarge | m5.12xlarge | m5.16xlarge | m5.24xlarge |'
' m5.2xlarge | m5.4xlarge | m5.8xlarge | m5.large | m5.xlarge | m5a.12xlarge |'
' m5a.16xlarge | m5a.24xlarge | m5a.2xlarge | m5a.4xlarge | m5a.8xlarge | m5a.large |'
' m5a.xlarge | r3.2xlarge | r3.4xlarge | r3.8xlarge | r3.large | r3.xlarge | r4.16xlarge |'
' r4.2xlarge | r4.4xlarge | r4.8xlarge | r4.large | r4.xlarge | r5.12xlarge |'
' r5.16xlarge | r5.24xlarge | r5.2xlarge | r5.4xlarge | r5.8xlarge | r5.large |'
' r5.xlarge | r5a.12xlarge | r5a.16xlarge | r5a.24xlarge | r5a.2xlarge | r5a.4xlarge |'
' r5a.8xlarge | r5a.large | r5a.xlarge | t2.large | t2.medium | t2.micro | t2.small',
# (Optional) Indicates whether to use On-Demand or Spot instances for this fleet.
'fleet_type': 'ON_DEMAND | SPOT',
# (Optional) A game session protection policy to apply to all game sessions hosted on instances in this fleet.
'new_game_session_protection_policy': 'FullProtection | NoProtection',
# (Optional) A policy that limits the number of game sessions that an individual player
# can create on instances in this fleet within a specified span of time.
'resource_creation_limit_policy': {
# (Optional) The maximum number of game sessions that an individual can create during the policy period.
# Provide any integer not less than 0.
'new_game_sessions_per_creator': 3,
# (Optional) The time span used in evaluating the resource creation limit policy.
# Provide any integer not less than 0.
'policy_period_in_minutes': 15
},
# (Conditional) Instructions for launching server processes on each instance in the fleet.
# This parameter is required unless the parameters ServerLaunchPath and ServerLaunchParameters are defined.
'runtime_configuration': {
# (Optional) The maximum amount of time (in seconds) allowed to launch a new game session and
# have it report ready to host players.
# Provide an integer from 1 to 600.
'game_session_activation_timeout_seconds': 300,
# (Optional) The number of game sessions in status ACTIVATING to allow on an instance.
# Provide an integer from 1 to 2147483647.
'max_concurrent_game_session_activations': 2,
# (Optional) A collection of server process configurations that identify what server processes
# to run on each instance in a fleet. To set up a fleet's runtime configuration to
# run multiple game server processes per instance, please check the following document:
# https://docs.aws.amazon.com/gamelift/latest/developerguide/fleets-multiprocess.html
'server_processes': [
{
# (Required) The number of server processes using this configuration that
# run concurrently on each instance.
# Provide any integer not less than 1.
'concurrent_executions': 1,
# (Required) The location of a game build executable or the Realtime script file that
# contains the Init() function.
'launch_path': '(Windows) <C:\\game\\<executable or script> | '
'(Linux) /local/game/MyGame/<executable or script>',
# (Optional) An optional list of parameters to pass to the server executable
# or Realtime script on launch.
'parameters': '<launch parameters>'
}
]
}
# For additional fleet configurations, please check:
# # https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_GameLift.html
}
]

@ -0,0 +1,184 @@
"""
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.
"""
import typing
from aws_cdk import core
from aws_cdk import aws_gamelift as gamelift
class GameLiftStack(core.Stack):
"""
The AWS GameLift stack
Defines GameLift resources to use in project
"""
def __init__(self, scope: core.Construct, id_: str,
stack_name: str, fleet_configurations: dict,
create_game_session_queue: bool, **kwargs) -> None:
super().__init__(scope, id_, **kwargs)
self._stack_name = stack_name
fleet_ids = []
queue_destinations = []
for index in range(len(fleet_configurations)):
fleet_configuration = fleet_configurations[index]
# Create a new GameLift fleet using the configuration
fleet_ids.append(self._create_fleet(fleet_configuration, index).attr_fleet_id)
destination_arn = core.Fn.sub(
body='arn:${AWS::Partition}:gamelift:${AWS::Region}::fleet/${FleetId}',
variables={
'FleetId': fleet_ids[index],
}
)
if fleet_configuration.get('alias_configuration'):
# Create an alias for the fleet if the alias configuration is provided
alias = self._create_alias(fleet_configuration['alias_configuration'], fleet_ids[index])
destination_arn = core.Fn.sub(
body='arn:${AWS::Partition}:gamelift:${AWS::Region}::alias/${AliasId}',
variables={
'AliasId': alias.attr_alias_id,
}
)
queue_destinations.append(destination_arn)
# Export the GameLift fleet ids as a stack output
fleets_output = core.CfnOutput(
self,
id='GameLiftFleets',
description='List of GameLift fleet ids',
export_name=f'{self._stack_name}:GameLiftFleets',
value=','.join(fleet_ids)
)
if create_game_session_queue:
# Create a game session queue which fulfills game session placement requests using the fleets
game_session_queue = self._create_game_session_queue(queue_destinations)
# Export the game session queue name as a stack output
game_session_queue_output = core.CfnOutput(
self,
id='GameSessionQueue',
description='Name of the game session queue',
export_name=f'{self._stack_name}:GameSessionQueue',
value=game_session_queue.name)
def _create_fleet(self, fleet_configuration: dict, identifier: int) -> gamelift.CfnFleet:
"""
Create an Amazon GameLift fleet to host game servers.
:param fleet_configuration: Configuration of the fleet.
:param identifier: Unique identifier of the fleet which will be included in the resource id.
:return: Generated GameLift fleet.
"""
fleet = gamelift.CfnFleet(
self,
id=f'{self._stack_name}-GameLiftFleet{identifier}',
build_id=self._get_gamelift_build_id(fleet_configuration.get('build_configuration', {}), identifier),
certificate_configuration=gamelift.CfnFleet.CertificateConfigurationProperty(
certificate_type=fleet_configuration['certificate_configuration'].get('certificate_type')
) if fleet_configuration.get('certificate_configuration') else None,
description=fleet_configuration.get('description'),
ec2_inbound_permissions=[
gamelift.CfnFleet.IpPermissionProperty(
**inbound_permission
) for inbound_permission in fleet_configuration.get('ec2_inbound_permissions', [])
],
ec2_instance_type=fleet_configuration.get('ec2_instance_type'),
fleet_type=fleet_configuration.get('fleet_type'),
name=f'{self._stack_name}-GameLiftFleet{identifier}',
new_game_session_protection_policy=fleet_configuration.get('new_game_session_protection_policy'),
resource_creation_limit_policy=gamelift.CfnFleet.ResourceCreationLimitPolicyProperty(
**fleet_configuration['resource_creation_limit_policy']
) if fleet_configuration.get('resource_creation_limit_policy') else None,
runtime_configuration=gamelift.CfnFleet.RuntimeConfigurationProperty(
game_session_activation_timeout_seconds=fleet_configuration['runtime_configuration'].get(
'game_session_activation_timeout_seconds'),
max_concurrent_game_session_activations=fleet_configuration['runtime_configuration'].get(
'max_concurrent_game_session_activations'),
server_processes=[
gamelift.CfnFleet.ServerProcessProperty(
**server_process
) for server_process in fleet_configuration['runtime_configuration'].get('server_processes', [])
]
) if fleet_configuration.get('runtime_configuration') else None,
)
return fleet
def _get_gamelift_build_id(self, build_configuration: dict, identifier: int) -> str:
"""
Get the GameLift build id.
Create the GameLift build from the storage location information if the build doesn't exist.
:param build_configuration: Configuration of the GameLift build.
:param identifier: Unique identifier of the build which will be included in the resource id.
:return: Build id.
"""
if build_configuration.get('build_id'):
# GameLift build already exists
return build_configuration['build_id']
elif build_configuration.get('storage_location'):
# Create the GameLift build using the storage location information.
build = gamelift.CfnBuild(
self,
id=f'{self._stack_name}-GameLiftBuild{identifier}',
name=f'{self._stack_name}-GameLiftBuild{identifier}',
operating_system=build_configuration.get('operating_system'),
storage_location=gamelift.CfnBuild.S3LocationProperty(
**build_configuration['storage_location']
)
)
return build.ref
return ''
def _create_alias(self, alias_configuration: dict, fleet_id: str) -> gamelift.CfnAlias:
"""
Create an alias for an Amazon GameLift fleet destination.
:param alias_configuration: Configuration of the alias
:param fleet_id: Fleet id that the alias points to.
:return: Generated GameLift fleet alias.
"""
alias = gamelift.CfnAlias(
self,
id=f'{self._stack_name}-GameLiftAlias',
name=alias_configuration.get('name'),
routing_strategy=gamelift.CfnAlias.RoutingStrategyProperty(
**alias_configuration.get('routing_strategy', {}),
fleet_id=fleet_id
)
)
return alias
def _create_game_session_queue(self, destinations: typing.List) -> gamelift.CfnGameSessionQueue:
"""
Create a placement queue that processes requests for new game sessions.
:param destinations: Destinations of the queue.
:return: Generated GameLift game session queue.
"""
game_session_queue = gamelift.CfnGameSessionQueue(
self,
id=f'{self._stack_name}-GameLiftQueue',
name=f'{self._stack_name}-game-session-queue',
destinations=[
gamelift.CfnGameSessionQueue.DestinationProperty(
destination_arn=resource_arn
) for resource_arn in destinations
]
)
return game_session_queue

@ -0,0 +1,71 @@
"""
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.
"""
from aws_cdk import aws_iam as iam
from aws_cdk import aws_s3_assets as assets
from aws_cdk import core
class SupportStack(core.Stack):
"""
The support stack
Defines AWS resources that help to create GameLift builds from local files
"""
def __init__(self, scope: core.Construct, id_: str,
stack_name: str, fleet_configurations: dict, **kwargs) -> None:
super().__init__(scope, id_, **kwargs)
self._stack_name = stack_name
self._support_iam_role = self._create_support_iam_role()
for index in range(len(fleet_configurations)):
# Update the fleet configuration to include the corresponding build id
fleet_configurations[index]['build_configuration']['storage_location'] = self._upload_build_asset(
fleet_configurations[index].get('build_configuration', {}), index)
def _create_support_iam_role(self) -> iam.Role:
"""
Create an IAM role for GameLift to read build files stored in S3.
:return: Generated IAM role.
"""
support_role = iam.Role(
self,
id=f'{self._stack_name}-SupportRole',
assumed_by=iam.ServicePrincipal(
service='gamelift.amazonaws.com'
)
)
return support_role
def _upload_build_asset(self, build_configuration: dict, identifier: int) -> dict:
"""
Upload the local build files to S3 for a creating GameLift build.
:param build_configuration: Configuration of the GameLift build.
:param identifier: Unique identifier of the asset which will be included in the resource id.
:return: Storage location of the S3 object.
"""
build_asset = assets.Asset(
self,
id=f'{self._stack_name}-Asset{identifier}',
path=build_configuration.get('build_path')
)
# Grant the support IAM role permission to read the asset
build_asset.grant_read(self._support_iam_role)
storage_location = {
'bucket': build_asset.s3_bucket_name,
'key': build_asset.s3_object_key,
'role_arn': self._support_iam_role.role_arn
}
return storage_location

@ -0,0 +1,17 @@
{
"app": "python app.py",
"context": {
"@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true,
"@aws-cdk/core:enableStackNameDuplicates": "true",
"aws-cdk:enableDiffNoFail": "true",
"@aws-cdk/core:stackRelativeExports": "true",
"@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true,
"@aws-cdk/aws-secretsmanager:parseOwnedSecretName": true,
"@aws-cdk/aws-kms:defaultKeyPolicies": true,
"@aws-cdk/aws-s3:grantWriteWithoutAcl": true,
"@aws-cdk/aws-ecs-patterns:removeDefaultDesiredCount": true,
"@aws-cdk/aws-rds:lowercaseDbIdentifier": true,
"@aws-cdk/aws-efs:defaultEncryptionAtRest": true,
"@aws-cdk/aws-lambda:recognizeVersionProps": true
}
}

@ -0,0 +1,4 @@
aws-cdk.core>=1.91.0
aws-cdk.aws_gamelift>=1.91.0
aws-cdk.aws_iam>=1.91.0
aws-cdk.aws_s3_assets>=1.91.0

@ -0,0 +1,14 @@
{
"gem_name": "AWSGameLift",
"origin": "The primary repo for AWSGameLift goes here: i.e. http://www.mydomain.com",
"license": "What license AWSGameLift uses goes here: i.e. https://opensource.org/licenses/MIT",
"display_name": "AWSGameLift",
"summary": "The AWSGameLift Gem provides a framework to extend O3DE networking layer to work with GameLift resources via GameLift server and client SDK.",
"canonical_tags": [
"Gem"
],
"user_tags": [
"AWSGameLift"
],
"icon_path": "preview.png"
}

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:7aca75b5e82f55478f4f8c575d384ff3ef67260dde2107bd45d377516e6104f7
size 22196

@ -18,6 +18,7 @@
"Gems/AutomatedLauncherTesting", "Gems/AutomatedLauncherTesting",
"Gems/AWSClientAuth", "Gems/AWSClientAuth",
"Gems/AWSCore", "Gems/AWSCore",
"Gems/AWSGameLift",
"Gems/AWSMetrics", "Gems/AWSMetrics",
"Gems/Blast", "Gems/Blast",
"Gems/Camera", "Gems/Camera",

Loading…
Cancel
Save