|
|
//===== Copyright � 1996-2009, Valve Corporation, All rights reserved. ======//
//
// Purpose:
//
//===========================================================================//
#include "mm_framework.h"
#include "vstdlib/random.h"
#include "fmtstr.h"
#include "steam_datacenterjobs.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
ConVar mm_teamsearch_errortime( "mm_teamsearch_errortime", "3.0", FCVAR_DEVELOPMENTONLY, "Time team search is in error state until it self-cancels" ); ConVar mm_teamsearch_nostart( "mm_teamsearch_nostart", "0", FCVAR_DEVELOPMENTONLY, "Team search will fake cancel before searching for server" );
#ifndef _GAMECONSOLE
ConVar sv_search_team_key( "sv_search_team_key", "public", FCVAR_RELEASE, "When initiating team search, set this key to match with known opponents team" ); #endif
//
//
// Specialized implementation of SysSessions for team search
//
//
template < typename TBaseSession > class CSysSessionStubForTeamSearch : public TBaseSession { public: explicit CSysSessionStubForTeamSearch( KeyValues *pSettings, CMatchSessionOnlineTeamSearch *pMatchSession ) : TBaseSession( pSettings ), m_pMatchSession( pMatchSession ) { }
protected: virtual void OnSessionEvent( KeyValues *notify ) { if ( !notify ) return;
if ( m_pMatchSession ) m_pMatchSession->OnSessionEvent( notify );
notify->deleteThis(); }
protected: // No voice
virtual void Voice_ProcessTalkers( KeyValues *pMachine, bool bAdd ) {} virtual void Voice_CaptureAndTransmitLocalVoiceData() {} virtual void Voice_Playback( KeyValues *msg, XUID xuidSrc ) OVERRIDE {} virtual void Voice_UpdateLocalHeadsetsStatus() {} virtual void Voice_UpdateMutelist() {}
protected: // No p2p connections, just two hosts talking
virtual void XP2P_Interconnect() {}
protected: CMatchSessionOnlineTeamSearch *m_pMatchSession; };
typedef CSysSessionStubForTeamSearch< CSysSessionClient > CSysTeamSearchClient; typedef CSysSessionStubForTeamSearch< CSysSessionHost > CSysTeamSearchHost;
//
//
// CMatchSessionOnlineTeamSearch implementation
//
//
CMatchSessionOnlineTeamSearch::CMatchSessionOnlineTeamSearch( KeyValues *pSettings, CMatchSessionOnlineHost *pHost ) : m_pHostSession( pHost ), m_eState( STATE_SEARCHING ), m_pSysSessionHost( NULL ), m_pSysSessionClient( NULL ), m_pDsSearcher( NULL ), m_flActionTime( 0.0f ), m_pUpdateHostSessionPacket( NULL ), m_autodelete_pUpdateHostSessionPacket( m_pUpdateHostSessionPacket ), m_iLinkState( 0 ), m_xuidLinkPeer( 0ull ), #ifdef _X360
m_pXlspConnection( NULL ), m_pXlspCommandBatch( NULL ), #endif
m_flCreationTime( Plat_FloatTime() ) { m_pSettings = pSettings->MakeCopy(); m_autodelete_pSettings.Assign( m_pSettings );
#ifndef _GAMECONSOLE
m_pSettings->SetString( "options/searchteamkey", sv_search_team_key.GetString() ); #endif
if ( IsPC() ) { // On PC limit server selection for team games to official and listen
if ( Q_stricmp( m_pSettings->GetString( "options/server" ), "listen" ) ) m_pSettings->SetString( "options/server", "official" ); }
DevMsg( "Created CMatchSessionOnlineTeamSearch:\n" ); KeyValuesDumpAsDevMsg( m_pSettings, 1 ); }
CMatchSessionOnlineTeamSearch::~CMatchSessionOnlineTeamSearch() { DevMsg( "Destroying CMatchSessionOnlineTeamSearch.\n" ); }
CMatchSearcher * CMatchSessionOnlineTeamSearch::OnStartSearching() { return new CMatchSearcher_OnlineTeamSearch( this, m_pSettings->MakeCopy() ); }
CMatchSearcher_OnlineTeamSearch::CMatchSearcher_OnlineTeamSearch( CMatchSessionOnlineTeamSearch *pSession, KeyValues *pSettings ) : CMatchSearcher_OnlineSearch( pSession, pSettings ) { // Search settings cannot be locked as it will interfere with syssessions
m_pSettings->SetString( "system/lock", "" );
// Team versus searchable lobbies are public
m_pSettings->SetString( "system/access", "public" );
// If we happen to host the session it will be a special teamlink session
m_pSettings->SetString( "system/netflag", "teamlink" );
if ( IMatchSession *pMainSession = g_pMatchFramework->GetMatchSession() ) { KeyValues *kvSystemData = pMainSession->GetSessionSystemData(); m_pSettings->SetUint64( "System/dependentlobby", kvSystemData->GetUint64( "xuidReserve" ) ); }
// Double the number of slots since we assume two teams playing
m_pSettings->SetInt( "Members/numSlots", g_pMatchFramework->GetMatchTitle()->GetTotalNumPlayersSupported() );
// Let the title extend the game settings
g_pMMF->GetMatchTitleGameSettingsMgr()->InitializeGameSettings( m_pSettings, "search_onlineteam" );
DevMsg( "CMatchSearcher_OnlineTeamSearch title adjusted settings:\n" ); KeyValuesDumpAsDevMsg( m_pSettings, 1 ); }
void CMatchSearcher_OnlineTeamSearch::StartSearchPass( KeyValues *pSearchPass ) { #ifndef _GAMECONSOLE
pSearchPass->SetString( "Filter=/options:searchteamkey", sv_search_team_key.GetString() ); #endif
CMatchSearcher_OnlineSearch::StartSearchPass( pSearchPass ); }
void CMatchSessionOnlineTeamSearch::OnSearchEvent( KeyValues *pNotify ) { if ( !pNotify ) return;
if ( m_pHostSession ) m_pHostSession->OnEvent( pNotify ); pNotify->deleteThis(); }
void CMatchSessionOnlineTeamSearch::OnSessionEvent( KeyValues *pEvent ) { OnEvent( pEvent );
// Searching state is handled entirely by the base class
if ( m_eState == STATE_SEARCHING ) return;
char const *szEvent = pEvent->GetName();
if ( !Q_stricmp( "mmF->SysSessionUpdate", szEvent ) ) { if ( m_pSysSessionHost && pEvent->GetPtr( "syssession", NULL ) == m_pSysSessionHost ) { // We had a session error
if ( char const *szError = pEvent->GetString( "error", NULL ) ) { // Destroy the session
m_pSysSessionHost->Destroy(); m_pSysSessionHost = NULL;
// Handle error
m_eState = STATE_ERROR; m_flActionTime = Plat_FloatTime() + mm_teamsearch_errortime.GetFloat(); OnSearchEvent( new KeyValues( "OnMatchSessionUpdate", "state", "progress", "progress", "searcherror" ) ); return; }
// This is our session
switch ( m_eState ) { case STATE_CREATING: // Session created successfully and we are awaiting peer
m_eState = STATE_AWAITING_PEER; OnSearchEvent( new KeyValues( "OnMatchSessionUpdate", "state", "progress", "progress", "searchawaitingpeer" ) ); break; } } } else if ( !Q_stricmp( "mmF->SysSessionCommand", szEvent ) ) { if ( m_pSysSessionHost && pEvent->GetPtr( "syssession", NULL ) == m_pSysSessionHost ) { KeyValues *pCommand = pEvent->GetFirstTrueSubKey(); if ( pCommand ) { OnRunSessionCommand( pCommand ); } } if ( m_pSysSessionClient && pEvent->GetPtr( "syssession", NULL ) == m_pSysSessionClient ) { KeyValues *pCommand = pEvent->GetFirstTrueSubKey(); if ( pCommand ) { OnRunSessionCommand( pCommand ); } } } else if ( !Q_stricmp( "OnPlayerMachinesConnected", szEvent ) ) { // Another team is challenging us
m_eState = STATE_LINK_HOST; m_xuidLinkPeer = pEvent->GetUint64( "id" ); OnSearchEvent( new KeyValues( "OnMatchSessionUpdate", "state", "progress", "progress", "searchlinked" ) );
// Lock the session to prevent other teams challenges
m_pSettings->SetString( "system/lock", "linked" ); m_pSysSessionHost->OnUpdateSessionSettings( KeyValues::AutoDeleteInline( KeyValues::FromString( "update", " update { " " system { " " lock linked " " } " " } " ) ) );
LinkHost().LinkInit(); } else if ( !Q_stricmp( "OnPlayerRemoved", szEvent ) ) { // Assert( m_xuidLinkPeer == pEvent->GetUint64( "xuid" ) );
// the peer gave up before we finished negotiation, start the process all over
ResetAndRestartTeamSearch(); } }
void CMatchSessionOnlineTeamSearch::ResetAndRestartTeamSearch() { m_eState = STATE_ERROR; m_flActionTime = 0.0f; OnSearchEvent( new KeyValues( "OnMatchSessionUpdate", "state", "progress", "progress", "restart" ) ); }
void CMatchSessionOnlineTeamSearch::RememberHostSessionUpdatePacket( KeyValues *pPacket ) { if ( m_pUpdateHostSessionPacket ) m_pUpdateHostSessionPacket->deleteThis(); m_pUpdateHostSessionPacket = pPacket; m_autodelete_pUpdateHostSessionPacket.Assign( m_pUpdateHostSessionPacket ); }
void CMatchSessionOnlineTeamSearch::ApplyHostSessionUpdatePacket() { if ( m_pUpdateHostSessionPacket ) { KeyValues *pUpdatePkt = m_pUpdateHostSessionPacket; m_pUpdateHostSessionPacket = NULL; m_autodelete_pUpdateHostSessionPacket.Assign( NULL );
m_pHostSession->UpdateSessionSettings( pUpdatePkt );
pUpdatePkt->deleteThis(); } }
void CMatchSessionOnlineTeamSearch::OnRunSessionCommand( KeyValues *pCommand ) { switch ( m_eState ) { case STATE_LINK_HOST: LinkHost().LinkCommand( pCommand ); break; case STATE_LINK_CLIENT: LinkClient().LinkCommand( pCommand ); break; } }
CMatchSessionOnlineTeamSearchLinkHost & CMatchSessionOnlineTeamSearch::LinkHost() { return static_cast< CMatchSessionOnlineTeamSearchLinkHost & >( *this ); }
CMatchSessionOnlineTeamSearchLinkClient & CMatchSessionOnlineTeamSearch::LinkClient() { return static_cast< CMatchSessionOnlineTeamSearchLinkClient & >( *this ); }
CSysSessionBase * CMatchSessionOnlineTeamSearch::LinkSysSession() { switch ( m_eState ) { case STATE_LINK_HOST: return m_pSysSessionHost; case STATE_LINK_CLIENT: return m_pSysSessionClient; default: Assert( !m_pSysSessionClient || !m_pSysSessionHost ); if ( m_pSysSessionHost ) return m_pSysSessionHost; else if ( m_pSysSessionClient ) return m_pSysSessionClient; else return NULL; } }
CSysSessionClient * CMatchSessionOnlineTeamSearch::OnBeginJoiningSearchResult() { return new CSysTeamSearchClient( m_pSettings, this ); }
void CMatchSessionOnlineTeamSearch::OnSearchCompletedSuccess( CSysSessionClient *pSysSession, KeyValues *pSettings ) { // Push the settings back into searcher since we are going to be using them
m_pSettings = pSettings; m_autodelete_pSettings.Assign( m_pSettings ); m_pSysSessionClient = pSysSession;
// Established connection with another team
m_eState = STATE_LINK_CLIENT; m_xuidLinkPeer = pSysSession->GetHostXuid(); OnSearchEvent( new KeyValues( "OnMatchSessionUpdate", "state", "progress", "progress", "searchlinked" ) ); LinkClient().LinkInit(); }
void CMatchSessionOnlineTeamSearch::OnSearchCompletedEmpty( KeyValues *pSettings ) { // Push the settings back into searcher since we are going to be searching again
m_pSettings = pSettings; m_autodelete_pSettings.Assign( m_pSettings );
// Idle out for some time
m_eState = STATE_CREATING;
// Notify everybody that our search idled out
OnSearchEvent( new KeyValues( "OnMatchSessionUpdate", "state", "progress", "progress", "searchidle" ) );
// Allocate the hosting object to accept matches
m_pSysSessionHost = new CSysTeamSearchHost( m_pSettings, this ); }
void CMatchSessionOnlineTeamSearch::DebugPrint() { DevMsg( "CMatchSessionOnlineTeamSearch::CMatchSessionOnlineSearch\n" ); CMatchSessionOnlineSearch::DebugPrint();
DevMsg( "CMatchSessionOnlineTeamSearch [ state=%d ]\n", m_eState ); DevMsg( " linkstate: %d\n", m_iLinkState ); DevMsg( " linkpeer: %llx\n", m_xuidLinkPeer ); DevMsg( " actiontime:%.3f\n", m_flActionTime ? m_flActionTime - Plat_FloatTime() : 0.0f );
if ( m_pDsSearcher ) DevMsg( "TeamSearch: Dedicated search in progress\n" ); else DevMsg( "TeamSearch: Dedicated search not active\n" );
DevMsg( "TeamSearch: SysSession host state:\n" ); if ( m_pSysSessionHost ) m_pSysSessionHost->DebugPrint(); else DevMsg( "SysSession is NULL\n" );
DevMsg( "TeamSearch: SysSession client state:\n" ); if ( m_pSysSessionClient ) m_pSysSessionClient->DebugPrint(); else DevMsg( "SysSession is NULL\n" ); }
void CMatchSessionOnlineTeamSearch::OnEvent( KeyValues *pEvent ) { CMatchSessionOnlineSearch::OnEvent( pEvent );
// Let the dedicated search handle the responses too
if ( m_pDsSearcher ) m_pDsSearcher->OnEvent( pEvent ); }
void CMatchSessionOnlineTeamSearch::Update() { switch ( m_eState ) { case STATE_ERROR: if ( m_flActionTime && Plat_FloatTime() > m_flActionTime ) { m_flActionTime = 0.0f; if ( m_pHostSession ) m_pHostSession->Command( KeyValues::AutoDeleteInline( new KeyValues( "Stop" ) ) ); } return;
case STATE_AWAITING_PEER: break;
case STATE_LINK_CLIENT: LinkClient().LinkUpdate(); break;
case STATE_LINK_HOST: LinkHost().LinkUpdate(); break; }
CMatchSessionOnlineSearch::Update();
if ( CSysSessionBase *pLinkSysSession = LinkSysSession() ) pLinkSysSession->Update(); }
void CMatchSessionOnlineTeamSearch::Destroy() { if ( m_pSysSessionHost ) { m_pSysSessionHost->Destroy(); m_pSysSessionHost = NULL; } if ( m_pSysSessionClient ) { m_pSysSessionClient->Destroy(); m_pSysSessionClient = NULL; } if ( m_pDsSearcher ) { m_pDsSearcher->Destroy(); m_pDsSearcher = NULL; }
#ifdef _X360
if ( m_pXlspCommandBatch ) { m_pXlspCommandBatch->Destroy(); m_pXlspCommandBatch = NULL; } if ( m_pXlspConnection ) { m_pXlspConnection->Destroy(); m_pXlspConnection = NULL; } #endif
CMatchSessionOnlineSearch::Destroy(); }
//////////////////////////////////////////////////////////////////////////
//
// Link base implementation
//
//
void CMatchSessionOnlineTeamSearchLinkBase::LinkUpdate() { switch ( m_iLinkState ) { case STATE_SEARCHING_DEDICATED: Assert( m_pDsSearcher ); if ( m_pDsSearcher ) { m_pDsSearcher->Update(); if ( m_pDsSearcher->IsFinished() ) { OnDedicatedSearchFinished(); return; } } break;
case STATE_HOSTING_LISTEN_SERVER: if ( KeyValues *pServer = m_pHostSession->GetSessionSettings()->FindKey( "server" ) ) { // Listen server has started and we should notify the link peer
if ( KeyValues *pPeerCommand = new KeyValues( "TeamSearchLink::ListenClient" ) ) { KeyValues::AutoDelete autodelete( pPeerCommand ); pPeerCommand->SetString( "run", "xuid" ); pPeerCommand->SetUint64( "runxuid", m_xuidLinkPeer ); pPeerCommand->AddSubKey( pServer->MakeCopy() ); pPeerCommand->SetString( "server/server", "externalpeer" ); // for other team it is not a listen server, but externalpeer
pPeerCommand->SetInt( "server/team", 2 ); // other team is nominated team 2
LinkSysSession()->Command( pPeerCommand ); } m_iLinkState = STATE_LINK_FINISHED; } break; } }
void CMatchSessionOnlineTeamSearchLinkBase::LinkCommand( KeyValues *pCommand ) { char const *szCommand = pCommand->GetName();
if ( !Q_stricmp( "TeamSearchLink::Dedicated", szCommand ) || !Q_stricmp( "TeamSearchLink::ListenClient", szCommand ) ) { Assert( m_iLinkState == STATE_WAITING_FOR_PEER_SERVER ); KeyValues *pServerInfo = pCommand->FindKey( "server", false ); if ( !pServerInfo ) { ResetAndRestartTeamSearch(); return; }
// Apply host session update packet
ApplyHostSessionUpdatePacket(); // Notify our team about the server
if ( KeyValues *pOurTeamNotify = new KeyValues( CFmtStr( "TeamSearchResult::%s", szCommand + strlen( "TeamSearchLink::" ) ) ) ) { pOurTeamNotify->AddSubKey( pServerInfo->MakeCopy() ); OnSearchEvent( pOurTeamNotify ); } return; } }
void CMatchSessionOnlineTeamSearchLinkBase::StartHostingListenServer() { if ( mm_teamsearch_nostart.GetBool() ) { // Fake-cancel the session for debugging
m_pHostSession->Command( KeyValues::AutoDeleteInline( new KeyValues( "Cancel" ) ) ); return; }
m_iLinkState = STATE_HOSTING_LISTEN_SERVER;
// Update host session settings packet
ApplyHostSessionUpdatePacket(); OnSearchEvent( new KeyValues( "TeamSearchResult::ListenHost" ) ); }
void CMatchSessionOnlineTeamSearchLinkBase::StartDedicatedServerSearch() { if ( mm_teamsearch_nostart.GetBool() ) { // Fake-cancel the session for debugging
m_pHostSession->Command( KeyValues::AutoDeleteInline( new KeyValues( "Cancel" ) ) ); return; }
m_iLinkState = STATE_SEARCHING_DEDICATED;
// Notify everybody that we are searching for dedicated server now
OnSearchEvent( new KeyValues( "OnMatchSessionUpdate", "state", "progress", "progress", "dedicated" ) );
m_pDsSearcher = new CDsSearcher( m_pSettings, m_pHostSession->GetSessionSystemData()->GetUint64( "xuidReserve" ), NULL ); }
void CMatchSessionOnlineTeamSearchLinkBase::OnDedicatedSearchFinished() { Assert( m_pDsSearcher ); CDsSearcher::DsResult_t dsResult = m_pDsSearcher->GetResult();
m_pDsSearcher->Destroy(); m_pDsSearcher = NULL;
if ( !dsResult.m_bDedicated ) { StartHostingListenServer(); return; }
//
// Serialize the information about the dedicated server
//
KeyValues *pServerInfo = new KeyValues( "server" ); dsResult.CopyToServerKey( pServerInfo ); pServerInfo->SetUint64( "reservationid", m_pHostSession->GetSessionSystemData()->GetUint64( "xuidReserve" ) );
// Apply host session update packet
ApplyHostSessionUpdatePacket();
//
// Notify the peer team about the server
//
if ( KeyValues *pPeerCommand = new KeyValues( "TeamSearchLink::Dedicated" ) ) { KeyValues::AutoDelete autodelete( pPeerCommand ); pPeerCommand->SetString( "run", "xuid" ); pPeerCommand->SetUint64( "runxuid", m_xuidLinkPeer ); pServerInfo->SetInt( "team", 2 ); pPeerCommand->AddSubKey( pServerInfo->MakeCopy() ); LinkSysSession()->Command( pPeerCommand ); }
// Notify our team about the server
if ( KeyValues *pOurTeamNotify = new KeyValues( "TeamSearchResult::Dedicated" ) ) { pOurTeamNotify->SetPtr( "dsresult", &dsResult ); pServerInfo->SetInt( "team", 1 ); pOurTeamNotify->AddSubKey( pServerInfo ); OnSearchEvent( pOurTeamNotify ); }
m_iLinkState = STATE_LINK_FINISHED; }
void CMatchSessionOnlineTeamSearchLinkBase::StartWaitingForPeerServer() { m_iLinkState = STATE_WAITING_FOR_PEER_SERVER;
// Notify everybody that peer is searching for game server
OnSearchEvent( new KeyValues( "OnMatchSessionUpdate", "state", "progress", "progress", "peerserver" ) ); }
//////////////////////////////////////////////////////////////////////////
//
// Link host implementation
//
//
void CMatchSessionOnlineTeamSearchLinkHost::LinkInit() { m_iLinkState = STATE_SUBMIT_STATS; }
void CMatchSessionOnlineTeamSearchLinkHost::LinkUpdate() { switch ( m_iLinkState ) { case STATE_SUBMIT_STATS: { #ifdef _X360
m_pXlspConnection = new CXlspConnection( false ); CUtlVector< KeyValues * > arrCommands; #endif
if ( KeyValues *pCmd = new KeyValues( "stat_agg" ) ) { int numSeconds = int( 1 + Plat_FloatTime() - m_flCreationTime ); numSeconds = ClampArrayBounds( numSeconds, 30 * 60 ); // 30 minutes
pCmd->SetInt( "search_team_time", numSeconds );
#ifdef _X360
arrCommands.AddToTail( pCmd ); #elif !defined( NO_STEAM ) && !defined( NO_STEAM_GAMECOORDINATOR )
CGCClientJobUpdateStats *pJob = new CGCClientJobUpdateStats( pCmd ); pJob->StartJob( NULL ); #else
pCmd->deleteThis(); #endif
} #ifdef _X360
m_pXlspCommandBatch = new CXlspConnectionCmdBatch( m_pXlspConnection, arrCommands ); #endif
} m_iLinkState = STATE_REPORTING_STATS; break;
case STATE_REPORTING_STATS: #ifdef _X360
m_pXlspCommandBatch->Update(); if ( !m_pXlspCommandBatch->IsFinished() ) return;
m_pXlspCommandBatch->Destroy(); m_pXlspCommandBatch = NULL;
m_pXlspConnection->Destroy(); m_pXlspConnection = NULL; #endif
m_iLinkState = STATE_CONFIRM_JOIN; break;
case STATE_CONFIRM_JOIN: if ( KeyValues *pPeerCommand = new KeyValues( "TeamSearchLink::HostConfirmJoinReady" ) ) { KeyValues::AutoDelete autodelete( pPeerCommand ); pPeerCommand->SetString( "run", "xuid" ); pPeerCommand->SetUint64( "runxuid", m_xuidLinkPeer ); pPeerCommand->AddSubKey( m_pHostSession->GetSessionSettings()->MakeCopy() ); // Submit a copy of our session settings as well
m_pSysSessionHost->Command( pPeerCommand ); } m_iLinkState = STATE_CONFIRM_JOIN_WAIT; break;
case STATE_CONFIRM_JOIN_WAIT: // Waiting for client to tell us how to select server
break; }
CMatchSessionOnlineTeamSearchLinkBase::LinkUpdate(); }
void CMatchSessionOnlineTeamSearchLinkHost::LinkCommand( KeyValues *pCommand ) { char const *szCommand = pCommand->GetName();
if ( !Q_stricmp( "TeamSearchLink::TeamLinkSessionUpdate", szCommand ) ) { if ( KeyValues *pUpdatePkt = pCommand->GetFirstTrueSubKey() ) { m_pSettings->MergeFrom( pUpdatePkt ); RememberHostSessionUpdatePacket( pUpdatePkt->MakeCopy() ); } } else if ( !Q_stricmp( "TeamSearchLink::HostHosting", szCommand ) ) { // We are going to host
char const *szLinkHostServer = m_pSettings->GetString( "options/server", "" ); if ( !Q_stricmp( szLinkHostServer, "listen" ) ) StartHostingListenServer(); else StartDedicatedServerSearch(); return; } else if ( !Q_stricmp( "TeamSearchLink::ClientHosting", szCommand ) ) { // Our peer is going to host
StartWaitingForPeerServer(); return; }
CMatchSessionOnlineTeamSearchLinkBase::LinkCommand( pCommand ); }
//////////////////////////////////////////////////////////////////////////
//
// Link client implementation
//
//
void CMatchSessionOnlineTeamSearchLinkClient::LinkInit() { m_iLinkState = STATE_WAITING_FOR_HOST_READY; }
void CMatchSessionOnlineTeamSearchLinkClient::LinkUpdate() { switch ( m_iLinkState ) { case STATE_WAITING_FOR_HOST_READY: // We are waiting for host to report statistics and get the merged teamlink lobby ready
return;
case STATE_CONFIRM_JOIN: // m_pSettings has been set to the aggregate of host settings
// and our members, so we can inspect host's preference of the Server to
// decide who is going to search for the game server
{ char const *szLinkHostServer = m_pSettings->GetString( "options/server", "" ); char const *szOurServer = m_pHostSession->GetSessionSettings()->GetString( "options/server", "" ); if ( Q_stricmp( szLinkHostServer, "listen" ) && !Q_stricmp( szOurServer, "listen" ) ) { // Host doesn't care, but we need listen server
m_pSysSessionClient->Command( KeyValues::AutoDeleteInline( new KeyValues( "TeamSearchLink::ClientHosting", "run", "host" ) ) ); StartHostingListenServer(); } else { // Let host find the server
m_pSysSessionClient->Command( KeyValues::AutoDeleteInline( new KeyValues( "TeamSearchLink::HostHosting", "run", "host" ) ) ); StartWaitingForPeerServer(); } } return; }
CMatchSessionOnlineTeamSearchLinkBase::LinkUpdate(); }
void CMatchSessionOnlineTeamSearchLinkClient::LinkCommand( KeyValues *pCommand ) { char const *szCommand = pCommand->GetName();
if ( !Q_stricmp( "TeamSearchLink::HostConfirmJoinReady", szCommand ) ) { // Host has sent us full settings of the host session,
// let's try to reconcile and summarize the settings and prepare an update package if needed
KeyValues *pRemoteSettings = pCommand->GetFirstTrueSubKey(); KeyValues *pLocalSettings = m_pHostSession->GetSessionSettings();
if ( KeyValues *pUpdatePkt = g_pMMF->GetMatchTitleGameSettingsMgr()->PrepareTeamLinkForGame( pLocalSettings, pRemoteSettings ) ) { if ( KeyValues *pHostCmd = new KeyValues( "TeamSearchLink::TeamLinkSessionUpdate", "run", "host" ) ) { pHostCmd->AddSubKey( pUpdatePkt->MakeCopy() ); m_pSysSessionClient->Command( KeyValues::AutoDeleteInline( pHostCmd ) ); }
m_pSettings->MergeFrom( pUpdatePkt ); RememberHostSessionUpdatePacket( pUpdatePkt ); }
// Host is now ready
if ( m_iLinkState == STATE_WAITING_FOR_HOST_READY ) m_iLinkState = STATE_CONFIRM_JOIN; return; }
CMatchSessionOnlineTeamSearchLinkBase::LinkCommand( pCommand ); }
|