/* * 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 defined(BUILD_GAMELIFT_CLIENT) #include "GameLift_Traits.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace { //This is used when a playerId is not specified when initializing GameLiftSDK with developer credentials. const char* DEFAULT_PLAYER_ID = "AnonymousPlayerId"; const char* FAKE_FLEET_ID = "fleet-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"; } namespace GridMate { namespace Platform { void ResolveCaCertFilePath(Aws::String& caFile); } GameLiftClientService::GameLiftClientService(const GameLiftClientServiceDesc& desc) : SessionService(desc) , m_serviceDesc(desc) , m_clientStatus(GameLift_NotInited) { } GameLiftClientService::~GameLiftClientService() { } bool GameLiftClientService::IsReady() const { return m_clientStatus == GameLift_Ready; } AZStd::shared_ptr GameLiftClientService::GetClient() const { return m_clientSharedPtr; } Aws::String GameLiftClientService::GetPlayerId() const { return m_serviceDesc.m_playerId.c_str(); } void GameLiftClientService::OnServiceRegistered(IGridMate* gridMate) { SessionService::OnServiceRegistered(gridMate); GameLiftClientSession::RegisterReplicaChunks(); if (!StartGameLiftClient()) { EBUS_EVENT_ID(m_gridMate, GameLiftClientServiceEventsBus, OnGameLiftSessionServiceFailed, this, "GameLift client failed to start"); } GameLiftClientServiceBus::Handler::BusConnect(gridMate); } void GameLiftClientService::OnServiceUnregistered(IGridMate* gridMate) { GameLiftClientServiceBus::Handler::BusDisconnect(); if (m_clientStatus == GameLift_Ready) { m_clientSharedPtr.reset(); m_clientStatus = GameLift_NotInited; } SessionService::OnServiceUnregistered(gridMate); } void GameLiftClientService::Update() { if (m_describeGameSessionsOutcomeCallable.valid() && m_describeGameSessionsOutcomeCallable.wait_for(std::chrono::milliseconds(0)) == std::future_status::ready) { auto outcome = m_describeGameSessionsOutcomeCallable.get(); if (outcome.IsSuccess()) { AZ_TracePrintf("GameLift", "Initialized GameLift client successfully.\n"); m_clientStatus = GameLift_Ready; EBUS_EVENT_ID(m_gridMate, GameLiftClientServiceEventsBus, OnGameLiftSessionServiceReady, this); EBUS_DBG_EVENT(Debug::SessionDrillerBus, OnSessionServiceReady); EBUS_EVENT_ID(m_gridMate, SessionEventBus, OnSessionServiceReady); } else { auto errorMessage = outcome.GetError().GetMessage(); AZ_TracePrintf("GameLift", "Failed to initialize GameLift client: %s\n", errorMessage.c_str()); m_clientStatus = GameLift_Failed; // defer the notification so Gridmate doesn't destroy this service while updating AZ::TickBus::QueueFunction([this, errorMessage]() { GameLiftClientServiceEventsBus::Event(m_gridMate, &GameLiftClientServiceEventsBus::Events::OnGameLiftSessionServiceFailed, this, errorMessage.c_str()); }); } } SessionService::Update(); } GridSession* GameLiftClientService::JoinSessionBySearchInfo(const GameLiftSearchInfo& searchInfo, const CarrierDesc& carrierDesc) { if (m_clientStatus != GameLift_Ready) { AZ_TracePrintf("GameLift", "Client API is not initialized.\n"); return nullptr; } GameLiftClientSession* session = aznew GameLiftClientSession(this); if (!session->Initialize(searchInfo, JoinParams(), carrierDesc)) { delete session; return nullptr; } return session; } GridSearch* GameLiftClientService::RequestSession(const GameLiftSessionRequestParams& params) { if (m_clientStatus != GameLift_Ready) { AZ_TracePrintf("GameLift", "Client API is not initialized.\n"); return nullptr; } AZStd::shared_ptr context = AZStd::make_shared(); context->m_gameLiftClient = m_clientSharedPtr; context->m_playerId = m_serviceDesc.m_playerId.c_str(); // If queue name is set use queues to create a GameLift session. else use fleetId. if (!params.m_queueName.empty()) { context->m_requestParams = params; GameLiftGameSessionPlacementRequest* request = aznew GameLiftGameSessionPlacementRequest(this, context); if (!request->Initialize()) { delete request; return nullptr; } return request; } else { context->m_requestParams = params; GameLiftSessionRequest* request = aznew GameLiftSessionRequest(this, context); if (!request->Initialize()) { delete request; return nullptr; } return request; } } GridSearch* GameLiftClientService::StartMatchmaking(const AZStd::string& matchmakingConfigName) { if (m_clientStatus != GameLift_Ready) { AZ_TracePrintf("GameLift", "Client API is not initialized.\n"); return nullptr; } AZStd::shared_ptr context = AZStd::make_shared(); context->m_gameLiftClient = m_clientSharedPtr; context->m_playerId = m_serviceDesc.m_playerId.c_str(); GameLiftMatchmaking* request = aznew GameLiftMatchmaking(this, context, Aws::String(matchmakingConfigName.c_str())); if (!request->Initialize()) { delete request; return nullptr; } return request; } GameLiftSearch* GameLiftClientService::StartSearch(const GameLiftSearchParams& params) { if (m_clientStatus != GameLift_Ready) { AZ_TracePrintf("GameLift", "Client API is not initialized.\n"); return nullptr; } AZStd::shared_ptr context = AZStd::make_shared(); context->m_gameLiftClient = m_clientSharedPtr; context->m_searchParams = params; GameLiftSearch* search = aznew GameLiftSearch(this, context); if (!search->Initialize()) { delete search; return nullptr; } return search; } GameLiftClientSession* GameLiftClientService::QueryGameLiftSession(const GridSession* session) { for (GridSession* s : m_sessions) { if (s == session) { return static_cast(s); } } return nullptr; } GameLiftSearch* GameLiftClientService::QueryGameLiftSearch(const GridSearch* search) { for (GridSearch* s : m_activeSearches) { if (s == search) { return static_cast(s); } } for (GridSearch* s : m_completedSearches) { if (s == search) { return static_cast(s); } } return nullptr; } bool GameLiftClientService::StartGameLiftClient() { if (m_clientStatus == GameLift_NotInited) { if (!ValidateAWSCredentials()) { m_clientStatus = GameLift_Failed; } else { m_clientStatus = GameLift_Initing; CreateSharedAWSGameLiftClient(); // Sanity check that GameLift is reachable and credentials are valid.DescribeGameSessions requires a fleet id that is non - null, // so pass in mock fleet id.Sanity check is optional and can be removed if required Aws::GameLift::Model::DescribeGameSessionsRequest request; request.SetFleetId(FAKE_FLEET_ID); m_describeGameSessionsOutcomeCallable = m_clientSharedPtr->DescribeGameSessionsCallable(request); } } return m_clientStatus != GameLift_Failed; } void GameLiftClientService::CreateSharedAWSGameLiftClient() { Aws::Client::ClientConfiguration config; config.enableTcpKeepAlive = AZ_TRAIT_AZFRAMEWORK_AWS_ENABLE_TCP_KEEP_ALIVE_SUPPORTED; config.region = m_serviceDesc.m_region.c_str(); config.endpointOverride = m_serviceDesc.m_endpoint.c_str(); #if AZ_TRAIT_CLOCK_SKEW_CORRECTION_DISABLED config.enableClockSkewAdjustment = false; #endif if (m_serviceDesc.m_useGameLiftLocalServer) { config.verifySSL = false; config.scheme = Aws::Http::Scheme::HTTP; } else { config.verifySSL = true; config.scheme = Aws::Http::Scheme::HTTPS; Platform::ResolveCaCertFilePath(config.caFile); } Aws::Http::URI uri; if (config.endpointOverride.length() && config.endpointOverride.find(Aws::Http::SchemeMapper::ToString(Aws::Http::Scheme::HTTP)) == Aws::String::npos && config.endpointOverride.find(Aws::Http::SchemeMapper::ToString(Aws::Http::Scheme::HTTPS)) == Aws::String::npos) { // Generate the complete endpoint URI based on the schema uri.SetScheme(config.scheme); uri.SetAuthority(config.endpointOverride); config.endpointOverride = uri.GetURIString(); } Aws::String accessKey(m_serviceDesc.m_accessKey.c_str()); Aws::String secretKey(m_serviceDesc.m_secretKey.c_str()); Aws::Auth::AWSCredentials cred = Aws::Auth::AWSCredentials(accessKey, secretKey); m_clientSharedPtr = AZStd::make_shared(cred, config); } bool GameLiftClientService::ValidateAWSCredentials() { if (m_serviceDesc.m_accessKey.empty() || m_serviceDesc.m_secretKey.empty()) { AZ_TracePrintf("GameLift", "Initialize failed. Cannot use GameLift without access and secret key.\n"); return false; } return true; } } // namespace GridMate #endif // BUILD_GAMELIFT_CLIENT