|
|
//===== Copyright � 1996-2009, Valve Corporation, All rights reserved. ======//
//
// Purpose:
//
//===========================================================================//
#include "mm_framework.h"
#include "fmtstr.h"
#include "netmessages_signon.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
//
// CMatchSessionOfflineCustom
//
// Implementation of an offline session
// that allows customization before the actual
// game commences (like playing commentary mode
// or playing single-player)
//
CMatchSessionOfflineCustom::CMatchSessionOfflineCustom( KeyValues *pSettings ) : m_pSettings( pSettings->MakeCopy() ), m_autodelete_pSettings( m_pSettings ), m_eState( STATE_INIT ), m_bExpectingServerReload( false ) { DevMsg( "Created CMatchSessionOfflineCustom:\n" ); KeyValuesDumpAsDevMsg( m_pSettings, 1 );
InitializeGameSettings(); }
CMatchSessionOfflineCustom::~CMatchSessionOfflineCustom() { DevMsg( "Destroying CMatchSessionOfflineCustom:\n" ); KeyValuesDumpAsDevMsg( m_pSettings, 1 ); }
KeyValues * CMatchSessionOfflineCustom::GetSessionSettings() { return m_pSettings; }
void CMatchSessionOfflineCustom::UpdateSessionSettings( KeyValues *pSettings ) { // Extend the update keys
g_pMMF->GetMatchTitleGameSettingsMgr()->ExtendGameSettingsUpdateKeys( m_pSettings, pSettings ); m_pSettings->MergeFrom( pSettings );
// Broadcast the update to everybody interested
MatchSession_BroadcastSessionSettingsUpdate( pSettings ); }
void CMatchSessionOfflineCustom::UpdateTeamProperties( KeyValues *pTeamProperties ) { }
void CMatchSessionOfflineCustom::Command( KeyValues *pCommand ) { char const *szCommand = pCommand->GetName();
if ( !Q_stricmp( "Start", szCommand ) && m_eState < STATE_RUNNING ) { m_eState = STATE_RUNNING;
OnGamePrepareLobbyForGame();
UpdateSessionSettings( KeyValues::AutoDeleteInline( KeyValues::FromString( "update", " update { " " server { " " server listen " " } " " } " ) ) );
g_pMatchFramework->GetEventsSubscription()->BroadcastEvent( new KeyValues( "OnProfilesWriteOpportunity", "reason", "sessionstart" ) ); bool bResult = g_pMatchFramework->GetMatchTitle()->StartServerMap( m_pSettings ); if ( !bResult ) { Warning( "Failed to start server map!\n" ); KeyValuesDumpAsDevMsg( m_pSettings, 1 ); Assert( 0 ); g_pMatchEventsSubscription->BroadcastEvent( new KeyValues( "OnMatchSessionUpdate", "state", "error", "error", "nomap" ) ); } Msg( "Succeeded in starting server map!\n" ); return; } if ( !Q_stricmp( "QueueConnect", szCommand ) ) { char const *szConnectAddress = pCommand->GetString( "adronline", "0.0.0.0" ); uint64 uiReservationId = pCommand->GetUint64( "reservationid" ); bool bAutoCloseSession = pCommand->GetBool( "auto_close_session" ); Assert( bAutoCloseSession ); if ( bAutoCloseSession ) { // Switch the state
m_eState = STATE_RUNNING;
MatchSession_PrepareClientForConnect( m_pSettings, uiReservationId );
// Close the session, potentially resetting a bunch of state
if ( bAutoCloseSession ) g_pMatchFramework->CloseSession();
// Determine reservation settings required
g_pMatchExtensions->GetINetSupport()->UpdateClientReservation( uiReservationId, 0ull );
// Issue the connect command
g_pMatchExtensions->GetIVEngineClient()->StartLoadingScreenForCommand( CFmtStr( "connect %s", szConnectAddress ) );
return; } }
//
// Let the title-specific matchmaking handle the command
//
CUtlVector< KeyValues * > arrPlayersUpdated; arrPlayersUpdated.SetCount( m_pSettings->GetInt( "members/numPlayers", 0 ) ); memset( arrPlayersUpdated.Base(), 0, arrPlayersUpdated.Count() * sizeof( KeyValues * ) );
g_pMMF->GetMatchTitleGameSettingsMgr()->ExecuteCommand( pCommand, GetSessionSystemData(), m_pSettings, arrPlayersUpdated.Base() );
// Now notify the framework about player updated
for ( int k = 0; k < arrPlayersUpdated.Count(); ++ k ) { if ( !arrPlayersUpdated[k] ) break;
// Notify the framework about player updated
KeyValues *kvEvent = new KeyValues( "OnPlayerUpdated" ); kvEvent->SetUint64( "xuid", arrPlayersUpdated[k]->GetUint64( "xuid" ) ); g_pMatchEventsSubscription->BroadcastEvent( kvEvent ); }
//
// Send the command as event for handling
//
KeyValues *pEvent = pCommand->MakeCopy(); pEvent->SetName( CFmtStr( "Command::%s", pCommand->GetName() ) ); g_pMatchEventsSubscription->BroadcastEvent( pEvent ); }
uint64 CMatchSessionOfflineCustom::GetSessionID() { return 0; }
void CMatchSessionOfflineCustom::Update() { switch ( m_eState ) { case STATE_INIT: m_eState = STATE_CONFIG; // Let everybody know that the session is now ready
g_pMatchEventsSubscription->BroadcastEvent( new KeyValues( "OnMatchSessionUpdate", "state", "ready", "transition", "offlineinit" ) ); break; } }
void CMatchSessionOfflineCustom::Destroy() { if ( m_eState == STATE_RUNNING ) { g_pMatchExtensions->GetIVEngineClient()->ExecuteClientCmd( "disconnect" );
g_pMatchFramework->GetEventsSubscription()->BroadcastEvent( new KeyValues( "OnProfilesWriteOpportunity", "reason", "sessionend" ) ); }
delete this; }
void CMatchSessionOfflineCustom::DebugPrint() { DevMsg( "CMatchSessionOfflineCustom [ state=%d ]\n", m_eState ); KeyValuesDumpAsDevMsg( m_pSettings, 1 ); }
void CMatchSessionOfflineCustom::OnEvent( KeyValues *pEvent ) { char const *szEvent = pEvent->GetName();
if ( !Q_stricmp( "OnEngineClientSignonStateChange", szEvent ) ) { int iOldState = pEvent->GetInt( "old", 0 ); int iNewState = pEvent->GetInt( "new", 0 );
if ( iOldState >= SIGNONSTATE_CONNECTED && iNewState < SIGNONSTATE_CONNECTED ) { // Disconnecting from server
DevMsg( "OnEngineClientSignonStateChange\n" ); if ( m_bExpectingServerReload ) { m_bExpectingServerReload = false; DevMsg( " session was expecting server reload...\n" ); return; } g_pMatchEventsSubscription->BroadcastEvent( new KeyValues( "mmF->CloseSession" ) ); return; } } else if ( !Q_stricmp( "OnEngineClientSignonStatePrepareChange", szEvent ) ) { char const *szReason = pEvent->GetString( "reason" ); if ( !Q_stricmp( "reload", szReason ) ) { Assert( !m_bExpectingServerReload ); m_bExpectingServerReload = true; return; } else if ( !Q_stricmp( "load", szReason ) ) { char const *szLevelName = g_pMatchExtensions->GetIVEngineClient()->GetLevelName(); if ( szLevelName && szLevelName[0] && g_pMatchExtensions->GetIVEngineClient()->IsConnected() ) { Assert( !m_bExpectingServerReload ); m_bExpectingServerReload = true; return; } } } else if ( !Q_stricmp( "OnEngineEndGame", szEvent ) ) { DevMsg( "OnEngineEndGame\n" ); // Issue the disconnect command
g_pMatchExtensions->GetIVEngineClient()->ExecuteClientCmd( "disconnect" ); g_pMatchEventsSubscription->BroadcastEvent( new KeyValues( "mmF->CloseSession" ) ); return; } }
void CMatchSessionOfflineCustom::InitializeGameSettings() { // Since the session can be created with a minimal amount of data available
// the session object is responsible for initializing the missing data to defaults
// or saved values or values from gamer progress/profile or etc...
if ( KeyValues *kv = m_pSettings->FindKey( "system", true ) ) { kv->SetString( "network", "offline" ); kv->SetString( "access", "public" ); }
if ( KeyValues *kv = m_pSettings->FindKey( "options", true ) ) { kv->SetString( "server", "listen" ); }
if ( KeyValues *pMembers = m_pSettings->FindKey( "members", true ) ) { pMembers->SetInt( "numMachines", 1 );
int numPlayers = 1; #ifdef _GAMECONSOLE
numPlayers = XBX_GetNumGameUsers(); #endif
pMembers->SetInt( "numPlayers", numPlayers ); pMembers->SetInt( "numSlots", numPlayers );
if ( KeyValues *pMachine = pMembers->FindKey( "machine0", true ) ) { IPlayerLocal *pPriPlayer = g_pPlayerManager->GetLocalPlayer( XBX_GetPrimaryUserId() );
pMachine->SetUint64( "id", ( pPriPlayer ? pPriPlayer->GetXUID() : INVALID_XUID ) ); pMachine->SetUint64( "flags", MatchSession_GetMachineFlags() ); pMachine->SetInt( "numPlayers", numPlayers ); pMachine->SetUint64( "dlcmask", g_pMatchFramework->GetMatchSystem()->GetDlcManager()->GetDataInfo()->GetUint64( "@info/installed" ) ); pMachine->SetString( "tuver", MatchSession_GetTuInstalledString() ); pMachine->SetInt( "ping", 0 );
for ( int k = 0; k < numPlayers; ++ k ) { if ( KeyValues *pPlayer = pMachine->FindKey( CFmtStr( "player%d", k ), true ) ) { int iController = 0; #ifdef _GAMECONSOLE
iController = XBX_GetUserId( k ); #endif
IPlayerLocal *player = g_pPlayerManager->GetLocalPlayer( iController ); if ( player ) { pPlayer->SetUint64( "xuid", player->GetXUID() ); pPlayer->SetString( "name", player->GetName() ); } } } } }
// Let the title extend the game settings
g_pMMF->GetMatchTitleGameSettingsMgr()->InitializeGameSettings( m_pSettings, "host" );
DevMsg( "CMatchSessionOfflineCustom::InitializeGameSettings adjusted settings:\n" ); KeyValuesDumpAsDevMsg( m_pSettings, 1 ); }
void CMatchSessionOfflineCustom::OnGamePrepareLobbyForGame() { // Remember which players will get updated
CUtlVector< KeyValues * > arrPlayersUpdated; arrPlayersUpdated.SetCount( m_pSettings->GetInt( "members/numPlayers", 0 ) ); memset( arrPlayersUpdated.Base(), 0, arrPlayersUpdated.Count() * sizeof( KeyValues * ) );
g_pMMF->GetMatchTitleGameSettingsMgr()->PrepareLobbyForGame( m_pSettings, arrPlayersUpdated.Base() );
// Notify the framework of the updates
for ( int k = 0; k < arrPlayersUpdated.Count(); ++ k ) { if ( !arrPlayersUpdated[k] ) break;
// Notify the framework about player updated
KeyValues *kvEvent = new KeyValues( "OnPlayerUpdated" ); kvEvent->SetUint64( "xuid", arrPlayersUpdated[k]->GetUint64( "xuid" ) ); g_pMatchEventsSubscription->BroadcastEvent( kvEvent ); }
// Let the title prepare for connect
MatchSession_PrepareClientForConnect( m_pSettings ); }
|