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.

378 lines
10 KiB

  1. //===== Copyright � 1996-2009, Valve Corporation, All rights reserved. ======//
  2. //
  3. // Purpose:
  4. //
  5. //===========================================================================//
  6. #include "mm_title.h"
  7. #include "mm_title_richpresence.h"
  8. #include "fmtstr.h"
  9. // memdbgon must be the last include file in a .cpp file!!!
  10. #include "tier0/memdbgon.h"
  11. CMatchTitle::CMatchTitle()
  12. {
  13. ;
  14. }
  15. CMatchTitle::~CMatchTitle()
  16. {
  17. ;
  18. }
  19. //
  20. // Init / shutdown
  21. //
  22. InitReturnVal_t CMatchTitle::Init()
  23. {
  24. if ( IGameEventManager2 *mgr = g_pMatchExtensions->GetIGameEventManager2() )
  25. {
  26. mgr->AddListener( this, "server_pre_shutdown", false );
  27. mgr->AddListener( this, "game_newmap", false );
  28. mgr->AddListener( this, "finale_start", false );
  29. mgr->AddListener( this, "round_start", false );
  30. mgr->AddListener( this, "round_end", false );
  31. mgr->AddListener( this, "difficulty_changed", false );
  32. }
  33. return INIT_OK;
  34. }
  35. void CMatchTitle::Shutdown()
  36. {
  37. if ( IGameEventManager2 *mgr = g_pMatchExtensions->GetIGameEventManager2() )
  38. {
  39. mgr->RemoveListener( this );
  40. }
  41. }
  42. //
  43. // Implementation
  44. //
  45. uint64 CMatchTitle::GetTitleID()
  46. {
  47. #ifdef _X360
  48. return 0xFFFFFFFFFFFFFFFF;
  49. #elif !defined( SWDS )
  50. static uint64 uiAppID = 0ull;
  51. if ( !uiAppID && steamapicontext && steamapicontext->SteamUtils() )
  52. {
  53. uiAppID = steamapicontext->SteamUtils()->GetAppID();
  54. }
  55. return uiAppID;
  56. #else
  57. return 0ull;
  58. #endif
  59. }
  60. uint64 CMatchTitle::GetTitleServiceID()
  61. {
  62. #ifdef _X360
  63. return 0x45410880ull; // Left 4 Dead 1 Service ID
  64. #else
  65. return 0ull;
  66. #endif
  67. }
  68. bool CMatchTitle::IsMultiplayer()
  69. {
  70. return true;
  71. }
  72. void CMatchTitle::PrepareNetStartupParams( void *pNetStartupParams )
  73. {
  74. #ifdef _X360
  75. XNetStartupParams &xnsp = *( XNetStartupParams * ) pNetStartupParams;
  76. xnsp.cfgQosDataLimitDiv4 = 64; // 256 bytes
  77. xnsp.cfgSockDefaultRecvBufsizeInK = 64; // Increase receive size for UDP to 64k
  78. xnsp.cfgSockDefaultSendBufsizeInK = 64; // Keep send size at 64k too
  79. int numGamePlayersMax = GetTotalNumPlayersSupported();
  80. int numConnections = 4 * ( numGamePlayersMax - 1 );
  81. // - the max number of connections to members of your game party
  82. // - the max number of connections to members of your social party
  83. // - the max number of connections to a pending game party (if you are joining a new one ).
  84. // - matchmakings client info structure also creates a connection per client for the lobby.
  85. // 1 - the main game session
  86. int numTotalConnections = 1 + numConnections;
  87. // 29 - total Connections (XNADDR/XNKID pairs) ,using 5 sessions (XNKID/XNKEY pairs).
  88. xnsp.cfgKeyRegMax = 16; //adding some extra room because of lazy dealocation of these pairs.
  89. xnsp.cfgSecRegMax = MAX( 64, numTotalConnections ); //adding some extra room because of lazy dealocation of these pairs.
  90. xnsp.cfgSockMaxDgramSockets = xnsp.cfgSecRegMax;
  91. xnsp.cfgSockMaxStreamSockets = xnsp.cfgSecRegMax;
  92. #endif
  93. }
  94. int CMatchTitle::GetTotalNumPlayersSupported()
  95. {
  96. return 1;
  97. }
  98. // Get a guest player name
  99. char const * CMatchTitle::GetGuestPlayerName( int iUserIndex )
  100. {
  101. if ( vgui::ILocalize *pLocalize = g_pMatchExtensions->GetILocalize() )
  102. {
  103. if ( wchar_t* wStringTableEntry = pLocalize->Find( "#L4D360UI_Character_Guest" ) )
  104. {
  105. static char szName[ MAX_PLAYER_NAME_LENGTH ] = {0};
  106. pLocalize->ConvertUnicodeToANSI( wStringTableEntry, szName, ARRAYSIZE( szName ) );
  107. return szName;
  108. }
  109. }
  110. return "";
  111. }
  112. // Sets up all necessary client-side convars and user info before
  113. // connecting to server
  114. void CMatchTitle::PrepareClientForConnect( KeyValues *pSettings )
  115. {
  116. #ifndef SWDS
  117. int numPlayers = 1;
  118. #ifdef _X360
  119. numPlayers = XBX_GetNumGameUsers();
  120. #endif
  121. //
  122. // Now we set the convars
  123. //
  124. for ( int k = 0; k < numPlayers; ++ k )
  125. {
  126. int iController = k;
  127. #ifdef _X360
  128. iController = XBX_GetUserId( k );
  129. #endif
  130. IPlayerLocal *pPlayerLocal = g_pPlayerManager->GetLocalPlayer( iController );
  131. if ( !pPlayerLocal )
  132. continue;
  133. // Set "name"
  134. static SplitScreenConVarRef s_cl_name( "name" );
  135. char const *szName = pPlayerLocal->GetName();
  136. s_cl_name.SetValue( k, szName );
  137. // Set "networkid_force"
  138. if ( IsX360() )
  139. {
  140. static SplitScreenConVarRef s_networkid_force( "networkid_force" );
  141. uint64 xid = pPlayerLocal->GetXUID();
  142. s_networkid_force.SetValue( k, CFmtStr( "%08X:%08X:", uint32( xid >> 32 ), uint32( xid ) ) );
  143. }
  144. }
  145. #endif
  146. }
  147. bool CMatchTitle::StartServerMap( KeyValues *pSettings )
  148. {
  149. int numPlayers = 1;
  150. #ifdef _X360
  151. numPlayers = XBX_GetNumGameUsers();
  152. #endif
  153. char const *szMap = pSettings->GetString( "game/bspname", NULL );
  154. if ( !szMap )
  155. return false;
  156. // Check that we have the server interface and that the map is valid
  157. if ( !g_pMatchExtensions->GetIVEngineServer() )
  158. return false;
  159. if ( !g_pMatchExtensions->GetIVEngineServer()->IsMapValid( szMap ) )
  160. return false;
  161. //
  162. // Prepare game dll reservation package
  163. //
  164. KeyValues *pGameDllReserve = g_pMatchFramework->GetMatchNetworkMsgController()->PackageGameDetailsForReservation( pSettings );
  165. KeyValues::AutoDelete autodelete( pGameDllReserve );
  166. pGameDllReserve->SetString( "map/mapcommand", ( numPlayers <= 1 ) ? "map" : "ss_map" );
  167. if ( !Q_stricmp( "commentary", pSettings->GetString( "options/play", "" ) ) )
  168. pGameDllReserve->SetString( "map/mapcommand", "map_commentary" );
  169. // Run map based off the faked reservation packet
  170. g_pMatchExtensions->GetIServerGameDLL()->ApplyGameSettings( pGameDllReserve );
  171. return true;
  172. }
  173. static KeyValues * GetCurrentMatchSessionSettings()
  174. {
  175. IMatchSession *pIMatchSession = g_pMatchFramework->GetMatchSession();
  176. return pIMatchSession ? pIMatchSession->GetSessionSettings() : NULL;
  177. }
  178. void CMatchTitle::OnEvent( KeyValues *pEvent )
  179. {
  180. char const *szEvent = pEvent->GetName();
  181. if ( !Q_stricmp( "OnPlayerRemoved", szEvent ) ||
  182. !Q_stricmp( "OnPlayerUpdated", szEvent ) )
  183. {
  184. MM_Title_RichPresence_PlayersChanged( GetCurrentMatchSessionSettings() );
  185. }
  186. else if ( !Q_stricmp( "OnMatchSessionUpdate", szEvent ) )
  187. {
  188. if ( !Q_stricmp( pEvent->GetString( "state" ), "updated" ) )
  189. {
  190. if ( KeyValues *kvUpdate = pEvent->FindKey( "update" ) )
  191. {
  192. MM_Title_RichPresence_Update( GetCurrentMatchSessionSettings(), kvUpdate );
  193. }
  194. }
  195. else if ( !Q_stricmp( pEvent->GetString( "state" ), "created" ) ||
  196. !Q_stricmp( pEvent->GetString( "state" ), "ready" ) )
  197. {
  198. MM_Title_RichPresence_Update( GetCurrentMatchSessionSettings(), NULL );
  199. }
  200. else if ( !Q_stricmp( pEvent->GetString( "state" ), "closed" ) )
  201. {
  202. MM_Title_RichPresence_Update( NULL, NULL );
  203. }
  204. }
  205. else if ( !Q_stricmp( "Client::CmdKeyValues", szEvent ) )
  206. {
  207. KeyValues *pCmd = pEvent->GetFirstTrueSubKey();
  208. if ( !pCmd )
  209. return;
  210. char const *szCmd = pCmd->GetName();
  211. if ( !Q_stricmp( "swapteam", szCmd ) )
  212. {
  213. if ( IMatchSession *pIMatchSession = g_pMatchFramework->GetMatchSession() )
  214. {
  215. KeyValues *pRequest = new KeyValues( "Game::Team" );
  216. KeyValues::AutoDelete autodelete( pRequest );
  217. // If a player is on infected team, then the avatar is infected
  218. char const *szTeam = pCmd->GetString( "team" );
  219. // Parse out the team and avatar info
  220. pRequest->SetString( "run", "host" );
  221. pRequest->SetUint64( "xuid", pCmd->GetUint64( "xuid" ) );
  222. pRequest->SetString( "team", szTeam );
  223. pIMatchSession->Command( pRequest );
  224. }
  225. }
  226. }
  227. }
  228. //
  229. //
  230. //
  231. int CMatchTitle::GetEventDebugID( void )
  232. {
  233. return EVENT_DEBUG_ID_INIT;
  234. }
  235. void CMatchTitle::FireGameEvent( IGameEvent *pIGameEvent )
  236. {
  237. // Check if the current match session is on an active game server
  238. IMatchSession *pMatchSession = g_pMatchFramework->GetMatchSession();
  239. if ( !pMatchSession )
  240. return;
  241. KeyValues *pSessionSettings = pMatchSession->GetSessionSettings();
  242. char const *szGameServer = pSessionSettings->GetString( "server/server", "" );
  243. char const *szSystemLock = pSessionSettings->GetString( "system/lock", "" );
  244. if ( ( !szGameServer || !*szGameServer ) &&
  245. ( !szSystemLock || !*szSystemLock ) )
  246. return;
  247. // Also don't run on the client when there's a host
  248. char const *szSessionType = pMatchSession->GetSessionSystemData()->GetString( "type", NULL );
  249. if ( szSessionType && !Q_stricmp( szSessionType, "client" ) )
  250. return;
  251. // Parse the game event
  252. char const *szGameEvent = pIGameEvent->GetName();
  253. if ( !szGameEvent || !*szGameEvent )
  254. return;
  255. if ( !Q_stricmp( "round_start", szGameEvent ) )
  256. {
  257. pMatchSession->UpdateSessionSettings( KeyValues::AutoDeleteInline( KeyValues::FromString(
  258. "update",
  259. " update { "
  260. " game { "
  261. " state game "
  262. " } "
  263. " } "
  264. ) ) );
  265. }
  266. else if ( !Q_stricmp( "finale_start", szGameEvent ) )
  267. {
  268. pMatchSession->UpdateSessionSettings( KeyValues::AutoDeleteInline( KeyValues::FromString(
  269. "update",
  270. " update { "
  271. " game { "
  272. " state finale "
  273. " } "
  274. " } "
  275. ) ) );
  276. }
  277. else if ( !Q_stricmp( "game_newmap", szGameEvent ) )
  278. {
  279. KeyValues *kvUpdate = KeyValues::FromString(
  280. "update",
  281. " update { "
  282. " game { "
  283. " state game "
  284. " } "
  285. " } "
  286. );
  287. KeyValues::AutoDelete autodelete( kvUpdate );
  288. pMatchSession->UpdateSessionSettings( kvUpdate );
  289. }
  290. else if ( !Q_stricmp( "difficulty_changed", szGameEvent ) )
  291. {
  292. char const *szDifficulty = pIGameEvent->GetString( "strDifficulty", "normal" );
  293. KeyValues *kvUpdate = KeyValues::FromString(
  294. "update",
  295. " update { "
  296. " game { "
  297. " difficulty = "
  298. " } "
  299. " } "
  300. );
  301. KeyValues::AutoDelete autodelete( kvUpdate );
  302. kvUpdate->SetString( "update/game/difficulty", szDifficulty );
  303. pMatchSession->UpdateSessionSettings( kvUpdate );
  304. }
  305. else if ( !Q_stricmp( "server_pre_shutdown", szGameEvent ) )
  306. {
  307. char const *szReason = pIGameEvent->GetString( "reason", "quit" );
  308. if ( !Q_stricmp( szReason, "quit" ) )
  309. {
  310. DevMsg( "Received server_pre_shutdown notification - server is shutting down...\n" );
  311. // Transform the server shutdown event into game end event
  312. g_pMatchFramework->GetEventsSubscription()->BroadcastEvent( new KeyValues(
  313. "OnEngineDisconnectReason", "reason", "Server shutting down"
  314. ) );
  315. }
  316. }
  317. }