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.

332 lines
9.8 KiB

  1. //===== Copyright � 1996-2009, Valve Corporation, All rights reserved. ======//
  2. //
  3. // Purpose:
  4. //
  5. //===========================================================================//
  6. #include "mm_framework.h"
  7. #include "fmtstr.h"
  8. #include "netmessages_signon.h"
  9. // memdbgon must be the last include file in a .cpp file!!!
  10. #include "tier0/memdbgon.h"
  11. //
  12. // CMatchSessionOfflineCustom
  13. //
  14. // Implementation of an offline session
  15. // that allows customization before the actual
  16. // game commences (like playing commentary mode
  17. // or playing single-player)
  18. //
  19. CMatchSessionOfflineCustom::CMatchSessionOfflineCustom( KeyValues *pSettings ) :
  20. m_pSettings( pSettings->MakeCopy() ),
  21. m_autodelete_pSettings( m_pSettings ),
  22. m_eState( STATE_INIT ),
  23. m_bExpectingServerReload( false )
  24. {
  25. DevMsg( "Created CMatchSessionOfflineCustom:\n" );
  26. KeyValuesDumpAsDevMsg( m_pSettings, 1 );
  27. InitializeGameSettings();
  28. }
  29. CMatchSessionOfflineCustom::~CMatchSessionOfflineCustom()
  30. {
  31. DevMsg( "Destroying CMatchSessionOfflineCustom:\n" );
  32. KeyValuesDumpAsDevMsg( m_pSettings, 1 );
  33. }
  34. KeyValues * CMatchSessionOfflineCustom::GetSessionSettings()
  35. {
  36. return m_pSettings;
  37. }
  38. void CMatchSessionOfflineCustom::UpdateSessionSettings( KeyValues *pSettings )
  39. {
  40. // Extend the update keys
  41. g_pMMF->GetMatchTitleGameSettingsMgr()->ExtendGameSettingsUpdateKeys( m_pSettings, pSettings );
  42. m_pSettings->MergeFrom( pSettings );
  43. // Broadcast the update to everybody interested
  44. MatchSession_BroadcastSessionSettingsUpdate( pSettings );
  45. }
  46. void CMatchSessionOfflineCustom::UpdateTeamProperties( KeyValues *pTeamProperties )
  47. {
  48. }
  49. void CMatchSessionOfflineCustom::Command( KeyValues *pCommand )
  50. {
  51. char const *szCommand = pCommand->GetName();
  52. if ( !Q_stricmp( "Start", szCommand ) && m_eState < STATE_RUNNING )
  53. {
  54. m_eState = STATE_RUNNING;
  55. OnGamePrepareLobbyForGame();
  56. UpdateSessionSettings( KeyValues::AutoDeleteInline( KeyValues::FromString(
  57. "update",
  58. " update { "
  59. " server { "
  60. " server listen "
  61. " } "
  62. " } "
  63. ) ) );
  64. g_pMatchFramework->GetEventsSubscription()->BroadcastEvent( new KeyValues(
  65. "OnProfilesWriteOpportunity", "reason", "sessionstart"
  66. ) );
  67. bool bResult = g_pMatchFramework->GetMatchTitle()->StartServerMap( m_pSettings );
  68. if ( !bResult )
  69. {
  70. Warning( "Failed to start server map!\n" );
  71. KeyValuesDumpAsDevMsg( m_pSettings, 1 );
  72. Assert( 0 );
  73. g_pMatchEventsSubscription->BroadcastEvent( new KeyValues( "OnMatchSessionUpdate", "state", "error", "error", "nomap" ) );
  74. }
  75. Msg( "Succeeded in starting server map!\n" );
  76. return;
  77. }
  78. if ( !Q_stricmp( "QueueConnect", szCommand ) )
  79. {
  80. char const *szConnectAddress = pCommand->GetString( "adronline", "0.0.0.0" );
  81. uint64 uiReservationId = pCommand->GetUint64( "reservationid" );
  82. bool bAutoCloseSession = pCommand->GetBool( "auto_close_session" );
  83. Assert( bAutoCloseSession );
  84. if ( bAutoCloseSession )
  85. {
  86. // Switch the state
  87. m_eState = STATE_RUNNING;
  88. MatchSession_PrepareClientForConnect( m_pSettings, uiReservationId );
  89. // Close the session, potentially resetting a bunch of state
  90. if ( bAutoCloseSession )
  91. g_pMatchFramework->CloseSession();
  92. // Determine reservation settings required
  93. g_pMatchExtensions->GetINetSupport()->UpdateClientReservation( uiReservationId, 0ull );
  94. // Issue the connect command
  95. g_pMatchExtensions->GetIVEngineClient()->StartLoadingScreenForCommand( CFmtStr( "connect %s", szConnectAddress ) );
  96. return;
  97. }
  98. }
  99. //
  100. // Let the title-specific matchmaking handle the command
  101. //
  102. CUtlVector< KeyValues * > arrPlayersUpdated;
  103. arrPlayersUpdated.SetCount( m_pSettings->GetInt( "members/numPlayers", 0 ) );
  104. memset( arrPlayersUpdated.Base(), 0, arrPlayersUpdated.Count() * sizeof( KeyValues * ) );
  105. g_pMMF->GetMatchTitleGameSettingsMgr()->ExecuteCommand( pCommand, GetSessionSystemData(), m_pSettings, arrPlayersUpdated.Base() );
  106. // Now notify the framework about player updated
  107. for ( int k = 0; k < arrPlayersUpdated.Count(); ++ k )
  108. {
  109. if ( !arrPlayersUpdated[k] )
  110. break;
  111. // Notify the framework about player updated
  112. KeyValues *kvEvent = new KeyValues( "OnPlayerUpdated" );
  113. kvEvent->SetUint64( "xuid", arrPlayersUpdated[k]->GetUint64( "xuid" ) );
  114. g_pMatchEventsSubscription->BroadcastEvent( kvEvent );
  115. }
  116. //
  117. // Send the command as event for handling
  118. //
  119. KeyValues *pEvent = pCommand->MakeCopy();
  120. pEvent->SetName( CFmtStr( "Command::%s", pCommand->GetName() ) );
  121. g_pMatchEventsSubscription->BroadcastEvent( pEvent );
  122. }
  123. uint64 CMatchSessionOfflineCustom::GetSessionID()
  124. {
  125. return 0;
  126. }
  127. void CMatchSessionOfflineCustom::Update()
  128. {
  129. switch ( m_eState )
  130. {
  131. case STATE_INIT:
  132. m_eState = STATE_CONFIG;
  133. // Let everybody know that the session is now ready
  134. g_pMatchEventsSubscription->BroadcastEvent( new KeyValues( "OnMatchSessionUpdate", "state", "ready", "transition", "offlineinit" ) );
  135. break;
  136. }
  137. }
  138. void CMatchSessionOfflineCustom::Destroy()
  139. {
  140. if ( m_eState == STATE_RUNNING )
  141. {
  142. g_pMatchExtensions->GetIVEngineClient()->ExecuteClientCmd( "disconnect" );
  143. g_pMatchFramework->GetEventsSubscription()->BroadcastEvent( new KeyValues(
  144. "OnProfilesWriteOpportunity", "reason", "sessionend"
  145. ) );
  146. }
  147. delete this;
  148. }
  149. void CMatchSessionOfflineCustom::DebugPrint()
  150. {
  151. DevMsg( "CMatchSessionOfflineCustom [ state=%d ]\n", m_eState );
  152. KeyValuesDumpAsDevMsg( m_pSettings, 1 );
  153. }
  154. void CMatchSessionOfflineCustom::OnEvent( KeyValues *pEvent )
  155. {
  156. char const *szEvent = pEvent->GetName();
  157. if ( !Q_stricmp( "OnEngineClientSignonStateChange", szEvent ) )
  158. {
  159. int iOldState = pEvent->GetInt( "old", 0 );
  160. int iNewState = pEvent->GetInt( "new", 0 );
  161. if ( iOldState >= SIGNONSTATE_CONNECTED &&
  162. iNewState < SIGNONSTATE_CONNECTED )
  163. {
  164. // Disconnecting from server
  165. DevMsg( "OnEngineClientSignonStateChange\n" );
  166. if ( m_bExpectingServerReload )
  167. {
  168. m_bExpectingServerReload = false;
  169. DevMsg( " session was expecting server reload...\n" );
  170. return;
  171. }
  172. g_pMatchEventsSubscription->BroadcastEvent( new KeyValues( "mmF->CloseSession" ) );
  173. return;
  174. }
  175. }
  176. else if ( !Q_stricmp( "OnEngineClientSignonStatePrepareChange", szEvent ) )
  177. {
  178. char const *szReason = pEvent->GetString( "reason" );
  179. if ( !Q_stricmp( "reload", szReason ) )
  180. {
  181. Assert( !m_bExpectingServerReload );
  182. m_bExpectingServerReload = true;
  183. return;
  184. }
  185. else if ( !Q_stricmp( "load", szReason ) )
  186. {
  187. char const *szLevelName = g_pMatchExtensions->GetIVEngineClient()->GetLevelName();
  188. if ( szLevelName && szLevelName[0] && g_pMatchExtensions->GetIVEngineClient()->IsConnected() )
  189. {
  190. Assert( !m_bExpectingServerReload );
  191. m_bExpectingServerReload = true;
  192. return;
  193. }
  194. }
  195. }
  196. else if ( !Q_stricmp( "OnEngineEndGame", szEvent ) )
  197. {
  198. DevMsg( "OnEngineEndGame\n" );
  199. // Issue the disconnect command
  200. g_pMatchExtensions->GetIVEngineClient()->ExecuteClientCmd( "disconnect" );
  201. g_pMatchEventsSubscription->BroadcastEvent( new KeyValues( "mmF->CloseSession" ) );
  202. return;
  203. }
  204. }
  205. void CMatchSessionOfflineCustom::InitializeGameSettings()
  206. {
  207. // Since the session can be created with a minimal amount of data available
  208. // the session object is responsible for initializing the missing data to defaults
  209. // or saved values or values from gamer progress/profile or etc...
  210. if ( KeyValues *kv = m_pSettings->FindKey( "system", true ) )
  211. {
  212. kv->SetString( "network", "offline" );
  213. kv->SetString( "access", "public" );
  214. }
  215. if ( KeyValues *kv = m_pSettings->FindKey( "options", true ) )
  216. {
  217. kv->SetString( "server", "listen" );
  218. }
  219. if ( KeyValues *pMembers = m_pSettings->FindKey( "members", true ) )
  220. {
  221. pMembers->SetInt( "numMachines", 1 );
  222. int numPlayers = 1;
  223. #ifdef _GAMECONSOLE
  224. numPlayers = XBX_GetNumGameUsers();
  225. #endif
  226. pMembers->SetInt( "numPlayers", numPlayers );
  227. pMembers->SetInt( "numSlots", numPlayers );
  228. if ( KeyValues *pMachine = pMembers->FindKey( "machine0", true ) )
  229. {
  230. IPlayerLocal *pPriPlayer = g_pPlayerManager->GetLocalPlayer( XBX_GetPrimaryUserId() );
  231. pMachine->SetUint64( "id", ( pPriPlayer ? pPriPlayer->GetXUID() : INVALID_XUID ) );
  232. pMachine->SetUint64( "flags", MatchSession_GetMachineFlags() );
  233. pMachine->SetInt( "numPlayers", numPlayers );
  234. pMachine->SetUint64( "dlcmask", g_pMatchFramework->GetMatchSystem()->GetDlcManager()->GetDataInfo()->GetUint64( "@info/installed" ) );
  235. pMachine->SetString( "tuver", MatchSession_GetTuInstalledString() );
  236. pMachine->SetInt( "ping", 0 );
  237. for ( int k = 0; k < numPlayers; ++ k )
  238. {
  239. if ( KeyValues *pPlayer = pMachine->FindKey( CFmtStr( "player%d", k ), true ) )
  240. {
  241. int iController = 0;
  242. #ifdef _GAMECONSOLE
  243. iController = XBX_GetUserId( k );
  244. #endif
  245. IPlayerLocal *player = g_pPlayerManager->GetLocalPlayer( iController );
  246. if ( player )
  247. {
  248. pPlayer->SetUint64( "xuid", player->GetXUID() );
  249. pPlayer->SetString( "name", player->GetName() );
  250. }
  251. }
  252. }
  253. }
  254. }
  255. // Let the title extend the game settings
  256. g_pMMF->GetMatchTitleGameSettingsMgr()->InitializeGameSettings( m_pSettings, "host" );
  257. DevMsg( "CMatchSessionOfflineCustom::InitializeGameSettings adjusted settings:\n" );
  258. KeyValuesDumpAsDevMsg( m_pSettings, 1 );
  259. }
  260. void CMatchSessionOfflineCustom::OnGamePrepareLobbyForGame()
  261. {
  262. // Remember which players will get updated
  263. CUtlVector< KeyValues * > arrPlayersUpdated;
  264. arrPlayersUpdated.SetCount( m_pSettings->GetInt( "members/numPlayers", 0 ) );
  265. memset( arrPlayersUpdated.Base(), 0, arrPlayersUpdated.Count() * sizeof( KeyValues * ) );
  266. g_pMMF->GetMatchTitleGameSettingsMgr()->PrepareLobbyForGame( m_pSettings, arrPlayersUpdated.Base() );
  267. // Notify the framework of the updates
  268. for ( int k = 0; k < arrPlayersUpdated.Count(); ++ k )
  269. {
  270. if ( !arrPlayersUpdated[k] )
  271. break;
  272. // Notify the framework about player updated
  273. KeyValues *kvEvent = new KeyValues( "OnPlayerUpdated" );
  274. kvEvent->SetUint64( "xuid", arrPlayersUpdated[k]->GetUint64( "xuid" ) );
  275. g_pMatchEventsSubscription->BroadcastEvent( kvEvent );
  276. }
  277. // Let the title prepare for connect
  278. MatchSession_PrepareClientForConnect( m_pSettings );
  279. }