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.

241 lines
7.7 KiB

  1. //===== Copyright � 1996-2009, Valve Corporation, All rights reserved. ======//
  2. //
  3. // Purpose:
  4. //
  5. //===========================================================================//
  6. #include "mm_title_richpresence.h"
  7. #include "swarm.spa.h"
  8. #include "matchext_swarm.h"
  9. // memdbgon must be the last include file in a .cpp file!!!
  10. #include "tier0/memdbgon.h"
  11. //
  12. // Mapping of context values
  13. //
  14. ContextValue_t g_pcv_CONTEXT_GAME_MODE[] = {
  15. { "versus", CONTEXT_GAME_MODE_VERSUS },
  16. { "teamversus", CONTEXT_GAME_MODE_TEAMVERSUS },
  17. { "scavenge", CONTEXT_GAME_MODE_SCAVENGE },
  18. { "teamscavenge", CONTEXT_GAME_MODE_TEAMSCAVENGE },
  19. { "survival", CONTEXT_GAME_MODE_SURVIVAL },
  20. { "realism", CONTEXT_GAME_MODE_REALISM },
  21. { NULL, CONTEXT_GAME_MODE_COOP },
  22. };
  23. ContextValue_t g_pcv_CONTEXT_STATE[] = {
  24. { "game", CONTEXT_STATE_GAME },
  25. { "finale", CONTEXT_STATE_FINALE },
  26. { NULL, CONTEXT_STATE_LOBBY },
  27. };
  28. ContextValue_t g_pcv_CONTEXT_DIFFICULTY[] = {
  29. { "easy", CONTEXT_DIFFICULTY_EASY },
  30. { "hard", CONTEXT_DIFFICULTY_HARD },
  31. { "impossible", CONTEXT_DIFFICULTY_IMPOSSIBLE },
  32. { NULL, CONTEXT_DIFFICULTY_NORMAL },
  33. };
  34. ContextValue_t g_pcv_CONTEXT_ACCESS[] = {
  35. { "public", CONTEXT_ACCESS_PUBLIC },
  36. { "friends", CONTEXT_ACCESS_FRIENDS },
  37. { NULL, CONTEXT_ACCESS_PRIVATE },
  38. };
  39. //
  40. // User context and property setting
  41. //
  42. static void SetAllUsersContext( DWORD dwContextId, DWORD dwValue, bool bAsync = true )
  43. {
  44. #ifdef _X360
  45. for ( int k = 0; k < ( int ) XBX_GetNumGameUsers(); ++ k )
  46. {
  47. if ( XBX_GetUserIsGuest( k ) )
  48. continue;
  49. int iCtrlr = XBX_GetUserId( k );
  50. if ( bAsync )
  51. XUserSetContextEx( iCtrlr, dwContextId, dwValue, MMX360_NewOverlappedDormant() );
  52. else
  53. XUserSetContext( iCtrlr, dwContextId, dwValue );
  54. }
  55. #endif
  56. }
  57. static void SetAllUsersProperty( DWORD dwPropertyId, DWORD cbValue, void const *pvValue )
  58. {
  59. #ifdef _X360
  60. for ( int k = 0; k < ( int ) XBX_GetNumGameUsers(); ++ k )
  61. {
  62. if ( XBX_GetUserIsGuest( k ) )
  63. continue;
  64. int iCtrlr = XBX_GetUserId( k );
  65. XUserSetPropertyEx( iCtrlr, dwPropertyId, cbValue, pvValue, MMX360_NewOverlappedDormant() );
  66. }
  67. #endif
  68. }
  69. KeyValues * MM_Title_RichPresence_PrepareForSessionCreate( KeyValues *pSettings )
  70. {
  71. if ( char const *szValue = pSettings->GetString( "game/mode", NULL ) )
  72. {
  73. SetAllUsersContext( X_CONTEXT_GAME_MODE, g_pcv_CONTEXT_GAME_MODE->ScanValues( szValue ), false );
  74. }
  75. // matchmaking version
  76. {
  77. static int val; // must be valid for the async call
  78. extern ConVar mm_matchmaking_version;
  79. val = mm_matchmaking_version.GetInt();
  80. SetAllUsersProperty( PROPERTY_MMVERSION, sizeof( val ), &val );
  81. DevMsg( "PrepareForSessionCreate: matchmaking version %d\n", val );
  82. }
  83. return NULL;
  84. }
  85. void MM_Title_RichPresence_Update( KeyValues *pFullSettings, KeyValues *pUpdatedSettings )
  86. {
  87. if ( !pFullSettings )
  88. {
  89. SetAllUsersContext( X_CONTEXT_PRESENCE, 1 ); // main menu
  90. return;
  91. }
  92. // Also set players information during initial rich presence update
  93. if ( !pUpdatedSettings && pFullSettings )
  94. {
  95. MM_Title_RichPresence_PlayersChanged( pFullSettings );
  96. }
  97. // pUpdatedSettings = NULL when the session is created and all contexts need to be set
  98. KeyValues *pNewSettings = pUpdatedSettings ? pUpdatedSettings : pFullSettings;
  99. // Current mission/map (can be NULL!)
  100. char const *szCampaign = pFullSettings->GetString( "game/campaign", "" );
  101. KeyValues *pInfoMission = szCampaign[0] ? g_pMatchExtSwarm->GetAllMissions()->FindKey( szCampaign ) : NULL;
  102. KeyValues *pInfoChapter = g_pMatchExtSwarm->GetMapInfo( pFullSettings );
  103. if ( char const *szValue = pNewSettings->GetString( "system/access", NULL ) )
  104. {
  105. SetAllUsersContext( CONTEXT_ACCESS, g_pcv_CONTEXT_ACCESS->ScanValues( szValue ) );
  106. }
  107. if ( char const *szValue = pNewSettings->GetString( "game/state", NULL ) )
  108. {
  109. SetAllUsersContext( CONTEXT_STATE, g_pcv_CONTEXT_STATE->ScanValues( szValue ) );
  110. }
  111. if ( char const *szValue = pNewSettings->GetString( "game/mode", NULL ) )
  112. {
  113. SetAllUsersContext( X_CONTEXT_GAME_MODE, g_pcv_CONTEXT_GAME_MODE->ScanValues( szValue ) );
  114. }
  115. if ( char const *szValue = pNewSettings->GetString( "game/difficulty", NULL ) )
  116. {
  117. SetAllUsersContext( CONTEXT_DIFFICULTY, g_pcv_CONTEXT_DIFFICULTY->ScanValues( szValue ) );
  118. }
  119. if ( KeyValues *kvVal = pNewSettings->FindKey( "game/maxrounds" ) )
  120. {
  121. static int val; // must be valid for the async call
  122. val = kvVal->GetInt();
  123. SetAllUsersProperty( PROPERTY_MAXROUNDS, sizeof( val ), &val );
  124. }
  125. bool bSetLevelDescription = false;
  126. if ( char const *szValue = pNewSettings->GetString( "game/campaign", NULL ) )
  127. {
  128. int iCampaign = pInfoMission->GetInt( "x360ctx", CONTEXT_CAMPAIGN_ANY );
  129. SetAllUsersContext( CONTEXT_CAMPAIGN, iCampaign );
  130. bSetLevelDescription = true;
  131. }
  132. if ( KeyValues *kvVal = pNewSettings->FindKey( "game/chapter" ) )
  133. {
  134. static int val; // must be valid for the async call
  135. val = kvVal->GetInt();
  136. SetAllUsersProperty( PROPERTY_CHAPTER, sizeof( val ), &val );
  137. bSetLevelDescription = true;
  138. }
  139. if ( bSetLevelDescription )
  140. {
  141. int iContext = CONTEXT_LEVELDESCRIPTION_ANY;
  142. if ( pInfoChapter )
  143. iContext = pInfoChapter->GetInt( "x360ctx", iContext );
  144. else if ( pInfoMission )
  145. iContext = pInfoMission->GetInt( "x360ctx", iContext ); // mission contexts correspond to chapters too
  146. SetAllUsersContext( CONTEXT_LEVELDESCRIPTION, iContext );
  147. }
  148. if ( KeyValues *kvVal = pNewSettings->FindKey( "game/dlcrequired" ) )
  149. {
  150. static int val[10]; // must be valid for the async call
  151. uint64 uiDlcRequired = kvVal->GetUint64();
  152. extern ConVar mm_matchmaking_dlcsquery;
  153. for ( int k = 1; k <= mm_matchmaking_dlcsquery.GetInt(); ++ k )
  154. {
  155. val[k] = !!( uiDlcRequired & ( 1ull << k ) );
  156. DevMsg( "DLC%d required: %d\n", k, val[k] );
  157. SetAllUsersProperty( PROPERTY_MMVERSION + k, sizeof( val ), &val );
  158. }
  159. }
  160. //
  161. // Determine Rich Presence Display
  162. //
  163. if ( char const *szGameModeForRichPresence = pFullSettings->GetString( "game/mode", NULL ) )
  164. {
  165. unsigned int dwLevelPresence = CONTEXT_PRESENCE_MAINMENU;
  166. static ContextValue_t values[] = {
  167. { "versus", CONTEXT_PRESENCE_MODE_GAP_MISSION_LOBBY },
  168. { "teamversus", CONTEXT_PRESENCE_MODE_GAP_MISSION_LOBBY },
  169. { "survival", CONTEXT_PRESENCE_MODE_GAP_LEVEL_LOBBY },
  170. { "scavenge", CONTEXT_PRESENCE_MODE_GAP_LEVEL_LOBBY },
  171. { "teamscavenge", CONTEXT_PRESENCE_MODE_GAP_LEVEL_LOBBY },
  172. { "coop", CONTEXT_PRESENCE_MODE_DIFF_MISSION_LOBBY },
  173. { "realism", CONTEXT_PRESENCE_MODE_DIFF_MISSION_LOBBY },
  174. { NULL, CONTEXT_PRESENCE_MAINMENU },
  175. };
  176. dwLevelPresence = values->ScanValues( szGameModeForRichPresence );
  177. // Hook for offline game
  178. if ( !Q_stricmp( "offline", pFullSettings->GetString( "system/network" ) ) )
  179. dwLevelPresence = CONTEXT_PRESENCE_LOCAL_DIFF_MISSION_SETTINGS;
  180. // Special hook for developers commentary
  181. if ( !Q_stricmp( "commentary", pFullSettings->GetString( "options/play" ) ) )
  182. dwLevelPresence = CONTEXT_PRESENCE_DEVELOPER_COMM_SETTINGS;
  183. // If the game is active, then use the +1 presence
  184. if ( Q_stricmp( "lobby", pFullSettings->GetString( "game/state", "lobby" ) ) )
  185. ++ dwLevelPresence;
  186. dwLevelPresence = pInfoMission->GetInt( "x360presence", dwLevelPresence ); // let the mission override
  187. dwLevelPresence = pInfoChapter->GetInt( "x360presence", dwLevelPresence ); // let the chapter override
  188. SetAllUsersContext( X_CONTEXT_PRESENCE, dwLevelPresence );
  189. }
  190. }
  191. void MM_Title_RichPresence_PlayersChanged( KeyValues *pFullSettings )
  192. {
  193. if ( int numPlayers = pFullSettings->GetInt( "members/numPlayers" ) )
  194. {
  195. static int val; // must be valid for the async call
  196. val = numPlayers;
  197. SetAllUsersProperty( PROPERTY_NUMPLAYERS, sizeof( val ), &val );
  198. }
  199. }