summaryrefslogtreecommitdiff
path: root/external/vpc/vstdlib/cvar.cpp
diff options
context:
space:
mode:
authorFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
committerFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
commit3bf9df6b2785fa6d951086978a3e66f49427166a (patch)
tree2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /external/vpc/vstdlib/cvar.cpp
downloadarchived-source-engine-2018-hl2-src-3bf9df6b2785fa6d951086978a3e66f49427166a.tar.xz
archived-source-engine-2018-hl2-src-3bf9df6b2785fa6d951086978a3e66f49427166a.zip
Diffstat (limited to 'external/vpc/vstdlib/cvar.cpp')
-rw-r--r--external/vpc/vstdlib/cvar.cpp1302
1 files changed, 1302 insertions, 0 deletions
diff --git a/external/vpc/vstdlib/cvar.cpp b/external/vpc/vstdlib/cvar.cpp
new file mode 100644
index 0000000..060b674
--- /dev/null
+++ b/external/vpc/vstdlib/cvar.cpp
@@ -0,0 +1,1302 @@
+//===== Copyright 1996-2005, Valve Corporation, All rights reserved. ======//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//===========================================================================//
+
+#include "vstdlib/cvar.h"
+#include <ctype.h>
+#include "tier0/icommandline.h"
+#include "tier1/utlrbtree.h"
+#include "tier1/strtools.h"
+#include "tier1/keyvalues.h"
+#include "tier1/convar.h"
+#include "tier0/vprof.h"
+#include "tier1/tier1.h"
+#include "tier1/utlbuffer.h"
+#include "tier1/utlmap.h"
+#include "tier1/fmtstr.h"
+
+#ifdef _X360
+#include "xbox/xbox_console.h"
+#elif defined( _PS3 )
+#include "ps3/ps3_console.h"
+#endif
+
+#ifdef POSIX
+#include <wctype.h>
+#include <wchar.h>
+
+#define VPROJ_INCREMENT_COUNTER(a, b) /* */
+#define VPROJ(a) /* */
+#endif
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+
+//-----------------------------------------------------------------------------
+// Default implementation of CvarQuery
+//-----------------------------------------------------------------------------
+class CDefaultCvarQuery : public CBaseAppSystem< ICvarQuery >
+{
+public:
+ virtual void *QueryInterface( const char *pInterfaceName )
+ {
+ if ( !V_stricmp( pInterfaceName, CVAR_QUERY_INTERFACE_VERSION ) )
+ return (ICvarQuery*)this;
+ return NULL;
+
+ }
+
+ virtual bool AreConVarsLinkable( const ConVar *child, const ConVar *parent )
+ {
+ return true;
+ }
+};
+
+static CDefaultCvarQuery s_DefaultCvarQuery;
+static ICvarQuery *s_pCVarQuery = NULL;
+
+#include "concommandhash.h"
+
+//-----------------------------------------------------------------------------
+// Default implementation
+//-----------------------------------------------------------------------------
+class CCvar : public CBaseAppSystem< ICvar >
+{
+public:
+ CCvar();
+
+ // Methods of IAppSystem
+ virtual bool Connect( CreateInterfaceFn factory );
+ virtual void Disconnect();
+ virtual void *QueryInterface( const char *pInterfaceName );
+ virtual InitReturnVal_t Init();
+ virtual void Shutdown();
+
+ // Inherited from ICVar
+ virtual CVarDLLIdentifier_t AllocateDLLIdentifier();
+ virtual void RegisterConCommand( ConCommandBase *pCommandBase );
+ virtual void UnregisterConCommand( ConCommandBase *pCommandBase );
+ virtual void UnregisterConCommands( CVarDLLIdentifier_t id );
+ virtual const char* GetCommandLineValue( const char *pVariableName );
+ virtual ConCommandBase *FindCommandBase( const char *name );
+ virtual const ConCommandBase *FindCommandBase( const char *name ) const;
+ virtual ConVar *FindVar ( const char *var_name );
+ virtual const ConVar *FindVar ( const char *var_name ) const;
+ virtual ConCommand *FindCommand( const char *name );
+ virtual const ConCommand *FindCommand( const char *name ) const;
+ virtual void InstallGlobalChangeCallback( FnChangeCallback_t callback );
+ virtual void RemoveGlobalChangeCallback( FnChangeCallback_t callback );
+ virtual void CallGlobalChangeCallbacks( ConVar *var, const char *pOldString, float flOldValue );
+ virtual void InstallConsoleDisplayFunc( IConsoleDisplayFunc* pDisplayFunc );
+ virtual void RemoveConsoleDisplayFunc( IConsoleDisplayFunc* pDisplayFunc );
+ virtual void ConsoleColorPrintf( const Color& clr, const char *pFormat, ... ) const;
+ virtual void ConsolePrintf( const char *pFormat, ... ) const;
+ virtual void ConsoleDPrintf( const char *pFormat, ... ) const;
+ virtual void RevertFlaggedConVars( int nFlag );
+ virtual void InstallCVarQuery( ICvarQuery *pQuery );
+
+#if defined( USE_VXCONSOLE )
+ virtual void PublishToVXConsole( );
+#endif
+
+ virtual void SetMaxSplitScreenSlots( int nSlots );
+ virtual int GetMaxSplitScreenSlots() const;
+
+ virtual void AddSplitScreenConVars();
+ virtual void RemoveSplitScreenConVars( CVarDLLIdentifier_t id );
+
+ virtual int GetConsoleDisplayFuncCount() const;
+ virtual void GetConsoleText( int nDisplayFuncIndex, char *pchText, size_t bufSize ) const;
+ virtual bool IsMaterialThreadSetAllowed( ) const;
+ virtual void QueueMaterialThreadSetValue( ConVar *pConVar, const char *pValue );
+ virtual void QueueMaterialThreadSetValue( ConVar *pConVar, int nValue );
+ virtual void QueueMaterialThreadSetValue( ConVar *pConVar, float flValue );
+ virtual bool HasQueuedMaterialThreadConVarSets() const;
+ virtual int ProcessQueuedMaterialThreadConVarSets();
+
+private:
+ enum
+ {
+ CONSOLE_COLOR_PRINT = 0,
+ CONSOLE_PRINT,
+ CONSOLE_DPRINT,
+ };
+
+ void DisplayQueuedMessages( );
+
+ CUtlVector< FnChangeCallback_t > m_GlobalChangeCallbacks;
+ CUtlVector< IConsoleDisplayFunc* > m_DisplayFuncs;
+ int m_nNextDLLIdentifier;
+
+ ConCommandBase *m_pConCommandList;
+ CConCommandHash m_CommandHash;
+
+ // temporary console area so we can store prints before console display funs are installed
+ mutable CUtlBuffer m_TempConsoleBuffer;
+ int m_nMaxSplitScreenSlots;
+
+protected:
+
+ // internals for ICVarIterator
+ class CCVarIteratorInternal : public ICVarIteratorInternal
+ {
+ public:
+ CCVarIteratorInternal( CCvar *outer )
+ : m_pOuter( outer ), m_pHash( &outer->m_CommandHash ), // remember my CCvar,
+ m_hashIter( -1, -1 ) // and invalid iterator
+ {}
+ virtual void SetFirst( void );
+ virtual void Next( void );
+ virtual bool IsValid( void );
+ virtual ConCommandBase *Get( void );
+ protected:
+ CCvar * const m_pOuter;
+ CConCommandHash * const m_pHash;
+ CConCommandHash::CCommandHashIterator_t m_hashIter;
+ };
+
+ virtual ICVarIteratorInternal *FactoryInternalIterator( void );
+ friend class CCVarIteratorInternal;
+
+ enum ConVarSetType_t
+ {
+ CONVAR_SET_STRING = 0,
+ CONVAR_SET_INT,
+ CONVAR_SET_FLOAT,
+ };
+
+ struct QueuedConVarSet_t
+ {
+ ConVar *m_pConVar;
+ ConVarSetType_t m_nType;
+ int m_nInt;
+ float m_flFloat;
+ CUtlString m_String;
+ };
+
+ struct SplitScreenConVar_t
+ {
+ SplitScreenConVar_t()
+ {
+ Reset();
+ }
+
+ void Reset()
+ {
+ m_VarName = "";
+ m_pVar = NULL;
+ }
+
+ CUtlString m_VarName;
+ CSplitScreenAddedConVar *m_pVar;
+ };
+
+ struct SplitScreenAddedConVars_t
+ {
+ SplitScreenAddedConVars_t()
+ {
+ for ( int i = 0; i < MAX_SPLITSCREEN_CLIENTS - 1; ++i )
+ {
+ m_Vars[ i ].Reset();
+ }
+ }
+
+ // Var names need "static" buffers...
+ SplitScreenConVar_t m_Vars[ MAX_SPLITSCREEN_CLIENTS - 1 ];
+ };
+
+ CUtlMap< ConVar *, SplitScreenAddedConVars_t > m_SplitScreenAddedConVarsMap;
+ CUtlVector< QueuedConVarSet_t > m_QueuedConVarSets;
+ bool m_bMaterialSystemThreadSetAllowed;
+
+private:
+ // Standard console commands -- DO NOT PLACE ANY HIGHER THAN HERE BECAUSE THESE MUST BE THE FIRST TO DESTRUCT
+ CON_COMMAND_MEMBER_F( CCvar, "find", Find, "Find concommands with the specified string in their name/help text.", 0 )
+#ifdef _DEBUG
+ CON_COMMAND_MEMBER_F( CCvar, "ccvar_hash_report", HashReport, "report info on bucket distribution of internal hash.", 0 )
+#endif
+};
+
+void CCvar::CCVarIteratorInternal::SetFirst( void )
+{
+ m_hashIter = m_pHash->First();
+}
+
+void CCvar::CCVarIteratorInternal::Next( void )
+{
+ m_hashIter = m_pHash->Next( m_hashIter );
+}
+
+bool CCvar::CCVarIteratorInternal::IsValid( void )
+{
+ return m_pHash->IsValidIterator( m_hashIter );
+}
+
+ConCommandBase *CCvar::CCVarIteratorInternal::Get( void )
+{
+ Assert( IsValid( ) );
+ return (*m_pHash)[m_hashIter];
+}
+
+ICvar::ICVarIteratorInternal *CCvar::FactoryInternalIterator( void )
+{
+ return new CCVarIteratorInternal( this );
+}
+
+//-----------------------------------------------------------------------------
+// Factor for CVars
+//-----------------------------------------------------------------------------
+static CCvar s_Cvar;
+EXPOSE_SINGLE_INTERFACE_GLOBALVAR( CCvar, ICvar, CVAR_INTERFACE_VERSION, s_Cvar );
+
+
+//-----------------------------------------------------------------------------
+// Returns a CVar dictionary for tool usage
+//-----------------------------------------------------------------------------
+CreateInterfaceFn VStdLib_GetICVarFactory()
+{
+ return Sys_GetFactoryThis();
+}
+
+
+//-----------------------------------------------------------------------------
+// Constructor
+//-----------------------------------------------------------------------------
+CCvar::CCvar() : m_TempConsoleBuffer( 0, 1024 ), m_SplitScreenAddedConVarsMap( 0, 0, DefLessFunc( ConVar * ) )
+{
+ m_nNextDLLIdentifier = 0;
+ m_pConCommandList = NULL;
+ m_nMaxSplitScreenSlots = 1;
+ m_bMaterialSystemThreadSetAllowed = false;
+ m_CommandHash.Init();
+}
+
+//-----------------------------------------------------------------------------
+// Methods of IAppSystem
+//-----------------------------------------------------------------------------
+bool CCvar::Connect( CreateInterfaceFn factory )
+{
+ ConnectTier1Libraries( &factory, 1 );
+
+ s_pCVarQuery = (ICvarQuery*)factory( CVAR_QUERY_INTERFACE_VERSION, NULL );
+ if ( !s_pCVarQuery )
+ {
+ s_pCVarQuery = &s_DefaultCvarQuery;
+ }
+
+ ConVar_Register();
+ return true;
+}
+
+void CCvar::Disconnect()
+{
+ ConVar_Unregister();
+ s_pCVarQuery = NULL;
+ DisconnectTier1Libraries();
+
+ Assert( m_SplitScreenAddedConVarsMap.Count() == 0 );
+}
+
+InitReturnVal_t CCvar::Init()
+{
+ return INIT_OK;
+}
+
+void CCvar::Shutdown()
+{
+}
+
+void *CCvar::QueryInterface( const char *pInterfaceName )
+{
+ // We implement the ICvar interface
+ if ( !V_strcmp( pInterfaceName, CVAR_INTERFACE_VERSION ) )
+ return (ICvar*)this;
+
+ return NULL;
+}
+
+
+//-----------------------------------------------------------------------------
+// Method allowing the engine ICvarQuery interface to take over
+//-----------------------------------------------------------------------------
+void CCvar::InstallCVarQuery( ICvarQuery *pQuery )
+{
+ Assert( s_pCVarQuery == &s_DefaultCvarQuery );
+ s_pCVarQuery = pQuery ? pQuery : &s_DefaultCvarQuery;
+}
+
+
+//-----------------------------------------------------------------------------
+// Used by DLLs to be able to unregister all their commands + convars
+//-----------------------------------------------------------------------------
+CVarDLLIdentifier_t CCvar::AllocateDLLIdentifier()
+{
+ return m_nNextDLLIdentifier++;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *variable -
+//-----------------------------------------------------------------------------
+void CCvar::RegisterConCommand( ConCommandBase *variable )
+{
+ // Already registered
+ if ( variable->IsRegistered() )
+ return;
+
+ variable->m_bRegistered = true;
+
+ const char *pName = variable->GetName();
+ if ( !pName || !pName[0] )
+ {
+ variable->m_pNext = NULL;
+ return;
+ }
+
+ // If the variable is already defined, then setup the new variable as a proxy to it.
+ const ConCommandBase *pOther = FindCommandBase( variable->GetName() );
+ if ( pOther )
+ {
+ if ( variable->IsCommand() || pOther->IsCommand() )
+ {
+ Warning( "WARNING: unable to link %s and %s because one or more is a ConCommand.\n", variable->GetName(), pOther->GetName() );
+ }
+ else
+ {
+ // This cast is ok because we make sure they're ConVars above.
+ ConVar *pChildVar = const_cast< ConVar* >( static_cast< const ConVar* >( variable ) );
+ ConVar *pParentVar = const_cast< ConVar* >( static_cast< const ConVar* >( pOther ) );
+
+ // See if it's a valid linkage
+ if ( s_pCVarQuery->AreConVarsLinkable( pChildVar, pParentVar ) )
+ {
+ // Make sure the default values are the same (but only spew about this for FCVAR_REPLICATED)
+ if( pChildVar->m_pszDefaultValue && pParentVar->m_pszDefaultValue &&
+ pChildVar->IsFlagSet( FCVAR_REPLICATED ) && pParentVar->IsFlagSet( FCVAR_REPLICATED ) )
+ {
+ if( V_stricmp( pChildVar->m_pszDefaultValue, pParentVar->m_pszDefaultValue ) != 0 )
+ {
+ Warning( "Parent and child ConVars with different default values! %s child: %s parent: %s (parent wins)\n",
+ variable->GetName(), pChildVar->m_pszDefaultValue, pParentVar->m_pszDefaultValue );
+ }
+ }
+
+ pChildVar->m_pParent = pParentVar->m_pParent;
+
+ // Absorb material thread related convar flags
+ pParentVar->m_nFlags |= pChildVar->m_nFlags & ( FCVAR_MATERIAL_THREAD_MASK | FCVAR_ACCESSIBLE_FROM_THREADS );
+
+ // Transfer children's callbacks to parent
+ if ( pChildVar->m_fnChangeCallbacks.Count() )
+ {
+ for ( int i = 0; i < pChildVar->m_fnChangeCallbacks.Count(); ++i )
+ {
+ pParentVar->m_fnChangeCallbacks.AddToTail( pChildVar->m_fnChangeCallbacks[ i ] );
+ }
+ // Wipe child callbacks
+ pChildVar->m_fnChangeCallbacks.RemoveAll();
+ }
+
+ // make sure we don't have conflicting help strings.
+ if ( pChildVar->m_pszHelpString && V_strlen( pChildVar->m_pszHelpString ) != 0 )
+ {
+ if ( pParentVar->m_pszHelpString && V_strlen( pParentVar->m_pszHelpString ) != 0 )
+ {
+ if ( V_stricmp( pParentVar->m_pszHelpString, pChildVar->m_pszHelpString ) != 0 )
+ {
+ Warning( "Convar %s has multiple help strings:\n\tparent (wins): \"%s\"\n\tchild: \"%s\"\n",
+ variable->GetName(), pParentVar->m_pszHelpString, pChildVar->m_pszHelpString );
+ }
+ }
+ else
+ {
+ pParentVar->m_pszHelpString = pChildVar->m_pszHelpString;
+ }
+ }
+
+ // make sure we don't have conflicting FCVAR_*** flags.
+ static int const nFlags[] =
+ { FCVAR_CHEAT, FCVAR_REPLICATED, FCVAR_DONTRECORD, FCVAR_ARCHIVE, FCVAR_ARCHIVE_GAMECONSOLE };
+ static char const * const szFlags[] =
+ { "FCVAR_CHEAT", "FCVAR_REPLICATED", "FCVAR_DONTRECORD", "FCVAR_ARCHIVE", "FCVAR_ARCHIVE_GAMECONSOLE" };
+
+ COMPILE_TIME_ASSERT( ARRAYSIZE( nFlags ) == ARRAYSIZE( szFlags ) );
+
+ for ( int k = 0; k < ARRAYSIZE( nFlags ); ++ k )
+ {
+ if ( ( pChildVar->m_nFlags & nFlags[k] ) != ( pParentVar->m_nFlags & nFlags[k] ) )
+ {
+ Warning( "Convar %s has conflicting %s flags (child: %s%s, parent: %s%s, parent wins)\n",
+ variable->GetName(), szFlags[k],
+ ( pChildVar->m_nFlags & nFlags[k] ) ? "has " : "no ", szFlags[k],
+ ( pParentVar->m_nFlags & nFlags[k] ) ? "has " : "no ", szFlags[k] );
+ }
+ }
+ }
+ }
+
+ variable->m_pNext = NULL;
+ return;
+ }
+
+ // link the variable in
+ variable->m_pNext = m_pConCommandList;
+ m_pConCommandList = variable;
+
+ AssertMsg1(FindCommandBase(variable->GetName()) == NULL, "Console command %s added twice!",
+ variable->GetName());
+ m_CommandHash.Insert(variable);
+}
+
+void CCvar::AddSplitScreenConVars()
+{
+ if ( m_nMaxSplitScreenSlots == 1 )
+ return;
+
+ for( ConCommandBase *pCommand = m_pConCommandList; pCommand; pCommand = pCommand->m_pNext )
+ {
+ if ( pCommand->IsCommand() )
+ continue;
+
+ ConVar *pConVar = static_cast< ConVar * >( pCommand );
+
+ if ( !pConVar->IsFlagSet( FCVAR_SS ) )
+ continue;
+
+ // See if it's already mapped in
+ int idx = m_SplitScreenAddedConVarsMap.Find( pConVar );
+ if ( idx == m_SplitScreenAddedConVarsMap.InvalidIndex() )
+ {
+ idx = m_SplitScreenAddedConVarsMap.Insert( pConVar );
+ }
+
+ SplitScreenAddedConVars_t &info = m_SplitScreenAddedConVarsMap[ idx ];
+ for ( int i = 1 ; i < m_nMaxSplitScreenSlots; ++i )
+ {
+ // Already registered it
+ if ( info.m_Vars[ i - 1 ].m_pVar )
+ continue;
+
+ // start at name2, etc.
+ info.m_Vars[ i - 1 ].m_VarName = CFmtStr( "%s%d", pConVar->GetName(), i + 1 );
+
+ CSplitScreenAddedConVar *pVar = new CSplitScreenAddedConVar( i, info.m_Vars[ i - 1 ].m_VarName.Get(), pConVar );
+ info.m_Vars[ i - 1 ].m_pVar = pVar;
+ pVar->SetSplitScreenPlayerSlot( i );
+
+ RegisterConCommand( pVar );
+ }
+ }
+
+ ConCommandBase::s_pConCommandBases = NULL;
+}
+
+void CCvar::RemoveSplitScreenConVars( CVarDLLIdentifier_t id )
+
+{
+ if ( m_nMaxSplitScreenSlots == 1 )
+ {
+ Assert( m_SplitScreenAddedConVarsMap.Count() == 0 );
+ return;
+ }
+
+ CUtlVector< ConVar * > deleted;
+
+ FOR_EACH_MAP( m_SplitScreenAddedConVarsMap, i )
+ {
+ ConVar *key = m_SplitScreenAddedConVarsMap.Key( i );
+
+ if ( key->GetDLLIdentifier() != id )
+ {
+ continue;
+ }
+
+ SplitScreenAddedConVars_t &info = m_SplitScreenAddedConVarsMap[ i ];
+
+
+
+ for ( int i = 1 ; i < m_nMaxSplitScreenSlots; ++i )
+ {
+
+ if ( info.m_Vars[ i - 1 ].m_pVar )
+ {
+ UnregisterConCommand( info.m_Vars[ i - 1 ].m_pVar );
+ delete info.m_Vars[ i - 1 ].m_pVar;
+ info.m_Vars[ i - 1 ].m_pVar = NULL;
+ }
+ }
+ deleted.AddToTail( key );
+ }
+
+ for ( int i = 0; i < deleted.Count(); ++i )
+ {
+ m_SplitScreenAddedConVarsMap.Remove( deleted[ i ] );
+ }
+}
+
+void CCvar::UnregisterConCommand( ConCommandBase *pCommandToRemove )
+{
+ // Not registered? Don't bother
+ if ( !pCommandToRemove->IsRegistered() )
+ return;
+
+ pCommandToRemove->m_bRegistered = false;
+
+ // FIXME: Should we make this a doubly-linked list? Would remove faster
+ ConCommandBase *pPrev = NULL;
+ for( ConCommandBase *pCommand = m_pConCommandList; pCommand; pCommand = pCommand->m_pNext )
+ {
+ if ( pCommand != pCommandToRemove )
+ {
+ pPrev = pCommand;
+ continue;
+ }
+
+ if ( pPrev == NULL )
+ {
+ m_pConCommandList = pCommand->m_pNext;
+ }
+ else
+ {
+ pPrev->m_pNext = pCommand->m_pNext;
+ }
+ pCommand->m_pNext = NULL;
+ m_CommandHash.Remove(m_CommandHash.Find(pCommand));
+ break;
+ }
+}
+
+void CCvar::UnregisterConCommands( CVarDLLIdentifier_t id )
+{
+ ConCommandBase *pNewList;
+ ConCommandBase *pCommand, *pNext;
+
+ pNewList = NULL;
+
+ m_CommandHash.Purge( true );
+ pCommand = m_pConCommandList;
+ while ( pCommand )
+ {
+ pNext = pCommand->m_pNext;
+ if ( pCommand->GetDLLIdentifier() != id )
+ {
+ pCommand->m_pNext = pNewList;
+ pNewList = pCommand;
+
+ m_CommandHash.Insert( pCommand );
+ }
+ else
+ {
+ // Unlink
+ pCommand->m_bRegistered = false;
+ pCommand->m_pNext = NULL;
+
+ }
+
+ pCommand = pNext;
+ }
+
+ m_pConCommandList = pNewList;
+}
+
+
+//-----------------------------------------------------------------------------
+// Finds base commands
+//-----------------------------------------------------------------------------
+const ConCommandBase *CCvar::FindCommandBase( const char *name ) const
+{
+ VPROF_INCREMENT_COUNTER( "CCvar::FindCommandBase", 1 );
+ VPROF_BUDGET( "CCvar::FindCommandBase", VPROF_BUDGETGROUP_CVAR_FIND );
+
+ return m_CommandHash.FindPtr( name );
+}
+
+ConCommandBase *CCvar::FindCommandBase( const char *name )
+{
+ VPROF_INCREMENT_COUNTER( "CCvar::FindCommandBase", 1 );
+ VPROF_BUDGET( "CCvar::FindCommandBase", VPROF_BUDGETGROUP_CVAR_FIND );
+
+ return m_CommandHash.FindPtr( name );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose Finds ConVars
+//-----------------------------------------------------------------------------
+const ConVar *CCvar::FindVar( const char *var_name ) const
+{
+ const ConCommandBase *var = FindCommandBase( var_name );
+ if ( !var )
+ {
+ return NULL;
+ }
+ else
+ {
+ if (var->IsCommand())
+ {
+ AssertMsg1( false , "Tried to look up command %s as if it were a variable.\n", var_name );
+ return NULL;
+ }
+ }
+
+ return static_cast<const ConVar*>(var);
+}
+
+ConVar *CCvar::FindVar( const char *var_name )
+{
+ ConCommandBase *var = FindCommandBase( var_name );
+ if ( !var )
+ {
+ return NULL;
+ }
+ else
+ {
+ if (var->IsCommand())
+ {
+ AssertMsg1( false , "Tried to look up command %s as if it were a variable.\n", var_name );
+ return NULL;
+ }
+ }
+
+ return static_cast<ConVar*>( var );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose Finds ConCommands
+//-----------------------------------------------------------------------------
+const ConCommand *CCvar::FindCommand( const char *pCommandName ) const
+{
+ const ConCommandBase *var = FindCommandBase( pCommandName );
+ if ( !var || !var->IsCommand() )
+ return NULL;
+
+ return static_cast<const ConCommand*>(var);
+}
+
+ConCommand *CCvar::FindCommand( const char *pCommandName )
+{
+ ConCommandBase *var = FindCommandBase( pCommandName );
+ if ( !var || !var->IsCommand() )
+ return NULL;
+
+ return static_cast<ConCommand*>( var );
+}
+
+
+const char* CCvar::GetCommandLineValue( const char *pVariableName )
+{
+ int nLen = V_strlen(pVariableName);
+ char *pSearch = (char*)stackalloc( nLen + 2 );
+ pSearch[0] = '+';
+ memcpy( &pSearch[1], pVariableName, nLen + 1 );
+ return CommandLine()->ParmValue( pSearch );
+}
+
+//-----------------------------------------------------------------------------
+// Install, remove global callbacks
+//-----------------------------------------------------------------------------
+void CCvar::InstallGlobalChangeCallback( FnChangeCallback_t callback )
+{
+ Assert( callback && m_GlobalChangeCallbacks.Find( callback ) < 0 );
+ m_GlobalChangeCallbacks.AddToTail( callback );
+}
+
+void CCvar::RemoveGlobalChangeCallback( FnChangeCallback_t callback )
+{
+ Assert( callback );
+ m_GlobalChangeCallbacks.FindAndRemove( callback );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CCvar::CallGlobalChangeCallbacks( ConVar *var, const char *pOldString, float flOldValue )
+{
+ int nCallbackCount = m_GlobalChangeCallbacks.Count();
+ for ( int i = 0; i < nCallbackCount; ++i )
+ {
+ (*m_GlobalChangeCallbacks[i])( var, pOldString, flOldValue );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Sets convars containing the flags to their default value
+//-----------------------------------------------------------------------------
+void CCvar::RevertFlaggedConVars( int nFlag )
+{
+ for ( CConCommandHash::CCommandHashIterator_t i = m_CommandHash.First() ;
+ m_CommandHash.IsValidIterator( i ) ;
+ i = m_CommandHash.Next( i ) )
+ {
+ ConCommandBase *var = m_CommandHash[ i ];
+ if ( var->IsCommand() )
+ continue;
+
+ ConVar *cvar = ( ConVar * )var;
+
+ if ( !cvar->IsFlagSet( nFlag ) )
+ continue;
+
+ // It's == to the default value, don't count
+ if ( !V_stricmp( cvar->GetDefault(), cvar->GetString() ) )
+ continue;
+
+ cvar->Revert();
+ // DevMsg( "%s = \"%s\" (reverted)\n", cvar->GetName(), cvar->GetString() );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Deal with queued material system convars
+//-----------------------------------------------------------------------------
+bool CCvar::IsMaterialThreadSetAllowed( ) const
+{
+ Assert( ThreadInMainThread() );
+ return m_bMaterialSystemThreadSetAllowed;
+}
+
+void CCvar::QueueMaterialThreadSetValue( ConVar *pConVar, const char *pValue )
+{
+ Assert( ThreadInMainThread() );
+ int j = m_QueuedConVarSets.AddToTail();
+ m_QueuedConVarSets[j].m_pConVar = pConVar;
+ m_QueuedConVarSets[j].m_nType = CONVAR_SET_STRING;
+ m_QueuedConVarSets[j].m_String = pValue;
+}
+
+void CCvar::QueueMaterialThreadSetValue( ConVar *pConVar, int nValue )
+{
+ Assert( ThreadInMainThread() );
+ int j = m_QueuedConVarSets.AddToTail();
+ m_QueuedConVarSets[j].m_pConVar = pConVar;
+ m_QueuedConVarSets[j].m_nType = CONVAR_SET_INT;
+ m_QueuedConVarSets[j].m_nInt = nValue;
+}
+
+void CCvar::QueueMaterialThreadSetValue( ConVar *pConVar, float flValue )
+{
+ Assert( ThreadInMainThread() );
+ int j = m_QueuedConVarSets.AddToTail();
+ m_QueuedConVarSets[j].m_pConVar = pConVar;
+ m_QueuedConVarSets[j].m_nType = CONVAR_SET_FLOAT;
+ m_QueuedConVarSets[j].m_flFloat = flValue;
+}
+
+bool CCvar::HasQueuedMaterialThreadConVarSets() const
+{
+ Assert( ThreadInMainThread() );
+ return m_QueuedConVarSets.Count() > 0;
+}
+
+int CCvar::ProcessQueuedMaterialThreadConVarSets()
+{
+ Assert( ThreadInMainThread() );
+ m_bMaterialSystemThreadSetAllowed = true;
+
+ int nUpdateFlags = 0;
+ int nCount = m_QueuedConVarSets.Count();
+ for ( int i = 0; i < nCount; ++i )
+ {
+ const QueuedConVarSet_t& set = m_QueuedConVarSets[i];
+ switch( set.m_nType )
+ {
+ case CONVAR_SET_FLOAT:
+ set.m_pConVar->SetValue( set.m_flFloat );
+ break;
+ case CONVAR_SET_INT:
+ set.m_pConVar->SetValue( set.m_nInt );
+ break;
+ case CONVAR_SET_STRING:
+ set.m_pConVar->SetValue( set.m_String );
+ break;
+ }
+
+ nUpdateFlags |= set.m_pConVar->GetFlags() & FCVAR_MATERIAL_THREAD_MASK;
+ }
+
+ m_QueuedConVarSets.RemoveAll();
+ m_bMaterialSystemThreadSetAllowed = false;
+ return nUpdateFlags;
+}
+
+
+//-----------------------------------------------------------------------------
+// Display queued messages
+//-----------------------------------------------------------------------------
+void CCvar::DisplayQueuedMessages( )
+{
+ // Display any queued up messages
+ if ( m_TempConsoleBuffer.TellPut() == 0 )
+ return;
+
+ Color clr;
+ int nStringLength;
+ while( m_TempConsoleBuffer.IsValid() )
+ {
+ int nType = m_TempConsoleBuffer.GetChar();
+ if ( nType == CONSOLE_COLOR_PRINT )
+ {
+ clr.SetRawColor( m_TempConsoleBuffer.GetInt() );
+ }
+ nStringLength = m_TempConsoleBuffer.PeekStringLength();
+ char* pTemp = (char*)stackalloc( nStringLength + 1 );
+ m_TempConsoleBuffer.GetString( pTemp );
+
+ switch( nType )
+ {
+ case CONSOLE_COLOR_PRINT:
+ ConsoleColorPrintf( clr, pTemp );
+ break;
+
+ case CONSOLE_PRINT:
+ ConsolePrintf( pTemp );
+ break;
+
+ case CONSOLE_DPRINT:
+ ConsoleDPrintf( pTemp );
+ break;
+ }
+ }
+
+ m_TempConsoleBuffer.Purge();
+}
+
+
+//-----------------------------------------------------------------------------
+// Install a console printer
+//-----------------------------------------------------------------------------
+void CCvar::InstallConsoleDisplayFunc( IConsoleDisplayFunc* pDisplayFunc )
+{
+ Assert( m_DisplayFuncs.Find( pDisplayFunc ) < 0 );
+ m_DisplayFuncs.AddToTail( pDisplayFunc );
+ DisplayQueuedMessages();
+}
+
+void CCvar::RemoveConsoleDisplayFunc( IConsoleDisplayFunc* pDisplayFunc )
+{
+ m_DisplayFuncs.FindAndRemove( pDisplayFunc );
+}
+
+int CCvar::GetConsoleDisplayFuncCount() const
+{
+ return m_DisplayFuncs.Count();
+}
+
+void CCvar::GetConsoleText( int nDisplayFuncIndex, char *pchText, size_t bufSize ) const
+{
+ m_DisplayFuncs[ nDisplayFuncIndex ]->GetConsoleText( pchText, bufSize );
+}
+
+void CCvar::ConsoleColorPrintf( const Color& clr, const char *pFormat, ... ) const
+{
+ char temp[ 8192 ];
+ va_list argptr;
+ va_start( argptr, pFormat );
+ _vsnprintf( temp, sizeof( temp ) - 1, pFormat, argptr );
+ va_end( argptr );
+ temp[ sizeof( temp ) - 1 ] = 0;
+
+ int c = m_DisplayFuncs.Count();
+ if ( c == 0 )
+ {
+ m_TempConsoleBuffer.PutChar( CONSOLE_COLOR_PRINT );
+ m_TempConsoleBuffer.PutInt( clr.GetRawColor() );
+ m_TempConsoleBuffer.PutString( temp );
+ return;
+ }
+
+ for ( int i = 0 ; i < c; ++i )
+ {
+ m_DisplayFuncs[ i ]->ColorPrint( clr, temp );
+ }
+}
+
+void CCvar::ConsolePrintf( const char *pFormat, ... ) const
+{
+ char temp[ 8192 ];
+ va_list argptr;
+ va_start( argptr, pFormat );
+ _vsnprintf( temp, sizeof( temp ) - 1, pFormat, argptr );
+ va_end( argptr );
+ temp[ sizeof( temp ) - 1 ] = 0;
+
+ int c = m_DisplayFuncs.Count();
+ if ( c == 0 )
+ {
+ m_TempConsoleBuffer.PutChar( CONSOLE_PRINT );
+ m_TempConsoleBuffer.PutString( temp );
+ return;
+ }
+
+ for ( int i = 0 ; i < c; ++i )
+ {
+ m_DisplayFuncs[ i ]->Print( temp );
+ }
+}
+
+void CCvar::ConsoleDPrintf( const char *pFormat, ... ) const
+{
+ char temp[ 8192 ];
+ va_list argptr;
+ va_start( argptr, pFormat );
+ _vsnprintf( temp, sizeof( temp ) - 1, pFormat, argptr );
+ va_end( argptr );
+ temp[ sizeof( temp ) - 1 ] = 0;
+
+ int c = m_DisplayFuncs.Count();
+ if ( c == 0 )
+ {
+ m_TempConsoleBuffer.PutChar( CONSOLE_DPRINT );
+ m_TempConsoleBuffer.PutString( temp );
+ return;
+ }
+
+ for ( int i = 0 ; i < c; ++i )
+ {
+ m_DisplayFuncs[ i ]->DPrint( temp );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+#if defined( USE_VXCONSOLE )
+#ifdef _PS3
+/*
+Here's a terrible hack.
+In porting the part of the game that speaks to VXConsole, EA chose to
+write it as a cluster of global functions, instead of a class interface like
+Aaron did with IXboxConsole. Some of these globals need access to symbols
+inside the engine, so they are defined there. However, CCvar is inside vstdlib.
+In the EA build this didn't make a difference because everything was a huge
+monolithic executable, and you could just access any symbol from anywhere.
+In our build, with its PRXes, that doesn't fly.
+So, the proper solution to this problem is to wrap all of the PS3 vxconsole
+stuff in an interface, put it inside vstlib, create the dcim connection there,
+and then export the interface pointer. The engine meanwhile would export the
+symbols the vxlib needs, and then we give that interface class inside
+vstlib a pointer to the engine once the engine is available.
+Right now however I just want to get the thing working with as little modification
+as possible so I can fix the vxconsole windows app itself and hopefully get
+bidirectional TTY to our game. So, instead of the proper solution,
+I'm just duct-taping everything together by simply passing a pointer to the engine
+symbol this function needs whenever I call it.
+Blech. I'll fix it later.
+-egr 4/29/10. (is it later than September 2010? go call egr and make fun of him.)
+*/
+void CCvar::PublishToVXConsole()
+#else
+void CCvar::PublishToVXConsole()
+#endif
+{
+ const char *commands[6*1024];
+ const char *helptext[6*1024];
+ int numCommands = 0;
+
+ // iterate and publish commands to the remote console
+ for ( CConCommandHash::CCommandHashIterator_t i = m_CommandHash.First() ;
+ m_CommandHash.IsValidIterator( i ) ;
+ i = m_CommandHash.Next( i ) )
+ {
+ ConCommandBase *pCur = m_CommandHash[ i ];
+ // add unregistered commands to list
+ if ( numCommands < sizeof(commands)/sizeof(commands[0]) )
+ {
+ commands[numCommands] = pCur->GetName();
+ helptext[numCommands] = pCur->GetHelpText();
+ numCommands++;
+ }
+ }
+
+ if ( numCommands )
+ {
+#ifdef _PS3
+ g_pValvePS3Console->AddCommands( numCommands, commands, helptext );
+#else
+ XBX_rAddCommands( numCommands, commands, helptext );
+#endif
+ }
+}
+
+#endif
+
+
+static bool ConVarSortFunc( ConCommandBase * const &lhs, ConCommandBase * const &rhs )
+{
+ return CaselessStringLessThan( lhs->GetName(), rhs->GetName() );
+}
+
+//-----------------------------------------------------------------------------
+// Console commands
+//-----------------------------------------------------------------------------
+void CCvar::Find( const CCommand &args )
+{
+ const char *search;
+
+ if ( args.ArgC() != 2 )
+ {
+ ConMsg( "Usage: find <string>\n" );
+ return;
+ }
+
+ // Get substring to find
+ search = args[1];
+
+ CUtlRBTree< ConCommandBase *, int > sorted( 0, 0, ConVarSortFunc );
+
+ // Loop through vars and print out findings
+ for ( CConCommandHash::CCommandHashIterator_t i = m_CommandHash.First() ;
+ m_CommandHash.IsValidIterator(i) ;
+ i = m_CommandHash.Next(i) )
+ {
+ ConCommandBase *var = m_CommandHash[ i ];
+ if ( var->IsFlagSet(FCVAR_DEVELOPMENTONLY) || var->IsFlagSet(FCVAR_HIDDEN) )
+ continue;
+
+ if ( !V_stristr( var->GetName(), search ) &&
+ !V_stristr( var->GetHelpText(), search ) )
+ continue;
+
+ sorted.Insert( var );
+ }
+
+ for ( int i = sorted.FirstInorder(); i != sorted.InvalidIndex(); i = sorted.NextInorder( i ) )
+ {
+ ConVar_PrintDescription( sorted[ i ] );
+ }
+}
+
+#ifdef _DEBUG
+void CCvar::HashReport( const CCommand &args )
+{
+ m_CommandHash.Report();
+}
+#endif
+
+
+void CCvar::SetMaxSplitScreenSlots( int nSlots )
+{
+ m_nMaxSplitScreenSlots = nSlots;
+
+ AddSplitScreenConVars();
+}
+
+int CCvar::GetMaxSplitScreenSlots() const
+{
+ return m_nMaxSplitScreenSlots;
+}
+
+
+
+//-----------------------------------------------------------------------------
+// Console command hash data structure
+//-----------------------------------------------------------------------------
+CConCommandHash::CConCommandHash()
+{
+ Purge( true );
+}
+
+CConCommandHash::~CConCommandHash()
+{
+ Purge( false );
+}
+
+void CConCommandHash::Purge( bool bReinitialize )
+{
+ m_aBuckets.Purge();
+ m_aDataPool.Purge();
+ if ( bReinitialize )
+ {
+ Init();
+ }
+}
+
+// Initialize.
+void CConCommandHash::Init( void )
+{
+ // kNUM_BUCKETS must be a power of two.
+ COMPILE_TIME_ASSERT((kNUM_BUCKETS & ( kNUM_BUCKETS - 1 )) == 0);
+
+ // Set the bucket size.
+ m_aBuckets.SetSize( kNUM_BUCKETS );
+ for ( int iBucket = 0; iBucket < kNUM_BUCKETS; ++iBucket )
+ {
+ m_aBuckets[iBucket] = m_aDataPool.InvalidIndex();
+ }
+
+ // Calculate the grow size.
+ int nGrowSize = 4 * kNUM_BUCKETS;
+ m_aDataPool.SetGrowSize( nGrowSize );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Insert data into the hash table given its key (unsigned int),
+// WITH a check to see if the element already exists within the hash.
+//-----------------------------------------------------------------------------
+CConCommandHash::CCommandHashHandle_t CConCommandHash::Insert( ConCommandBase *cmd )
+{
+ // Check to see if that key already exists in the buckets (should be unique).
+ CCommandHashHandle_t hHash = Find( cmd );
+ if( hHash != InvalidHandle() )
+ return hHash;
+
+ return FastInsert( cmd );
+}
+//-----------------------------------------------------------------------------
+// Purpose: Insert data into the hash table given its key (unsigned int),
+// WITHOUT a check to see if the element already exists within the hash.
+//-----------------------------------------------------------------------------
+CConCommandHash::CCommandHashHandle_t CConCommandHash::FastInsert( ConCommandBase *cmd )
+{
+ // Get a new element from the pool.
+ int iHashData = m_aDataPool.Alloc( true );
+ HashEntry_t * pHashData = &m_aDataPool[iHashData];
+ if ( !pHashData )
+ return InvalidHandle();
+
+ HashKey_t key = Hash(cmd);
+
+ // Add data to new element.
+ pHashData->m_uiKey = key;
+ pHashData->m_Data = cmd;
+
+ // Link element.
+ int iBucket = key & kBUCKETMASK ; // HashFuncs::Hash( uiKey, m_uiBucketMask );
+ m_aDataPool.LinkBefore( m_aBuckets[iBucket], iHashData );
+ m_aBuckets[iBucket] = iHashData;
+
+ return iHashData;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Remove a given element from the hash.
+//-----------------------------------------------------------------------------
+void CConCommandHash::Remove( CCommandHashHandle_t hHash )
+{
+ HashEntry_t * entry = &m_aDataPool[hHash];
+ HashKey_t iBucket = entry->m_uiKey & kBUCKETMASK ;
+ if ( m_aBuckets[iBucket] == hHash )
+ {
+ // It is a bucket head.
+ m_aBuckets[iBucket] = m_aDataPool.Next( hHash );
+ }
+ else
+ {
+ // Not a bucket head.
+ m_aDataPool.Unlink( hHash );
+ }
+
+ // Remove the element.
+ m_aDataPool.Remove( hHash );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Remove all elements from the hash
+//-----------------------------------------------------------------------------
+void CConCommandHash::RemoveAll( void )
+{
+ m_aBuckets.RemoveAll();
+ m_aDataPool.RemoveAll();
+}
+
+//-----------------------------------------------------------------------------
+// Find hash entry corresponding to a string name
+//-----------------------------------------------------------------------------
+CConCommandHash::CCommandHashHandle_t CConCommandHash::Find( const char *name, HashKey_t hashkey) const
+{
+ // hash the "key" - get the correct hash table "bucket"
+ int iBucket = hashkey & kBUCKETMASK;
+
+ for ( datapool_t::IndexLocalType_t iElement = m_aBuckets[iBucket]; iElement != m_aDataPool.InvalidIndex(); iElement = m_aDataPool.Next( iElement ) )
+ {
+ const HashEntry_t &element = m_aDataPool[iElement];
+ if ( element.m_uiKey == hashkey && // if hashes of strings match,
+ V_stricmp( name, element.m_Data->GetName() ) == 0) // then test the actual strings
+ {
+ return iElement;
+ }
+ }
+
+ // found nuffink
+ return InvalidHandle();
+}
+
+//-----------------------------------------------------------------------------
+// Find a command in the hash.
+//-----------------------------------------------------------------------------
+CConCommandHash::CCommandHashHandle_t CConCommandHash::Find( const ConCommandBase *cmd ) const
+{
+ // Set this #if to 1 if the assert at bottom starts whining --
+ // that indicates that a console command is being double-registered,
+ // or something similarly nonfatally bad. With this #if 1, we'll search
+ // by name instead of by pointer, which is more robust in the face
+ // of double registered commands, but obviously slower.
+#if 0
+ return Find(cmd->GetName());
+#else
+ HashKey_t hashkey = Hash(cmd);
+ int iBucket = hashkey & kBUCKETMASK;
+
+ // hunt through all entries in that bucket
+ for ( datapool_t::IndexLocalType_t iElement = m_aBuckets[iBucket]; iElement != m_aDataPool.InvalidIndex(); iElement = m_aDataPool.Next( iElement ) )
+ {
+ const HashEntry_t &element = m_aDataPool[iElement];
+ if ( element.m_uiKey == hashkey && // if the hashes match...
+ element.m_Data == cmd ) // and the pointers...
+ {
+ // in debug, test to make sure we don't have commands under the same name
+ // or something goofy like that
+ AssertMsg1( iElement == Find(cmd->GetName()),
+ "ConCommand %s had two entries in the hash!", cmd->GetName() );
+
+ // return this element
+ return iElement;
+ }
+ }
+
+ // found nothing.
+#ifdef DBGFLAG_ASSERT // double check against search by name
+ CCommandHashHandle_t dbghand = Find(cmd->GetName());
+
+ AssertMsg1( InvalidHandle() == dbghand,
+ "ConCommand %s couldn't be found by pointer, but was found by name!", cmd->GetName() );
+#endif
+ return InvalidHandle();
+#endif
+}
+
+
+#ifdef _DEBUG
+// Dump a report to MSG
+void CConCommandHash::Report( void )
+{
+ Msg("Console command hash bucket load:\n");
+ int total = 0;
+ for ( int iBucket = 0 ; iBucket < kNUM_BUCKETS ; ++iBucket )
+ {
+ int count = 0;
+ CCommandHashHandle_t iElement = m_aBuckets[iBucket]; // get the head of the bucket
+ while ( iElement != m_aDataPool.InvalidIndex() )
+ {
+ ++count;
+ iElement = m_aDataPool.Next( iElement );
+ }
+
+ Msg( "%d: %d\n", iBucket, count );
+ total += count;
+ }
+
+ Msg("\tAverage: %.1f\n", total / ((float)(kNUM_BUCKETS)));
+}
+#endif