mirror of
https://github.com/nillerusr/source-engine.git
synced 2024-12-23 06:36:54 +00:00
1522 lines
39 KiB
C++
1522 lines
39 KiB
C++
//===== Copyright <20> 1996-2005, Valve Corporation, All rights reserved. ======//
|
||
//
|
||
// Purpose:
|
||
//
|
||
// $NoKeywords: $
|
||
//
|
||
//===========================================================================//
|
||
|
||
#include <stdio.h>
|
||
#include <stdlib.h>
|
||
#include <string.h>
|
||
#include "basetypes.h"
|
||
#include "tier1/convar.h"
|
||
#include "tier1/strtools.h"
|
||
#include "tier1/characterset.h"
|
||
#include "tier1/utlbuffer.h"
|
||
#include "tier1/tier1.h"
|
||
#include "tier1/convar_serverbounded.h"
|
||
#include "icvar.h"
|
||
#include "tier0/dbg.h"
|
||
#if defined( _X360 )
|
||
#include "xbox/xbox_console.h"
|
||
#endif
|
||
#include "tier0/memdbgon.h"
|
||
|
||
|
||
// Comment this out when we release.
|
||
//#define ALLOW_DEVELOPMENT_CVARS
|
||
// This enables the l4d style of culling all cvars that are not marked FCVAR_RELEASE :
|
||
// #define CULL_ALL_CVARS_NOT_FCVAR_RELEASE
|
||
|
||
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Statically constructed list of ConCommandBases,
|
||
// used for registering them with the ICVar interface
|
||
//-----------------------------------------------------------------------------
|
||
ConCommandBase *ConCommandBase::s_pConCommandBases = NULL;
|
||
IConCommandBaseAccessor *ConCommandBase::s_pAccessor = NULL;
|
||
static int s_nCVarFlag = 0;
|
||
static int s_nDLLIdentifier = -1; // A unique identifier indicating which DLL this convar came from
|
||
static bool s_bRegistered = false;
|
||
|
||
class CDefaultAccessor : public IConCommandBaseAccessor
|
||
{
|
||
public:
|
||
virtual bool RegisterConCommandBase( ConCommandBase *pVar )
|
||
{
|
||
// Link to engine's list instead
|
||
g_pCVar->RegisterConCommand( pVar );
|
||
return true;
|
||
}
|
||
};
|
||
|
||
static CDefaultAccessor s_DefaultAccessor;
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Called by the framework to register ConCommandBases with the ICVar
|
||
//-----------------------------------------------------------------------------
|
||
void ConVar_Register( int nCVarFlag, IConCommandBaseAccessor *pAccessor )
|
||
{
|
||
if ( !g_pCVar || s_bRegistered )
|
||
return;
|
||
|
||
Assert( s_nDLLIdentifier < 0 );
|
||
s_bRegistered = true;
|
||
s_nCVarFlag = nCVarFlag;
|
||
s_nDLLIdentifier = g_pCVar->AllocateDLLIdentifier();
|
||
|
||
ConCommandBase *pCur, *pNext;
|
||
|
||
ConCommandBase::s_pAccessor = pAccessor ? pAccessor : &s_DefaultAccessor;
|
||
pCur = ConCommandBase::s_pConCommandBases;
|
||
while ( pCur )
|
||
{
|
||
pNext = pCur->m_pNext;
|
||
pCur->AddFlags( s_nCVarFlag );
|
||
pCur->Init();
|
||
pCur = pNext;
|
||
}
|
||
|
||
g_pCVar->AddSplitScreenConVars();
|
||
g_pCVar->ProcessQueuedMaterialThreadConVarSets();
|
||
|
||
ConCommandBase::s_pConCommandBases = NULL;
|
||
}
|
||
|
||
void ConVar_Unregister( )
|
||
{
|
||
if ( !g_pCVar || !s_bRegistered )
|
||
return;
|
||
|
||
Assert( s_nDLLIdentifier >= 0 );
|
||
|
||
// Do this after unregister!!!
|
||
g_pCVar->RemoveSplitScreenConVars( s_nDLLIdentifier );
|
||
g_pCVar->UnregisterConCommands( s_nDLLIdentifier );
|
||
s_nDLLIdentifier = -1;
|
||
s_bRegistered = false;
|
||
}
|
||
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Purpose: Default constructor
|
||
//-----------------------------------------------------------------------------
|
||
ConCommandBase::ConCommandBase( void )
|
||
{
|
||
m_bRegistered = false;
|
||
m_pszName = NULL;
|
||
m_pszHelpString = NULL;
|
||
|
||
m_nFlags = 0;
|
||
m_pNext = NULL;
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Purpose: The base console invoked command/cvar interface
|
||
// Input : *pName - name of variable/command
|
||
// *pHelpString - help text
|
||
// flags - flags
|
||
//-----------------------------------------------------------------------------
|
||
ConCommandBase::ConCommandBase( const char *pName, const char *pHelpString /*=0*/, int flags /*= 0*/ )
|
||
{
|
||
Create( pName, pHelpString, flags );
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Purpose:
|
||
//-----------------------------------------------------------------------------
|
||
ConCommandBase::~ConCommandBase( void )
|
||
{
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Purpose:
|
||
// Output : Returns true on success, false on failure.
|
||
//-----------------------------------------------------------------------------
|
||
bool ConCommandBase::IsCommand( void ) const
|
||
{
|
||
// Assert( 0 ); This can't assert. . causes a recursive assert in Sys_Printf, etc.
|
||
return true;
|
||
}
|
||
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Returns the DLL identifier
|
||
//-----------------------------------------------------------------------------
|
||
CVarDLLIdentifier_t ConCommandBase::GetDLLIdentifier() const
|
||
{
|
||
return s_nDLLIdentifier;
|
||
}
|
||
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Purpose:
|
||
// Input : *pName -
|
||
// callback -
|
||
// *pHelpString -
|
||
// flags -
|
||
//-----------------------------------------------------------------------------
|
||
void ConCommandBase::Create( const char *pName, const char *pHelpString /*= 0*/, int flags /*= 0*/ )
|
||
{
|
||
static char *empty_string = "";
|
||
|
||
m_bRegistered = false;
|
||
|
||
// Name should be static data
|
||
Assert( pName );
|
||
m_pszName = pName;
|
||
m_pszHelpString = pHelpString ? pHelpString : empty_string;
|
||
|
||
m_nFlags = flags;
|
||
|
||
#ifdef ALLOW_DEVELOPMENT_CVARS
|
||
m_nFlags &= ~FCVAR_DEVELOPMENTONLY;
|
||
#endif
|
||
|
||
if ( !( m_nFlags & FCVAR_UNREGISTERED ) )
|
||
{
|
||
m_pNext = s_pConCommandBases;
|
||
s_pConCommandBases = this;
|
||
}
|
||
else
|
||
{
|
||
// It's unregistered
|
||
m_pNext = NULL;
|
||
}
|
||
|
||
// If s_pAccessor is already set (this ConVar is not a global variable),
|
||
// register it.
|
||
if ( s_pAccessor )
|
||
{
|
||
Init();
|
||
}
|
||
}
|
||
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Purpose: Used internally by OneTimeInit to initialize.
|
||
//-----------------------------------------------------------------------------
|
||
void ConCommandBase::Init()
|
||
{
|
||
if ( s_pAccessor )
|
||
{
|
||
s_pAccessor->RegisterConCommandBase( this );
|
||
}
|
||
}
|
||
|
||
void ConCommandBase::Shutdown()
|
||
{
|
||
if ( g_pCVar )
|
||
{
|
||
g_pCVar->UnregisterConCommand( this );
|
||
}
|
||
}
|
||
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Purpose: Return name of the command/var
|
||
// Output : const char
|
||
//-----------------------------------------------------------------------------
|
||
const char *ConCommandBase::GetName( void ) const
|
||
{
|
||
return m_pszName;
|
||
}
|
||
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Purpose:
|
||
// Input : flag -
|
||
// Output : Returns true on success, false on failure.
|
||
//-----------------------------------------------------------------------------
|
||
bool ConCommandBase::IsFlagSet( int flag ) const
|
||
{
|
||
return ( flag & m_nFlags ) ? true : false;
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Purpose:
|
||
// Input : flags -
|
||
//-----------------------------------------------------------------------------
|
||
void ConCommandBase::AddFlags( int flags )
|
||
{
|
||
m_nFlags |= flags;
|
||
|
||
#ifdef ALLOW_DEVELOPMENT_CVARS
|
||
m_nFlags &= ~FCVAR_DEVELOPMENTONLY;
|
||
#endif
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Purpose: removes specified flags
|
||
//-----------------------------------------------------------------------------
|
||
void ConCommandBase::RemoveFlags( int flags )
|
||
{
|
||
m_nFlags &= ~flags;
|
||
}
|
||
|
||
// Returns current flags
|
||
int ConCommandBase::GetFlags() const
|
||
{
|
||
return m_nFlags;
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Purpose:
|
||
// Output : const ConCommandBase
|
||
//-----------------------------------------------------------------------------
|
||
const ConCommandBase *ConCommandBase::GetNext( void ) const
|
||
{
|
||
return m_pNext;
|
||
}
|
||
|
||
ConCommandBase *ConCommandBase::GetNext( void )
|
||
{
|
||
return m_pNext;
|
||
}
|
||
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Purpose: Copies string using local new/delete operators
|
||
// Input : *from -
|
||
// Output : char
|
||
//-----------------------------------------------------------------------------
|
||
char *ConCommandBase::CopyString( const char *from )
|
||
{
|
||
int len;
|
||
char *to;
|
||
|
||
len = strlen( from );
|
||
if ( len <= 0 )
|
||
{
|
||
to = new char[1];
|
||
to[0] = 0;
|
||
}
|
||
else
|
||
{
|
||
to = new char[len+1];
|
||
V_strncpy( to, from, len+1 );
|
||
}
|
||
return to;
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Purpose:
|
||
// Output : const char
|
||
//-----------------------------------------------------------------------------
|
||
const char *ConCommandBase::GetHelpText( void ) const
|
||
{
|
||
return m_pszHelpString;
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Purpose: Has this cvar been registered
|
||
// Output : Returns true on success, false on failure.
|
||
//-----------------------------------------------------------------------------
|
||
bool ConCommandBase::IsRegistered( void ) const
|
||
{
|
||
return m_bRegistered;
|
||
}
|
||
|
||
|
||
//-----------------------------------------------------------------------------
|
||
//
|
||
// Con Commands start here
|
||
//
|
||
//-----------------------------------------------------------------------------
|
||
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Global methods
|
||
//-----------------------------------------------------------------------------
|
||
static characterset_t s_BreakSet;
|
||
static bool s_bBuiltBreakSet = false;
|
||
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Tokenizer class
|
||
//-----------------------------------------------------------------------------
|
||
CCommand::CCommand()
|
||
{
|
||
if ( !s_bBuiltBreakSet )
|
||
{
|
||
s_bBuiltBreakSet = true;
|
||
CharacterSetBuild( &s_BreakSet, "{}()':" );
|
||
}
|
||
|
||
Reset();
|
||
}
|
||
|
||
CCommand::CCommand( int nArgC, const char **ppArgV )
|
||
{
|
||
Assert( nArgC > 0 );
|
||
|
||
if ( !s_bBuiltBreakSet )
|
||
{
|
||
s_bBuiltBreakSet = true;
|
||
CharacterSetBuild( &s_BreakSet, "{}()':" );
|
||
}
|
||
|
||
Reset();
|
||
|
||
char *pBuf = m_pArgvBuffer;
|
||
char *pSBuf = m_pArgSBuffer;
|
||
m_nArgc = nArgC;
|
||
for ( int i = 0; i < nArgC; ++i )
|
||
{
|
||
m_ppArgv[i] = pBuf;
|
||
int nLen = V_strlen( ppArgV[i] );
|
||
memcpy( pBuf, ppArgV[i], nLen+1 );
|
||
if ( i == 0 )
|
||
{
|
||
m_nArgv0Size = nLen;
|
||
}
|
||
pBuf += nLen+1;
|
||
|
||
bool bContainsSpace = strchr( ppArgV[i], ' ' ) != NULL;
|
||
if ( bContainsSpace )
|
||
{
|
||
*pSBuf++ = '\"';
|
||
}
|
||
memcpy( pSBuf, ppArgV[i], nLen );
|
||
pSBuf += nLen;
|
||
if ( bContainsSpace )
|
||
{
|
||
*pSBuf++ = '\"';
|
||
}
|
||
|
||
if ( i != nArgC - 1 )
|
||
{
|
||
*pSBuf++ = ' ';
|
||
}
|
||
}
|
||
}
|
||
|
||
void CCommand::Reset()
|
||
{
|
||
m_nArgc = 0;
|
||
m_nArgv0Size = 0;
|
||
m_pArgSBuffer[0] = 0;
|
||
}
|
||
|
||
characterset_t* CCommand::DefaultBreakSet()
|
||
{
|
||
return &s_BreakSet;
|
||
}
|
||
|
||
bool CCommand::Tokenize( const char *pCommand, characterset_t *pBreakSet )
|
||
{
|
||
Reset();
|
||
if ( !pCommand )
|
||
return false;
|
||
|
||
// Use default break set
|
||
if ( !pBreakSet )
|
||
{
|
||
pBreakSet = &s_BreakSet;
|
||
}
|
||
|
||
// Copy the current command into a temp buffer
|
||
// NOTE: This is here to avoid the pointers returned by DequeueNextCommand
|
||
// to become invalid by calling AddText. Is there a way we can avoid the memcpy?
|
||
int nLen = V_strlen( pCommand );
|
||
if ( nLen >= COMMAND_MAX_LENGTH - 1 )
|
||
{
|
||
Warning( "CCommand::Tokenize: Encountered command which overflows the tokenizer buffer.. Skipping!\n" );
|
||
return false;
|
||
}
|
||
|
||
memcpy( m_pArgSBuffer, pCommand, nLen + 1 );
|
||
|
||
// Parse the current command into the current command buffer
|
||
CUtlBuffer bufParse( m_pArgSBuffer, nLen, CUtlBuffer::TEXT_BUFFER | CUtlBuffer::READ_ONLY );
|
||
int nArgvBufferSize = 0;
|
||
while ( bufParse.IsValid() && ( m_nArgc < COMMAND_MAX_ARGC ) )
|
||
{
|
||
char *pArgvBuf = &m_pArgvBuffer[nArgvBufferSize];
|
||
int nMaxLen = COMMAND_MAX_LENGTH - nArgvBufferSize;
|
||
int nStartGet = bufParse.TellGet();
|
||
int nSize = bufParse.ParseToken( pBreakSet, pArgvBuf, nMaxLen );
|
||
if ( nSize < 0 )
|
||
break;
|
||
|
||
// Check for overflow condition
|
||
if ( nMaxLen == nSize )
|
||
{
|
||
Reset();
|
||
return false;
|
||
}
|
||
|
||
if ( m_nArgc == 1 )
|
||
{
|
||
// Deal with the case where the arguments were quoted
|
||
m_nArgv0Size = bufParse.TellGet();
|
||
bool bFoundEndQuote = m_pArgSBuffer[m_nArgv0Size-1] == '\"';
|
||
if ( bFoundEndQuote )
|
||
{
|
||
--m_nArgv0Size;
|
||
}
|
||
m_nArgv0Size -= nSize;
|
||
Assert( m_nArgv0Size != 0 );
|
||
|
||
// The StartGet check is to handle this case: "foo"bar
|
||
// which will parse into 2 different args. ArgS should point to bar.
|
||
bool bFoundStartQuote = ( m_nArgv0Size > nStartGet ) && ( m_pArgSBuffer[m_nArgv0Size-1] == '\"' );
|
||
Assert( bFoundEndQuote == bFoundStartQuote );
|
||
if ( bFoundStartQuote )
|
||
{
|
||
--m_nArgv0Size;
|
||
}
|
||
}
|
||
|
||
m_ppArgv[ m_nArgc++ ] = pArgvBuf;
|
||
if( m_nArgc >= COMMAND_MAX_ARGC )
|
||
{
|
||
Warning( "CCommand::Tokenize: Encountered command which overflows the argument buffer.. Clamped!\n" );
|
||
}
|
||
|
||
nArgvBufferSize += nSize + 1;
|
||
Assert( nArgvBufferSize <= COMMAND_MAX_LENGTH );
|
||
}
|
||
|
||
return true;
|
||
}
|
||
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Helper function to parse arguments to commands.
|
||
//-----------------------------------------------------------------------------
|
||
const char* CCommand::FindArg( const char *pName ) const
|
||
{
|
||
int nArgC = ArgC();
|
||
for ( int i = 1; i < nArgC; i++ )
|
||
{
|
||
if ( !V_stricmp( Arg(i), pName ) )
|
||
return (i+1) < nArgC ? Arg( i+1 ) : "";
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
int CCommand::FindArgInt( const char *pName, int nDefaultVal ) const
|
||
{
|
||
const char *pVal = FindArg( pName );
|
||
if ( pVal )
|
||
return atoi( pVal );
|
||
else
|
||
return nDefaultVal;
|
||
}
|
||
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Default console command autocompletion function
|
||
//-----------------------------------------------------------------------------
|
||
int DefaultCompletionFunc( const char *partial, char commands[ COMMAND_COMPLETION_MAXITEMS ][ COMMAND_COMPLETION_ITEM_LENGTH ] )
|
||
{
|
||
return 0;
|
||
}
|
||
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Purpose: Constructs a console command
|
||
//-----------------------------------------------------------------------------
|
||
//ConCommand::ConCommand()
|
||
//{
|
||
// m_bIsNewConCommand = true;
|
||
//}
|
||
|
||
ConCommand::ConCommand( const char *pName, FnCommandCallbackV1_t callback, const char *pHelpString /*= 0*/, int flags /*= 0*/, FnCommandCompletionCallback completionFunc /*= 0*/ )
|
||
{
|
||
// Set the callback
|
||
m_fnCommandCallbackV1 = callback;
|
||
m_bUsingNewCommandCallback = false;
|
||
m_bUsingCommandCallbackInterface = false;
|
||
m_fnCompletionCallback = completionFunc ? completionFunc : DefaultCompletionFunc;
|
||
m_bHasCompletionCallback = completionFunc != 0 ? true : false;
|
||
|
||
// Setup the rest
|
||
BaseClass::Create( pName, pHelpString, flags );
|
||
}
|
||
|
||
ConCommand::ConCommand( const char *pName, FnCommandCallback_t callback, const char *pHelpString /*= 0*/, int flags /*= 0*/, FnCommandCompletionCallback completionFunc /*= 0*/ )
|
||
{
|
||
// Set the callback
|
||
m_fnCommandCallback = callback;
|
||
m_bUsingNewCommandCallback = true;
|
||
m_fnCompletionCallback = completionFunc ? completionFunc : DefaultCompletionFunc;
|
||
m_bHasCompletionCallback = completionFunc != 0 ? true : false;
|
||
m_bUsingCommandCallbackInterface = false;
|
||
|
||
// Setup the rest
|
||
BaseClass::Create( pName, pHelpString, flags );
|
||
}
|
||
|
||
ConCommand::ConCommand( const char *pName, ICommandCallback *pCallback, const char *pHelpString /*= 0*/, int flags /*= 0*/, ICommandCompletionCallback *pCompletionCallback /*= 0*/ )
|
||
{
|
||
// Set the callback
|
||
m_pCommandCallback = pCallback;
|
||
m_bUsingNewCommandCallback = false;
|
||
m_pCommandCompletionCallback = pCompletionCallback;
|
||
m_bHasCompletionCallback = ( pCompletionCallback != 0 );
|
||
m_bUsingCommandCallbackInterface = true;
|
||
|
||
// Setup the rest
|
||
BaseClass::Create( pName, pHelpString, flags );
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Destructor
|
||
//-----------------------------------------------------------------------------
|
||
ConCommand::~ConCommand( void )
|
||
{
|
||
}
|
||
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Purpose: Returns true if this is a command
|
||
//-----------------------------------------------------------------------------
|
||
bool ConCommand::IsCommand( void ) const
|
||
{
|
||
return true;
|
||
}
|
||
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Purpose: Invoke the function if there is one
|
||
//-----------------------------------------------------------------------------
|
||
void ConCommand::Dispatch( const CCommand &command )
|
||
{
|
||
if ( m_bUsingNewCommandCallback )
|
||
{
|
||
if ( m_fnCommandCallback )
|
||
{
|
||
( *m_fnCommandCallback )( command );
|
||
return;
|
||
}
|
||
}
|
||
else if ( m_bUsingCommandCallbackInterface )
|
||
{
|
||
if ( m_pCommandCallback )
|
||
{
|
||
m_pCommandCallback->CommandCallback( command );
|
||
return;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
if ( m_fnCommandCallbackV1 )
|
||
{
|
||
( *m_fnCommandCallbackV1 )();
|
||
return;
|
||
}
|
||
}
|
||
|
||
// Command without callback!!!
|
||
AssertMsg1( 0, "Encountered ConCommand '%s' without a callback!\n", GetName() );
|
||
}
|
||
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Purpose: Calls the autocompletion method to get autocompletion suggestions
|
||
//-----------------------------------------------------------------------------
|
||
int ConCommand::AutoCompleteSuggest( const char *partial, CUtlVector< CUtlString > &commands )
|
||
{
|
||
if ( m_bUsingCommandCallbackInterface )
|
||
{
|
||
if ( !m_pCommandCompletionCallback )
|
||
return 0;
|
||
return m_pCommandCompletionCallback->CommandCompletionCallback( partial, commands );
|
||
}
|
||
|
||
Assert( m_fnCompletionCallback );
|
||
if ( !m_fnCompletionCallback )
|
||
return 0;
|
||
|
||
char rgpchCommands[ COMMAND_COMPLETION_MAXITEMS ][ COMMAND_COMPLETION_ITEM_LENGTH ];
|
||
int iret = ( m_fnCompletionCallback )( partial, rgpchCommands );
|
||
for ( int i = 0 ; i < iret; ++i )
|
||
{
|
||
CUtlString str = rgpchCommands[ i ];
|
||
commands.AddToTail( str );
|
||
}
|
||
return iret;
|
||
}
|
||
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Returns true if the console command can autocomplete
|
||
//-----------------------------------------------------------------------------
|
||
bool ConCommand::CanAutoComplete( void )
|
||
{
|
||
return m_bHasCompletionCallback;
|
||
}
|
||
|
||
|
||
|
||
//-----------------------------------------------------------------------------
|
||
//
|
||
// Console Variables
|
||
//
|
||
//-----------------------------------------------------------------------------
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Various constructors
|
||
//-----------------------------------------------------------------------------
|
||
ConVar::ConVar( const char *pName, const char *pDefaultValue, int flags /* = 0 */ )
|
||
{
|
||
Create( pName, pDefaultValue, flags );
|
||
}
|
||
|
||
ConVar::ConVar( const char *pName, const char *pDefaultValue, int flags, const char *pHelpString )
|
||
{
|
||
Create( pName, pDefaultValue, flags, pHelpString );
|
||
}
|
||
|
||
ConVar::ConVar( const char *pName, const char *pDefaultValue, int flags, const char *pHelpString, bool bMin, float fMin, bool bMax, float fMax )
|
||
{
|
||
Create( pName, pDefaultValue, flags, pHelpString, bMin, fMin, bMax, fMax );
|
||
}
|
||
|
||
ConVar::ConVar( const char *pName, const char *pDefaultValue, int flags, const char *pHelpString, FnChangeCallback_t callback )
|
||
{
|
||
Create( pName, pDefaultValue, flags, pHelpString, false, 0.0, false, 0.0, callback );
|
||
}
|
||
|
||
ConVar::ConVar( const char *pName, const char *pDefaultValue, int flags, const char *pHelpString, bool bMin, float fMin, bool bMax, float fMax, FnChangeCallback_t callback )
|
||
{
|
||
Create( pName, pDefaultValue, flags, pHelpString, bMin, fMin, bMax, fMax, callback );
|
||
}
|
||
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Destructor
|
||
//-----------------------------------------------------------------------------
|
||
ConVar::~ConVar( void )
|
||
{
|
||
if ( m_Value.m_pszString )
|
||
{
|
||
delete[] m_Value.m_pszString;
|
||
m_Value.m_pszString = NULL;
|
||
}
|
||
}
|
||
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Install a change callback (there shouldn't already be one....)
|
||
//-----------------------------------------------------------------------------
|
||
void ConVar::InstallChangeCallback( FnChangeCallback_t callback, bool bInvoke /*=true*/ )
|
||
{
|
||
if ( !callback )
|
||
{
|
||
Warning( "InstallChangeCallback called with NULL callback, ignoring!!!\n" );
|
||
return;
|
||
}
|
||
|
||
if ( m_pParent->m_fnChangeCallbacks.Find( callback ) != m_pParent->m_fnChangeCallbacks.InvalidIndex() )
|
||
{
|
||
// Same ptr added twice, sigh...
|
||
Warning( "InstallChangeCallback ignoring duplicate change callback!!!\n" );
|
||
return;
|
||
}
|
||
|
||
m_pParent->m_fnChangeCallbacks.AddToTail( callback );
|
||
|
||
// Call it immediately to set the initial value...
|
||
if ( bInvoke )
|
||
{
|
||
callback( this, m_Value.m_pszString, m_Value.m_fValue );
|
||
}
|
||
}
|
||
|
||
void ConVar::RemoveChangeCallback( FnChangeCallback_t callback )
|
||
{
|
||
m_pParent->m_fnChangeCallbacks.FindAndRemove( callback );
|
||
}
|
||
|
||
bool ConVar::IsFlagSet( int flag ) const
|
||
{
|
||
return ( flag & m_pParent->m_nFlags ) ? true : false;
|
||
}
|
||
|
||
int ConVar::GetFlags() const
|
||
{
|
||
return m_pParent->m_nFlags;
|
||
}
|
||
|
||
const char *ConVar::GetHelpText( void ) const
|
||
{
|
||
return m_pParent->m_pszHelpString;
|
||
}
|
||
|
||
void ConVar::AddFlags( int flags )
|
||
{
|
||
m_pParent->m_nFlags |= flags;
|
||
|
||
#ifdef ALLOW_DEVELOPMENT_CVARS
|
||
m_pParent->m_nFlags &= ~FCVAR_DEVELOPMENTONLY;
|
||
#endif
|
||
}
|
||
|
||
bool ConVar::IsRegistered( void ) const
|
||
{
|
||
return m_pParent->m_bRegistered;
|
||
}
|
||
|
||
const char *ConVar::GetName( void ) const
|
||
{
|
||
return m_pParent->m_pszName;
|
||
}
|
||
|
||
const char *ConVar::GetBaseName( void ) const
|
||
{
|
||
return m_pParent->m_pszName;
|
||
}
|
||
|
||
int ConVar::GetSplitScreenPlayerSlot( void ) const
|
||
{
|
||
// Default implementation (certain FCVAR_USERINFO derive a new type of convar and set this)
|
||
return 0;
|
||
}
|
||
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Purpose:
|
||
// Output : Returns true on success, false on failure.
|
||
//-----------------------------------------------------------------------------
|
||
bool ConVar::IsCommand( void ) const
|
||
{
|
||
return false;
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Purpose:
|
||
// Input :
|
||
//-----------------------------------------------------------------------------
|
||
void ConVar::Init()
|
||
{
|
||
BaseClass::Init();
|
||
}
|
||
|
||
bool ConVar::InternalSetColorFromString( const char *value )
|
||
{
|
||
bool bColor = false;
|
||
|
||
// Try pulling RGBA color values out of the string
|
||
int nRGBA[4];
|
||
int nParamsRead = sscanf( value, "%i %i %i %i", &(nRGBA[0]), &(nRGBA[1]), &(nRGBA[2]), &(nRGBA[3]) );
|
||
|
||
if ( nParamsRead >= 3 )
|
||
{
|
||
// This is probably a color!
|
||
if ( nParamsRead == 3 )
|
||
{
|
||
// Assume they wanted full alpha
|
||
nRGBA[3] = 255;
|
||
}
|
||
|
||
if ( nRGBA[0] >= 0 && nRGBA[0] <= 255 &&
|
||
nRGBA[1] >= 0 && nRGBA[1] <= 255 &&
|
||
nRGBA[2] >= 0 && nRGBA[2] <= 255 &&
|
||
nRGBA[3] >= 0 && nRGBA[3] <= 255 )
|
||
{
|
||
// This is definitely a color!
|
||
bColor = true;
|
||
|
||
// Stuff all the values into each byte of our int
|
||
unsigned char *pColorElement = ((unsigned char*)&m_Value.m_nValue);
|
||
pColorElement[0] = nRGBA[0];
|
||
pColorElement[1] = nRGBA[1];
|
||
pColorElement[2] = nRGBA[2];
|
||
pColorElement[3] = nRGBA[3];
|
||
|
||
// Copy that value into a float (even though this has little meaning)
|
||
m_Value.m_fValue = ( float )( m_Value.m_nValue );
|
||
}
|
||
}
|
||
|
||
return bColor;
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Purpose:
|
||
// Input : *value -
|
||
//-----------------------------------------------------------------------------
|
||
void ConVar::InternalSetValue( const char *value )
|
||
{
|
||
if ( IsFlagSet( FCVAR_MATERIAL_THREAD_MASK ) )
|
||
{
|
||
if ( g_pCVar && !g_pCVar->IsMaterialThreadSetAllowed() )
|
||
{
|
||
g_pCVar->QueueMaterialThreadSetValue( this, value );
|
||
return;
|
||
}
|
||
}
|
||
|
||
char tempVal[ 32 ];
|
||
char *val;
|
||
|
||
Assert(m_pParent == this); // Only valid for root convars.
|
||
|
||
float flOldValue = m_Value.m_fValue;
|
||
val = (char *)value;
|
||
if ( !val )
|
||
val = "";
|
||
|
||
if ( !InternalSetColorFromString( value ) )
|
||
{
|
||
// Not a color, do the standard thing
|
||
float fNewValue = ( float )atof( value );
|
||
if ( !IsFinite( fNewValue ) )
|
||
{
|
||
Warning( "Warning: %s = '%s' is infinite, clamping value.\n", GetName(), value );
|
||
fNewValue = FLT_MAX;
|
||
}
|
||
|
||
if ( ClampValue( fNewValue ) )
|
||
{
|
||
V_snprintf( tempVal,sizeof(tempVal), "%f", fNewValue );
|
||
val = tempVal;
|
||
}
|
||
|
||
// Redetermine value
|
||
m_Value.m_fValue = fNewValue;
|
||
m_Value.m_nValue = ( int )( m_Value.m_fValue );
|
||
}
|
||
|
||
if ( !( m_nFlags & FCVAR_NEVER_AS_STRING ) )
|
||
{
|
||
ChangeStringValue( val, flOldValue );
|
||
}
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Purpose:
|
||
// Input : *tempVal -
|
||
//-----------------------------------------------------------------------------
|
||
void ConVar::ChangeStringValue( const char *tempVal, float flOldValue )
|
||
{
|
||
Assert( !( m_nFlags & FCVAR_NEVER_AS_STRING ) );
|
||
|
||
char* pszOldValue = (char*)stackalloc( m_Value.m_StringLength );
|
||
memcpy( pszOldValue, m_Value.m_pszString, m_Value.m_StringLength );
|
||
|
||
int len = V_strlen(tempVal) + 1;
|
||
|
||
if ( len > m_Value.m_StringLength)
|
||
{
|
||
if (m_Value.m_pszString)
|
||
{
|
||
delete[] m_Value.m_pszString;
|
||
}
|
||
|
||
m_Value.m_pszString = new char[len];
|
||
m_Value.m_StringLength = len;
|
||
}
|
||
|
||
memcpy( m_Value.m_pszString, tempVal, len );
|
||
|
||
// Invoke any necessary callback function
|
||
for ( int i = 0; i < m_fnChangeCallbacks.Count(); ++i )
|
||
{
|
||
m_fnChangeCallbacks[ i ]( this, pszOldValue, flOldValue );
|
||
}
|
||
|
||
if ( g_pCVar )
|
||
{
|
||
g_pCVar->CallGlobalChangeCallbacks( this, pszOldValue, flOldValue );
|
||
}
|
||
|
||
stackfree( pszOldValue );
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Purpose: Check whether to clamp and then perform clamp
|
||
// Input : value -
|
||
// Output : Returns true if value changed
|
||
//-----------------------------------------------------------------------------
|
||
bool ConVar::ClampValue( float& value )
|
||
{
|
||
if ( m_bHasMin && ( value < m_fMinVal ) )
|
||
{
|
||
value = m_fMinVal;
|
||
return true;
|
||
}
|
||
|
||
if ( m_bHasMax && ( value > m_fMaxVal ) )
|
||
{
|
||
value = m_fMaxVal;
|
||
return true;
|
||
}
|
||
|
||
return false;
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Purpose:
|
||
// Input : *value -
|
||
//-----------------------------------------------------------------------------
|
||
void ConVar::InternalSetFloatValue( float fNewValue )
|
||
{
|
||
if ( fNewValue == m_Value.m_fValue )
|
||
return;
|
||
|
||
if ( IsFlagSet( FCVAR_MATERIAL_THREAD_MASK ) )
|
||
{
|
||
if ( g_pCVar && !g_pCVar->IsMaterialThreadSetAllowed() )
|
||
{
|
||
g_pCVar->QueueMaterialThreadSetValue( this, fNewValue );
|
||
return;
|
||
}
|
||
}
|
||
|
||
Assert( m_pParent == this ); // Only valid for root convars.
|
||
|
||
// Check bounds
|
||
ClampValue( fNewValue );
|
||
|
||
// Redetermine value
|
||
float flOldValue = m_Value.m_fValue;
|
||
m_Value.m_fValue = fNewValue;
|
||
m_Value.m_nValue = ( int )m_Value.m_fValue;
|
||
|
||
if ( !( m_nFlags & FCVAR_NEVER_AS_STRING ) )
|
||
{
|
||
char tempVal[ 32 ];
|
||
V_snprintf( tempVal, sizeof( tempVal), "%f", m_Value.m_fValue );
|
||
ChangeStringValue( tempVal, flOldValue );
|
||
}
|
||
else
|
||
{
|
||
Assert( m_fnChangeCallbacks.Count() == 0 );
|
||
}
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Purpose:
|
||
// Input : *value -
|
||
//-----------------------------------------------------------------------------
|
||
void ConVar::InternalSetIntValue( int nValue )
|
||
{
|
||
if ( nValue == m_Value.m_nValue )
|
||
return;
|
||
|
||
if ( IsFlagSet( FCVAR_MATERIAL_THREAD_MASK ) )
|
||
{
|
||
if ( g_pCVar && !g_pCVar->IsMaterialThreadSetAllowed() )
|
||
{
|
||
g_pCVar->QueueMaterialThreadSetValue( this, nValue );
|
||
return;
|
||
}
|
||
}
|
||
|
||
Assert( m_pParent == this ); // Only valid for root convars.
|
||
|
||
float fValue = (float)nValue;
|
||
if ( ClampValue( fValue ) )
|
||
{
|
||
nValue = ( int )( fValue );
|
||
}
|
||
|
||
// Redetermine value
|
||
float flOldValue = m_Value.m_fValue;
|
||
m_Value.m_fValue = fValue;
|
||
m_Value.m_nValue = nValue;
|
||
|
||
if ( !( m_nFlags & FCVAR_NEVER_AS_STRING ) )
|
||
{
|
||
char tempVal[ 32 ];
|
||
V_snprintf( tempVal, sizeof( tempVal ), "%d", m_Value.m_nValue );
|
||
ChangeStringValue( tempVal, flOldValue );
|
||
}
|
||
else
|
||
{
|
||
Assert( m_fnChangeCallbacks.Count() == 0 );
|
||
}
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Purpose:
|
||
// Input : *value -
|
||
//-----------------------------------------------------------------------------
|
||
void ConVar::InternalSetColorValue( Color value )
|
||
{
|
||
// Stuff color values into an int
|
||
int nValue;
|
||
|
||
unsigned char *pColorElement = ((unsigned char*)&nValue);
|
||
pColorElement[0] = value[0];
|
||
pColorElement[1] = value[1];
|
||
pColorElement[2] = value[2];
|
||
pColorElement[3] = value[3];
|
||
|
||
// Call the int internal set
|
||
InternalSetIntValue( nValue );
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Purpose: Private creation
|
||
//-----------------------------------------------------------------------------
|
||
void ConVar::Create( const char *pName, const char *pDefaultValue, int flags /*= 0*/,
|
||
const char *pHelpString /*= NULL*/, bool bMin /*= false*/, float fMin /*= 0.0*/,
|
||
bool bMax /*= false*/, float fMax /*= false*/, FnChangeCallback_t callback /*= NULL*/ )
|
||
{
|
||
static char *empty_string = "";
|
||
|
||
m_pParent = this;
|
||
|
||
// Name should be static data
|
||
m_pszDefaultValue = pDefaultValue ? pDefaultValue : empty_string;
|
||
Assert( m_pszDefaultValue );
|
||
|
||
m_bHasMin = bMin;
|
||
m_fMinVal = fMin;
|
||
m_bHasMax = bMax;
|
||
m_fMaxVal = fMax;
|
||
|
||
if ( callback )
|
||
{
|
||
m_fnChangeCallbacks.AddToTail( callback );
|
||
}
|
||
|
||
m_Value.m_StringLength = strlen( m_pszDefaultValue ) + 1;
|
||
m_Value.m_pszString = new char[m_Value.m_StringLength];
|
||
memcpy( m_Value.m_pszString, m_pszDefaultValue, m_Value.m_StringLength );
|
||
|
||
if ( !InternalSetColorFromString( m_Value.m_pszString ) )
|
||
{
|
||
m_Value.m_fValue = ( float )atof( m_Value.m_pszString );
|
||
if ( !IsFinite( m_Value.m_fValue ) )
|
||
{
|
||
Warning( "ConVar(%s) defined with infinite float value (%s)\n", pName, m_Value.m_pszString );
|
||
m_Value.m_fValue = FLT_MAX;
|
||
Assert( 0 );
|
||
}
|
||
|
||
// Bounds Check, should never happen, if it does, no big deal
|
||
if ( m_bHasMin && ( m_Value.m_fValue < m_fMinVal ) )
|
||
{
|
||
Assert( 0 );
|
||
}
|
||
|
||
if ( m_bHasMax && ( m_Value.m_fValue > m_fMaxVal ) )
|
||
{
|
||
Assert( 0 );
|
||
}
|
||
|
||
m_Value.m_nValue = ( int )m_Value.m_fValue;
|
||
}
|
||
|
||
//If we're not tagged as cheat, archive or release then hide us.
|
||
#if CULL_ALL_CVARS_NOT_FCVAR_RELEASE
|
||
// FIXMEL4DTOMAINMERGE: will need to assess if this hides too many convars for TF and other projects in main
|
||
if ( !( flags & ( FCVAR_CHEAT | FCVAR_ARCHIVE | FCVAR_RELEASE | FCVAR_USERINFO ) ) )
|
||
{
|
||
flags |= FCVAR_DEVELOPMENTONLY;
|
||
}
|
||
#else
|
||
|
||
#endif
|
||
|
||
|
||
BaseClass::Create( pName, pHelpString, flags );
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Purpose:
|
||
// Input : *value -
|
||
//-----------------------------------------------------------------------------
|
||
void ConVar::SetValue(const char *value)
|
||
{
|
||
ConVar *var = ( ConVar * )m_pParent;
|
||
var->InternalSetValue( value );
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Purpose:
|
||
// Input : value -
|
||
//-----------------------------------------------------------------------------
|
||
void ConVar::SetValue( float value )
|
||
{
|
||
ConVar *var = ( ConVar * )m_pParent;
|
||
var->InternalSetFloatValue( value );
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Purpose:
|
||
// Input : value -
|
||
//-----------------------------------------------------------------------------
|
||
void ConVar::SetValue( int value )
|
||
{
|
||
ConVar *var = ( ConVar * )m_pParent;
|
||
var->InternalSetIntValue( value );
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Purpose:
|
||
// Input : value -
|
||
//-----------------------------------------------------------------------------
|
||
void ConVar::SetValue( Color value )
|
||
{
|
||
ConVar *var = ( ConVar * )m_pParent;
|
||
var->InternalSetColorValue( value );
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Purpose: Reset to default value
|
||
//-----------------------------------------------------------------------------
|
||
void ConVar::Revert( void )
|
||
{
|
||
// Force default value again
|
||
ConVar *var = ( ConVar * )m_pParent;
|
||
var->SetValue( var->m_pszDefaultValue );
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Purpose:
|
||
// Input : minVal -
|
||
// Output : true if there is a min set
|
||
//-----------------------------------------------------------------------------
|
||
bool ConVar::GetMin( float& minVal ) const
|
||
{
|
||
minVal = m_pParent->m_fMinVal;
|
||
return m_pParent->m_bHasMin;
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Purpose:
|
||
// Input : maxVal -
|
||
//-----------------------------------------------------------------------------
|
||
bool ConVar::GetMax( float& maxVal ) const
|
||
{
|
||
maxVal = m_pParent->m_fMaxVal;
|
||
return m_pParent->m_bHasMax;
|
||
}
|
||
|
||
float ConVar::GetMinValue() const
|
||
{
|
||
return m_pParent->m_fMinVal;
|
||
}
|
||
|
||
float ConVar::GetMaxValue() const
|
||
{
|
||
return m_pParent->m_fMaxVal;;
|
||
}
|
||
|
||
bool ConVar::HasMin() const
|
||
{
|
||
return m_pParent->m_bHasMin;
|
||
}
|
||
|
||
bool ConVar::HasMax() const
|
||
{
|
||
return m_pParent->m_bHasMax;
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Purpose:
|
||
// Output : const char
|
||
//-----------------------------------------------------------------------------
|
||
const char *ConVar::GetDefault( void ) const
|
||
{
|
||
return m_pParent->m_pszDefaultValue;
|
||
}
|
||
|
||
void ConVar::SetDefault( const char *pszDefault )
|
||
{
|
||
static char *empty_string = "";
|
||
m_pszDefaultValue = pszDefault ? pszDefault : empty_string;
|
||
Assert( m_pszDefaultValue );
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// This version is simply used to make reading convars simpler.
|
||
// Writing convars isn't allowed in this mode
|
||
//-----------------------------------------------------------------------------
|
||
class CEmptyConVar : public ConVar
|
||
{
|
||
public:
|
||
CEmptyConVar() : ConVar( "", "0" ) {}
|
||
// Used for optimal read access
|
||
virtual void SetValue( const char *pValue ) {}
|
||
virtual void SetValue( float flValue ) {}
|
||
virtual void SetValue( int nValue ) {}
|
||
virtual const char *GetName( void ) const { return ""; }
|
||
virtual bool IsFlagSet( int nFlags ) const { return false; }
|
||
};
|
||
|
||
static CEmptyConVar s_EmptyConVar;
|
||
|
||
ConVarRef::ConVarRef( const char *pName )
|
||
{
|
||
Init( pName, false );
|
||
}
|
||
|
||
ConVarRef::ConVarRef( const char *pName, bool bIgnoreMissing )
|
||
{
|
||
Init( pName, bIgnoreMissing );
|
||
}
|
||
|
||
void ConVarRef::Init( const char *pName, bool bIgnoreMissing )
|
||
{
|
||
m_pConVar = g_pCVar ? g_pCVar->FindVar( pName ) : &s_EmptyConVar;
|
||
if ( !m_pConVar )
|
||
{
|
||
m_pConVar = &s_EmptyConVar;
|
||
}
|
||
m_pConVarState = static_cast< ConVar * >( m_pConVar );
|
||
if( !IsValid() )
|
||
{
|
||
static bool bFirst = true;
|
||
if ( g_pCVar || bFirst )
|
||
{
|
||
if ( !bIgnoreMissing )
|
||
{
|
||
Warning( "ConVarRef %s doesn't point to an existing ConVar\n", pName );
|
||
}
|
||
bFirst = false;
|
||
}
|
||
}
|
||
}
|
||
|
||
ConVarRef::ConVarRef( IConVar *pConVar )
|
||
{
|
||
m_pConVar = pConVar ? pConVar : &s_EmptyConVar;
|
||
m_pConVarState = static_cast< ConVar * >( m_pConVar );
|
||
}
|
||
|
||
bool ConVarRef::IsValid() const
|
||
{
|
||
return m_pConVar != &s_EmptyConVar;
|
||
}
|
||
|
||
// Helper for splitscreen ConVars
|
||
SplitScreenConVarRef::SplitScreenConVarRef( const char *pName )
|
||
{
|
||
Init( pName, false );
|
||
}
|
||
|
||
SplitScreenConVarRef::SplitScreenConVarRef( const char *pName, bool bIgnoreMissing )
|
||
{
|
||
Init( pName, bIgnoreMissing );
|
||
}
|
||
|
||
void SplitScreenConVarRef::Init( const char *pName, bool bIgnoreMissing )
|
||
{
|
||
for ( int i = 0; i < MAX_SPLITSCREEN_CLIENTS; ++i )
|
||
{
|
||
cv_t &info = m_Info[ i ];
|
||
char pchName[ 256 ];
|
||
if ( i != 0 )
|
||
{
|
||
V_snprintf( pchName, sizeof( pchName ), "%s%d", pName, i + 1 );
|
||
}
|
||
else
|
||
{
|
||
V_strncpy( pchName, pName, sizeof( pchName ) );
|
||
}
|
||
|
||
info.m_pConVar = g_pCVar ? g_pCVar->FindVar( pchName ) : &s_EmptyConVar;
|
||
if ( !info.m_pConVar )
|
||
{
|
||
info.m_pConVar = &s_EmptyConVar;
|
||
if ( i > 0 )
|
||
{
|
||
// Point at slot zero instead, in case we got in here with a non FCVAR_SS var...
|
||
info.m_pConVar = m_Info[ 0 ].m_pConVar;
|
||
}
|
||
}
|
||
info.m_pConVarState = static_cast< ConVar * >( info.m_pConVar );
|
||
}
|
||
|
||
if ( !IsValid() )
|
||
{
|
||
static bool bFirst = true;
|
||
if ( g_pCVar || bFirst )
|
||
{
|
||
if ( !bIgnoreMissing )
|
||
{
|
||
Warning( "ConVarRef %s doesn't point to an existing ConVar\n", pName );
|
||
}
|
||
bFirst = false;
|
||
}
|
||
}
|
||
}
|
||
|
||
SplitScreenConVarRef::SplitScreenConVarRef( IConVar *pConVar )
|
||
{
|
||
cv_t &info = m_Info[ 0 ];
|
||
info.m_pConVar = pConVar ? pConVar : &s_EmptyConVar;
|
||
info.m_pConVarState = static_cast< ConVar * >( info.m_pConVar );
|
||
|
||
for ( int i = 1; i < MAX_SPLITSCREEN_CLIENTS; ++i )
|
||
{
|
||
info = m_Info[ i ];
|
||
char pchName[ 256 ];
|
||
V_snprintf( pchName, sizeof( pchName ), "%s%d", pConVar->GetName(), i + 1 );
|
||
|
||
info.m_pConVar = g_pCVar ? g_pCVar->FindVar( pchName ) : &s_EmptyConVar;
|
||
if ( !info.m_pConVar )
|
||
{
|
||
info.m_pConVar = &s_EmptyConVar;
|
||
if ( i > 0 )
|
||
{
|
||
// Point at slot zero instead, in case we got in here with a non FCVAR_SS var...
|
||
info.m_pConVar = m_Info[ 0 ].m_pConVar;
|
||
}
|
||
}
|
||
info.m_pConVarState = static_cast< ConVar * >( info.m_pConVar );
|
||
}
|
||
}
|
||
|
||
bool SplitScreenConVarRef::IsValid() const
|
||
{
|
||
return m_Info[ 0 ].m_pConVar != &s_EmptyConVar;
|
||
}
|
||
|
||
struct PrintConVarFlags_t
|
||
{
|
||
int flag;
|
||
const char *desc;
|
||
};
|
||
|
||
static PrintConVarFlags_t g_PrintConVarFlags[] =
|
||
{
|
||
{ FCVAR_GAMEDLL, "game" },
|
||
{ FCVAR_CLIENTDLL, "client" },
|
||
{ FCVAR_ARCHIVE, "archive" },
|
||
{ FCVAR_NOTIFY, "notify" },
|
||
{ FCVAR_SPONLY, "singleplayer" },
|
||
{ FCVAR_NOT_CONNECTED, "notconnected" },
|
||
{ FCVAR_CHEAT, "cheat" },
|
||
{ FCVAR_REPLICATED, "replicated" },
|
||
{ FCVAR_SERVER_CAN_EXECUTE, "server_can_execute" },
|
||
{ FCVAR_CLIENTCMD_CAN_EXECUTE, "clientcmd_can_execute" },
|
||
{ FCVAR_USERINFO, "user" },
|
||
{ FCVAR_SS, "ss" },
|
||
{ FCVAR_SS_ADDED, "ss_added" },
|
||
};
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Purpose:
|
||
//-----------------------------------------------------------------------------
|
||
void ConVar_AppendFlags( const ConCommandBase *var, char *buf, size_t bufsize )
|
||
{
|
||
for ( int i = 0; i < ARRAYSIZE( g_PrintConVarFlags ) ; ++i )
|
||
{
|
||
const PrintConVarFlags_t &info = g_PrintConVarFlags[ i ];
|
||
if ( var->IsFlagSet( info.flag ) )
|
||
{
|
||
char append[ 128 ];
|
||
V_snprintf( append, sizeof( append ), " %s", info.desc );
|
||
V_strncat( buf, append, bufsize, COPY_ALL_CHARACTERS );
|
||
}
|
||
}
|
||
}
|
||
|
||
static void AppendPrintf( char *buf, size_t bufsize, char const *fmt, ... )
|
||
{
|
||
char scratch[ 1024 ];
|
||
va_list argptr;
|
||
va_start( argptr, fmt );
|
||
_vsnprintf( scratch, sizeof( scratch ) - 1, fmt, argptr );
|
||
va_end( argptr );
|
||
scratch[ sizeof( scratch ) - 1 ] = 0;
|
||
|
||
V_strncat( buf, scratch, bufsize, COPY_ALL_CHARACTERS );
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Purpose:
|
||
//-----------------------------------------------------------------------------
|
||
void ConVar_PrintDescription( const ConCommandBase *pVar )
|
||
{
|
||
bool bMin, bMax;
|
||
float fMin, fMax;
|
||
const char *pStr;
|
||
|
||
Assert( pVar );
|
||
|
||
Color clr;
|
||
clr.SetColor( 255, 100, 100, 255 );
|
||
|
||
char outstr[ 4096 ];
|
||
outstr[ 0 ] = 0;
|
||
|
||
if ( !pVar->IsCommand() )
|
||
{
|
||
ConVar *var = ( ConVar * )pVar;
|
||
const ConVar_ServerBounded *pBounded = dynamic_cast<const ConVar_ServerBounded*>( var );
|
||
|
||
bMin = var->GetMin( fMin );
|
||
bMax = var->GetMax( fMax );
|
||
|
||
const char *value = NULL;
|
||
char tempVal[ 32 ];
|
||
|
||
if ( pBounded || var->IsFlagSet( FCVAR_NEVER_AS_STRING ) )
|
||
{
|
||
value = tempVal;
|
||
|
||
int intVal = pBounded ? pBounded->GetInt() : var->GetInt();
|
||
float floatVal = pBounded ? pBounded->GetFloat() : var->GetFloat();
|
||
|
||
if ( fabs( (float)intVal - floatVal ) < 0.000001 )
|
||
{
|
||
V_snprintf( tempVal, sizeof( tempVal ), "%d", intVal );
|
||
}
|
||
else
|
||
{
|
||
V_snprintf( tempVal, sizeof( tempVal ), "%f", floatVal );
|
||
}
|
||
}
|
||
else
|
||
{
|
||
value = var->GetString();
|
||
}
|
||
|
||
if ( value )
|
||
{
|
||
AppendPrintf( outstr, sizeof( outstr ), "\"%s\" = \"%s\"", var->GetName(), value );
|
||
|
||
if ( V_stricmp( value, var->GetDefault() ) )
|
||
{
|
||
AppendPrintf( outstr, sizeof( outstr ), " ( def. \"%s\" )", var->GetDefault() );
|
||
}
|
||
}
|
||
|
||
if ( bMin )
|
||
{
|
||
AppendPrintf( outstr, sizeof( outstr ), " min. %f", fMin );
|
||
}
|
||
if ( bMax )
|
||
{
|
||
AppendPrintf( outstr, sizeof( outstr ), " max. %f", fMax );
|
||
}
|
||
|
||
// Handle virtualized cvars.
|
||
if ( pBounded && fabs( pBounded->GetFloat() - var->GetFloat() ) > 0.0001f )
|
||
{
|
||
AppendPrintf( outstr, sizeof( outstr ), " [%.3f server clamped to %.3f]",
|
||
var->GetFloat(), pBounded->GetFloat() );
|
||
}
|
||
}
|
||
else
|
||
{
|
||
ConCommand *var = ( ConCommand * )pVar;
|
||
|
||
AppendPrintf( outstr, sizeof( outstr ), "\"%s\" ", var->GetName() );
|
||
}
|
||
|
||
ConVar_AppendFlags( pVar, outstr, sizeof( outstr ) );
|
||
|
||
pStr = pVar->GetHelpText();
|
||
if ( pStr && *pStr )
|
||
{
|
||
ConMsg( "%-80s - %.80s\n", outstr, pStr );
|
||
}
|
||
else
|
||
{
|
||
ConMsg( "%-80s\n", outstr );
|
||
}
|
||
}
|