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.

960 lines
25 KiB

  1. //===== Copyright � 1996-2009, Valve Corporation, All rights reserved. ======//
  2. //
  3. // Purpose:
  4. //
  5. //===========================================================================//
  6. #include "mm_framework.h"
  7. #include "mm_netmsgcontroller.h"
  8. #include "matchsystem.h"
  9. #include "mm_title_main.h"
  10. #include "x360_lobbyapi.h"
  11. // memdbgon must be the last include file in a .cpp file!!!
  12. #include "tier0/memdbgon.h"
  13. // Stress testing events listeners every frame
  14. ConVar mm_events_listeners_validation( "mm_events_listeners_validation", "0", FCVAR_DEVELOPMENTONLY );
  15. //
  16. // Implementation of Steam invite listener
  17. //
  18. uint64 g_uiLastInviteFlags = 0ull;
  19. #if !defined( _X360 ) && !defined( NO_STEAM ) && !defined( SWDS )
  20. class CMatchSteamInviteListener
  21. {
  22. public:
  23. void RunFrame();
  24. void Register();
  25. STEAM_CALLBACK_MANUAL( CMatchSteamInviteListener, Steam_OnGameLobbyJoinRequested, GameLobbyJoinRequested_t, m_CallbackOnGameLobbyJoinRequested );
  26. #ifdef _PS3
  27. STEAM_CALLBACK_MANUAL( CMatchSteamInviteListener, Steam_OnPSNGameBootInviteResult, PSNGameBootInviteResult_t, m_CallbackOnPSNGameBootInviteResult );
  28. #endif
  29. protected:
  30. GameLobbyJoinRequested_t m_msgPending;
  31. }
  32. g_MatchSteamInviteListener;
  33. void CMatchSteamInviteListener::Register()
  34. {
  35. m_CallbackOnGameLobbyJoinRequested.Register( this, &CMatchSteamInviteListener::Steam_OnGameLobbyJoinRequested );
  36. #ifdef _PS3
  37. m_CallbackOnPSNGameBootInviteResult.Register( this, &CMatchSteamInviteListener::Steam_OnPSNGameBootInviteResult );
  38. #endif
  39. }
  40. #else
  41. class CMatchSteamInviteListener
  42. {
  43. public:
  44. void RunFrame() {}
  45. void Register() {}
  46. }
  47. g_MatchSteamInviteListener;
  48. #endif
  49. //
  50. // Implementation
  51. //
  52. CMatchFramework::CMatchFramework() :
  53. m_pMatchSession( NULL ),
  54. m_bJoinTeamSession( false ),
  55. m_pTeamSessionSettings( NULL )
  56. {
  57. }
  58. CMatchFramework::~CMatchFramework()
  59. {
  60. ;
  61. }
  62. InitReturnVal_t CMatchFramework::Init()
  63. {
  64. InitReturnVal_t ret = INIT_OK;
  65. ret = MM_Title_Init();
  66. if ( ret != INIT_OK )
  67. return ret;
  68. g_MatchSteamInviteListener.Register();
  69. return INIT_OK;
  70. }
  71. void CMatchFramework::Shutdown()
  72. {
  73. // Shutdown event system
  74. g_pMatchEventsSubscription->Shutdown();
  75. // Shutdown the title
  76. MM_Title_Shutdown();
  77. // Cancel any pending server updates before shutdown
  78. g_pServerManager->EnableServersUpdate( false );
  79. // Cancel any pending datacenter queries
  80. g_pDatacenter->EnableUpdate( false );
  81. }
  82. void CMatchFramework::RunFrame()
  83. {
  84. // Run frame listeners validation if requested
  85. if ( mm_events_listeners_validation.GetBool() )
  86. {
  87. g_pMatchEventsSubscription->BroadcastEvent( new KeyValues( "mm_events_listeners_validation" ) );
  88. }
  89. #ifdef _X360
  90. if ( IXOnline *pIXOnline = g_pMatchExtensions->GetIXOnline() )
  91. pIXOnline->RunFrame();
  92. MMX360_UpdateDormantOperations();
  93. SysSession360_UpdatePending();
  94. #endif
  95. RunFrame_Invite();
  96. g_MatchSteamInviteListener.RunFrame();
  97. #ifdef _X360
  98. // Pump rate adjustments
  99. MatchSession_RateAdjustmentUpdate();
  100. #endif
  101. // Let the network mgr run
  102. g_pConnectionlessLanMgr->Update();
  103. // Let the matchsystem run
  104. g_pMatchSystem->Update();
  105. // Let the match session run
  106. if ( m_pMatchSession )
  107. m_pMatchSession->Update();
  108. // Let the match title run frame
  109. g_pIMatchTitle->RunFrame();
  110. if ( m_bJoinTeamSession )
  111. {
  112. m_bJoinTeamSession = false;
  113. MatchSession( m_pTeamSessionSettings );
  114. m_pTeamSessionSettings->deleteThis();
  115. m_pTeamSessionSettings = NULL;
  116. }
  117. }
  118. IMatchExtensions * CMatchFramework::GetMatchExtensions()
  119. {
  120. return g_pMatchExtensions;
  121. }
  122. IMatchEventsSubscription * CMatchFramework::GetEventsSubscription()
  123. {
  124. return g_pMatchEventsSubscription;
  125. }
  126. IMatchTitle * CMatchFramework::GetMatchTitle()
  127. {
  128. return g_pIMatchTitle;
  129. }
  130. IMatchTitleGameSettingsMgr * CMatchFramework::GetMatchTitleGameSettingsMgr()
  131. {
  132. return g_pIMatchTitleGameSettingsMgr;
  133. }
  134. IMatchNetworkMsgController * CMatchFramework::GetMatchNetworkMsgController()
  135. {
  136. return g_pMatchNetMsgControllerBase;
  137. }
  138. IMatchSystem * CMatchFramework::GetMatchSystem()
  139. {
  140. return g_pMatchSystem;
  141. }
  142. void CMatchFramework::ApplySettings( KeyValues* keyValues )
  143. {
  144. g_pMatchExtensions->GetIServerGameDLL()->ApplyGameSettings( keyValues );
  145. }
  146. #ifdef _X360
  147. static XINVITE_INFO s_InviteInfo;
  148. #else
  149. static uint64 s_InviteInfo;
  150. #endif
  151. static bool s_bInviteSessionDelayedJoin;
  152. static int s_nInviteConfirmed;
  153. template < int datasize >
  154. static bool IsZeroData( void const *pvData )
  155. {
  156. static char s_zerodata[ datasize ];
  157. return !memcmp( s_zerodata, pvData, datasize );
  158. }
  159. static bool ValidateInviteController( int iController )
  160. {
  161. #ifdef _X360
  162. XUSER_SIGNIN_STATE eSignInState = XUserGetSigninState( iController );
  163. XUSER_SIGNIN_INFO xsi = {0};
  164. if ( ( eSignInState != eXUserSigninState_SignedInToLive ) ||
  165. ( ERROR_SUCCESS != XUserGetSigninInfo( iController, XUSER_GET_SIGNIN_INFO_ONLINE_XUID_ONLY, &xsi ) ) ||
  166. ! ( xsi.dwInfoFlags & XUSER_INFO_FLAG_LIVE_ENABLED ) )
  167. {
  168. DevWarning( "ValidateInviteController: ctrl%d check1 failed (state=%d, flags=0x%X, xuid=%llx)!\n",
  169. eSignInState, xsi.dwInfoFlags, xsi.xuid );
  170. if ( KeyValues *notify = new KeyValues(
  171. "OnInvite", "action", "error", "error", "NotOnline" ) )
  172. {
  173. notify->SetInt( "user", iController );
  174. g_pMatchEventsSubscription->BroadcastEvent( notify );
  175. }
  176. return false;
  177. }
  178. BOOL bMultiplayer = FALSE;
  179. if ( ( ERROR_SUCCESS != XUserCheckPrivilege( iController, XPRIVILEGE_MULTIPLAYER_SESSIONS, &bMultiplayer ) ) ||
  180. ( !bMultiplayer ) )
  181. {
  182. DevWarning( "ValidateInviteController: ctrl%d check2 failed (state=%d, flags=0x%X, xuid=%llx) - on multiplayer priv!\n",
  183. eSignInState, xsi.dwInfoFlags, xsi.xuid );
  184. if ( KeyValues *notify = new KeyValues(
  185. "OnInvite", "action", "error", "error", "NoMultiplayer" ) )
  186. {
  187. notify->SetInt( "user", iController );
  188. g_pMatchEventsSubscription->BroadcastEvent( notify );
  189. }
  190. return false;
  191. }
  192. #endif
  193. return true;
  194. }
  195. static bool ValidateInviteControllers()
  196. {
  197. for ( DWORD k = 0; k < XBX_GetNumGameUsers(); ++ k )
  198. {
  199. if ( !ValidateInviteController( XBX_GetUserId( k ) ) )
  200. return false;
  201. }
  202. return true;
  203. }
  204. static bool VerifyInviteEligibility()
  205. {
  206. #ifdef _X360
  207. // Make sure that the inviter is not signed in
  208. for ( int k = 0; k < XUSER_MAX_COUNT; ++ k )
  209. {
  210. XUID xuid;
  211. if ( ERROR_SUCCESS == XUserGetXUID( k, &xuid ) &&
  212. xuid == s_InviteInfo.xuidInviter )
  213. {
  214. g_pMatchEventsSubscription->BroadcastEvent( new KeyValues(
  215. "OnInvite", "action", "error", "error", "SameConsole" ) );
  216. return false;
  217. }
  218. }
  219. // Check if the user is currently inactive
  220. bool bExistingUser = false;
  221. for ( DWORD k = 0; k < XBX_GetNumGameUsers(); ++ k )
  222. {
  223. if ( XBX_GetInvitedUserId() == (DWORD) XBX_GetUserId( k ) &&
  224. !XBX_GetUserIsGuest( k ) )
  225. {
  226. bExistingUser = true;
  227. break;
  228. }
  229. }
  230. // Check if this is the existing user that the invite is for a different session
  231. // than the session they are currently in (e.g. they are in a lobby and do
  232. // "Join Party and Game" with another user who is in the same lobby)
  233. char chInviteSessionInfo[ XSESSION_INFO_STRING_LENGTH ] = {0};
  234. MMX360_SessionInfoToString( s_InviteInfo.hostInfo, chInviteSessionInfo );
  235. if ( IMatchSession *pIMatchSession = g_pMatchFramework->GetMatchSession() )
  236. {
  237. bool bJoinable = ( ( IMatchSessionInternal * ) pIMatchSession )->IsAnotherSessionJoinable( chInviteSessionInfo );
  238. if ( !bJoinable && bExistingUser )
  239. {
  240. Warning( "VerifyInviteEligibility: declined invite due to local session!\n" );
  241. return false;
  242. }
  243. }
  244. // New user is eligible since otherwise he shouldn't be able to accept an invite
  245. if ( !bExistingUser || ( XBX_GetNumGameUsers() < 2 ) ||
  246. ( g_pMMF->GetMatchTitle()->GetTitleSettingsFlags() & MATCHTITLE_INVITE_ONLY_SINGLE_USER ) )
  247. {
  248. if ( !ValidateInviteController( XBX_GetInvitedUserId() ) )
  249. return false;
  250. else
  251. return true;
  252. }
  253. #endif
  254. // Check that every user is valid
  255. return ValidateInviteControllers();
  256. }
  257. static void JoinInviteSession()
  258. {
  259. s_bInviteSessionDelayedJoin = false;
  260. #ifdef _X360
  261. if ( 0ull == ( uint64 const & ) s_InviteInfo.hostInfo.sessionID )
  262. #else
  263. if ( !s_InviteInfo )
  264. #endif
  265. return;
  266. if ( g_pMatchExtensions->GetIVEngineClient()->IsDrawingLoadingImage() )
  267. {
  268. s_bInviteSessionDelayedJoin = true;
  269. return;
  270. }
  271. // Invites cannot be accepted from inside an event broadcast
  272. // internally used events must be top-level events since they
  273. // operate on signed in / active users, trigger playermanager,
  274. // account access and other events
  275. // Wait until next frame in such case
  276. if ( g_pMatchEventsSubscription && g_pMatchEventsSubscription->IsBroacasting() )
  277. {
  278. s_bInviteSessionDelayedJoin = true;
  279. return;
  280. }
  281. #if !defined( NO_STEAM ) && !defined( _GAMECONSOLE ) && !defined( SWDS )
  282. extern bool g_bSteamStatsReceived;
  283. if ( !g_bSteamStatsReceived && ( g_uiLastInviteFlags & MM_INVITE_FLAG_PCBOOT ) )
  284. {
  285. s_bInviteSessionDelayedJoin = true;
  286. return;
  287. }
  288. #endif
  289. #ifdef _X360
  290. DevMsg( "JoinInviteSession: sessionid = %llx, xuid = %llx\n", ( uint64 const & ) s_InviteInfo.hostInfo.sessionID, s_InviteInfo.xuidInvitee );
  291. #else
  292. DevMsg( "JoinInviteSession: sessionid = %llx\n", s_InviteInfo );
  293. #endif
  294. //
  295. // Validate the user accepting the invite
  296. //
  297. #ifdef _GAMECONSOLE
  298. if ( XBX_GetInvitedUserId() == INVALID_USER_ID )
  299. {
  300. DevWarning( "JoinInviteSession: no invited user!\n" );
  301. return;
  302. }
  303. #endif
  304. #ifdef _X360
  305. XUSER_SIGNIN_STATE eSignInState = XUserGetSigninState( XBX_GetInvitedUserId() );
  306. XUSER_SIGNIN_INFO xsi = {0};
  307. if ( ( eSignInState != eXUserSigninState_SignedInToLive ) ||
  308. ( ERROR_SUCCESS != XUserGetSigninInfo( XBX_GetInvitedUserId(), XUSER_GET_SIGNIN_INFO_ONLINE_XUID_ONLY, &xsi ) ) ||
  309. ! ( xsi.dwInfoFlags & XUSER_INFO_FLAG_LIVE_ENABLED ) ||
  310. ( xsi.dwInfoFlags & XUSER_INFO_FLAG_GUEST ) ||
  311. !IsEqualXUID( xsi.xuid, s_InviteInfo.xuidInvitee ) )
  312. {
  313. DevWarning( "JoinInviteSession: invited user signin information validation failed (state=%d, flags=0x%X, xuid=%llx)!\n",
  314. eSignInState, xsi.dwInfoFlags, xsi.xuid );
  315. return;
  316. }
  317. BOOL bMultiplayer = FALSE;
  318. if ( ( ERROR_SUCCESS != XUserCheckPrivilege( XBX_GetInvitedUserId(), XPRIVILEGE_MULTIPLAYER_SESSIONS, &bMultiplayer ) ) ||
  319. ( !bMultiplayer ) )
  320. {
  321. DevWarning( "JoinInviteSession: no multiplayer priv!\n" );
  322. return;
  323. }
  324. #endif
  325. //
  326. // Check if the currently-involved user is accepting the invite
  327. //
  328. #ifdef _GAMECONSOLE
  329. bool bExistingUser = false;
  330. for ( DWORD k = 0; k < XBX_GetNumGameUsers(); ++ k )
  331. {
  332. if ( XBX_GetInvitedUserId() == (DWORD) XBX_GetUserId( k ) &&
  333. !XBX_GetUserIsGuest( k ) )
  334. {
  335. bExistingUser = true;
  336. break;
  337. }
  338. }
  339. if ( !bExistingUser ||
  340. ( ( XBX_GetNumGameUsers() > 1 ) && ( g_pMMF->GetMatchTitle()->GetTitleSettingsFlags() & MATCHTITLE_INVITE_ONLY_SINGLE_USER ) ) )
  341. {
  342. // Another controller is accepting the invite or guest status
  343. // has changed.
  344. // then we need to reset all our XBX core state:
  345. DevMsg( "JoinInviteSession: activating inactive controller%d\n", XBX_GetInvitedUserId() );
  346. g_pMatchEventsSubscription->BroadcastEvent( new KeyValues( "OnProfilesWriteOpportunity", "reason", "deactivation" ) );
  347. XBX_ClearUserIdSlots();
  348. XBX_SetPrimaryUserId( XBX_GetInvitedUserId() );
  349. XBX_SetPrimaryUserIsGuest( 0 );
  350. XBX_SetUserId( 0, XBX_GetInvitedUserId() );
  351. XBX_SetUserIsGuest( 0, 0 );
  352. XBX_SetNumGameUsers( 1 );
  353. g_pMatchEventsSubscription->BroadcastEvent( new KeyValues( "OnProfilesChanged", "numProfiles", int(1) ) );
  354. IPlayerLocal *pPlayer = g_pPlayerManager->GetLocalPlayer( XBX_GetPrimaryUserId() );
  355. if ( !pPlayer )
  356. {
  357. g_pMatchEventsSubscription->BroadcastEvent( new KeyValues(
  358. "OnInvite", "action", "error", "error", "" ) );
  359. return;
  360. }
  361. ( ( PlayerLocal * ) pPlayer )->SetFlag_AwaitingTitleData();
  362. // Since we have activated a new profile, we need to wait until title data gets loaded
  363. DevMsg( "JoinInviteSession: activated inactive controller%d, waiting for title data...\n", XBX_GetInvitedUserId() );
  364. return;
  365. }
  366. #endif
  367. // Validate storage device
  368. s_nInviteConfirmed = -1;
  369. if ( KeyValues *notify = new KeyValues( "OnInvite" ) )
  370. {
  371. #ifdef _X360
  372. char chSessionInfo[ XSESSION_INFO_STRING_LENGTH ] = {0};
  373. MMX360_SessionInfoToString( s_InviteInfo.hostInfo, chSessionInfo );
  374. notify->SetInt( "user", XBX_GetInvitedUserId() );
  375. notify->SetString( "sessioninfo", chSessionInfo );
  376. #else
  377. notify->SetUint64( "sessionid", s_InviteInfo );
  378. #endif
  379. notify->SetString( "action", "storage" );
  380. notify->SetPtr( "confirmed", &s_nInviteConfirmed );
  381. g_pMatchEventsSubscription->BroadcastEvent( notify );
  382. // If handlers decided they need to confirm storage devices, etc.
  383. if ( s_nInviteConfirmed != -1 )
  384. {
  385. DevMsg( "JoinInviteSession: waiting for storage device selection...\n" );
  386. return;
  387. }
  388. }
  389. // Verify eligibility
  390. DevMsg( "JoinInviteSession: verifying eligibility...\n" );
  391. if ( !VerifyInviteEligibility() )
  392. return;
  393. DevMsg( "JoinInviteSession: connecting...\n" );
  394. //
  395. // Argument validation
  396. //
  397. #ifdef _GAMECONSOLE
  398. Assert( XBX_GetInvitedUserId() >= 0 );
  399. Assert( XBX_GetInvitedUserId() < XUSER_MAX_COUNT );
  400. Assert( XBX_GetSlotByUserId( XBX_GetInvitedUserId() ) < ( int ) XBX_GetNumGameUsers() );
  401. Assert( XBX_GetNumGameUsers() < MAX_SPLITSCREEN_CLIENTS );
  402. #endif
  403. // Requesting to join the stored off session
  404. KeyValues *pSettings = KeyValues::FromString(
  405. "settings",
  406. " system { "
  407. " network LIVE "
  408. " } "
  409. " options { "
  410. " action joinsession "
  411. " } "
  412. );
  413. #ifdef _X360
  414. pSettings->SetUint64( "options/sessionid", ( const uint64 & ) s_InviteInfo.hostInfo.sessionID );
  415. if ( !IsZeroData< sizeof( s_InviteInfo.hostInfo.keyExchangeKey ) >( &s_InviteInfo.hostInfo.keyExchangeKey ) )
  416. {
  417. // Missing sessioninfo will cause the session info to be discovered during session
  418. // creation time
  419. char chSessionInfoBuffer[ XSESSION_INFO_STRING_LENGTH ] = {0};
  420. MMX360_SessionInfoToString( s_InviteInfo.hostInfo, chSessionInfoBuffer );
  421. pSettings->SetString( "options/sessioninfo", chSessionInfoBuffer );
  422. }
  423. #else
  424. pSettings->SetUint64( "options/sessionid", s_InviteInfo );
  425. #endif
  426. KeyValues::AutoDelete autodelete( pSettings );
  427. Q_memset( &s_InviteInfo, 0, sizeof( s_InviteInfo ) );
  428. g_pMatchFramework->MatchSession( pSettings );
  429. }
  430. static void OnInviteAccepted()
  431. {
  432. // Verify eligibility
  433. DevMsg( "OnInviteAccepted: verifying eligibility...\n" );
  434. if ( !VerifyInviteEligibility() )
  435. return;
  436. DevMsg( "OnInviteAccepted: confirming...\n" );
  437. // Make sure the user confirms the invite
  438. s_nInviteConfirmed = -1;
  439. if ( KeyValues *notify = new KeyValues( "OnInvite" ) )
  440. {
  441. #ifdef _X360
  442. char chSessionInfo[ XSESSION_INFO_STRING_LENGTH ] = {0};
  443. MMX360_SessionInfoToString( s_InviteInfo.hostInfo, chSessionInfo );
  444. notify->SetInt( "user", XBX_GetInvitedUserId() );
  445. notify->SetString( "sessioninfo", chSessionInfo );
  446. #else
  447. notify->SetUint64( "sessionid", s_InviteInfo );
  448. #endif
  449. notify->SetString( "action", "accepted" );
  450. notify->SetPtr( "confirmed", &s_nInviteConfirmed );
  451. g_pMatchEventsSubscription->BroadcastEvent( notify );
  452. // If handlers decided they need to confirm destructive actions or
  453. // select storage devices, etc.
  454. if ( s_nInviteConfirmed != -1 )
  455. {
  456. DevMsg( "OnInviteAccepted: waiting for confirmation...\n" );
  457. return;
  458. }
  459. }
  460. DevMsg( "OnInviteAccepted: accepting...\n" );
  461. // Otherwise, launch depending on our current MOD
  462. // if ( !Q_stricmp( GetCurrentMod(), "left4dead2" ) ) <-- for multi-game package
  463. {
  464. // Kick off our join
  465. JoinInviteSession();
  466. }
  467. // else <-- for multi-game package supporting cross-game invites
  468. // {
  469. // // Save off our session ID for later retrieval
  470. // // NOTE: We may need to actually save off the inviter's XID and search for them later on if we took too long or the
  471. // // session they were a part of went away
  472. //
  473. // XBX_SetInviteSessionId( inviteInfo.hostInfo.sessionID );
  474. //
  475. // // Quit via the menu path "QuitNoConfirm"
  476. // EngineVGui()->SystemNotification( SYSTEMNOTIFY_INVITE_SHUTDOWN, NULL );
  477. // }
  478. }
  479. void CMatchFramework::RunFrame_Invite()
  480. {
  481. if ( s_bInviteSessionDelayedJoin )
  482. JoinInviteSession();
  483. }
  484. void CMatchFramework::AcceptInvite( int iController )
  485. {
  486. #ifdef _X360
  487. s_bInviteSessionDelayedJoin = false;
  488. // Grab our invite info
  489. DWORD dwError = g_pMatchExtensions->GetIXOnline()->XInviteGetAcceptedInfo( iController, &s_InviteInfo );
  490. if ( dwError != ERROR_SUCCESS )
  491. {
  492. ZeroMemory( &s_InviteInfo, sizeof( s_InviteInfo ) );
  493. return;
  494. }
  495. // We only care if we're asked to join this title's session
  496. if ( s_InviteInfo.dwTitleID != GetMatchTitle()->GetTitleID() )
  497. {
  498. ZeroMemory( &s_InviteInfo, sizeof( s_InviteInfo ) );
  499. return;
  500. }
  501. // We just mark the invited user and let the matchmaking handle profile changes
  502. XBX_SetInvitedUserId( iController );
  503. // Invite accepted logic after globals have been setup
  504. OnInviteAccepted();
  505. #endif
  506. }
  507. #if !defined( _X360 ) && !defined( NO_STEAM ) && !defined( SWDS )
  508. void CMatchSteamInviteListener::Steam_OnGameLobbyJoinRequested( GameLobbyJoinRequested_t *pJoinInvite )
  509. {
  510. #ifdef _PS3
  511. if ( pJoinInvite->m_steamIDFriend.ConvertToUint64() != ~0ull )
  512. {
  513. g_uiLastInviteFlags = ( pJoinInvite->m_steamIDFriend.BConsoleUserAccount() ? MM_INVITE_FLAG_CONSOLE : 0 );
  514. }
  515. #endif
  516. #if !defined( _GAMECONSOLE )
  517. g_uiLastInviteFlags = ( pJoinInvite->m_steamIDFriend.ConvertToUint64() == ~0ull ) ? MM_INVITE_FLAG_PCBOOT : 0;
  518. #endif
  519. m_msgPending = GameLobbyJoinRequested_t();
  520. s_bInviteSessionDelayedJoin = false;
  521. s_InviteInfo = pJoinInvite->m_steamIDLobby.ConvertToUint64();
  522. if ( !s_InviteInfo )
  523. return;
  524. #ifdef _GAMECONSOLE
  525. // We just mark the invited user and let the matchmaking handle profile changes
  526. XBX_SetInvitedUserId( XBX_GetPrimaryUserId() );
  527. #endif
  528. // Whether we have to make invite go pending
  529. char chBuffer[2] = {};
  530. if ( g_pMatchExtensions->GetIVEngineClient()->IsDrawingLoadingImage() ||
  531. ( g_pMatchEventsSubscription && g_pMatchEventsSubscription->IsBroacasting() ) ||
  532. ( g_pMatchExtensions->GetIBaseClientDLL()->GetStatus( chBuffer, 2 ), ( chBuffer[0] != '+' ) ) )
  533. {
  534. m_msgPending = *pJoinInvite;
  535. return;
  536. }
  537. // Invite accepted logic after globals have been setup
  538. OnInviteAccepted();
  539. }
  540. #ifdef _PS3
  541. void CMatchSteamInviteListener::Steam_OnPSNGameBootInviteResult( PSNGameBootInviteResult_t *pParam )
  542. {
  543. if ( pParam->m_bGameBootInviteExists && pParam->m_steamIDLobby.IsValid() )
  544. {
  545. g_uiLastInviteFlags = MM_INVITE_FLAG_CONSOLE;
  546. }
  547. }
  548. #endif
  549. void CMatchSteamInviteListener::RunFrame()
  550. {
  551. if ( m_msgPending.m_steamIDLobby.IsValid() )
  552. {
  553. GameLobbyJoinRequested_t msgRequest = m_msgPending;
  554. Steam_OnGameLobbyJoinRequested( &msgRequest );
  555. }
  556. }
  557. #endif
  558. IMatchSession *CMatchFramework::GetMatchSession()
  559. {
  560. return m_pMatchSession;
  561. }
  562. void CMatchFramework::CreateSession( KeyValues *pSettings )
  563. {
  564. DevMsg( "CreateSession: \n");
  565. KeyValuesDumpAsDevMsg( pSettings );
  566. #ifndef SWDS
  567. if ( !pSettings )
  568. return;
  569. IMatchSessionInternal *pMatchSessionNew = NULL;
  570. //
  571. // Analyze the type of session requested to create
  572. //
  573. char const *szNetwork = pSettings->GetString( "system/network", "offline" );
  574. #ifdef _X360
  575. if ( !Q_stricmp( "LIVE", szNetwork ) && !ValidateInviteControllers() )
  576. return;
  577. #endif
  578. // Recompute XUIDs for the session type that we are creating
  579. g_pPlayerManager->RecomputePlayerXUIDs( szNetwork );
  580. //
  581. // Process create session request
  582. //
  583. if ( !Q_stricmp( "offline", szNetwork ) )
  584. {
  585. CMatchSessionOfflineCustom *pSession = new CMatchSessionOfflineCustom( pSettings );
  586. pMatchSessionNew = pSession;
  587. }
  588. else
  589. {
  590. CMatchSessionOnlineHost *pSession = new CMatchSessionOnlineHost( pSettings );
  591. pMatchSessionNew = pSession;
  592. }
  593. if ( pMatchSessionNew )
  594. {
  595. CloseSession();
  596. m_pMatchSession = pMatchSessionNew;
  597. }
  598. #endif
  599. }
  600. void CMatchFramework::MatchSession( KeyValues *pSettings )
  601. {
  602. #ifndef SWDS
  603. if ( !pSettings )
  604. return;
  605. DevMsg( "MatchSession: \n");
  606. KeyValuesDumpAsDevMsg( pSettings );
  607. IMatchSessionInternal *pMatchSessionNew = NULL;
  608. //
  609. // Analyze what kind of client-side matchmaking
  610. // needs to happen.
  611. //
  612. char const *szNetwork = pSettings->GetString( "system/network", "LIVE" );
  613. char const *szAction = pSettings->GetString( "options/action", "" );
  614. // Recompute XUIDs for the session type that we are creating
  615. g_pPlayerManager->RecomputePlayerXUIDs( szNetwork );
  616. //
  617. // Process match session request
  618. //
  619. if ( !Q_stricmp( "joinsession", szAction ) )
  620. {
  621. #ifdef _X360
  622. // For LIVE sessions we need to be eligible
  623. if ( !Q_stricmp( "LIVE", szNetwork ) && !ValidateInviteControllers() )
  624. return;
  625. #endif
  626. // We have an explicit session to join
  627. CMatchSessionOnlineClient *pSession = new CMatchSessionOnlineClient( pSettings );
  628. pMatchSessionNew = pSession;
  629. }
  630. else if ( !Q_stricmp( "joininvitesession", szAction ) )
  631. {
  632. #ifdef _X360
  633. ZeroMemory( &s_InviteInfo, sizeof( s_InviteInfo ) );
  634. XUSER_SIGNIN_INFO xsi;
  635. if ( ERROR_SUCCESS == XUserGetSigninInfo( XBX_GetInvitedUserId(), XUSER_GET_SIGNIN_INFO_ONLINE_XUID_ONLY, &xsi ) )
  636. s_InviteInfo.xuidInvitee = xsi.xuid;
  637. uint64 uiSessionID = pSettings->GetUint64( "options/sessionid", 0ull );
  638. s_InviteInfo.hostInfo.sessionID = ( XNKID & ) uiSessionID;
  639. OnInviteAccepted();
  640. #endif
  641. }
  642. else // "quickmatch" or "custommatch"
  643. {
  644. #ifdef _X360
  645. // For LIVE sessions we need to be eligible
  646. if ( !Q_stricmp( "LIVE", szNetwork ) && !ValidateInviteControllers() )
  647. return;
  648. #endif
  649. CMatchSessionOnlineSearch *pSession = new CMatchSessionOnlineSearch( pSettings );
  650. pMatchSessionNew = pSession;
  651. }
  652. if ( pMatchSessionNew )
  653. {
  654. CloseSession();
  655. m_pMatchSession = pMatchSessionNew;
  656. }
  657. #endif
  658. }
  659. void CMatchFramework::CloseSession()
  660. {
  661. // Destroy the session
  662. if ( m_pMatchSession )
  663. {
  664. IMatchSessionInternal *pMatchSession = m_pMatchSession;
  665. m_pMatchSession = NULL;
  666. pMatchSession->Destroy();
  667. g_pMatchEventsSubscription->BroadcastEvent( new KeyValues( "OnMatchSessionUpdate", "state", "closed" ) );
  668. }
  669. }
  670. bool CMatchFramework::IsOnlineGame( void )
  671. {
  672. IMatchSession *pMatchSession = GetMatchSession();
  673. if ( pMatchSession )
  674. {
  675. KeyValues* kv = pMatchSession->GetSessionSettings();
  676. if ( kv )
  677. {
  678. char const *szMode = kv->GetString( "system/network", NULL );
  679. if ( szMode && !V_stricmp( "LIVE", szMode ) )
  680. {
  681. return true;
  682. }
  683. }
  684. }
  685. return false;
  686. }
  687. void CMatchFramework::UpdateTeamProperties( KeyValues *pTeamProperties )
  688. {
  689. IMatchSession *pMatchSession = GetMatchSession();
  690. IMatchTitleGameSettingsMgr *pMatchTitleGameSettingsMgr = GetMatchTitleGameSettingsMgr();
  691. if ( pMatchSession && pMatchTitleGameSettingsMgr )
  692. {
  693. pMatchSession->UpdateTeamProperties( pTeamProperties );
  694. KeyValues *pCurrentSettings = pMatchSession->GetSessionSettings();
  695. pMatchTitleGameSettingsMgr->UpdateTeamProperties( pCurrentSettings, pTeamProperties );
  696. }
  697. }
  698. void CMatchFramework::OnEvent( KeyValues *pEvent )
  699. {
  700. char const *szEvent = pEvent->GetName();
  701. if ( !Q_stricmp( "mmF->CloseSession", szEvent ) )
  702. {
  703. CloseSession();
  704. return;
  705. }
  706. else if ( !Q_stricmp( "OnInvite", szEvent ) )
  707. {
  708. if ( !Q_stricmp( "join", pEvent->GetString( "action" ) ) )
  709. {
  710. s_bInviteSessionDelayedJoin = true;
  711. }
  712. else if ( !Q_stricmp( "deny", pEvent->GetString( "action" ) ) )
  713. {
  714. Q_memset( &s_InviteInfo, 0, sizeof( s_InviteInfo ) );
  715. s_bInviteSessionDelayedJoin = false;
  716. }
  717. return;
  718. }
  719. else if ( !Q_stricmp( "OnSteamOverlayCall::LobbyJoin", szEvent ) )
  720. {
  721. #if !defined( _X360 ) && !defined( NO_STEAM ) && !defined( SWDS )
  722. GameLobbyJoinRequested_t msg;
  723. msg.m_steamIDLobby.SetFromUint64( pEvent->GetUint64( "sessionid" ) );
  724. msg.m_steamIDFriend.SetFromUint64( ~0ull );
  725. g_MatchSteamInviteListener.Steam_OnGameLobbyJoinRequested( &msg );
  726. #endif
  727. return;
  728. }
  729. else if ( !Q_stricmp( "OnMatchSessionUpdate", szEvent ) )
  730. {
  731. KeyValues *pUpdate = pEvent->FindKey( "update" );
  732. if ( pUpdate )
  733. {
  734. const char *pAction = pUpdate->GetString( "options/action", "" );
  735. if ( !Q_stricmp( "joinsession", pAction ) )
  736. {
  737. KeyValues *pTeamMembers = pUpdate->FindKey( "teamMembers" );
  738. if ( pTeamMembers )
  739. {
  740. // Received console team match settings from host
  741. // Find what team we are on
  742. int numPlayers = pTeamMembers->GetInt( "numPlayers" );
  743. int playerTeam = -1;
  744. int activeUer = XBX_GetPrimaryUserId();
  745. IPlayerLocal *player = g_pPlayerManager->GetLocalPlayer( activeUer );
  746. uint64 localPlayerId = player->GetXUID();
  747. for ( int i = 0; i < numPlayers; i++ )
  748. {
  749. KeyValues *pTeamPlayer = pTeamMembers->FindKey( CFmtStr( "player%d", i ) );
  750. uint64 playerId = pTeamPlayer->GetUint64( "xuid" );
  751. if ( playerId == localPlayerId )
  752. {
  753. int team = pTeamPlayer->GetInt( "team" );
  754. DevMsg( "Adding player %llu to team %d\n", playerId, team );
  755. playerTeam = team;
  756. break;
  757. }
  758. }
  759. m_pTeamSessionSettings = pUpdate->MakeCopy();
  760. m_pTeamSessionSettings->SetName( "settings ");
  761. // Delete the "teamMembers" key
  762. m_pTeamSessionSettings->RemoveSubKey( m_pTeamSessionSettings->FindKey( "teamMembers" ) );
  763. // Add "conteam" value
  764. m_pTeamSessionSettings->SetInt( "conteam", playerTeam );
  765. // Add the "sessionHostDataUnpacked" key
  766. KeyValues *pSessionHostDataSrc = pUpdate->FindKey( "sessionHostDataUnpacked" );
  767. if ( pSessionHostDataSrc )
  768. {
  769. KeyValues *pSessionHostDataDst = m_pTeamSessionSettings->CreateNewKey();
  770. pSessionHostDataDst->SetName( "sessionHostDataUnpacked" );
  771. pSessionHostDataSrc->CopySubkeys( pSessionHostDataDst );
  772. }
  773. m_bJoinTeamSession = true;
  774. }
  775. }
  776. }
  777. }
  778. //
  779. // Delegate to the managers
  780. //
  781. if ( g_pPlayerManager )
  782. g_pPlayerManager->OnEvent( pEvent );
  783. if ( g_pServerManager )
  784. g_pServerManager->OnEvent( pEvent );
  785. if ( g_pDatacenter )
  786. g_pDatacenter->OnEvent( pEvent );
  787. if ( g_pDlcManager )
  788. g_pDlcManager->OnEvent( pEvent );
  789. //
  790. // Delegate to the title
  791. //
  792. if ( g_pIMatchTitleEventsSink )
  793. g_pIMatchTitleEventsSink->OnEvent( pEvent );
  794. //
  795. // Delegate to the session
  796. //
  797. if ( m_pMatchSession )
  798. m_pMatchSession->OnEvent( pEvent );
  799. }
  800. void CMatchFramework::SetCurrentMatchSession( IMatchSessionInternal *pNewMatchSession )
  801. {
  802. m_pMatchSession = pNewMatchSession;
  803. }
  804. uint64 CMatchFramework::GetLastInviteFlags()
  805. {
  806. return g_uiLastInviteFlags;
  807. }