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.

1376 lines
36 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //
  7. //===========================================================================//
  8. #include <stdio.h>
  9. #include <stdlib.h>
  10. #include <string.h>
  11. #include "basetypes.h"
  12. #include "tier1/convar.h"
  13. #include "tier1/strtools.h"
  14. #include "tier1/characterset.h"
  15. #include "tier1/utlbuffer.h"
  16. #include "tier1/tier1.h"
  17. #include "tier1/convar_serverbounded.h"
  18. #include "icvar.h"
  19. #include "tier0/dbg.h"
  20. #include "Color.h"
  21. #if defined( _X360 )
  22. #include "xbox/xbox_console.h"
  23. #endif
  24. #include "tier0/memdbgon.h"
  25. #ifndef NDEBUG
  26. // Comment this out when we release.
  27. #define ALLOW_DEVELOPMENT_CVARS
  28. #endif
  29. //-----------------------------------------------------------------------------
  30. // Statically constructed list of ConCommandBases,
  31. // used for registering them with the ICVar interface
  32. //-----------------------------------------------------------------------------
  33. ConCommandBase *ConCommandBase::s_pConCommandBases = NULL;
  34. IConCommandBaseAccessor *ConCommandBase::s_pAccessor = NULL;
  35. static int s_nCVarFlag = 0;
  36. static int s_nDLLIdentifier = -1; // A unique identifier indicating which DLL this convar came from
  37. static bool s_bRegistered = false;
  38. class CDefaultAccessor : public IConCommandBaseAccessor
  39. {
  40. public:
  41. virtual bool RegisterConCommandBase( ConCommandBase *pVar )
  42. {
  43. // Link to engine's list instead
  44. g_pCVar->RegisterConCommand( pVar );
  45. return true;
  46. }
  47. };
  48. static CDefaultAccessor s_DefaultAccessor;
  49. //-----------------------------------------------------------------------------
  50. // Called by the framework to register ConCommandBases with the ICVar
  51. //-----------------------------------------------------------------------------
  52. void ConVar_Register( int nCVarFlag, IConCommandBaseAccessor *pAccessor )
  53. {
  54. if ( !g_pCVar || s_bRegistered )
  55. return;
  56. Assert( s_nDLLIdentifier < 0 );
  57. s_bRegistered = true;
  58. s_nCVarFlag = nCVarFlag;
  59. s_nDLLIdentifier = g_pCVar->AllocateDLLIdentifier();
  60. ConCommandBase *pCur, *pNext;
  61. ConCommandBase::s_pAccessor = pAccessor ? pAccessor : &s_DefaultAccessor;
  62. pCur = ConCommandBase::s_pConCommandBases;
  63. while ( pCur )
  64. {
  65. pNext = pCur->m_pNext;
  66. pCur->AddFlags( s_nCVarFlag );
  67. pCur->Init();
  68. pCur = pNext;
  69. }
  70. g_pCVar->ProcessQueuedMaterialThreadConVarSets();
  71. ConCommandBase::s_pConCommandBases = NULL;
  72. }
  73. void ConVar_Unregister( )
  74. {
  75. if ( !g_pCVar || !s_bRegistered )
  76. return;
  77. Assert( s_nDLLIdentifier >= 0 );
  78. g_pCVar->UnregisterConCommands( s_nDLLIdentifier );
  79. s_nDLLIdentifier = -1;
  80. s_bRegistered = false;
  81. }
  82. //-----------------------------------------------------------------------------
  83. // Purpose: Default constructor
  84. //-----------------------------------------------------------------------------
  85. ConCommandBase::ConCommandBase( void )
  86. {
  87. m_bRegistered = false;
  88. m_pszName = NULL;
  89. m_pszHelpString = NULL;
  90. m_nFlags = 0;
  91. m_pNext = NULL;
  92. }
  93. //-----------------------------------------------------------------------------
  94. // Purpose: The base console invoked command/cvar interface
  95. // Input : *pName - name of variable/command
  96. // *pHelpString - help text
  97. // flags - flags
  98. //-----------------------------------------------------------------------------
  99. ConCommandBase::ConCommandBase( const char *pName, const char *pHelpString /*=0*/, int flags /*= 0*/ )
  100. {
  101. CreateBase( pName, pHelpString, flags );
  102. }
  103. //-----------------------------------------------------------------------------
  104. // Purpose:
  105. //-----------------------------------------------------------------------------
  106. ConCommandBase::~ConCommandBase( void )
  107. {
  108. }
  109. //-----------------------------------------------------------------------------
  110. // Purpose:
  111. // Output : Returns true on success, false on failure.
  112. //-----------------------------------------------------------------------------
  113. bool ConCommandBase::IsCommand( void ) const
  114. {
  115. // Assert( 0 ); This can't assert. . causes a recursive assert in Sys_Printf, etc.
  116. return true;
  117. }
  118. //-----------------------------------------------------------------------------
  119. // Returns the DLL identifier
  120. //-----------------------------------------------------------------------------
  121. CVarDLLIdentifier_t ConCommandBase::GetDLLIdentifier() const
  122. {
  123. return s_nDLLIdentifier;
  124. }
  125. //-----------------------------------------------------------------------------
  126. // Purpose:
  127. // Input : *pName -
  128. // callback -
  129. // *pHelpString -
  130. // flags -
  131. //-----------------------------------------------------------------------------
  132. void ConCommandBase::CreateBase( const char *pName, const char *pHelpString /*= 0*/, int flags /*= 0*/ )
  133. {
  134. m_bRegistered = false;
  135. // Name should be static data
  136. Assert( pName );
  137. m_pszName = pName;
  138. m_pszHelpString = pHelpString ? pHelpString : "";
  139. m_nFlags = flags;
  140. #ifdef ALLOW_DEVELOPMENT_CVARS
  141. m_nFlags &= ~FCVAR_DEVELOPMENTONLY;
  142. #endif
  143. if ( !( m_nFlags & FCVAR_UNREGISTERED ) )
  144. {
  145. m_pNext = s_pConCommandBases;
  146. s_pConCommandBases = this;
  147. }
  148. else
  149. {
  150. // It's unregistered
  151. m_pNext = NULL;
  152. }
  153. // If s_pAccessor is already set (this ConVar is not a global variable),
  154. // register it.
  155. if ( s_pAccessor )
  156. {
  157. Init();
  158. }
  159. }
  160. //-----------------------------------------------------------------------------
  161. // Purpose: Used internally by OneTimeInit to initialize.
  162. //-----------------------------------------------------------------------------
  163. void ConCommandBase::Init()
  164. {
  165. if ( s_pAccessor )
  166. {
  167. s_pAccessor->RegisterConCommandBase( this );
  168. }
  169. }
  170. void ConCommandBase::Shutdown()
  171. {
  172. if ( g_pCVar )
  173. {
  174. g_pCVar->UnregisterConCommand( this );
  175. }
  176. }
  177. //-----------------------------------------------------------------------------
  178. // Purpose: Return name of the command/var
  179. // Output : const char
  180. //-----------------------------------------------------------------------------
  181. const char *ConCommandBase::GetName( void ) const
  182. {
  183. return m_pszName;
  184. }
  185. //-----------------------------------------------------------------------------
  186. // Purpose:
  187. // Input : flag -
  188. // Output : Returns true on success, false on failure.
  189. //-----------------------------------------------------------------------------
  190. bool ConCommandBase::IsFlagSet( int flag ) const
  191. {
  192. return ( flag & m_nFlags ) ? true : false;
  193. }
  194. //-----------------------------------------------------------------------------
  195. // Purpose:
  196. // Input : flags -
  197. //-----------------------------------------------------------------------------
  198. void ConCommandBase::AddFlags( int flags )
  199. {
  200. m_nFlags |= flags;
  201. #ifdef ALLOW_DEVELOPMENT_CVARS
  202. m_nFlags &= ~FCVAR_DEVELOPMENTONLY;
  203. #endif
  204. }
  205. //-----------------------------------------------------------------------------
  206. // Purpose:
  207. // Output : const ConCommandBase
  208. //-----------------------------------------------------------------------------
  209. const ConCommandBase *ConCommandBase::GetNext( void ) const
  210. {
  211. return m_pNext;
  212. }
  213. ConCommandBase *ConCommandBase::GetNext( void )
  214. {
  215. return m_pNext;
  216. }
  217. //-----------------------------------------------------------------------------
  218. // Purpose: Copies string using local new/delete operators
  219. // Input : *from -
  220. // Output : char
  221. //-----------------------------------------------------------------------------
  222. char *ConCommandBase::CopyString( const char *from )
  223. {
  224. int len;
  225. char *to;
  226. len = V_strlen( from );
  227. if ( len <= 0 )
  228. {
  229. to = new char[1];
  230. to[0] = 0;
  231. }
  232. else
  233. {
  234. to = new char[len+1];
  235. Q_strncpy( to, from, len+1 );
  236. }
  237. return to;
  238. }
  239. //-----------------------------------------------------------------------------
  240. // Purpose:
  241. // Output : const char
  242. //-----------------------------------------------------------------------------
  243. const char *ConCommandBase::GetHelpText( void ) const
  244. {
  245. return m_pszHelpString;
  246. }
  247. //-----------------------------------------------------------------------------
  248. // Purpose: Has this cvar been registered
  249. // Output : Returns true on success, false on failure.
  250. //-----------------------------------------------------------------------------
  251. bool ConCommandBase::IsRegistered( void ) const
  252. {
  253. return m_bRegistered;
  254. }
  255. //-----------------------------------------------------------------------------
  256. //
  257. // Con Commands start here
  258. //
  259. //-----------------------------------------------------------------------------
  260. //-----------------------------------------------------------------------------
  261. // Global methods
  262. //-----------------------------------------------------------------------------
  263. static characterset_t s_BreakSet;
  264. static bool s_bBuiltBreakSet = false;
  265. //-----------------------------------------------------------------------------
  266. // Tokenizer class
  267. //-----------------------------------------------------------------------------
  268. CCommand::CCommand()
  269. {
  270. if ( !s_bBuiltBreakSet )
  271. {
  272. s_bBuiltBreakSet = true;
  273. CharacterSetBuild( &s_BreakSet, "{}()':" );
  274. }
  275. Reset();
  276. }
  277. CCommand::CCommand( int nArgC, const char **ppArgV )
  278. {
  279. Assert( nArgC > 0 );
  280. if ( !s_bBuiltBreakSet )
  281. {
  282. s_bBuiltBreakSet = true;
  283. CharacterSetBuild( &s_BreakSet, "{}()':" );
  284. }
  285. Reset();
  286. char *pBuf = m_pArgvBuffer;
  287. char *pSBuf = m_pArgSBuffer;
  288. m_nArgc = nArgC;
  289. for ( int i = 0; i < nArgC; ++i )
  290. {
  291. m_ppArgv[i] = pBuf;
  292. int nLen = Q_strlen( ppArgV[i] );
  293. memcpy( pBuf, ppArgV[i], nLen+1 );
  294. if ( i == 0 )
  295. {
  296. m_nArgv0Size = nLen;
  297. }
  298. pBuf += nLen+1;
  299. bool bContainsSpace = strchr( ppArgV[i], ' ' ) != NULL;
  300. if ( bContainsSpace )
  301. {
  302. *pSBuf++ = '\"';
  303. }
  304. memcpy( pSBuf, ppArgV[i], nLen );
  305. pSBuf += nLen;
  306. if ( bContainsSpace )
  307. {
  308. *pSBuf++ = '\"';
  309. }
  310. if ( i != nArgC - 1 )
  311. {
  312. *pSBuf++ = ' ';
  313. }
  314. }
  315. }
  316. void CCommand::Reset()
  317. {
  318. m_nArgc = 0;
  319. m_nArgv0Size = 0;
  320. m_pArgSBuffer[0] = 0;
  321. }
  322. characterset_t* CCommand::DefaultBreakSet()
  323. {
  324. return &s_BreakSet;
  325. }
  326. bool CCommand::Tokenize( const char *pCommand, characterset_t *pBreakSet )
  327. {
  328. Reset();
  329. if ( !pCommand )
  330. return false;
  331. // Use default break set
  332. if ( !pBreakSet )
  333. {
  334. pBreakSet = &s_BreakSet;
  335. }
  336. // Copy the current command into a temp buffer
  337. // NOTE: This is here to avoid the pointers returned by DequeueNextCommand
  338. // to become invalid by calling AddText. Is there a way we can avoid the memcpy?
  339. int nLen = Q_strlen( pCommand );
  340. if ( nLen >= COMMAND_MAX_LENGTH - 1 )
  341. {
  342. Warning( "CCommand::Tokenize: Encountered command which overflows the tokenizer buffer.. Skipping!\n" );
  343. return false;
  344. }
  345. memcpy( m_pArgSBuffer, pCommand, nLen + 1 );
  346. // Parse the current command into the current command buffer
  347. CUtlBuffer bufParse( m_pArgSBuffer, nLen, CUtlBuffer::TEXT_BUFFER | CUtlBuffer::READ_ONLY );
  348. int nArgvBufferSize = 0;
  349. while ( bufParse.IsValid() && ( m_nArgc < COMMAND_MAX_ARGC ) )
  350. {
  351. char *pArgvBuf = &m_pArgvBuffer[nArgvBufferSize];
  352. int nMaxLen = COMMAND_MAX_LENGTH - nArgvBufferSize;
  353. int nStartGet = bufParse.TellGet();
  354. int nSize = bufParse.ParseToken( pBreakSet, pArgvBuf, nMaxLen );
  355. if ( nSize < 0 )
  356. break;
  357. // Check for overflow condition
  358. if ( nMaxLen == nSize )
  359. {
  360. Reset();
  361. return false;
  362. }
  363. if ( m_nArgc == 1 )
  364. {
  365. // Deal with the case where the arguments were quoted
  366. m_nArgv0Size = bufParse.TellGet();
  367. bool bFoundEndQuote = m_pArgSBuffer[m_nArgv0Size-1] == '\"';
  368. if ( bFoundEndQuote )
  369. {
  370. --m_nArgv0Size;
  371. }
  372. m_nArgv0Size -= nSize;
  373. Assert( m_nArgv0Size != 0 );
  374. // The StartGet check is to handle this case: "foo"bar
  375. // which will parse into 2 different args. ArgS should point to bar.
  376. bool bFoundStartQuote = ( m_nArgv0Size > nStartGet ) && ( m_pArgSBuffer[m_nArgv0Size-1] == '\"' );
  377. Assert( bFoundEndQuote == bFoundStartQuote );
  378. if ( bFoundStartQuote )
  379. {
  380. --m_nArgv0Size;
  381. }
  382. }
  383. m_ppArgv[ m_nArgc++ ] = pArgvBuf;
  384. if( m_nArgc >= COMMAND_MAX_ARGC )
  385. {
  386. Warning( "CCommand::Tokenize: Encountered command which overflows the argument buffer.. Clamped!\n" );
  387. }
  388. nArgvBufferSize += nSize + 1;
  389. Assert( nArgvBufferSize <= COMMAND_MAX_LENGTH );
  390. }
  391. return true;
  392. }
  393. //-----------------------------------------------------------------------------
  394. // Helper function to parse arguments to commands.
  395. //-----------------------------------------------------------------------------
  396. const char* CCommand::FindArg( const char *pName ) const
  397. {
  398. int nArgC = ArgC();
  399. for ( int i = 1; i < nArgC; i++ )
  400. {
  401. if ( !Q_stricmp( Arg(i), pName ) )
  402. return (i+1) < nArgC ? Arg( i+1 ) : "";
  403. }
  404. return 0;
  405. }
  406. int CCommand::FindArgInt( const char *pName, int nDefaultVal ) const
  407. {
  408. const char *pVal = FindArg( pName );
  409. if ( pVal )
  410. return atoi( pVal );
  411. else
  412. return nDefaultVal;
  413. }
  414. //-----------------------------------------------------------------------------
  415. // Default console command autocompletion function
  416. //-----------------------------------------------------------------------------
  417. int DefaultCompletionFunc( const char *partial, char commands[ COMMAND_COMPLETION_MAXITEMS ][ COMMAND_COMPLETION_ITEM_LENGTH ] )
  418. {
  419. return 0;
  420. }
  421. //-----------------------------------------------------------------------------
  422. // Purpose: Constructs a console command
  423. //-----------------------------------------------------------------------------
  424. //ConCommand::ConCommand()
  425. //{
  426. // m_bIsNewConCommand = true;
  427. //}
  428. ConCommand::ConCommand( const char *pName, FnCommandCallbackVoid_t callback, const char *pHelpString /*= 0*/, int flags /*= 0*/, FnCommandCompletionCallback completionFunc /*= 0*/ )
  429. {
  430. // Set the callback
  431. m_fnCommandCallbackV1 = callback;
  432. m_bUsingNewCommandCallback = false;
  433. m_bUsingCommandCallbackInterface = false;
  434. m_fnCompletionCallback = completionFunc ? completionFunc : DefaultCompletionFunc;
  435. m_bHasCompletionCallback = completionFunc != 0 ? true : false;
  436. // Setup the rest
  437. BaseClass::CreateBase( pName, pHelpString, flags );
  438. }
  439. ConCommand::ConCommand( const char *pName, FnCommandCallback_t callback, const char *pHelpString /*= 0*/, int flags /*= 0*/, FnCommandCompletionCallback completionFunc /*= 0*/ )
  440. {
  441. // Set the callback
  442. m_fnCommandCallback = callback;
  443. m_bUsingNewCommandCallback = true;
  444. m_fnCompletionCallback = completionFunc ? completionFunc : DefaultCompletionFunc;
  445. m_bHasCompletionCallback = completionFunc != 0 ? true : false;
  446. m_bUsingCommandCallbackInterface = false;
  447. // Setup the rest
  448. BaseClass::CreateBase( pName, pHelpString, flags );
  449. }
  450. ConCommand::ConCommand( const char *pName, ICommandCallback *pCallback, const char *pHelpString /*= 0*/, int flags /*= 0*/, ICommandCompletionCallback *pCompletionCallback /*= 0*/ )
  451. {
  452. // Set the callback
  453. m_pCommandCallback = pCallback;
  454. m_bUsingNewCommandCallback = false;
  455. m_pCommandCompletionCallback = pCompletionCallback;
  456. m_bHasCompletionCallback = ( pCompletionCallback != 0 );
  457. m_bUsingCommandCallbackInterface = true;
  458. // Setup the rest
  459. BaseClass::CreateBase( pName, pHelpString, flags );
  460. }
  461. //-----------------------------------------------------------------------------
  462. // Destructor
  463. //-----------------------------------------------------------------------------
  464. ConCommand::~ConCommand( void )
  465. {
  466. }
  467. //-----------------------------------------------------------------------------
  468. // Purpose: Returns true if this is a command
  469. //-----------------------------------------------------------------------------
  470. bool ConCommand::IsCommand( void ) const
  471. {
  472. return true;
  473. }
  474. //-----------------------------------------------------------------------------
  475. // Purpose: Invoke the function if there is one
  476. //-----------------------------------------------------------------------------
  477. void ConCommand::Dispatch( const CCommand &command )
  478. {
  479. if ( m_bUsingNewCommandCallback )
  480. {
  481. if ( m_fnCommandCallback )
  482. {
  483. ( *m_fnCommandCallback )( command );
  484. return;
  485. }
  486. }
  487. else if ( m_bUsingCommandCallbackInterface )
  488. {
  489. if ( m_pCommandCallback )
  490. {
  491. m_pCommandCallback->CommandCallback( command );
  492. return;
  493. }
  494. }
  495. else
  496. {
  497. if ( m_fnCommandCallbackV1 )
  498. {
  499. ( *m_fnCommandCallbackV1 )();
  500. return;
  501. }
  502. }
  503. // Command without callback!!!
  504. AssertMsg( 0, "Encountered ConCommand '%s' without a callback!\n", GetName() );
  505. }
  506. //-----------------------------------------------------------------------------
  507. // Purpose: Calls the autocompletion method to get autocompletion suggestions
  508. //-----------------------------------------------------------------------------
  509. int ConCommand::AutoCompleteSuggest( const char *partial, CUtlVector< CUtlString > &commands )
  510. {
  511. if ( m_bUsingCommandCallbackInterface )
  512. {
  513. if ( !m_pCommandCompletionCallback )
  514. return 0;
  515. return m_pCommandCompletionCallback->CommandCompletionCallback( partial, commands );
  516. }
  517. Assert( m_fnCompletionCallback );
  518. if ( !m_fnCompletionCallback )
  519. return 0;
  520. char rgpchCommands[ COMMAND_COMPLETION_MAXITEMS ][ COMMAND_COMPLETION_ITEM_LENGTH ];
  521. int iret = ( m_fnCompletionCallback )( partial, rgpchCommands );
  522. for ( int i = 0 ; i < iret; ++i )
  523. {
  524. CUtlString str = rgpchCommands[ i ];
  525. commands.AddToTail( str );
  526. }
  527. return iret;
  528. }
  529. //-----------------------------------------------------------------------------
  530. // Returns true if the console command can autocomplete
  531. //-----------------------------------------------------------------------------
  532. bool ConCommand::CanAutoComplete( void )
  533. {
  534. return m_bHasCompletionCallback;
  535. }
  536. //-----------------------------------------------------------------------------
  537. //
  538. // Console Variables
  539. //
  540. //-----------------------------------------------------------------------------
  541. //-----------------------------------------------------------------------------
  542. // Various constructors
  543. //-----------------------------------------------------------------------------
  544. ConVar::ConVar( const char *pName, const char *pDefaultValue, int flags /* = 0 */ )
  545. {
  546. Create( pName, pDefaultValue, flags );
  547. }
  548. ConVar::ConVar( const char *pName, const char *pDefaultValue, int flags, const char *pHelpString )
  549. {
  550. Create( pName, pDefaultValue, flags, pHelpString );
  551. }
  552. ConVar::ConVar( const char *pName, const char *pDefaultValue, int flags, const char *pHelpString, bool bMin, float fMin, bool bMax, float fMax )
  553. {
  554. Create( pName, pDefaultValue, flags, pHelpString, bMin, fMin, bMax, fMax );
  555. }
  556. ConVar::ConVar( const char *pName, const char *pDefaultValue, int flags, const char *pHelpString, FnChangeCallback_t callback )
  557. {
  558. Create( pName, pDefaultValue, flags, pHelpString, false, 0.0, false, 0.0, false, 0.0, false, 0.0, callback );
  559. }
  560. ConVar::ConVar( const char *pName, const char *pDefaultValue, int flags, const char *pHelpString, bool bMin, float fMin, bool bMax, float fMax, FnChangeCallback_t callback )
  561. {
  562. Create( pName, pDefaultValue, flags, pHelpString, bMin, fMin, bMax, fMax, false, 0.0, false, 0.0, callback );
  563. }
  564. ConVar::ConVar( const char *pName, const char *pDefaultValue, int flags, const char *pHelpString, bool bMin, float fMin, bool bMax, float fMax, bool bCompMin, float fCompMin, bool bCompMax, float fCompMax, FnChangeCallback_t callback )
  565. {
  566. Create( pName, pDefaultValue, flags, pHelpString, bMin, fMin, bMax, fMax, bCompMin, fCompMin, bCompMax, fCompMax, callback );
  567. }
  568. //-----------------------------------------------------------------------------
  569. // Destructor
  570. //-----------------------------------------------------------------------------
  571. ConVar::~ConVar( void )
  572. {
  573. if ( m_pszString )
  574. {
  575. delete[] m_pszString;
  576. m_pszString = NULL;
  577. }
  578. }
  579. //-----------------------------------------------------------------------------
  580. // Install a change callback (there shouldn't already be one....)
  581. //-----------------------------------------------------------------------------
  582. void ConVar::InstallChangeCallback( FnChangeCallback_t callback )
  583. {
  584. Assert( !m_pParent->m_fnChangeCallback || !callback );
  585. m_pParent->m_fnChangeCallback = callback;
  586. if ( m_pParent->m_fnChangeCallback )
  587. {
  588. // Call it immediately to set the initial value...
  589. m_pParent->m_fnChangeCallback( this, m_pszString, m_fValue );
  590. }
  591. }
  592. bool ConVar::IsFlagSet( int flag ) const
  593. {
  594. return ( flag & m_pParent->m_nFlags ) ? true : false;
  595. }
  596. const char *ConVar::GetHelpText( void ) const
  597. {
  598. return m_pParent->m_pszHelpString;
  599. }
  600. void ConVar::AddFlags( int flags )
  601. {
  602. m_pParent->m_nFlags |= flags;
  603. #ifdef ALLOW_DEVELOPMENT_CVARS
  604. m_pParent->m_nFlags &= ~FCVAR_DEVELOPMENTONLY;
  605. #endif
  606. }
  607. bool ConVar::IsRegistered( void ) const
  608. {
  609. return m_pParent->m_bRegistered;
  610. }
  611. const char *ConVar::GetName( void ) const
  612. {
  613. return m_pParent->m_pszName;
  614. }
  615. //-----------------------------------------------------------------------------
  616. // Purpose:
  617. // Output : Returns true on success, false on failure.
  618. //-----------------------------------------------------------------------------
  619. bool ConVar::IsCommand( void ) const
  620. {
  621. return false;
  622. }
  623. //-----------------------------------------------------------------------------
  624. // Purpose:
  625. // Input :
  626. //-----------------------------------------------------------------------------
  627. void ConVar::Init()
  628. {
  629. BaseClass::Init();
  630. }
  631. //-----------------------------------------------------------------------------
  632. // Purpose:
  633. // Input : *value -
  634. //-----------------------------------------------------------------------------
  635. void ConVar::InternalSetValue( const char *value )
  636. {
  637. if ( IsFlagSet( FCVAR_MATERIAL_THREAD_MASK ) )
  638. {
  639. if ( g_pCVar && !g_pCVar->IsMaterialThreadSetAllowed() )
  640. {
  641. g_pCVar->QueueMaterialThreadSetValue( this, value );
  642. return;
  643. }
  644. }
  645. float fNewValue;
  646. char tempVal[ 32 ];
  647. char *val;
  648. Assert(m_pParent == this); // Only valid for root convars.
  649. float flOldValue = m_fValue;
  650. val = (char *)value;
  651. if ( !value )
  652. fNewValue = 0.0f;
  653. else
  654. fNewValue = ( float )atof( value );
  655. if ( ClampValue( fNewValue ) )
  656. {
  657. Q_snprintf( tempVal,sizeof(tempVal), "%f", fNewValue );
  658. val = tempVal;
  659. }
  660. // Redetermine value
  661. m_fValue = fNewValue;
  662. m_nValue = ( int )( fNewValue );
  663. if ( !( m_nFlags & FCVAR_NEVER_AS_STRING ) )
  664. {
  665. ChangeStringValue( val, flOldValue );
  666. }
  667. }
  668. //-----------------------------------------------------------------------------
  669. // Purpose:
  670. // Input : *tempVal -
  671. //-----------------------------------------------------------------------------
  672. void ConVar::ChangeStringValue( const char *tempVal, float flOldValue )
  673. {
  674. Assert( !( m_nFlags & FCVAR_NEVER_AS_STRING ) );
  675. char* pszOldValue = (char*)stackalloc( m_StringLength );
  676. memcpy( pszOldValue, m_pszString, m_StringLength );
  677. if ( tempVal )
  678. {
  679. int len = Q_strlen(tempVal) + 1;
  680. if ( len > m_StringLength)
  681. {
  682. if (m_pszString)
  683. {
  684. delete[] m_pszString;
  685. }
  686. m_pszString = new char[len];
  687. m_StringLength = len;
  688. }
  689. memcpy( m_pszString, tempVal, len );
  690. }
  691. else
  692. {
  693. *m_pszString = 0;
  694. }
  695. // If nothing has changed, don't do the callbacks.
  696. if (V_strcmp(pszOldValue, m_pszString) != 0)
  697. {
  698. // Invoke any necessary callback function
  699. if ( m_fnChangeCallback )
  700. {
  701. m_fnChangeCallback( this, pszOldValue, flOldValue );
  702. }
  703. g_pCVar->CallGlobalChangeCallbacks( this, pszOldValue, flOldValue );
  704. }
  705. stackfree( pszOldValue );
  706. }
  707. //-----------------------------------------------------------------------------
  708. // Purpose: Check whether to clamp and then perform clamp
  709. // Input : value -
  710. // Output : Returns true if value changed
  711. //-----------------------------------------------------------------------------
  712. bool ConVar::ClampValue( float& value )
  713. {
  714. // Competitive /should/ be more restrictive, so do it first.
  715. if ( m_bCompetitiveRestrictions )
  716. {
  717. if ( m_bHasCompMin && ( value < m_fCompMinVal ) )
  718. {
  719. value = m_fCompMinVal;
  720. return true;
  721. }
  722. if ( m_bHasCompMax && ( value > m_fCompMaxVal ) )
  723. {
  724. value = m_fCompMaxVal;
  725. return true;
  726. }
  727. if ( !m_bHasCompMin && !m_bHasCompMax )
  728. {
  729. float fDefaultAsFloat = V_atof( m_pszDefaultValue );
  730. if ( fabs( value - fDefaultAsFloat ) > 0.0001f )
  731. {
  732. value = fDefaultAsFloat;
  733. return true;
  734. }
  735. }
  736. }
  737. if ( m_bHasMin && ( value < m_fMinVal ) )
  738. {
  739. value = m_fMinVal;
  740. return true;
  741. }
  742. if ( m_bHasMax && ( value > m_fMaxVal ) )
  743. {
  744. value = m_fMaxVal;
  745. return true;
  746. }
  747. return false;
  748. }
  749. //-----------------------------------------------------------------------------
  750. // Purpose:
  751. // Input : *value -
  752. //-----------------------------------------------------------------------------
  753. void ConVar::InternalSetFloatValue( float fNewValue, bool bForce /*= false */ )
  754. {
  755. if ( fNewValue == m_fValue && !bForce )
  756. return;
  757. if ( IsFlagSet( FCVAR_MATERIAL_THREAD_MASK ) )
  758. {
  759. if ( g_pCVar && !g_pCVar->IsMaterialThreadSetAllowed() )
  760. {
  761. g_pCVar->QueueMaterialThreadSetValue( this, fNewValue );
  762. return;
  763. }
  764. }
  765. Assert( m_pParent == this ); // Only valid for root convars.
  766. // Check bounds
  767. ClampValue( fNewValue );
  768. // Redetermine value
  769. float flOldValue = m_fValue;
  770. m_fValue = fNewValue;
  771. m_nValue = ( int )m_fValue;
  772. if ( !( m_nFlags & FCVAR_NEVER_AS_STRING ) )
  773. {
  774. char tempVal[ 32 ];
  775. Q_snprintf( tempVal, sizeof( tempVal), "%f", m_fValue );
  776. ChangeStringValue( tempVal, flOldValue );
  777. }
  778. else
  779. {
  780. Assert( !m_fnChangeCallback );
  781. }
  782. }
  783. //-----------------------------------------------------------------------------
  784. // Purpose:
  785. // Input : *value -
  786. //-----------------------------------------------------------------------------
  787. void ConVar::InternalSetIntValue( int nValue )
  788. {
  789. if ( nValue == m_nValue )
  790. return;
  791. if ( IsFlagSet( FCVAR_MATERIAL_THREAD_MASK ) )
  792. {
  793. if ( g_pCVar && !g_pCVar->IsMaterialThreadSetAllowed() )
  794. {
  795. g_pCVar->QueueMaterialThreadSetValue( this, nValue );
  796. return;
  797. }
  798. }
  799. Assert( m_pParent == this ); // Only valid for root convars.
  800. float fValue = (float)nValue;
  801. if ( ClampValue( fValue ) )
  802. {
  803. nValue = ( int )( fValue );
  804. }
  805. // Redetermine value
  806. float flOldValue = m_fValue;
  807. m_fValue = fValue;
  808. m_nValue = nValue;
  809. if ( !( m_nFlags & FCVAR_NEVER_AS_STRING ) )
  810. {
  811. char tempVal[ 32 ];
  812. Q_snprintf( tempVal, sizeof( tempVal ), "%d", m_nValue );
  813. ChangeStringValue( tempVal, flOldValue );
  814. }
  815. else
  816. {
  817. Assert( !m_fnChangeCallback );
  818. }
  819. }
  820. //-----------------------------------------------------------------------------
  821. // Purpose: Private creation
  822. //-----------------------------------------------------------------------------
  823. void ConVar::Create( const char *pName, const char *pDefaultValue, int flags /*= 0*/,
  824. const char *pHelpString /*= NULL*/, bool bMin /*= false*/, float fMin /*= 0.0*/,
  825. bool bMax /*= false*/, float fMax /*= false*/, bool bCompMin /*= false */,
  826. float fCompMin /*= 0.0*/, bool bCompMax /*= false*/, float fCompMax /*= 0.0*/,
  827. FnChangeCallback_t callback /*= NULL*/ )
  828. {
  829. m_pParent = this;
  830. // Name should be static data
  831. SetDefault( pDefaultValue );
  832. m_StringLength = V_strlen( m_pszDefaultValue ) + 1;
  833. m_pszString = new char[m_StringLength];
  834. memcpy( m_pszString, m_pszDefaultValue, m_StringLength );
  835. m_bHasMin = bMin;
  836. m_fMinVal = fMin;
  837. m_bHasMax = bMax;
  838. m_fMaxVal = fMax;
  839. m_bHasCompMin = bCompMin;
  840. m_fCompMinVal = fCompMin;
  841. m_bHasCompMax = bCompMax;
  842. m_fCompMaxVal = fCompMax;
  843. m_bCompetitiveRestrictions = false;
  844. m_fnChangeCallback = callback;
  845. m_fValue = ( float )atof( m_pszString );
  846. m_nValue = atoi( m_pszString ); // dont convert from float to int and lose bits
  847. // Bounds Check, should never happen, if it does, no big deal
  848. Assert( !m_bHasMin || m_fValue >= m_fMinVal );
  849. Assert( !m_bHasMax || m_fValue <= m_fMaxVal );
  850. BaseClass::CreateBase( pName, pHelpString, flags );
  851. }
  852. //-----------------------------------------------------------------------------
  853. // Purpose:
  854. // Input : *value -
  855. //-----------------------------------------------------------------------------
  856. void ConVar::SetValue(const char *value)
  857. {
  858. ConVar *var = ( ConVar * )m_pParent;
  859. var->InternalSetValue( value );
  860. }
  861. //-----------------------------------------------------------------------------
  862. // Purpose:
  863. // Input : value -
  864. //-----------------------------------------------------------------------------
  865. void ConVar::SetValue( float value )
  866. {
  867. ConVar *var = ( ConVar * )m_pParent;
  868. var->InternalSetFloatValue( value );
  869. }
  870. //-----------------------------------------------------------------------------
  871. // Purpose:
  872. // Input : value -
  873. //-----------------------------------------------------------------------------
  874. void ConVar::SetValue( int value )
  875. {
  876. ConVar *var = ( ConVar * )m_pParent;
  877. var->InternalSetIntValue( value );
  878. }
  879. //-----------------------------------------------------------------------------
  880. // Purpose: Reset to default value
  881. //-----------------------------------------------------------------------------
  882. void ConVar::Revert( void )
  883. {
  884. // Force default value again
  885. ConVar *var = ( ConVar * )m_pParent;
  886. var->SetValue( var->m_pszDefaultValue );
  887. }
  888. //-----------------------------------------------------------------------------
  889. // Purpose:
  890. // Input : minVal -
  891. // Output : true if there is a min set
  892. //-----------------------------------------------------------------------------
  893. bool ConVar::GetMin( float& minVal ) const
  894. {
  895. minVal = m_pParent->m_fMinVal;
  896. return m_pParent->m_bHasMin;
  897. }
  898. //-----------------------------------------------------------------------------
  899. // Purpose:
  900. // Input : maxVal -
  901. //-----------------------------------------------------------------------------
  902. bool ConVar::GetMax( float& maxVal ) const
  903. {
  904. maxVal = m_pParent->m_fMaxVal;
  905. return m_pParent->m_bHasMax;
  906. }
  907. //-----------------------------------------------------------------------------
  908. // Purpose:
  909. // Input : minVal -
  910. // Output : true if there is a min set
  911. //-----------------------------------------------------------------------------
  912. bool ConVar::GetCompMin( float& minVal ) const
  913. {
  914. minVal = m_pParent->m_fCompMinVal;
  915. return m_pParent->m_bHasCompMin;
  916. }
  917. //-----------------------------------------------------------------------------
  918. // Purpose:
  919. // Input : maxVal -
  920. //-----------------------------------------------------------------------------
  921. bool ConVar::GetCompMax( float& maxVal ) const
  922. {
  923. maxVal = m_pParent->m_fCompMaxVal;
  924. return m_pParent->m_bHasCompMax;
  925. }
  926. //-----------------------------------------------------------------------------
  927. // Purpose: Sets that competitive mode is enabled for this var, and then
  928. // attempts to clamp to competitive values.
  929. // Input : maxVal -
  930. // Output : true if the value was successfully updated, otherwise false.
  931. //-----------------------------------------------------------------------------
  932. bool ConVar::SetCompetitiveMode( bool bCompetitive )
  933. {
  934. // Should only do this for competitive restricted things.
  935. Assert( IsCompetitiveRestricted() );
  936. ConVar* var = m_pParent;
  937. var->m_bCompetitiveRestrictions = true;
  938. float fDefaultAsFloat = 0.0f;
  939. bool bRequiresClamp = ( var->m_bHasCompMin && var->m_fCompMinVal > var->m_fValue )
  940. || ( var->m_bHasCompMax && var->m_fCompMaxVal < var->m_fValue );
  941. bool bForceToDefault = !var->m_bHasCompMin && !var->m_bHasCompMax
  942. && ( fabs( var->m_fValue - ( fDefaultAsFloat = V_atof( var->m_pszDefaultValue ) ) ) > 0.00001f );
  943. if ( bRequiresClamp )
  944. var->InternalSetFloatValue( var->m_fValue, true );
  945. else if ( bForceToDefault )
  946. {
  947. STAGING_ONLY_EXEC( Msg( "Changing Convar: %s ( cur: %.2f ) to %.2f -> ", GetName(), var->m_fValue, fDefaultAsFloat ) );
  948. var->InternalSetFloatValue( fDefaultAsFloat, true );
  949. STAGING_ONLY_EXEC( Msg( "%.2f\n", var->m_fValue ) );
  950. }
  951. // The clamping should've worked, so if it didn't--need to understand why.
  952. Assert( !bRequiresClamp || IsFlagSet( FCVAR_MATERIAL_THREAD_MASK ) || ( ( !var->m_bHasCompMin || var->m_fCompMinVal <= var->m_fValue )
  953. && ( !var->m_bHasCompMax || var->m_fCompMaxVal >= var->m_fValue ) ) );
  954. Assert( !bForceToDefault || IsFlagSet( FCVAR_MATERIAL_THREAD_MASK ) || ( var->m_fValue == fDefaultAsFloat ) );
  955. return true;
  956. }
  957. //-----------------------------------------------------------------------------
  958. // Purpose:
  959. // Output : const char
  960. //-----------------------------------------------------------------------------
  961. const char *ConVar::GetDefault( void ) const
  962. {
  963. return m_pParent->m_pszDefaultValue;
  964. }
  965. void ConVar::SetDefault( const char *pszDefault )
  966. {
  967. m_pszDefaultValue = pszDefault ? pszDefault : "";
  968. Assert( m_pszDefaultValue );
  969. }
  970. //-----------------------------------------------------------------------------
  971. // This version is simply used to make reading convars simpler.
  972. // Writing convars isn't allowed in this mode
  973. //-----------------------------------------------------------------------------
  974. class CEmptyConVar : public ConVar
  975. {
  976. public:
  977. CEmptyConVar() : ConVar( "", "0" ) {}
  978. // Used for optimal read access
  979. virtual void SetValue( const char *pValue ) {}
  980. virtual void SetValue( float flValue ) {}
  981. virtual void SetValue( int nValue ) {}
  982. virtual const char *GetName( void ) const { return ""; }
  983. virtual bool IsFlagSet( int nFlags ) const { return false; }
  984. };
  985. static CEmptyConVar s_EmptyConVar;
  986. ConVarRef::ConVarRef( const char *pName )
  987. {
  988. Init( pName, false );
  989. }
  990. ConVarRef::ConVarRef( const char *pName, bool bIgnoreMissing )
  991. {
  992. Init( pName, bIgnoreMissing );
  993. }
  994. void ConVarRef::Init( const char *pName, bool bIgnoreMissing )
  995. {
  996. m_pConVar = g_pCVar ? g_pCVar->FindVar( pName ) : &s_EmptyConVar;
  997. if ( !m_pConVar )
  998. {
  999. m_pConVar = &s_EmptyConVar;
  1000. }
  1001. m_pConVarState = static_cast< ConVar * >( m_pConVar );
  1002. if( !IsValid() )
  1003. {
  1004. static bool bFirst = true;
  1005. if ( g_pCVar || bFirst )
  1006. {
  1007. if ( !bIgnoreMissing )
  1008. {
  1009. Warning( "ConVarRef %s doesn't point to an existing ConVar\n", pName );
  1010. }
  1011. bFirst = false;
  1012. }
  1013. }
  1014. }
  1015. ConVarRef::ConVarRef( IConVar *pConVar )
  1016. {
  1017. m_pConVar = pConVar ? pConVar : &s_EmptyConVar;
  1018. m_pConVarState = static_cast< ConVar * >( m_pConVar );
  1019. }
  1020. bool ConVarRef::IsValid() const
  1021. {
  1022. return m_pConVar != &s_EmptyConVar;
  1023. }
  1024. //-----------------------------------------------------------------------------
  1025. // Purpose:
  1026. //-----------------------------------------------------------------------------
  1027. void ConVar_PrintFlags( const ConCommandBase *var )
  1028. {
  1029. bool any = false;
  1030. if ( var->IsFlagSet( FCVAR_GAMEDLL ) )
  1031. {
  1032. ConMsg( " game" );
  1033. any = true;
  1034. }
  1035. if ( var->IsFlagSet( FCVAR_CLIENTDLL ) )
  1036. {
  1037. ConMsg( " client" );
  1038. any = true;
  1039. }
  1040. if ( var->IsFlagSet( FCVAR_ARCHIVE ) )
  1041. {
  1042. ConMsg( " archive" );
  1043. any = true;
  1044. }
  1045. if ( var->IsFlagSet( FCVAR_NOTIFY ) )
  1046. {
  1047. ConMsg( " notify" );
  1048. any = true;
  1049. }
  1050. if ( var->IsFlagSet( FCVAR_SPONLY ) )
  1051. {
  1052. ConMsg( " singleplayer" );
  1053. any = true;
  1054. }
  1055. if ( var->IsFlagSet( FCVAR_NOT_CONNECTED ) )
  1056. {
  1057. ConMsg( " notconnected" );
  1058. any = true;
  1059. }
  1060. if ( var->IsFlagSet( FCVAR_CHEAT ) )
  1061. {
  1062. ConMsg( " cheat" );
  1063. any = true;
  1064. }
  1065. if ( var->IsFlagSet( FCVAR_REPLICATED ) )
  1066. {
  1067. ConMsg( " replicated" );
  1068. any = true;
  1069. }
  1070. if ( var->IsFlagSet( FCVAR_SERVER_CAN_EXECUTE ) )
  1071. {
  1072. ConMsg( " server_can_execute" );
  1073. any = true;
  1074. }
  1075. if ( var->IsFlagSet( FCVAR_CLIENTCMD_CAN_EXECUTE ) )
  1076. {
  1077. ConMsg( " clientcmd_can_execute" );
  1078. any = true;
  1079. }
  1080. if ( any )
  1081. {
  1082. ConMsg( "\n" );
  1083. }
  1084. }
  1085. //-----------------------------------------------------------------------------
  1086. // Purpose:
  1087. //-----------------------------------------------------------------------------
  1088. void ConVar_PrintDescription( const ConCommandBase *pVar )
  1089. {
  1090. bool bMin, bMax;
  1091. float fMin, fMax;
  1092. const char *pStr;
  1093. assert( pVar );
  1094. Color clr;
  1095. clr.SetColor( 255, 100, 100, 255 );
  1096. if ( !pVar->IsCommand() )
  1097. {
  1098. ConVar *var = ( ConVar * )pVar;
  1099. const ConVar_ServerBounded *pBounded = dynamic_cast<const ConVar_ServerBounded*>( var );
  1100. bMin = var->GetMin( fMin );
  1101. bMax = var->GetMax( fMax );
  1102. const char *value = NULL;
  1103. char tempVal[ 32 ];
  1104. if ( pBounded || var->IsFlagSet( FCVAR_NEVER_AS_STRING ) )
  1105. {
  1106. value = tempVal;
  1107. int intVal = pBounded ? pBounded->GetInt() : var->GetInt();
  1108. float floatVal = pBounded ? pBounded->GetFloat() : var->GetFloat();
  1109. if ( fabs( (float)intVal - floatVal ) < 0.000001 )
  1110. {
  1111. Q_snprintf( tempVal, sizeof( tempVal ), "%d", intVal );
  1112. }
  1113. else
  1114. {
  1115. Q_snprintf( tempVal, sizeof( tempVal ), "%f", floatVal );
  1116. }
  1117. }
  1118. else
  1119. {
  1120. value = var->GetString();
  1121. }
  1122. if ( value )
  1123. {
  1124. ConColorMsg( clr, "\"%s\" = \"%s\"", var->GetName(), value );
  1125. if ( stricmp( value, var->GetDefault() ) )
  1126. {
  1127. ConMsg( " ( def. \"%s\" )", var->GetDefault() );
  1128. }
  1129. }
  1130. if ( bMin )
  1131. {
  1132. ConMsg( " min. %f", fMin );
  1133. }
  1134. if ( bMax )
  1135. {
  1136. ConMsg( " max. %f", fMax );
  1137. }
  1138. ConMsg( "\n" );
  1139. // Handled virtualized cvars.
  1140. if ( pBounded && fabs( pBounded->GetFloat() - var->GetFloat() ) > 0.0001f )
  1141. {
  1142. ConColorMsg( clr, "** NOTE: The real value is %.3f but the server has temporarily restricted it to %.3f **\n",
  1143. var->GetFloat(), pBounded->GetFloat() );
  1144. }
  1145. }
  1146. else
  1147. {
  1148. ConCommand *var = ( ConCommand * )pVar;
  1149. ConColorMsg( clr, "\"%s\"\n", var->GetName() );
  1150. }
  1151. ConVar_PrintFlags( pVar );
  1152. pStr = pVar->GetHelpText();
  1153. if ( pStr && pStr[0] )
  1154. {
  1155. ConMsg( " - %s\n", pStr );
  1156. }
  1157. }