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

375 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 "Multiplayer/BehaviorContext/GridSearchContext.h"
#include <GridMate/NetworkGridMate.h>
#include "Multiplayer/MultiplayerEventsComponent.h"
#include "Multiplayer/BehaviorContext/GridSystemContext.h"
#include "Multiplayer/GridMateServiceWrapper/GridMateServiceWrapper.h"
#include <Multiplayer/MultiplayerUtils.h>
namespace Multiplayer
{
/**
* Wrapper around a GridMate::GridSearch pointer
*/
struct GridSearchTicket
{
AZ_TYPE_INFO(GridSearchTicket, "{ADFA9839-4D38-4B3E-8909-9D55261E69D5}");
AZ_CLASS_ALLOCATOR(GridSearchTicket, AZ::SystemAllocator, 0);
GridSearchTicket(GridMate::GridSearch* ptr) : m_ptr(ptr)
{
}
~GridSearchTicket()
{
Reset();
}
int GetNumResults() const
{
if (m_ptr)
{
return m_ptr->GetNumResults();
}
return 0;
}
void Reset()
{
m_ptr = nullptr;
}
GridMate::GridSearch* GetGridSearch() const
{
return m_ptr;
}
private:
GridMate::GridSearch* m_ptr;
};
/**
* Helper class to manage SessionEventBus events on behalf of GridSearchBusHandler
*/
struct GridSessionCallbacksHandler
: public GridMate::SessionEventBus::Handler
{
GridSessionCallbacksHandler()
{
}
virtual ~GridSessionCallbacksHandler()
{
Disconnect();
}
void Connect(const SessionDesc& m_sessionDesc, GridMate::IGridMate* gridMate)
{
m_desc = m_sessionDesc;
GridMate::SessionEventBus::Handler::BusConnect(gridMate);
}
void Disconnect()
{
GridMate::SessionEventBus::Handler::BusDisconnect();
for (auto it : m_ticketMap)
{
delete it.second;
}
m_ticketMap.clear();
}
GridSearchTicket* CreateTicket(GridMate::GridSearch* gridSearch)
{
GridSearchTicket* gridSearchTicket = aznew GridSearchTicket(gridSearch);
m_ticketMap.insert(AZStd::make_pair(gridSearch, gridSearchTicket));
return gridSearchTicket;
}
bool ReleaseTicket(GridSearchTicket* ticket)
{
return ReleaseGridSearch(ticket->GetGridSearch());
}
bool ReleaseGridSearch(GridMate::GridSearch* gridSearch)
{
if (gridSearch == nullptr)
{
return false;
}
auto it = m_ticketMap.find(gridSearch);
if (it != m_ticketMap.end())
{
delete it->second;
m_ticketMap.erase(it);
return true;
}
return false;
}
GridSearchTicket* FindOrCreateGridSearchTicket(GridMate::GridSearch* gridSearch)
{
auto it = m_ticketMap.find(gridSearch);
if (it != m_ticketMap.end())
{
return it->second;
}
GridSearchTicket* newTicket = aznew GridSearchTicket(gridSearch);
m_ticketMap.insert(AZStd::make_pair(gridSearch, newTicket));
return newTicket;
}
//
// GridMate::SessionEventBus::Handler
//
void OnGridSearchComplete(GridMate::GridSearch* gridSearch) override
{
for (size_t i = 0; i < gridSearch->GetNumResults(); ++i)
{
EBUS_EVENT(GridSearchBus, OnSearchInfo, gridSearch->GetResult(i));
}
EBUS_EVENT(GridSearchBus, OnSearchComplete, FindOrCreateGridSearchTicket(gridSearch));
}
void OnGridSearchRelease(GridMate::GridSearch* gridSearch) override
{
ReleaseGridSearch(gridSearch);
}
void OnGridSearchStart(GridMate::GridSearch* gridSearch) override
{
(void)gridSearch;
}
void OnSessionDelete(GridMate::GridSession* session) override
{
(void)session;
Disconnect();
}
void OnSessionJoined(GridMate::GridSession* session) override
{
EBUS_EVENT(GridSearchBus, OnJoinComplete, session);
}
private:
SessionDesc m_desc;
AZStd::unordered_map<GridMate::GridSearch*, GridSearchTicket*> m_ticketMap;
};
/**
* Extends the Grid parameters with an optional security string
*/
struct SearchGridParameters
{
GridMate::string m_securityString;
const SessionDesc& m_sessionDesc;
SearchGridParameters(const SessionDesc& sessionDesc)
: m_securityString()
, m_sessionDesc(sessionDesc)
{
}
GridMate::GridSessionParam FetchGridSessionParam(const char* key)
{
GridMate::GridSessionParam param;
if (GridMateSystemContext::FetchParam(key, m_sessionDesc, param))
{
return param;
}
else if (!strcmp(key, "gm_securityData")) // has to come from a CFG
{
if (gEnv && gEnv->pConsole && gEnv->pConsole->GetCVar("gm_securityData"))
{
m_securityString = gEnv->pConsole->GetCVar("gm_securityData")->GetString();
param.SetValue(m_securityString);
}
}
return param;
}
};
/**
* Handles grid searches for a behavior context
*/
class GridSearchBusHandler
: public GridSearchBus::Handler
, public AZ::BehaviorEBusHandler
{
public:
AZ_EBUS_BEHAVIOR_BINDER(GridSearchBusHandler, "{83FF3AEB-2513-43A0-9BEE-ED8980449AEB}", AZ::SystemAllocator
, StartSearch
, StopSearch
, OnSearchComplete
, OnSearchError
, OnSearchInfo
, OnSearchClosed
, OnJoinComplete
);
protected:
//
// GridSearchInterface::Handler
//
const GridSearchTicket* StartSearch(const SessionDesc& sessionDesc) override
{
m_sessionDesc = sessionDesc;
GridMate::IGridMate* gridMate = FindGridMate();
if (!gridMate)
{
OnSearchError("Global GridMate not ready");
return nullptr;
}
m_gridSessionCallbacksHandler.Connect(m_sessionDesc, gridMate);
m_gridMateServiceWrapper.reset(GridMateSystemContext::RegisterServiceWrapper(m_sessionDesc.m_serviceType));
if (!m_gridMateServiceWrapper)
{
// error
return nullptr;
}
SearchGridParameters searchGridParameters(m_sessionDesc);
GridMateServiceParams gridMateServiceParams({}, AZStd::bind(&SearchGridParameters::FetchGridSessionParam, &searchGridParameters, AZStd::placeholders::_1));
GridMate::GridSearch* search = m_gridMateServiceWrapper->ListServers(gridMate, gridMateServiceParams);
if (search == nullptr)
{
EBUS_EVENT(GridSearchBus, OnSearchError, "ListServers failed to start a GridSearch.");
}
return m_gridSessionCallbacksHandler.CreateTicket(search);
}
bool JoinSession(const GridMate::SearchInfo* searchInfo)
{
GridMate::GridSession* session = nullptr;
GridMate::CarrierDesc carrierDesc;
SearchGridParameters searchGridParameters(m_sessionDesc);
GridMateServiceParams gridMateServiceParams({}, AZStd::bind(&SearchGridParameters::FetchGridSessionParam, &searchGridParameters, AZStd::placeholders::_1));
GridMateSystemContext::InitCarrierDesc(gridMateServiceParams, carrierDesc);
Multiplayer::NetSec::ConfigureCarrierDescForJoin(carrierDesc);
session = m_gridMateServiceWrapper->JoinSession(FindGridMate(), carrierDesc, searchInfo);
if (session == nullptr)
{
OnSearchClosed(false);
Multiplayer::NetSec::OnSessionFailedToCreate(carrierDesc);
EBUS_EVENT(GridSearchBus, OnSearchError, "ListServers failed to start a GridSearch.");
}
else
{
OnSearchClosed(true);
}
return session != nullptr;
}
bool StopSearch(GridSearchTicket* ticket) override
{
if (ticket)
{
m_gridSessionCallbacksHandler.ReleaseTicket(ticket);
return true;
}
return false;
}
void OnSearchComplete(const GridSearchTicket* gridSearchTicket) override
{
Call(FN_OnSearchComplete, gridSearchTicket);
}
void OnSearchError(const GridMate::string& errorMsg)
{
Call(FN_OnSearchError, errorMsg);
}
void OnSearchInfo(const GridMate::SearchInfo* searchInfo) override
{
Call(FN_OnSearchInfo, searchInfo);
}
void OnSearchClosed(bool isJoiningSession) override
{
Call(FN_OnSearchClosed, isJoiningSession);
}
void OnJoinComplete(const GridMate::GridSession* gridSession) override
{
Call(FN_OnJoinComplete, gridSession);
}
//
// helper method(s)
//
GridMate::IGridMate* FindGridMate()
{
if (gEnv && gEnv->pNetwork)
{
return gEnv->pNetwork->GetGridMate();
}
return nullptr;
}
GridSessionCallbacksHandler m_gridSessionCallbacksHandler;
SessionDesc m_sessionDesc;
AZStd::unique_ptr<GridMateServiceWrapper> m_gridMateServiceWrapper;
};
/**
* Exposes Grid searching events and callbacks to a behavior context such as Lua
*/
namespace GridSearchBehavior
{
void Reflect(AZ::ReflectContext* reflectContext)
{
AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(reflectContext);
if (serializeContext)
{
serializeContext->Class<GridMate::SearchInfo>()
->Version(1)
->Field("SessionId", &GridMate::SearchInfo::m_sessionId)
->Field("FreePublicSlots", &GridMate::SearchInfo::m_numFreePublicSlots)
->Field("FreePrivateSlots", &GridMate::SearchInfo::m_numFreePrivateSlots)
->Field("UsedPublicSlots", &GridMate::SearchInfo::m_numUsedPublicSlots)
->Field("UsedPrivateSlots", &GridMate::SearchInfo::m_numUsedPrivateSlots)
->Field("NumPlayers", &GridMate::SearchInfo::m_numPlayers)
;
}
AZ::BehaviorContext* behaviorContext = azrtti_cast<AZ::BehaviorContext*>(reflectContext);
if (behaviorContext)
{
behaviorContext->Class<GridSearchTicket>()
->Attribute(AZ::Script::Attributes::Storage, AZ::Script::Attributes::StorageType::Value)
->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::List)
->Method("GetNumResults", &GridSearchTicket::GetNumResults)
;
behaviorContext->Class<GridMate::SearchInfo>()
->Attribute(AZ::Script::Attributes::Storage, AZ::Script::Attributes::StorageType::RuntimeOwn)
->Property("numPlayers", BehaviorValueProperty(&GridMate::SearchInfo::m_numPlayers))
->Property("numFreePrivateSlots", BehaviorValueProperty(&GridMate::SearchInfo::m_numFreePrivateSlots))
->Property("numUsedPrivateSlots", BehaviorValueProperty(&GridMate::SearchInfo::m_numUsedPrivateSlots))
->Property("numFreePublicSlots", BehaviorValueProperty(&GridMate::SearchInfo::m_numFreePublicSlots))
->Property("numUsedPublicSlots", BehaviorValueProperty(&GridMate::SearchInfo::m_numUsedPublicSlots))
;
behaviorContext->EBus<GridSearchBus>("GridSearchBusHandler")
->Handler<GridSearchBusHandler>()
->Event("StartSearch", &GridSearchBus::Events::StartSearch)
->Event("StopSearch", &GridSearchBus::Events::StopSearch)
->Event("JoinSession", &GridSearchBus::Events::JoinSession)
;
}
}
}
};