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.

372 lines
12 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 "vstdlib/random.h"
  9. #include "fmtstr.h"
  10. // memdbgon must be the last include file in a .cpp file!!!
  11. #include "tier0/memdbgon.h"
  12. class CMatchTitleGameSettingsMgr : public IMatchTitleGameSettingsMgr
  13. {
  14. public:
  15. // Extends server game details
  16. virtual void ExtendServerDetails( KeyValues *pDetails, KeyValues *pRequest );
  17. // Adds the essential part of game details to be broadcast
  18. virtual void ExtendLobbyDetailsTemplate( KeyValues *pDetails, char const *szReason, KeyValues *pFullSettings );
  19. // Extends game settings update packet for lobby transition,
  20. // either due to a migration or due to an endgame condition
  21. virtual void ExtendGameSettingsForLobbyTransition( KeyValues *pSettings, KeyValues *pSettingsUpdate, bool bEndGame );
  22. // Rolls up game details for matches grouping
  23. virtual KeyValues * RollupGameDetails( KeyValues *pDetails, KeyValues *pRollup, KeyValues *pQuery );
  24. // Defines session search keys for matchmaking
  25. virtual KeyValues * DefineSessionSearchKeys( KeyValues *pSettings );
  26. // Defines dedicated server search key
  27. virtual KeyValues * DefineDedicatedSearchKeys( KeyValues *pSettings );
  28. // Initializes full game settings from potentially abbreviated game settings
  29. virtual void InitializeGameSettings( KeyValues *pSettings );
  30. // Extends game settings update packet before it gets merged with
  31. // session settings and networked to remote clients
  32. virtual void ExtendGameSettingsUpdateKeys( KeyValues *pSettings, KeyValues *pUpdateDeleteKeys );
  33. // Prepares system for session creation
  34. virtual KeyValues * PrepareForSessionCreate( KeyValues *pSettings );
  35. // Executes the command on the session settings, this function on host
  36. // is allowed to modify Members/Game subkeys and has to fill in modified players KeyValues
  37. // When running on a remote client "ppPlayersUpdated" is NULL and players cannot
  38. // be modified
  39. virtual void ExecuteCommand( KeyValues *pCommand, KeyValues *pSessionSystemData, KeyValues *pSettings, KeyValues **ppPlayersUpdated );
  40. // Prepares the lobby for game or adjust settings of new players who
  41. // join a game in progress, this function is allowed to modify
  42. // Members/Game subkeys and has to fill in modified players KeyValues
  43. virtual void PrepareLobbyForGame( KeyValues *pSettings, KeyValues **ppPlayersUpdated );
  44. // Prepares the host team lobby for game adjusting the game settings
  45. // this function is allowed to prepare modification package to update
  46. // Game subkeys.
  47. // Returns the update/delete package to be applied to session settings
  48. // and pushed to dependent two sesssion of the two teams.
  49. virtual KeyValues * PrepareTeamLinkForGame( KeyValues *pSettingsLocal, KeyValues *pSettingsRemote );
  50. };
  51. CMatchTitleGameSettingsMgr g_MatchTitleGameSettingsMgr;
  52. IMatchTitleGameSettingsMgr *g_pIMatchTitleGameSettingsMgr = &g_MatchTitleGameSettingsMgr;
  53. //
  54. // Implementation of CMatchTitleGameSettingsMgr
  55. //
  56. // Extends server game details
  57. void CMatchTitleGameSettingsMgr::ExtendServerDetails( KeyValues *pDetails, KeyValues *pRequest )
  58. {
  59. // Query server info
  60. INetSupport::ServerInfo_t si;
  61. g_pMatchExtensions->GetINetSupport()->GetServerInfo( &si );
  62. // Server is always in game
  63. pDetails->SetString( "game/state", "game" );
  64. //
  65. // Determine map info
  66. //
  67. {
  68. pDetails->SetString( "game/bspname", CFmtStr( "%s", si.m_szMapName ) );
  69. }
  70. }
  71. // Adds the essential part of game details to be broadcast
  72. void CMatchTitleGameSettingsMgr::ExtendLobbyDetailsTemplate( KeyValues *pDetails, char const *szReason, KeyValues *pFullSettings )
  73. {
  74. static KeyValues *pkvExt = KeyValues::FromString(
  75. "settings",
  76. " game { "
  77. " bspname #empty# "
  78. " } "
  79. );
  80. pDetails->MergeFrom( pkvExt, KeyValues::MERGE_KV_UPDATE );
  81. }
  82. // Extends game settings update packet for lobby transition,
  83. // either due to a migration or due to an endgame condition
  84. void CMatchTitleGameSettingsMgr::ExtendGameSettingsForLobbyTransition( KeyValues *pSettings, KeyValues *pSettingsUpdate, bool bEndGame )
  85. {
  86. pSettingsUpdate->SetString( "game/state", "lobby" );
  87. }
  88. // Rolls up game details for matches grouping
  89. KeyValues * CMatchTitleGameSettingsMgr::RollupGameDetails( KeyValues *pDetails, KeyValues *pRollup, KeyValues *pQuery )
  90. {
  91. return NULL;
  92. }
  93. // Defines dedicated server search key
  94. KeyValues * CMatchTitleGameSettingsMgr::DefineDedicatedSearchKeys( KeyValues *pSettings )
  95. {
  96. if ( IsPC() )
  97. {
  98. static ConVarRef sv_search_key( "sv_search_key" );
  99. KeyValues *pKeys = new KeyValues( "SearchKeys" );
  100. pKeys->SetString( "gametype", CFmtStr( "%s,sv_search_key_%s%d",
  101. "empty",
  102. sv_search_key.GetString(),
  103. g_pMatchExtensions->GetINetSupport()->GetEngineBuildNumber() ) );
  104. return pKeys;
  105. }
  106. else
  107. {
  108. return NULL;
  109. }
  110. }
  111. // Defines session search keys for matchmaking
  112. KeyValues * CMatchTitleGameSettingsMgr::DefineSessionSearchKeys( KeyValues *pSettings )
  113. {
  114. MEM_ALLOC_CREDIT();
  115. KeyValues *pResult = new KeyValues( "SessionSearch" );
  116. pResult->SetInt( "numPlayers", pSettings->GetInt( "members/numPlayers", XBX_GetNumGameUsers() ) );
  117. /*
  118. char const *szGameMode = pSettings->GetString( "game/mode", "" );
  119. if ( IsX360() )
  120. {
  121. if ( char const *szValue = pSettings->GetString( "game/mode", NULL ) )
  122. {
  123. static ContextValue_t values[] = {
  124. { "versus", SESSION_MATCH_QUERY_PUBLIC_STATE_C___SORT___CHAPTER },
  125. { "teamversus", SESSION_MATCH_QUERY_TEAM_STATE_C_CHAPTER },
  126. { "scavenge", SESSION_MATCH_QUERY_PUBLIC_STATE_C_CHAPTER___SORT___ROUNDS },
  127. { "teamscavenge", SESSION_MATCH_QUERY_TEAM_STATE_C_CHAPTER_ROUNDS },
  128. { "survival", SESSION_MATCH_QUERY_PUBLIC_STATE_C_CHAPTER },
  129. { "coop", SESSION_MATCH_QUERY_PUBLIC_STATE_C_DIFF___SORT___CHAPTER },
  130. { "realism", SESSION_MATCH_QUERY_PUBLIC_STATE_C_DIFF___SORT___CHAPTER },
  131. { NULL, 0xFFFF },
  132. };
  133. pResult->SetInt( "rule", values->ScanValues( szValue ) );
  134. }
  135. // Set the matchmaking version
  136. pResult->SetInt( CFmtStr( "Properties/%d", PROPERTY_MMVERSION ), mm_matchmaking_version.GetInt() );
  137. #ifdef _X360
  138. // Set the installed DLCs masks
  139. uint64 uiDlcsMask = MatchSession_GetDlcInstalledMask();
  140. for ( int k = 1; k <= mm_matchmaking_dlcsquery.GetInt(); ++ k )
  141. {
  142. pResult->SetInt( CFmtStr( "Properties/%d", PROPERTY_MMVERSION + k ), !!( uiDlcsMask & ( 1ull << k ) ) );
  143. }
  144. pResult->SetInt( "dlc1", PROPERTY_MMVERSION + 1 );
  145. pResult->SetInt( "dlcN", PROPERTY_MMVERSION + mm_matchmaking_dlcsquery.GetInt() );
  146. #endif
  147. // X_CONTEXT_GAME_TYPE
  148. pResult->SetInt( CFmtStr( "Contexts/%d", X_CONTEXT_GAME_TYPE ), X_CONTEXT_GAME_TYPE_STANDARD );
  149. // X_CONTEXT_GAME_MODE
  150. if ( char const *szValue = pSettings->GetString( "game/mode", NULL ) )
  151. {
  152. pResult->SetInt( CFmtStr( "Contexts/%d", X_CONTEXT_GAME_MODE ), g_pcv_CONTEXT_GAME_MODE->ScanValues( szValue ) );
  153. }
  154. if ( char const *szValue = pSettings->GetString( "game/state", NULL ) )
  155. {
  156. pResult->SetInt( CFmtStr( "Contexts/%d", CONTEXT_STATE ), g_pcv_CONTEXT_STATE->ScanValues( szValue ) );
  157. }
  158. if ( char const *szValue = pSettings->GetString( "game/difficulty", NULL ) )
  159. {
  160. if ( !Q_stricmp( "coop", szGameMode ) || !Q_stricmp( "realism", szGameMode ) )
  161. {
  162. pResult->SetInt( CFmtStr( "Contexts/%d", CONTEXT_DIFFICULTY ), g_pcv_CONTEXT_DIFFICULTY->ScanValues( szValue ) );
  163. }
  164. }
  165. if ( int val = pSettings->GetInt( "game/maxrounds" ) )
  166. {
  167. if ( !Q_stricmp( "scavenge", szGameMode ) || !Q_stricmp( "teamscavenge", szGameMode ) )
  168. {
  169. pResult->SetInt( CFmtStr( "Properties/%d", PROPERTY_MAXROUNDS ), val );
  170. }
  171. }
  172. char const *szCampaign = pSettings->GetString( "game/campaign" );
  173. if ( *szCampaign )
  174. {
  175. DWORD dwContext = CONTEXT_CAMPAIGN_UNKNOWN;
  176. if ( KeyValues *pAllMissions = g_pMatchExtL4D->GetAllMissions() )
  177. {
  178. if ( KeyValues *pMission = pAllMissions->FindKey( szCampaign ) )
  179. {
  180. dwContext = pMission->GetInt( "x360ctx", dwContext );
  181. }
  182. }
  183. if ( dwContext != CONTEXT_CAMPAIGN_UNKNOWN )
  184. {
  185. pResult->SetInt( CFmtStr( "Contexts/%d", CONTEXT_CAMPAIGN ), dwContext );
  186. }
  187. }
  188. if ( int val = pSettings->GetInt( "game/chapter" ) )
  189. {
  190. pResult->SetInt( CFmtStr( "Properties/%d", PROPERTY_CHAPTER ), val );
  191. }
  192. }
  193. else
  194. */
  195. {
  196. if ( char const *szValue = pSettings->GetString( "game/bspname", NULL ) )
  197. {
  198. pResult->SetString( "Filter=/game:bspname", szValue );
  199. }
  200. }
  201. return pResult;
  202. }
  203. // Initializes full game settings from potentially abbreviated game settings
  204. void CMatchTitleGameSettingsMgr::InitializeGameSettings( KeyValues *pSettings )
  205. {
  206. char const *szNetwork = pSettings->GetString( "system/network", "LIVE" );
  207. pSettings->SetString( "game/state", "lobby" );
  208. if ( KeyValues *kv = pSettings->FindKey( "Options", true ) )
  209. {
  210. kv->SetString( "server", "listen" );
  211. }
  212. // Offline games don't need slots and player setup
  213. if ( !Q_stricmp( "offline", szNetwork ) )
  214. return;
  215. //
  216. // Set the number of slots
  217. //
  218. int numSlots = 10;
  219. pSettings->SetInt( "members/numSlots", numSlots );
  220. }
  221. // Extends game settings update packet before it gets merged with
  222. // session settings and networked to remote clients
  223. void CMatchTitleGameSettingsMgr::ExtendGameSettingsUpdateKeys( KeyValues *pSettings, KeyValues *pUpdateDeleteKeys )
  224. {
  225. }
  226. // Prepares system for session creation
  227. KeyValues * CMatchTitleGameSettingsMgr::PrepareForSessionCreate( KeyValues *pSettings )
  228. {
  229. return MM_Title_RichPresence_PrepareForSessionCreate( pSettings );
  230. }
  231. // Prepares the lobby for game or adjust settings of new players who
  232. // join a game in progress, this function is allowed to modify
  233. // Members/Game subkeys and has to write modified players XUIDs
  234. void CMatchTitleGameSettingsMgr::PrepareLobbyForGame( KeyValues *pSettings, KeyValues **ppPlayersUpdated )
  235. {
  236. // set player avatar/teams, etc
  237. }
  238. // Prepares the host team lobby for game adjusting the game settings
  239. // this function is allowed to prepare modification package to update
  240. // Game subkeys.
  241. // Returns the update/delete package to be applied to session settings
  242. // and pushed to dependent two sesssion of the two teams.
  243. KeyValues * CMatchTitleGameSettingsMgr::PrepareTeamLinkForGame( KeyValues *pSettingsLocal, KeyValues *pSettingsRemote )
  244. {
  245. return NULL;
  246. }
  247. static void OnRunCommand_TeamChange( KeyValues *pCommand, KeyValues *pSettings, KeyValues **ppPlayersUpdated )
  248. {
  249. MEM_ALLOC_CREDIT();
  250. XUID xuid = pCommand->GetUint64( "xuid" );
  251. char const *szTeam = pCommand->GetString( "team", "" );
  252. KeyValues *pMembers = pSettings->FindKey( "members" );
  253. if ( !pMembers )
  254. return;
  255. // Find the avatar that is going to be updated
  256. KeyValues *pPlayer = SessionMembersFindPlayer( pSettings, xuid );
  257. if ( !pPlayer )
  258. return;
  259. // Check if the team is the same
  260. if ( !Q_stricmp( szTeam, pPlayer->GetString( "game/team", "" ) ) )
  261. return;
  262. KeyValues *kvGame = pPlayer->FindKey( "game", true );
  263. if ( !kvGame )
  264. return;
  265. // If desired avatar is blank, then no validation required
  266. if ( !*szTeam )
  267. {
  268. kvGame->SetString( "team", "random" );
  269. }
  270. else
  271. {
  272. kvGame->SetString( "team", szTeam );
  273. }
  274. // Notify the sessions of a player update
  275. * ( ppPlayersUpdated ++ ) = pPlayer;
  276. }
  277. // Executes the command on the session settings, this function on host
  278. // is allowed to modify Members/Game subkeys and has to fill in modified players KeyValues
  279. // When running on a remote client "ppPlayersUpdated" is NULL and players cannot
  280. // be modified
  281. void CMatchTitleGameSettingsMgr::ExecuteCommand( KeyValues *pCommand, KeyValues *pSessionSystemData, KeyValues *pSettings, KeyValues **ppPlayersUpdated )
  282. {
  283. char const *szCommand = pCommand->GetName();
  284. if ( !Q_stricmp( "Game::Team", szCommand ) )
  285. {
  286. if ( !Q_stricmp( "host", pSessionSystemData->GetString( "type", "host" ) ) &&
  287. // !Q_stricmp( "lobby", pSessionSystemData->GetString( "state", "lobby" ) ) && - avatars also update when players change team ingame
  288. ppPlayersUpdated )
  289. {
  290. char const *szAvatar = pCommand->GetString( "team" );
  291. if ( !*szAvatar )
  292. {
  293. // Requesting random is only allowed in unlocked lobby
  294. if ( Q_stricmp( "lobby", pSessionSystemData->GetString( "state", "lobby" ) ) )
  295. return;
  296. if ( *pSettings->GetString( "system/lock" ) )
  297. return;
  298. }
  299. OnRunCommand_TeamChange( pCommand, pSettings, ppPlayersUpdated );
  300. return;
  301. }
  302. }
  303. }