Team Fortress 2 Source Code as on 22/4/2020
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.

729 lines
21 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================
  7. #ifdef TF
  8. #include "steamcommon.h"
  9. #define INCLUDED_STEAM2_USERID_STRUCTS
  10. #include "steam/steamclientpublic.h"
  11. #endif
  12. #include "stdafx.h"
  13. #ifdef HL1
  14. #include "steamcommon.h"
  15. #include "steam/steamclientpublic.h"
  16. #endif
  17. // memdbgon must be the last include file in a .cpp file!!!
  18. #include "tier0/memdbgon.h"
  19. #ifndef UINT64_MAX
  20. #define UINT64_MAX ((uint64)-1)
  21. #endif
  22. static const char *DecimalToUint64( const char *pchStr, uint64 unLimit,
  23. uint64 *punVal )
  24. {
  25. const char *pchStart = pchStr;
  26. uint64 unVal = 0;
  27. while ( *pchStr >= '0' && *pchStr <= '9' )
  28. {
  29. uint64 unNext = unVal * 10;
  30. if ( unNext < unVal )
  31. {
  32. // 64-bit overflow.
  33. return NULL;
  34. }
  35. unVal = unNext + (uint64)( *pchStr - '0' );
  36. if ( unVal > unLimit )
  37. {
  38. // Limit overflow.
  39. return NULL;
  40. }
  41. pchStr++;
  42. }
  43. if ( pchStr == pchStart )
  44. {
  45. // No number at all.
  46. return NULL;
  47. }
  48. *punVal = unVal;
  49. return pchStr;
  50. }
  51. //-----------------------------------------------------------------------------
  52. // Purpose: Constructor
  53. // Input : pchSteamID - text representation of a Steam ID
  54. //-----------------------------------------------------------------------------
  55. CSteamID::CSteamID( const char *pchSteamID, EUniverse eDefaultUniverse /* = k_EUniverseInvalid */ )
  56. {
  57. SetFromString( pchSteamID, eDefaultUniverse );
  58. }
  59. //-----------------------------------------------------------------------------
  60. // Purpose: Initializes a steam ID from a string
  61. // Input : pchSteamID - text representation of a Steam ID
  62. //-----------------------------------------------------------------------------
  63. void CSteamID::SetFromString( const char *pchSteamID, EUniverse eDefaultUniverse )
  64. {
  65. uint nAccountID = 0;
  66. uint nInstance = 1;
  67. EUniverse eUniverse = eDefaultUniverse;
  68. EAccountType eAccountType = k_EAccountTypeIndividual;
  69. #ifdef DBGFLAG_ASSERT
  70. // TF Merge -- Assert is debug-only and we have unused variable warnings on :-/
  71. const char *pchSteamIDString = pchSteamID;
  72. #endif
  73. CSteamID StrictID;
  74. StrictID.SetFromStringStrict( pchSteamID, eDefaultUniverse );
  75. if ( *pchSteamID == '[' )
  76. pchSteamID++;
  77. // BUGBUG Rich use the Q_ functions
  78. if (*pchSteamID == 'A')
  79. {
  80. // This is test only
  81. pchSteamID++; // skip the A
  82. eAccountType = k_EAccountTypeAnonGameServer;
  83. if (*pchSteamID == '-' || *pchSteamID == ':')
  84. pchSteamID++; // skip the optional - or :
  85. if ( strchr( pchSteamID, '(' ) )
  86. sscanf( strchr( pchSteamID, '(' ), "(%u)", &nInstance );
  87. const char *pchColon = strchr( pchSteamID, ':' );
  88. if ( pchColon && *pchColon != 0 && strchr( pchColon+1, ':' ))
  89. {
  90. sscanf( pchSteamID, "%u:%u:%u", (uint*)&eUniverse, &nAccountID, &nInstance );
  91. }
  92. else if ( pchColon )
  93. {
  94. sscanf( pchSteamID, "%u:%u", (uint*)&eUniverse, &nAccountID );
  95. }
  96. else
  97. {
  98. sscanf( pchSteamID, "%u", &nAccountID );
  99. }
  100. if ( nAccountID == 0 )
  101. {
  102. // i dont care what number you entered
  103. CreateBlankAnonLogon(eUniverse);
  104. }
  105. else
  106. {
  107. InstancedSet( nAccountID, nInstance, eUniverse, eAccountType );
  108. }
  109. // Catch cases where we're allowing sloppy input that we
  110. // might not want to allow.
  111. AssertMsg1( this->operator==( StrictID ), "Steam ID does not pass strict parsing: '%s'", pchSteamIDString );
  112. return;
  113. }
  114. else if (*pchSteamID == 'G')
  115. {
  116. pchSteamID++; // skip the G
  117. eAccountType = k_EAccountTypeGameServer;
  118. if (*pchSteamID == '-' || *pchSteamID == ':')
  119. pchSteamID++; // skip the optional - or :
  120. }
  121. else if (*pchSteamID == 'C')
  122. {
  123. pchSteamID++; // skip the C
  124. eAccountType = k_EAccountTypeContentServer;
  125. if (*pchSteamID == '-' || *pchSteamID == ':')
  126. pchSteamID++; // skip the optional - or :
  127. }
  128. else if (*pchSteamID == 'g')
  129. {
  130. pchSteamID++; // skip the g
  131. eAccountType = k_EAccountTypeClan;
  132. nInstance = 0;
  133. if (*pchSteamID == '-' || *pchSteamID == ':')
  134. pchSteamID++; // skip the optional - or :
  135. }
  136. else if (*pchSteamID == 'c')
  137. {
  138. pchSteamID++; // skip the c
  139. eAccountType = k_EAccountTypeChat;
  140. nInstance = k_EChatInstanceFlagClan;
  141. if (*pchSteamID == '-' || *pchSteamID == ':')
  142. pchSteamID++; // skip the optional - or :
  143. }
  144. else if (*pchSteamID == 'L')
  145. {
  146. pchSteamID++; // skip the c
  147. eAccountType = k_EAccountTypeChat;
  148. nInstance = k_EChatInstanceFlagLobby;
  149. if (*pchSteamID == '-' || *pchSteamID == ':')
  150. pchSteamID++; // skip the optional - or :
  151. }
  152. else if (*pchSteamID == 'T')
  153. {
  154. pchSteamID++; // skip the T
  155. eAccountType = k_EAccountTypeChat;
  156. nInstance = 0; // Anon chat
  157. if (*pchSteamID == '-' || *pchSteamID == ':')
  158. pchSteamID++; // skip the optional - or :
  159. }
  160. else if (*pchSteamID == 'U')
  161. {
  162. pchSteamID++; // skip the U
  163. eAccountType = k_EAccountTypeIndividual;
  164. nInstance = 1;
  165. if (*pchSteamID == '-' || *pchSteamID == ':')
  166. pchSteamID++; // skip the optional - or :
  167. }
  168. else if (*pchSteamID == 'i')
  169. {
  170. pchSteamID++; // skip the i
  171. eAccountType = k_EAccountTypeInvalid;
  172. nInstance = 1;
  173. if (*pchSteamID == '-' || *pchSteamID == ':')
  174. pchSteamID++; // skip the optional - or :
  175. }
  176. if ( strchr( pchSteamID, ':' ) )
  177. {
  178. if (*pchSteamID == '[')
  179. pchSteamID++; // skip the optional [
  180. sscanf( pchSteamID, "%u:%u", (uint*)&eUniverse, &nAccountID );
  181. if ( eUniverse == k_EUniverseInvalid )
  182. eUniverse = eDefaultUniverse;
  183. }
  184. else
  185. {
  186. uint64 unVal64 = 0;
  187. sscanf( pchSteamID, "%llu", &unVal64 );
  188. if ( unVal64 > UINT_MAX )
  189. {
  190. // Assume a full 64-bit Steam ID.
  191. SetFromUint64( unVal64 );
  192. // Catch cases where we're allowing sloppy input that we
  193. // might not want to allow.
  194. AssertMsg1( this->operator==( StrictID ), "Steam ID does not pass strict parsing: '%s'", pchSteamIDString );
  195. return;
  196. }
  197. else
  198. {
  199. nAccountID = (uint)unVal64;
  200. }
  201. }
  202. Assert( (eUniverse > k_EUniverseInvalid) && (eUniverse < k_EUniverseMax) );
  203. InstancedSet( nAccountID, nInstance, eUniverse, eAccountType );
  204. // Catch cases where we're allowing sloppy input that we
  205. // might not want to allow.
  206. AssertMsg1( this->operator==( StrictID ), "Steam ID does not pass strict parsing: '%s'", pchSteamIDString );
  207. }
  208. // SetFromString allows many partially-correct strings, constraining how
  209. // we might be able to change things in the future.
  210. // SetFromStringStrict requires the exact string forms that we support
  211. // and is preferred when the caller knows it's safe to be strict.
  212. // Returns whether the string parsed correctly. The ID may
  213. // still be invalid even if the string parsed correctly.
  214. // If the string didn't parse correctly the ID will always be invalid.
  215. bool CSteamID::SetFromStringStrict( const char *pchSteamID, EUniverse eDefaultUniverse )
  216. {
  217. uint nAccountID = 0;
  218. uint nInstance = 1;
  219. uint unMaxVal = 2;
  220. EUniverse eUniverse = eDefaultUniverse;
  221. EAccountType eAccountType = k_EAccountTypeIndividual;
  222. char chPrefix;
  223. bool bBracket = false;
  224. bool bValid = true;
  225. uint64 unVal[3];
  226. const char *pchEnd;
  227. // Start invalid.
  228. Clear();
  229. if ( !pchSteamID )
  230. {
  231. return false;
  232. }
  233. if ( *pchSteamID == '[' )
  234. {
  235. pchSteamID++;
  236. bBracket = true;
  237. }
  238. chPrefix = *pchSteamID;
  239. switch( chPrefix )
  240. {
  241. case 'A':
  242. // This is test only
  243. eAccountType = k_EAccountTypeAnonGameServer;
  244. unMaxVal = 3;
  245. break;
  246. case 'G':
  247. eAccountType = k_EAccountTypeGameServer;
  248. break;
  249. case 'C':
  250. eAccountType = k_EAccountTypeContentServer;
  251. break;
  252. case 'g':
  253. eAccountType = k_EAccountTypeClan;
  254. nInstance = 0;
  255. break;
  256. case 'c':
  257. eAccountType = k_EAccountTypeChat;
  258. nInstance = k_EChatInstanceFlagClan;
  259. break;
  260. case 'L':
  261. eAccountType = k_EAccountTypeChat;
  262. nInstance = k_EChatInstanceFlagLobby;
  263. break;
  264. case 'T':
  265. eAccountType = k_EAccountTypeChat;
  266. nInstance = 0; // Anon chat
  267. break;
  268. case 'U':
  269. eAccountType = k_EAccountTypeIndividual;
  270. nInstance = 1;
  271. break;
  272. case 'i':
  273. eAccountType = k_EAccountTypeInvalid;
  274. nInstance = 1;
  275. break;
  276. default:
  277. // We're reserving other leading characters so
  278. // this should only be the plain-digits case.
  279. if (chPrefix < '0' || chPrefix > '9')
  280. {
  281. bValid = false;
  282. }
  283. chPrefix = 0;
  284. break;
  285. }
  286. if ( chPrefix )
  287. {
  288. pchSteamID++; // skip the prefix
  289. if (*pchSteamID == '-' || *pchSteamID == ':')
  290. pchSteamID++; // skip the optional - or :
  291. }
  292. uint unIdx = 0;
  293. for (;;)
  294. {
  295. pchEnd = DecimalToUint64( pchSteamID, UINT64_MAX, &unVal[unIdx] );
  296. if ( !pchEnd )
  297. {
  298. bValid = false;
  299. break;
  300. }
  301. unIdx++;
  302. // For 'A' we can have a trailing instance, which must
  303. // be the end of the string.
  304. if ( *pchEnd == '(' &&
  305. chPrefix == 'A' )
  306. {
  307. if ( unIdx > 2 )
  308. {
  309. // Two instance IDs provided.
  310. bValid = false;
  311. }
  312. pchEnd = DecimalToUint64( pchEnd + 1, k_unSteamAccountInstanceMask, &unVal[2] );
  313. if ( !pchEnd ||
  314. *pchEnd != ')' )
  315. {
  316. bValid = false;
  317. break;
  318. }
  319. else
  320. {
  321. nInstance = (uint)unVal[2];
  322. pchEnd++;
  323. if ( *pchEnd == ':' )
  324. {
  325. // Not expecting more values.
  326. bValid = false;
  327. break;
  328. }
  329. }
  330. }
  331. if ( *pchEnd != ':' )
  332. {
  333. if ( bBracket )
  334. {
  335. if ( *pchEnd != ']' ||
  336. *(pchEnd + 1) != 0 )
  337. {
  338. bValid = false;
  339. }
  340. }
  341. else if ( *pchEnd != 0 )
  342. {
  343. bValid = false;
  344. }
  345. break;
  346. }
  347. if ( unIdx >= unMaxVal )
  348. {
  349. bValid = false;
  350. break;
  351. }
  352. pchSteamID = pchEnd + 1;
  353. }
  354. if ( unIdx > 2 )
  355. {
  356. if ( unVal[2] <= k_unSteamAccountInstanceMask )
  357. {
  358. nInstance = (uint)unVal[2];
  359. }
  360. else
  361. {
  362. bValid = false;
  363. }
  364. }
  365. if ( unIdx > 1 )
  366. {
  367. if ( unVal[0] >= k_EUniverseInvalid &&
  368. unVal[0] < k_EUniverseMax )
  369. {
  370. eUniverse = (EUniverse)unVal[0];
  371. if ( eUniverse == k_EUniverseInvalid )
  372. eUniverse = eDefaultUniverse;
  373. }
  374. else
  375. {
  376. bValid = false;
  377. }
  378. if ( unVal[1] <= k_unSteamAccountIDMask )
  379. {
  380. nAccountID = (uint)unVal[1];
  381. }
  382. else
  383. {
  384. bValid = false;
  385. }
  386. }
  387. else if ( unIdx > 0 )
  388. {
  389. if ( unVal[0] <= k_unSteamAccountIDMask )
  390. {
  391. nAccountID = (uint)unVal[0];
  392. }
  393. else if ( !chPrefix )
  394. {
  395. if ( bValid )
  396. {
  397. SetFromUint64( unVal[0] );
  398. }
  399. return bValid;
  400. }
  401. else
  402. {
  403. bValid = false;
  404. }
  405. }
  406. else
  407. {
  408. bValid = false;
  409. }
  410. if ( bValid )
  411. {
  412. if ( chPrefix == 'A' )
  413. {
  414. if ( nAccountID == 0 )
  415. {
  416. // i dont care what number you entered
  417. CreateBlankAnonLogon(eUniverse);
  418. return bValid;
  419. }
  420. }
  421. InstancedSet( nAccountID, nInstance, eUniverse, eAccountType );
  422. }
  423. return bValid;
  424. }
  425. #if defined( INCLUDED_STEAM2_USERID_STRUCTS )
  426. //-----------------------------------------------------------------------------
  427. // Purpose: Initializes a steam ID from a Steam2 ID string
  428. // Input: pchSteam2ID - Steam2 ID (as a string #:#:#) to convert
  429. // eUniverse - universe this ID belongs to
  430. // Output: true if successful, false otherwise
  431. //-----------------------------------------------------------------------------
  432. bool CSteamID::SetFromSteam2String( const char *pchSteam2ID, EUniverse eUniverse )
  433. {
  434. Assert( pchSteam2ID );
  435. // Convert the Steam2 ID string to a Steam2 ID structure
  436. TSteamGlobalUserID steam2ID;
  437. steam2ID.m_SteamInstanceID = 0;
  438. steam2ID.m_SteamLocalUserID.Split.High32bits = 0;
  439. steam2ID.m_SteamLocalUserID.Split.Low32bits = 0;
  440. const char *pchTSteam2ID = pchSteam2ID;
  441. // Customer support is fond of entering steam IDs in the following form: STEAM_n:x:y
  442. const char *pchOptionalLeadString = "STEAM_";
  443. if ( V_strnicmp( pchSteam2ID, pchOptionalLeadString, V_strlen( pchOptionalLeadString ) ) == 0 )
  444. pchTSteam2ID = pchSteam2ID + V_strlen( pchOptionalLeadString );
  445. char cExtraCharCheck = 0;
  446. int cFieldConverted = sscanf( pchTSteam2ID, "%hu:%u:%u%c", &steam2ID.m_SteamInstanceID,
  447. &steam2ID.m_SteamLocalUserID.Split.High32bits, &steam2ID.m_SteamLocalUserID.Split.Low32bits, &cExtraCharCheck );
  448. // Validate the conversion ... a special case is steam2 instance ID 1 which is reserved for special DoD handling
  449. if ( cExtraCharCheck != 0 || cFieldConverted == EOF || cFieldConverted < 2 || ( cFieldConverted < 3 && steam2ID.m_SteamInstanceID != 1 ) )
  450. return false;
  451. // Now convert to steam ID from the Steam2 ID structure
  452. SetFromSteam2( &steam2ID, eUniverse );
  453. return true;
  454. }
  455. #endif
  456. //-----------------------------------------------------------------------------
  457. // Purpose: Renders the steam ID to a buffer. NOTE: for convenience of calling
  458. // code, this code returns a pointer to a static buffer and is NOT thread-safe.
  459. // Output: buffer with rendered Steam ID
  460. //-----------------------------------------------------------------------------
  461. const char * CSteamID::Render() const
  462. {
  463. // longest length of returned string is k_cBufLen
  464. // [A:%u:%u:%u]
  465. // %u == 10 * 3 + 6 == 36, plus terminator == 37
  466. const int k_cBufLen = 37;
  467. const int k_cBufs = 4; // # of static bufs to use (so people can compose output with multiple calls to Render() )
  468. static char rgchBuf[k_cBufs][k_cBufLen];
  469. static int nBuf = 0;
  470. char * pchBuf = rgchBuf[nBuf]; // get pointer to current static buf
  471. nBuf ++; // use next buffer for next call to this method
  472. nBuf %= k_cBufs;
  473. if ( k_EAccountTypeAnonGameServer == m_steamid.m_comp.m_EAccountType )
  474. {
  475. 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 );
  476. }
  477. else if ( k_EAccountTypeGameServer == m_steamid.m_comp.m_EAccountType )
  478. {
  479. V_snprintf( pchBuf, k_cBufLen, "[G:%u:%u]", m_steamid.m_comp.m_EUniverse, m_steamid.m_comp.m_unAccountID );
  480. }
  481. else if ( k_EAccountTypeMultiseat == m_steamid.m_comp.m_EAccountType )
  482. {
  483. 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 );
  484. }
  485. else if ( k_EAccountTypePending == m_steamid.m_comp.m_EAccountType )
  486. {
  487. V_snprintf( pchBuf, k_cBufLen, "[P:%u:%u]", m_steamid.m_comp.m_EUniverse, m_steamid.m_comp.m_unAccountID );
  488. }
  489. else if ( k_EAccountTypeContentServer == m_steamid.m_comp.m_EAccountType )
  490. {
  491. V_snprintf( pchBuf, k_cBufLen, "[C:%u:%u]", m_steamid.m_comp.m_EUniverse, m_steamid.m_comp.m_unAccountID );
  492. }
  493. else if ( k_EAccountTypeClan == m_steamid.m_comp.m_EAccountType )
  494. {
  495. // 'g' for "group"
  496. V_snprintf( pchBuf, k_cBufLen, "[g:%u:%u]", m_steamid.m_comp.m_EUniverse, m_steamid.m_comp.m_unAccountID );
  497. }
  498. else if ( k_EAccountTypeChat == m_steamid.m_comp.m_EAccountType )
  499. {
  500. if ( m_steamid.m_comp.m_unAccountInstance & k_EChatInstanceFlagClan )
  501. {
  502. V_snprintf( pchBuf, k_cBufLen, "[c:%u:%u]", m_steamid.m_comp.m_EUniverse, m_steamid.m_comp.m_unAccountID );
  503. }
  504. else if ( m_steamid.m_comp.m_unAccountInstance & k_EChatInstanceFlagLobby )
  505. {
  506. V_snprintf( pchBuf, k_cBufLen, "[L:%u:%u]", m_steamid.m_comp.m_EUniverse, m_steamid.m_comp.m_unAccountID );
  507. }
  508. else // Anon chat
  509. {
  510. V_snprintf( pchBuf, k_cBufLen, "[T:%u:%u]", m_steamid.m_comp.m_EUniverse, m_steamid.m_comp.m_unAccountID );
  511. }
  512. }
  513. else if ( k_EAccountTypeInvalid == m_steamid.m_comp.m_EAccountType )
  514. {
  515. V_snprintf( pchBuf, k_cBufLen, "[I:%u:%u]", m_steamid.m_comp.m_EUniverse, m_steamid.m_comp.m_unAccountID );
  516. }
  517. else if ( k_EAccountTypeIndividual == m_steamid.m_comp.m_EAccountType )
  518. {
  519. if ( m_steamid.m_comp.m_unAccountInstance != k_unSteamUserDesktopInstance )
  520. 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 );
  521. else
  522. V_snprintf( pchBuf, k_cBufLen, "[U:%u:%u]", m_steamid.m_comp.m_EUniverse, m_steamid.m_comp.m_unAccountID );
  523. }
  524. else if ( k_EAccountTypeAnonUser == m_steamid.m_comp.m_EAccountType )
  525. {
  526. V_snprintf( pchBuf, k_cBufLen, "[a:%u:%u]", m_steamid.m_comp.m_EUniverse, m_steamid.m_comp.m_unAccountID );
  527. }
  528. else
  529. {
  530. V_snprintf( pchBuf, k_cBufLen, "[i:%u:%u]", m_steamid.m_comp.m_EUniverse, m_steamid.m_comp.m_unAccountID );
  531. }
  532. return pchBuf;
  533. }
  534. //-----------------------------------------------------------------------------
  535. // Purpose: Renders the passed-in steam ID to a buffer. NOTE: for convenience of calling
  536. // code, this code returns a pointer to a static buffer and is NOT thread-safe.
  537. // Input: 64-bit representation of Steam ID to render
  538. // Output: buffer with rendered Steam ID
  539. //-----------------------------------------------------------------------------
  540. const char * CSteamID::Render( uint64 ulSteamID )
  541. {
  542. CSteamID steamID( ulSteamID );
  543. return steamID.Render();
  544. }
  545. //-----------------------------------------------------------------------------
  546. // Purpose: some steamIDs are for internal use only
  547. // This is really debug code, but we run with asserts on in retail, so ...
  548. //-----------------------------------------------------------------------------
  549. bool CSteamID::BValidExternalSteamID() const
  550. {
  551. if ( m_steamid.m_comp.m_EAccountType == k_EAccountTypePending )
  552. return false;
  553. 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 )
  554. {
  555. if ( m_steamid.m_comp.m_unAccountID == 0 && m_steamid.m_comp.m_unAccountInstance == 0 )
  556. return false;
  557. }
  558. return true;
  559. }
  560. #ifdef STEAM
  561. //-----------------------------------------------------------------------------
  562. // Purpose: Returns the matching chat steamID, with the default instance of 0
  563. // Input: SteamID, either a Clan or a Chat type
  564. // Output: SteamID with account type changed to chat, and the Clan flag set.
  565. // If account type was not chat to start with, instance will be set to 0
  566. //-----------------------------------------------------------------------------
  567. CSteamID ChatIDFromSteamID( const CSteamID &steamID )
  568. {
  569. if ( steamID.GetEAccountType() == k_EAccountTypeChat )
  570. return steamID;
  571. return ChatIDFromClanID( steamID );
  572. }
  573. //-----------------------------------------------------------------------------
  574. // Purpose: Returns the matching chat steamID, with the default instance of 0
  575. // Input: SteamID, either a Clan type or a Chat type w/ the Clan flag set
  576. // Output: SteamID with account type changed to clan.
  577. // If account type was not clan to start with, instance will be set to 0
  578. //-----------------------------------------------------------------------------
  579. CSteamID ClanIDFromSteamID( const CSteamID &steamID )
  580. {
  581. if ( steamID.GetEAccountType() == k_EAccountTypeClan )
  582. return steamID;
  583. return ClanIDFromChatID( steamID );
  584. }
  585. // Asserts steamID type before conversion
  586. CSteamID ChatIDFromClanID( const CSteamID &steamIDClan )
  587. {
  588. Assert( steamIDClan.GetEAccountType() == k_EAccountTypeClan );
  589. return CSteamID( steamIDClan.GetAccountID(), k_EChatInstanceFlagClan, steamIDClan.GetEUniverse(), k_EAccountTypeChat );
  590. }
  591. // Asserts steamID type before conversion
  592. CSteamID ClanIDFromChatID( const CSteamID &steamIDChat )
  593. {
  594. Assert( steamIDChat.GetEAccountType() == k_EAccountTypeChat );
  595. Assert( k_EChatInstanceFlagClan & steamIDChat.GetUnAccountInstance() );
  596. return CSteamID( steamIDChat.GetAccountID(), 0, steamIDChat.GetEUniverse(), k_EAccountTypeClan );
  597. }
  598. //-----------------------------------------------------------------------------
  599. // Purpose: CGameID "hidden" functions
  600. // move these somewhere else maybe
  601. //-----------------------------------------------------------------------------
  602. CGameID::CGameID( const char *pchGameID )
  603. {
  604. m_ulGameID = 0;
  605. sscanf( pchGameID, "%llu", &m_ulGameID );
  606. switch ( m_gameID.m_nType )
  607. {
  608. default:
  609. AssertMsg( false, "Unknown GameID type" );
  610. m_ulGameID = 0;
  611. break;
  612. case k_EGameIDTypeApp:
  613. case k_EGameIDTypeGameMod:
  614. case k_EGameIDTypeShortcut:
  615. case k_EGameIDTypeP2P:
  616. break;
  617. }
  618. }
  619. // renders this Game ID to string
  620. const char * CGameID::Render() const
  621. {
  622. // longest buffer is log10(2**64) == 20 + 1 == 21
  623. const int k_cBufLen = 21;
  624. const int k_cBufs = 4; // # of static bufs to use (so people can compose output with multiple calls to Render() )
  625. static char rgchBuf[k_cBufs][k_cBufLen];
  626. static int nBuf = 0;
  627. char * pchBuf = rgchBuf[nBuf]; // get pointer to current static buf
  628. nBuf ++; // use next buffer for next call to this method
  629. nBuf %= k_cBufs;
  630. V_snprintf( pchBuf, k_cBufLen, "%llu", m_ulGameID );
  631. return pchBuf;
  632. }
  633. // static method to render a uint64 representation of a Game ID to a string
  634. const char * CGameID::Render( uint64 ulGameID )
  635. {
  636. CGameID nGameID( ulGameID );
  637. return nGameID.Render();
  638. }
  639. #endif