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.

1425 lines
35 KiB

  1. //===== Copyright 1996-2005, Valve Corporation, All rights reserved. ======//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //
  7. //===========================================================================//
  8. #include "cvar.h"
  9. #include "gl_cvars.h"
  10. #include "tier1/convar.h"
  11. #include "filesystem.h"
  12. #include "filesystem_engine.h"
  13. #include "client.h"
  14. #include "server.h"
  15. #include "GameEventManager.h"
  16. #include "netmessages.h"
  17. #include "sv_main.h"
  18. #include "demo.h"
  19. #include <ctype.h>
  20. #include "vstdlib/vstrtools.h"
  21. #ifdef POSIX
  22. #include <wctype.h>
  23. #endif
  24. #ifdef _PS3
  25. #include <ps3/ps3_console.h>
  26. #endif
  27. #ifndef DEDICATED
  28. #include <vgui_controls/Controls.h>
  29. #include <vgui/ILocalize.h>
  30. #endif
  31. // memdbgon must be the last include file in a .cpp file!!!
  32. #include "tier0/memdbgon.h"
  33. //-----------------------------------------------------------------------------
  34. // Singleton CCvarUtilities
  35. //-----------------------------------------------------------------------------
  36. static CCvarUtilities g_CvarUtilities;
  37. CCvarUtilities *ConVarUtilities = &g_CvarUtilities;
  38. //-----------------------------------------------------------------------------
  39. // Purpose: Update clients/server when FCVAR_REPLICATED etc vars change
  40. //-----------------------------------------------------------------------------
  41. static void ConVarNetworkChangeCallback( IConVar *pConVar, const char *pOldValue, float flOldValue )
  42. {
  43. ConVarRef var( pConVar );
  44. if ( !pOldValue )
  45. {
  46. if ( var.GetFloat() == flOldValue )
  47. return;
  48. }
  49. else
  50. {
  51. if ( !Q_strcmp( var.GetString(), pOldValue ) )
  52. return;
  53. }
  54. if ( var.IsFlagSet( FCVAR_USERINFO ) )
  55. {
  56. #ifndef DEDICATED
  57. ACTIVE_SPLITSCREEN_PLAYER_GUARD( var.GetSplitScreenPlayerSlot() );
  58. // Are we not a server, but a client and have a change?
  59. if ( GetLocalClient().IsConnected() )
  60. {
  61. // send changed cvar to server
  62. CNETMsg_SetConVar_t convar( var.GetBaseName(), var.GetString() );
  63. GetLocalClient().m_NetChannel->SendNetMsg( convar );
  64. }
  65. #endif
  66. }
  67. // Log changes to server variables
  68. // Print to clients
  69. if ( var.IsFlagSet( FCVAR_NOTIFY ) )
  70. {
  71. IGameEvent *event = g_GameEventManager.CreateEvent( "server_cvar" );
  72. if ( event )
  73. {
  74. event->SetString( "cvarname", var.GetName() );
  75. if ( var.IsFlagSet( FCVAR_PROTECTED ) )
  76. {
  77. event->SetString("cvarvalue", "***PROTECTED***" );
  78. }
  79. else
  80. {
  81. event->SetString("cvarvalue", var.GetString() );
  82. }
  83. g_GameEventManager.FireEvent( event );
  84. }
  85. }
  86. // Force changes down to clients (if running server)
  87. if ( var.IsFlagSet( FCVAR_REPLICATED ) && sv.IsActive() )
  88. {
  89. SV_ReplicateConVarChange( static_cast< ConVar* >( pConVar ), var.GetString() );
  90. }
  91. }
  92. //-----------------------------------------------------------------------------
  93. // Implementation of the ICvarQuery interface
  94. //-----------------------------------------------------------------------------
  95. class CCvarQuery : public CBaseAppSystem< ICvarQuery >
  96. {
  97. public:
  98. bool m_bCallbackInstalled;
  99. CCvarQuery( void )
  100. {
  101. m_bCallbackInstalled = false;
  102. }
  103. virtual bool Connect( CreateInterfaceFn factory )
  104. {
  105. ICvar *pCVar = (ICvar*)factory( CVAR_INTERFACE_VERSION, 0 );
  106. if ( !pCVar )
  107. return false;
  108. pCVar->InstallCVarQuery( this );
  109. return true;
  110. }
  111. virtual InitReturnVal_t Init()
  112. {
  113. // If the value has changed, notify clients/server based on ConVar flags.
  114. // NOTE: this will only happen for non-FCVAR_NEVER_AS_STRING vars.
  115. // Also, this happened in SetDirect for older clients that don't have the
  116. // callback interface.
  117. if (! m_bCallbackInstalled )
  118. {
  119. m_bCallbackInstalled = true;
  120. g_pCVar->InstallGlobalChangeCallback( ConVarNetworkChangeCallback );
  121. }
  122. return INIT_OK;
  123. }
  124. virtual void Shutdown()
  125. {
  126. g_pCVar->RemoveGlobalChangeCallback( ConVarNetworkChangeCallback );
  127. m_bCallbackInstalled = false;
  128. }
  129. virtual void *QueryInterface( const char *pInterfaceName )
  130. {
  131. if ( !Q_stricmp( pInterfaceName, CVAR_QUERY_INTERFACE_VERSION ) )
  132. return (ICvarQuery*)this;
  133. return NULL;
  134. }
  135. // Purpose: Returns true if the commands can be aliased to one another
  136. // Either game/client .dll shared with engine,
  137. // or game and client dll shared and marked FCVAR_REPLICATED
  138. virtual bool AreConVarsLinkable( const ConVar *child, const ConVar *parent )
  139. {
  140. // Both parent and child must be marked replicated for this to work
  141. bool repchild = child->IsFlagSet( FCVAR_REPLICATED );
  142. bool repparent = parent->IsFlagSet( FCVAR_REPLICATED );
  143. if ( repchild && repparent )
  144. {
  145. // Never on protected vars
  146. if ( child->IsFlagSet( FCVAR_PROTECTED ) || parent->IsFlagSet( FCVAR_PROTECTED ) )
  147. {
  148. ConMsg( "FCVAR_REPLICATED can't also be FCVAR_PROTECTED (%s)\n", child->GetName() );
  149. return false;
  150. }
  151. // Only on ConVars
  152. if ( child->IsCommand() || parent->IsCommand() )
  153. {
  154. ConMsg( "FCVAR_REPLICATED not valid on ConCommands (%s)\n", child->GetName() );
  155. return false;
  156. }
  157. // One must be in client .dll and the other in the game .dll, or both in the engine
  158. if ( child->IsFlagSet( FCVAR_GAMEDLL ) && !parent->IsFlagSet( FCVAR_CLIENTDLL ) )
  159. {
  160. ConMsg( "For FCVAR_REPLICATED, ConVar must be defined in client and game .dlls (%s)\n", child->GetName() );
  161. return false;
  162. }
  163. if ( child->IsFlagSet( FCVAR_CLIENTDLL ) && !parent->IsFlagSet( FCVAR_GAMEDLL ) )
  164. {
  165. ConMsg( "For FCVAR_REPLICATED, ConVar must be defined in client and game .dlls (%s)\n", child->GetName() );
  166. return false;
  167. }
  168. // Allowable
  169. return true;
  170. }
  171. // Otherwise need both to allow linkage
  172. if ( repchild || repparent )
  173. {
  174. ConMsg( "Both ConVars must be marked FCVAR_REPLICATED for linkage to work (%s)\n", child->GetName() );
  175. return false;
  176. }
  177. if ( parent->IsFlagSet( FCVAR_CLIENTDLL ) )
  178. {
  179. ConMsg( "Parent cvar in client.dll not allowed (%s)\n", child->GetName() );
  180. return false;
  181. }
  182. if ( parent->IsFlagSet( FCVAR_GAMEDLL ) )
  183. {
  184. ConMsg( "Parent cvar in server.dll not allowed (%s)\n", child->GetName() );
  185. return false;
  186. }
  187. return true;
  188. }
  189. };
  190. //-----------------------------------------------------------------------------
  191. // Singleton
  192. //-----------------------------------------------------------------------------
  193. static CCvarQuery s_CvarQuery;
  194. EXPOSE_SINGLE_INTERFACE_GLOBALVAR( CCvarQuery, ICvarQuery, CVAR_QUERY_INTERFACE_VERSION, s_CvarQuery );
  195. void InstallConVarHook( void )
  196. {
  197. s_CvarQuery.Init();
  198. }
  199. //-----------------------------------------------------------------------------
  200. //
  201. // CVar utilities begins here
  202. //
  203. //-----------------------------------------------------------------------------
  204. static bool IsAllSpaces( const wchar_t *str )
  205. {
  206. const wchar_t *p = str;
  207. while ( p && *p )
  208. {
  209. if ( !iswspace( *p ) )
  210. return false;
  211. ++p;
  212. }
  213. return true;
  214. }
  215. //-----------------------------------------------------------------------------
  216. // Purpose:
  217. // Input : *var -
  218. // *value -
  219. //-----------------------------------------------------------------------------
  220. void CCvarUtilities::SetDirect( ConVar *var, const char *value )
  221. {
  222. const char *pszValue;
  223. char szNew[ 1024 ];
  224. // Bail early if we're trying to set a FCVAR_USERINFO cvar on a dedicated server
  225. if ( var->IsFlagSet( FCVAR_USERINFO ) )
  226. {
  227. if ( sv.IsDedicated() )
  228. {
  229. return;
  230. }
  231. }
  232. pszValue = value;
  233. // This cvar's string must only contain printable characters.
  234. // Strip out any other crap.
  235. // We'll fill in "empty" if nothing is left
  236. if ( var->IsFlagSet( FCVAR_PRINTABLEONLY ) )
  237. {
  238. wchar_t unicode[ 512 ];
  239. #ifndef DEDICATED
  240. if ( sv.IsDedicated() )
  241. {
  242. // Dedicated servers don't have g_pVGuiLocalize, so fall back
  243. V_UTF8ToUnicode( pszValue, unicode, sizeof( unicode ) );
  244. }
  245. else
  246. {
  247. g_pVGuiLocalize->ConvertANSIToUnicode( pszValue, unicode, sizeof( unicode ) );
  248. }
  249. #else
  250. V_UTF8ToUnicode( pszValue, unicode, sizeof( unicode ) );
  251. #endif
  252. wchar_t newUnicode[ 512 ];
  253. const wchar_t *pS;
  254. wchar_t *pD;
  255. // Clear out new string
  256. newUnicode[0] = L'\0';
  257. pS = unicode;
  258. pD = newUnicode;
  259. // Step through the string, only copying back in characters that are printable
  260. while ( *pS )
  261. {
  262. if ( iswcntrl( *pS ) || *pS == '~' )
  263. {
  264. pS++;
  265. continue;
  266. }
  267. *pD++ = *pS++;
  268. }
  269. // Terminate the new string
  270. *pD = L'\0';
  271. // If it's empty or all spaces, then insert a marker string
  272. if ( !wcslen( newUnicode ) || IsAllSpaces( newUnicode ) )
  273. {
  274. wcsncpy( newUnicode, L"#empty", ( sizeof( newUnicode ) / sizeof( wchar_t ) ) - 1 );
  275. newUnicode[ ( sizeof( newUnicode ) / sizeof( wchar_t ) ) - 1 ] = L'\0';
  276. }
  277. #ifndef DEDICATED
  278. if ( sv.IsDedicated() )
  279. {
  280. V_UnicodeToUTF8( newUnicode, szNew, sizeof( szNew ) );
  281. }
  282. else
  283. {
  284. g_pVGuiLocalize->ConvertUnicodeToANSI( newUnicode, szNew, sizeof( szNew ) );
  285. }
  286. #else
  287. V_UnicodeToUTF8( newUnicode, szNew, sizeof( szNew ) );
  288. #endif
  289. // Point the value here.
  290. pszValue = szNew;
  291. }
  292. if ( var->IsFlagSet( FCVAR_NEVER_AS_STRING ) )
  293. {
  294. var->SetValue( (float)atof( pszValue ) );
  295. }
  296. else
  297. {
  298. var->SetValue( pszValue );
  299. }
  300. }
  301. //-----------------------------------------------------------------------------
  302. // Purpose:
  303. // Output : Returns true on success, false on failure.
  304. //-----------------------------------------------------------------------------
  305. // If you are changing this, please take a look at IsValidToggleCommand()
  306. bool CCvarUtilities::IsCommand( const CCommand &args, const int iSplitscreenSlot /*= -1*/ )
  307. {
  308. int c = args.ArgC();
  309. if ( c == 0 )
  310. return false;
  311. ConVar *v;
  312. // check variables
  313. v = g_pCVar->FindVar( args[0] );
  314. if ( !v )
  315. return false;
  316. // adjust for split screen convars for slots 2, 3, 4
  317. if ( iSplitscreenSlot > 0 && v->IsFlagSet( FCVAR_SS ) )
  318. {
  319. char buf[512];
  320. Q_snprintf( buf, sizeof(buf), "%s%d", args[0], iSplitscreenSlot+1 );
  321. v = g_pCVar->FindVar( buf );
  322. }
  323. if ( !v )
  324. return false;
  325. // NOTE: Not checking for 'HIDDEN' here so we can actually set hidden convars
  326. if ( v->IsFlagSet(FCVAR_DEVELOPMENTONLY) )
  327. return false;
  328. // perform a variable print or set
  329. if ( c == 1 )
  330. {
  331. ConVar_PrintDescription( v );
  332. return true;
  333. }
  334. if ( v->IsFlagSet( FCVAR_SPONLY ) )
  335. {
  336. #ifndef DEDICATED
  337. // Connected to server?
  338. if ( GetBaseLocalClient().IsConnected() )
  339. {
  340. // Is it not a single player game?
  341. if ( GetBaseLocalClient().m_nMaxClients > 1 )
  342. {
  343. ConMsg( "Can't set %s in multiplayer\n", v->GetName() );
  344. return true;
  345. }
  346. }
  347. #endif
  348. }
  349. if ( v->IsFlagSet( FCVAR_NOT_CONNECTED ) )
  350. {
  351. #ifndef DEDICATED
  352. // Connected to server?
  353. if ( GetBaseLocalClient().IsConnected() )
  354. {
  355. extern IBaseClientDLL *g_ClientDLL;
  356. if ( v->IsFlagSet( FCVAR_USERINFO ) && g_ClientDLL && g_ClientDLL->IsConnectedUserInfoChangeAllowed( v ) )
  357. {
  358. // Client.dll is allowing the convar change
  359. }
  360. else
  361. {
  362. ConMsg( "Can't change %s when playing, disconnect from the server or switch team to spectators\n", v->GetName() );
  363. return true;
  364. }
  365. }
  366. #endif
  367. }
  368. // Allow cheat commands in singleplayer, debug, or multiplayer with sv_cheats on
  369. if ( v->IsFlagSet( FCVAR_CHEAT ) )
  370. {
  371. if ( !Host_IsSinglePlayerGame() && !CanCheat()
  372. #if !defined(DEDICATED)
  373. && !GetBaseLocalClient().ishltv
  374. #if defined( REPLAY_ENABLED )
  375. && !GetBaseLocalClient().isreplay
  376. #endif
  377. && !demoplayer->IsPlayingBack()
  378. #endif
  379. )
  380. {
  381. ConMsg( "Can't use cheat cvar %s in multiplayer, unless the server has sv_cheats set to 1.\n", v->GetName() );
  382. return true;
  383. }
  384. }
  385. // Text invoking the command was typed into the console, decide what to do with it
  386. // if this is a replicated ConVar, except don't worry about restrictions if playing a .dem file
  387. if ( v->IsFlagSet( FCVAR_REPLICATED )
  388. #if !defined(DEDICATED)
  389. && !demoplayer->IsPlayingBack()
  390. #endif
  391. )
  392. {
  393. #ifndef DEDICATED
  394. // If not running a server but possibly connected as a client, then
  395. // if the message came from console, don't process the command
  396. if ( !sv.IsActive()
  397. && !sv.IsLoading()
  398. && GetBaseLocalClient().IsConnected()
  399. )
  400. {
  401. ConMsg( "Can't change replicated ConVar %s from console of client, only server operator can change its value\n", v->GetName() );
  402. return true;
  403. }
  404. #endif
  405. }
  406. // Note that we don't want the tokenized list, send down the entire string
  407. // except for surrounding quotes
  408. char remaining[1024];
  409. const char *pArgS = args.ArgS();
  410. int nLen = Q_strlen( pArgS );
  411. bool bIsQuoted = pArgS[0] == '\"';
  412. if ( !bIsQuoted )
  413. {
  414. Q_strncpy( remaining, args.ArgS(), sizeof(remaining) );
  415. }
  416. else
  417. {
  418. --nLen;
  419. Q_strncpy( remaining, &pArgS[1], sizeof(remaining) );
  420. }
  421. // Now strip off any trailing spaces
  422. char *p = remaining + nLen - 1;
  423. while ( p >= remaining )
  424. {
  425. if ( *p > ' ' )
  426. break;
  427. *p-- = 0;
  428. }
  429. // Strip off ending quote
  430. if ( bIsQuoted && p >= remaining )
  431. {
  432. if ( *p == '\"' )
  433. {
  434. *p = 0;
  435. }
  436. }
  437. SetDirect( v, remaining );
  438. return true;
  439. }
  440. // This is a band-aid copied directly from IsCommand().
  441. bool CCvarUtilities::IsValidToggleCommand( const char *cmd )
  442. {
  443. ConVar *v;
  444. // check variables
  445. v = g_pCVar->FindVar ( cmd );
  446. if (!v)
  447. {
  448. ConMsg( "%s is not a valid cvar\n", cmd );
  449. return false;
  450. }
  451. if ( v->IsFlagSet(FCVAR_DEVELOPMENTONLY) || v->IsFlagSet(FCVAR_HIDDEN) )
  452. return false;
  453. if ( v->IsFlagSet( FCVAR_SPONLY ) )
  454. {
  455. #ifndef DEDICATED
  456. // Connected to server?
  457. if ( GetBaseLocalClient().IsConnected() )
  458. {
  459. // Is it not a single player game?
  460. if ( GetBaseLocalClient().m_nMaxClients > 1 )
  461. {
  462. ConMsg( "Can't set %s in multiplayer\n", v->GetName() );
  463. return false;
  464. }
  465. }
  466. #endif
  467. }
  468. if ( v->IsFlagSet( FCVAR_NOT_CONNECTED ) )
  469. {
  470. #ifndef DEDICATED
  471. // Connected to server?
  472. if ( GetBaseLocalClient().IsConnected() )
  473. {
  474. extern IBaseClientDLL *g_ClientDLL;
  475. if ( v->IsFlagSet( FCVAR_USERINFO ) && g_ClientDLL && g_ClientDLL->IsConnectedUserInfoChangeAllowed( v ) )
  476. {
  477. // Client.dll is allowing the convar change
  478. }
  479. else
  480. {
  481. ConMsg( "Can't change %s when playing, disconnect from the server or switch team to spectators\n", v->GetName() );
  482. return false;
  483. }
  484. }
  485. #endif
  486. }
  487. // Allow cheat commands in singleplayer, debug, or multiplayer with sv_cheats on
  488. if ( v->IsFlagSet( FCVAR_CHEAT ) )
  489. {
  490. if ( !Host_IsSinglePlayerGame() && !CanCheat()
  491. #if !defined(DEDICATED)
  492. && !demoplayer->IsPlayingBack()
  493. #endif
  494. )
  495. {
  496. ConMsg( "Can't use cheat cvar %s in multiplayer, unless the server has sv_cheats set to 1.\n", v->GetName() );
  497. return false;
  498. }
  499. }
  500. // Text invoking the command was typed into the console, decide what to do with it
  501. // if this is a replicated ConVar, except don't worry about restrictions if playing a .dem file
  502. if ( v->IsFlagSet( FCVAR_REPLICATED )
  503. #if !defined(DEDICATED)
  504. && !demoplayer->IsPlayingBack()
  505. #endif
  506. )
  507. {
  508. #ifndef DEDICATED
  509. // If not running a server but possibly connected as a client, then
  510. // if the message came from console, don't process the command
  511. if ( !sv.IsActive()
  512. && !sv.IsLoading()
  513. && GetBaseLocalClient().IsConnected()
  514. )
  515. {
  516. ConMsg( "Can't change replicated ConVar %s from console of client, only server operator can change its value\n", v->GetName() );
  517. return false;
  518. }
  519. #endif
  520. }
  521. return true;
  522. }
  523. void CCvarUtilities::ResetConVarsToDefaultValues( const char *pMatchStr )
  524. {
  525. ICvar::Iterator iter( g_pCVar );
  526. for ( iter.SetFirst() ; iter.IsValid() ; iter.Next() )
  527. {
  528. ConCommandBase *var = iter.Get();
  529. if ( var->IsCommand() )
  530. continue;
  531. ConVar *cv = (ConVar *)var;
  532. if ( ( ! pMatchStr ) || // null pattern match?
  533. ( memcmp( pMatchStr, cv->GetName(), strlen( pMatchStr ) ) == 0 ) // first chars match
  534. )
  535. {
  536. cv->Revert();
  537. }
  538. }
  539. }
  540. static bool CVarSortFunc( ConVar * const &lhs, ConVar * const &rhs )
  541. {
  542. return ( CaselessStringLessThan( lhs->GetName(), rhs->GetName() ) );
  543. }
  544. //-----------------------------------------------------------------------------
  545. // Purpose:
  546. // Input : *f -
  547. //-----------------------------------------------------------------------------
  548. void CCvarUtilities::WriteVariables( CUtlBuffer *buff, const int iSplitscreenSlot /*= -1*/, bool bSlotRequired /* = false */, void *pConvarsListVoid /*= NULL*/ )
  549. {
  550. CUtlRBTree< ConVar *, int > sorted( 0, 0, CVarSortFunc );
  551. CUtlVector< ConVar * > *pConvarsList = (CUtlVector< ConVar * > *)pConvarsListVoid;
  552. ICvar::Iterator iter( g_pCVar );
  553. for ( iter.SetFirst() ; iter.IsValid() ; iter.Next() )
  554. {
  555. ConCommandBase *var = iter.Get();
  556. if ( var->IsCommand() )
  557. continue;
  558. ConVar *cv = (ConVar *)var;
  559. bool archive = cv->IsFlagSet( IsGameConsole() ? FCVAR_ARCHIVE_GAMECONSOLE : FCVAR_ARCHIVE );
  560. if ( archive )
  561. {
  562. if ( iSplitscreenSlot >= 0 )
  563. {
  564. bool bSlotSpecificConvar = false;
  565. if ( cv->IsFlagSet( FCVAR_SS ) )
  566. {
  567. // only valid for the 0'th player
  568. if ( iSplitscreenSlot != 0 )
  569. {
  570. continue;
  571. }
  572. bSlotSpecificConvar = true;
  573. }
  574. if ( cv->IsFlagSet( FCVAR_SS_ADDED ) )
  575. {
  576. // which added player is this relevant to
  577. CSplitScreenAddedConVar *pCheck = dynamic_cast< CSplitScreenAddedConVar * >( cv );
  578. if ( pCheck && pCheck->GetSplitScreenPlayerSlot() != iSplitscreenSlot )
  579. {
  580. continue;
  581. }
  582. bSlotSpecificConvar = true;
  583. }
  584. if ( bSlotRequired != bSlotSpecificConvar )
  585. {
  586. continue;
  587. }
  588. }
  589. sorted.Insert( cv );
  590. }
  591. }
  592. for ( int i = sorted.FirstInorder(); i != sorted.InvalidIndex(); i = sorted.NextInorder( i ) )
  593. {
  594. ConVar *var = sorted[ i ];
  595. // If we are saving per-controller, we always want to write the base name ( joy_inverty as opposed to joy_inverty2 )
  596. const char *name = ( iSplitscreenSlot >= 0 ) ? var->GetBaseName() : var->GetName();
  597. DevMsg( 2, "%s \"%s\"\n", name, var->GetString() );
  598. if ( buff )
  599. buff->Printf( "%s \"%s\"\n", name, var->GetString() );
  600. if ( pConvarsList )
  601. pConvarsList->AddToTail( var );
  602. }
  603. }
  604. static void Cmd_SetPlayer( int slot, const CCommand &args )
  605. {
  606. if ( slot >= host_state.max_splitscreen_players )
  607. {
  608. DevMsg( 1, "ignore: %d '%s'\n", slot, args.ArgS() );
  609. return;
  610. }
  611. // Strip the cmdN and pass the rest of the command to the appropriate slot
  612. Cbuf_AddText( (ECommandTarget_t)slot, args.ArgS() );
  613. }
  614. CON_COMMAND( cmd1, "sets userinfo string for split screen player in slot 1" )
  615. {
  616. Cmd_SetPlayer( 0, args );
  617. }
  618. CON_COMMAND( cmd2, "sets userinfo string for split screen player in slot 2" )
  619. {
  620. Cmd_SetPlayer( 1, args );
  621. }
  622. CON_COMMAND( cmd3, "sets userinfo string for split screen player in slot 3" )
  623. {
  624. Cmd_SetPlayer( 2, args );
  625. }
  626. CON_COMMAND( cmd4, "sets userinfo string for split screen player in slot 4" )
  627. {
  628. Cmd_SetPlayer( 3, args );
  629. }
  630. static char *StripTabsAndReturns( const char *inbuffer, char *outbuffer, int outbufferSize )
  631. {
  632. char *out = outbuffer;
  633. const char *i = inbuffer;
  634. char *o = out;
  635. out[ 0 ] = 0;
  636. while ( *i && o - out < outbufferSize - 1 )
  637. {
  638. if ( *i == '\n' ||
  639. *i == '\r' ||
  640. *i == '\t' )
  641. {
  642. *o++ = ' ';
  643. i++;
  644. continue;
  645. }
  646. if ( *i == '\"' )
  647. {
  648. *o++ = '\'';
  649. i++;
  650. continue;
  651. }
  652. *o++ = *i++;
  653. }
  654. *o = '\0';
  655. return out;
  656. }
  657. static char *StripQuotes( const char *inbuffer, char *outbuffer, int outbufferSize )
  658. {
  659. char *out = outbuffer;
  660. const char *i = inbuffer;
  661. char *o = out;
  662. out[ 0 ] = 0;
  663. while ( *i && o - out < outbufferSize - 1 )
  664. {
  665. if ( *i == '\"' )
  666. {
  667. *o++ = '\'';
  668. i++;
  669. continue;
  670. }
  671. *o++ = *i++;
  672. }
  673. *o = '\0';
  674. return out;
  675. }
  676. struct ConVarFlags_t
  677. {
  678. int bit;
  679. const char *desc;
  680. const char *shortdesc;
  681. };
  682. #define CONVARFLAG( x, y ) { FCVAR_##x, #x, #y }
  683. static ConVarFlags_t g_ConVarFlags[]=
  684. {
  685. // CONVARFLAG( UNREGISTERED, "u" ),
  686. CONVARFLAG( ARCHIVE, "a" ),
  687. CONVARFLAG( SPONLY, "sp" ),
  688. CONVARFLAG( GAMEDLL, "sv" ),
  689. CONVARFLAG( CHEAT, "cheat" ),
  690. CONVARFLAG( USERINFO, "user" ),
  691. CONVARFLAG( NOTIFY, "nf" ),
  692. CONVARFLAG( PROTECTED, "prot" ),
  693. CONVARFLAG( PRINTABLEONLY, "print" ),
  694. CONVARFLAG( UNLOGGED, "log" ),
  695. CONVARFLAG( NEVER_AS_STRING, "numeric" ),
  696. CONVARFLAG( REPLICATED, "rep" ),
  697. CONVARFLAG( DEMO, "demo" ),
  698. CONVARFLAG( DONTRECORD, "norecord" ),
  699. CONVARFLAG( SERVER_CAN_EXECUTE, "server_can_execute" ),
  700. CONVARFLAG( CLIENTCMD_CAN_EXECUTE, "clientcmd_can_execute" ),
  701. CONVARFLAG( CLIENTDLL, "cl" ),
  702. CONVARFLAG( SS, "ss" ),
  703. CONVARFLAG( SS_ADDED, "ss_added" ),
  704. CONVARFLAG( DEVELOPMENTONLY, "dev_only" ),
  705. };
  706. static void PrintListHeader( FileHandle_t& f )
  707. {
  708. char csvflagstr[ 1024 ];
  709. csvflagstr[ 0 ] = 0;
  710. int c = ARRAYSIZE( g_ConVarFlags );
  711. for ( int i = 0 ; i < c; ++i )
  712. {
  713. char csvf[ 64 ];
  714. ConVarFlags_t & entry = g_ConVarFlags[ i ];
  715. Q_snprintf( csvf, sizeof( csvf ), "\"%s\",", entry.desc );
  716. Q_strncat( csvflagstr, csvf, sizeof( csvflagstr ), COPY_ALL_CHARACTERS );
  717. }
  718. g_pFileSystem->FPrintf( f,"\"%s\",\"%s\",%s,\"%s\"\n", "Name", "Value", csvflagstr, "Help Text" );
  719. }
  720. //-----------------------------------------------------------------------------
  721. // Purpose:
  722. // Input : *var -
  723. // *f -
  724. //-----------------------------------------------------------------------------
  725. static void PrintCvar( const ConVar *var, bool logging, FileHandle_t& f )
  726. {
  727. char flagstr[ 128 ];
  728. char csvflagstr[ 1024 ];
  729. flagstr[ 0 ] = 0;
  730. csvflagstr[ 0 ] = 0;
  731. int c = ARRAYSIZE( g_ConVarFlags );
  732. for ( int i = 0 ; i < c; ++i )
  733. {
  734. char f[ 32 ];
  735. char csvf[ 64 ];
  736. ConVarFlags_t & entry = g_ConVarFlags[ i ];
  737. if ( var->IsFlagSet( entry.bit ) )
  738. {
  739. Q_snprintf( f, sizeof( f ), ", %s", entry.shortdesc );
  740. Q_strncat( flagstr, f, sizeof( flagstr ), COPY_ALL_CHARACTERS );
  741. Q_snprintf( csvf, sizeof( csvf ), "\"%s\",", entry.desc );
  742. }
  743. else
  744. {
  745. Q_snprintf( csvf, sizeof( csvf ), "," );
  746. }
  747. Q_strncat( csvflagstr, csvf, sizeof( csvflagstr ), COPY_ALL_CHARACTERS );
  748. }
  749. char valstr[ 32 ];
  750. char tempbuff[128];
  751. // Clean up integers
  752. if ( var->GetInt() == (int)var->GetFloat() )
  753. {
  754. Q_snprintf(valstr, sizeof( valstr ), "%-8i", var->GetInt() );
  755. }
  756. else
  757. {
  758. Q_snprintf(valstr, sizeof( valstr ), "%-8.3f", var->GetFloat() );
  759. }
  760. // Print to console
  761. ConMsg( "%-40s : %-8s : %-16s : %s\n", var->GetName(), valstr, flagstr, StripTabsAndReturns( var->GetHelpText(), tempbuff, sizeof(tempbuff) ) );
  762. if ( logging )
  763. {
  764. g_pFileSystem->FPrintf( f,"\"%s\",\"%s\",%s,\"%s\"\n", var->GetName(), valstr, csvflagstr, StripQuotes( var->GetHelpText(), tempbuff, sizeof(tempbuff) ) );
  765. }
  766. }
  767. static void PrintCommand( const ConCommand *cmd, bool logging, FileHandle_t& f )
  768. {
  769. // Print to console
  770. char tempbuff[128];
  771. ConMsg ("%-40s : %-8s : %-16s : %s\n",cmd->GetName(), "cmd", "", StripTabsAndReturns( cmd->GetHelpText(), tempbuff, sizeof(tempbuff) ) );
  772. if ( logging )
  773. {
  774. char emptyflags[ 256 ];
  775. emptyflags[ 0 ] = 0;
  776. int c = ARRAYSIZE( g_ConVarFlags );
  777. for ( int i = 0; i < c; ++i )
  778. {
  779. char csvf[ 64 ];
  780. Q_snprintf( csvf, sizeof( csvf ), "," );
  781. Q_strncat( emptyflags, csvf, sizeof( emptyflags ), COPY_ALL_CHARACTERS );
  782. }
  783. // Names staring with +/- need to be wrapped in single quotes
  784. char name[ 256 ];
  785. Q_snprintf( name, sizeof( name ), "%s", cmd->GetName() );
  786. if ( name[ 0 ] == '+' || name[ 0 ] == '-' )
  787. {
  788. Q_snprintf( name, sizeof( name ), "'%s'", cmd->GetName() );
  789. }
  790. char tempbuff[128];
  791. g_pFileSystem->FPrintf( f, "\"%s\",\"%s\",%s,\"%s\"\n", name, "cmd", emptyflags, StripQuotes( cmd->GetHelpText(), tempbuff, sizeof(tempbuff) ) );
  792. }
  793. }
  794. static bool ConCommandBaseLessFunc( const ConCommandBase * const &lhs, const ConCommandBase * const &rhs )
  795. {
  796. const char *left = lhs->GetName();
  797. const char *right = rhs->GetName();
  798. if ( *left == '-' || *left == '+' )
  799. left++;
  800. if ( *right == '-' || *right == '+' )
  801. right++;
  802. return ( Q_stricmp( left, right ) < 0 );
  803. }
  804. //-----------------------------------------------------------------------------
  805. // Purpose:
  806. // Output : void CCvar::CvarList_f
  807. //-----------------------------------------------------------------------------
  808. void CCvarUtilities::CvarList( const CCommand &args )
  809. {
  810. const ConCommandBase *var; // Temporary Pointer to cvars
  811. int iArgs; // Argument count
  812. const char *partial = NULL; // Partial cvar to search for...
  813. // E.eg
  814. int ipLen = 0; // Length of the partial cvar
  815. FileHandle_t f = FILESYSTEM_INVALID_HANDLE; // FilePointer for logging
  816. bool bLogging = false;
  817. // Are we logging?
  818. iArgs = args.ArgC(); // Get count
  819. // Print usage?
  820. if ( iArgs == 2 && !Q_strcasecmp( args[1],"?" ) )
  821. {
  822. ConMsg( "cvarlist: [log logfile] [ partial ]\n" );
  823. return;
  824. }
  825. if ( !Q_strcasecmp( args[1],"log" ) && iArgs >= 3 )
  826. {
  827. char fn[256];
  828. Q_snprintf( fn, sizeof( fn ), "%s", args[2] );
  829. f = g_pFileSystem->Open( fn,"wb" );
  830. if ( f )
  831. {
  832. bLogging = true;
  833. }
  834. else
  835. {
  836. ConMsg( "Couldn't open '%s' for writing!\n", fn );
  837. return;
  838. }
  839. if ( iArgs == 4 )
  840. {
  841. partial = args[ 3 ];
  842. ipLen = Q_strlen( partial );
  843. }
  844. }
  845. else
  846. {
  847. partial = args[ 1 ];
  848. ipLen = Q_strlen( partial );
  849. }
  850. // Banner
  851. ConMsg( "cvar list\n--------------\n" );
  852. CUtlRBTree< const ConCommandBase * > sorted( 0, 0, ConCommandBaseLessFunc );
  853. // Loop through cvars...
  854. ICvar::Iterator iter( g_pCVar );
  855. for ( iter.SetFirst() ; iter.IsValid() ; iter.Next() )
  856. {
  857. ConCommandBase *var = iter.Get();
  858. bool print = false;
  859. if ( var->IsFlagSet(FCVAR_DEVELOPMENTONLY) || var->IsFlagSet(FCVAR_HIDDEN) )
  860. continue;
  861. if (partial) // Partial string searching?
  862. {
  863. if ( !Q_strncasecmp( var->GetName(), partial, ipLen ) )
  864. {
  865. print = true;
  866. }
  867. }
  868. else
  869. {
  870. print = true;
  871. }
  872. if ( !print )
  873. continue;
  874. sorted.Insert( var );
  875. }
  876. if ( bLogging )
  877. {
  878. PrintListHeader( f );
  879. }
  880. for ( int i = sorted.FirstInorder(); i != sorted.InvalidIndex(); i = sorted.NextInorder( i ) )
  881. {
  882. var = sorted[ i ];
  883. if ( var->IsCommand() )
  884. {
  885. PrintCommand( (ConCommand *)var, bLogging, f );
  886. }
  887. else
  888. {
  889. PrintCvar( (ConVar *)var, bLogging, f );
  890. }
  891. }
  892. // Show total and syntax help...
  893. if ( partial && partial[0] )
  894. {
  895. ConMsg("--------------\n%3i convars/concommands for [%s]\n", sorted.Count(), partial );
  896. }
  897. else
  898. {
  899. ConMsg("--------------\n%3i total convars/concommands\n", sorted.Count() );
  900. }
  901. if ( bLogging )
  902. {
  903. g_pFileSystem->Close( f );
  904. }
  905. }
  906. //-----------------------------------------------------------------------------
  907. // Purpose: Removes the FCVAR_DEVELOPMENTONLY flag from all cvars, making them accessible
  908. //-----------------------------------------------------------------------------
  909. void CCvarUtilities::EnableDevCvars()
  910. {
  911. // Loop through cvars...
  912. ICvar::Iterator iter( g_pCVar );
  913. for ( iter.SetFirst() ; iter.IsValid() ; iter.Next() )
  914. {
  915. ConCommandBase *var = iter.Get();
  916. // remove flag from all cvars
  917. var->RemoveFlags( FCVAR_DEVELOPMENTONLY );
  918. }
  919. }
  920. //-----------------------------------------------------------------------------
  921. // Purpose:
  922. // Input :
  923. // Output : int
  924. //-----------------------------------------------------------------------------
  925. int CCvarUtilities::CountVariablesWithFlags( int flags )
  926. {
  927. int c = 0;
  928. ICvar::Iterator iter( g_pCVar );
  929. for ( iter.SetFirst() ; iter.IsValid() ; iter.Next() )
  930. {
  931. ConCommandBase *var = iter.Get();
  932. if ( var->IsCommand() )
  933. continue;
  934. if ( var->IsFlagSet( flags ) )
  935. {
  936. ++c;
  937. }
  938. }
  939. return c;
  940. }
  941. //-----------------------------------------------------------------------------
  942. // Purpose:
  943. //-----------------------------------------------------------------------------
  944. void CCvarUtilities::CvarHelp( const CCommand &args )
  945. {
  946. const char *search;
  947. const ConCommandBase *var;
  948. if ( args.ArgC() != 2 )
  949. {
  950. ConMsg( "Usage: help <cvarname>\n" );
  951. return;
  952. }
  953. // Get name of var to find
  954. search = args[1];
  955. // Search for it
  956. var = g_pCVar->FindCommandBase( search );
  957. if ( !var )
  958. {
  959. ConMsg( "help: no cvar or command named %s\n", search );
  960. return;
  961. }
  962. // Show info
  963. ConVar_PrintDescription( var );
  964. }
  965. //-----------------------------------------------------------------------------
  966. // Purpose:
  967. //-----------------------------------------------------------------------------
  968. void CCvarUtilities::CvarDifferences( const CCommand &args )
  969. {
  970. ICvar::Iterator iter( g_pCVar );
  971. for ( iter.SetFirst() ; iter.IsValid() ; iter.Next() )
  972. {
  973. ConCommandBase *var = iter.Get();
  974. if ( var->IsCommand( ) )
  975. continue;
  976. if ( var->IsFlagSet(FCVAR_DEVELOPMENTONLY) || var->IsFlagSet(FCVAR_HIDDEN) )
  977. continue;
  978. if ( !Q_stricmp( ((ConVar *)var)->GetDefault(), ((ConVar *)var)->GetString() ) )
  979. continue;
  980. ConVar_PrintDescription( (ConVar *)var );
  981. }
  982. }
  983. //-----------------------------------------------------------------------------
  984. // Purpose: Toggles a cvar on/off, or cycles through a set of values
  985. //-----------------------------------------------------------------------------
  986. void CCvarUtilities::CvarToggle( const CCommand &args )
  987. {
  988. int i;
  989. int c = args.ArgC();
  990. if ( c < 2 )
  991. {
  992. ConMsg( "Usage: toggle <cvarname> [value1] [value2] [value3]...\n" );
  993. return;
  994. }
  995. ConVar *var = g_pCVar->FindVar( args[1] );
  996. if ( !IsValidToggleCommand( args[1] ) )
  997. {
  998. return;
  999. }
  1000. if ( c == 2 )
  1001. {
  1002. // just toggle it on and off
  1003. var->SetValue( !var->GetBool() );
  1004. ConVar_PrintDescription( var );
  1005. }
  1006. else
  1007. {
  1008. // look for the current value in the command arguments
  1009. for( i = 2; i < c; i++ )
  1010. {
  1011. if ( !Q_strcmp( var->GetString(), args[ i ] ) )
  1012. break;
  1013. }
  1014. // choose the next one
  1015. i++;
  1016. // if we didn't find it, or were at the last value in the command arguments, use the 1st argument
  1017. if ( i >= c )
  1018. {
  1019. i = 2;
  1020. }
  1021. var->SetValue( args[ i ] );
  1022. ConVar_PrintDescription( var );
  1023. }
  1024. }
  1025. int CCvarUtilities::CvarFindFlagsCompletionCallback( const char *partial, char commands[ COMMAND_COMPLETION_MAXITEMS ][ COMMAND_COMPLETION_ITEM_LENGTH ] )
  1026. {
  1027. int flagC = ARRAYSIZE( g_ConVarFlags );
  1028. char const *pcmd = "findflags ";
  1029. int len = Q_strlen( partial );
  1030. if ( len < Q_strlen( pcmd ) )
  1031. {
  1032. int i = 0;
  1033. for ( ; i < MIN( flagC, COMMAND_COMPLETION_MAXITEMS ); i++ )
  1034. {
  1035. Q_snprintf( commands[ i ], sizeof( commands[ i ] ), "%s %s", pcmd, g_ConVarFlags[i].desc );
  1036. Q_strlower( commands[ i ] );
  1037. }
  1038. return i;
  1039. }
  1040. char const *pSub = partial + Q_strlen( pcmd );
  1041. int nSubLen = Q_strlen( pSub );
  1042. int values = 0;
  1043. for ( int i=0; i < flagC; ++i )
  1044. {
  1045. if ( Q_strnicmp( g_ConVarFlags[i].desc, pSub, nSubLen ) )
  1046. continue;
  1047. Q_snprintf( commands[ values ], sizeof( commands[ values ] ), "%s %s", pcmd, g_ConVarFlags[i].desc );
  1048. Q_strlower( commands[ values ] );
  1049. ++values;
  1050. if ( values >= COMMAND_COMPLETION_MAXITEMS )
  1051. break;
  1052. }
  1053. return values;
  1054. }
  1055. void CCvarUtilities::CvarFindFlags_f( const CCommand &args )
  1056. {
  1057. if ( args.ArgC() < 2 )
  1058. {
  1059. ConMsg( "Usage: findflags <string>\n" );
  1060. ConMsg( "Available flags to search for: \n" );
  1061. for ( int i=0; i < ARRAYSIZE( g_ConVarFlags ); i++ )
  1062. {
  1063. ConMsg( " - %s\n", g_ConVarFlags[i].desc );
  1064. }
  1065. return;
  1066. }
  1067. // Get substring to find
  1068. const char *search = args[1];
  1069. // Loop through vars and print out findings
  1070. ICvar::Iterator iter( g_pCVar );
  1071. for ( iter.SetFirst() ; iter.IsValid() ; iter.Next() )
  1072. {
  1073. ConCommandBase *var = iter.Get();
  1074. if ( var->IsFlagSet(FCVAR_DEVELOPMENTONLY) || var->IsFlagSet(FCVAR_HIDDEN) )
  1075. continue;
  1076. for ( int j=0; j < ARRAYSIZE( g_ConVarFlags ); ++j )
  1077. {
  1078. if ( !var->IsFlagSet( g_ConVarFlags[j].bit ) )
  1079. continue;
  1080. if ( Q_stricmp( g_ConVarFlags[j].desc, search ) )
  1081. continue;
  1082. ConVar_PrintDescription( var );
  1083. }
  1084. }
  1085. }
  1086. int FindFlagsCompletionCallback( const char *partial, char commands[ COMMAND_COMPLETION_MAXITEMS ][ COMMAND_COMPLETION_ITEM_LENGTH ] )
  1087. {
  1088. return ConVarUtilities->CvarFindFlagsCompletionCallback( partial, commands );
  1089. }
  1090. //-----------------------------------------------------------------------------
  1091. // Purpose: Hook to command
  1092. //-----------------------------------------------------------------------------
  1093. CON_COMMAND_F_COMPLETION( findflags, "Find concommands by flags.", 0, FindFlagsCompletionCallback )
  1094. {
  1095. ConVarUtilities->CvarFindFlags_f( args );
  1096. }
  1097. //-----------------------------------------------------------------------------
  1098. // Purpose: Hook to command
  1099. //-----------------------------------------------------------------------------
  1100. CON_COMMAND( cvarlist, "Show the list of convars/concommands." )
  1101. {
  1102. ConVarUtilities->CvarList( args );
  1103. }
  1104. //-----------------------------------------------------------------------------
  1105. // Purpose: Print help text for cvar
  1106. //-----------------------------------------------------------------------------
  1107. CON_COMMAND( help, "Find help about a convar/concommand." )
  1108. {
  1109. ConVarUtilities->CvarHelp( args );
  1110. }
  1111. //-----------------------------------------------------------------------------
  1112. // Purpose:
  1113. //-----------------------------------------------------------------------------
  1114. CON_COMMAND( differences, "Show all convars which are not at their default values." )
  1115. {
  1116. ConVarUtilities->CvarDifferences( args );
  1117. }
  1118. //-----------------------------------------------------------------------------
  1119. // Purpose:
  1120. //-----------------------------------------------------------------------------
  1121. CON_COMMAND( toggle, "Toggles a convar on or off, or cycles through a set of values." )
  1122. {
  1123. ConVarUtilities->CvarToggle( args );
  1124. }
  1125. void ResetGameConVarsToDefaults( void )
  1126. {
  1127. #if defined( LEFT4DEAD )
  1128. ConVarRef testprocess( "test_progression_loop" );
  1129. ConVarUtilities->ResetConVarsToDefaultValues( "z_" );
  1130. if ( ! testprocess.GetInt() )
  1131. {
  1132. ConVarUtilities->ResetConVarsToDefaultValues( "sb_" );
  1133. }
  1134. ConVarUtilities->ResetConVarsToDefaultValues( "survivor_" );
  1135. ConVarUtilities->ResetConVarsToDefaultValues( "director_" );
  1136. ConVarUtilities->ResetConVarsToDefaultValues( "intensity_" );
  1137. ConVarUtilities->ResetConVarsToDefaultValues( "rescue_" );
  1138. ConVarUtilities->ResetConVarsToDefaultValues( "tongue_" );
  1139. ConVarUtilities->ResetConVarsToDefaultValues( "inferno_" );
  1140. ConVarUtilities->ResetConVarsToDefaultValues( "boomer_" );
  1141. ConVarUtilities->ResetConVarsToDefaultValues( "hunter_" );
  1142. ConVarUtilities->ResetConVarsToDefaultValues( "smoker_" );
  1143. ConVarUtilities->ResetConVarsToDefaultValues( "tank_" );
  1144. ConVarUtilities->ResetConVarsToDefaultValues( "nav_" );
  1145. #endif
  1146. }
  1147. CON_COMMAND_F( reset_gameconvars, "Reset a bunch of game convars to default values", FCVAR_CHEAT )
  1148. {
  1149. ResetGameConVarsToDefaults();
  1150. }
  1151. //-----------------------------------------------------------------------------
  1152. // Purpose: Send the cvars to VXConsole
  1153. //-----------------------------------------------------------------------------
  1154. #if defined( USE_VXCONSOLE )
  1155. CON_COMMAND( getcvars, "" )
  1156. {
  1157. {
  1158. // avoid noisy requests
  1159. // outer logic to prevent multiple requests more complicated than doing just this
  1160. #if defined( _X360 )
  1161. bool bConnected = XBX_IsConsoleConnected();
  1162. if ( !bConnected )
  1163. {
  1164. return;
  1165. }
  1166. #endif
  1167. static float s_flLastPublishTime = 0;
  1168. if ( s_flLastPublishTime && Plat_FloatTime() < s_flLastPublishTime + 2.0f )
  1169. {
  1170. return;
  1171. }
  1172. s_flLastPublishTime = Plat_FloatTime();
  1173. }
  1174. #if defined( _X360 )
  1175. // get the version from the image
  1176. // regardles of where the image came from (DVD, HDD) this cracks the embedded version info
  1177. int nVersion = 0;
  1178. if ( !IsCert() )
  1179. {
  1180. HANDLE hFile = CreateFile( "d:\\version.xtx", GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
  1181. if ( hFile != INVALID_HANDLE_VALUE )
  1182. {
  1183. DWORD nFileSize = GetFileSize( hFile, NULL );
  1184. if ( nFileSize != (DWORD)-1 && nFileSize > 0 )
  1185. {
  1186. char versionData[1024];
  1187. DWORD nBufferSize = MIN( nFileSize, sizeof( versionData ) - 1 );
  1188. DWORD nBytesRead = 0;
  1189. BOOL bResult = ReadFile( hFile, versionData, nBufferSize, &nBytesRead, NULL );
  1190. if ( bResult )
  1191. {
  1192. versionData[nBytesRead] = '\0';
  1193. nVersion = atoi( versionData );
  1194. }
  1195. }
  1196. CloseHandle( hFile );
  1197. }
  1198. }
  1199. XBX_rVersion( nVersion );
  1200. #endif
  1201. // Host_Init() will be calling us again, so defer this expensive operation until then
  1202. if ( host_initialized )
  1203. {
  1204. #ifdef _PS3
  1205. if ( g_pValvePS3Console )
  1206. {
  1207. g_pCVar->PublishToVXConsole();
  1208. }
  1209. #else
  1210. g_pCVar->PublishToVXConsole();
  1211. #endif
  1212. }
  1213. }
  1214. #endif