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.

277 lines
7.5 KiB

  1. //========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include "cbase.h"
  8. #include "cs_app_lifetime_gamestats.h"
  9. #include "steamworks_gamestats.h"
  10. #include "steam/isteamutils.h"
  11. #include "csgo_serialnumbersequence.h"
  12. #include "gametypes.h"
  13. #include "matchmaking/imatchframework.h"
  14. #include "cs_gamerules.h"
  15. // memdbgon must be the last include file in a .cpp file!!!
  16. #include "tier0/memdbgon.h"
  17. extern IGameTypes *g_pGameTypes;
  18. ConVar cl_debug_client_gamestats( "cl_debug_client_gamestats", "1" );
  19. static CS_App_Lifetime_Gamestats g_CSAppLifetimeGamestats;
  20. CS_App_Lifetime_Gamestats* CSAppLifetimeGameStats() { return &g_CSAppLifetimeGamestats; }
  21. uint16 CS_App_Lifetime_Gamestats::m_unEventCount = 0;
  22. const char* g_szValidUIEvents [] =
  23. {
  24. "ServerBrowserLAN",
  25. "ServerBrowserFriends",
  26. "ServerBrowserJoinFriend",
  27. "ServerBrowserUnknownJoinType",
  28. "ServerBrowserFavorites",
  29. "ServerBrowserHistory",
  30. "ServerBrowserSpectator",
  31. "ServerBrowserInternet",
  32. "ServerBrowserUnknownPageType",
  33. "ServerBrowserJoinByIP",
  34. "HLTVConnectRelay",
  35. "CommunityQuickPlay",
  36. "ConnectStringOnCommandline",
  37. "PurchaseEventRequired",
  38. "PurchaseEventMinutesPlayed",
  39. "PurchaseEventNoMinutesPlayed",
  40. "PurchaseEventStash",
  41. "InventoryEquipMainMenu",
  42. "InventoryEquipConnectedActive",
  43. "InventoryEquipConnectedInactive",
  44. "CrateUnlockMainMenu",
  45. "CrateUnlockConnected",
  46. "WeaponInspectMainMenuDefault",
  47. "WeaponInspectMainMenuPainted",
  48. "WeaponInspectConnectedDefault",
  49. "WeaponInspectConnectedPainted",
  50. "WorkshopWeaponPreview",
  51. "MatchDownloadAttempt",
  52. "WatchLiveMatch",
  53. "WatchDownloadedMatch",
  54. "WatchGOTVTheater",
  55. "WatchTwitchStream",
  56. "WeaponInspectExternalItem",
  57. "ViewedOffers",
  58. "BorrowedMusicKit",
  59. "ViewOnMarket",
  60. "InsufficientLevel",
  61. "PartyBrowserRefreshEmpty",
  62. "PartyBrowserRefreshResults",
  63. "PartyBrowserJoin",
  64. "FriendJoin",
  65. "SoloSearch",
  66. "WatchEmbeddedStreamExternally",
  67. "PartyBrowserJoinNearby",
  68. "SwitchedToHRTFEnabled",
  69. "SwitchedToHRTFDisabled",
  70. "PartyBrowserJoinInvited",
  71. };
  72. ConVar steamworks_sessionid_lifetime_client( "steamworks_sessionid_lifetime_client", "0", FCVAR_HIDDEN, "The full client session ID for the new steamworks gamestats." );
  73. CS_App_Lifetime_Gamestats::CS_App_Lifetime_Gamestats() :
  74. BaseClass( "CS_App_Lifetime_Gamestats", "steamworks_sessionid_lifetime_client" ),
  75. m_GameJoinRequested( this, &CS_App_Lifetime_Gamestats::OnGameJoinRequested )
  76. {
  77. }
  78. bool CS_App_Lifetime_Gamestats::Init()
  79. {
  80. if ( !BaseClass::Init() )
  81. return false;
  82. StartSession();
  83. return true;
  84. }
  85. void CS_App_Lifetime_Gamestats::Shutdown()
  86. {
  87. WriteStats();
  88. EndSession();
  89. }
  90. void CS_App_Lifetime_Gamestats::WriteStats( void )
  91. {
  92. // Refresh the interface in case steam has unloaded
  93. m_SteamWorksInterface = GetInterface();
  94. if ( !m_SteamWorksInterface )
  95. {
  96. DevMsg( "WARNING: Attempted to send a steamworks gamestats row when the steamworks interface was not available!" );
  97. }
  98. else
  99. {
  100. WriteUIEvents();
  101. WriteGameJoins();
  102. }
  103. }
  104. EResult CS_App_Lifetime_Gamestats::WriteUIEvents()
  105. {
  106. FOR_EACH_VEC( m_vecUIEvents, i )
  107. {
  108. uint64 iTableID = 0;
  109. m_SteamWorksInterface->AddNewRow( &iTableID, m_SessionID, "CSGOUIEvent" );
  110. if ( !iTableID )
  111. return k_EResultFail;
  112. UIEvent_t *pData = &m_vecUIEvents[i];
  113. WriteStringToTable( pData->strEventID.Access(), iTableID, "EventID" );
  114. WriteIntToTable( pData->unCount, iTableID, "EventCount" );
  115. WriteIntToTable( pData->unTime, iTableID, "TimeSubmitted" );
  116. if ( cl_debug_client_gamestats.GetBool() )
  117. {
  118. Msg( "Steamworks gamestats: %s adding UI data %s id=%d time=%d\n", Name(), pData->strEventID.Get(), pData->unCount, pData->unTime );
  119. }
  120. EResult res = m_SteamWorksInterface->CommitRow( iTableID );
  121. if ( res != k_EResultOK )
  122. {
  123. char pzMessage[MAX_PATH] = {0};
  124. V_snprintf( pzMessage, ARRAYSIZE(pzMessage), "Failed To Submit table %s", "CSUIEvent" );
  125. Assert( pzMessage );
  126. return res;
  127. }
  128. }
  129. m_vecUIEvents.RemoveAll();
  130. return k_EResultOK;
  131. }
  132. EResult CS_App_Lifetime_Gamestats::WriteGameJoins()
  133. {
  134. FOR_EACH_VEC( m_vecGameJoins, i )
  135. {
  136. uint64 iTableID = 0;
  137. m_SteamWorksInterface->AddNewRow( &iTableID, m_SessionID, "CSGOGameJoin" );
  138. if ( !iTableID )
  139. return k_EResultFail;
  140. uint64 ullGameSessionID = m_vecGameJoins[i].ullSessionID;
  141. uint16 unGameType = (uint16)m_vecGameJoins[i].unGameType;
  142. uint16 unGameMode = (uint16)m_vecGameJoins[i].unGameMode;
  143. bool bValveOfficial = m_vecGameJoins[i].bIsValveOfficial;
  144. WriteInt64ToTable( ullGameSessionID, iTableID, "GameSessionID" );
  145. WriteIntToTable( unGameType, iTableID, "GameTypeID" );
  146. WriteIntToTable( unGameMode, iTableID, "GameModeID" );
  147. WriteIntToTable( bValveOfficial, iTableID, "IsValveOfficial" );
  148. if ( cl_debug_client_gamestats.GetBool() )
  149. {
  150. Msg( "Steamworks gamestats: %s adding game session %llu", Name(), ullGameSessionID );
  151. }
  152. EResult res = m_SteamWorksInterface->CommitRow( iTableID );
  153. if ( res != k_EResultOK )
  154. {
  155. char pzMessage[MAX_PATH] = {0};
  156. V_snprintf( pzMessage, ARRAYSIZE(pzMessage), "Failed To Submit table %s", "CSGOGameJoin" );
  157. Assert( pzMessage );
  158. return res;
  159. }
  160. }
  161. m_vecGameJoins.RemoveAll();
  162. return k_EResultOK;
  163. }
  164. static bool BHelperCheckSafeUserCmdString( char const *ipconnect )
  165. {
  166. bool bConnectValid = true;
  167. while ( *ipconnect )
  168. {
  169. if ( ( ( *ipconnect >= '0' ) && ( *ipconnect <= '9' ) ) ||
  170. ( ( *ipconnect >= 'a' ) && ( *ipconnect <= 'z' ) ) ||
  171. ( ( *ipconnect >= 'A' ) && ( *ipconnect <= 'Z' ) ) ||
  172. ( *ipconnect == '_' ) || ( *ipconnect == '-' ) || ( *ipconnect == '.' ) ||
  173. ( *ipconnect == ':' ) || ( *ipconnect == '?' ) || ( *ipconnect == '%' ) ||
  174. ( *ipconnect == '/' ) || ( *ipconnect == '=' ) || ( *ipconnect == ' ' ) ||
  175. ( *ipconnect == '[' ) || ( *ipconnect == ']' ) || ( *ipconnect == '@' ) ||
  176. ( *ipconnect == '"' ) || ( *ipconnect == '\'' ) || ( *ipconnect == '#' ) ||
  177. ( *ipconnect == '(' ) || ( *ipconnect == ')' ) || ( *ipconnect == '!' ) ||
  178. ( *ipconnect == '\\' ) || ( *ipconnect == '$' )
  179. )
  180. ++ipconnect;
  181. else
  182. {
  183. bConnectValid = false;
  184. break;
  185. }
  186. }
  187. return bConnectValid;
  188. }
  189. void CS_App_Lifetime_Gamestats::OnGameJoinRequested( GameRichPresenceJoinRequested_t *pCallback )
  190. {
  191. /* Removed for partner depot */
  192. }
  193. void CS_App_Lifetime_Gamestats::RecordUIEvent( const char* szEventName )
  194. {
  195. if ( m_unEventCount == (uint16)-1 )
  196. return;
  197. bool bFound = false;
  198. for ( int i = 0; i < ARRAYSIZE( g_szValidUIEvents ); ++i )
  199. {
  200. if ( V_strcmp( g_szValidUIEvents[i], szEventName) == 0 )
  201. {
  202. bFound = true;
  203. break;
  204. }
  205. }
  206. // Only record whitelisted events
  207. if ( !bFound )
  208. {
  209. return;
  210. }
  211. Assert( V_strlen( szEventName ) < UI_EVENT_NAME_MAX );
  212. uint16 idx = m_vecUIEvents.AddToTail();
  213. m_vecUIEvents[idx].unCount = ++m_unEventCount;
  214. CRTime now;
  215. m_vecUIEvents[idx].unTime = now.GetRTime32();
  216. m_vecUIEvents[idx].strEventID.Set( szEventName );
  217. }
  218. void CS_App_Lifetime_Gamestats::AddSessionIDsToTable( int iTableID )
  219. {
  220. // Our client side session.
  221. WriteInt64ToTable( m_SessionID, iTableID, "SessionID" );
  222. }
  223. void CS_App_Lifetime_Gamestats::RecordGameJoin( uint64 ullSessionID )
  224. {
  225. GameJoins_t gameJoinInfo;
  226. gameJoinInfo.ullSessionID = ullSessionID;
  227. gameJoinInfo.unGameMode = g_pGameTypes->GetCurrentGameMode();
  228. gameJoinInfo.unGameType = g_pGameTypes->GetCurrentGameType();
  229. gameJoinInfo.bIsValveOfficial = CSGameRules() && CSGameRules()->IsValveDS();
  230. if ( m_vecGameJoins.Find( gameJoinInfo ) == m_vecGameJoins.InvalidIndex() )
  231. {
  232. m_vecGameJoins.AddToTail( gameJoinInfo );
  233. }
  234. else
  235. {
  236. Assert( 0 ); // Attempting double add-- would cause PK violation.
  237. }
  238. }