Files
o3de/Gems/Multiplayer/Code/Source/MultiplayerGameLiftClient.cpp
T
2021-03-08 14:30:57 -08:00

390 lines
13 KiB
C++

/*
* 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 <Multiplayer_precompiled.h>
#include "MultiplayerGameLiftClient.h"
#include <GameLift/Session/GameLiftClientService.h>
#include <GameLift/Session/GameLiftSearch.h>
#include <GameLift/Session/GameLiftSessionRequest.h>
#include <CrySystemBus.h>
#include <INetwork.h>
#include <Multiplayer/MultiplayerUtils.h>
namespace Multiplayer
{
#if defined(BUILD_GAMELIFT_CLIENT)
static const char* GameLiftSessionAlreadyConnectedErrorMessage = "Already connected to a session. Use 'mpdisconnect' to leave current session";
MultiplayerGameLiftClient::MultiplayerGameLiftClient()
: m_mode(Mode::None)
, m_serviceStatus(ServiceStatus::Stopped)
, m_console(nullptr)
, m_gridMate(nullptr)
, m_search(nullptr)
, m_maxPlayers(0)
{
MultiplayerGameLiftClientBus::Handler::BusConnect();
}
MultiplayerGameLiftClient::~MultiplayerGameLiftClient()
{
MultiplayerGameLiftClientBus::Handler::BusDisconnect();
}
void MultiplayerGameLiftClient::HostGameLiftSession(const char* serverName, const char* mapName,
const AZ::u32 maxPlayers)
{
GridMate::GridSession* session = nullptr;
MultiplayerRequestBus::BroadcastResult(session, &MultiplayerRequestBus::Events::GetSession);
if (session)
{
AZ_TracePrintf("MultiplayerModule", GameLiftSessionAlreadyConnectedErrorMessage);
return;
}
if (m_serviceStatus == ServiceStatus::Starting)
{
AZ_TracePrintf("MultiplayerModule", "GameLift client service startup is already in-progress");
return;
}
m_mode = Mode::Host;
m_serverName = serverName;
m_mapName = mapName;
m_maxPlayers = maxPlayers;
if (m_serviceStatus == ServiceStatus::Stopped)
{
StartGameLiftClientService();
}
else
{
HandleGameLiftRequestByMode();
}
}
void MultiplayerGameLiftClient::JoinGameLiftSession()
{
GridMate::GridSession* session = nullptr;
MultiplayerRequestBus::BroadcastResult(session, &MultiplayerRequestBus::Events::GetSession);
if (session)
{
AZ_TracePrintf("MultiplayerModule", GameLiftSessionAlreadyConnectedErrorMessage);
return;
}
if (m_serviceStatus == ServiceStatus::Starting)
{
AZ_TracePrintf("MultiplayerModule", "GameLift client service startup is already in-progress");
return;
}
m_mode = Mode::Join;
if (m_serviceStatus == ServiceStatus::Stopped)
{
StartGameLiftClientService();
}
else
{
HandleGameLiftRequestByMode();
}
}
void MultiplayerGameLiftClient::StartGameLiftMatchmaking(const char* matchmakingConfigName)
{
GridMate::GridSession* session = nullptr;
MultiplayerRequestBus::BroadcastResult(session, &MultiplayerRequestBus::Events::GetSession);
if (session)
{
AZ_TracePrintf("MultiplayerModule", GameLiftSessionAlreadyConnectedErrorMessage);
return;
}
if (m_serviceStatus == ServiceStatus::Starting)
{
AZ_TracePrintf("MultiplayerModule", "GameLift client service startup is already in-progress");
return;
}
m_mode = Mode::FlexMatch;
m_matchmakingConfigName = matchmakingConfigName;
if (m_serviceStatus == ServiceStatus::Stopped)
{
StartGameLiftClientService();
}
else
{
HandleGameLiftRequestByMode();
}
}
void MultiplayerGameLiftClient::StopGameLiftClientService()
{
GameLift::GameLiftRequestBus::Broadcast(&GameLift::GameLiftRequestBus::Events::StopClientService);
m_serviceStatus = ServiceStatus::Stopped;
}
IConsole* MultiplayerGameLiftClient::GetConsole()
{
if (!m_console)
{
ISystem* system = nullptr;
CrySystemRequestBus::BroadcastResult(system, &CrySystemRequestBus::Events::GetCrySystem);
if (system)
{
m_console = system->GetIConsole();
}
}
return m_console;
}
GridMate::IGridMate* MultiplayerGameLiftClient::GetGridMate()
{
if (!m_gridMate)
{
ISystem* system = nullptr;
CrySystemRequestBus::BroadcastResult(system, &CrySystemRequestBus::Events::GetCrySystem);
if (system && system->GetINetwork())
{
m_gridMate = system->GetINetwork()->GetGridMate();
}
}
return m_gridMate;
}
const char* MultiplayerGameLiftClient::GetConsoleParam(const char* paramName)
{
const char* value = "";
IConsole* console = GetConsole();
if (console)
{
ICVar* cvar = console->GetCVar(paramName);
if (cvar)
{
value = cvar->GetString();
}
}
else
{
AZ_TracePrintf("MultiplayerModule", "Console has not been initialized.");
}
return value;
}
const bool MultiplayerGameLiftClient::GetConsoleBoolParam(const char* paramName)
{
bool value = false;
IConsole* console = GetConsole();
if (console)
{
ICVar* cvar = GetConsole()->GetCVar(paramName);
value = cvar && cvar->GetI64Val();
}
else
{
AZ_TracePrintf("MultiplayerModule", "Console has not been initialized.");
}
return value;
}
void MultiplayerGameLiftClient::AddRequestParameter(GridMate::GameLiftSessionRequestParams& params,
const char* name, const char* value)
{
if (params.m_numParams < params.k_maxNumParams)
{
params.m_params[params.m_numParams].m_id = name;
params.m_params[params.m_numParams].m_value = value;
params.m_numParams++;
}
else
{
AZ_TracePrintf("MultiplayerModule", "Failed to add parameter to request; request contains maximum number of parameters.");
}
}
void MultiplayerGameLiftClient::StartGameLiftClientService()
{
GridMate::IGridMate* gridMate = GetGridMate();
if (!gridMate)
{
AZ_TracePrintf("MultiplayerModule", "GridMate has not been initialized.");
return;
}
bool netSecEnabled = false;
MultiplayerRequestBus::BroadcastResult(netSecEnabled, &MultiplayerRequestBus::Events::IsNetSecEnabled);
if (netSecEnabled)
{
if (!Multiplayer::NetSec::CanCreateSecureSocketForJoining())
{
m_serviceStatus = ServiceStatus::Stopped;
AZ_TracePrintf("MultiplayerModule", "Invalid Secure Socket Configuration.");
return;
}
}
GridMate::GameLiftClientServiceEventsBus::Handler::BusConnect(gridMate);
GridMate::GameLiftClientServiceDesc serviceDesc;
serviceDesc.m_accessKey = GetConsoleParam("gamelift_aws_access_key");
serviceDesc.m_secretKey = GetConsoleParam("gamelift_aws_secret_key");
serviceDesc.m_endpoint = GetConsoleParam("gamelift_endpoint");
serviceDesc.m_region = GetConsoleParam("gamelift_aws_region");
serviceDesc.m_playerId = GetConsoleParam("gamelift_player_id");
serviceDesc.m_useGameLiftLocalServer = GetConsoleBoolParam("gamelift_uselocalserver");
m_serviceStatus = ServiceStatus::Starting;
GameLift::GameLiftRequestBus::Broadcast(
&GameLift::GameLiftRequestBus::Events::StartClientService, serviceDesc);
}
void MultiplayerGameLiftClient::HostGameLiftSessionInternal()
{
GridMate::GameLiftSessionRequestParams params;
params.m_instanceName = m_serverName;
params.m_numPublicSlots = m_maxPlayers;
params.m_numParams = 0;
AddRequestParameter(params, "sv_name", m_serverName.c_str());
AddRequestParameter(params, "sv_map", m_mapName.c_str());
params.m_fleetId = GetConsoleParam("gamelift_fleet_id");
params.m_aliasId = GetConsoleParam("gamelift_alias_id");
params.m_queueName = GetConsoleParam("gamelift_queue_name");
params.m_useFleetId = !params.m_fleetId.empty();
GridMate::GameLiftClientServiceBus::BroadcastResult(m_search,
&GridMate::GameLiftClientServiceBus::Events::RequestSession, params);
}
void MultiplayerGameLiftClient::StartGameLiftMatchmakingInternal()
{
GridMate::GameLiftClientServiceBus::BroadcastResult(m_search,
&GridMate::GameLiftClientServiceBus::Events::StartMatchmaking, m_matchmakingConfigName);
}
void MultiplayerGameLiftClient::JoinGameLiftSessionInternal(const GridMate::GameLiftSearchInfo& searchInfo)
{
GridMate::GridSession* session = nullptr;
MultiplayerRequestBus::BroadcastResult(session, &MultiplayerRequestBus::Events::GetSession);
if (session)
{
AZ_TracePrintf("MultiplayerModule", GameLiftSessionAlreadyConnectedErrorMessage);
}
GridMate::CarrierDesc carrierDesc;
Multiplayer::Utils::InitCarrierDesc(carrierDesc);
Multiplayer::NetSec::ConfigureCarrierDescForJoin(carrierDesc);
GridMate::GameLiftClientServiceBus::BroadcastResult(session,
&GridMate::GameLiftClientServiceBus::Events::JoinSessionBySearchInfo, searchInfo, carrierDesc);
if (session)
{
MultiplayerRequestBus::Broadcast(&MultiplayerRequestBus::Events::RegisterSession, session);
}
else
{
AZ_TracePrintf("MultiplayerModule", "Failed to create GameLift session.");
Multiplayer::NetSec::OnSessionFailedToCreate(carrierDesc);
}
}
void MultiplayerGameLiftClient::QueryGameLiftServers()
{
m_search = nullptr;
GridMate::GameLiftSearchParams searchParams;
searchParams.m_fleetId = GetConsoleParam("gamelift_fleet_id");
searchParams.m_aliasId = GetConsoleParam("gamelift_alias_id");
searchParams.m_queueName = GetConsoleParam("gamelift_queue_name");
searchParams.m_useFleetId = !searchParams.m_fleetId.empty();
GridMate::GameLiftClientServiceBus::BroadcastResult(m_search,
&GridMate::GameLiftClientServiceBus::Events::StartSearch, searchParams);
if (m_search == nullptr)
{
AZ_TracePrintf("MultiplayerModule", "Failed to start a GridSearch");
}
}
void MultiplayerGameLiftClient::HandleGameLiftRequestByMode()
{
GridMate::SessionEventBus::Handler::BusConnect(GetGridMate());
switch (m_mode)
{
case Mode::Join:
QueryGameLiftServers();
break;
case Mode::Host:
HostGameLiftSessionInternal();
break;
case Mode::FlexMatch:
StartGameLiftMatchmakingInternal();
break;
default:
break;
}
}
void MultiplayerGameLiftClient::OnGameLiftSessionServiceReady(GridMate::GameLiftClientService*)
{
GridMate::GameLiftClientServiceEventsBus::Handler::BusDisconnect();
m_serviceStatus = ServiceStatus::Started;
HandleGameLiftRequestByMode();
}
void MultiplayerGameLiftClient::OnGameLiftSessionServiceFailed(GridMate::GameLiftClientService*, [[maybe_unused]] const AZStd::string& message)
{
GridMate::GameLiftClientServiceEventsBus::Handler::BusDisconnect();
AZ_TracePrintf("MultiplayerModule", "GameLift Error: %s", message.c_str());
StopGameLiftClientService();
}
void MultiplayerGameLiftClient::OnGridSearchComplete(GridMate::GridSearch* gridSearch)
{
// When connecting the SessionEventBus, we will be notified when any grid search completes.
// This check ensures that we are only handling grid searches that we initiated (which populate m_search).
if (gridSearch != m_search)
{
return;
}
if (m_search->GetNumResults() == 0)
{
AZ_TracePrintf("MultiplayerModule", "GridSearch returned no results.");
return;
}
const GridMate::GameLiftSearchInfo& gameliftSearchInfo =
static_cast<const GridMate::GameLiftSearchInfo&>(*m_search->GetResult(0));
JoinGameLiftSessionInternal(gameliftSearchInfo);
m_search->Release();
m_search = nullptr;
GridMate::SessionEventBus::Handler::BusDisconnect(GetGridMate());
}
#endif
}