|
|
//========= Copyright � 1996-2009, Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=====================================================================================//
#ifndef _X360
#include "xbox/xboxstubs.h"
#endif
#include "mm_framework.h"
#include "match_searcher.h"
#if !defined( _X360 ) && !defined( NO_STEAM ) && !defined( SWDS )
#include "steam/matchmakingtypes.h"
#endif
#include "proto_oob.h"
#include "fmtstr.h"
// NOTE: This has to be the last file included!
#include "tier0/memdbgon.h"
#pragma warning (disable : 4355 )
static ConVar mm_match_search_update_interval( "mm_match_search_update_interval", "10", FCVAR_DEVELOPMENTONLY, "Interval between matchsearcher updates." );
//
// Match searching overrides
//
class CMatchSearcher_SearchMgr : public CMatchSearcher { public: CMatchSearcher_SearchMgr( CSearchManager *pMgr, KeyValues *pSettings );
public: virtual void StartSearchPass( KeyValues *pSearchPass ); virtual void OnSearchEvent( KeyValues *pNotify ); virtual void OnSearchDone();
protected: CSearchManager *m_pMgr; };
class CMatchSearchResultItem : public IMatchSearchResult { public: explicit CMatchSearchResultItem( XUID xuid, KeyValues *pDetails ); ~CMatchSearchResultItem();
public: virtual XUID GetOnlineId() { return m_xuid; } virtual KeyValues * GetGameDetails() { return m_pDetails; } virtual bool IsJoinable() { return m_pDetails != NULL; } virtual void Join();
protected: XUID m_xuid; KeyValues *m_pDetails; };
//
// Pool of search managers
//
typedef CUtlVector< CSearchManager * > SearchManagerPool;
static SearchManagerPool & GetSearchManagerPool() { static SearchManagerPool s_smp; return s_smp; }
void CSearchManager::UpdateAll() { SearchManagerPool &smp = GetSearchManagerPool(); for ( int k = 0; k < smp.Count(); ) { CSearchManager *pUpdate = smp[k]; pUpdate->Update(); if ( smp.IsValidIndex( k ) && smp[k] == pUpdate ) ++ k; } }
//
// Search manager implementation
//
CSearchManager::CSearchManager( KeyValues *pSearchParams ) : m_pSettings( pSearchParams ? pSearchParams->MakeCopy() : NULL ), m_pSearcher( NULL ), m_eState( STATE_IDLE ) { GetSearchManagerPool().AddToTail( this ); DevMsg( "Created CSearchManager(%p):\n", this ); KeyValuesDumpAsDevMsg( m_pSettings, 1 ); }
CSearchManager::~CSearchManager() { GetSearchManagerPool().FindAndRemove( this );
DevMsg( "Destroying CSearchManager(%p):\n", this ); KeyValuesDumpAsDevMsg( m_pSettings, 1 );
if ( m_pSearcher ) m_pSearcher->Destroy(); m_pSearcher = NULL;
if ( m_pSettings ) m_pSettings->deleteThis(); m_pSettings = NULL;
ClearResults( m_arrResults ); }
void CSearchManager::ClearResults( CUtlVector< IMatchSearchResult * > &arr ) { for ( int k = 0; k < arr.Count(); ++ k ) { IMatchSearchResult *p = arr[k]; CMatchSearchResultItem *pItem = ( CMatchSearchResultItem * ) p; delete pItem; } arr.RemoveAll(); }
void CSearchManager::EnableResultsUpdate( bool bEnable, KeyValues *pSearchParams /* = NULL */ ) { if ( bEnable && pSearchParams ) { if ( m_pSettings ) m_pSettings->deleteThis();
m_pSettings = pSearchParams->MakeCopy(); } if ( !bEnable && m_pSettings ) { m_pSettings->deleteThis(); }
switch ( m_eState ) { case STATE_PAUSED: m_eState = STATE_IDLE; break;
case STATE_SEARCHING: m_eState = STATE_SEARCHING_CRITERIA_UPDATED; break; } }
int CSearchManager::GetNumResults() { return m_arrResults.Count(); }
IMatchSearchResult * CSearchManager::GetResultByIndex( int iResultIdx ) { return m_arrResults.IsValidIndex( iResultIdx ) ? m_arrResults[ iResultIdx ] : NULL; }
IMatchSearchResult * CSearchManager::GetResultByOnlineId( XUID xuidResultOnline ) { return GetResultById( m_arrResults, xuidResultOnline ); }
IMatchSearchResult * CSearchManager::GetResultById( CUtlVector< IMatchSearchResult * > &arr, XUID id ) { for ( int k = 0; k < arr.Count(); ++ k ) { IMatchSearchResult *pResult = arr[k]; if ( pResult && ( pResult->GetOnlineId() == id ) ) return pResult; } return NULL; }
void CSearchManager::Destroy() { if ( m_pSearcher ) m_pSearcher->Destroy(); m_pSearcher = NULL;
delete this; }
void CSearchManager::OnEvent( KeyValues *pEvent ) { }
void CSearchManager::Update() { switch ( m_eState ) { case STATE_IDLE: if ( m_pSettings ) { m_eState = STATE_SEARCHING; if( m_pSearcher ) m_pSearcher->Destroy(); m_pSearcher = new CMatchSearcher_SearchMgr( this, m_pSettings->MakeCopy() ); } break;
case STATE_SEARCHING: case STATE_SEARCHING_CRITERIA_UPDATED: Assert( m_pSearcher ); m_pSearcher->Update(); break;
case STATE_PAUSED: if ( Plat_FloatTime() > m_flNextSearchTime && !IsLocalClientConnectedToServer() ) { // Trigger another search
m_eState = STATE_IDLE; } break; } }
void CSearchManager::OnSearchDone() { if ( m_eState == STATE_SEARCHING_CRITERIA_UPDATED ) { m_eState = STATE_IDLE; } else { m_eState = STATE_PAUSED; m_flNextSearchTime = Plat_FloatTime() + mm_match_search_update_interval.GetFloat(); }
// Prepare the new results
IMatchTitleGameSettingsMgr *mgr = g_pMMF->GetMatchTitleGameSettingsMgr(); CUtlVector< IMatchSearchResult * > arrResults;
// Now traverse the results we received and roll them up
for ( int k = 0, kNum = m_pSearcher->GetNumSearchResults(); k < kNum; ++ k ) { CMatchSearcher::SearchResult_t const &sr = m_pSearcher->GetSearchResult( k );
KeyValues *pDetails = sr.GetGameDetails(); if ( !pDetails ) continue;
// Determine the rollup key
KeyValues *pRollupKey = mgr->RollupGameDetails( pDetails, NULL, m_pSearcher->GetSearchSettings() ); KeyValues::AutoDelete autodelete_pRollupKey( pRollupKey ); if ( !pRollupKey ) continue;
// Find if we already have the rollup information for it
XUID uidKey = pRollupKey->GetUint64( "rollupkey", 0ull ); if ( !uidKey ) continue;
IMatchSearchResult *pResult = GetResultById( arrResults, uidKey ); if ( !pResult ) { pResult = new CMatchSearchResultItem( uidKey, pRollupKey ); arrResults.AddToTail( pResult ); }
// Roll up these details into an already existing or newly created rollup
mgr->RollupGameDetails( pDetails, pResult->GetGameDetails(), m_pSearcher->GetSearchSettings() ); }
// Now after all the rollup is finished, process ones that have not had any matching details
for ( int k = 0; k < m_arrResults.Count(); ++ k ) { IMatchSearchResult *pOldResult = m_arrResults[k]; XUID uidKey = pOldResult->GetOnlineId(); if ( GetResultById( arrResults, uidKey ) ) continue; // have fresh data
if ( !mgr->RollupGameDetails( NULL, pOldResult->GetGameDetails(), m_pSearcher->GetSearchSettings() ) ) continue; // cannot keep this result
arrResults.AddToTail( pOldResult ); m_arrResults.FastRemove( k -- ); }
// Remove all old results, swap for new results and broadcast a notification
ClearResults( m_arrResults ); m_arrResults.Swap( arrResults ); }
//
// MatchSearcher override
//
CMatchSearcher_SearchMgr::CMatchSearcher_SearchMgr( CSearchManager *pMgr, KeyValues *pSettings ) : CMatchSearcher( pSettings ), m_pMgr( pMgr ) { // Let the title extend the game settings
g_pMMF->GetMatchTitleGameSettingsMgr()->InitializeGameSettings( m_pSettings, "search_rollup" );
DevMsg( "CMatchSearcher_SearchMgr title adjusted settings:\n" ); KeyValuesDumpAsDevMsg( m_pSettings, 1 );
// Signal that we are starting a search
KeyValues *pNotify = new KeyValues( "OnMatchSearchMgrUpdate", "update", "searchstarted" ); pNotify->SetPtr( "mgr", m_pMgr ); g_pMatchFramework->GetEventsSubscription()->BroadcastEvent( pNotify ); }
void CMatchSearcher_SearchMgr::StartSearchPass( KeyValues *pSearchPass ) { CMatchSearcher::StartSearchPass( pSearchPass ); }
void CMatchSearcher_SearchMgr::OnSearchEvent( KeyValues *pNotify ) { // Swallow events
pNotify->deleteThis(); }
void CMatchSearcher_SearchMgr::OnSearchDone() { CMatchSearcher::OnSearchDone(); m_pMgr->OnSearchDone();
// Signal that we are finished with search
KeyValues *pNotify = new KeyValues( "OnMatchSearchMgrUpdate", "update", "searchfinished" ); pNotify->SetPtr( "mgr", m_pMgr ); g_pMatchFramework->GetEventsSubscription()->BroadcastEvent( pNotify ); }
//
// CMatchSearchResultItem implementation
//
CMatchSearchResultItem::CMatchSearchResultItem( XUID xuid, KeyValues *pDetails ) : m_xuid( xuid ), m_pDetails( pDetails ? pDetails->MakeCopy() : NULL ) { }
CMatchSearchResultItem::~CMatchSearchResultItem() { if ( m_pDetails ) m_pDetails->deleteThis(); m_pDetails = NULL; }
void CMatchSearchResultItem::Join() { if ( !m_pDetails ) return;
// Detach details
KeyValues *pSettings = m_pDetails; m_pDetails = NULL;
// Trigger matchmaking
g_pMatchFramework->MatchSession( pSettings );
// Delete settings
pSettings->deleteThis(); }
|