Counter Strike : Global Offensive Source Code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

735 lines
21 KiB

  1. //========= Copyright � 1996-2009, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=====================================================================================//
  6. #ifndef _X360
  7. #include "xbox/xboxstubs.h"
  8. #endif
  9. #include "mm_framework.h"
  10. #if !defined( _X360 ) && !defined( NO_STEAM ) && !defined( SWDS )
  11. #include "steam/matchmakingtypes.h"
  12. #endif
  13. #include "proto_oob.h"
  14. #include "fmtstr.h"
  15. // NOTE: This has to be the last file included!
  16. #include "tier0/memdbgon.h"
  17. #pragma warning (disable : 4355 )
  18. size_t const mm_filter_max_size = 128; // Maximum size of a filter key, it's key+value+3
  19. static ConVar mm_server_search_update_interval( "mm_server_search_update_interval", "60", FCVAR_DEVELOPMENTONLY, "Interval between servers updates." );
  20. static ConVar mm_server_search_inet_ping_interval( "mm_server_search_inet_ping_interval", "1.0", FCVAR_DEVELOPMENTONLY, "How long to wait between pinging internet server details." );
  21. static ConVar mm_server_search_inet_ping_timeout( "mm_server_search_inet_ping_timeout", "3.0", FCVAR_DEVELOPMENTONLY, "How long to wait for internet server details." );
  22. static ConVar mm_server_search_inet_ping_window( "mm_server_search_inet_ping_window", "10", FCVAR_DEVELOPMENTONLY, "How many servers can be pinged for server details in a batch." );
  23. static ConVar mm_server_search_inet_ping_refresh( "mm_server_search_inet_ping_refresh", "15", FCVAR_DEVELOPMENTONLY, "How often to refresh a listed server." );
  24. static ConVar mm_server_search_server_lifetime( "mm_server_search_server_lifetime", "180", FCVAR_DEVELOPMENTONLY, "How long until a server is no longer returned by the master till we remove it." );
  25. static ConVar mm_server_search_lan_ping_interval( "mm_server_search_lan_ping_interval", "0.4", FCVAR_DEVELOPMENTONLY, "Interval between LAN discovery pings." );
  26. static ConVar mm_server_search_lan_ping_duration( "mm_server_search_lan_ping_duration", "1.0", FCVAR_DEVELOPMENTONLY, "Duration of LAN discovery ping phase." );
  27. static ConVar mm_server_search_lan_ports( "mm_server_search_lan_ports",
  28. "27015,27016,27017,27018,27019,27020",
  29. FCVAR_RELEASE | FCVAR_ARCHIVE,
  30. "Ports to scan during LAN games discovery. Also used to discover and correctly connect to dedicated LAN servers behind NATs." );
  31. //
  32. // Server implementation
  33. //
  34. class CServerPinging : public CServer
  35. {
  36. public:
  37. CServerPinging() : m_flTimeout( 0 ) {}
  38. public:
  39. #if !defined( _X360 ) && !defined( NO_STEAM ) && !defined( SWDS )
  40. gameserveritem_t m_gsi;
  41. #endif
  42. float m_flTimeout;
  43. };
  44. CServer::CServer() :
  45. m_flLastRefresh( Plat_FloatTime() ),
  46. m_xuid( 0ull ),
  47. m_pGameDetails( NULL )
  48. {
  49. }
  50. CServer::~CServer()
  51. {
  52. if ( m_pGameDetails )
  53. m_pGameDetails->deleteThis();
  54. m_pGameDetails = NULL;
  55. }
  56. XUID CServer::GetOnlineId()
  57. {
  58. return m_xuid;
  59. }
  60. KeyValues * CServer::GetGameDetails()
  61. {
  62. return m_pGameDetails;
  63. }
  64. bool CServer::IsJoinable()
  65. {
  66. return m_pGameDetails != NULL;
  67. }
  68. void CServer::Join()
  69. {
  70. char const *szConnectString = m_pGameDetails->GetString( "server/connectstring", NULL );
  71. if ( !szConnectString || !*szConnectString )
  72. return;
  73. g_pMatchExtensions->GetIVEngineClient()->ClientCmd( CFmtStr( "connect %s\n", szConnectString ) );
  74. }
  75. //
  76. // Server manager implementation
  77. //
  78. CServerManager::CServerManager()
  79. {
  80. #if !defined( _X360 ) && !defined( NO_STEAM ) && !defined( SWDS )
  81. m_hRequest = NULL;
  82. #endif
  83. m_bUpdateEnabled = false;
  84. m_flNextUpdateTime = 0.0f;
  85. m_flNextServerUpdateTime = 0.0f;
  86. m_eState = STATE_IDLE;
  87. }
  88. CServerManager::~CServerManager()
  89. {
  90. m_Servers.PurgeAndDeleteElements();
  91. m_ServersPinging.PurgeAndDeleteElements();
  92. #if !defined( _X360 ) && !defined( NO_STEAM ) && !defined( SWDS )
  93. if ( m_hRequest )
  94. steamapicontext->SteamMatchmakingServers()->ReleaseRequest( m_hRequest );
  95. m_hRequest = NULL;
  96. #endif
  97. }
  98. static CServerManager g_ServerManager;
  99. CServerManager *g_pServerManager = &g_ServerManager;
  100. void CServerManager::EnableServersUpdate( bool bEnable )
  101. {
  102. if ( bEnable &&
  103. ( g_pMatchFramework->GetMatchTitle()->GetTitleSettingsFlags() & MATCHTITLE_SERVERMGR_DISABLED ) )
  104. bEnable = false;
  105. m_bUpdateEnabled = bEnable;
  106. m_flNextUpdateTime = 0.0f;
  107. // If enabled the search, we'll pick it up next update
  108. if ( bEnable )
  109. return;
  110. // Otherwise search is being disabled
  111. m_Servers.PurgeAndDeleteElements();
  112. m_ServersPinging.PurgeAndDeleteElements();
  113. #if !defined( _X360 ) && !defined( NO_STEAM ) && !defined( SWDS )
  114. if ( m_eState == STATE_FETCHING_SERVERS && m_hRequest )
  115. {
  116. steamapicontext->SteamMatchmakingServers()->ReleaseRequest( m_hRequest );
  117. m_hRequest = NULL;
  118. }
  119. #endif
  120. // Will clean up all servers and go IDLE
  121. OnAllDataFetched();
  122. }
  123. int CServerManager::GetNumServers()
  124. {
  125. return m_Servers.Count();
  126. }
  127. IMatchServer * CServerManager::GetServerByIndex( int iServerIdx )
  128. {
  129. return m_Servers.IsValidIndex( iServerIdx ) ? m_Servers[ iServerIdx ] : NULL;
  130. }
  131. IMatchServer * CServerManager::GetServerByOnlineId( XUID xuidServerOnline )
  132. {
  133. return GetServerRecordByOnlineId( m_Servers, xuidServerOnline );
  134. }
  135. CServer * CServerManager::GetServerRecordByOnlineId( CUtlVector< CServer * > &arr, XUID xuidServerOnline )
  136. {
  137. for ( int k = 0; k < arr.Count(); ++ k )
  138. {
  139. CServer *pServer = arr[ k ];
  140. if ( pServer && pServer->GetOnlineId() == xuidServerOnline )
  141. return pServer;
  142. }
  143. return NULL;
  144. }
  145. void CServerManager::OnEvent( KeyValues *pEvent )
  146. {
  147. if ( IsX360() )
  148. return;
  149. char const *szName = pEvent->GetName();
  150. if ( !Q_stricmp( szName, "OnNetLanConnectionlessPacket" ) )
  151. {
  152. char const * arrServerProbeKeys[] = { "LanSearchServerPing", "ConnectServerDetailsRequest", "InetSearchServerDetails" };
  153. for ( int k = 0; k < ARRAYSIZE( arrServerProbeKeys ); ++ k )
  154. {
  155. KeyValues *pProbeKey = pEvent->FindKey( arrServerProbeKeys[k] );
  156. if ( !pProbeKey )
  157. continue;
  158. KeyValues *pDetails = g_pMatchFramework->GetMatchNetworkMsgController()->GetActiveServerGameDetails( pEvent );
  159. KeyValues::AutoDelete autodelete_pDetails( pDetails );
  160. if ( !pDetails )
  161. return;
  162. if ( !pDetails->FindKey( "server" ) )
  163. return;
  164. pDetails->FindKey( arrServerProbeKeys[k], true )->MergeFrom( pProbeKey, KeyValues::MERGE_KV_UPDATE );
  165. g_pConnectionlessLanMgr->SendPacket( pDetails, pEvent->GetString( "from" ), INetSupport::NS_SOCK_SERVER );
  166. return;
  167. }
  168. if ( KeyValues *pGameDetailsServer = pEvent->FindKey( "GameDetailsServer" ) )
  169. {
  170. // Incoming data:
  171. //
  172. // System
  173. // Game
  174. // Server
  175. // Members
  176. // LanSearchServerPing
  177. // timestamp = holds the time packet was sent for ping
  178. // Server ping
  179. int nPing = 0;
  180. if ( float flTimeSent = pGameDetailsServer->GetFloat( "LanSearchServerPing/timestamp" ) )
  181. {
  182. float flSeconds = Plat_FloatTime() - flTimeSent;
  183. nPing = flSeconds * 1000;
  184. if ( nPing < 0 )
  185. nPing = 0;
  186. if ( nPing >= 1000 )
  187. nPing = 999;
  188. }
  189. else if ( uint64 xuidInetPing = pGameDetailsServer->GetUint64( "InetSearchServerDetails/pingxuid" ) )
  190. {
  191. CServerPinging *pServerPinging = ( CServerPinging * ) GetServerRecordByOnlineId( m_ServersPinging, xuidInetPing );
  192. if ( !pServerPinging )
  193. return;
  194. if ( float flTimeSent = pGameDetailsServer->GetFloat( "InetSearchServerDetails/timestamp" ) )
  195. {
  196. float flSeconds = Plat_FloatTime() - flTimeSent;
  197. nPing = flSeconds * 1000;
  198. if ( nPing < 0 )
  199. nPing = 0;
  200. if ( nPing >= 1000 )
  201. nPing = 999;
  202. }
  203. #if !defined( _X360 ) && !defined( NO_STEAM ) && !defined( SWDS )
  204. else
  205. {
  206. nPing = pServerPinging->m_gsi.m_nPing;
  207. }
  208. #endif
  209. // Remove the server from outstanding pings list
  210. m_ServersPinging.FindAndFastRemove( pServerPinging );
  211. delete pServerPinging;
  212. }
  213. else if ( char const *szDetailsAdr = pGameDetailsServer->GetString( "ConnectServerDetailsRequest/server" ) )
  214. {
  215. g_pMatchExtensions->GetINetSupport()->OnMatchEvent( pEvent );
  216. return;
  217. }
  218. else
  219. return;
  220. // Server address
  221. char const *szAddr = pGameDetailsServer->GetString( "server/adronline", NULL );
  222. if ( !szAddr || !*szAddr )
  223. return;
  224. // Determine server network address
  225. netadr_t netAddress;
  226. netAddress.SetType( NA_IP );
  227. netAddress.SetPort( PORT_SERVER );
  228. netAddress.SetFromString( szAddr );
  229. // Check if this is not our local server
  230. INetSupport::ServerInfo_t si;
  231. g_pMatchExtensions->GetINetSupport()->GetServerInfo( &si );
  232. if ( si.m_bActive && ( si.m_netAdr.CompareAdr( netAddress ) || si.m_netAdrOnline.CompareAdr( netAddress ) ) )
  233. return;
  234. // Coalesce it into its XUID online id
  235. XUID xuidOnline = uint64( netAddress.GetIPNetworkByteOrder() ) | ( uint64( netAddress.GetPort() ) << 32ull );
  236. // Prepare the settings
  237. KeyValues *pSettings = pGameDetailsServer->MakeCopy();
  238. pSettings->SetName( "settings" );
  239. if ( KeyValues *kvLanSearch = pSettings->FindKey( "LanSearch" ) )
  240. {
  241. pSettings->RemoveSubKey( kvLanSearch );
  242. kvLanSearch->deleteThis();
  243. }
  244. pSettings->SetInt( "server/ping", nPing );
  245. if ( char const *szPacketFrom = pEvent->GetString( "from", NULL ) )
  246. pSettings->SetString( "server/connectstring", szPacketFrom );
  247. //
  248. // Find the server or create a new one
  249. //
  250. IMatchServer *pExistingServer = GetServerByOnlineId( xuidOnline );
  251. CServer *pServer = ( CServer * ) pExistingServer;
  252. if ( !pServer )
  253. {
  254. pServer = new CServer();
  255. pServer->m_xuid = xuidOnline;
  256. #if !defined( NO_STEAM ) && !defined( SWDS )
  257. servernetadr_t serverNetAddr;
  258. serverNetAddr.Init( netAddress.GetIPHostByteOrder(), netAddress.GetPort(), netAddress.GetPort() );
  259. pServer->m_netAdr = serverNetAddr;
  260. #endif
  261. m_Servers.AddToTail( pServer );
  262. }
  263. if ( pServer->m_pGameDetails )
  264. {
  265. // Average out the ping value
  266. int nKnownPing = pServer->m_pGameDetails->GetInt( "server/ping", 0 );
  267. if ( nKnownPing < nPing )
  268. {
  269. // we got a high ping, try to display the ping as low as possible
  270. nPing = ( nKnownPing * 9 + nPing * 1 ) / 10;
  271. pSettings->SetInt( "server/ping", nPing );
  272. }
  273. pServer->m_pGameDetails->deleteThis();
  274. }
  275. pServer->m_pGameDetails = pSettings;
  276. pServer->m_flLastRefresh = Plat_FloatTime();
  277. // Signal that we have updated a server
  278. KeyValues *kvEvent = new KeyValues( "OnMatchServerMgrUpdate", "update", "server" );
  279. kvEvent->SetUint64( "xuid", xuidOnline );
  280. g_pMatchFramework->GetEventsSubscription()->BroadcastEvent( kvEvent );
  281. }
  282. }
  283. else if ( !Q_stricmp( "Client::ResendGameDetailsRequest", szName ) )
  284. {
  285. KeyValues *kv = new KeyValues( "ConnectServerDetailsRequest" );
  286. KeyValues::AutoDelete autodelete( kv );
  287. kv->SetString( "server", pEvent->GetString( "to", "" ) );
  288. g_pConnectionlessLanMgr->SendPacket( kv, pEvent->GetString( "to", "" ) );
  289. }
  290. }
  291. #if !defined( _X360 ) && !defined( NO_STEAM ) && !defined( SWDS )
  292. void CServerManager::ServerResponded( HServerListRequest hReq, int iServer )
  293. {
  294. gameserveritem_t *gsi = steamapicontext->SteamMatchmakingServers()->GetServerDetails( hReq, iServer );
  295. if ( !gsi )
  296. return;
  297. // Every time a server responds during groups query, bump this groups last request timeout
  298. m_lanSearchData.m_flLastBroadcastTime = Plat_FloatTime();
  299. // Determine server network address
  300. netadr_t netAddress;
  301. netAddress.SetType( NA_IP );
  302. netAddress.SetPort( PORT_SERVER );
  303. netAddress.SetFromString( gsi->m_NetAdr.GetConnectionAddressString() );
  304. // Coalesce it into its XUID online id
  305. XUID xuidOnline = uint64( netAddress.GetIPNetworkByteOrder() ) | ( uint64( netAddress.GetPort() ) << 32ull );
  306. // Check if we have a pinging record for this server
  307. CServerPinging *pServer = ( CServerPinging * ) GetServerRecordByOnlineId( m_ServersPinging, xuidOnline );
  308. if ( pServer )
  309. {
  310. // We already have a pinging record for this server, just update its info
  311. pServer->m_gsi = *gsi;
  312. pServer->m_netAdr = gsi->m_NetAdr;
  313. return;
  314. }
  315. // Create a new pinging record
  316. pServer = new CServerPinging();
  317. pServer->m_xuid = xuidOnline;
  318. pServer->m_gsi = *gsi;
  319. pServer->m_netAdr = gsi->m_NetAdr;
  320. m_ServersPinging.AddToTail( pServer );
  321. }
  322. void CServerManager::RefreshComplete( HServerListRequest hReq, EMatchMakingServerResponse response )
  323. {
  324. if ( m_eState == STATE_FETCHING_SERVERS )
  325. m_eState = STATE_GROUP_FETCHED;
  326. steamapicontext->SteamMatchmakingServers()->ReleaseRequest( m_hRequest );
  327. m_hRequest = NULL;
  328. }
  329. #endif
  330. void CServerManager::Update()
  331. {
  332. #if !( !defined( _X360 ) && !defined( NO_STEAM ) && !defined( SWDS ) )
  333. return;
  334. #endif
  335. float now = Plat_FloatTime();
  336. switch ( m_eState )
  337. {
  338. case STATE_IDLE:
  339. if ( m_bUpdateEnabled && !IsLocalClientConnectedToServer() )
  340. {
  341. if ( now > m_flNextUpdateTime )
  342. {
  343. MarkOldServersAndBeginSearch();
  344. }
  345. else if ( now > m_flNextServerUpdateTime )
  346. {
  347. float nextUpdatePeriod = mm_server_search_inet_ping_refresh.GetFloat();
  348. // any servers not in the pinging list but haven't been refreshed in a while should be refreshed
  349. for ( int i = 0; i < m_Servers.Count(); ++i )
  350. {
  351. float timePassed = now - m_Servers[i]->m_flLastRefresh;
  352. if ( timePassed > mm_server_search_inet_ping_refresh.GetFloat() )
  353. {
  354. CServerPinging *pServerPinging = ( CServerPinging * ) GetServerRecordByOnlineId( m_ServersPinging, m_Servers[i]->GetOnlineId() );
  355. if ( !pServerPinging )
  356. {
  357. pServerPinging = new CServerPinging();
  358. pServerPinging->m_xuid = m_Servers[i]->GetOnlineId();
  359. #if !defined( NO_STEAM ) && !defined( SWDS )
  360. pServerPinging->m_netAdr = m_Servers[i]->m_netAdr;
  361. #endif
  362. m_ServersPinging.AddToTail( pServerPinging );
  363. }
  364. }
  365. else
  366. {
  367. nextUpdatePeriod = MIN( nextUpdatePeriod, mm_server_search_inet_ping_refresh.GetFloat() - timePassed );
  368. }
  369. }
  370. m_flNextServerUpdateTime = now + nextUpdatePeriod;
  371. m_eState = STATE_REQUESTING_DETAILS;
  372. break;
  373. }
  374. }
  375. break;
  376. case STATE_LAN_SEARCH:
  377. UpdateLanSearch();
  378. break;
  379. case STATE_GROUP_SEARCH:
  380. if ( StartFetchingGroupServersData() )
  381. break;
  382. // else -> // fall through
  383. case STATE_GROUP_FETCHED:
  384. OnGroupFetched();
  385. break;
  386. #if !defined( _X360 ) && !defined( NO_STEAM ) && !defined( SWDS )
  387. case STATE_FETCHING_SERVERS:
  388. if ( Plat_FloatTime() > m_lanSearchData.m_flLastBroadcastTime + mm_server_search_inet_ping_timeout.GetFloat() )
  389. {
  390. steamapicontext->SteamMatchmakingServers()->ReleaseRequest( m_hRequest );
  391. m_hRequest = NULL;
  392. m_eState = STATE_GROUP_FETCHED;
  393. }
  394. break;
  395. #endif
  396. case STATE_REQUESTING_DETAILS:
  397. UpdateRequestingDetails();
  398. break;
  399. }
  400. }
  401. void CServerManager::MarkOldServersAndBeginSearch()
  402. {
  403. DevMsg( 2, "Server manager refreshing...\n" );
  404. // Signal that we are starting a search
  405. g_pMatchFramework->GetEventsSubscription()->BroadcastEvent( new KeyValues(
  406. "OnMatchServerMgrUpdate", "update", "searchstarted" ) );
  407. m_ServersPinging.PurgeAndDeleteElements();
  408. m_groupSearchData.Reset();
  409. m_lanSearchData = SLanSearchData_t();
  410. m_eState = STATE_LAN_SEARCH;
  411. // If broadcasts are disallowed, then go straight to group search state
  412. extern ConVar net_allow_multicast;
  413. if ( !net_allow_multicast.GetBool() )
  414. m_eState = STATE_GROUP_SEARCH;
  415. }
  416. void CServerManager::UpdateLanSearch()
  417. {
  418. if ( m_lanSearchData.m_flStartTime && m_lanSearchData.m_flLastBroadcastTime )
  419. {
  420. if ( Plat_FloatTime() > m_lanSearchData.m_flStartTime + mm_server_search_lan_ping_duration.GetFloat() )
  421. {
  422. m_eState = STATE_GROUP_SEARCH;
  423. return;
  424. }
  425. if ( Plat_FloatTime() < m_lanSearchData.m_flLastBroadcastTime + mm_server_search_lan_ping_interval.GetFloat() )
  426. {
  427. // waiting out interval between pings
  428. return;
  429. }
  430. }
  431. else
  432. {
  433. // Initialize the start time of the lan broadcast
  434. m_lanSearchData.m_flStartTime = Plat_FloatTime();
  435. }
  436. //
  437. // Send the packet
  438. //
  439. m_lanSearchData.m_flLastBroadcastTime = Plat_FloatTime();
  440. KeyValues *kv = new KeyValues( "LanSearchServerPing" );
  441. KeyValues::AutoDelete autodelete( kv );
  442. kv->SetFloat( "timestamp", Plat_FloatTime() );
  443. if ( mm_server_search_lan_ports.GetString()[0] )
  444. {
  445. // Build the list of ports to scan
  446. CSplitString arrPorts( mm_server_search_lan_ports.GetString(), "," );
  447. for ( int i = 0; i < arrPorts.Count(); i++ )
  448. {
  449. // Port number
  450. int nPort = Q_atoi( arrPorts[i] );
  451. if ( nPort <= 0 )
  452. continue;
  453. g_pConnectionlessLanMgr->SendPacket( kv, CFmtStr( "*:%d", nPort ) );
  454. }
  455. }
  456. }
  457. void CServerManager::RemoveOldServers()
  458. {
  459. float now = Plat_FloatTime();
  460. for ( int k = 0; k < m_Servers.Count(); ++ k )
  461. {
  462. CServer *pServer = m_Servers[ k ];
  463. if ( pServer && now - pServer->m_flLastRefresh < mm_server_search_server_lifetime.GetFloat() )
  464. continue;
  465. m_Servers.Remove( k -- );
  466. }
  467. }
  468. bool CServerManager::StartFetchingGroupServersData()
  469. {
  470. #if !defined( _X360 ) && !defined( NO_STEAM ) && !defined( SWDS )
  471. ISteamUser *pUser = steamapicontext->SteamUser();
  472. ISteamFriends *pFriends = steamapicontext->SteamFriends();
  473. if ( !pUser || !pFriends )
  474. return false;
  475. int iGroupCount = pFriends->GetClanCount();
  476. if ( !iGroupCount )
  477. return false;
  478. m_groupSearchData.m_UserGroupAccountIDs.SetCount( iGroupCount );
  479. for ( int k = 0; k < iGroupCount; ++ k )
  480. {
  481. m_groupSearchData.m_UserGroupAccountIDs[ k ] = pFriends->GetClanByIndex( k ).GetAccountID();
  482. }
  483. return FetchGroupServers();
  484. #else
  485. return false;
  486. #endif
  487. }
  488. bool CServerManager::FetchGroupServers()
  489. {
  490. #if !defined( _X360 ) && !defined( NO_STEAM ) && !defined( SWDS )
  491. static const char gamedataFilterType[] = "gamedataor";
  492. char gamedataFitler[ mm_filter_max_size ];
  493. *gamedataFitler = 0;
  494. size_t roomLeft = mm_filter_max_size - strlen( gamedataFilterType ) - 3;
  495. // Add as many groups as will fit
  496. while ( m_groupSearchData.m_idxSearchGroupId < m_groupSearchData.m_UserGroupAccountIDs.Count() )
  497. {
  498. const char *tag = CFmtStr( *gamedataFitler ? ",grp:%ui" : "grp:%ui", m_groupSearchData.m_UserGroupAccountIDs[ m_groupSearchData.m_idxSearchGroupId ] );
  499. if ( roomLeft < strlen( tag ) )
  500. {
  501. break;
  502. }
  503. Q_strncat( gamedataFitler, tag, mm_filter_max_size );
  504. roomLeft -= strlen( tag );
  505. ++m_groupSearchData.m_idxSearchGroupId;
  506. }
  507. MatchMakingKeyValuePair_t filters[ 2 ] = {
  508. // filter by game
  509. MatchMakingKeyValuePair_t( "gamedir", COM_GetModDirectory() ),
  510. // look for group servers
  511. MatchMakingKeyValuePair_t( gamedataFilterType, gamedataFitler )
  512. };
  513. // request the server list. We will get called back at ServerResponded, ServerFailedToRespond, and RefreshComplete
  514. m_eState = STATE_FETCHING_SERVERS;
  515. m_lanSearchData.m_flLastBroadcastTime = Plat_FloatTime();
  516. MatchMakingKeyValuePair_t *pFilter = filters;
  517. DevMsg( 2, "Requesting group server list for groups %s...\n", gamedataFitler );
  518. if ( m_hRequest )
  519. steamapicontext->SteamMatchmakingServers()->ReleaseRequest( m_hRequest );
  520. m_hRequest = steamapicontext->SteamMatchmakingServers()->RequestInternetServerList(
  521. ( AppId_t ) g_pMatchFramework->GetMatchTitle()->GetTitleID(), &pFilter, ARRAYSIZE( filters ), this );
  522. return true;
  523. #else
  524. return false;
  525. #endif
  526. }
  527. void CServerManager::OnGroupFetched()
  528. {
  529. if ( m_bUpdateEnabled &&
  530. m_groupSearchData.m_UserGroupAccountIDs.IsValidIndex( m_groupSearchData.m_idxSearchGroupId ) &&
  531. FetchGroupServers() )
  532. return;
  533. OnAllGroupsFetched();
  534. }
  535. void CServerManager::OnAllGroupsFetched()
  536. {
  537. m_flNextUpdateTime = Plat_FloatTime() + mm_server_search_update_interval.GetInt();
  538. if ( !m_ServersPinging.Count() )
  539. {
  540. OnAllDataFetched();
  541. return;
  542. }
  543. m_eState = STATE_REQUESTING_DETAILS;
  544. m_lanSearchData.m_flStartTime = Plat_FloatTime();
  545. RequestPingingDetails();
  546. }
  547. void CServerManager::RequestPingingDetails()
  548. {
  549. // Ping every server that we deferred to ping
  550. KeyValues *kv = new KeyValues( "InetSearchServerDetails" );
  551. KeyValues::AutoDelete autodelete( kv );
  552. for ( int k = 0; k < m_ServersPinging.Count() && k < mm_server_search_inet_ping_window.GetInt(); ++ k )
  553. {
  554. CServerPinging *pServerPinging = ( CServerPinging * ) m_ServersPinging[k];
  555. if ( pServerPinging->m_flTimeout && Plat_FloatTime() > pServerPinging->m_flTimeout )
  556. {
  557. m_ServersPinging.FastRemove( k -- ); // server timed out
  558. delete pServerPinging;
  559. continue;
  560. }
  561. kv->SetFloat( "timestamp", Plat_FloatTime() );
  562. kv->SetUint64( "pingxuid", pServerPinging->m_xuid );
  563. #if !defined( _X360 ) && !defined( NO_STEAM ) && !defined( SWDS )
  564. g_pConnectionlessLanMgr->SendPacket( kv, pServerPinging->m_netAdr.GetConnectionAddressString() );
  565. #else
  566. DevWarning( "Cannot request internet pinging server details.\n" );
  567. #endif
  568. if ( !pServerPinging->m_flTimeout )
  569. pServerPinging->m_flTimeout = Plat_FloatTime() + mm_server_search_inet_ping_timeout.GetFloat();
  570. }
  571. m_lanSearchData.m_flLastBroadcastTime = Plat_FloatTime();
  572. DevMsg( 2, "Server manager waiting for game details from %d servers...\n", m_ServersPinging.Count() );
  573. }
  574. void CServerManager::UpdateRequestingDetails()
  575. {
  576. if ( !m_ServersPinging.Count() )
  577. {
  578. // We have no more servers to ping
  579. m_ServersPinging.PurgeAndDeleteElements();
  580. OnAllDataFetched();
  581. return;
  582. }
  583. if ( m_lanSearchData.m_flLastBroadcastTime + mm_server_search_inet_ping_interval.GetFloat() < Plat_FloatTime() )
  584. {
  585. RequestPingingDetails();
  586. }
  587. }
  588. void CServerManager::OnAllDataFetched()
  589. {
  590. DevMsg( 2, "Server manager refresh completed.\n" );
  591. m_eState = STATE_IDLE;
  592. if ( !m_bUpdateEnabled )
  593. {
  594. m_Servers.PurgeAndDeleteElements();
  595. m_ServersPinging.PurgeAndDeleteElements();
  596. }
  597. else
  598. {
  599. RemoveOldServers();
  600. }
  601. if ( g_pMatchFramework )
  602. {
  603. g_pMatchFramework->GetEventsSubscription()->BroadcastEvent( new KeyValues(
  604. "OnMatchServerMgrUpdate", "update", "searchfinished" ) );
  605. }
  606. }