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.

639 lines
18 KiB

  1. //===== Copyright � 1996-2009, Valve Corporation, All rights reserved. ======//
  2. //
  3. // Purpose:
  4. //
  5. //===========================================================================//
  6. #include "mm_framework.h"
  7. #include "vstdlib/random.h"
  8. #include "fmtstr.h"
  9. #include "netmessages_signon.h"
  10. // memdbgon must be the last include file in a .cpp file!!!
  11. #include "tier0/memdbgon.h"
  12. //
  13. // CMatchSessionOnlineClient
  14. //
  15. // Implementation of an online session of a host machine
  16. //
  17. void CMatchSessionOnlineClient::Init()
  18. {
  19. KeyValues *psessionHostDataUnpacked = m_pSettings->FindKey( "sessionHostDataUnpacked" );
  20. if ( psessionHostDataUnpacked )
  21. {
  22. m_pSettings->SetPtr( "options/sessionHostData", psessionHostDataUnpacked );
  23. }
  24. }
  25. CMatchSessionOnlineClient::CMatchSessionOnlineClient( KeyValues *pSettings ) :
  26. m_pSettings( pSettings->MakeCopy() ),
  27. m_autodelete_pSettings( m_pSettings ),
  28. m_pSysData( new KeyValues( "SysSessionData", "type", "client" ) ),
  29. m_autodelete_pSysData( m_pSysData ),
  30. m_eState( STATE_INIT ),
  31. m_pSysSession( NULL )
  32. {
  33. DevMsg( "Created CMatchSessionOnlineClient:\n" );
  34. Init();
  35. KeyValuesDumpAsDevMsg( m_pSettings, 1 );
  36. InitializeGameSettings();
  37. }
  38. CMatchSessionOnlineClient::CMatchSessionOnlineClient( CSysSessionClient *pSysSession, KeyValues *pSettings ) :
  39. m_pSettings( pSettings ),
  40. m_autodelete_pSettings( m_pSettings ),
  41. m_pSysData( new KeyValues( "SysSessionData", "type", "client" ) ),
  42. m_autodelete_pSysData( m_pSysData ),
  43. m_eState( STATE_LOBBY ),
  44. m_pSysSession( pSysSession )
  45. {
  46. DevMsg( "Converted sys session into CMatchSessionOnlineClient:\n" );
  47. Init();
  48. KeyValuesDumpAsDevMsg( m_pSettings, 1 );
  49. }
  50. CMatchSessionOnlineClient::CMatchSessionOnlineClient( CSysSessionHost *pSysSession, KeyValues *pExtendedSettings ) :
  51. m_pSettings( pExtendedSettings->FindKey( "settings" ) ),
  52. m_autodelete_pSettings( m_pSettings ),
  53. m_pSysData( new KeyValues( "SysSessionData", "type", "client" ) ),
  54. m_autodelete_pSysData( m_pSysData ),
  55. m_eState( STATE_LOBBY ), // it's at least lobby, we'll figure out later
  56. m_pSysSession( NULL )
  57. {
  58. DevMsg( "Migrating into CMatchSessionOnlineClient...\n" );
  59. Init();
  60. Assert( m_pSettings );
  61. KeyValues::AutoDelete autodelete( pExtendedSettings );
  62. pExtendedSettings->RemoveSubKey( m_pSettings ); // it's now our settings
  63. // Install our session
  64. g_pMMF->SetCurrentMatchSession( this );
  65. // Check if the game is in a non-lobby state
  66. char const *szState = pExtendedSettings->GetString( "state", "" );
  67. if ( !Q_stricmp( szState, "game" ) )
  68. m_eState = STATE_GAME;
  69. else if ( !Q_stricmp( szState, "ending" ) )
  70. m_eState = STATE_ENDING;
  71. // Now we need to create the system session to reflect the client session passed
  72. m_pSysSession = new CSysSessionClient( pSysSession, m_pSettings );
  73. pSysSession->Destroy();
  74. // Show the state
  75. DevMsg( "Migrated into CMatchSessionOnlineClient:\n" );
  76. KeyValuesDumpAsDevMsg( m_pSettings, 1 );
  77. }
  78. CMatchSessionOnlineClient::~CMatchSessionOnlineClient()
  79. {
  80. DevMsg( "Destroying CMatchSessionOnlineClient:\n" );
  81. KeyValuesDumpAsDevMsg( m_pSettings, 1 );
  82. }
  83. KeyValues * CMatchSessionOnlineClient::GetSessionSystemData()
  84. {
  85. // Setup our sys data
  86. m_pSysData->SetUint64( "xuidReserve", m_pSysSession ? m_pSysSession->GetReservationCookie() : 0ull );
  87. m_pSysData->SetUint64( "xuidHost", m_pSysSession ? m_pSysSession->GetHostXuid() : 0ull );
  88. switch ( m_eState )
  89. {
  90. case STATE_LOBBY:
  91. m_pSysData->SetString( "state", "lobby" );
  92. break;
  93. case STATE_GAME:
  94. m_pSysData->SetString( "state", "game" );
  95. break;
  96. default:
  97. m_pSysData->SetString( "state", "" );
  98. break;
  99. }
  100. return m_pSysData;
  101. }
  102. KeyValues * CMatchSessionOnlineClient::GetSessionSettings()
  103. {
  104. return m_pSettings;
  105. }
  106. void CMatchSessionOnlineClient::UpdateSessionSettings( KeyValues *pSettings )
  107. {
  108. // Avoid a warning and assert for queue state manipulation
  109. if ( pSettings->GetFirstSubKey()->GetString( "game/mmqueue", NULL ) )
  110. return;
  111. // Otherwise warn
  112. Warning( "CMatchSessionOnlineClient::UpdateSessionSettings is unavailable in state %d!\n", m_eState );
  113. Assert( !"CMatchSessionOnlineClient::UpdateSessionSettings is unavailable!\n" );
  114. }
  115. void CMatchSessionOnlineClient::UpdateTeamProperties( KeyValues *pSettings )
  116. {
  117. m_pSysSession->UpdateTeamProperties( pSettings );
  118. }
  119. void CMatchSessionOnlineClient::Command( KeyValues *pCommand )
  120. {
  121. char const *szCommand, *szRun;
  122. szCommand = pCommand->GetName();
  123. szRun = pCommand->GetString( "run", "" );
  124. if ( !Q_stricmp( szRun, "host" ) || !Q_stricmp( szRun, "all" ) || !Q_stricmp( szRun, "xuid" ) )
  125. {
  126. if ( m_pSysSession )
  127. {
  128. m_pSysSession->Command( pCommand );
  129. return;
  130. }
  131. }
  132. else if ( !*szRun || !Q_stricmp( szRun, "local" ) )
  133. {
  134. OnRunCommand( pCommand );
  135. return;
  136. }
  137. Warning( "CMatchSessionOnlineClient::Command( %s ) unhandled!\n", szCommand );
  138. Assert( !"CMatchSessionOnlineClient::Command" );
  139. }
  140. void CMatchSessionOnlineClient::OnRunCommand( KeyValues *pCommand )
  141. {
  142. char const *szCommand = pCommand->GetName();
  143. if ( !Q_stricmp( "Migrate", szCommand ) )
  144. {
  145. if ( m_pSysSession ) // TODO: research who sends the "Migrate" command and how secure it is?
  146. {
  147. m_pSysSession->Migrate( pCommand );
  148. return;
  149. }
  150. }
  151. if ( !Q_stricmp( "QueueConnect", szCommand ) )
  152. {
  153. if ( ( m_eState == STATE_LOBBY ) && !pCommand->GetUint64( "_remote_xuidsrc" ) )
  154. {
  155. OnRunCommand_QueueConnect( pCommand );
  156. return;
  157. }
  158. }
  159. // Client-side command cannot update the players
  160. g_pMMF->GetMatchTitleGameSettingsMgr()->ExecuteCommand( pCommand, GetSessionSystemData(), m_pSettings, NULL );
  161. // Send the command as event for handling
  162. KeyValues *pEvent = pCommand->MakeCopy();
  163. pEvent->SetName( CFmtStr( "Command::%s", pCommand->GetName() ) );
  164. g_pMatchEventsSubscription->BroadcastEvent( pEvent );
  165. }
  166. uint64 CMatchSessionOnlineClient::GetSessionID()
  167. {
  168. if( m_pSysSession )
  169. {
  170. return m_pSysSession->GetSessionID();
  171. }
  172. return 0;
  173. }
  174. void CMatchSessionOnlineClient::Update()
  175. {
  176. switch ( m_eState )
  177. {
  178. case STATE_INIT:
  179. m_eState = STATE_CREATING;
  180. // Adjust invite-based settings
  181. uint64 uiInviteFlags = g_pMMF->GetLastInviteFlags();
  182. m_pSettings->SetUint64( "members/joinflags", uiInviteFlags );
  183. // Session is creating
  184. g_pMatchEventsSubscription->BroadcastEvent( new KeyValues(
  185. "OnMatchSessionUpdate",
  186. "state", "progress",
  187. "progress", "joining"
  188. ) );
  189. // Trigger session creation
  190. m_pSysSession = new CSysSessionClient( m_pSettings );
  191. break;
  192. }
  193. if ( m_pSysSession )
  194. {
  195. m_pSysSession->Update();
  196. }
  197. }
  198. void CMatchSessionOnlineClient::Destroy()
  199. {
  200. if ( m_eState != STATE_MIGRATE )
  201. {
  202. g_pMatchExtensions->GetINetSupport()->UpdateClientReservation( 0ull, 0ull );
  203. }
  204. if ( m_eState == STATE_GAME || m_eState == STATE_ENDING )
  205. {
  206. m_eState = STATE_INIT; // the object is being deleted, but prevent signon state change handlers
  207. g_pMatchExtensions->GetIVEngineClient()->ExecuteClientCmd( "disconnect" );
  208. }
  209. if ( m_pSysSession )
  210. {
  211. m_pSysSession->Destroy();
  212. m_pSysSession = NULL;
  213. }
  214. delete this;
  215. }
  216. void CMatchSessionOnlineClient::DebugPrint()
  217. {
  218. DevMsg( "CMatchSessionOnlineClient [ state=%d ]\n", m_eState );
  219. DevMsg( "System data:\n" );
  220. KeyValuesDumpAsDevMsg( GetSessionSystemData(), 1 );
  221. DevMsg( "Settings data:\n" );
  222. KeyValuesDumpAsDevMsg( GetSessionSettings(), 1 );
  223. if ( m_pSysSession )
  224. m_pSysSession->DebugPrint();
  225. else
  226. DevMsg( "SysSession is NULL\n" );
  227. }
  228. bool CMatchSessionOnlineClient::IsAnotherSessionJoinable( const char *pszAnotherSessionInfo )
  229. {
  230. #ifdef _X360
  231. if ( m_pSysSession )
  232. {
  233. XSESSION_INFO xsi;
  234. if ( m_pSysSession->GetHostNetworkAddress( xsi ) )
  235. {
  236. XSESSION_INFO xsiAnother;
  237. MMX360_SessionInfoFromString( xsiAnother, pszAnotherSessionInfo );
  238. if ( !memcmp( &xsiAnother.sessionID, &xsi.sessionID, sizeof( xsi.sessionID ) ) )
  239. return false;
  240. }
  241. }
  242. #endif
  243. return true;
  244. }
  245. void CMatchSessionOnlineClient::OnEvent( KeyValues *pEvent )
  246. {
  247. char const *szEvent = pEvent->GetName();
  248. if ( !Q_stricmp( "OnEngineClientSignonStateChange", szEvent ) )
  249. {
  250. int iOldState = pEvent->GetInt( "old", 0 );
  251. int iNewState = pEvent->GetInt( "new", 0 );
  252. if ( iOldState >= SIGNONSTATE_CONNECTED &&
  253. iNewState < SIGNONSTATE_CONNECTED )
  254. {
  255. if ( m_eState == STATE_GAME )
  256. {
  257. // Lost connection from server or explicit disconnect
  258. DevMsg( "OnEngineClientSignonStateChange\n" );
  259. g_pMatchEventsSubscription->BroadcastEvent( new KeyValues( "mmF->CloseSession" ) );
  260. }
  261. else if ( m_eState == STATE_ENDING )
  262. {
  263. m_eState = STATE_LOBBY;
  264. g_pMatchEventsSubscription->BroadcastEvent( new KeyValues( "OnMatchSessionUpdate", "state", "ready", "transition", "clientendgame" ) );
  265. }
  266. }
  267. }
  268. else if ( !Q_stricmp( "OnEngineDisconnectReason", szEvent ) )
  269. {
  270. if ( m_eState == STATE_GAME )
  271. {
  272. // Lost connection from server or explicit disconnect
  273. char const *szReason = pEvent->GetString( "reason", "" );
  274. DevMsg( "OnEngineDisconnectReason %s\n", szReason );
  275. bool bLobbySalvagable =
  276. StringHasPrefix( szReason, "Connection to server timed out" ) ||
  277. StringHasPrefix( szReason, "Server shutting down" );
  278. if ( KeyValues *pDisconnectHdlr = g_pMMF->GetMatchTitleGameSettingsMgr()->PrepareClientLobbyForGameDisconnect( m_pSettings, pEvent ) )
  279. {
  280. KeyValues::AutoDelete autodelete( pDisconnectHdlr );
  281. char const *szDisconnectHdlr = pDisconnectHdlr->GetString( "disconnecthdlr", "" );
  282. if ( !Q_stricmp( szDisconnectHdlr, "destroy" ) )
  283. bLobbySalvagable = false;
  284. else if ( !Q_stricmp( szDisconnectHdlr, "lobby" ) )
  285. bLobbySalvagable = true;
  286. }
  287. if ( !bLobbySalvagable )
  288. {
  289. g_pMatchEventsSubscription->BroadcastEvent( new KeyValues( "mmF->CloseSession" ) );
  290. }
  291. else
  292. {
  293. // Server shutting down, try to retain the lobby
  294. pEvent->SetString( "disconnecthdlr", "lobby" );
  295. g_pMatchEventsSubscription->RegisterEventData( pEvent->MakeCopy() );
  296. OnEndGameToLobby();
  297. }
  298. }
  299. }
  300. else if ( !Q_stricmp( "OnEngineEndGame", szEvent ) )
  301. {
  302. if ( m_eState == STATE_GAME )
  303. {
  304. OnEndGameToLobby();
  305. }
  306. }
  307. else if ( !Q_stricmp( "OnMatchSessionUpdate", szEvent ) )
  308. {
  309. char const *szState = pEvent->GetString( "state", "" );
  310. if ( !Q_stricmp( "updated", szState ) )
  311. {
  312. switch ( m_eState )
  313. {
  314. case STATE_LOBBY:
  315. if ( KeyValues *pServer = pEvent->FindKey( "update/server" ) )
  316. {
  317. // If we are in a con team match we only connect to game servers
  318. // in response to an invite from the host so don't do anything
  319. KeyValues *pConTeamMatch = m_pSettings->FindKey("options/conteammatch");
  320. if ( !pConTeamMatch ||
  321. ( pEvent->GetUint64( "update/server/xuid" ) && pEvent->GetUint64( "update/server/reservationid" ) ) )
  322. {
  323. // Game server has become available - connect to it!
  324. ConnectGameServer();
  325. }
  326. }
  327. break;
  328. case STATE_GAME:
  329. if ( KeyValues *pServer = pEvent->FindKey( "delete/server" ) )
  330. {
  331. // Lobby leader has disconnected from game server, disconnect too
  332. OnEndGameToLobby();
  333. }
  334. break;
  335. }
  336. }
  337. }
  338. else if ( !Q_stricmp( "OnNetLanConnectionlessPacket", szEvent ) )
  339. {
  340. char const *szPacketType = pEvent->GetFirstTrueSubKey()->GetName();
  341. if ( m_pSysSession && m_eState > STATE_CREATING &&
  342. !Q_stricmp( szPacketType, "LanSearch" ) )
  343. {
  344. m_pSysSession->ReplyLanSearch( pEvent );
  345. }
  346. }
  347. else if ( !Q_stricmp( "OnSysMuteListChanged", szEvent ) )
  348. {
  349. if ( m_pSysSession )
  350. m_pSysSession->Voice_UpdateMutelist();
  351. }
  352. else if ( !Q_stricmp( "mmF->SysSessionUpdate", szEvent ) )
  353. {
  354. if ( m_pSysSession && pEvent->GetPtr( "syssession", NULL ) == m_pSysSession )
  355. {
  356. // This is our session
  357. if ( char const *szError = pEvent->GetString( "error", NULL ) )
  358. {
  359. // Destroy the session
  360. m_pSysSession->Destroy();
  361. m_pSysSession = NULL;
  362. m_eState = STATE_CREATING;
  363. // Handle error
  364. KeyValues *kvUpdateError = pEvent->MakeCopy();
  365. kvUpdateError->SetName( "OnMatchSessionUpdate" );
  366. kvUpdateError->SetString( "state", "error" );
  367. g_pMatchEventsSubscription->BroadcastEvent( kvUpdateError );
  368. return;
  369. }
  370. if ( uint64 ullCrypt = pEvent->GetUint64( "crypt" ) )
  371. m_pSysData->SetUint64( "crypt", ullCrypt );
  372. switch ( m_eState )
  373. {
  374. case STATE_CREATING:
  375. // Session was creating
  376. // Now we are at least in the lobby
  377. m_eState = STATE_LOBBY;
  378. OnClientFullyConnectedToSession();
  379. return;
  380. default:
  381. if ( char const *szAction = pEvent->GetString( "action", NULL ) )
  382. {
  383. if ( !Q_stricmp( "host", szAction ) )
  384. {
  385. KeyValues *pExtendedSettings = new KeyValues( "ExtendedSettings" );
  386. char const *szMigrateState = "lobby";
  387. switch ( m_eState )
  388. {
  389. case STATE_GAME:
  390. szMigrateState = "game";
  391. break;
  392. case STATE_ENDING:
  393. szMigrateState = "ending";
  394. break;
  395. }
  396. pExtendedSettings->SetString( "state", szMigrateState );
  397. if ( uint64 ullCrypt = m_pSysData->GetUint64( "crypt" ) )
  398. pExtendedSettings->SetUint64( "crypt", ullCrypt );
  399. pExtendedSettings->AddSubKey( m_pSettings );
  400. // Release ownership of the resources since new match session now owns them
  401. m_pSettings = NULL;
  402. m_autodelete_pSettings.Assign( NULL );
  403. CSysSessionClient *pSysSession = m_pSysSession;
  404. m_pSysSession = NULL;
  405. // Destroy our instance and create the new match interface
  406. m_eState = STATE_MIGRATE;
  407. g_pMMF->SetCurrentMatchSession( NULL );
  408. this->Destroy();
  409. // Now we need to create the new host session that will install itself
  410. IMatchSession *pNewHost = new CMatchSessionOnlineHost( pSysSession, pExtendedSettings );
  411. Assert( g_pMMF->GetMatchSession() == pNewHost );
  412. pNewHost;
  413. return;
  414. }
  415. }
  416. break;
  417. }
  418. DevWarning( "Unhandled mmF->SysSessionUpdate!\n" );
  419. Assert( !"Unhandled mmF->SysSessionUpdate!\n" );
  420. }
  421. }
  422. else if ( !Q_stricmp( "mmF->SysSessionCommand", szEvent ) )
  423. {
  424. if ( m_pSysSession && pEvent->GetPtr( "syssession", NULL ) == m_pSysSession )
  425. {
  426. KeyValues *pCommand = pEvent->GetFirstTrueSubKey();
  427. if ( pCommand )
  428. {
  429. OnRunCommand( pCommand );
  430. }
  431. }
  432. }
  433. }
  434. void CMatchSessionOnlineClient::OnClientFullyConnectedToSession()
  435. {
  436. g_pMatchEventsSubscription->BroadcastEvent( new KeyValues( "OnMatchSessionUpdate", "state", "created" ) );
  437. // Check whether the game server is available (i.e. game in progress)
  438. if ( KeyValues *pServer = m_pSettings->FindKey( "server" ) )
  439. {
  440. ConnectGameServer();
  441. }
  442. else
  443. {
  444. g_pMatchEventsSubscription->BroadcastEvent( new KeyValues( "OnMatchSessionUpdate", "state", "ready", "transition", "clientconnect" ) );
  445. }
  446. }
  447. void CMatchSessionOnlineClient::OnEndGameToLobby()
  448. {
  449. m_eState = STATE_ENDING;
  450. // Issue the disconnect command
  451. g_pMatchExtensions->GetIVEngineClient()->ExecuteClientCmd( "disconnect" );
  452. // Mark gameplay state as inactive
  453. m_pSysSession->SetSessionActiveGameplayState( false, NULL );
  454. }
  455. void CMatchSessionOnlineClient::InitializeGameSettings()
  456. {
  457. // Initialize only the settings required to connect...
  458. if ( KeyValues *kv = m_pSettings->FindKey( "system", true ) )
  459. {
  460. KeyValuesAddDefaultString( kv, "network", "LIVE" );
  461. KeyValuesAddDefaultString( kv, "access", "public" );
  462. }
  463. if ( KeyValues *pMembers = m_pSettings->FindKey( "members", true ) )
  464. {
  465. pMembers->SetInt( "numMachines", 1 );
  466. int numPlayers = 1;
  467. #ifdef _GAMECONSOLE
  468. numPlayers = XBX_GetNumGameUsers();
  469. #endif
  470. pMembers->SetInt( "numPlayers", numPlayers );
  471. pMembers->SetInt( "numSlots", numPlayers );
  472. if ( KeyValues *pMachine = pMembers->FindKey( "machine0", true ) )
  473. {
  474. XUID machineid = g_pPlayerManager->GetLocalPlayer( XBX_GetPrimaryUserId() )->GetXUID();
  475. pMachine->SetUint64( "id", machineid );
  476. #if defined( _PS3 ) && !defined( NO_STEAM )
  477. pMachine->SetUint64( "psnid", steamapicontext->SteamUser()->GetConsoleSteamID().ConvertToUint64() );
  478. #endif
  479. pMachine->SetUint64( "flags", MatchSession_GetMachineFlags() );
  480. pMachine->SetInt( "numPlayers", numPlayers );
  481. pMachine->SetUint64( "dlcmask", g_pMatchFramework->GetMatchSystem()->GetDlcManager()->GetDataInfo()->GetUint64( "@info/installed" ) );
  482. pMachine->SetString( "tuver", MatchSession_GetTuInstalledString() );
  483. pMachine->SetInt( "ping", 0 );
  484. for ( int k = 0; k < numPlayers; ++ k )
  485. {
  486. if ( KeyValues *pPlayer = pMachine->FindKey( CFmtStr( "player%d", k ), true ) )
  487. {
  488. int iController = 0;
  489. #ifdef _GAMECONSOLE
  490. iController = XBX_GetUserId( k );
  491. #endif
  492. IPlayerLocal *player = g_pPlayerManager->GetLocalPlayer( iController );
  493. pPlayer->SetUint64( "xuid", player->GetXUID() );
  494. pPlayer->SetString( "name", player->GetName() );
  495. }
  496. }
  497. }
  498. }
  499. // Let the title extend the game settings
  500. g_pMMF->GetMatchTitleGameSettingsMgr()->InitializeGameSettings( m_pSettings, "client" );
  501. DevMsg( "CMatchSessionOnlineClient::InitializeGameSettings adjusted settings:\n" );
  502. KeyValuesDumpAsDevMsg( m_pSettings, 1 );
  503. }
  504. void CMatchSessionOnlineClient::OnRunCommand_QueueConnect( KeyValues *pCommand )
  505. {
  506. char const *szConnectAddress = pCommand->GetString( "adronline", "0.0.0.0" );
  507. uint64 uiReservationId = pCommand->GetUint64( "reservationid" );
  508. bool bAutoCloseSession = pCommand->GetBool( "auto_close_session" );
  509. // Switch the state
  510. m_eState = STATE_GAME;
  511. MatchSession_PrepareClientForConnect( m_pSettings, uiReservationId );
  512. // Mark gameplay state as active
  513. m_pSysSession->SetSessionActiveGameplayState( true, szConnectAddress );
  514. // Close the session, potentially resetting a bunch of state
  515. if ( bAutoCloseSession )
  516. g_pMatchFramework->CloseSession();
  517. // Determine reservation settings required
  518. g_pMatchExtensions->GetINetSupport()->UpdateClientReservation( uiReservationId, 0ull );
  519. // Issue the connect command
  520. g_pMatchExtensions->GetIVEngineClient()->StartLoadingScreenForCommand( CFmtStr( "connect %s", szConnectAddress ) );
  521. }
  522. void CMatchSessionOnlineClient::ConnectGameServer()
  523. {
  524. // Switch the state
  525. m_eState = STATE_GAME;
  526. MatchSession_PrepareClientForConnect( m_pSettings );
  527. //
  528. // Resolve server information
  529. //
  530. MatchSessionServerInfo_t msInfo = {0};
  531. if ( !MatchSession_ResolveServerInfo( m_pSettings, m_pSysSession, msInfo, msInfo.RESOLVE_DEFAULT, m_pSysData->GetUint64( "crypt" ) ) )
  532. {
  533. // Destroy the session
  534. m_pSysSession->Destroy();
  535. m_pSysSession = NULL;
  536. // Handle error
  537. g_pMatchEventsSubscription->BroadcastEvent( new KeyValues( "OnMatchSessionUpdate",
  538. "state", "error", "error", "connect" ) );
  539. return;
  540. }
  541. // Determine reservation settings required
  542. g_pMatchExtensions->GetINetSupport()->UpdateClientReservation( msInfo.m_uiReservationCookie, msInfo.m_xuidJingle );
  543. // Mark gameplay state as active
  544. m_pSysSession->SetSessionActiveGameplayState( true, msInfo.m_szSecureServerAddress );
  545. // Issue the connect command
  546. g_pMatchExtensions->GetIVEngineClient()->ClientCmd_Unrestricted( msInfo.m_szConnectCmd );
  547. }