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.

899 lines
25 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //
  7. //===========================================================================//
  8. #include "vstdlib/cvar.h"
  9. #include <ctype.h>
  10. #include "tier0/icommandline.h"
  11. #include "tier1/utlrbtree.h"
  12. #include "tier1/strtools.h"
  13. #include "tier1/KeyValues.h"
  14. #include "tier1/convar.h"
  15. #include "tier0/vprof.h"
  16. #include "tier1/tier1.h"
  17. #include "tier1/utlbuffer.h"
  18. #ifdef _X360
  19. #include "xbox/xbox_console.h"
  20. #endif
  21. #ifdef POSIX
  22. #include <wctype.h>
  23. #include <wchar.h>
  24. #endif
  25. // memdbgon must be the last include file in a .cpp file!!!
  26. #include "tier0/memdbgon.h"
  27. //-----------------------------------------------------------------------------
  28. // Default implementation of CvarQuery
  29. //-----------------------------------------------------------------------------
  30. class CDefaultCvarQuery : public CBaseAppSystem< ICvarQuery >
  31. {
  32. public:
  33. virtual void *QueryInterface( const char *pInterfaceName )
  34. {
  35. if ( !Q_stricmp( pInterfaceName, CVAR_QUERY_INTERFACE_VERSION ) )
  36. return (ICvarQuery*)this;
  37. return NULL;
  38. }
  39. virtual bool AreConVarsLinkable( const ConVar *child, const ConVar *parent )
  40. {
  41. return true;
  42. }
  43. };
  44. static CDefaultCvarQuery s_DefaultCvarQuery;
  45. static ICvarQuery *s_pCVarQuery = NULL;
  46. //-----------------------------------------------------------------------------
  47. // Default implementation
  48. //-----------------------------------------------------------------------------
  49. class CCvar : public ICvar
  50. {
  51. public:
  52. CCvar();
  53. // Methods of IAppSystem
  54. virtual bool Connect( CreateInterfaceFn factory );
  55. virtual void Disconnect();
  56. virtual void *QueryInterface( const char *pInterfaceName );
  57. virtual InitReturnVal_t Init();
  58. virtual void Shutdown();
  59. // Inherited from ICVar
  60. virtual CVarDLLIdentifier_t AllocateDLLIdentifier();
  61. virtual void RegisterConCommand( ConCommandBase *pCommandBase );
  62. virtual void UnregisterConCommand( ConCommandBase *pCommandBase );
  63. virtual void UnregisterConCommands( CVarDLLIdentifier_t id );
  64. virtual const char* GetCommandLineValue( const char *pVariableName );
  65. virtual ConCommandBase *FindCommandBase( const char *name );
  66. virtual const ConCommandBase *FindCommandBase( const char *name ) const;
  67. virtual ConVar *FindVar ( const char *var_name );
  68. virtual const ConVar *FindVar ( const char *var_name ) const;
  69. virtual ConCommand *FindCommand( const char *name );
  70. virtual const ConCommand *FindCommand( const char *name ) const;
  71. virtual ConCommandBase *GetCommands( void );
  72. virtual const ConCommandBase *GetCommands( void ) const;
  73. virtual void InstallGlobalChangeCallback( FnChangeCallback_t callback );
  74. virtual void RemoveGlobalChangeCallback( FnChangeCallback_t callback );
  75. virtual void CallGlobalChangeCallbacks( ConVar *var, const char *pOldString, float flOldValue );
  76. virtual void InstallConsoleDisplayFunc( IConsoleDisplayFunc* pDisplayFunc );
  77. virtual void RemoveConsoleDisplayFunc( IConsoleDisplayFunc* pDisplayFunc );
  78. virtual void ConsoleColorPrintf( const Color& clr, const char *pFormat, ... ) const;
  79. virtual void ConsolePrintf( const char *pFormat, ... ) const;
  80. virtual void ConsoleDPrintf( const char *pFormat, ... ) const;
  81. virtual void RevertFlaggedConVars( int nFlag );
  82. virtual void InstallCVarQuery( ICvarQuery *pQuery );
  83. #if defined( _X360 )
  84. virtual void PublishToVXConsole( );
  85. #endif
  86. virtual bool IsMaterialThreadSetAllowed( ) const;
  87. virtual void QueueMaterialThreadSetValue( ConVar *pConVar, const char *pValue );
  88. virtual void QueueMaterialThreadSetValue( ConVar *pConVar, int nValue );
  89. virtual void QueueMaterialThreadSetValue( ConVar *pConVar, float flValue );
  90. virtual bool HasQueuedMaterialThreadConVarSets() const;
  91. virtual int ProcessQueuedMaterialThreadConVarSets();
  92. private:
  93. enum
  94. {
  95. CONSOLE_COLOR_PRINT = 0,
  96. CONSOLE_PRINT,
  97. CONSOLE_DPRINT,
  98. };
  99. void DisplayQueuedMessages( );
  100. CUtlVector< FnChangeCallback_t > m_GlobalChangeCallbacks;
  101. CUtlVector< IConsoleDisplayFunc* > m_DisplayFuncs;
  102. int m_nNextDLLIdentifier;
  103. ConCommandBase *m_pConCommandList;
  104. // temporary console area so we can store prints before console display funs are installed
  105. mutable CUtlBuffer m_TempConsoleBuffer;
  106. protected:
  107. // internals for ICVarIterator
  108. class CCVarIteratorInternal : public ICVarIteratorInternal
  109. {
  110. public:
  111. CCVarIteratorInternal( CCvar *outer )
  112. : m_pOuter( outer )
  113. //, m_pHash( &outer->m_CommandHash ), // remember my CCvar,
  114. //m_hashIter( -1, -1 ) // and invalid iterator
  115. , m_pCur( NULL )
  116. {}
  117. virtual void SetFirst( void );
  118. virtual void Next( void );
  119. virtual bool IsValid( void );
  120. virtual ConCommandBase *Get( void );
  121. protected:
  122. CCvar * const m_pOuter;
  123. //CConCommandHash * const m_pHash;
  124. //CConCommandHash::CCommandHashIterator_t m_hashIter;
  125. ConCommandBase *m_pCur;
  126. };
  127. virtual ICVarIteratorInternal *FactoryInternalIterator( void );
  128. friend class CCVarIteratorInternal;
  129. enum ConVarSetType_t
  130. {
  131. CONVAR_SET_STRING = 0,
  132. CONVAR_SET_INT,
  133. CONVAR_SET_FLOAT,
  134. };
  135. struct QueuedConVarSet_t
  136. {
  137. ConVar *m_pConVar;
  138. ConVarSetType_t m_nType;
  139. int m_nInt;
  140. float m_flFloat;
  141. CUtlString m_String;
  142. };
  143. CUtlVector< QueuedConVarSet_t > m_QueuedConVarSets;
  144. bool m_bMaterialSystemThreadSetAllowed;
  145. private:
  146. // Standard console commands -- DO NOT PLACE ANY HIGHER THAN HERE BECAUSE THESE MUST BE THE FIRST TO DESTRUCT
  147. CON_COMMAND_MEMBER_F( CCvar, "find", Find, "Find concommands with the specified string in their name/help text.", 0 )
  148. };
  149. void CCvar::CCVarIteratorInternal::SetFirst( void ) RESTRICT
  150. {
  151. //m_hashIter = m_pHash->First();
  152. m_pCur = m_pOuter->GetCommands();
  153. }
  154. void CCvar::CCVarIteratorInternal::Next( void ) RESTRICT
  155. {
  156. //m_hashIter = m_pHash->Next( m_hashIter );
  157. if ( m_pCur )
  158. m_pCur = m_pCur->GetNext();
  159. }
  160. bool CCvar::CCVarIteratorInternal::IsValid( void ) RESTRICT
  161. {
  162. //return m_pHash->IsValidIterator( m_hashIter );
  163. return m_pCur != NULL;
  164. }
  165. ConCommandBase *CCvar::CCVarIteratorInternal::Get( void ) RESTRICT
  166. {
  167. Assert( IsValid( ) );
  168. //return (*m_pHash)[m_hashIter];
  169. return m_pCur;
  170. }
  171. ICvar::ICVarIteratorInternal *CCvar::FactoryInternalIterator( void )
  172. {
  173. return new CCVarIteratorInternal( this );
  174. }
  175. //-----------------------------------------------------------------------------
  176. // Factor for CVars
  177. //-----------------------------------------------------------------------------
  178. static CCvar s_Cvar;
  179. EXPOSE_SINGLE_INTERFACE_GLOBALVAR( CCvar, ICvar, CVAR_INTERFACE_VERSION, s_Cvar );
  180. //-----------------------------------------------------------------------------
  181. // Returns a CVar dictionary for tool usage
  182. //-----------------------------------------------------------------------------
  183. CreateInterfaceFn VStdLib_GetICVarFactory()
  184. {
  185. return Sys_GetFactoryThis();
  186. }
  187. //-----------------------------------------------------------------------------
  188. // Constructor
  189. //-----------------------------------------------------------------------------
  190. CCvar::CCvar() : m_TempConsoleBuffer( 0, 1024 )
  191. {
  192. m_nNextDLLIdentifier = 0;
  193. m_pConCommandList = NULL;
  194. m_bMaterialSystemThreadSetAllowed = false;
  195. }
  196. //-----------------------------------------------------------------------------
  197. // Methods of IAppSystem
  198. //-----------------------------------------------------------------------------
  199. bool CCvar::Connect( CreateInterfaceFn factory )
  200. {
  201. ConnectTier1Libraries( &factory, 1 );
  202. s_pCVarQuery = (ICvarQuery*)factory( CVAR_QUERY_INTERFACE_VERSION, NULL );
  203. if ( !s_pCVarQuery )
  204. {
  205. s_pCVarQuery = &s_DefaultCvarQuery;
  206. }
  207. ConVar_Register();
  208. return true;
  209. }
  210. void CCvar::Disconnect()
  211. {
  212. ConVar_Unregister();
  213. s_pCVarQuery = NULL;
  214. DisconnectTier1Libraries();
  215. }
  216. InitReturnVal_t CCvar::Init()
  217. {
  218. return INIT_OK;
  219. }
  220. void CCvar::Shutdown()
  221. {
  222. }
  223. void *CCvar::QueryInterface( const char *pInterfaceName )
  224. {
  225. // We implement the ICvar interface
  226. if ( !V_strcmp( pInterfaceName, CVAR_INTERFACE_VERSION ) )
  227. return (ICvar*)this;
  228. return NULL;
  229. }
  230. //-----------------------------------------------------------------------------
  231. // Method allowing the engine ICvarQuery interface to take over
  232. //-----------------------------------------------------------------------------
  233. void CCvar::InstallCVarQuery( ICvarQuery *pQuery )
  234. {
  235. Assert( s_pCVarQuery == &s_DefaultCvarQuery );
  236. s_pCVarQuery = pQuery ? pQuery : &s_DefaultCvarQuery;
  237. }
  238. //-----------------------------------------------------------------------------
  239. // Used by DLLs to be able to unregister all their commands + convars
  240. //-----------------------------------------------------------------------------
  241. CVarDLLIdentifier_t CCvar::AllocateDLLIdentifier()
  242. {
  243. return m_nNextDLLIdentifier++;
  244. }
  245. //-----------------------------------------------------------------------------
  246. // Purpose:
  247. // Input : *variable -
  248. //-----------------------------------------------------------------------------
  249. void CCvar::RegisterConCommand( ConCommandBase *variable )
  250. {
  251. // Already registered
  252. if ( variable->IsRegistered() )
  253. return;
  254. variable->m_bRegistered = true;
  255. const char *pName = variable->GetName();
  256. if ( !pName || !pName[0] )
  257. {
  258. variable->m_pNext = NULL;
  259. return;
  260. }
  261. // If the variable is already defined, then setup the new variable as a proxy to it.
  262. const ConCommandBase *pOther = FindVar( variable->GetName() );
  263. if ( pOther )
  264. {
  265. if ( variable->IsCommand() || pOther->IsCommand() )
  266. {
  267. Warning( "WARNING: unable to link %s and %s because one or more is a ConCommand.\n", variable->GetName(), pOther->GetName() );
  268. }
  269. else
  270. {
  271. // This cast is ok because we make sure they're ConVars above.
  272. const ConVar *pChildVar = static_cast< const ConVar* >( variable );
  273. const ConVar *pParentVar = static_cast< const ConVar* >( pOther );
  274. // See if it's a valid linkage
  275. if ( s_pCVarQuery->AreConVarsLinkable( pChildVar, pParentVar ) )
  276. {
  277. // Make sure the default values are the same (but only spew about this for FCVAR_REPLICATED)
  278. if( pChildVar->m_pszDefaultValue && pParentVar->m_pszDefaultValue &&
  279. pChildVar->IsFlagSet( FCVAR_REPLICATED ) && pParentVar->IsFlagSet( FCVAR_REPLICATED ) )
  280. {
  281. if( Q_stricmp( pChildVar->m_pszDefaultValue, pParentVar->m_pszDefaultValue ) != 0 )
  282. {
  283. Warning( "Parent and child ConVars with different default values! %s child: %s parent: %s (parent wins)\n",
  284. variable->GetName(), pChildVar->m_pszDefaultValue, pParentVar->m_pszDefaultValue );
  285. }
  286. }
  287. const_cast<ConVar*>( pChildVar )->m_pParent = const_cast<ConVar*>( pParentVar )->m_pParent;
  288. // Absorb material thread related convar flags
  289. const_cast<ConVar*>( pParentVar )->m_nFlags |= pChildVar->m_nFlags & ( FCVAR_MATERIAL_THREAD_MASK | FCVAR_ACCESSIBLE_FROM_THREADS );
  290. // check the parent's callbacks and slam if doesn't have, warn if both have callbacks
  291. if( pChildVar->m_fnChangeCallback )
  292. {
  293. if ( !pParentVar->m_fnChangeCallback )
  294. {
  295. const_cast<ConVar*>( pParentVar )->m_fnChangeCallback = pChildVar->m_fnChangeCallback;
  296. }
  297. else
  298. {
  299. Warning( "Convar %s has multiple different change callbacks\n", variable->GetName() );
  300. }
  301. }
  302. // make sure we don't have conflicting help strings.
  303. if ( pChildVar->m_pszHelpString && Q_strlen( pChildVar->m_pszHelpString ) != 0 )
  304. {
  305. if ( pParentVar->m_pszHelpString && Q_strlen( pParentVar->m_pszHelpString ) != 0 )
  306. {
  307. if ( Q_stricmp( pParentVar->m_pszHelpString, pChildVar->m_pszHelpString ) != 0 )
  308. {
  309. Warning( "Convar %s has multiple help strings:\n\tparent (wins): \"%s\"\n\tchild: \"%s\"\n",
  310. variable->GetName(), pParentVar->m_pszHelpString, pChildVar->m_pszHelpString );
  311. }
  312. }
  313. else
  314. {
  315. const_cast<ConVar *>( pParentVar )->m_pszHelpString = pChildVar->m_pszHelpString;
  316. }
  317. }
  318. // make sure we don't have conflicting FCVAR_CHEAT flags.
  319. if ( ( pChildVar->m_nFlags & FCVAR_CHEAT ) != ( pParentVar->m_nFlags & FCVAR_CHEAT ) )
  320. {
  321. Warning( "Convar %s has conflicting FCVAR_CHEAT flags (child: %s, parent: %s, parent wins)\n",
  322. variable->GetName(), ( pChildVar->m_nFlags & FCVAR_CHEAT ) ? "FCVAR_CHEAT" : "no FCVAR_CHEAT",
  323. ( pParentVar->m_nFlags & FCVAR_CHEAT ) ? "FCVAR_CHEAT" : "no FCVAR_CHEAT" );
  324. }
  325. // make sure we don't have conflicting FCVAR_REPLICATED flags.
  326. if ( ( pChildVar->m_nFlags & FCVAR_REPLICATED ) != ( pParentVar->m_nFlags & FCVAR_REPLICATED ) )
  327. {
  328. Warning( "Convar %s has conflicting FCVAR_REPLICATED flags (child: %s, parent: %s, parent wins)\n",
  329. variable->GetName(), ( pChildVar->m_nFlags & FCVAR_REPLICATED ) ? "FCVAR_REPLICATED" : "no FCVAR_REPLICATED",
  330. ( pParentVar->m_nFlags & FCVAR_REPLICATED ) ? "FCVAR_REPLICATED" : "no FCVAR_REPLICATED" );
  331. }
  332. // make sure we don't have conflicting FCVAR_DONTRECORD flags.
  333. if ( ( pChildVar->m_nFlags & FCVAR_DONTRECORD ) != ( pParentVar->m_nFlags & FCVAR_DONTRECORD ) )
  334. {
  335. Warning( "Convar %s has conflicting FCVAR_DONTRECORD flags (child: %s, parent: %s, parent wins)\n",
  336. variable->GetName(), ( pChildVar->m_nFlags & FCVAR_DONTRECORD ) ? "FCVAR_DONTRECORD" : "no FCVAR_DONTRECORD",
  337. ( pParentVar->m_nFlags & FCVAR_DONTRECORD ) ? "FCVAR_DONTRECORD" : "no FCVAR_DONTRECORD" );
  338. }
  339. }
  340. }
  341. variable->m_pNext = NULL;
  342. return;
  343. }
  344. // link the variable in
  345. variable->m_pNext = m_pConCommandList;
  346. m_pConCommandList = variable;
  347. }
  348. void CCvar::UnregisterConCommand( ConCommandBase *pCommandToRemove )
  349. {
  350. // Not registered? Don't bother
  351. if ( !pCommandToRemove->IsRegistered() )
  352. return;
  353. pCommandToRemove->m_bRegistered = false;
  354. // FIXME: Should we make this a doubly-linked list? Would remove faster
  355. ConCommandBase *pPrev = NULL;
  356. for( ConCommandBase *pCommand = m_pConCommandList; pCommand; pCommand = pCommand->m_pNext )
  357. {
  358. if ( pCommand != pCommandToRemove )
  359. {
  360. pPrev = pCommand;
  361. continue;
  362. }
  363. if ( pPrev == NULL )
  364. {
  365. m_pConCommandList = pCommand->m_pNext;
  366. }
  367. else
  368. {
  369. pPrev->m_pNext = pCommand->m_pNext;
  370. }
  371. pCommand->m_pNext = NULL;
  372. break;
  373. }
  374. }
  375. // Crash here in TF2, so I'm adding some debugging stuff.
  376. #ifdef WIN32
  377. #pragma optimize( "", off )
  378. #endif
  379. void CCvar::UnregisterConCommands( CVarDLLIdentifier_t id )
  380. {
  381. ConCommandBase *pNewList;
  382. ConCommandBase *pCommand, *pNext;
  383. int iCommandsLooped = 0;
  384. pNewList = NULL;
  385. pCommand = m_pConCommandList;
  386. while ( pCommand )
  387. {
  388. pNext = pCommand->m_pNext;
  389. if ( pCommand->GetDLLIdentifier() != id )
  390. {
  391. pCommand->m_pNext = pNewList;
  392. pNewList = pCommand;
  393. }
  394. else
  395. {
  396. // Unlink
  397. pCommand->m_bRegistered = false;
  398. pCommand->m_pNext = NULL;
  399. }
  400. pCommand = pNext;
  401. iCommandsLooped++;
  402. }
  403. m_pConCommandList = pNewList;
  404. }
  405. #ifdef WIN32
  406. #pragma optimize( "", on )
  407. #endif
  408. //-----------------------------------------------------------------------------
  409. // Finds base commands
  410. //-----------------------------------------------------------------------------
  411. const ConCommandBase *CCvar::FindCommandBase( const char *name ) const
  412. {
  413. const ConCommandBase *cmd = GetCommands();
  414. for ( ; cmd; cmd = cmd->GetNext() )
  415. {
  416. if ( !Q_stricmp( name, cmd->GetName() ) )
  417. return cmd;
  418. }
  419. return NULL;
  420. }
  421. ConCommandBase *CCvar::FindCommandBase( const char *name )
  422. {
  423. ConCommandBase *cmd = GetCommands();
  424. for ( ; cmd; cmd = cmd->GetNext() )
  425. {
  426. if ( !Q_stricmp( name, cmd->GetName() ) )
  427. return cmd;
  428. }
  429. return NULL;
  430. }
  431. //-----------------------------------------------------------------------------
  432. // Purpose Finds ConVars
  433. //-----------------------------------------------------------------------------
  434. const ConVar *CCvar::FindVar( const char *var_name ) const
  435. {
  436. VPROF_INCREMENT_COUNTER( "CCvar::FindVar", 1 );
  437. VPROF( "CCvar::FindVar" );
  438. const ConCommandBase *var = FindCommandBase( var_name );
  439. if ( !var || var->IsCommand() )
  440. return NULL;
  441. return static_cast<const ConVar*>(var);
  442. }
  443. ConVar *CCvar::FindVar( const char *var_name )
  444. {
  445. VPROF_INCREMENT_COUNTER( "CCvar::FindVar", 1 );
  446. VPROF( "CCvar::FindVar" );
  447. ConCommandBase *var = FindCommandBase( var_name );
  448. if ( !var || var->IsCommand() )
  449. return NULL;
  450. return static_cast<ConVar*>( var );
  451. }
  452. //-----------------------------------------------------------------------------
  453. // Purpose Finds ConCommands
  454. //-----------------------------------------------------------------------------
  455. const ConCommand *CCvar::FindCommand( const char *pCommandName ) const
  456. {
  457. const ConCommandBase *var = FindCommandBase( pCommandName );
  458. if ( !var || !var->IsCommand() )
  459. return NULL;
  460. return static_cast<const ConCommand*>(var);
  461. }
  462. ConCommand *CCvar::FindCommand( const char *pCommandName )
  463. {
  464. ConCommandBase *var = FindCommandBase( pCommandName );
  465. if ( !var || !var->IsCommand() )
  466. return NULL;
  467. return static_cast<ConCommand*>( var );
  468. }
  469. const char* CCvar::GetCommandLineValue( const char *pVariableName )
  470. {
  471. int nLen = Q_strlen(pVariableName);
  472. char *pSearch = (char*)stackalloc( nLen + 2 );
  473. pSearch[0] = '+';
  474. memcpy( &pSearch[1], pVariableName, nLen + 1 );
  475. return CommandLine()->ParmValue( pSearch );
  476. }
  477. //-----------------------------------------------------------------------------
  478. // Purpose:
  479. //-----------------------------------------------------------------------------
  480. ConCommandBase *CCvar::GetCommands( void )
  481. {
  482. return m_pConCommandList;
  483. }
  484. const ConCommandBase *CCvar::GetCommands( void ) const
  485. {
  486. return m_pConCommandList;
  487. }
  488. //-----------------------------------------------------------------------------
  489. // Install, remove global callbacks
  490. //-----------------------------------------------------------------------------
  491. void CCvar::InstallGlobalChangeCallback( FnChangeCallback_t callback )
  492. {
  493. Assert( callback && m_GlobalChangeCallbacks.Find( callback ) < 0 );
  494. m_GlobalChangeCallbacks.AddToTail( callback );
  495. }
  496. void CCvar::RemoveGlobalChangeCallback( FnChangeCallback_t callback )
  497. {
  498. Assert( callback );
  499. m_GlobalChangeCallbacks.FindAndRemove( callback );
  500. }
  501. //-----------------------------------------------------------------------------
  502. // Purpose:
  503. //-----------------------------------------------------------------------------
  504. void CCvar::CallGlobalChangeCallbacks( ConVar *var, const char *pOldString, float flOldValue )
  505. {
  506. int nCallbackCount = m_GlobalChangeCallbacks.Count();
  507. for ( int i = 0; i < nCallbackCount; ++i )
  508. {
  509. (*m_GlobalChangeCallbacks[i])( var, pOldString, flOldValue );
  510. }
  511. }
  512. //-----------------------------------------------------------------------------
  513. // Sets convars containing the flags to their default value
  514. //-----------------------------------------------------------------------------
  515. void CCvar::RevertFlaggedConVars( int nFlag )
  516. {
  517. for (const ConCommandBase *var= GetCommands() ; var ; var=var->GetNext())
  518. {
  519. if ( var->IsCommand() )
  520. continue;
  521. ConVar *pCvar = ( ConVar * )var;
  522. if ( !pCvar->IsFlagSet( nFlag ) )
  523. continue;
  524. // It's == to the default value, don't count
  525. if ( !Q_stricmp( pCvar->GetDefault(), pCvar->GetString() ) )
  526. continue;
  527. pCvar->Revert();
  528. // DevMsg( "%s = \"%s\" (reverted)\n", cvar->GetName(), cvar->GetString() );
  529. }
  530. }
  531. //-----------------------------------------------------------------------------
  532. // Deal with queued material system convars
  533. //-----------------------------------------------------------------------------
  534. bool CCvar::IsMaterialThreadSetAllowed( ) const
  535. {
  536. Assert( ThreadInMainThread() );
  537. return m_bMaterialSystemThreadSetAllowed;
  538. }
  539. void CCvar::QueueMaterialThreadSetValue( ConVar *pConVar, const char *pValue )
  540. {
  541. Assert( ThreadInMainThread() );
  542. int j = m_QueuedConVarSets.AddToTail();
  543. m_QueuedConVarSets[j].m_pConVar = pConVar;
  544. m_QueuedConVarSets[j].m_nType = CONVAR_SET_STRING;
  545. m_QueuedConVarSets[j].m_String = pValue;
  546. }
  547. void CCvar::QueueMaterialThreadSetValue( ConVar *pConVar, int nValue )
  548. {
  549. Assert( ThreadInMainThread() );
  550. int j = m_QueuedConVarSets.AddToTail();
  551. m_QueuedConVarSets[j].m_pConVar = pConVar;
  552. m_QueuedConVarSets[j].m_nType = CONVAR_SET_INT;
  553. m_QueuedConVarSets[j].m_nInt = nValue;
  554. }
  555. void CCvar::QueueMaterialThreadSetValue( ConVar *pConVar, float flValue )
  556. {
  557. Assert( ThreadInMainThread() );
  558. int j = m_QueuedConVarSets.AddToTail();
  559. m_QueuedConVarSets[j].m_pConVar = pConVar;
  560. m_QueuedConVarSets[j].m_nType = CONVAR_SET_FLOAT;
  561. m_QueuedConVarSets[j].m_flFloat = flValue;
  562. }
  563. bool CCvar::HasQueuedMaterialThreadConVarSets() const
  564. {
  565. Assert( ThreadInMainThread() );
  566. return m_QueuedConVarSets.Count() > 0;
  567. }
  568. int CCvar::ProcessQueuedMaterialThreadConVarSets()
  569. {
  570. Assert( ThreadInMainThread() );
  571. m_bMaterialSystemThreadSetAllowed = true;
  572. int nUpdateFlags = 0;
  573. int nCount = m_QueuedConVarSets.Count();
  574. for ( int i = 0; i < nCount; ++i )
  575. {
  576. const QueuedConVarSet_t& set = m_QueuedConVarSets[i];
  577. switch( set.m_nType )
  578. {
  579. case CONVAR_SET_FLOAT:
  580. set.m_pConVar->SetValue( set.m_flFloat );
  581. break;
  582. case CONVAR_SET_INT:
  583. set.m_pConVar->SetValue( set.m_nInt );
  584. break;
  585. case CONVAR_SET_STRING:
  586. set.m_pConVar->SetValue( set.m_String );
  587. break;
  588. }
  589. nUpdateFlags |= set.m_pConVar->GetFlags() & FCVAR_MATERIAL_THREAD_MASK;
  590. }
  591. m_QueuedConVarSets.RemoveAll();
  592. m_bMaterialSystemThreadSetAllowed = false;
  593. return nUpdateFlags;
  594. }
  595. //-----------------------------------------------------------------------------
  596. // Display queued messages
  597. //-----------------------------------------------------------------------------
  598. void CCvar::DisplayQueuedMessages( )
  599. {
  600. // Display any queued up messages
  601. if ( m_TempConsoleBuffer.TellPut() == 0 )
  602. return;
  603. Color clr;
  604. int nStringLength;
  605. while( m_TempConsoleBuffer.IsValid() )
  606. {
  607. int nType = m_TempConsoleBuffer.GetChar();
  608. if ( nType == CONSOLE_COLOR_PRINT )
  609. {
  610. clr.SetRawColor( m_TempConsoleBuffer.GetInt() );
  611. }
  612. nStringLength = m_TempConsoleBuffer.PeekStringLength();
  613. char* pTemp = (char*)stackalloc( nStringLength + 1 );
  614. m_TempConsoleBuffer.GetStringManualCharCount( pTemp, nStringLength + 1 );
  615. switch( nType )
  616. {
  617. case CONSOLE_COLOR_PRINT:
  618. ConsoleColorPrintf( clr, pTemp );
  619. break;
  620. case CONSOLE_PRINT:
  621. ConsolePrintf( pTemp );
  622. break;
  623. case CONSOLE_DPRINT:
  624. ConsoleDPrintf( pTemp );
  625. break;
  626. }
  627. }
  628. m_TempConsoleBuffer.Purge();
  629. }
  630. //-----------------------------------------------------------------------------
  631. // Install a console printer
  632. //-----------------------------------------------------------------------------
  633. void CCvar::InstallConsoleDisplayFunc( IConsoleDisplayFunc* pDisplayFunc )
  634. {
  635. Assert( m_DisplayFuncs.Find( pDisplayFunc ) < 0 );
  636. m_DisplayFuncs.AddToTail( pDisplayFunc );
  637. DisplayQueuedMessages();
  638. }
  639. void CCvar::RemoveConsoleDisplayFunc( IConsoleDisplayFunc* pDisplayFunc )
  640. {
  641. m_DisplayFuncs.FindAndRemove( pDisplayFunc );
  642. }
  643. void CCvar::ConsoleColorPrintf( const Color& clr, const char *pFormat, ... ) const
  644. {
  645. char temp[ 8192 ];
  646. va_list argptr;
  647. va_start( argptr, pFormat );
  648. _vsnprintf( temp, sizeof( temp ) - 1, pFormat, argptr );
  649. va_end( argptr );
  650. temp[ sizeof( temp ) - 1 ] = 0;
  651. int c = m_DisplayFuncs.Count();
  652. if ( c == 0 )
  653. {
  654. m_TempConsoleBuffer.PutChar( CONSOLE_COLOR_PRINT );
  655. m_TempConsoleBuffer.PutInt( clr.GetRawColor() );
  656. m_TempConsoleBuffer.PutString( temp );
  657. return;
  658. }
  659. for ( int i = 0 ; i < c; ++i )
  660. {
  661. m_DisplayFuncs[ i ]->ColorPrint( clr, temp );
  662. }
  663. }
  664. void CCvar::ConsolePrintf( const char *pFormat, ... ) const
  665. {
  666. char temp[ 8192 ];
  667. va_list argptr;
  668. va_start( argptr, pFormat );
  669. _vsnprintf( temp, sizeof( temp ) - 1, pFormat, argptr );
  670. va_end( argptr );
  671. temp[ sizeof( temp ) - 1 ] = 0;
  672. int c = m_DisplayFuncs.Count();
  673. if ( c == 0 )
  674. {
  675. m_TempConsoleBuffer.PutChar( CONSOLE_PRINT );
  676. m_TempConsoleBuffer.PutString( temp );
  677. return;
  678. }
  679. for ( int i = 0 ; i < c; ++i )
  680. {
  681. m_DisplayFuncs[ i ]->Print( temp );
  682. }
  683. }
  684. void CCvar::ConsoleDPrintf( const char *pFormat, ... ) const
  685. {
  686. char temp[ 8192 ];
  687. va_list argptr;
  688. va_start( argptr, pFormat );
  689. _vsnprintf( temp, sizeof( temp ) - 1, pFormat, argptr );
  690. va_end( argptr );
  691. temp[ sizeof( temp ) - 1 ] = 0;
  692. int c = m_DisplayFuncs.Count();
  693. if ( c == 0 )
  694. {
  695. m_TempConsoleBuffer.PutChar( CONSOLE_DPRINT );
  696. m_TempConsoleBuffer.PutString( temp );
  697. return;
  698. }
  699. for ( int i = 0 ; i < c; ++i )
  700. {
  701. m_DisplayFuncs[ i ]->DPrint( temp );
  702. }
  703. }
  704. //-----------------------------------------------------------------------------
  705. // Purpose:
  706. //-----------------------------------------------------------------------------
  707. #if defined( _X360 )
  708. void CCvar::PublishToVXConsole()
  709. {
  710. const char *commands[4096];
  711. const char *helptext[4096];
  712. const ConCommandBase *pCur;
  713. int numCommands = 0;
  714. // iterate and publish commands to the remote console
  715. for ( pCur = m_pConCommandList; pCur; pCur=pCur->GetNext() )
  716. {
  717. // add unregistered commands to list
  718. if ( numCommands < sizeof(commands)/sizeof(commands[0]) )
  719. {
  720. commands[numCommands] = pCur->GetName();
  721. helptext[numCommands] = pCur->GetHelpText();
  722. numCommands++;
  723. }
  724. }
  725. if ( numCommands )
  726. {
  727. XBX_rAddCommands( numCommands, commands, helptext );
  728. }
  729. }
  730. #endif
  731. //-----------------------------------------------------------------------------
  732. // Console commands
  733. //-----------------------------------------------------------------------------
  734. void CCvar::Find( const CCommand &args )
  735. {
  736. const char *search;
  737. const ConCommandBase *var;
  738. if ( args.ArgC() != 2 )
  739. {
  740. ConMsg( "Usage: find <string>\n" );
  741. return;
  742. }
  743. // Get substring to find
  744. search = args[1];
  745. // Loop through vars and print out findings
  746. for ( var = GetCommands(); var; var=var->GetNext() )
  747. {
  748. if ( var->IsFlagSet(FCVAR_DEVELOPMENTONLY) || var->IsFlagSet(FCVAR_HIDDEN) )
  749. continue;
  750. if ( !Q_stristr( var->GetName(), search ) &&
  751. !Q_stristr( var->GetHelpText(), search ) )
  752. continue;
  753. ConVar_PrintDescription( var );
  754. }
  755. }