diff --git a/public/icvar.h b/public/icvar.h index acd9dbdf..f449922e 100644 --- a/public/icvar.h +++ b/public/icvar.h @@ -74,6 +74,8 @@ public: virtual void CallChangeCallback( ConVarRef cvar, const CSplitScreenSlot nSlot, const CVValue_t* pNewValue, const CVValue_t* pOldValue, void *__unk01 = nullptr ) = 0; // Would call cb for every change callback defined for this cvar virtual void IterateConVarCallbacks( ConVarRef cvar, FnCvarCallbacksReader_t cb ) = 0; + // If returns false value shouldn't be modified + virtual bool CallFilterCallback( ConVarRef cvar, const CSplitScreenSlot nSlot, const CVValue_t *pNewValue, const CVValue_t *pOldValue, void *__unk01 = nullptr ) = 0; // allow_defensive - Allows finding commands with FCVAR_DEFENSIVE flag virtual ConCommandRef FindConCommand( const char *name, bool allow_defensive = false ) = 0; @@ -198,7 +200,7 @@ public: return base; } - struct CConVarChangeCallbackNode_t + struct ConVarChangeCallbackData_t { FnGenericChangeCallbackProvider_t m_pProviderCallBack; FnGenericChangeCallback_t m_pCallback; @@ -207,6 +209,15 @@ public: int m_ConVarIndex; }; + struct ConVarFilterCallbackData_t + { + FnGenericFilterCallbackProvider_t m_pProviderCallBack; + FnGenericFilterCallback_t m_pCallback; + + // Register index of cvar which change cb comes from + int m_ConVarIndex; + }; + struct ConCommandCallbackInfoNode_t { ConCommandCallbackInfo_t m_CB; @@ -232,7 +243,8 @@ public: CUtlLinkedList m_ConVarList; CUtlHashtable m_ConVarHashes; - CUtlLinkedList m_ConVarChangeCBList; + CUtlLinkedList m_ConVarChangeCBList; + CUtlLinkedList m_ConVarFilterCBList; int m_ConVarCount; CUtlVector m_CvarCreationListeners; diff --git a/public/tier1/convar.h b/public/tier1/convar.h index e5724d1f..bf0958bd 100644 --- a/public/tier1/convar.h +++ b/public/tier1/convar.h @@ -618,6 +618,14 @@ using FnTypedChangeCallbackProvider_t = void(*)(CConVar *cvar, CSplitScreenSl using FnGenericChangeCallback_t = void(*)(ConVarRefAbstract *ref, CSplitScreenSlot nSlot, const CVValue_t *pNewValue, const CVValue_t *pOldValue); using FnGenericChangeCallbackProvider_t = void(*)(ConVarRefAbstract *ref, CSplitScreenSlot nSlot, const CVValue_t *pNewValue, const CVValue_t *pOldValue, void *__unk01, FnGenericChangeCallback_t cb); +template +using FnTypedFilterCallback_t = void (*)(CConVar *cvar, CSplitScreenSlot nSlot, const T *pNewValue, const T *pOldValue); +template +using FnTypedFilterCallbackProvider_t = void(*)(CConVar *cvar, CSplitScreenSlot slot, const T *pNewValue, const T *pOldValue, void *__unk01, FnTypedFilterCallback_t cb); + +using FnGenericFilterCallback_t = bool(*)(ConVarRefAbstract *ref, CSplitScreenSlot nSlot, const CVValue_t *pNewValue, const CVValue_t *pOldValue); +using FnGenericFilterCallbackProvider_t = bool(*)(ConVarRefAbstract *ref, CSplitScreenSlot nSlot, const CVValue_t *pNewValue, const CVValue_t *pOldValue, void *__unk01, FnGenericFilterCallback_t cb); + struct ConVarValueInfo_t { ConVarValueInfo_t( EConVarType type = EConVarType_Invalid ) : @@ -630,6 +638,8 @@ struct ConVarValueInfo_t m_maxValue {}, m_fnProviderCallBack( nullptr ), m_fnCallBack( nullptr ), + m_fnProviderFilterCallBack( nullptr ), + m_fnFilterCallBack( nullptr ), m_eVarType( type ) {} @@ -667,6 +677,19 @@ struct ConVarValueInfo_t } } + template + void SetFilterCallback( FnTypedFilterCallback_t cb ) + { + if(cb) + { + m_fnProviderFilterCallBack = []( ConVarRefAbstract *ref, CSplitScreenSlot nSlot, const CVValue_t *pNewValue, const CVValue_t *pOldValue, void *__unk01, FnGenericFilterCallback_t cb ) { + return reinterpret_cast>(cb)(reinterpret_cast *>(ref), nSlot, reinterpret_cast(pNewValue), reinterpret_cast(pOldValue)); + }; + + m_fnFilterCallBack = reinterpret_cast(cb); + } + } + int32 m_Version; bool m_bHasDefault; @@ -683,6 +706,9 @@ public: FnGenericChangeCallbackProvider_t m_fnProviderCallBack; FnGenericChangeCallback_t m_fnCallBack; + FnGenericFilterCallbackProvider_t m_fnProviderFilterCallBack; + FnGenericFilterCallback_t m_fnFilterCallBack; + EConVarType m_eVarType; }; @@ -861,6 +887,7 @@ public: m_iTimesChanged = 0; m_nFlags = FCVAR_REFERENCE; m_iCallbackIndex = 0; + m_iFilterCBIndex = 0; m_GameInfoFlags = 0; } @@ -969,6 +996,8 @@ private: // Index into a linked list of cvar callbacks unsigned int m_iCallbackIndex; + // Index into a linked list of cvar filter callbacks + unsigned int m_iFilterCBIndex; int m_GameInfoFlags; int m_UserInfoByteIndex; @@ -1273,6 +1302,28 @@ public: BaseClass::Register( name, flags, help_string, value_info ); } + CConVar( const char *name, uint64 flags, const char *help_string, const T &default_value, bool min, const T &minValue, bool max, const T &maxValue, FnTypedChangeCallback_t cb = nullptr, FnTypedFilterCallback_t filter_cb = nullptr ) + : BaseClass() + { + Assert( name ); + + BaseClass::Init( ConVarRef(), TranslateConVarType() ); + + ConVarValueInfo_t value_info( TranslateConVarType() ); + value_info.SetDefaultValue( default_value ); + + if(min) + value_info.SetMinValue( minValue ); + + if(max) + value_info.SetMaxValue( maxValue ); + + value_info.SetCallback( cb ); + value_info.SetFilterCallback( filter_cb ); + + BaseClass::Register( name, flags, help_string, value_info ); + } + ~CConVar() { UnRegisterConVar( this ); diff --git a/tier1/convar.cpp b/tier1/convar.cpp index afbfce07..caf64841 100644 --- a/tier1/convar.cpp +++ b/tier1/convar.cpp @@ -599,24 +599,27 @@ void ConVarRefAbstract::SetValueInternal( CSplitScreenSlot slot, CVValue_t *valu CVValue_t prev; TypeTraits()->Construct( &prev ); - TypeTraits()->Copy( &prev, *curr_value ); - TypeTraits()->Destruct( curr_value ); - TypeTraits()->Construct( curr_value ); - TypeTraits()->Copy( curr_value, *value ); - m_ConVarData->Clamp( slot ); - - if(!m_ConVarData->IsEqual( slot, &prev )) + if(g_pCVar->CallFilterCallback( *this, slot, value, &prev )) { - CBufferString prev_str, new_str; + TypeTraits()->Destruct( curr_value ); - TypeTraits()->ValueToString( &prev, prev_str ); - TypeTraits()->ValueToString( curr_value, new_str ); + TypeTraits()->Construct( curr_value ); + TypeTraits()->Copy( curr_value, *value ); + m_ConVarData->Clamp( slot ); - m_ConVarData->IncrementTimesChanged(); + if(!m_ConVarData->IsEqual( slot, &prev )) + { + CBufferString prev_str, new_str; - CallChangeCallbacks( slot, curr_value, &prev, new_str.Get(), prev_str.Get() ); + TypeTraits()->ValueToString( &prev, prev_str ); + TypeTraits()->ValueToString( curr_value, new_str ); + + m_ConVarData->IncrementTimesChanged(); + + CallChangeCallbacks( slot, curr_value, &prev, new_str.Get(), prev_str.Get() ); + } } TypeTraits()->Destruct( &prev );