ds@3099: //===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======// ds@3099: // ds@3099: // Purpose: ds@3099: // ds@3099: // $Workfile: $ ds@3099: // $Date: $ ds@3099: // ds@3099: //----------------------------------------------------------------------------- ds@3099: // $NoKeywords: $ ds@3099: //===========================================================================// ds@3099: ds@3099: #ifndef CONVAR_H ds@3099: #define CONVAR_H ds@3099: ds@3099: #if _WIN32 ds@3099: #pragma once ds@3099: #endif ds@3099: ds@3099: #include "tier0/dbg.h" ds@3099: #include "tier1/iconvar.h" ds@3099: #include "tier1/utlvector.h" ds@3099: #include "tier1/utlstring.h" skamonkey@3518: #include "Color.h" ds@3099: #include "icvar.h" ds@3099: ds@3099: #ifdef _WIN32 ds@3099: #define FORCEINLINE_CVAR FORCEINLINE ds@3099: #elif POSIX ds@3099: #define FORCEINLINE_CVAR inline ds@3099: #else ds@3099: #error "implement me" ds@3099: #endif ds@3099: ds@3099: ds@3099: //----------------------------------------------------------------------------- ds@3099: // Uncomment me to test for threading issues for material system convars ds@3099: // NOTE: You want to disable all threading when you do this ds@3099: // +host_thread_mode 0 +r_threaded_particles 0 +sv_parallel_packentities 0 +sv_disable_querycache 0 ds@3099: //----------------------------------------------------------------------------- ds@3099: //#define CONVAR_TEST_MATERIAL_THREAD_CONVARS 1 ds@3099: ds@3099: ds@3099: //----------------------------------------------------------------------------- ds@3099: // Forward declarations ds@3099: //----------------------------------------------------------------------------- ds@3099: class ConVar; ds@3099: class CCommand; ds@3099: class ConCommand; ds@3099: class ConCommandBase; ds@3099: struct characterset_t; ds@3099: ds@3099: ds@3099: ds@3099: //----------------------------------------------------------------------------- ds@3099: // Any executable that wants to use ConVars need to implement one of ds@3099: // these to hook up access to console variables. ds@3099: //----------------------------------------------------------------------------- ds@3099: class IConCommandBaseAccessor ds@3099: { ds@3099: public: ds@3099: // Flags is a combination of FCVAR flags in cvar.h. ds@3099: // hOut is filled in with a handle to the variable. ds@3099: virtual bool RegisterConCommandBase( ConCommandBase *pVar ) = 0; ds@3099: }; ds@3099: ds@3099: ds@3099: //----------------------------------------------------------------------------- ds@3099: // Helper method for console development ds@3099: //----------------------------------------------------------------------------- ds@3099: #if defined( _X360 ) ds@3099: void ConVar_PublishToVXConsole(); ds@3099: #endif ds@3099: ds@3099: ds@3099: //----------------------------------------------------------------------------- ds@3099: // Called when a ConCommand needs to execute ds@3099: //----------------------------------------------------------------------------- ds@3099: typedef void ( *FnCommandCallbackV1_t )( void ); ds@3099: typedef void ( *FnCommandCallback_t )( const CCommand &command ); ds@3099: ds@3099: #define COMMAND_COMPLETION_MAXITEMS 64 ds@3099: #define COMMAND_COMPLETION_ITEM_LENGTH 64 ds@3099: ds@3099: //----------------------------------------------------------------------------- ds@3099: // Returns 0 to COMMAND_COMPLETION_MAXITEMS worth of completion strings ds@3099: //----------------------------------------------------------------------------- ds@3099: typedef int ( *FnCommandCompletionCallback )( const char *partial, char commands[ COMMAND_COMPLETION_MAXITEMS ][ COMMAND_COMPLETION_ITEM_LENGTH ] ); ds@3099: ds@3099: ds@3099: //----------------------------------------------------------------------------- ds@3099: // Interface version ds@3099: //----------------------------------------------------------------------------- ds@3099: class ICommandCallback ds@3099: { ds@3099: public: ds@3099: virtual void CommandCallback( const CCommand &command ) = 0; ds@3099: }; ds@3099: ds@3099: class ICommandCompletionCallback ds@3099: { ds@3099: public: ds@3099: virtual int CommandCompletionCallback( const char *pPartial, CUtlVector< CUtlString > &commands ) = 0; ds@3099: }; ds@3099: ds@3099: //----------------------------------------------------------------------------- ds@3099: // Purpose: The base console invoked command/cvar interface ds@3099: //----------------------------------------------------------------------------- ds@3099: class ConCommandBase ds@3099: { ds@3099: friend class CCvar; ds@3099: friend class ConVar; ds@3099: friend class ConCommand; ds@3099: friend void ConVar_Register( int nCVarFlag, IConCommandBaseAccessor *pAccessor ); ds@3099: friend void ConVar_PublishToVXConsole(); ds@3099: ds@3099: // FIXME: Remove when ConVar changes are done ds@3099: friend class CDefaultCvar; ds@3099: ds@3099: public: ds@3099: ConCommandBase( void ); ds@3099: ConCommandBase( const char *pName, const char *pHelpString = 0, ds@3099: int flags = 0 ); ds@3099: ds@3099: virtual ~ConCommandBase( void ); ds@3099: ds@3099: virtual bool IsCommand( void ) const; ds@3099: ds@3099: // Check flag ds@3099: virtual bool IsFlagSet( int flag ) const; ds@3099: // Set flag ds@3099: virtual void AddFlags( int flags ); ds@3099: // Clear flag ds@3099: virtual void RemoveFlags( int flags ); ds@3099: ds@3099: virtual int GetFlags() const; ds@3099: ds@3099: // Return name of cvar ds@3099: virtual const char *GetName( void ) const; ds@3099: ds@3099: // Return help text for cvar ds@3099: virtual const char *GetHelpText( void ) const; ds@3099: ds@3099: // Deal with next pointer ds@3099: const ConCommandBase *GetNext( void ) const; ds@3099: ConCommandBase *GetNext( void ); ds@3099: ds@3099: virtual bool IsRegistered( void ) const; ds@3099: ds@3099: // Returns the DLL identifier ds@3099: virtual CVarDLLIdentifier_t GetDLLIdentifier() const; ds@3099: ds@3099: protected: ds@3099: virtual void Create( const char *pName, const char *pHelpString = 0, ds@3099: int flags = 0 ); ds@3099: ds@3099: // Used internally by OneTimeInit to initialize/shutdown ds@3099: virtual void Init(); ds@3099: void Shutdown(); ds@3099: ds@3099: // Internal copy routine ( uses new operator from correct module ) ds@3099: char *CopyString( const char *from ); ds@3099: ds@3099: private: ds@3099: // Next ConVar in chain ds@3099: // Prior to register, it points to the next convar in the DLL. ds@3099: // Once registered, though, m_pNext is reset to point to the next ds@3099: // convar in the global list ds@3099: ConCommandBase *m_pNext; ds@3099: ds@3099: // Has the cvar been added to the global list? ds@3099: bool m_bRegistered; ds@3099: ds@3099: // Static data ds@3099: const char *m_pszName; ds@3099: const char *m_pszHelpString; ds@3099: ds@3099: // ConVar flags ds@3099: int m_nFlags; ds@3099: ds@3099: protected: ds@3099: // ConVars add themselves to this list for the executable. ds@3099: // Then ConVar_Register runs through all the console variables ds@3099: // and registers them into a global list stored in vstdlib.dll ds@3099: static ConCommandBase *s_pConCommandBases; ds@3099: ds@3099: // ConVars in this executable use this 'global' to access values. ds@3099: static IConCommandBaseAccessor *s_pAccessor; ds@3099: public: ds@3099: inline void SetFlags(int flags) ds@3099: { ds@3099: m_nFlags = flags; ds@3099: } ds@3099: }; ds@3099: ds@3099: ds@3099: //----------------------------------------------------------------------------- ds@3099: // Command tokenizer ds@3099: //----------------------------------------------------------------------------- ds@3099: class CCommand ds@3099: { ds@3099: public: ds@3099: CCommand(); ds@3099: CCommand( int nArgC, const char **ppArgV ); ds@3099: bool Tokenize( const char *pCommand, characterset_t *pBreakSet = NULL ); ds@3099: void Reset(); ds@3099: ds@3099: int ArgC() const; ds@3099: const char **ArgV() const; ds@3099: const char *ArgS() const; // All args that occur after the 0th arg, in string form ds@3099: const char *GetCommandString() const; // The entire command in string form, including the 0th arg ds@3099: const char *operator[]( int nIndex ) const; // Gets at arguments ds@3099: const char *Arg( int nIndex ) const; // Gets at arguments ds@3099: ds@3099: // Helper functions to parse arguments to commands. ds@3099: const char* FindArg( const char *pName ) const; ds@3099: int FindArgInt( const char *pName, int nDefaultVal ) const; ds@3099: ds@3099: static int MaxCommandLength(); ds@3099: static characterset_t* DefaultBreakSet(); ds@3099: ds@3099: private: ds@3099: enum ds@3099: { ds@3099: COMMAND_MAX_ARGC = 64, ds@3099: COMMAND_MAX_LENGTH = 512, ds@3099: }; ds@3099: ds@3099: int m_nArgc; ds@3099: int m_nArgv0Size; ds@3099: char m_pArgSBuffer[ COMMAND_MAX_LENGTH ]; ds@3099: char m_pArgvBuffer[ COMMAND_MAX_LENGTH ]; ds@3099: const char* m_ppArgv[ COMMAND_MAX_ARGC ]; ds@3099: }; ds@3099: ds@3099: inline int CCommand::MaxCommandLength() ds@3099: { ds@3099: return COMMAND_MAX_LENGTH - 1; ds@3099: } ds@3099: ds@3099: inline int CCommand::ArgC() const ds@3099: { ds@3099: return m_nArgc; ds@3099: } ds@3099: ds@3099: inline const char **CCommand::ArgV() const ds@3099: { ds@3099: return m_nArgc ? (const char**)m_ppArgv : NULL; ds@3099: } ds@3099: ds@3099: inline const char *CCommand::ArgS() const ds@3099: { ds@3099: return m_nArgv0Size ? &m_pArgSBuffer[m_nArgv0Size] : ""; ds@3099: } ds@3099: ds@3099: inline const char *CCommand::GetCommandString() const ds@3099: { ds@3099: return m_nArgc ? m_pArgSBuffer : ""; ds@3099: } ds@3099: ds@3099: inline const char *CCommand::Arg( int nIndex ) const ds@3099: { ds@3099: // FIXME: Many command handlers appear to not be particularly careful ds@3099: // about checking for valid argc range. For now, we're going to ds@3099: // do the extra check and return an empty string if it's out of range ds@3099: if ( nIndex < 0 || nIndex >= m_nArgc ) ds@3099: return ""; ds@3099: return m_ppArgv[nIndex]; ds@3099: } ds@3099: ds@3099: inline const char *CCommand::operator[]( int nIndex ) const ds@3099: { ds@3099: return Arg( nIndex ); ds@3099: } ds@3099: ds@3099: ds@3099: //----------------------------------------------------------------------------- ds@3099: // Purpose: The console invoked command ds@3099: //----------------------------------------------------------------------------- ds@3099: class ConCommand : public ConCommandBase ds@3099: { ds@3099: friend class CCvar; ds@3099: ds@3099: public: ds@3099: typedef ConCommandBase BaseClass; ds@3099: ds@3099: ConCommand( const char *pName, FnCommandCallbackV1_t callback, ds@3099: const char *pHelpString = 0, int flags = 0, FnCommandCompletionCallback completionFunc = 0 ); ds@3099: ConCommand( const char *pName, FnCommandCallback_t callback, ds@3099: const char *pHelpString = 0, int flags = 0, FnCommandCompletionCallback completionFunc = 0 ); ds@3099: ConCommand( const char *pName, ICommandCallback *pCallback, ds@3099: const char *pHelpString = 0, int flags = 0, ICommandCompletionCallback *pCommandCompletionCallback = 0 ); ds@3099: ds@3099: virtual ~ConCommand( void ); ds@3099: ds@3099: virtual bool IsCommand( void ) const; ds@3099: ds@3099: virtual int AutoCompleteSuggest( const char *partial, CUtlVector< CUtlString > &commands ); ds@3099: ds@3099: virtual bool CanAutoComplete( void ); ds@3099: ds@3099: // Invoke the function ds@3099: virtual void Dispatch( const CCommand &command ); ds@3099: ds@3099: private: ds@3099: // NOTE: To maintain backward compat, we have to be very careful: ds@3099: // All public virtual methods must appear in the same order always ds@3099: // since engine code will be calling into this code, which *does not match* ds@3099: // in the mod code; it's using slightly different, but compatible versions ds@3099: // of this class. Also: Be very careful about adding new fields to this class. ds@3099: // Those fields will not exist in the version of this class that is instanced ds@3099: // in mod code. ds@3099: ds@3099: // Call this function when executing the command ds@3099: union ds@3099: { ds@3099: FnCommandCallbackV1_t m_fnCommandCallbackV1; ds@3099: FnCommandCallback_t m_fnCommandCallback; ds@3099: ICommandCallback *m_pCommandCallback; ds@3099: }; ds@3099: ds@3099: union ds@3099: { ds@3099: FnCommandCompletionCallback m_fnCompletionCallback; ds@3099: ICommandCompletionCallback *m_pCommandCompletionCallback; ds@3099: }; ds@3099: ds@3099: bool m_bHasCompletionCallback : 1; ds@3099: bool m_bUsingNewCommandCallback : 1; ds@3099: bool m_bUsingCommandCallbackInterface : 1; ds@3099: public: ds@3099: inline FnCommandCallback_t GetCallback() const ds@3099: { ds@3099: return m_fnCommandCallback; ds@3099: } ds@3099: }; ds@3099: ds@3099: ds@3099: //----------------------------------------------------------------------------- ds@3099: // Purpose: A console variable ds@3099: //----------------------------------------------------------------------------- ds@3099: class ConVar : public ConCommandBase, public IConVar ds@3099: { ds@3099: friend class CCvar; ds@3099: friend class ConVarRef; ds@3099: friend class SplitScreenConVarRef; ds@3099: ds@3099: public: ds@3099: typedef ConCommandBase BaseClass; ds@3099: ds@3099: ConVar( const char *pName, const char *pDefaultValue, int flags = 0); ds@3099: ds@3099: ConVar( const char *pName, const char *pDefaultValue, int flags, ds@3099: const char *pHelpString ); ds@3099: ConVar( const char *pName, const char *pDefaultValue, int flags, ds@3099: const char *pHelpString, bool bMin, float fMin, bool bMax, float fMax ); ds@3099: ConVar( const char *pName, const char *pDefaultValue, int flags, ds@3099: const char *pHelpString, FnChangeCallback_t callback ); ds@3099: ConVar( const char *pName, const char *pDefaultValue, int flags, ds@3099: const char *pHelpString, bool bMin, float fMin, bool bMax, float fMax, ds@3099: FnChangeCallback_t callback ); ds@3099: ds@3099: virtual ~ConVar( void ); ds@3099: ds@3099: virtual bool IsFlagSet( int flag ) const; ds@3099: virtual const char* GetHelpText( void ) const; ds@3099: virtual bool IsRegistered( void ) const; ds@3099: virtual const char *GetName( void ) const; ds@3099: // Return name of command (usually == GetName(), except in case of FCVAR_SS_ADDED vars ds@3099: virtual const char *GetBaseName( void ) const; ds@3099: virtual int GetSplitScreenPlayerSlot() const; ds@3099: ds@3099: virtual void AddFlags( int flags ); ds@3099: virtual int GetFlags() const; ds@3099: virtual bool IsCommand( void ) const; ds@3099: ds@3099: // Install a change callback (there shouldn't already be one....) ds@3099: void InstallChangeCallback( FnChangeCallback_t callback, bool bInvoke = true ); ds@3099: void RemoveChangeCallback( FnChangeCallback_t callbackToRemove ); ds@3099: ds@3099: int GetChangeCallbackCount() const { return m_pParent->m_fnChangeCallbacks.Count(); } ds@3099: FnChangeCallback_t GetChangeCallback( int slot ) const { return m_pParent->m_fnChangeCallbacks[ slot ]; } ds@3099: ds@3099: // Retrieve value skamonkey@3515: #if SOURCE_ENGINE == SE_CSGO skamonkey@3515: virtual float GetFloat( void ) const; skamonkey@3515: virtual int GetInt( void ) const; skamonkey@3515: #else ds@3099: FORCEINLINE_CVAR float GetFloat( void ) const; ds@3099: FORCEINLINE_CVAR int GetInt( void ) const; skamonkey@3515: #endif skamonkey@3515: ds@3099: FORCEINLINE_CVAR Color GetColor( void ) const; ds@3099: FORCEINLINE_CVAR bool GetBool() const { return !!GetInt(); } ds@3099: FORCEINLINE_CVAR char const *GetString( void ) const; ds@3099: ds@3099: // Compiler driven selection for template use ds@3099: template T Get( void ) const; ds@3099: template T Get( T * ) const; ds@3099: ds@3099: // Any function that allocates/frees memory needs to be virtual or else you'll have crashes ds@3099: // from alloc/free across dll/exe boundaries. ds@3099: ds@3099: // These just call into the IConCommandBaseAccessor to check flags and set the var (which ends up calling InternalSetValue). ds@3099: virtual void SetValue( const char *value ); ds@3099: virtual void SetValue( float value ); ds@3099: virtual void SetValue( int value ); ds@3099: virtual void SetValue( Color value ); ds@3099: ds@3099: // Reset to default value ds@3099: void Revert( void ); ds@3099: ds@3099: // True if it has a min/max setting ds@3099: bool HasMin() const; ds@3099: bool HasMax() const; ds@3099: ds@3099: bool GetMin( float& minVal ) const; ds@3099: bool GetMax( float& maxVal ) const; ds@3099: ds@3099: float GetMinValue() const; ds@3099: float GetMaxValue() const; ds@3099: ds@3099: const char *GetDefault( void ) const; ds@3099: ds@3099: // Value ds@3099: struct CVValue_t ds@3099: { ds@3099: char *m_pszString; ds@3099: int m_StringLength; ds@3099: ds@3099: // Values ds@3099: float m_fValue; ds@3099: int m_nValue; ds@3099: }; ds@3099: ds@3099: FORCEINLINE_CVAR CVValue_t &GetRawValue() ds@3099: { ds@3099: return m_Value; ds@3099: } ds@3099: FORCEINLINE_CVAR const CVValue_t &GetRawValue() const ds@3099: { ds@3099: return m_Value; ds@3099: } ds@3099: ds@3099: private: ds@3099: bool InternalSetColorFromString( const char *value ); ds@3099: // Called by CCvar when the value of a var is changing. ds@3099: virtual void InternalSetValue(const char *value); ds@3099: // For CVARs marked FCVAR_NEVER_AS_STRING ds@3099: virtual void InternalSetFloatValue( float fNewValue ); ds@3099: virtual void InternalSetIntValue( int nValue ); ds@3099: virtual void InternalSetColorValue( Color value ); ds@3099: ds@3099: virtual bool ClampValue( float& value ); ds@3099: virtual void ChangeStringValue( const char *tempVal, float flOldValue ); ds@3099: ds@3099: virtual void Create( const char *pName, const char *pDefaultValue, int flags = 0, ds@3099: const char *pHelpString = 0, bool bMin = false, float fMin = 0.0, ds@3099: bool bMax = false, float fMax = false, FnChangeCallback_t callback = 0 ); ds@3099: ds@3099: // Used internally by OneTimeInit to initialize. ds@3099: virtual void Init(); ds@3099: ds@3099: ds@3099: ds@3099: protected: ds@3099: ds@3099: // This either points to "this" or it points to the original declaration of a ConVar. ds@3099: // This allows ConVars to exist in separate modules, and they all use the first one to be declared. ds@3099: // m_pParent->m_pParent must equal m_pParent (ie: m_pParent must be the root, or original, ConVar). ds@3099: ConVar *m_pParent; ds@3099: ds@3099: // Static data ds@3099: const char *m_pszDefaultValue; ds@3099: ds@3099: CVValue_t m_Value; ds@3099: ds@3099: // Min/Max values ds@3099: bool m_bHasMin; ds@3099: float m_fMinVal; ds@3099: bool m_bHasMax; ds@3099: float m_fMaxVal; ds@3099: ds@3099: // Call this function when ConVar changes ds@3099: CUtlVector< FnChangeCallback_t > m_fnChangeCallbacks; ds@3099: public: ds@3099: inline void SetMin(bool set, float min=0.0) ds@3099: { ds@3099: m_bHasMin = set; ds@3099: m_fMinVal = min; ds@3099: } ds@3099: inline void SetMax(bool set, float max=0.0) ds@3099: { ds@3099: m_bHasMax = set; ds@3099: m_fMaxVal = max; ds@3099: } ds@3099: }; ds@3099: ds@3099: ds@3099: //----------------------------------------------------------------------------- ds@3099: // Purpose: Return ConVar value as a float ds@3099: // Output : float ds@3099: //----------------------------------------------------------------------------- ds@3099: FORCEINLINE_CVAR float ConVar::GetFloat( void ) const ds@3099: { ds@3099: #ifdef CONVAR_TEST_MATERIAL_THREAD_CONVARS ds@3099: Assert( ThreadInMainThread() || IsFlagSet( FCVAR_MATERIAL_THREAD_MASK | FCVAR_ACCESSIBLE_FROM_THREADS ) ); ds@3099: #endif ds@3099: return m_pParent->m_Value.m_fValue; ds@3099: } ds@3099: ds@3099: //----------------------------------------------------------------------------- ds@3099: // Purpose: Return ConVar value as an int ds@3099: // Output : int ds@3099: //----------------------------------------------------------------------------- ds@3099: FORCEINLINE_CVAR int ConVar::GetInt( void ) const ds@3099: { ds@3099: #ifdef CONVAR_TEST_MATERIAL_THREAD_CONVARS ds@3099: Assert( ThreadInMainThread() || IsFlagSet( FCVAR_MATERIAL_THREAD_MASK | FCVAR_ACCESSIBLE_FROM_THREADS ) ); ds@3099: #endif ds@3099: return m_pParent->m_Value.m_nValue; ds@3099: } ds@3099: ds@3099: //----------------------------------------------------------------------------- ds@3099: // Purpose: Return ConVar value as a color ds@3099: // Output : Color ds@3099: //----------------------------------------------------------------------------- ds@3099: FORCEINLINE_CVAR Color ConVar::GetColor( void ) const ds@3099: { ds@3099: #ifdef CONVAR_TEST_MATERIAL_THREAD_CONVARS ds@3099: Assert( ThreadInMainThread() || IsFlagSet( FCVAR_MATERIAL_THREAD_MASK | FCVAR_ACCESSIBLE_FROM_THREADS ) ); ds@3099: #endif ds@3099: unsigned char *pColorElement = ((unsigned char *)&m_pParent->m_Value.m_nValue); ds@3099: return Color( pColorElement[0], pColorElement[1], pColorElement[2], pColorElement[3] ); ds@3099: } ds@3099: ds@3099: ds@3099: //----------------------------------------------------------------------------- ds@3099: ds@3099: template <> FORCEINLINE_CVAR float ConVar::Get( void ) const { return GetFloat(); } ds@3099: template <> FORCEINLINE_CVAR int ConVar::Get( void ) const { return GetInt(); } ds@3099: template <> FORCEINLINE_CVAR bool ConVar::Get( void ) const { return GetBool(); } ds@3099: template <> FORCEINLINE_CVAR const char * ConVar::Get( void ) const { return GetString(); } ds@3099: template <> FORCEINLINE_CVAR float ConVar::Get( float *p ) const { return ( *p = GetFloat() ); } ds@3099: template <> FORCEINLINE_CVAR int ConVar::Get( int *p ) const { return ( *p = GetInt() ); } ds@3099: template <> FORCEINLINE_CVAR bool ConVar::Get( bool *p ) const { return ( *p = GetBool() ); } ds@3099: template <> FORCEINLINE_CVAR const char * ConVar::Get( char const **p ) const { return ( *p = GetString() ); } ds@3099: ds@3099: //----------------------------------------------------------------------------- ds@3099: // Purpose: Return ConVar value as a string, return "" for bogus string pointer, etc. ds@3099: // Output : const char * ds@3099: //----------------------------------------------------------------------------- ds@3099: FORCEINLINE_CVAR const char *ConVar::GetString( void ) const ds@3099: { ds@3099: #ifdef CONVAR_TEST_MATERIAL_THREAD_CONVARS ds@3099: Assert( ThreadInMainThread() || IsFlagSet( FCVAR_MATERIAL_THREAD_MASK | FCVAR_ACCESSIBLE_FROM_THREADS ) ); ds@3099: #endif ds@3099: if ( m_nFlags & FCVAR_NEVER_AS_STRING ) ds@3099: return "FCVAR_NEVER_AS_STRING"; ds@3099: ds@3099: char const *str = m_pParent->m_Value.m_pszString; ds@3099: return str ? str : ""; ds@3099: } ds@3099: ds@3099: class CSplitScreenAddedConVar : public ConVar ds@3099: { ds@3099: typedef ConVar BaseClass; ds@3099: public: ds@3099: CSplitScreenAddedConVar( int nSplitScreenSlot, const char *pName, const ConVar *pBaseVar ) : ds@3099: BaseClass ds@3099: ( ds@3099: pName, ds@3099: pBaseVar->GetDefault(), ds@3099: // Keep basevar flags, except remove _SS and add _SS_ADDED instead ds@3099: ( pBaseVar->GetFlags() & ~FCVAR_SS ) | FCVAR_SS_ADDED, ds@3099: pBaseVar->GetHelpText(), ds@3099: pBaseVar->HasMin(), ds@3099: pBaseVar->GetMinValue(), ds@3099: pBaseVar->HasMax(), ds@3099: pBaseVar->GetMaxValue() ds@3099: ), ds@3099: m_pBaseVar( pBaseVar ), ds@3099: m_nSplitScreenSlot( nSplitScreenSlot ) ds@3099: { ds@3099: for ( int i = 0; i < pBaseVar->GetChangeCallbackCount(); ++i ) ds@3099: { ds@3099: InstallChangeCallback( pBaseVar->GetChangeCallback( i ), false ); ds@3099: } ds@3099: Assert( nSplitScreenSlot >= 1 ); ds@3099: Assert( nSplitScreenSlot < MAX_SPLITSCREEN_CLIENTS ); ds@3099: Assert( m_pBaseVar ); ds@3099: Assert( IsFlagSet( FCVAR_SS_ADDED ) ); ds@3099: Assert( !IsFlagSet( FCVAR_SS ) ); ds@3099: } ds@3099: ds@3099: const ConVar *GetBaseVar() const; ds@3099: virtual const char *GetBaseName() const; ds@3099: void SetSplitScreenPlayerSlot( int nSlot ); ds@3099: virtual int GetSplitScreenPlayerSlot() const; ds@3099: ds@3099: protected: ds@3099: ds@3099: const ConVar *m_pBaseVar; ds@3099: int m_nSplitScreenSlot; ds@3099: }; ds@3099: ds@3099: FORCEINLINE_CVAR const ConVar *CSplitScreenAddedConVar::GetBaseVar() const ds@3099: { ds@3099: Assert( m_pBaseVar ); ds@3099: return m_pBaseVar; ds@3099: } ds@3099: ds@3099: FORCEINLINE_CVAR const char *CSplitScreenAddedConVar::GetBaseName() const ds@3099: { ds@3099: Assert( m_pBaseVar ); ds@3099: return m_pBaseVar->GetName(); ds@3099: } ds@3099: ds@3099: FORCEINLINE_CVAR void CSplitScreenAddedConVar::SetSplitScreenPlayerSlot( int nSlot ) ds@3099: { ds@3099: m_nSplitScreenSlot = nSlot; ds@3099: } ds@3099: ds@3099: FORCEINLINE_CVAR int CSplitScreenAddedConVar::GetSplitScreenPlayerSlot() const ds@3099: { ds@3099: return m_nSplitScreenSlot; ds@3099: } ds@3099: ds@3099: //----------------------------------------------------------------------------- ds@3099: // Used to read/write convars that already exist (replaces the FindVar method) ds@3099: //----------------------------------------------------------------------------- ds@3099: class ConVarRef ds@3099: { ds@3099: public: ds@3099: ConVarRef( const char *pName ); ds@3099: ConVarRef( const char *pName, bool bIgnoreMissing ); ds@3099: ConVarRef( IConVar *pConVar ); ds@3099: ds@3099: void Init( const char *pName, bool bIgnoreMissing ); ds@3099: bool IsValid() const; ds@3099: bool IsFlagSet( int nFlags ) const; ds@3099: IConVar *GetLinkedConVar(); ds@3099: ds@3099: // Get/Set value ds@3099: float GetFloat( void ) const; ds@3099: int GetInt( void ) const; ds@3099: Color GetColor( void ) const; ds@3099: bool GetBool() const { return !!GetInt(); } ds@3099: const char *GetString( void ) const; ds@3099: ds@3099: void SetValue( const char *pValue ); ds@3099: void SetValue( float flValue ); ds@3099: void SetValue( int nValue ); ds@3099: void SetValue( Color value ); ds@3099: void SetValue( bool bValue ); ds@3099: ds@3099: const char *GetName() const; ds@3099: ds@3099: const char *GetDefault() const; ds@3099: ds@3099: const char *GetBaseName() const; ds@3099: ds@3099: int GetSplitScreenPlayerSlot() const; ds@3099: ds@3099: private: ds@3099: // High-speed method to read convar data ds@3099: IConVar *m_pConVar; ds@3099: ConVar *m_pConVarState; ds@3099: }; ds@3099: ds@3099: ds@3099: //----------------------------------------------------------------------------- ds@3099: // Did we find an existing convar of that name? ds@3099: //----------------------------------------------------------------------------- ds@3099: FORCEINLINE_CVAR bool ConVarRef::IsFlagSet( int nFlags ) const ds@3099: { ds@3099: return ( m_pConVar->IsFlagSet( nFlags ) != 0 ); ds@3099: } ds@3099: ds@3099: FORCEINLINE_CVAR IConVar *ConVarRef::GetLinkedConVar() ds@3099: { ds@3099: return m_pConVar; ds@3099: } ds@3099: ds@3099: FORCEINLINE_CVAR const char *ConVarRef::GetName() const ds@3099: { ds@3099: return m_pConVar->GetName(); ds@3099: } ds@3099: ds@3099: FORCEINLINE_CVAR const char *ConVarRef::GetBaseName() const ds@3099: { ds@3099: return m_pConVar->GetBaseName(); ds@3099: } ds@3099: ds@3099: FORCEINLINE_CVAR int ConVarRef::GetSplitScreenPlayerSlot() const ds@3099: { ds@3099: return m_pConVar->GetSplitScreenPlayerSlot(); ds@3099: } ds@3099: ds@3099: //----------------------------------------------------------------------------- ds@3099: // Purpose: Return ConVar value as a float ds@3099: //----------------------------------------------------------------------------- ds@3099: FORCEINLINE_CVAR float ConVarRef::GetFloat( void ) const ds@3099: { ds@3099: return m_pConVarState->m_Value.m_fValue; ds@3099: } ds@3099: ds@3099: //----------------------------------------------------------------------------- ds@3099: // Purpose: Return ConVar value as an int ds@3099: //----------------------------------------------------------------------------- ds@3099: FORCEINLINE_CVAR int ConVarRef::GetInt( void ) const ds@3099: { ds@3099: return m_pConVarState->m_Value.m_nValue; ds@3099: } ds@3099: ds@3099: //----------------------------------------------------------------------------- ds@3099: // Purpose: Return ConVar value as a color ds@3099: //----------------------------------------------------------------------------- ds@3099: FORCEINLINE_CVAR Color ConVarRef::GetColor( void ) const ds@3099: { ds@3099: return m_pConVarState->GetColor(); ds@3099: } ds@3099: ds@3099: //----------------------------------------------------------------------------- ds@3099: // Purpose: Return ConVar value as a string, return "" for bogus string pointer, etc. ds@3099: //----------------------------------------------------------------------------- ds@3099: FORCEINLINE_CVAR const char *ConVarRef::GetString( void ) const ds@3099: { ds@3099: Assert( !IsFlagSet( FCVAR_NEVER_AS_STRING ) ); ds@3099: return m_pConVarState->m_Value.m_pszString; ds@3099: } ds@3099: ds@3099: ds@3099: FORCEINLINE_CVAR void ConVarRef::SetValue( const char *pValue ) ds@3099: { ds@3099: m_pConVar->SetValue( pValue ); ds@3099: } ds@3099: ds@3099: FORCEINLINE_CVAR void ConVarRef::SetValue( float flValue ) ds@3099: { ds@3099: m_pConVar->SetValue( flValue ); ds@3099: } ds@3099: ds@3099: FORCEINLINE_CVAR void ConVarRef::SetValue( int nValue ) ds@3099: { ds@3099: m_pConVar->SetValue( nValue ); ds@3099: } ds@3099: ds@3099: FORCEINLINE_CVAR void ConVarRef::SetValue( Color value ) ds@3099: { ds@3099: m_pConVar->SetValue( value ); ds@3099: } ds@3099: ds@3099: FORCEINLINE_CVAR void ConVarRef::SetValue( bool bValue ) ds@3099: { ds@3099: m_pConVar->SetValue( bValue ? 1 : 0 ); ds@3099: } ds@3099: ds@3099: FORCEINLINE_CVAR const char *ConVarRef::GetDefault() const ds@3099: { ds@3099: return m_pConVarState->m_pszDefaultValue; ds@3099: } ds@3099: ds@3099: //----------------------------------------------------------------------------- ds@3099: // Helper for referencing splitscreen convars (i.e., "name" and "name2") ds@3099: //----------------------------------------------------------------------------- ds@3099: class SplitScreenConVarRef ds@3099: { ds@3099: public: ds@3099: SplitScreenConVarRef( const char *pName ); ds@3099: SplitScreenConVarRef( const char *pName, bool bIgnoreMissing ); ds@3099: SplitScreenConVarRef( IConVar *pConVar ); ds@3099: ds@3099: void Init( const char *pName, bool bIgnoreMissing ); ds@3099: bool IsValid() const; ds@3099: bool IsFlagSet( int nFlags ) const; ds@3099: ds@3099: // Get/Set value ds@3099: float GetFloat( int nSlot ) const; ds@3099: int GetInt( int nSlot ) const; ds@3099: Color GetColor( int nSlot ) const; ds@3099: bool GetBool( int nSlot ) const { return !!GetInt( nSlot ); } ds@3099: const char *GetString( int nSlot ) const; ds@3099: ds@3099: void SetValue( int nSlot, const char *pValue ); ds@3099: void SetValue( int nSlot, float flValue ); ds@3099: void SetValue( int nSlot, int nValue ); ds@3099: void SetValue( int nSlot, Color value ); ds@3099: void SetValue( int nSlot, bool bValue ); ds@3099: ds@3099: const char *GetName( int nSlot ) const; ds@3099: ds@3099: const char *GetDefault() const; ds@3099: ds@3099: const char *GetBaseName() const; ds@3099: ds@3099: private: ds@3099: struct cv_t ds@3099: { ds@3099: IConVar *m_pConVar; ds@3099: ConVar *m_pConVarState; ds@3099: }; ds@3099: ds@3099: cv_t m_Info[ MAX_SPLITSCREEN_CLIENTS ]; ds@3099: }; ds@3099: ds@3099: //----------------------------------------------------------------------------- ds@3099: // Did we find an existing convar of that name? ds@3099: //----------------------------------------------------------------------------- ds@3099: FORCEINLINE_CVAR bool SplitScreenConVarRef::IsFlagSet( int nFlags ) const ds@3099: { ds@3099: return ( m_Info[ 0 ].m_pConVar->IsFlagSet( nFlags ) != 0 ); ds@3099: } ds@3099: ds@3099: FORCEINLINE_CVAR const char *SplitScreenConVarRef::GetName( int nSlot ) const ds@3099: { ds@3099: return m_Info[ nSlot ].m_pConVar->GetName(); ds@3099: } ds@3099: ds@3099: FORCEINLINE_CVAR const char *SplitScreenConVarRef::GetBaseName() const ds@3099: { ds@3099: return m_Info[ 0 ].m_pConVar->GetBaseName(); ds@3099: } ds@3099: ds@3099: //----------------------------------------------------------------------------- ds@3099: // Purpose: Return ConVar value as a float ds@3099: //----------------------------------------------------------------------------- ds@3099: FORCEINLINE_CVAR float SplitScreenConVarRef::GetFloat( int nSlot ) const ds@3099: { ds@3099: return m_Info[ nSlot ].m_pConVarState->m_Value.m_fValue; ds@3099: } ds@3099: ds@3099: //----------------------------------------------------------------------------- ds@3099: // Purpose: Return ConVar value as an int ds@3099: //----------------------------------------------------------------------------- ds@3099: FORCEINLINE_CVAR int SplitScreenConVarRef::GetInt( int nSlot ) const ds@3099: { ds@3099: return m_Info[ nSlot ].m_pConVarState->m_Value.m_nValue; ds@3099: } ds@3099: ds@3099: //----------------------------------------------------------------------------- ds@3099: // Purpose: Return ConVar value as an int ds@3099: //----------------------------------------------------------------------------- ds@3099: FORCEINLINE_CVAR Color SplitScreenConVarRef::GetColor( int nSlot ) const ds@3099: { ds@3099: return m_Info[ nSlot ].m_pConVarState->GetColor(); ds@3099: } ds@3099: ds@3099: //----------------------------------------------------------------------------- ds@3099: // Purpose: Return ConVar value as a string, return "" for bogus string pointer, etc. ds@3099: //----------------------------------------------------------------------------- ds@3099: FORCEINLINE_CVAR const char *SplitScreenConVarRef::GetString( int nSlot ) const ds@3099: { ds@3099: Assert( !IsFlagSet( FCVAR_NEVER_AS_STRING ) ); ds@3099: return m_Info[ nSlot ].m_pConVarState->m_Value.m_pszString; ds@3099: } ds@3099: ds@3099: ds@3099: FORCEINLINE_CVAR void SplitScreenConVarRef::SetValue( int nSlot, const char *pValue ) ds@3099: { ds@3099: m_Info[ nSlot ].m_pConVar->SetValue( pValue ); ds@3099: } ds@3099: ds@3099: FORCEINLINE_CVAR void SplitScreenConVarRef::SetValue( int nSlot, float flValue ) ds@3099: { ds@3099: m_Info[ nSlot ].m_pConVar->SetValue( flValue ); ds@3099: } ds@3099: ds@3099: FORCEINLINE_CVAR void SplitScreenConVarRef::SetValue( int nSlot, int nValue ) ds@3099: { ds@3099: m_Info[ nSlot ].m_pConVar->SetValue( nValue ); ds@3099: } ds@3099: ds@3099: FORCEINLINE_CVAR void SplitScreenConVarRef::SetValue( int nSlot, Color value ) ds@3099: { ds@3099: m_Info[ nSlot ].m_pConVar->SetValue( value ); ds@3099: } ds@3099: ds@3099: FORCEINLINE_CVAR void SplitScreenConVarRef::SetValue( int nSlot, bool bValue ) ds@3099: { ds@3099: m_Info[ nSlot ].m_pConVar->SetValue( bValue ? 1 : 0 ); ds@3099: } ds@3099: ds@3099: FORCEINLINE_CVAR const char *SplitScreenConVarRef::GetDefault() const ds@3099: { ds@3099: return m_Info[ 0 ].m_pConVarState->m_pszDefaultValue; ds@3099: } ds@3099: ds@3099: //----------------------------------------------------------------------------- ds@3099: // Called by the framework to register ConCommands with the ICVar ds@3099: //----------------------------------------------------------------------------- ds@3099: void ConVar_Register( int nCVarFlag = 0, IConCommandBaseAccessor *pAccessor = NULL ); ds@3099: void ConVar_Unregister( ); ds@3099: ds@3099: ds@3099: //----------------------------------------------------------------------------- ds@3099: // Utility methods ds@3099: //----------------------------------------------------------------------------- ds@3099: void ConVar_PrintDescription( const ConCommandBase *pVar ); ds@3099: ds@3099: ds@3099: //----------------------------------------------------------------------------- ds@3099: // Purpose: Utility class to quickly allow ConCommands to call member methods ds@3099: //----------------------------------------------------------------------------- skamonkey@3515: #ifdef _WIN32 ds@3099: #pragma warning (disable : 4355 ) skamonkey@3515: #endif ds@3099: ds@3099: template< class T > ds@3099: class CConCommandMemberAccessor : public ConCommand, public ICommandCallback, public ICommandCompletionCallback ds@3099: { ds@3099: typedef ConCommand BaseClass; ds@3099: typedef void ( T::*FnMemberCommandCallback_t )( const CCommand &command ); ds@3099: typedef int ( T::*FnMemberCommandCompletionCallback_t )( const char *pPartial, CUtlVector< CUtlString > &commands ); ds@3099: ds@3099: public: ds@3099: CConCommandMemberAccessor( T* pOwner, const char *pName, FnMemberCommandCallback_t callback, const char *pHelpString = 0, ds@3099: int flags = 0, FnMemberCommandCompletionCallback_t completionFunc = 0 ) : ds@3099: BaseClass( pName, this, pHelpString, flags, ( completionFunc != 0 ) ? this : NULL ) ds@3099: { ds@3099: m_pOwner = pOwner; ds@3099: m_Func = callback; ds@3099: m_CompletionFunc = completionFunc; ds@3099: } ds@3099: ds@3099: ~CConCommandMemberAccessor() ds@3099: { ds@3099: Shutdown(); ds@3099: } ds@3099: ds@3099: void SetOwner( T* pOwner ) ds@3099: { ds@3099: m_pOwner = pOwner; ds@3099: } ds@3099: ds@3099: virtual void CommandCallback( const CCommand &command ) ds@3099: { ds@3099: Assert( m_pOwner && m_Func ); ds@3099: (m_pOwner->*m_Func)( command ); ds@3099: } ds@3099: ds@3099: virtual int CommandCompletionCallback( const char *pPartial, CUtlVector< CUtlString > &commands ) ds@3099: { ds@3099: Assert( m_pOwner && m_CompletionFunc ); ds@3099: return (m_pOwner->*m_CompletionFunc)( pPartial, commands ); ds@3099: } ds@3099: ds@3099: private: ds@3099: T* m_pOwner; ds@3099: FnMemberCommandCallback_t m_Func; ds@3099: FnMemberCommandCompletionCallback_t m_CompletionFunc; ds@3099: }; ds@3099: skamonkey@3515: #ifdef _WIN32 ds@3099: #pragma warning ( default : 4355 ) skamonkey@3515: #endif ds@3099: ds@3099: ds@3099: //----------------------------------------------------------------------------- ds@3099: // Purpose: Utility macros to quicky generate a simple console command ds@3099: //----------------------------------------------------------------------------- ds@3099: #define CON_COMMAND( name, description ) \ ds@3099: static void name( const CCommand &args ); \ ds@3099: static ConCommand name##_command( #name, name, description ); \ ds@3099: static void name( const CCommand &args ) ds@3099: ds@3099: #ifdef CLIENT_DLL ds@3099: #define CON_COMMAND_SHARED( name, description ) \ ds@3099: static void name( const CCommand &args ); \ ds@3099: static ConCommand name##_command_client( #name "_client", name, description ); \ ds@3099: static void name( const CCommand &args ) ds@3099: #else ds@3099: #define CON_COMMAND_SHARED( name, description ) \ ds@3099: static void name( const CCommand &args ); \ ds@3099: static ConCommand name##_command( #name, name, description ); \ ds@3099: static void name( const CCommand &args ) ds@3099: #endif ds@3099: ds@3099: ds@3099: #define CON_COMMAND_F( name, description, flags ) \ ds@3099: static void name( const CCommand &args ); \ ds@3099: static ConCommand name##_command( #name, name, description, flags ); \ ds@3099: static void name( const CCommand &args ) ds@3099: ds@3099: #ifdef CLIENT_DLL ds@3099: #define CON_COMMAND_F_SHARED( name, description, flags ) \ ds@3099: static void name( const CCommand &args ); \ ds@3099: static ConCommand name##_command_client( #name "_client", name, description, flags ); \ ds@3099: static void name( const CCommand &args ) ds@3099: #else ds@3099: #define CON_COMMAND_F_SHARED( name, description, flags ) \ ds@3099: static void name( const CCommand &args ); \ ds@3099: static ConCommand name##_command( #name, name, description, flags ); \ ds@3099: static void name( const CCommand &args ) ds@3099: #endif ds@3099: ds@3099: ds@3099: #define CON_COMMAND_F_COMPLETION( name, description, flags, completion ) \ ds@3099: static void name( const CCommand &args ); \ ds@3099: static ConCommand name##_command( #name, name, description, flags, completion ); \ ds@3099: static void name( const CCommand &args ) ds@3099: ds@3099: #ifdef CLIENT_DLL ds@3099: #define CON_COMMAND_F_COMPLETION_SHARED( name, description, flags, completion ) \ ds@3099: static void name( const CCommand &args ); \ ds@3099: static ConCommand name##_command_client( #name "_client", name, description, flags, completion ); \ ds@3099: static void name( const CCommand &args ) ds@3099: #else ds@3099: #define CON_COMMAND_F_COMPLETION_SHARED( name, description, flags, completion ) \ ds@3099: static void name( const CCommand &args ); \ ds@3099: static ConCommand name##_command( #name, name, description, flags, completion ); \ ds@3099: static void name( const CCommand &args ) ds@3099: #endif ds@3099: ds@3099: ds@3099: #define CON_COMMAND_EXTERN( name, _funcname, description ) \ ds@3099: void _funcname( const CCommand &args ); \ ds@3099: static ConCommand name##_command( #name, _funcname, description ); \ ds@3099: void _funcname( const CCommand &args ) ds@3099: ds@3099: #define CON_COMMAND_EXTERN_F( name, _funcname, description, flags ) \ ds@3099: void _funcname( const CCommand &args ); \ ds@3099: static ConCommand name##_command( #name, _funcname, description, flags ); \ ds@3099: void _funcname( const CCommand &args ) ds@3099: ds@3099: #define CON_COMMAND_MEMBER_F( _thisclass, name, _funcname, description, flags ) \ ds@3099: void _funcname( const CCommand &args ); \ ds@3099: friend class CCommandMemberInitializer_##_funcname; \ ds@3099: class CCommandMemberInitializer_##_funcname \ ds@3099: { \ ds@3099: public: \ ds@3099: CCommandMemberInitializer_##_funcname() : m_ConCommandAccessor( NULL, name, &_thisclass::_funcname, description, flags ) \ ds@3099: { \ ds@3099: m_ConCommandAccessor.SetOwner( GET_OUTER( _thisclass, m_##_funcname##_register ) ); \ ds@3099: } \ ds@3099: private: \ ds@3099: CConCommandMemberAccessor< _thisclass > m_ConCommandAccessor; \ ds@3099: }; \ ds@3099: \ ds@3099: CCommandMemberInitializer_##_funcname m_##_funcname##_register; \ ds@3099: ds@3099: ds@3099: #endif // CONVAR_H