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.

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