csgo-2018-source/matchmaking/mm_framework.cpp

961 lines
25 KiB
C++
Raw Permalink Normal View History

2021-07-25 12:11:47 +08:00
//===== Copyright <20> 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;
}