csgo-2018-source/matchmaking/mm_netmsgcontroller.cpp

307 lines
8.1 KiB
C++
Raw Normal View History

2021-07-25 12:11:47 +08:00
//===== Copyright <20> 1996-2009, Valve Corporation, All rights reserved. ======//
//
// Purpose:
//
//===========================================================================//
#include "mm_netmsgcontroller.h"
#include "matchmakingqos.h"
#include "proto_oob.h"
#include "bitbuf.h"
#include "fmtstr.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
//
// Implementation
//
CMatchNetworkMsgControllerBase::CMatchNetworkMsgControllerBase()
{
}
CMatchNetworkMsgControllerBase::~CMatchNetworkMsgControllerBase()
{
}
static CMatchNetworkMsgControllerBase g_MatchNetMsgControllerBase;
CMatchNetworkMsgControllerBase *g_pMatchNetMsgControllerBase = &g_MatchNetMsgControllerBase;
//
// A way to copy just value
//
static void CopyValue( KeyValues *pTo, KeyValues *pFrom )
{
switch ( pFrom->GetDataType() )
{
case KeyValues::TYPE_INT:
pTo->SetInt( "", pFrom->GetInt() );
break;
case KeyValues::TYPE_UINT64:
pTo->SetUint64( "", pFrom->GetUint64() );
break;
case KeyValues::TYPE_STRING:
pTo->SetString( "", pFrom->GetString() );
break;
default:
DevWarning( "NetMsgCtrlr::CopyValue using unknown type!\n" );
Assert( 0 );
break;
}
}
//
// Implementation
//
MM_QOS_t CMatchNetworkMsgControllerBase::GetQOS()
{
return MM_GetQos();
}
KeyValues * CMatchNetworkMsgControllerBase::GetActiveServerGameDetails( KeyValues *pRequest )
{
// Query server info
INetSupport::ServerInfo_t si;
g_pMatchExtensions->GetINetSupport()->GetServerInfo( &si );
KeyValues *pDetails = NULL;
if ( si.m_bActive )
{
MEM_ALLOC_CREDIT();
//
// Parse the game details from the values
//
pDetails = KeyValues::FromString(
"GameDetailsServer",
" system { "
" network LIVE "
" access public "
" } "
" server { "
" name = "
" server = "
" adronline = "
" adrlocal = "
" } "
" members { "
" numSlots #int#0 "
" numPlayers #int#0 "
" } "
);
//
// For a listen server and other MM session overlay the session settings
//
if ( !si.m_bDedicated && g_pMatchFramework->GetMatchSession() )
{
pDetails->MergeFrom( g_pMatchFramework->GetMatchSession()->GetSessionSettings(), KeyValues::MERGE_KV_BORROW );
}
//
// Get server information
//
pDetails->SetString( "server/name", si.m_szServerName );
pDetails->SetString( "server/server", si.m_bDedicated ? "dedicated" : "listen" );
pDetails->SetString( "server/adronline", si.m_netAdrOnline.ToString() );
pDetails->SetString( "server/adrlocal", si.m_netAdr.ToString() );
if ( si.m_bDedicated && si.m_bLobbyExclusive && si.m_bGroupExclusive )
pDetails->SetString( "system/access", "friends" );
si.m_numMaxHumanPlayers = ClampArrayBounds( si.m_numMaxHumanPlayers, g_pMMF->GetMatchTitle()->GetTotalNumPlayersSupported() );
pDetails->SetInt( "members/numSlots", si.m_numMaxHumanPlayers );
si.m_numHumanPlayers = ClampArrayBounds( si.m_numHumanPlayers, si.m_numMaxHumanPlayers );
pDetails->SetInt( "members/numPlayers", si.m_numHumanPlayers );
static ConVarRef host_info_show( "host_info_show" );
if ( host_info_show.GetInt() < 2 )
pDetails->SetString( "options/action", "crypt" );
}
else if ( IVEngineClient *pIVEngineClient = g_pMatchExtensions->GetIVEngineClient() )
{
if ( pIVEngineClient->IsLevelMainMenuBackground() )
return NULL;
char const *szLevelName = pIVEngineClient->GetLevelNameShort();
if ( !szLevelName || !*szLevelName )
return NULL;
MEM_ALLOC_CREDIT();
pDetails = new KeyValues( "GameDetailsClient" );
}
if ( !pDetails )
return NULL;
// Allow title to add game-specific settings
g_pMMF->GetMatchTitleGameSettingsMgr()->ExtendServerDetails( pDetails, pRequest );
return pDetails;
}
static KeyValues * GetLobbyDetailsTemplate( char const *szReason = "", KeyValues *pSettings = NULL )
{
KeyValues *pDetails = KeyValues::FromString(
"settings",
" system { "
" network #empty# "
" access #empty# "
" netflag #empty# "
" lock #empty# "
" } "
" options { "
" server #empty# "
" } "
" members { "
" numSlots #int#0 "
" numPlayers #int#0 "
" } "
);
g_pMMF->GetMatchTitleGameSettingsMgr()->ExtendLobbyDetailsTemplate( pDetails, szReason, pSettings );
return pDetails;
}
KeyValues * CMatchNetworkMsgControllerBase::UnpackGameDetailsFromQOS( MM_GameDetails_QOS_t const *pvQosReply )
{
//
// Check if we have correct header
//
CUtlBuffer bufQos( pvQosReply->m_pvData, pvQosReply->m_numDataBytes, CUtlBuffer::READ_ONLY );
bufQos.ActivateByteSwapping( !CByteswap::IsMachineBigEndian() );
int iProtocol = bufQos.GetInt();
int iVersion = bufQos.GetInt();
if ( iProtocol != g_pMatchExtensions->GetINetSupport()->GetEngineBuildNumber() )
return NULL;
if ( 0 != iVersion )
return NULL;
//
// Read the game details that we have received
//
MEM_ALLOC_CREDIT();
KeyValues *pDetails = new KeyValues( "" );
if ( !pDetails->ReadAsBinary( bufQos ) )
{
pDetails->deleteThis();
return NULL;
}
// Read the terminator
int iTerm = bufQos.GetInt();
if ( iTerm != 0 )
{
DevWarning( "UnpackGameDetailsFromQOS found bad QOS block terminator!\n" );
}
return pDetails;
}
void CMatchNetworkMsgControllerBase::PackageGameDetailsForQOS( KeyValues *pSettings, CUtlBuffer &buf )
{
KeyValues *pDetails = GetLobbyDetailsTemplate( "qos", pSettings );
KeyValues::AutoDelete autodelete( pDetails );
// Keep only keys specified in the template
pDetails->MergeFrom( pSettings, KeyValues::MERGE_KV_BORROW );
// Write the details as binary
buf.PutInt( g_pMatchExtensions->GetINetSupport()->GetEngineBuildNumber() );
buf.PutInt( 0 );
pDetails->WriteAsBinary( buf );
buf.PutInt( 0 );
}
#if !defined( _X360 ) && !defined( NO_STEAM ) && !defined( SWDS )
static void UnpackGameDetailsFromSteamLobbyInKey( uint64 uiLobbyID, char const *szPath, KeyValues *pKey )
{
// Iterate over all the values
for ( KeyValues *val = pKey->GetFirstValue(); val; val = val->GetNextValue() )
{
char const *szLobbyData = steamapicontext->SteamMatchmaking()
->GetLobbyData( uiLobbyID, CFmtStr( "%s%s", szPath, val->GetName() ) );
switch ( val->GetDataType() )
{
case KeyValues::TYPE_INT:
val->SetInt( "", atoi( szLobbyData ) );
break;
case KeyValues::TYPE_STRING:
val->SetString( "", szLobbyData );
break;
default:
DevWarning( "UnpackGameDetailsFromSteamLobby defined unknown type in schema!\n" );
Assert( 0 );
break;
}
}
// Iterate over subkeys
for ( KeyValues *sub = pKey->GetFirstTrueSubKey(); sub; sub = sub->GetNextTrueSubKey() )
{
UnpackGameDetailsFromSteamLobbyInKey( uiLobbyID, CFmtStr( "%s%s:", szPath, sub->GetName() ), sub );
}
}
#endif
KeyValues * CMatchNetworkMsgControllerBase::UnpackGameDetailsFromSteamLobby( uint64 uiLobbyID )
{
#if !defined( _X360 ) && !defined( NO_STEAM ) && !defined( SWDS )
// Make sure the basic metadata is set on the lobby
char const *arrRequiredMetadata[] = { "system:network", "system:access" };
for ( int k = 0; k < ARRAYSIZE( arrRequiredMetadata ); ++ k )
{
char const *szMetadata = steamapicontext->SteamMatchmaking()->GetLobbyData( uiLobbyID, arrRequiredMetadata[k] );
if ( !szMetadata || !*szMetadata )
return NULL;
}
// Allocate details template
KeyValues *pDetails = GetLobbyDetailsTemplate();
// Iterate over all the keys
UnpackGameDetailsFromSteamLobbyInKey( uiLobbyID, "", pDetails );
// Get members info
if ( KeyValues *kvMembers = pDetails->FindKey( "members", true ) )
{
int numSlots = steamapicontext->SteamMatchmaking()->GetLobbyMemberLimit( uiLobbyID );
numSlots = ClampArrayBounds( numSlots, g_pMMF->GetMatchTitle()->GetTotalNumPlayersSupported() );
kvMembers->SetInt( "numSlots", numSlots );
int numPlayers = steamapicontext->SteamMatchmaking()->GetNumLobbyMembers( uiLobbyID );
numPlayers = ClampArrayBounds( numPlayers, numSlots );
kvMembers->SetInt( "numPlayers", numPlayers );
}
return pDetails;
#endif
return NULL;
}
KeyValues * CMatchNetworkMsgControllerBase::PackageGameDetailsForReservation( KeyValues *pSettings )
{
KeyValues *res = GetLobbyDetailsTemplate( "reserve", pSettings );
res->SetName( COM_GetModDirectory() );
// Keep only keys specified in the template
res->MergeFrom( pSettings, KeyValues::MERGE_KV_BORROW );
return res;
}