307 lines
8.1 KiB
C++
307 lines
8.1 KiB
C++
//===== Copyright © 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;
|
|
}
|
|
|
|
|
|
|