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.

430 lines
14 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================
  7. #if defined( STEAM ) || defined( HL1 )
  8. #include "stdafx.h"
  9. #else
  10. #include <stdio.h>
  11. #include "dbg.h"
  12. #include "SteamCommon.h"
  13. #include "steam/steamclientpublic.h"
  14. #include "tier1/strtools.h"
  15. #endif
  16. #ifdef HL1
  17. #include "steamcommon.h"
  18. #include "steam/steamclientpublic.h"
  19. #endif
  20. // NOTE: This has to be the last file included!
  21. #include "tier0/memdbgon.h"
  22. //-----------------------------------------------------------------------------
  23. // Purpose: Constructor
  24. // Input : pchSteamID - text representation of a Steam ID
  25. //-----------------------------------------------------------------------------
  26. CSteamID::CSteamID( const char *pchSteamID, EUniverse eDefaultUniverse /* = k_EUniverseInvalid */ )
  27. {
  28. SetFromString( pchSteamID, eDefaultUniverse );
  29. }
  30. //-----------------------------------------------------------------------------
  31. // Purpose: Initializes a steam ID from a string
  32. // Input : pchSteamID - text representation of a Steam ID
  33. //-----------------------------------------------------------------------------
  34. void CSteamID::SetFromString( const char *pchSteamID, EUniverse eDefaultUniverse )
  35. {
  36. uint nAccountID = 0;
  37. uint nInstance = 1;
  38. EUniverse eUniverse = eDefaultUniverse;
  39. // Since we are using sscanf with %d to read this value
  40. // we need eUniverse to be the size of an int.
  41. COMPILE_TIME_ASSERT( sizeof(eUniverse) == sizeof(int) );
  42. EAccountType eAccountType = k_EAccountTypeIndividual;
  43. if ( *pchSteamID == '[' )
  44. pchSteamID++;
  45. // BUGBUG Rich use the Q_ functions
  46. if (*pchSteamID == 'A')
  47. {
  48. // This is test only
  49. pchSteamID++; // skip the A
  50. eAccountType = k_EAccountTypeAnonGameServer;
  51. if (*pchSteamID == '-' || *pchSteamID == ':')
  52. pchSteamID++; // skip the optional - or :
  53. if ( strchr( pchSteamID, '(' ) )
  54. sscanf( strchr( pchSteamID, '(' ), "(%u)", &nInstance );
  55. const char *pchColon = strchr( pchSteamID, ':' );
  56. if ( pchColon && *pchColon != 0 && strchr( pchColon+1, ':' ))
  57. {
  58. sscanf( pchSteamID, "%u:%u:%u", (uint*)&eUniverse, &nAccountID, &nInstance );
  59. }
  60. else if ( pchColon )
  61. {
  62. sscanf( pchSteamID, "%u:%u", (uint*)&eUniverse, &nAccountID );
  63. }
  64. else
  65. {
  66. sscanf( pchSteamID, "%u", &nAccountID );
  67. }
  68. if ( nAccountID == 0 )
  69. {
  70. // i dont care what number you entered
  71. CreateBlankAnonLogon(eUniverse);
  72. }
  73. else
  74. {
  75. InstancedSet( nAccountID, nInstance, eUniverse, eAccountType );
  76. }
  77. return;
  78. }
  79. else if (*pchSteamID == 'G')
  80. {
  81. pchSteamID++; // skip the G
  82. eAccountType = k_EAccountTypeGameServer;
  83. if (*pchSteamID == '-' || *pchSteamID == ':')
  84. pchSteamID++; // skip the optional - or :
  85. }
  86. else if (*pchSteamID == 'C')
  87. {
  88. pchSteamID++; // skip the C
  89. eAccountType = k_EAccountTypeContentServer;
  90. if (*pchSteamID == '-' || *pchSteamID == ':')
  91. pchSteamID++; // skip the optional - or :
  92. }
  93. else if (*pchSteamID == 'g')
  94. {
  95. pchSteamID++; // skip the g
  96. eAccountType = k_EAccountTypeClan;
  97. nInstance = 0;
  98. if (*pchSteamID == '-' || *pchSteamID == ':')
  99. pchSteamID++; // skip the optional - or :
  100. }
  101. else if (*pchSteamID == 'c')
  102. {
  103. pchSteamID++; // skip the c
  104. eAccountType = k_EAccountTypeChat;
  105. nInstance = k_EChatInstanceFlagClan;
  106. if (*pchSteamID == '-' || *pchSteamID == ':')
  107. pchSteamID++; // skip the optional - or :
  108. }
  109. else if (*pchSteamID == 'L')
  110. {
  111. pchSteamID++; // skip the c
  112. eAccountType = k_EAccountTypeChat;
  113. nInstance = k_EChatInstanceFlagLobby;
  114. if (*pchSteamID == '-' || *pchSteamID == ':')
  115. pchSteamID++; // skip the optional - or :
  116. }
  117. else if (*pchSteamID == 'T')
  118. {
  119. pchSteamID++; // skip the T
  120. eAccountType = k_EAccountTypeChat;
  121. nInstance = 0; // Anon chat
  122. if (*pchSteamID == '-' || *pchSteamID == ':')
  123. pchSteamID++; // skip the optional - or :
  124. }
  125. else if (*pchSteamID == 'U')
  126. {
  127. pchSteamID++; // skip the U
  128. eAccountType = k_EAccountTypeIndividual;
  129. nInstance = 1;
  130. if (*pchSteamID == '-' || *pchSteamID == ':')
  131. pchSteamID++; // skip the optional - or :
  132. }
  133. else if (*pchSteamID == 'i')
  134. {
  135. pchSteamID++; // skip the i
  136. eAccountType = k_EAccountTypeInvalid;
  137. nInstance = 1;
  138. if (*pchSteamID == '-' || *pchSteamID == ':')
  139. pchSteamID++; // skip the optional - or :
  140. }
  141. else
  142. {
  143. // Check for a 64-bit steamID, unadorned.
  144. uint64 unSteamID64 = V_atoui64( pchSteamID );
  145. if ( unSteamID64 > 0xffffffffU )
  146. {
  147. SetFromUint64( unSteamID64 );
  148. return;
  149. }
  150. }
  151. if ( strchr( pchSteamID, ':' ) )
  152. {
  153. if (*pchSteamID == '[')
  154. pchSteamID++; // skip the optional [
  155. sscanf( pchSteamID, "%u:%u", (uint*)&eUniverse, &nAccountID );
  156. if ( eUniverse == k_EUniverseInvalid )
  157. eUniverse = eDefaultUniverse;
  158. }
  159. else
  160. {
  161. sscanf( pchSteamID, "%u", &nAccountID );
  162. }
  163. Assert( (eUniverse > k_EUniverseInvalid) && (eUniverse < k_EUniverseMax) );
  164. InstancedSet( nAccountID, nInstance, eUniverse, eAccountType );
  165. }
  166. #if defined( INCLUDED_STEAM2_USERID_STRUCTS )
  167. //-----------------------------------------------------------------------------
  168. // Purpose: Initializes a steam ID from a Steam2 ID string
  169. // Input: pchSteam2ID - Steam2 ID (as a string #:#:#) to convert
  170. // eUniverse - universe this ID belongs to
  171. // Output: true if successful, false otherwise
  172. //-----------------------------------------------------------------------------
  173. bool CSteamID::SetFromSteam2String( const char *pchSteam2ID, EUniverse eUniverse )
  174. {
  175. Assert( pchSteam2ID );
  176. // Convert the Steam2 ID string to a Steam2 ID structure
  177. TSteamGlobalUserID steam2ID;
  178. steam2ID.m_SteamInstanceID = 0;
  179. steam2ID.m_SteamLocalUserID.Split.High32bits = 0;
  180. steam2ID.m_SteamLocalUserID.Split.Low32bits = 0;
  181. const char *pchTSteam2ID = pchSteam2ID;
  182. // Customer support is fond of entering steam IDs in the following form: STEAM_n:x:y
  183. const char *pchOptionalLeadString = "STEAM_";
  184. if ( V_strnicmp( pchSteam2ID, pchOptionalLeadString, V_strlen( pchOptionalLeadString ) ) == 0 )
  185. pchTSteam2ID = pchSteam2ID + V_strlen( pchOptionalLeadString );
  186. char cExtraCharCheck = 0;
  187. int cFieldConverted = sscanf( pchTSteam2ID, "%hu:%u:%u%c", &steam2ID.m_SteamInstanceID,
  188. &steam2ID.m_SteamLocalUserID.Split.High32bits, &steam2ID.m_SteamLocalUserID.Split.Low32bits, &cExtraCharCheck );
  189. // Validate the conversion ... a special case is steam2 instance ID 1 which is reserved for special DoD handling
  190. if ( cExtraCharCheck != 0 || cFieldConverted == EOF || cFieldConverted < 2 || ( cFieldConverted < 3 && steam2ID.m_SteamInstanceID != 1 ) )
  191. return false;
  192. // Now convert to steam ID from the Steam2 ID structure
  193. SetFromSteam2( &steam2ID, eUniverse );
  194. return true;
  195. }
  196. #endif
  197. //-----------------------------------------------------------------------------
  198. // Purpose: Renders the steam ID to a buffer. NOTE: for convenience of calling
  199. // code, this code returns a pointer to a static buffer and is NOT thread-safe.
  200. // Output: buffer with rendered Steam ID
  201. //-----------------------------------------------------------------------------
  202. const char * CSteamID::Render() const
  203. {
  204. // longest length of returned string is k_cBufLen
  205. // [A:%u:%u:%u]
  206. // %u == 10 * 3 + 6 == 36, plus terminator == 37
  207. const int k_cBufLen = 37;
  208. const int k_cBufs = 4; // # of static bufs to use (so people can compose output with multiple calls to Render() )
  209. static char rgchBuf[k_cBufs][k_cBufLen];
  210. static int nBuf = 0;
  211. char * pchBuf = rgchBuf[nBuf]; // get pointer to current static buf
  212. nBuf ++; // use next buffer for next call to this method
  213. nBuf %= k_cBufs;
  214. if ( k_EAccountTypeAnonGameServer == m_steamid.m_comp.m_EAccountType )
  215. {
  216. V_snprintf( pchBuf, k_cBufLen, "[A:%u:%u:%u]", m_steamid.m_comp.m_EUniverse, m_steamid.m_comp.m_unAccountID, m_steamid.m_comp.m_unAccountInstance );
  217. }
  218. else if ( k_EAccountTypeGameServer == m_steamid.m_comp.m_EAccountType )
  219. {
  220. V_snprintf( pchBuf, k_cBufLen, "[G:%u:%u]", m_steamid.m_comp.m_EUniverse, m_steamid.m_comp.m_unAccountID );
  221. }
  222. else if ( k_EAccountTypeMultiseat == m_steamid.m_comp.m_EAccountType )
  223. {
  224. V_snprintf( pchBuf, k_cBufLen, "[M:%u:%u:%u]", m_steamid.m_comp.m_EUniverse, m_steamid.m_comp.m_unAccountID, m_steamid.m_comp.m_unAccountInstance );
  225. }
  226. else if ( k_EAccountTypePending == m_steamid.m_comp.m_EAccountType )
  227. {
  228. V_snprintf( pchBuf, k_cBufLen, "[P:%u:%u]", m_steamid.m_comp.m_EUniverse, m_steamid.m_comp.m_unAccountID );
  229. }
  230. else if ( k_EAccountTypeContentServer == m_steamid.m_comp.m_EAccountType )
  231. {
  232. V_snprintf( pchBuf, k_cBufLen, "[C:%u:%u]", m_steamid.m_comp.m_EUniverse, m_steamid.m_comp.m_unAccountID );
  233. }
  234. else if ( k_EAccountTypeClan == m_steamid.m_comp.m_EAccountType )
  235. {
  236. // 'g' for "group"
  237. V_snprintf( pchBuf, k_cBufLen, "[g:%u:%u]", m_steamid.m_comp.m_EUniverse, m_steamid.m_comp.m_unAccountID );
  238. }
  239. else if ( k_EAccountTypeChat == m_steamid.m_comp.m_EAccountType )
  240. {
  241. if ( m_steamid.m_comp.m_unAccountInstance & k_EChatInstanceFlagClan )
  242. {
  243. V_snprintf( pchBuf, k_cBufLen, "[c:%u:%u]", m_steamid.m_comp.m_EUniverse, m_steamid.m_comp.m_unAccountID );
  244. }
  245. else if ( m_steamid.m_comp.m_unAccountInstance & k_EChatInstanceFlagLobby )
  246. {
  247. V_snprintf( pchBuf, k_cBufLen, "[L:%u:%u]", m_steamid.m_comp.m_EUniverse, m_steamid.m_comp.m_unAccountID );
  248. }
  249. else // Anon chat
  250. {
  251. V_snprintf( pchBuf, k_cBufLen, "[T:%u:%u]", m_steamid.m_comp.m_EUniverse, m_steamid.m_comp.m_unAccountID );
  252. }
  253. }
  254. else if ( k_EAccountTypeInvalid == m_steamid.m_comp.m_EAccountType )
  255. {
  256. V_snprintf( pchBuf, k_cBufLen, "[I:%u:%u]", m_steamid.m_comp.m_EUniverse, m_steamid.m_comp.m_unAccountID );
  257. }
  258. else if ( k_EAccountTypeIndividual == m_steamid.m_comp.m_EAccountType )
  259. {
  260. if ( m_steamid.m_comp.m_unAccountInstance != k_unSteamUserDesktopInstance )
  261. V_snprintf( pchBuf, k_cBufLen, "[U:%u:%u:%u]", m_steamid.m_comp.m_EUniverse, m_steamid.m_comp.m_unAccountID, m_steamid.m_comp.m_unAccountInstance );
  262. else
  263. V_snprintf( pchBuf, k_cBufLen, "[U:%u:%u]", m_steamid.m_comp.m_EUniverse, m_steamid.m_comp.m_unAccountID );
  264. }
  265. else if ( k_EAccountTypeAnonUser == m_steamid.m_comp.m_EAccountType )
  266. {
  267. V_snprintf( pchBuf, k_cBufLen, "[a:%u:%u]", m_steamid.m_comp.m_EUniverse, m_steamid.m_comp.m_unAccountID );
  268. }
  269. else
  270. {
  271. V_snprintf( pchBuf, k_cBufLen, "[i:%u:%u]", m_steamid.m_comp.m_EUniverse, m_steamid.m_comp.m_unAccountID );
  272. }
  273. return pchBuf;
  274. }
  275. //-----------------------------------------------------------------------------
  276. // Purpose: Renders the passed-in steam ID to a buffer. NOTE: for convenience of calling
  277. // code, this code returns a pointer to a static buffer and is NOT thread-safe.
  278. // Input: 64-bit representation of Steam ID to render
  279. // Output: buffer with rendered Steam ID
  280. //-----------------------------------------------------------------------------
  281. const char * CSteamID::Render( uint64 ulSteamID )
  282. {
  283. CSteamID steamID( ulSteamID );
  284. return steamID.Render();
  285. }
  286. //-----------------------------------------------------------------------------
  287. // Purpose: some steamIDs are for internal use only
  288. // This is really debug code, but we run with asserts on in retail, so ...
  289. //-----------------------------------------------------------------------------
  290. bool CSteamID::BValidExternalSteamID() const
  291. {
  292. if ( m_steamid.m_comp.m_EAccountType == k_EAccountTypePending )
  293. return false;
  294. if ( m_steamid.m_comp.m_EAccountType != k_EAccountTypeAnonGameServer && m_steamid.m_comp.m_EAccountType != k_EAccountTypeContentServer && m_steamid.m_comp.m_EAccountType != k_EAccountTypeAnonUser )
  295. {
  296. if ( m_steamid.m_comp.m_unAccountID == 0 && m_steamid.m_comp.m_unAccountInstance == 0 )
  297. return false;
  298. }
  299. return true;
  300. }
  301. #ifdef STEAM
  302. //-----------------------------------------------------------------------------
  303. // Purpose: Returns the matching chat steamID, with the default instance of 0
  304. // Input: SteamID, either a Clan or a Chat type
  305. // Output: SteamID with account type changed to chat, and the Clan flag set.
  306. // If account type was not chat to start with, instance will be set to 0
  307. //-----------------------------------------------------------------------------
  308. CSteamID ChatIDFromSteamID( const CSteamID &steamID )
  309. {
  310. if ( steamID.GetEAccountType() == k_EAccountTypeChat )
  311. return steamID;
  312. return ChatIDFromClanID( steamID );
  313. }
  314. //-----------------------------------------------------------------------------
  315. // Purpose: Returns the matching chat steamID, with the default instance of 0
  316. // Input: SteamID, either a Clan type or a Chat type w/ the Clan flag set
  317. // Output: SteamID with account type changed to clan.
  318. // If account type was not clan to start with, instance will be set to 0
  319. //-----------------------------------------------------------------------------
  320. CSteamID ClanIDFromSteamID( const CSteamID &steamID )
  321. {
  322. if ( steamID.GetEAccountType() == k_EAccountTypeClan )
  323. return steamID;
  324. return ClanIDFromChatID( steamID );
  325. }
  326. // Asserts steamID type before conversion
  327. CSteamID ChatIDFromClanID( const CSteamID &steamIDClan )
  328. {
  329. Assert( steamIDClan.GetEAccountType() == k_EAccountTypeClan );
  330. return CSteamID( steamIDClan.GetAccountID(), k_EChatInstanceFlagClan, steamIDClan.GetEUniverse(), k_EAccountTypeChat );
  331. }
  332. // Asserts steamID type before conversion
  333. CSteamID ClanIDFromChatID( const CSteamID &steamIDChat )
  334. {
  335. Assert( steamIDChat.GetEAccountType() == k_EAccountTypeChat );
  336. Assert( k_EChatInstanceFlagClan & steamIDChat.GetUnAccountInstance() );
  337. return CSteamID( steamIDChat.GetAccountID(), 0, steamIDChat.GetEUniverse(), k_EAccountTypeClan );
  338. }
  339. //-----------------------------------------------------------------------------
  340. // Purpose: CGameID "hidden" functions
  341. // move these somewhere else maybe
  342. //-----------------------------------------------------------------------------
  343. CGameID::CGameID( const char *pchGameID )
  344. {
  345. m_ulGameID = 0;
  346. sscanf( pchGameID, "%llu", &m_ulGameID );
  347. switch ( m_gameID.m_nType )
  348. {
  349. default:
  350. AssertMsg( false, "Unknown GameID type" );
  351. m_ulGameID = 0;
  352. break;
  353. case k_EGameIDTypeApp:
  354. case k_EGameIDTypeGameMod:
  355. case k_EGameIDTypeShortcut:
  356. case k_EGameIDTypeP2P:
  357. break;
  358. }
  359. }
  360. // renders this Game ID to string
  361. const char * CGameID::Render() const
  362. {
  363. // longest buffer is log10(2**64) == 20 + 1 == 21
  364. const int k_cBufLen = 21;
  365. const int k_cBufs = 4; // # of static bufs to use (so people can compose output with multiple calls to Render() )
  366. static char rgchBuf[k_cBufs][k_cBufLen];
  367. static int nBuf = 0;
  368. char * pchBuf = rgchBuf[nBuf]; // get pointer to current static buf
  369. nBuf ++; // use next buffer for next call to this method
  370. nBuf %= k_cBufs;
  371. V_snprintf( pchBuf, k_cBufLen, "%llu", m_ulGameID );
  372. return pchBuf;
  373. }
  374. // static method to render a uint64 representation of a Game ID to a string
  375. const char * CGameID::Render( uint64 ulGameID )
  376. {
  377. CGameID nGameID( ulGameID );
  378. return nGameID.Render();
  379. }
  380. #endif