diff --git a/public/icvar.h b/public/icvar.h index d3ee53af..950cf507 100644 --- a/public/icvar.h +++ b/public/icvar.h @@ -102,8 +102,91 @@ public: #if defined( _X360 ) virtual void PublishToVXConsole( ) = 0; #endif + virtual bool IsMaterialThreadSetAllowed( ) const = 0; + virtual void QueueMaterialThreadSetValue( ConVar *pConVar, const char *pValue ) = 0; + virtual void QueueMaterialThreadSetValue( ConVar *pConVar, int nValue ) = 0; + virtual void QueueMaterialThreadSetValue( ConVar *pConVar, float flValue ) = 0; + virtual bool HasQueuedMaterialThreadConVarSets() const = 0; + virtual int ProcessQueuedMaterialThreadConVarSets() = 0; + +protected: class ICVarIteratorInternal; +public: + /// Iteration over all cvars. + /// (THIS IS A SLOW OPERATION AND YOU SHOULD AVOID IT.) + /// usage: + /// { ICVar::Iterator iter(g_pCVar); + /// for ( iter.SetFirst() ; iter.IsValid() ; iter.Next() ) + /// { + /// ConCommandBase *cmd = iter.Get(); + /// } + /// } + /// The Iterator class actually wraps the internal factory methods + /// so you don't need to worry about new/delete -- scope takes care + // of it. + /// We need an iterator like this because we can't simply return a + /// pointer to the internal data type that contains the cvars -- + /// it's a custom, protected class with unusual semantics and is + /// prone to change. + class Iterator + { + public: + inline Iterator(ICvar *icvar); + inline ~Iterator(void); + inline void SetFirst( void ); + inline void Next( void ); + inline bool IsValid( void ); + inline ConCommandBase *Get( void ); + private: + ICVarIteratorInternal *m_pIter; + }; + +protected: + // internals for ICVarIterator + class ICVarIteratorInternal + { + public: + // warning: delete called on 'ICvar::ICVarIteratorInternal' that is abstract but has non-virtual destructor [-Wdelete-non-virtual-dtor] + virtual ~ICVarIteratorInternal() {} + virtual void SetFirst( void ) = 0; + virtual void Next( void ) = 0; + virtual bool IsValid( void ) = 0; + virtual ConCommandBase *Get( void ) = 0; + }; + + virtual ICVarIteratorInternal *FactoryInternalIterator( void ) = 0; + friend class Iterator; }; +inline ICvar::Iterator::Iterator(ICvar *icvar) +{ + m_pIter = icvar->FactoryInternalIterator(); +} + +inline ICvar::Iterator::~Iterator( void ) +{ + delete m_pIter; +} + +inline void ICvar::Iterator::SetFirst( void ) +{ + m_pIter->SetFirst(); +} + +inline void ICvar::Iterator::Next( void ) +{ + m_pIter->Next(); +} + +inline bool ICvar::Iterator::IsValid( void ) +{ + return m_pIter->IsValid(); +} + +inline ConCommandBase * ICvar::Iterator::Get( void ) +{ + return m_pIter->Get(); +} + #define CVAR_INTERFACE_VERSION "VEngineCvar004" @@ -114,7 +197,7 @@ public: // These are marked DLL_EXPORT for Linux. DLL_EXPORT ICvar *cvar; -DLL_EXPORT ICvar *g_pCVar; +extern ICvar *g_pCVar; #endif // ICVAR_H diff --git a/public/tier1/convar.h b/public/tier1/convar.h index a763c465..7b884e09 100644 --- a/public/tier1/convar.h +++ b/public/tier1/convar.h @@ -66,7 +66,7 @@ void ConVar_PublishToVXConsole(); //----------------------------------------------------------------------------- // Called when a ConCommand needs to execute //----------------------------------------------------------------------------- -typedef void ( *FnCommandCallbackV1_t )( void ); +typedef void ( *FnCommandCallbackVoid_t )( void ); typedef void ( *FnCommandCallback_t )( const CCommand &command ); #define COMMAND_COMPLETION_MAXITEMS 64 @@ -142,7 +142,7 @@ public: virtual CVarDLLIdentifier_t GetDLLIdentifier() const; protected: - virtual void Create( const char *pName, const char *pHelpString = 0, + virtual void CreateBase( const char *pName, const char *pHelpString = 0, int flags = 0 ); // Used internally by OneTimeInit to initialize/shutdown @@ -270,7 +270,7 @@ friend class CCvar; public: typedef ConCommandBase BaseClass; - ConCommand( const char *pName, FnCommandCallbackV1_t callback, + ConCommand( const char *pName, FnCommandCallbackVoid_t callback, const char *pHelpString = 0, int flags = 0, FnCommandCompletionCallback completionFunc = 0 ); ConCommand( const char *pName, FnCommandCallback_t callback, const char *pHelpString = 0, int flags = 0, FnCommandCompletionCallback completionFunc = 0 ); @@ -300,7 +300,7 @@ private: // Call this function when executing the command union { - FnCommandCallbackV1_t m_fnCommandCallbackV1; + FnCommandCallbackVoid_t m_fnCommandCallbackV1; FnCommandCallback_t m_fnCommandCallback; ICommandCallback *m_pCommandCallback; }; @@ -373,6 +373,7 @@ public: bool GetMin( float& minVal ) const; bool GetMax( float& maxVal ) const; const char *GetDefault( void ) const; + void SetDefault( const char *pszDefault ); private: // Called by CCvar when the value of a var is changing. @@ -390,7 +391,7 @@ private: // Used internally by OneTimeInit to initialize. virtual void Init(); - + int GetFlags() { return m_pParent->m_nFlags; } private: // This either points to "this" or it points to the original declaration of a ConVar. diff --git a/public/tier1/iconvar.h b/public/tier1/iconvar.h index 53a7e126..7a276bd0 100644 --- a/public/tier1/iconvar.h +++ b/public/tier1/iconvar.h @@ -62,11 +62,15 @@ class CCommand; #define FCVAR_REPLICATED (1<<13) // server setting enforced on clients, TODO rename to FCAR_SERVER at some time #define FCVAR_DEMO (1<<16) // record this cvar when starting a demo file #define FCVAR_DONTRECORD (1<<17) // don't record these command in demofiles +#define FCVAR_RELOAD_MATERIALS (1<<20) // If this cvar changes, it forces a material reload +#define FCVAR_RELOAD_TEXTURES (1<<21) // If this cvar changes, if forces a texture reload #define FCVAR_NOT_CONNECTED (1<<22) // cvar cannot be changed by a client that is connected to a server - +#define FCVAR_MATERIAL_SYSTEM_THREAD (1<<23) // Indicates this cvar is read from the material system thread #define FCVAR_ARCHIVE_XBOX (1<<24) // cvar written to config.cfg on the Xbox +#define FCVAR_ACCESSIBLE_FROM_THREADS (1<<25) // used as a debugging tool necessary to check material system thread convars + #define FCVAR_SERVER_CAN_EXECUTE (1<<28)// the server is allowed to execute this command on clients via ClientCommand/NET_StringCmd/CBaseClientState::ProcessStringCmd. #define FCVAR_SERVER_CANNOT_QUERY (1<<29)// If this is set, then the server is not allowed to query this cvar's value (via IServerPluginHelpers::StartQueryCvarValue). #define FCVAR_CLIENTCMD_CAN_EXECUTE (1<<30) // IVEngineClient::ClientCmd is allowed to execute this command. @@ -78,11 +82,11 @@ class CCommand; // #define FCVAR_AVAILABLE (1<<20) // #define FCVAR_AVAILABLE (1<<21) // #define FCVAR_AVAILABLE (1<<23) -// #define FCVAR_AVAILABLE (1<<25) // #define FCVAR_AVAILABLE (1<<26) // #define FCVAR_AVAILABLE (1<<27) // #define FCVAR_AVAILABLE (1<<31) +#define FCVAR_MATERIAL_THREAD_MASK ( FCVAR_RELOAD_MATERIALS | FCVAR_RELOAD_TEXTURES | FCVAR_MATERIAL_SYSTEM_THREAD ) //----------------------------------------------------------------------------- // Called when a ConVar changes value diff --git a/public/tier1/tier1.h b/public/tier1/tier1.h index 176e5879..8c70fc78 100644 --- a/public/tier1/tier1.h +++ b/public/tier1/tier1.h @@ -32,7 +32,7 @@ class IProcessUtils; // These are marked DLL_EXPORT for Linux. DLL_EXPORT ICvar *cvar; -DLL_EXPORT ICvar *g_pCVar; +extern ICvar *g_pCVar; extern IProcessUtils *g_pProcessUtils; diff --git a/tier1/convar.cpp b/tier1/convar.cpp index 5b693937..9011dbc7 100644 --- a/tier1/convar.cpp +++ b/tier1/convar.cpp @@ -24,9 +24,10 @@ #endif #include "tier0/memdbgon.h" - +#ifndef NDEBUG // Comment this out when we release. -//#define ALLOW_DEVELOPMENT_CVARS +#define ALLOW_DEVELOPMENT_CVARS +#endif @@ -78,6 +79,7 @@ void ConVar_Register( int nCVarFlag, IConCommandBaseAccessor *pAccessor ) pCur = pNext; } + g_pCVar->ProcessQueuedMaterialThreadConVarSets(); ConCommandBase::s_pConCommandBases = NULL; } @@ -114,7 +116,7 @@ ConCommandBase::ConCommandBase( void ) //----------------------------------------------------------------------------- ConCommandBase::ConCommandBase( const char *pName, const char *pHelpString /*=0*/, int flags /*= 0*/ ) { - Create( pName, pHelpString, flags ); + CreateBase( pName, pHelpString, flags ); } //----------------------------------------------------------------------------- @@ -151,16 +153,14 @@ CVarDLLIdentifier_t ConCommandBase::GetDLLIdentifier() const // *pHelpString - // flags - //----------------------------------------------------------------------------- -void ConCommandBase::Create( const char *pName, const char *pHelpString /*= 0*/, int flags /*= 0*/ ) +void ConCommandBase::CreateBase( const char *pName, const char *pHelpString /*= 0*/, int flags /*= 0*/ ) { - static const char *empty_string = ""; - m_bRegistered = false; // Name should be static data Assert( pName ); m_pszName = pName; - m_pszHelpString = pHelpString ? pHelpString : empty_string; + m_pszHelpString = pHelpString ? pHelpString : ""; m_nFlags = flags; @@ -267,7 +267,7 @@ char *ConCommandBase::CopyString( const char *from ) int len; char *to; - len = strlen( from ); + len = V_strlen( from ); if ( len <= 0 ) { to = new char[1]; @@ -505,7 +505,7 @@ int DefaultCompletionFunc( const char *partial, char commands[ COMMAND_COMPLETIO // m_bIsNewConCommand = true; //} -ConCommand::ConCommand( const char *pName, FnCommandCallbackV1_t callback, const char *pHelpString /*= 0*/, int flags /*= 0*/, FnCommandCompletionCallback completionFunc /*= 0*/ ) +ConCommand::ConCommand( const char *pName, FnCommandCallbackVoid_t callback, const char *pHelpString /*= 0*/, int flags /*= 0*/, FnCommandCompletionCallback completionFunc /*= 0*/ ) { // Set the callback m_fnCommandCallbackV1 = callback; @@ -515,7 +515,7 @@ ConCommand::ConCommand( const char *pName, FnCommandCallbackV1_t callback, const m_bHasCompletionCallback = completionFunc != 0 ? true : false; // Setup the rest - BaseClass::Create( pName, pHelpString, flags ); + BaseClass::CreateBase( pName, pHelpString, flags ); } ConCommand::ConCommand( const char *pName, FnCommandCallback_t callback, const char *pHelpString /*= 0*/, int flags /*= 0*/, FnCommandCompletionCallback completionFunc /*= 0*/ ) @@ -528,7 +528,7 @@ ConCommand::ConCommand( const char *pName, FnCommandCallback_t callback, const c m_bUsingCommandCallbackInterface = false; // Setup the rest - BaseClass::Create( pName, pHelpString, flags ); + BaseClass::CreateBase( pName, pHelpString, flags ); } ConCommand::ConCommand( const char *pName, ICommandCallback *pCallback, const char *pHelpString /*= 0*/, int flags /*= 0*/, ICommandCompletionCallback *pCompletionCallback /*= 0*/ ) @@ -541,7 +541,7 @@ ConCommand::ConCommand( const char *pName, ICommandCallback *pCallback, const ch m_bUsingCommandCallbackInterface = true; // Setup the rest - BaseClass::Create( pName, pHelpString, flags ); + BaseClass::CreateBase( pName, pHelpString, flags ); } //----------------------------------------------------------------------------- @@ -592,7 +592,7 @@ void ConCommand::Dispatch( const CCommand &command ) } // Command without callback!!! - AssertMsg( 0, ( "Encountered ConCommand without a callback!\n" ) ); + AssertMsg( 0, "Encountered ConCommand '%s' without a callback!\n", GetName() ); } @@ -749,6 +749,15 @@ void ConVar::Init() //----------------------------------------------------------------------------- void ConVar::InternalSetValue( const char *value ) { + if ( IsFlagSet( FCVAR_MATERIAL_THREAD_MASK ) ) + { + if ( g_pCVar && !g_pCVar->IsMaterialThreadSetAllowed() ) + { + g_pCVar->QueueMaterialThreadSetValue( this, value ); + return; + } + } + float fNewValue; char tempVal[ 32 ]; char *val; @@ -758,17 +767,20 @@ void ConVar::InternalSetValue( const char *value ) float flOldValue = m_fValue; val = (char *)value; - fNewValue = ( float )atof( value ); + if ( !value ) + fNewValue = 0.0f; + else + fNewValue = ( float )atof( value ); if ( ClampValue( fNewValue ) ) { Q_snprintf( tempVal,sizeof(tempVal), "%f", fNewValue ); val = tempVal; } - + // Redetermine value m_fValue = fNewValue; - m_nValue = ( int )( m_fValue ); + m_nValue = ( int )( fNewValue ); if ( !( m_nFlags & FCVAR_NEVER_AS_STRING ) ) { @@ -787,28 +799,39 @@ void ConVar::ChangeStringValue( const char *tempVal, float flOldValue ) char* pszOldValue = (char*)stackalloc( m_StringLength ); memcpy( pszOldValue, m_pszString, m_StringLength ); - int len = Q_strlen(tempVal) + 1; - - if ( len > m_StringLength) + if ( tempVal ) { - if (m_pszString) + int len = Q_strlen(tempVal) + 1; + + if ( len > m_StringLength) { - delete[] m_pszString; + if (m_pszString) + { + delete[] m_pszString; + } + + m_pszString = new char[len]; + m_StringLength = len; } - m_pszString = new char[len]; - m_StringLength = len; + memcpy( m_pszString, tempVal, len ); } - - memcpy( m_pszString, tempVal, len ); - - // Invoke any necessary callback function - if ( m_fnChangeCallback ) + else { - m_fnChangeCallback( this, pszOldValue, flOldValue ); + *m_pszString = 0; } - g_pCVar->CallGlobalChangeCallbacks( this, pszOldValue, flOldValue ); + // If nothing has changed, don't do the callbacks. + if (V_strcmp(pszOldValue, m_pszString) != 0) + { + // Invoke any necessary callback function + if ( m_fnChangeCallback ) + { + m_fnChangeCallback( this, pszOldValue, flOldValue ); + } + + g_pCVar->CallGlobalChangeCallbacks( this, pszOldValue, flOldValue ); + } stackfree( pszOldValue ); } @@ -844,6 +867,15 @@ void ConVar::InternalSetFloatValue( float fNewValue ) if ( fNewValue == 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 @@ -875,6 +907,15 @@ void ConVar::InternalSetIntValue( int nValue ) if ( nValue == 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; @@ -907,15 +948,12 @@ void ConVar::Create( const char *pName, const char *pDefaultValue, int flags /*= const char *pHelpString /*= NULL*/, bool bMin /*= false*/, float fMin /*= 0.0*/, bool bMax /*= false*/, float fMax /*= false*/, FnChangeCallback_t callback /*= NULL*/ ) { - static const char *empty_string = ""; - m_pParent = this; // Name should be static data - m_pszDefaultValue = pDefaultValue ? pDefaultValue : empty_string; - Assert( m_pszDefaultValue ); + SetDefault( pDefaultValue ); - m_StringLength = strlen( m_pszDefaultValue ) + 1; + m_StringLength = V_strlen( m_pszDefaultValue ) + 1; m_pszString = new char[m_StringLength]; memcpy( m_pszString, m_pszDefaultValue, m_StringLength ); @@ -927,6 +965,7 @@ void ConVar::Create( const char *pName, const char *pDefaultValue, int flags /*= m_fnChangeCallback = callback; m_fValue = ( float )atof( m_pszString ); + m_nValue = atoi( m_pszString ); // dont convert from float to int and lose bits // Bounds Check, should never happen, if it does, no big deal if ( m_bHasMin && ( m_fValue < m_fMinVal ) ) @@ -939,9 +978,7 @@ void ConVar::Create( const char *pName, const char *pDefaultValue, int flags /*= Assert( 0 ); } - m_nValue = ( int )m_fValue; - - BaseClass::Create( pName, pHelpString, flags ); + BaseClass::CreateBase( pName, pHelpString, flags ); } //----------------------------------------------------------------------------- @@ -1014,6 +1051,11 @@ const char *ConVar::GetDefault( void ) const return m_pParent->m_pszDefaultValue; } +void ConVar::SetDefault( const char *pszDefault ) +{ + m_pszDefaultValue = pszDefault ? pszDefault : ""; + Assert( m_pszDefaultValue ); +} //----------------------------------------------------------------------------- // This version is simply used to make reading convars simpler.