//===== Copyright © 1996-2009, Valve Corporation, All rights reserved. ======// // // Purpose: // //===========================================================================// #include "mm_framework.h" #include "mm_netmsgcontroller.h" #include "matchsystem.h" #include "mm_title_main.h" #include "x360_lobbyapi.h" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" // Stress testing events listeners every frame ConVar mm_events_listeners_validation( "mm_events_listeners_validation", "0", FCVAR_DEVELOPMENTONLY ); // // Implementation of Steam invite listener // uint64 g_uiLastInviteFlags = 0ull; #if !defined( _X360 ) && !defined( NO_STEAM ) && !defined( SWDS ) class CMatchSteamInviteListener { public: void RunFrame(); void Register(); STEAM_CALLBACK_MANUAL( CMatchSteamInviteListener, Steam_OnGameLobbyJoinRequested, GameLobbyJoinRequested_t, m_CallbackOnGameLobbyJoinRequested ); #ifdef _PS3 STEAM_CALLBACK_MANUAL( CMatchSteamInviteListener, Steam_OnPSNGameBootInviteResult, PSNGameBootInviteResult_t, m_CallbackOnPSNGameBootInviteResult ); #endif protected: GameLobbyJoinRequested_t m_msgPending; } g_MatchSteamInviteListener; void CMatchSteamInviteListener::Register() { m_CallbackOnGameLobbyJoinRequested.Register( this, &CMatchSteamInviteListener::Steam_OnGameLobbyJoinRequested ); #ifdef _PS3 m_CallbackOnPSNGameBootInviteResult.Register( this, &CMatchSteamInviteListener::Steam_OnPSNGameBootInviteResult ); #endif } #else class CMatchSteamInviteListener { public: void RunFrame() {} void Register() {} } g_MatchSteamInviteListener; #endif // // Implementation // CMatchFramework::CMatchFramework() : m_pMatchSession( NULL ), m_bJoinTeamSession( false ), m_pTeamSessionSettings( NULL ) { } CMatchFramework::~CMatchFramework() { ; } InitReturnVal_t CMatchFramework::Init() { InitReturnVal_t ret = INIT_OK; ret = MM_Title_Init(); if ( ret != INIT_OK ) return ret; g_MatchSteamInviteListener.Register(); return INIT_OK; } void CMatchFramework::Shutdown() { // Shutdown event system g_pMatchEventsSubscription->Shutdown(); // Shutdown the title MM_Title_Shutdown(); // Cancel any pending server updates before shutdown g_pServerManager->EnableServersUpdate( false ); // Cancel any pending datacenter queries g_pDatacenter->EnableUpdate( false ); } void CMatchFramework::RunFrame() { // Run frame listeners validation if requested if ( mm_events_listeners_validation.GetBool() ) { g_pMatchEventsSubscription->BroadcastEvent( new KeyValues( "mm_events_listeners_validation" ) ); } #ifdef _X360 if ( IXOnline *pIXOnline = g_pMatchExtensions->GetIXOnline() ) pIXOnline->RunFrame(); MMX360_UpdateDormantOperations(); SysSession360_UpdatePending(); #endif RunFrame_Invite(); g_MatchSteamInviteListener.RunFrame(); #ifdef _X360 // Pump rate adjustments MatchSession_RateAdjustmentUpdate(); #endif // Let the network mgr run g_pConnectionlessLanMgr->Update(); // Let the matchsystem run g_pMatchSystem->Update(); // Let the match session run if ( m_pMatchSession ) m_pMatchSession->Update(); // Let the match title run frame g_pIMatchTitle->RunFrame(); if ( m_bJoinTeamSession ) { m_bJoinTeamSession = false; MatchSession( m_pTeamSessionSettings ); m_pTeamSessionSettings->deleteThis(); m_pTeamSessionSettings = NULL; } } IMatchExtensions * CMatchFramework::GetMatchExtensions() { return g_pMatchExtensions; } IMatchEventsSubscription * CMatchFramework::GetEventsSubscription() { return g_pMatchEventsSubscription; } IMatchTitle * CMatchFramework::GetMatchTitle() { return g_pIMatchTitle; } IMatchTitleGameSettingsMgr * CMatchFramework::GetMatchTitleGameSettingsMgr() { return g_pIMatchTitleGameSettingsMgr; } IMatchNetworkMsgController * CMatchFramework::GetMatchNetworkMsgController() { return g_pMatchNetMsgControllerBase; } IMatchSystem * CMatchFramework::GetMatchSystem() { return g_pMatchSystem; } void CMatchFramework::ApplySettings( KeyValues* keyValues ) { g_pMatchExtensions->GetIServerGameDLL()->ApplyGameSettings( keyValues ); } #ifdef _X360 static XINVITE_INFO s_InviteInfo; #else static uint64 s_InviteInfo; #endif static bool s_bInviteSessionDelayedJoin; static int s_nInviteConfirmed; template < int datasize > static bool IsZeroData( void const *pvData ) { static char s_zerodata[ datasize ]; return !memcmp( s_zerodata, pvData, datasize ); } static bool ValidateInviteController( int iController ) { #ifdef _X360 XUSER_SIGNIN_STATE eSignInState = XUserGetSigninState( iController ); XUSER_SIGNIN_INFO xsi = {0}; if ( ( eSignInState != eXUserSigninState_SignedInToLive ) || ( ERROR_SUCCESS != XUserGetSigninInfo( iController, XUSER_GET_SIGNIN_INFO_ONLINE_XUID_ONLY, &xsi ) ) || ! ( xsi.dwInfoFlags & XUSER_INFO_FLAG_LIVE_ENABLED ) ) { DevWarning( "ValidateInviteController: ctrl%d check1 failed (state=%d, flags=0x%X, xuid=%llx)!\n", eSignInState, xsi.dwInfoFlags, xsi.xuid ); if ( KeyValues *notify = new KeyValues( "OnInvite", "action", "error", "error", "NotOnline" ) ) { notify->SetInt( "user", iController ); g_pMatchEventsSubscription->BroadcastEvent( notify ); } return false; } BOOL bMultiplayer = FALSE; if ( ( ERROR_SUCCESS != XUserCheckPrivilege( iController, XPRIVILEGE_MULTIPLAYER_SESSIONS, &bMultiplayer ) ) || ( !bMultiplayer ) ) { DevWarning( "ValidateInviteController: ctrl%d check2 failed (state=%d, flags=0x%X, xuid=%llx) - on multiplayer priv!\n", eSignInState, xsi.dwInfoFlags, xsi.xuid ); if ( KeyValues *notify = new KeyValues( "OnInvite", "action", "error", "error", "NoMultiplayer" ) ) { notify->SetInt( "user", iController ); g_pMatchEventsSubscription->BroadcastEvent( notify ); } return false; } #endif return true; } static bool ValidateInviteControllers() { for ( DWORD k = 0; k < XBX_GetNumGameUsers(); ++ k ) { if ( !ValidateInviteController( XBX_GetUserId( k ) ) ) return false; } return true; } static bool VerifyInviteEligibility() { #ifdef _X360 // Make sure that the inviter is not signed in for ( int k = 0; k < XUSER_MAX_COUNT; ++ k ) { XUID xuid; if ( ERROR_SUCCESS == XUserGetXUID( k, &xuid ) && xuid == s_InviteInfo.xuidInviter ) { g_pMatchEventsSubscription->BroadcastEvent( new KeyValues( "OnInvite", "action", "error", "error", "SameConsole" ) ); return false; } } // Check if the user is currently inactive bool bExistingUser = false; for ( DWORD k = 0; k < XBX_GetNumGameUsers(); ++ k ) { if ( XBX_GetInvitedUserId() == (DWORD) XBX_GetUserId( k ) && !XBX_GetUserIsGuest( k ) ) { bExistingUser = true; break; } } // Check if this is the existing user that the invite is for a different session // than the session they are currently in (e.g. they are in a lobby and do // "Join Party and Game" with another user who is in the same lobby) char chInviteSessionInfo[ XSESSION_INFO_STRING_LENGTH ] = {0}; MMX360_SessionInfoToString( s_InviteInfo.hostInfo, chInviteSessionInfo ); if ( IMatchSession *pIMatchSession = g_pMatchFramework->GetMatchSession() ) { bool bJoinable = ( ( IMatchSessionInternal * ) pIMatchSession )->IsAnotherSessionJoinable( chInviteSessionInfo ); if ( !bJoinable && bExistingUser ) { Warning( "VerifyInviteEligibility: declined invite due to local session!\n" ); return false; } } // New user is eligible since otherwise he shouldn't be able to accept an invite if ( !bExistingUser || ( XBX_GetNumGameUsers() < 2 ) || ( g_pMMF->GetMatchTitle()->GetTitleSettingsFlags() & MATCHTITLE_INVITE_ONLY_SINGLE_USER ) ) { if ( !ValidateInviteController( XBX_GetInvitedUserId() ) ) return false; else return true; } #endif // Check that every user is valid return ValidateInviteControllers(); } static void JoinInviteSession() { s_bInviteSessionDelayedJoin = false; #ifdef _X360 if ( 0ull == ( uint64 const & ) s_InviteInfo.hostInfo.sessionID ) #else if ( !s_InviteInfo ) #endif return; if ( g_pMatchExtensions->GetIVEngineClient()->IsDrawingLoadingImage() ) { s_bInviteSessionDelayedJoin = true; return; } // Invites cannot be accepted from inside an event broadcast // internally used events must be top-level events since they // operate on signed in / active users, trigger playermanager, // account access and other events // Wait until next frame in such case if ( g_pMatchEventsSubscription && g_pMatchEventsSubscription->IsBroacasting() ) { s_bInviteSessionDelayedJoin = true; return; } #if !defined( NO_STEAM ) && !defined( _GAMECONSOLE ) && !defined( SWDS ) extern bool g_bSteamStatsReceived; if ( !g_bSteamStatsReceived && ( g_uiLastInviteFlags & MM_INVITE_FLAG_PCBOOT ) ) { s_bInviteSessionDelayedJoin = true; return; } #endif #ifdef _X360 DevMsg( "JoinInviteSession: sessionid = %llx, xuid = %llx\n", ( uint64 const & ) s_InviteInfo.hostInfo.sessionID, s_InviteInfo.xuidInvitee ); #else DevMsg( "JoinInviteSession: sessionid = %llx\n", s_InviteInfo ); #endif // // Validate the user accepting the invite // #ifdef _GAMECONSOLE if ( XBX_GetInvitedUserId() == INVALID_USER_ID ) { DevWarning( "JoinInviteSession: no invited user!\n" ); return; } #endif #ifdef _X360 XUSER_SIGNIN_STATE eSignInState = XUserGetSigninState( XBX_GetInvitedUserId() ); XUSER_SIGNIN_INFO xsi = {0}; if ( ( eSignInState != eXUserSigninState_SignedInToLive ) || ( ERROR_SUCCESS != XUserGetSigninInfo( XBX_GetInvitedUserId(), XUSER_GET_SIGNIN_INFO_ONLINE_XUID_ONLY, &xsi ) ) || ! ( xsi.dwInfoFlags & XUSER_INFO_FLAG_LIVE_ENABLED ) || ( xsi.dwInfoFlags & XUSER_INFO_FLAG_GUEST ) || !IsEqualXUID( xsi.xuid, s_InviteInfo.xuidInvitee ) ) { DevWarning( "JoinInviteSession: invited user signin information validation failed (state=%d, flags=0x%X, xuid=%llx)!\n", eSignInState, xsi.dwInfoFlags, xsi.xuid ); return; } BOOL bMultiplayer = FALSE; if ( ( ERROR_SUCCESS != XUserCheckPrivilege( XBX_GetInvitedUserId(), XPRIVILEGE_MULTIPLAYER_SESSIONS, &bMultiplayer ) ) || ( !bMultiplayer ) ) { DevWarning( "JoinInviteSession: no multiplayer priv!\n" ); return; } #endif // // Check if the currently-involved user is accepting the invite // #ifdef _GAMECONSOLE bool bExistingUser = false; for ( DWORD k = 0; k < XBX_GetNumGameUsers(); ++ k ) { if ( XBX_GetInvitedUserId() == (DWORD) XBX_GetUserId( k ) && !XBX_GetUserIsGuest( k ) ) { bExistingUser = true; break; } } if ( !bExistingUser || ( ( XBX_GetNumGameUsers() > 1 ) && ( g_pMMF->GetMatchTitle()->GetTitleSettingsFlags() & MATCHTITLE_INVITE_ONLY_SINGLE_USER ) ) ) { // Another controller is accepting the invite or guest status // has changed. // then we need to reset all our XBX core state: DevMsg( "JoinInviteSession: activating inactive controller%d\n", XBX_GetInvitedUserId() ); g_pMatchEventsSubscription->BroadcastEvent( new KeyValues( "OnProfilesWriteOpportunity", "reason", "deactivation" ) ); XBX_ClearUserIdSlots(); XBX_SetPrimaryUserId( XBX_GetInvitedUserId() ); XBX_SetPrimaryUserIsGuest( 0 ); XBX_SetUserId( 0, XBX_GetInvitedUserId() ); XBX_SetUserIsGuest( 0, 0 ); XBX_SetNumGameUsers( 1 ); g_pMatchEventsSubscription->BroadcastEvent( new KeyValues( "OnProfilesChanged", "numProfiles", int(1) ) ); IPlayerLocal *pPlayer = g_pPlayerManager->GetLocalPlayer( XBX_GetPrimaryUserId() ); if ( !pPlayer ) { g_pMatchEventsSubscription->BroadcastEvent( new KeyValues( "OnInvite", "action", "error", "error", "" ) ); return; } ( ( PlayerLocal * ) pPlayer )->SetFlag_AwaitingTitleData(); // Since we have activated a new profile, we need to wait until title data gets loaded DevMsg( "JoinInviteSession: activated inactive controller%d, waiting for title data...\n", XBX_GetInvitedUserId() ); return; } #endif // Validate storage device s_nInviteConfirmed = -1; if ( KeyValues *notify = new KeyValues( "OnInvite" ) ) { #ifdef _X360 char chSessionInfo[ XSESSION_INFO_STRING_LENGTH ] = {0}; MMX360_SessionInfoToString( s_InviteInfo.hostInfo, chSessionInfo ); notify->SetInt( "user", XBX_GetInvitedUserId() ); notify->SetString( "sessioninfo", chSessionInfo ); #else notify->SetUint64( "sessionid", s_InviteInfo ); #endif notify->SetString( "action", "storage" ); notify->SetPtr( "confirmed", &s_nInviteConfirmed ); g_pMatchEventsSubscription->BroadcastEvent( notify ); // If handlers decided they need to confirm storage devices, etc. if ( s_nInviteConfirmed != -1 ) { DevMsg( "JoinInviteSession: waiting for storage device selection...\n" ); return; } } // Verify eligibility DevMsg( "JoinInviteSession: verifying eligibility...\n" ); if ( !VerifyInviteEligibility() ) return; DevMsg( "JoinInviteSession: connecting...\n" ); // // Argument validation // #ifdef _GAMECONSOLE Assert( XBX_GetInvitedUserId() >= 0 ); Assert( XBX_GetInvitedUserId() < XUSER_MAX_COUNT ); Assert( XBX_GetSlotByUserId( XBX_GetInvitedUserId() ) < ( int ) XBX_GetNumGameUsers() ); Assert( XBX_GetNumGameUsers() < MAX_SPLITSCREEN_CLIENTS ); #endif // Requesting to join the stored off session KeyValues *pSettings = KeyValues::FromString( "settings", " system { " " network LIVE " " } " " options { " " action joinsession " " } " ); #ifdef _X360 pSettings->SetUint64( "options/sessionid", ( const uint64 & ) s_InviteInfo.hostInfo.sessionID ); if ( !IsZeroData< sizeof( s_InviteInfo.hostInfo.keyExchangeKey ) >( &s_InviteInfo.hostInfo.keyExchangeKey ) ) { // Missing sessioninfo will cause the session info to be discovered during session // creation time char chSessionInfoBuffer[ XSESSION_INFO_STRING_LENGTH ] = {0}; MMX360_SessionInfoToString( s_InviteInfo.hostInfo, chSessionInfoBuffer ); pSettings->SetString( "options/sessioninfo", chSessionInfoBuffer ); } #else pSettings->SetUint64( "options/sessionid", s_InviteInfo ); #endif KeyValues::AutoDelete autodelete( pSettings ); Q_memset( &s_InviteInfo, 0, sizeof( s_InviteInfo ) ); g_pMatchFramework->MatchSession( pSettings ); } static void OnInviteAccepted() { // Verify eligibility DevMsg( "OnInviteAccepted: verifying eligibility...\n" ); if ( !VerifyInviteEligibility() ) return; DevMsg( "OnInviteAccepted: confirming...\n" ); // Make sure the user confirms the invite s_nInviteConfirmed = -1; if ( KeyValues *notify = new KeyValues( "OnInvite" ) ) { #ifdef _X360 char chSessionInfo[ XSESSION_INFO_STRING_LENGTH ] = {0}; MMX360_SessionInfoToString( s_InviteInfo.hostInfo, chSessionInfo ); notify->SetInt( "user", XBX_GetInvitedUserId() ); notify->SetString( "sessioninfo", chSessionInfo ); #else notify->SetUint64( "sessionid", s_InviteInfo ); #endif notify->SetString( "action", "accepted" ); notify->SetPtr( "confirmed", &s_nInviteConfirmed ); g_pMatchEventsSubscription->BroadcastEvent( notify ); // If handlers decided they need to confirm destructive actions or // select storage devices, etc. if ( s_nInviteConfirmed != -1 ) { DevMsg( "OnInviteAccepted: waiting for confirmation...\n" ); return; } } DevMsg( "OnInviteAccepted: accepting...\n" ); // Otherwise, launch depending on our current MOD // if ( !Q_stricmp( GetCurrentMod(), "left4dead2" ) ) <-- for multi-game package { // Kick off our join JoinInviteSession(); } // else <-- for multi-game package supporting cross-game invites // { // // Save off our session ID for later retrieval // // 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 // // session they were a part of went away // // XBX_SetInviteSessionId( inviteInfo.hostInfo.sessionID ); // // // Quit via the menu path "QuitNoConfirm" // EngineVGui()->SystemNotification( SYSTEMNOTIFY_INVITE_SHUTDOWN, NULL ); // } } void CMatchFramework::RunFrame_Invite() { if ( s_bInviteSessionDelayedJoin ) JoinInviteSession(); } void CMatchFramework::AcceptInvite( int iController ) { #ifdef _X360 s_bInviteSessionDelayedJoin = false; // Grab our invite info DWORD dwError = g_pMatchExtensions->GetIXOnline()->XInviteGetAcceptedInfo( iController, &s_InviteInfo ); if ( dwError != ERROR_SUCCESS ) { ZeroMemory( &s_InviteInfo, sizeof( s_InviteInfo ) ); return; } // We only care if we're asked to join this title's session if ( s_InviteInfo.dwTitleID != GetMatchTitle()->GetTitleID() ) { ZeroMemory( &s_InviteInfo, sizeof( s_InviteInfo ) ); return; } // We just mark the invited user and let the matchmaking handle profile changes XBX_SetInvitedUserId( iController ); // Invite accepted logic after globals have been setup OnInviteAccepted(); #endif } #if !defined( _X360 ) && !defined( NO_STEAM ) && !defined( SWDS ) void CMatchSteamInviteListener::Steam_OnGameLobbyJoinRequested( GameLobbyJoinRequested_t *pJoinInvite ) { #ifdef _PS3 if ( pJoinInvite->m_steamIDFriend.ConvertToUint64() != ~0ull ) { g_uiLastInviteFlags = ( pJoinInvite->m_steamIDFriend.BConsoleUserAccount() ? MM_INVITE_FLAG_CONSOLE : 0 ); } #endif #if !defined( _GAMECONSOLE ) g_uiLastInviteFlags = ( pJoinInvite->m_steamIDFriend.ConvertToUint64() == ~0ull ) ? MM_INVITE_FLAG_PCBOOT : 0; #endif m_msgPending = GameLobbyJoinRequested_t(); s_bInviteSessionDelayedJoin = false; s_InviteInfo = pJoinInvite->m_steamIDLobby.ConvertToUint64(); if ( !s_InviteInfo ) return; #ifdef _GAMECONSOLE // We just mark the invited user and let the matchmaking handle profile changes XBX_SetInvitedUserId( XBX_GetPrimaryUserId() ); #endif // Whether we have to make invite go pending char chBuffer[2] = {}; if ( g_pMatchExtensions->GetIVEngineClient()->IsDrawingLoadingImage() || ( g_pMatchEventsSubscription && g_pMatchEventsSubscription->IsBroacasting() ) || ( g_pMatchExtensions->GetIBaseClientDLL()->GetStatus( chBuffer, 2 ), ( chBuffer[0] != '+' ) ) ) { m_msgPending = *pJoinInvite; return; } // Invite accepted logic after globals have been setup OnInviteAccepted(); } #ifdef _PS3 void CMatchSteamInviteListener::Steam_OnPSNGameBootInviteResult( PSNGameBootInviteResult_t *pParam ) { if ( pParam->m_bGameBootInviteExists && pParam->m_steamIDLobby.IsValid() ) { g_uiLastInviteFlags = MM_INVITE_FLAG_CONSOLE; } } #endif void CMatchSteamInviteListener::RunFrame() { if ( m_msgPending.m_steamIDLobby.IsValid() ) { GameLobbyJoinRequested_t msgRequest = m_msgPending; Steam_OnGameLobbyJoinRequested( &msgRequest ); } } #endif IMatchSession *CMatchFramework::GetMatchSession() { return m_pMatchSession; } void CMatchFramework::CreateSession( KeyValues *pSettings ) { DevMsg( "CreateSession: \n"); KeyValuesDumpAsDevMsg( pSettings ); #ifndef SWDS if ( !pSettings ) return; IMatchSessionInternal *pMatchSessionNew = NULL; // // Analyze the type of session requested to create // char const *szNetwork = pSettings->GetString( "system/network", "offline" ); #ifdef _X360 if ( !Q_stricmp( "LIVE", szNetwork ) && !ValidateInviteControllers() ) return; #endif // Recompute XUIDs for the session type that we are creating g_pPlayerManager->RecomputePlayerXUIDs( szNetwork ); // // Process create session request // if ( !Q_stricmp( "offline", szNetwork ) ) { CMatchSessionOfflineCustom *pSession = new CMatchSessionOfflineCustom( pSettings ); pMatchSessionNew = pSession; } else { CMatchSessionOnlineHost *pSession = new CMatchSessionOnlineHost( pSettings ); pMatchSessionNew = pSession; } if ( pMatchSessionNew ) { CloseSession(); m_pMatchSession = pMatchSessionNew; } #endif } void CMatchFramework::MatchSession( KeyValues *pSettings ) { #ifndef SWDS if ( !pSettings ) return; DevMsg( "MatchSession: \n"); KeyValuesDumpAsDevMsg( pSettings ); IMatchSessionInternal *pMatchSessionNew = NULL; // // Analyze what kind of client-side matchmaking // needs to happen. // char const *szNetwork = pSettings->GetString( "system/network", "LIVE" ); char const *szAction = pSettings->GetString( "options/action", "" ); // Recompute XUIDs for the session type that we are creating g_pPlayerManager->RecomputePlayerXUIDs( szNetwork ); // // Process match session request // if ( !Q_stricmp( "joinsession", szAction ) ) { #ifdef _X360 // For LIVE sessions we need to be eligible if ( !Q_stricmp( "LIVE", szNetwork ) && !ValidateInviteControllers() ) return; #endif // We have an explicit session to join CMatchSessionOnlineClient *pSession = new CMatchSessionOnlineClient( pSettings ); pMatchSessionNew = pSession; } else if ( !Q_stricmp( "joininvitesession", szAction ) ) { #ifdef _X360 ZeroMemory( &s_InviteInfo, sizeof( s_InviteInfo ) ); XUSER_SIGNIN_INFO xsi; if ( ERROR_SUCCESS == XUserGetSigninInfo( XBX_GetInvitedUserId(), XUSER_GET_SIGNIN_INFO_ONLINE_XUID_ONLY, &xsi ) ) s_InviteInfo.xuidInvitee = xsi.xuid; uint64 uiSessionID = pSettings->GetUint64( "options/sessionid", 0ull ); s_InviteInfo.hostInfo.sessionID = ( XNKID & ) uiSessionID; OnInviteAccepted(); #endif } else // "quickmatch" or "custommatch" { #ifdef _X360 // For LIVE sessions we need to be eligible if ( !Q_stricmp( "LIVE", szNetwork ) && !ValidateInviteControllers() ) return; #endif CMatchSessionOnlineSearch *pSession = new CMatchSessionOnlineSearch( pSettings ); pMatchSessionNew = pSession; } if ( pMatchSessionNew ) { CloseSession(); m_pMatchSession = pMatchSessionNew; } #endif } void CMatchFramework::CloseSession() { // Destroy the session if ( m_pMatchSession ) { IMatchSessionInternal *pMatchSession = m_pMatchSession; m_pMatchSession = NULL; pMatchSession->Destroy(); g_pMatchEventsSubscription->BroadcastEvent( new KeyValues( "OnMatchSessionUpdate", "state", "closed" ) ); } } bool CMatchFramework::IsOnlineGame( void ) { IMatchSession *pMatchSession = GetMatchSession(); if ( pMatchSession ) { KeyValues* kv = pMatchSession->GetSessionSettings(); if ( kv ) { char const *szMode = kv->GetString( "system/network", NULL ); if ( szMode && !V_stricmp( "LIVE", szMode ) ) { return true; } } } return false; } void CMatchFramework::UpdateTeamProperties( KeyValues *pTeamProperties ) { IMatchSession *pMatchSession = GetMatchSession(); IMatchTitleGameSettingsMgr *pMatchTitleGameSettingsMgr = GetMatchTitleGameSettingsMgr(); if ( pMatchSession && pMatchTitleGameSettingsMgr ) { pMatchSession->UpdateTeamProperties( pTeamProperties ); KeyValues *pCurrentSettings = pMatchSession->GetSessionSettings(); pMatchTitleGameSettingsMgr->UpdateTeamProperties( pCurrentSettings, pTeamProperties ); } } void CMatchFramework::OnEvent( KeyValues *pEvent ) { char const *szEvent = pEvent->GetName(); if ( !Q_stricmp( "mmF->CloseSession", szEvent ) ) { CloseSession(); return; } else if ( !Q_stricmp( "OnInvite", szEvent ) ) { if ( !Q_stricmp( "join", pEvent->GetString( "action" ) ) ) { s_bInviteSessionDelayedJoin = true; } else if ( !Q_stricmp( "deny", pEvent->GetString( "action" ) ) ) { Q_memset( &s_InviteInfo, 0, sizeof( s_InviteInfo ) ); s_bInviteSessionDelayedJoin = false; } return; } else if ( !Q_stricmp( "OnSteamOverlayCall::LobbyJoin", szEvent ) ) { #if !defined( _X360 ) && !defined( NO_STEAM ) && !defined( SWDS ) GameLobbyJoinRequested_t msg; msg.m_steamIDLobby.SetFromUint64( pEvent->GetUint64( "sessionid" ) ); msg.m_steamIDFriend.SetFromUint64( ~0ull ); g_MatchSteamInviteListener.Steam_OnGameLobbyJoinRequested( &msg ); #endif return; } else if ( !Q_stricmp( "OnMatchSessionUpdate", szEvent ) ) { KeyValues *pUpdate = pEvent->FindKey( "update" ); if ( pUpdate ) { const char *pAction = pUpdate->GetString( "options/action", "" ); if ( !Q_stricmp( "joinsession", pAction ) ) { KeyValues *pTeamMembers = pUpdate->FindKey( "teamMembers" ); if ( pTeamMembers ) { // Received console team match settings from host // Find what team we are on int numPlayers = pTeamMembers->GetInt( "numPlayers" ); int playerTeam = -1; int activeUer = XBX_GetPrimaryUserId(); IPlayerLocal *player = g_pPlayerManager->GetLocalPlayer( activeUer ); uint64 localPlayerId = player->GetXUID(); for ( int i = 0; i < numPlayers; i++ ) { KeyValues *pTeamPlayer = pTeamMembers->FindKey( CFmtStr( "player%d", i ) ); uint64 playerId = pTeamPlayer->GetUint64( "xuid" ); if ( playerId == localPlayerId ) { int team = pTeamPlayer->GetInt( "team" ); DevMsg( "Adding player %llu to team %d\n", playerId, team ); playerTeam = team; break; } } m_pTeamSessionSettings = pUpdate->MakeCopy(); m_pTeamSessionSettings->SetName( "settings "); // Delete the "teamMembers" key m_pTeamSessionSettings->RemoveSubKey( m_pTeamSessionSettings->FindKey( "teamMembers" ) ); // Add "conteam" value m_pTeamSessionSettings->SetInt( "conteam", playerTeam ); // Add the "sessionHostDataUnpacked" key KeyValues *pSessionHostDataSrc = pUpdate->FindKey( "sessionHostDataUnpacked" ); if ( pSessionHostDataSrc ) { KeyValues *pSessionHostDataDst = m_pTeamSessionSettings->CreateNewKey(); pSessionHostDataDst->SetName( "sessionHostDataUnpacked" ); pSessionHostDataSrc->CopySubkeys( pSessionHostDataDst ); } m_bJoinTeamSession = true; } } } } // // Delegate to the managers // if ( g_pPlayerManager ) g_pPlayerManager->OnEvent( pEvent ); if ( g_pServerManager ) g_pServerManager->OnEvent( pEvent ); if ( g_pDatacenter ) g_pDatacenter->OnEvent( pEvent ); if ( g_pDlcManager ) g_pDlcManager->OnEvent( pEvent ); // // Delegate to the title // if ( g_pIMatchTitleEventsSink ) g_pIMatchTitleEventsSink->OnEvent( pEvent ); // // Delegate to the session // if ( m_pMatchSession ) m_pMatchSession->OnEvent( pEvent ); } void CMatchFramework::SetCurrentMatchSession( IMatchSessionInternal *pNewMatchSession ) { m_pMatchSession = pNewMatchSession; } uint64 CMatchFramework::GetLastInviteFlags() { return g_uiLastInviteFlags; }