|
|
//===== 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; }
|