diff --git a/r5dev/core/init.cpp b/r5dev/core/init.cpp index bac2e2ac..3e843127 100644 --- a/r5dev/core/init.cpp +++ b/r5dev/core/init.cpp @@ -448,7 +448,7 @@ void DetourRegister() // Register detour classes to be searched and hooked. // Tier1 REGISTER(VCommandLine); - REGISTER(VConCommand); + REGISTER(VConVar); REGISTER(VCVar); // VPC diff --git a/r5dev/public/iconcommand.h b/r5dev/public/iconcommand.h index 6181c373..af3bcb78 100644 --- a/r5dev/public/iconcommand.h +++ b/r5dev/public/iconcommand.h @@ -2,6 +2,24 @@ #define ICONCOMMAND_H #include "icvar.h" +//----------------------------------------------------------------------------- +// Forward declarations +//----------------------------------------------------------------------------- +class ConCommandBase; +class CCommand; + +//----------------------------------------------------------------------------- +// Any executable that wants to use ConVars need to implement one of +// these to hook up access to console variables. +//----------------------------------------------------------------------------- +abstract_class IConCommandBaseAccessor +{ +public: + // Flags is a combination of FCVAR flags in cvar.h. + // hOut is filled in with a handle to the variable. + virtual bool RegisterConCommandBase(ConCommandBase* pVar) = 0; +}; + //----------------------------------------------------------------------------- // Abstract interface for ConVars //----------------------------------------------------------------------------- diff --git a/r5dev/public/icvar.h b/r5dev/public/icvar.h index 76b1bd23..c40ff880 100644 --- a/r5dev/public/icvar.h +++ b/r5dev/public/icvar.h @@ -1,6 +1,7 @@ #ifndef ICVAR_H #define ICVAR_H #include "tier0/annotations.h" +#include "iconvar.h" #include "appframework/IAppSystem.h" //----------------------------------------------------------------------------- diff --git a/r5dev/public/tier1/cmd.h b/r5dev/public/tier1/cmd.h index cd35ff6c..9b9eff5b 100644 --- a/r5dev/public/tier1/cmd.h +++ b/r5dev/public/tier1/cmd.h @@ -12,29 +12,7 @@ #ifndef TIER1_CMD_H #define TIER1_CMD_H -#include "tier1/utlvector.h" -#include "tier1/utlstring.h" #include "tier1/characterset.h" -#include "public/iconvar.h" -#include "public/iconcommand.h" -#include "mathlib/color.h" - -//----------------------------------------------------------------------------- -// Forward declarations -//----------------------------------------------------------------------------- -class ConCommandBase; - -//----------------------------------------------------------------------------- -// Any executable that wants to use ConVars need to implement one of -// these to hook up access to console variables. -//----------------------------------------------------------------------------- -class IConCommandBaseAccessor -{ -public: - // Flags is a combination of FCVAR flags in cvar.h. - // hOut is filled in with a handle to the variable. - virtual bool RegisterConCommandBase(ConCommandBase* pVar) = 0; -}; //----------------------------------------------------------------------------- // Purpose: Command buffer context @@ -77,7 +55,7 @@ private: public: CCommand(); CCommand(int nArgC, const char** ppArgV, cmd_source_t source); - bool Tokenize(const char* pCommand, cmd_source_t source, characterset_t* pBreakSet = nullptr); + bool Tokenize(const char* pCommand, cmd_source_t source = cmd_source_t::kCommandSrcCode, characterset_t* pBreakSet = nullptr); int64_t ArgC(void) const; const char** ArgV(void) const; @@ -99,135 +77,4 @@ private: const char* m_ppArgv[COMMAND_MAX_ARGC]; }; -//----------------------------------------------------------------------------- -// Purpose: The base console invoked command/cvar interface -//----------------------------------------------------------------------------- -class ConCommandBase -{ -public: - virtual ~ConCommandBase(void) { }; - - virtual bool IsCommand(void) const = 0; - virtual bool IsFlagSet(int nFlags) const = 0; - - virtual void AddFlags(int nFlags) = 0; - virtual void RemoveFlags(int nFlags) = 0; - - virtual int GetFlags(void) const = 0; - virtual const char* GetName(void) const = 0; - virtual const char* GetHelpText(void) const = 0; - virtual const char* GetUsageText(void) const = 0; - - virtual void SetAccessor(IConCommandBaseAccessor* pAccessor) = 0; - virtual bool IsRegistered(void) const = 0; - - virtual int GetDLLIdentifier() const = 0; - virtual ConCommandBase* Create (const char* szName, const char* szHelpString, - int nFlags, const char* pszUsageString) = 0; - - virtual void Init() = 0; - - bool HasFlags(int nFlags) const; - - ConCommandBase* GetNext(void) const; - char* CopyString(const char* szFrom) const; - - ConCommandBase* m_pNext; //0x0008 - bool m_bRegistered; //0x0010 - const char* m_pszName; //0x0018 - const char* m_pszHelpString; //0x0020 - const char* m_pszUsageString; //0x0028 - IConCommandBaseAccessor* s_pAccessor; //0x0030 <-- unused since executable is monolithic. - int m_nFlags; //0x0038 -}; //Size: 0x0040 -static_assert(sizeof(ConCommandBase) == 0x40); - -//----------------------------------------------------------------------------- -// Purpose: The console invoked command -//----------------------------------------------------------------------------- -class ConCommand : public ConCommandBase -{ - friend class CCvar; -public: - ConCommand(void); - - static ConCommand* StaticCreate(const char* szName, const char* szHelpString, const char* pszUsageString, - int nFlags, FnCommandCallback_t pCallback, FnCommandCompletionCallback pCommandCompletionCallback); - - virtual int AutoCompleteSuggest(const char* partial, CUtlVector< CUtlString >& commands) = 0; - virtual bool CanAutoComplete(void) const = 0; - - void* m_nNullCallBack; //0x0040 - void* m_pSubCallback; //0x0048 - // Call this function when executing the command - union - { - FnCommandCallbackV1_t m_fnCommandCallbackV1; - FnCommandCallback_t m_fnCommandCallback; - ICommandCallback* m_pCommandCallback; - }; - - union - { - FnCommandCompletionCallback m_fnCompletionCallback; - ICommandCompletionCallback* m_pCommandCompletionCallback; - }; - - bool m_bHasCompletionCallback : 1; - bool m_bUsingNewCommandCallback : 1; - bool m_bUsingCommandCallbackInterface : 1; -}; - -/* ==== CONCOMMAND ====================================================================================================================================================== */ -inline CMemory p_ConCommand_AutoCompleteSuggest; -inline bool(*ConCommand_AutoCompleteSuggest)(ConCommand* pCommand, const char* partial, CUtlVector< CUtlString >& commands); - -inline CMemory p_ConCommandBase_IsFlagSet; -inline bool(*ConCommandBase_IsFlagSet)(ConCommandBase* pCommand, int nFlag); - -inline CMemory p_NullSub; -inline void(*NullSub)(void); - -inline CMemory p_CallbackStub; -inline FnCommandCompletionCallback CallbackStub; - -inline ConCommandBase* g_pConCommandVFTable; - -/////////////////////////////////////////////////////////////////////////////// -ECommandTarget_t Cbuf_GetCurrentPlayer(void); - -/////////////////////////////////////////////////////////////////////////////// -class VConCommand : public IDetour -{ - virtual void GetAdr(void) const - { - LogFunAdr("ConCommandBase::IsFlagSet", p_ConCommandBase_IsFlagSet.GetPtr()); - LogFunAdr("ConCommand::AutoCompleteSuggest", p_ConCommand_AutoCompleteSuggest.GetPtr()); - LogFunAdr("CallbackStub", p_CallbackStub.GetPtr()); - LogFunAdr("NullSub", p_NullSub.GetPtr()); - } - virtual void GetFun(void) const - { - p_ConCommand_AutoCompleteSuggest = g_GameDll.FindPatternSIMD("40 ?? B8 ?? ?? ?? ?? E8 ?? ?? ?? ?? 48 2B E0 F6 41 60 04"); - p_ConCommandBase_IsFlagSet = g_GameDll.FindPatternSIMD("85 51 38 0F 95 C0 C3"); - - p_NullSub = g_GameDll.FindPatternSIMD("C2 ?? ?? CC CC CC CC CC CC CC CC CC CC CC CC CC 40 53 48 83 EC 20 48 8D 05 ?? ?? ?? ??"); - p_CallbackStub = g_GameDll.FindPatternSIMD("33 C0 C3 CC CC CC CC CC CC CC CC CC CC CC CC CC 80 49 68 08"); - - ConCommandBase_IsFlagSet = p_ConCommandBase_IsFlagSet.RCast(); /*85 51 38 0F 95 C0 C3*/ - ConCommand_AutoCompleteSuggest = p_ConCommand_AutoCompleteSuggest.RCast&)>(); - - NullSub = p_NullSub.RCast(); /*C2 00 00 CC CC CC CC CC CC CC CC CC CC CC CC CC 40 53 48 83 EC 20 48 8D 05 ?? ?? ?? ??*/ - CallbackStub = p_CallbackStub.RCast(); /*33 C0 C3 CC CC CC CC CC CC CC CC CC CC CC CC CC 80 49 68 08*/ /*UserMathErrorFunction*/ - } - virtual void GetVar(void) const { } - virtual void GetCon(void) const - { - g_pConCommandVFTable = g_GameDll.GetVirtualMethodTable(".?AVConCommand@@").RCast(); - } - virtual void Attach(void) const { }; - virtual void Detach(void) const { }; -}; -/////////////////////////////////////////////////////////////////////////////// - #endif // TIER1_CMD_H diff --git a/r5dev/public/tier1/convar.h b/r5dev/public/tier1/convar.h new file mode 100644 index 00000000..34a26775 --- /dev/null +++ b/r5dev/public/tier1/convar.h @@ -0,0 +1,302 @@ +//===== Copyright � 1996-2005, Valve Corporation, All rights reserved. ======// +// +// Purpose: +// +// $Workfile: $ +// $Date: $ +// +//----------------------------------------------------------------------------- +// $NoKeywords: $ +//===========================================================================// + +#ifndef CONVAR_H +#define CONVAR_H + +#include "mathlib/color.h" +#include "public/iconvar.h" +#include "public/iconcommand.h" +#include "tier1/utlvector.h" +#include "tier1/utlstring.h" + +//----------------------------------------------------------------------------- +// Purpose: The base console invoked command/cvar interface +//----------------------------------------------------------------------------- +class ConCommandBase +{ +public: + virtual ~ConCommandBase(void) { }; + + virtual bool IsCommand(void) const = 0; + virtual bool IsFlagSet(int nFlags) const = 0; + + virtual void AddFlags(int nFlags) = 0; + virtual void RemoveFlags(int nFlags) = 0; + + virtual int GetFlags(void) const = 0; + virtual const char* GetName(void) const = 0; + virtual const char* GetHelpText(void) const = 0; + virtual const char* GetUsageText(void) const = 0; + + virtual void SetAccessor(IConCommandBaseAccessor* pAccessor) = 0; + virtual bool IsRegistered(void) const = 0; + + virtual int GetDLLIdentifier() const = 0; + virtual ConCommandBase* Create(const char* szName, const char* szHelpString, + int nFlags, const char* pszUsageString) = 0; + + virtual void Init() = 0; + + bool HasFlags(int nFlags) const; + + ConCommandBase* GetNext(void) const; + char* CopyString(const char* szFrom) const; + + ConCommandBase* m_pNext; //0x0008 + bool m_bRegistered; //0x0010 + const char* m_pszName; //0x0018 + const char* m_pszHelpString; //0x0020 + const char* m_pszUsageString; //0x0028 + IConCommandBaseAccessor* s_pAccessor; //0x0030 <-- unused since executable is monolithic. + int m_nFlags; //0x0038 +}; +static_assert(sizeof(ConCommandBase) == 0x40); + +/////////////////////////////////////////////////////////////////////////////// + +//----------------------------------------------------------------------------- +// Purpose: The console invoked command +//----------------------------------------------------------------------------- +class ConCommand : public ConCommandBase +{ + friend class CCvar; +public: + ConCommand(void); + + static ConCommand* StaticCreate(const char* szName, const char* szHelpString, const char* pszUsageString, + int nFlags, FnCommandCallback_t pCallback, FnCommandCompletionCallback pCommandCompletionCallback); + + virtual int AutoCompleteSuggest(const char* partial, CUtlVector< CUtlString >& commands) = 0; + virtual bool CanAutoComplete(void) const = 0; + + void* m_nNullCallBack; //0x0040 + void* m_pSubCallback; //0x0048 + // Call this function when executing the command + union + { + FnCommandCallbackV1_t m_fnCommandCallbackV1; + FnCommandCallback_t m_fnCommandCallback; + ICommandCallback* m_pCommandCallback; + }; + + union + { + FnCommandCompletionCallback m_fnCompletionCallback; + ICommandCompletionCallback* m_pCommandCompletionCallback; + }; + + bool m_bHasCompletionCallback : 1; + bool m_bUsingNewCommandCallback : 1; + bool m_bUsingCommandCallbackInterface : 1; +}; +static_assert(sizeof(ConCommand) == 0x68); + +/////////////////////////////////////////////////////////////////////////////// + +//----------------------------------------------------------------------------- +// Purpose: A console variable +//----------------------------------------------------------------------------- +class ConVar : public ConCommandBase, public IConVar +{ + friend class CCvar; + friend class ConVarRef; + +public: + static ConVar* StaticCreate(const char* pszName, const char* pszDefaultValue, int nFlags, const char* pszHelpString, + bool bMin, float fMin, bool bMax, float fMax, FnChangeCallback_t pCallback, const char* pszUsageString); + void Destroy(void); + + ConVar(void); + virtual ~ConVar(void) { }; + + FORCEINLINE bool GetBool(void) const; + FORCEINLINE float GetFloat(void) const; + FORCEINLINE double GetDouble(void) const; + FORCEINLINE int GetInt(void) const; + FORCEINLINE Color GetColor(void) const; + FORCEINLINE const char* GetString(void) const; + + void SetMax(float flMaxValue); + void SetMin(float flMinValue); + bool GetMin(float& flMinValue) const; + bool GetMax(float& flMaxValue) const; + float GetMinValue(void) const; + float GetMaxValue(void) const; + bool HasMin(void) const; + bool HasMax(void) const; + + void SetValue(int nValue); + void SetValue(float flValue); + void SetValue(const char* pszValue); + void SetValue(Color clValue); + + virtual void InternalSetValue(const char* pszValue) = 0; + virtual void InternalSetFloatValue(float flValue) = 0; + virtual void InternalSetIntValue(int nValue) = 0; + void InternalSetColorValue(Color value); + + virtual __int64 Unknown0(unsigned int a2) = 0; + virtual __int64 Unknown1(const char* a2) = 0; + + void Revert(void); + virtual bool ClampValue(float& flValue) = 0; + + const char* GetDefault(void) const; + void SetDefault(const char* pszDefault); + bool SetColorFromString(const char* pszValue); + + virtual void ChangeStringValue(const char* pszTempValue) = 0; + virtual void CreateInternal(const char* pszName, const char* pszDefaultValue, int nFlags, const char* pszHelpString, + bool bMin, float fMin, bool bMax, float fMax, FnChangeCallback_t pCallback, const char* pszUsageString) = 0; + + void InstallChangeCallback(FnChangeCallback_t callback, bool bInvoke); + void RemoveChangeCallback(FnChangeCallback_t callback); + + struct CVValue_t + { + char* m_pszString; + size_t m_iStringLength; + float m_fValue; + int m_nValue; + }; + + ConVar* m_pParent; //0x0048 + const char* m_pszDefaultValue; //0x0050 + CVValue_t m_Value; //0c0058 + bool m_bHasMin; //0x0070 + float m_fMinVal; //0x0074 + bool m_bHasMax; //0x0078 + float m_fMaxVal; //0x007C + CUtlVector m_fnChangeCallbacks; //0x0080 +}; +static_assert(sizeof(ConVar) == 0xA0); + +/////////////////////////////////////////////////////////////////////////////// + +//----------------------------------------------------------------------------- +// Purpose: Return ConVar value as a boolean. +// Output : bool +//----------------------------------------------------------------------------- +FORCEINLINE bool ConVar::GetBool(void) const +{ + return !!GetInt(); +} + +//----------------------------------------------------------------------------- +// Purpose: Return ConVar value as a float. +// Output : float +//----------------------------------------------------------------------------- +FORCEINLINE float ConVar::GetFloat(void) const +{ + return m_pParent->m_Value.m_fValue; +} + +//----------------------------------------------------------------------------- +// Purpose: Return ConVar value as a double. +// Output : double +//----------------------------------------------------------------------------- +FORCEINLINE double ConVar::GetDouble(void) const +{ + return static_cast(m_pParent->m_Value.m_fValue); +} + +//----------------------------------------------------------------------------- +// Purpose: Return ConVar value as an integer. +// Output : int +//----------------------------------------------------------------------------- +FORCEINLINE int ConVar::GetInt(void) const +{ + return m_pParent->m_Value.m_nValue; +} + +//----------------------------------------------------------------------------- +// Purpose: Return ConVar value as a color. +// Output : Color +//----------------------------------------------------------------------------- +FORCEINLINE Color ConVar::GetColor(void) const +{ + unsigned char* pColorElement = (reinterpret_cast(&m_pParent->m_Value.m_nValue)); + return Color(pColorElement[0], pColorElement[1], pColorElement[2], pColorElement[3]); +} + +//----------------------------------------------------------------------------- +// Purpose: Return ConVar value as a string. +// Output : const char * +//----------------------------------------------------------------------------- +FORCEINLINE const char* ConVar::GetString(void) const +{ + if (m_nFlags & FCVAR_NEVER_AS_STRING) + { + return "FCVAR_NEVER_AS_STRING"; + } + + char const* str = m_pParent->m_Value.m_pszString; + return str ? str : ""; +} + +/* ==== CONVAR ========================================================================================================================================================== */ +inline CMemory p_ConVar_Register; +inline void*(*v_ConVar_Register)(ConVar* thisptr, const char* szName, const char* szDefaultValue, int nFlags, const char* szHelpString, bool bMin, float fMin, bool bMax, float fMax, FnChangeCallback_t pCallback, const char* pszUsageString); + +inline CMemory p_ConVar_Unregister; +inline void(*v_ConVar_Unregister)(ConVar* thisptr); + +inline CMemory p_ConVar_IsFlagSet; +inline bool(*v_ConVar_IsFlagSet)(ConVar* pConVar, int nFlag); + +inline ConCommandBase* g_pConCommandBaseVFTable; +inline ConCommand* g_pConCommandVFTable; +inline ConVar* g_pConVarVBTable; +inline IConVar* g_pConVarVFTable; + +/////////////////////////////////////////////////////////////////////////////// +class VConVar : public IDetour +{ + virtual void GetAdr(void) const + { + LogConAdr("ConCommandBase::`vftable'", reinterpret_cast(g_pConCommandBaseVFTable)); + LogConAdr("ConCommand::`vftable'", reinterpret_cast(g_pConCommandVFTable)); + LogConAdr("ConVar::`vbtable'", reinterpret_cast(g_pConVarVBTable)); + LogConAdr("ConVar::`vftable'", reinterpret_cast(g_pConVarVFTable)); + LogFunAdr("ConVar::Register", p_ConVar_Register.GetPtr()); + LogFunAdr("ConVar::Unregister", p_ConVar_Unregister.GetPtr()); + LogFunAdr("ConVar::IsFlagSet", p_ConVar_IsFlagSet.GetPtr()); + } + virtual void GetFun(void) const + { +#if defined (GAMEDLL_S0) || defined (GAMEDLL_S1) + p_ConVar_Register = g_GameDll.FindPatternSIMD("48 89 5C 24 ?? 48 89 6C 24 ?? 48 89 74 24 ?? 48 89 7C 24 ?? 41 56 48 83 EC 30 F3 0F 10 44 24 ??"); + p_ConVar_Unregister = g_GameDll.FindPatternSIMD("48 89 5C 24 ?? 57 48 83 EC 20 48 8B 59 58 48 8D 05 ?? ?? ?? ??"); +#elif defined (GAMEDLL_S2) || defined (GAMEDLL_S3) + p_ConVar_Register = g_GameDll.FindPatternSIMD("48 89 5C 24 ?? 48 89 6C 24 ?? 48 89 74 24 ?? 57 48 83 EC 40 F3 0F 10 84 24 ?? ?? ?? ??"); + p_ConVar_Unregister = g_GameDll.FindPatternSIMD("48 89 5C 24 ?? 48 89 74 24 ?? 57 48 83 EC 20 48 8B 79 58"); +#endif + p_ConVar_IsFlagSet = g_GameDll.FindPatternSIMD("48 8B 41 48 85 50 38"); + + v_ConVar_IsFlagSet = p_ConVar_IsFlagSet.RCast(); + v_ConVar_Register = p_ConVar_Register.RCast(); + v_ConVar_Unregister = p_ConVar_Unregister.RCast(); + } + virtual void GetVar(void) const { } + virtual void GetCon(void) const + { + g_pConCommandBaseVFTable = g_GameDll.GetVirtualMethodTable(".?AVConCommandBase@@").RCast(); + g_pConCommandVFTable = g_GameDll.GetVirtualMethodTable(".?AVConCommand@@").RCast(); + g_pConVarVBTable = g_GameDll.GetVirtualMethodTable(".?AVConVar@@", 0).RCast(); + g_pConVarVFTable = g_GameDll.GetVirtualMethodTable(".?AVConVar@@", 1).RCast(); + } + virtual void Attach(void) const { } + virtual void Detach(void) const { } +}; +/////////////////////////////////////////////////////////////////////////////// + +#endif // CONVAR_H diff --git a/r5dev/public/tier1/cvar.h b/r5dev/public/tier1/cvar.h index 79a05bf1..22d67a5e 100644 --- a/r5dev/public/tier1/cvar.h +++ b/r5dev/public/tier1/cvar.h @@ -13,11 +13,80 @@ #define CVAR_H #include "vstdlib/concommandhash.h" +#include "public/icvar.h" +#include "public/iconvar.h" #include "tier1/utlmap.h" +#include "tier1/utlvector.h" +#include "tier1/utlstring.h" -/* ==== CCVAR =========================================================================================================================================================== */ //----------------------------------------------------------------------------- -// Purpose: +// Forward declarations +//----------------------------------------------------------------------------- +class ConCommandBase; + +//----------------------------------------------------------------------------- +// Purpose: Interface to ConVars/ConCommands +//----------------------------------------------------------------------------- +class CCvar : public CBaseAppSystem< ICvar > +{ // Implementation in engine. +protected: + enum ConVarSetType_t + { + CONVAR_SET_STRING = 0, + CONVAR_SET_INT, + CONVAR_SET_FLOAT, + }; + + struct QueuedConVarSet_t + { + ConVar* m_pConVar; + ConVarSetType_t m_nType; + int m_nInt; + float m_flFloat; + CUtlString m_String; + }; + + class CCVarIteratorInternal : public ICVarIteratorInternal + { + public: + + virtual void SetFirst(void) = 0; + virtual void Next(void) = 0; + virtual bool IsValid(void) = 0; + virtual ConCommandBase* Get(void) = 0; + + virtual ~CCVarIteratorInternal() { } + + CCvar* const m_pOuter = nullptr; + CConCommandHash* const m_pHash = nullptr; + CConCommandHash::CCommandHashIterator_t m_hashIter; + }; + + virtual CCVarIteratorInternal* FactoryInternalIterator(void) = 0; + + friend class CCVarIteratorInternal; + friend class CCvarUtilities; + +private: + CUtlVector< FnChangeCallback_t > m_GlobalChangeCallbacks; + char pad0[30]; //!TODO: + int m_nNextDLLIdentifier; + ConCommandBase* m_pConCommandList; + CConCommandHash m_CommandHash; + CUtlVector m_Unknown; + char pad2[32]; + void* m_pCallbackStub; + void* m_pAllocFunc; + char pad3[16]; + CUtlVector< QueuedConVarSet_t > m_QueuedConVarSets; + bool m_bMaterialSystemThreadSetAllowed; +}; + +extern CCvar* g_pCVar; +/////////////////////////////////////////////////////////////////////////////// + +//----------------------------------------------------------------------------- +// Purpose: ConVar tools //----------------------------------------------------------------------------- class CCvarUtilities { @@ -63,204 +132,7 @@ private: }; extern CCvarUtilities* cv; - -class CCvar : public CBaseAppSystem< ICvar > -{ // Implementation in engine. -protected: - enum ConVarSetType_t - { - CONVAR_SET_STRING = 0, - CONVAR_SET_INT, - CONVAR_SET_FLOAT, - }; - - struct QueuedConVarSet_t - { - ConVar* m_pConVar; - ConVarSetType_t m_nType; - int m_nInt; - float m_flFloat; - CUtlString m_String; - }; - - class CCVarIteratorInternal : public ICVarIteratorInternal - { - public: - - virtual void SetFirst(void) = 0; - virtual void Next(void) = 0; - virtual bool IsValid(void) = 0; - virtual ConCommandBase* Get(void) = 0; - - virtual ~CCVarIteratorInternal() { } - - CCvar* const m_pOuter = nullptr; - CConCommandHash* const m_pHash = nullptr; - CConCommandHash::CCommandHashIterator_t m_hashIter; - }; - - virtual CCVarIteratorInternal* FactoryInternalIterator(void) = 0; - - friend class CCVarIteratorInternal; - friend class CCvarUtilities; - -private: - CUtlVector< FnChangeCallback_t > m_GlobalChangeCallbacks; - char pad0[30]; //!TODO: - int m_nNextDLLIdentifier; - ConCommandBase* m_pConCommandList; - CConCommandHash m_CommandHash; - CUtlVector m_Unknown; - char pad2[32]; - void* m_pCallbackStub; - void* m_pAllocFunc; - char pad3[16]; - CUtlVector< QueuedConVarSet_t > m_QueuedConVarSets; - bool m_bMaterialSystemThreadSetAllowed; -}; - /////////////////////////////////////////////////////////////////////////////// -extern CCvar* g_pCVar; - -/* ==== CONVAR ========================================================================================================================================================== */ -//----------------------------------------------------------------------------- -// Purpose: A console variable -//----------------------------------------------------------------------------- -class ConVar : public ConCommandBase, public IConVar -{ - friend class CCvar; - friend class ConVarRef; - -public: - static ConVar* StaticCreate(const char* pszName, const char* pszDefaultValue, int nFlags, const char* pszHelpString, - bool bMin, float fMin, bool bMax, float fMax, FnChangeCallback_t pCallback, const char* pszUsageString); - void Destroy(void); - - ConVar(void); - virtual ~ConVar(void) { }; - - FORCEINLINE bool GetBool(void) const; - FORCEINLINE float GetFloat(void) const; - FORCEINLINE double GetDouble(void) const; - FORCEINLINE int GetInt(void) const; - FORCEINLINE Color GetColor(void) const; - FORCEINLINE const char* GetString(void) const; - - void SetMax(float flMaxValue); - void SetMin(float flMinValue); - bool GetMin(float& flMinValue) const; - bool GetMax(float& flMaxValue) const; - float GetMinValue(void) const; - float GetMaxValue(void) const; - bool HasMin(void) const; - bool HasMax(void) const; - - void SetValue(int nValue); - void SetValue(float flValue); - void SetValue(const char* pszValue); - void SetValue(Color clValue); - - virtual void InternalSetValue(const char* pszValue) = 0; - virtual void InternalSetFloatValue(float flValue) = 0; - virtual void InternalSetIntValue(int nValue) = 0; - void InternalSetColorValue(Color value); - - virtual __int64 Unknown0(unsigned int a2) = 0; - virtual __int64 Unknown1(const char* a2) = 0; - - void Revert(void); - virtual bool ClampValue(float& flValue) = 0; - - const char* GetDefault(void) const; - void SetDefault(const char* pszDefault); - bool SetColorFromString(const char* pszValue); - - virtual void ChangeStringValue(const char* pszTempValue) = 0; - virtual void CreateInternal(const char* pszName, const char* pszDefaultValue, int nFlags, const char* pszHelpString, - bool bMin, float fMin, bool bMax, float fMax, FnChangeCallback_t pCallback, const char* pszUsageString) = 0; - - void InstallChangeCallback(FnChangeCallback_t callback, bool bInvoke); - void RemoveChangeCallback(FnChangeCallback_t callback); - - struct CVValue_t - { - char* m_pszString; - size_t m_iStringLength; - float m_fValue; - int m_nValue; - }; - - ConVar* m_pParent; //0x0048 - const char* m_pszDefaultValue; //0x0050 - CVValue_t m_Value; //0c0058 - bool m_bHasMin; //0x0070 - float m_fMinVal; //0x0074 - bool m_bHasMax; //0x0078 - float m_fMaxVal; //0x007C - CUtlVector m_fnChangeCallbacks; //0x0080 -}; //Size: 0x00A0 -static_assert(sizeof(ConVar) == 0xA0); - -//----------------------------------------------------------------------------- -// Purpose: Return ConVar value as a boolean. -// Output : bool -//----------------------------------------------------------------------------- -FORCEINLINE bool ConVar::GetBool(void) const -{ - return !!GetInt(); -} - -//----------------------------------------------------------------------------- -// Purpose: Return ConVar value as a float. -// Output : float -//----------------------------------------------------------------------------- -FORCEINLINE float ConVar::GetFloat(void) const -{ - return m_pParent->m_Value.m_fValue; -} - -//----------------------------------------------------------------------------- -// Purpose: Return ConVar value as a double. -// Output : double -//----------------------------------------------------------------------------- -FORCEINLINE double ConVar::GetDouble(void) const -{ - return static_cast(m_pParent->m_Value.m_fValue); -} - -//----------------------------------------------------------------------------- -// Purpose: Return ConVar value as an integer. -// Output : int -//----------------------------------------------------------------------------- -FORCEINLINE int ConVar::GetInt(void) const -{ - return m_pParent->m_Value.m_nValue; -} - -//----------------------------------------------------------------------------- -// Purpose: Return ConVar value as a color. -// Output : Color -//----------------------------------------------------------------------------- -FORCEINLINE Color ConVar::GetColor(void) const -{ - unsigned char* pColorElement = (reinterpret_cast(&m_pParent->m_Value.m_nValue)); - return Color(pColorElement[0], pColorElement[1], pColorElement[2], pColorElement[3]); -} - -//----------------------------------------------------------------------------- -// Purpose: Return ConVar value as a string. -// Output : const char * -//----------------------------------------------------------------------------- -FORCEINLINE const char* ConVar::GetString(void) const -{ - if (m_nFlags & FCVAR_NEVER_AS_STRING) - { - return "FCVAR_NEVER_AS_STRING"; - } - - char const* str = m_pParent->m_Value.m_pszString; - return str ? str : ""; -} //----------------------------------------------------------------------------- // Purpose: Console variable flags container for tools @@ -289,52 +161,21 @@ extern ConVarFlags g_ConVarFlags; bool ConVar_ParseFlagString(const char* pszFlags, int& nFlags, const char* pszConVarName = "<>"); void ConVar_PrintDescription(ConCommandBase* pVar); -/* ==== CONVAR ========================================================================================================================================================== */ -inline CMemory p_ConVar_Register; -inline void*(*v_ConVar_Register)(ConVar* thisptr, const char* szName, const char* szDefaultValue, int nFlags, const char* szHelpString, bool bMin, float fMin, bool bMax, float fMax, FnChangeCallback_t pCallback, const char* pszUsageString); - -inline CMemory p_ConVar_Unregister; -inline void(*v_ConVar_Unregister)(ConVar* thisptr); - -inline CMemory p_ConVar_IsFlagSet; -inline bool(*v_ConVar_IsFlagSet)(ConVar* pConVar, int nFlag); - inline CMemory p_ConVar_PrintDescription; -inline void*(*v_ConVar_PrintDescription)(ConCommandBase* pVar); - -inline ConVar* g_pConVarVBTable; -inline IConVar* g_pConVarVFTable; +inline void* (*v_ConVar_PrintDescription)(ConCommandBase* pVar); /////////////////////////////////////////////////////////////////////////////// class VCVar : public IDetour { virtual void GetAdr(void) const { - LogConAdr("ConCommand::`vftable'", reinterpret_cast(g_pConCommandVFTable)); - LogConAdr("ConVar::`vbtable'", reinterpret_cast(g_pConVarVBTable)); - LogConAdr("ConVar::`vftable'", reinterpret_cast(g_pConVarVFTable)); - LogFunAdr("ConVar::Register", p_ConVar_Register.GetPtr()); - LogFunAdr("ConVar::Unregister", p_ConVar_Unregister.GetPtr()); - LogFunAdr("ConVar::IsFlagSet", p_ConVar_IsFlagSet.GetPtr()); LogFunAdr("ConVar_PrintDescription", p_ConVar_PrintDescription.GetPtr()); LogVarAdr("g_pCVar", reinterpret_cast(g_pCVar)); } - virtual void GetFun(void) const + virtual void GetFun(void) const { -#if defined (GAMEDLL_S0) || defined (GAMEDLL_S1) - p_ConVar_Register = g_GameDll.FindPatternSIMD("48 89 5C 24 ?? 48 89 6C 24 ?? 48 89 74 24 ?? 48 89 7C 24 ?? 41 56 48 83 EC 30 F3 0F 10 44 24 ??"); - p_ConVar_Unregister = g_GameDll.FindPatternSIMD("48 89 5C 24 ?? 57 48 83 EC 20 48 8B 59 58 48 8D 05 ?? ?? ?? ??"); -#elif defined (GAMEDLL_S2) || defined (GAMEDLL_S3) - p_ConVar_Register = g_GameDll.FindPatternSIMD("48 89 5C 24 ?? 48 89 6C 24 ?? 48 89 74 24 ?? 57 48 83 EC 40 F3 0F 10 84 24 ?? ?? ?? ??"); - p_ConVar_Unregister = g_GameDll.FindPatternSIMD("48 89 5C 24 ?? 48 89 74 24 ?? 57 48 83 EC 20 48 8B 79 58"); -#endif - p_ConVar_IsFlagSet = g_GameDll.FindPatternSIMD("48 8B 41 48 85 50 38"); - p_ConVar_PrintDescription = g_GameDll.FindPatternSIMD("B8 ?? ?? ?? ?? E8 ?? ?? ?? ?? 48 2B E0 48 8B 01 48 89 9C 24 ?? ?? ?? ??"); - - v_ConVar_IsFlagSet = p_ConVar_IsFlagSet.RCast(); - v_ConVar_Register = p_ConVar_Register.RCast(); - v_ConVar_Unregister = p_ConVar_Unregister.RCast(); - v_ConVar_PrintDescription = p_ConVar_PrintDescription.RCast(); + p_ConVar_PrintDescription = g_GameDll.FindPatternSIMD("B8 ?? ?? ?? ?? E8 ?? ?? ?? ?? 48 2B E0 48 8B 01 48 89 9C 24 ?? ?? ?? ??"); + v_ConVar_PrintDescription = p_ConVar_PrintDescription.RCast(); } virtual void GetVar(void) const { @@ -344,11 +185,7 @@ class VCVar : public IDetour //g_pCVar = g_GameDll.FindPatternSIMD("40 53 48 83 EC 20 48 83 3D ?? ?? ?? ?? ?? 48 8B D9 74 09") // Actual CCvar, above is the vtable ptr. //.FindPatternSelf("48 83 3D", CMemory::Direction::DOWN).ResolveRelativeAddressSelf(0x3, 0x8).RCast(); } - virtual void GetCon(void) const - { - g_pConVarVBTable = g_GameDll.GetVirtualMethodTable(".?AVConVar@@", 0).RCast(); - g_pConVarVFTable = g_GameDll.GetVirtualMethodTable(".?AVConVar@@", 1).RCast(); - } + virtual void GetCon(void) const { } virtual void Attach(void) const; virtual void Detach(void) const; }; diff --git a/r5dev/tier1/CMakeLists.txt b/r5dev/tier1/CMakeLists.txt index 11ff85b3..d10a8eb0 100644 --- a/r5dev/tier1/CMakeLists.txt +++ b/r5dev/tier1/CMakeLists.txt @@ -22,6 +22,7 @@ add_sources( SOURCE_GROUP "Utility" add_sources( SOURCE_GROUP "Private" "cmd.cpp" + "convar.cpp" "cvar.cpp" ) diff --git a/r5dev/tier1/cmd.cpp b/r5dev/tier1/cmd.cpp index 1f82e861..da7349ce 100644 --- a/r5dev/tier1/cmd.cpp +++ b/r5dev/tier1/cmd.cpp @@ -274,90 +274,3 @@ void CCommand::Reset() m_pArgSBuffer[0] = 0; m_nQueuedVal = cmd_source_t::kCommandSrcInvalid; } - -//----------------------------------------------------------------------------- -// Purpose: create -//----------------------------------------------------------------------------- -ConCommand* ConCommand::StaticCreate(const char* pszName, const char* pszHelpString, const char* pszUsageString, - int nFlags, FnCommandCallback_t pCallback, FnCommandCompletionCallback pCompletionFunc) -{ - ConCommand* pCommand = (ConCommand*)malloc(sizeof(ConCommand)); - *(ConCommandBase**)pCommand = g_pConCommandVFTable; - - pCommand->m_pNext = nullptr; - pCommand->m_bRegistered = false; - - pCommand->m_pszName = pszName; - pCommand->m_pszHelpString = pszHelpString; - pCommand->m_pszUsageString = pszUsageString; - pCommand->s_pAccessor = nullptr; - pCommand->m_nFlags = nFlags; - - pCommand->m_nNullCallBack = NullSub; - pCommand->m_pSubCallback = nullptr; - pCommand->m_fnCommandCallback = pCallback; - pCommand->m_bHasCompletionCallback = pCompletionFunc != nullptr ? true : false; - pCommand->m_bUsingNewCommandCallback = true; - pCommand->m_bUsingCommandCallbackInterface = false; - pCommand->m_fnCompletionCallback = pCompletionFunc ? pCompletionFunc : CallbackStub; - - g_pCVar->RegisterConCommand(pCommand); - return pCommand; -} - -//----------------------------------------------------------------------------- -// Purpose: construct/allocate -//----------------------------------------------------------------------------- -ConCommand::ConCommand() - : m_nNullCallBack(nullptr) - , m_pSubCallback(nullptr) - , m_fnCommandCallbackV1(nullptr) - , m_fnCompletionCallback(nullptr) - , m_bHasCompletionCallback(false) - , m_bUsingNewCommandCallback(false) - , m_bUsingCommandCallbackInterface(false) -{ -} - -//----------------------------------------------------------------------------- -// Purpose: Checks if ConCommand has requested flags. -// Input : nFlags - -// Output : True if ConCommand has nFlags. -//----------------------------------------------------------------------------- -bool ConCommandBase::HasFlags(int nFlags) const -{ - return m_nFlags & nFlags; -} - -//----------------------------------------------------------------------------- -// Purpose: -// Output : const ConCommandBase -//----------------------------------------------------------------------------- -ConCommandBase* ConCommandBase::GetNext(void) const -{ - return m_pNext; -} - -//----------------------------------------------------------------------------- -// Purpose: Copies string using local new/delete operators -// Input : *szFrom - -// Output : char -//----------------------------------------------------------------------------- -char* ConCommandBase::CopyString(const char* szFrom) const -{ - size_t nLen; - char* szTo; - - nLen = strlen(szFrom); - if (nLen <= 0) - { - szTo = new char[1]; - szTo[0] = 0; - } - else - { - szTo = new char[nLen + 1]; - memmove(szTo, szFrom, nLen + 1); - } - return szTo; -} diff --git a/r5dev/tier1/convar.cpp b/r5dev/tier1/convar.cpp new file mode 100644 index 00000000..c1c4a71c --- /dev/null +++ b/r5dev/tier1/convar.cpp @@ -0,0 +1,497 @@ +//=============================================================================// +// +// Purpose: +// +//=============================================================================// +#include "tier0/tslist.h" +#include "tier1/convar.h" + +//----------------------------------------------------------------------------- +// Purpose: Checks if ConCommand has requested flags. +// Input : nFlags - +// Output : True if ConCommand has nFlags. +//----------------------------------------------------------------------------- +bool ConCommandBase::HasFlags(int nFlags) const +{ + return m_nFlags & nFlags; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Output : const ConCommandBase +//----------------------------------------------------------------------------- +ConCommandBase* ConCommandBase::GetNext(void) const +{ + return m_pNext; +} + +//----------------------------------------------------------------------------- +// Purpose: Copies string using local new/delete operators +// Input : *szFrom - +// Output : char +//----------------------------------------------------------------------------- +char* ConCommandBase::CopyString(const char* szFrom) const +{ + size_t nLen; + char* szTo; + + nLen = strlen(szFrom); + if (nLen <= 0) + { + szTo = new char[1]; + szTo[0] = 0; + } + else + { + szTo = new char[nLen + 1]; + memmove(szTo, szFrom, nLen + 1); + } + return szTo; +} + +//----------------------------------------------------------------------------- +// Default do nothing function +//----------------------------------------------------------------------------- +void DefaultNullSub() +{ + ; /*DO NOTHING*/ +} + +//----------------------------------------------------------------------------- +// Default console command autocompletion function +//----------------------------------------------------------------------------- +int DefaultCompletionFunc(const char* partial, char commands[COMMAND_COMPLETION_MAXITEMS][COMMAND_COMPLETION_ITEM_LENGTH]) +{ + return 0; +} + +//----------------------------------------------------------------------------- +// Purpose: create +//----------------------------------------------------------------------------- +ConCommand* ConCommand::StaticCreate(const char* pszName, const char* pszHelpString, const char* pszUsageString, + int nFlags, FnCommandCallback_t pCallback, FnCommandCompletionCallback pCompletionFunc) +{ + ConCommand* pCommand = (ConCommand*)malloc(sizeof(ConCommand)); + *(ConCommand**)pCommand = g_pConCommandVFTable; + + pCommand->m_pNext = nullptr; + pCommand->m_bRegistered = false; + + pCommand->m_pszName = pszName; + pCommand->m_pszHelpString = pszHelpString; + pCommand->m_pszUsageString = pszUsageString; + pCommand->s_pAccessor = nullptr; + pCommand->m_nFlags = nFlags; + + pCommand->m_nNullCallBack = DefaultNullSub; + pCommand->m_pSubCallback = nullptr; + pCommand->m_fnCommandCallback = pCallback; + pCommand->m_bHasCompletionCallback = pCompletionFunc != nullptr ? true : false; + pCommand->m_bUsingNewCommandCallback = true; + pCommand->m_bUsingCommandCallbackInterface = false; + pCommand->m_fnCompletionCallback = pCompletionFunc ? pCompletionFunc : DefaultCompletionFunc; + + g_pCVar->RegisterConCommand(pCommand); + return pCommand; +} + +//----------------------------------------------------------------------------- +// Purpose: construct/allocate +//----------------------------------------------------------------------------- +ConCommand::ConCommand() + : m_nNullCallBack(nullptr) + , m_pSubCallback(nullptr) + , m_fnCommandCallbackV1(nullptr) + , m_fnCompletionCallback(nullptr) + , m_bHasCompletionCallback(false) + , m_bUsingNewCommandCallback(false) + , m_bUsingCommandCallbackInterface(false) +{ +} + +//----------------------------------------------------------------------------- +// Purpose: create +//----------------------------------------------------------------------------- +ConVar* ConVar::StaticCreate(const char* pszName, const char* pszDefaultValue, + int nFlags, const char* pszHelpString, bool bMin, float fMin, bool bMax, + float fMax, FnChangeCallback_t pCallback, const char* pszUsageString) +{ + ConVar* pNewConVar = (ConVar*)malloc(sizeof(ConVar)); + + pNewConVar->m_bRegistered = false; + *(ConVar**)pNewConVar = g_pConVarVBTable; + char* pConVarVFTable = (char*)pNewConVar + sizeof(ConCommandBase); + *(IConVar**)pConVarVFTable = g_pConVarVFTable; + + pNewConVar->m_pszName = nullptr; + pNewConVar->m_pszHelpString = nullptr; + pNewConVar->m_pszUsageString = nullptr; + pNewConVar->s_pAccessor = nullptr; + pNewConVar->m_nFlags = FCVAR_NONE; + pNewConVar->m_pNext = nullptr; + + pNewConVar->m_fnChangeCallbacks.Init(); + + v_ConVar_Register(pNewConVar, pszName, pszDefaultValue, nFlags, + pszHelpString, bMin, fMin, bMax, fMax, pCallback, pszUsageString); + return pNewConVar; +} + +//----------------------------------------------------------------------------- +// Purpose: destroy +//----------------------------------------------------------------------------- +void ConVar::Destroy(void) +{ + v_ConVar_Unregister(this); +} + +//----------------------------------------------------------------------------- +// Purpose: construct/allocate +//----------------------------------------------------------------------------- +ConVar::ConVar(void) + : m_pParent(nullptr) + , m_pszDefaultValue(nullptr) + , m_bHasMin(false) + , m_fMinVal(0.f) + , m_bHasMax(false) + , m_fMaxVal(0.f) +{ + m_Value.m_pszString = nullptr; + m_Value.m_iStringLength = 0; + m_Value.m_fValue = 0.0f; + m_Value.m_nValue = 0; +} + +//----------------------------------------------------------------------------- +// Purpose: destructor +//----------------------------------------------------------------------------- +//ConVar::~ConVar(void) +//{ +// if (m_Value.m_pszString) +// { +// delete[] m_Value.m_pszString); +// m_Value.m_pszString = NULL; +// } +//} + +////----------------------------------------------------------------------------- +//// Purpose: Returns the base ConVar name. +//// Output : const char* +////----------------------------------------------------------------------------- +//const char* ConVar::GetBaseName(void) const +//{ +// return m_pParent->m_pszName; +//} +// +////----------------------------------------------------------------------------- +//// Purpose: Returns the ConVar help text. +//// Output : const char* +////----------------------------------------------------------------------------- +//const char* ConVar::GetHelpText(void) const +//{ +// return m_pParent->m_pszHelpString; +//} +// +////----------------------------------------------------------------------------- +//// Purpose: Returns the ConVar usage text. +//// Output : const char* +////----------------------------------------------------------------------------- +//const char* ConVar::GetUsageText(void) const +//{ +// return m_pParent->m_pszUsageString; +//} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : flMaxVal - +//----------------------------------------------------------------------------- +void ConVar::SetMax(float flMaxVal) +{ + m_pParent->m_fMaxVal = flMaxVal; + m_pParent->m_bHasMax = true; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : flMinVal - +//----------------------------------------------------------------------------- +void ConVar::SetMin(float flMinVal) +{ + m_pParent->m_fMinVal = flMinVal; + m_pParent->m_bHasMin = true; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : flMinVal - +// Output : true if there is a min set. +//----------------------------------------------------------------------------- +bool ConVar::GetMin(float& flMinVal) const +{ + flMinVal = m_pParent->m_fMinVal; + return m_pParent->m_bHasMin; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : flMaxVal - +// Output : true if there is a max set. +//----------------------------------------------------------------------------- +bool ConVar::GetMax(float& flMaxVal) const +{ + flMaxVal = m_pParent->m_fMaxVal; + return m_pParent->m_bHasMax; +} + +//----------------------------------------------------------------------------- +// Purpose: returns the min value. +// Output : float +//----------------------------------------------------------------------------- +float ConVar::GetMinValue(void) const +{ + return m_pParent->m_fMinVal; +} + +//----------------------------------------------------------------------------- +// Purpose: returns the max value. +// Output : float +//----------------------------------------------------------------------------- +float ConVar::GetMaxValue(void) const +{ + return m_pParent->m_fMaxVal; +} + +//----------------------------------------------------------------------------- +// Purpose: checks if ConVar has min value. +// Output : bool +//----------------------------------------------------------------------------- +bool ConVar::HasMin(void) const +{ + return m_pParent->m_bHasMin; +} + +//----------------------------------------------------------------------------- +// Purpose: checks if ConVar has max value. +// Output : bool +//----------------------------------------------------------------------------- +bool ConVar::HasMax(void) const +{ + return m_pParent->m_bHasMax; +} + +//----------------------------------------------------------------------------- +// Purpose: sets the ConVar int value. +// Input : nValue - +//----------------------------------------------------------------------------- +void ConVar::SetValue(int nValue) +{ + ConVar* pCVar = reinterpret_cast(m_pParent); + pCVar->InternalSetIntValue(nValue); +} + +//----------------------------------------------------------------------------- +// Purpose: sets the ConVar float value. +// Input : flValue - +//----------------------------------------------------------------------------- +void ConVar::SetValue(float flValue) +{ + ConVar* pCVar = reinterpret_cast(m_pParent); + pCVar->InternalSetFloatValue(flValue); +} + +//----------------------------------------------------------------------------- +// Purpose: sets the ConVar string value. +// Input : *szValue - +//----------------------------------------------------------------------------- +void ConVar::SetValue(const char* pszValue) +{ + ConVar* pCVar = reinterpret_cast(m_pParent); + pCVar->InternalSetValue(pszValue); +} + +//----------------------------------------------------------------------------- +// Purpose: sets the ConVar color value. +// Input : value - +//----------------------------------------------------------------------------- +void ConVar::SetValue(Color value) +{ + ConVar* pCVar = reinterpret_cast(m_pParent); + pCVar->InternalSetColorValue(value); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *value - +//----------------------------------------------------------------------------- +void ConVar::InternalSetColorValue(Color value) +{ + // Stuff color values into an int + int nValue = 0; + + unsigned char* pColorElement = (reinterpret_cast(&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: Reset to default value. +//----------------------------------------------------------------------------- +void ConVar::Revert(void) +{ + SetValue(m_pszDefaultValue); +} + +//----------------------------------------------------------------------------- +// Purpose: returns the default ConVar value. +// Output : const char +//----------------------------------------------------------------------------- +const char* ConVar::GetDefault(void) const +{ + return m_pParent->m_pszDefaultValue; +} + +//----------------------------------------------------------------------------- +// Purpose: sets the default ConVar value. +// Input : *pszDefault - +//----------------------------------------------------------------------------- +void ConVar::SetDefault(const char* pszDefault) +{ + static const char* pszEmpty = ""; + m_pszDefaultValue = pszDefault ? pszDefault : pszEmpty; + assert(m_pszDefaultValue); +} + +//----------------------------------------------------------------------------- +// Purpose: sets the ConVar color value from string. +// Input : *pszValue - +//----------------------------------------------------------------------------- +bool ConVar::SetColorFromString(const char* pszValue) +{ + bool bColor = false; + + // Try pulling RGBA color values out of the string. + int nRGBA[4]; + int nParamsRead = sscanf_s(pszValue, "%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) + { + //printf("*** WOW! Found a color!! ***\n"); + + // This is definitely a color! + bColor = true; + + // Stuff all the values into each byte of our int. + unsigned char* pColorElement = + (reinterpret_cast(&m_Value.m_nValue)); + + pColorElement[0] = (unsigned char)nRGBA[0]; + pColorElement[1] = (unsigned char)nRGBA[1]; + pColorElement[2] = (unsigned char)nRGBA[2]; + pColorElement[3] = (unsigned char)nRGBA[3]; + + // Copy that value into our float. + m_Value.m_fValue = static_cast(m_Value.m_nValue); + } + } + + return bColor; +} + +//----------------------------------------------------------------------------- +// Purpose: changes the ConVar string value. +// Input : *pszTempVal - flOldValue +//----------------------------------------------------------------------------- +void ConVar::ChangeStringValue(const char* pszTempVal) +{ + Assert(!(m_nFlags & FCVAR_NEVER_AS_STRING)); + + char* pszOldValue = (char*)stackalloc(m_Value.m_iStringLength); + memcpy(pszOldValue, m_Value.m_pszString, m_Value.m_iStringLength); + + size_t len = strlen(pszTempVal) + 1; + + if (len > m_Value.m_iStringLength) + { + if (m_Value.m_pszString) + { + delete[] m_Value.m_pszString; + } + + m_Value.m_pszString = new char[len]; + m_Value.m_iStringLength = len; + } + + memcpy(reinterpret_cast(m_Value.m_pszString), pszTempVal, len); + + // Invoke any necessary callback function + for (int i = 0; i < m_fnChangeCallbacks.Count(); ++i) + { + m_fnChangeCallbacks[i](this, pszOldValue, NULL); + } + + if (g_pCVar) + { + g_pCVar->CallGlobalChangeCallbacks(this, pszOldValue); + } + + stackfree(pszOldValue); +} + +//----------------------------------------------------------------------------- +// Purpose: Install a change callback (there shouldn't already be one....) +// Input : callback - +// bInvoke - +//----------------------------------------------------------------------------- +void ConVar::InstallChangeCallback(FnChangeCallback_t callback, bool bInvoke /*=true*/) +{ + if (!callback) + { + Warning(eDLL_T::COMMON, "%s: Called with NULL callback; ignoring!!!\n", + __FUNCTION__); + return; + } + + if (m_pParent->m_fnChangeCallbacks.Find(callback) + != m_pParent->m_fnChangeCallbacks.InvalidIndex()) + { + // Same ptr added twice, sigh... + Warning(eDLL_T::COMMON, "%s: Ignoring duplicate change callback!!!\n", + __FUNCTION__); + 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); + } +} + +//----------------------------------------------------------------------------- +// Purpose: Install a change callback (there shouldn't already be one....) +// Input : callback - +//----------------------------------------------------------------------------- +void ConVar::RemoveChangeCallback(FnChangeCallback_t callback) +{ + m_pParent->m_fnChangeCallbacks.FindAndRemove(callback); +} diff --git a/r5dev/tier1/cvar.cpp b/r5dev/tier1/cvar.cpp index bf460161..266bd4dd 100644 --- a/r5dev/tier1/cvar.cpp +++ b/r5dev/tier1/cvar.cpp @@ -1,398 +1,12 @@ -#include "tier1/utlrbtree.h" -#include "tier1/utlmap.h" -#include "tier1/NetAdr.h" +//=============================================================================// +// +// Purpose: +// +//=============================================================================// +#include "mathlib/color.h" +#include "tier1/convar.h" #include "tier1/cvar.h" -#include "public/const.h" -#include "engine/sys_dll2.h" #include "filesystem/filesystem.h" -#include "vstdlib/concommandhash.h" - -//----------------------------------------------------------------------------- -// Purpose: create -//----------------------------------------------------------------------------- -ConVar* ConVar::StaticCreate(const char* pszName, const char* pszDefaultValue, - int nFlags, const char* pszHelpString, bool bMin, float fMin, bool bMax, - float fMax, FnChangeCallback_t pCallback, const char* pszUsageString) -{ - ConVar* pNewConVar = (ConVar*)malloc(sizeof(ConVar)); - - pNewConVar->m_bRegistered = false; - *(ConVar**)pNewConVar = g_pConVarVBTable; - char* pConVarVFTable = (char*)pNewConVar + sizeof(ConCommandBase); - *(IConVar**)pConVarVFTable = g_pConVarVFTable; - - pNewConVar->m_pszName = nullptr; - pNewConVar->m_pszHelpString = nullptr; - pNewConVar->m_pszUsageString = nullptr; - pNewConVar->s_pAccessor = nullptr; - pNewConVar->m_nFlags = FCVAR_NONE; - pNewConVar->m_pNext = nullptr; - - pNewConVar->m_fnChangeCallbacks.Init(); - - v_ConVar_Register(pNewConVar, pszName, pszDefaultValue, nFlags, - pszHelpString, bMin, fMin, bMax, fMax, pCallback, pszUsageString); - return pNewConVar; -} - -//----------------------------------------------------------------------------- -// Purpose: destroy -//----------------------------------------------------------------------------- -void ConVar::Destroy(void) -{ - v_ConVar_Unregister(this); -} - -//----------------------------------------------------------------------------- -// Purpose: construct/allocate -//----------------------------------------------------------------------------- -ConVar::ConVar(void) - : m_pParent(nullptr) - , m_pszDefaultValue(nullptr) - , m_bHasMin(false) - , m_fMinVal(0.f) - , m_bHasMax(false) - , m_fMaxVal(0.f) -{ - m_Value.m_pszString = nullptr; - m_Value.m_iStringLength = 0; - m_Value.m_fValue = 0.0f; - m_Value.m_nValue = 0; -} - -//----------------------------------------------------------------------------- -// Purpose: destructor -//----------------------------------------------------------------------------- -//ConVar::~ConVar(void) -//{ -// if (m_Value.m_pszString) -// { -// delete[] m_Value.m_pszString); -// m_Value.m_pszString = NULL; -// } -//} - -////----------------------------------------------------------------------------- -//// Purpose: Returns the base ConVar name. -//// Output : const char* -////----------------------------------------------------------------------------- -//const char* ConVar::GetBaseName(void) const -//{ -// return m_pParent->m_pszName; -//} -// -////----------------------------------------------------------------------------- -//// Purpose: Returns the ConVar help text. -//// Output : const char* -////----------------------------------------------------------------------------- -//const char* ConVar::GetHelpText(void) const -//{ -// return m_pParent->m_pszHelpString; -//} -// -////----------------------------------------------------------------------------- -//// Purpose: Returns the ConVar usage text. -//// Output : const char* -////----------------------------------------------------------------------------- -//const char* ConVar::GetUsageText(void) const -//{ -// return m_pParent->m_pszUsageString; -//} - -//----------------------------------------------------------------------------- -// Purpose: -// Input : flMaxVal - -//----------------------------------------------------------------------------- -void ConVar::SetMax(float flMaxVal) -{ - m_pParent->m_fMaxVal = flMaxVal; - m_pParent->m_bHasMax = true; -} - -//----------------------------------------------------------------------------- -// Purpose: -// Input : flMinVal - -//----------------------------------------------------------------------------- -void ConVar::SetMin(float flMinVal) -{ - m_pParent->m_fMinVal = flMinVal; - m_pParent->m_bHasMin = true; -} - -//----------------------------------------------------------------------------- -// Purpose: -// Input : flMinVal - -// Output : true if there is a min set. -//----------------------------------------------------------------------------- -bool ConVar::GetMin(float& flMinVal) const -{ - flMinVal = m_pParent->m_fMinVal; - return m_pParent->m_bHasMin; -} - -//----------------------------------------------------------------------------- -// Purpose: -// Input : flMaxVal - -// Output : true if there is a max set. -//----------------------------------------------------------------------------- -bool ConVar::GetMax(float& flMaxVal) const -{ - flMaxVal = m_pParent->m_fMaxVal; - return m_pParent->m_bHasMax; -} - -//----------------------------------------------------------------------------- -// Purpose: returns the min value. -// Output : float -//----------------------------------------------------------------------------- -float ConVar::GetMinValue(void) const -{ - return m_pParent->m_fMinVal; -} - -//----------------------------------------------------------------------------- -// Purpose: returns the max value. -// Output : float -//----------------------------------------------------------------------------- -float ConVar::GetMaxValue(void) const -{ - return m_pParent->m_fMaxVal; -} - -//----------------------------------------------------------------------------- -// Purpose: checks if ConVar has min value. -// Output : bool -//----------------------------------------------------------------------------- -bool ConVar::HasMin(void) const -{ - return m_pParent->m_bHasMin; -} - -//----------------------------------------------------------------------------- -// Purpose: checks if ConVar has max value. -// Output : bool -//----------------------------------------------------------------------------- -bool ConVar::HasMax(void) const -{ - return m_pParent->m_bHasMax; -} - -//----------------------------------------------------------------------------- -// Purpose: sets the ConVar int value. -// Input : nValue - -//----------------------------------------------------------------------------- -void ConVar::SetValue(int nValue) -{ - ConVar* pCVar = reinterpret_cast(m_pParent); - pCVar->InternalSetIntValue(nValue); -} - -//----------------------------------------------------------------------------- -// Purpose: sets the ConVar float value. -// Input : flValue - -//----------------------------------------------------------------------------- -void ConVar::SetValue(float flValue) -{ - ConVar* pCVar = reinterpret_cast(m_pParent); - pCVar->InternalSetFloatValue(flValue); -} - -//----------------------------------------------------------------------------- -// Purpose: sets the ConVar string value. -// Input : *szValue - -//----------------------------------------------------------------------------- -void ConVar::SetValue(const char* pszValue) -{ - ConVar* pCVar = reinterpret_cast(m_pParent); - pCVar->InternalSetValue(pszValue); -} - -//----------------------------------------------------------------------------- -// Purpose: sets the ConVar color value. -// Input : value - -//----------------------------------------------------------------------------- -void ConVar::SetValue(Color value) -{ - ConVar* pCVar = reinterpret_cast(m_pParent); - pCVar->InternalSetColorValue(value); -} - -//----------------------------------------------------------------------------- -// Purpose: -// Input : *value - -//----------------------------------------------------------------------------- -void ConVar::InternalSetColorValue(Color value) -{ - // Stuff color values into an int - int nValue = 0; - - unsigned char* pColorElement = (reinterpret_cast(&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: Reset to default value. -//----------------------------------------------------------------------------- -void ConVar::Revert(void) -{ - SetValue(m_pszDefaultValue); -} - -//----------------------------------------------------------------------------- -// Purpose: returns the default ConVar value. -// Output : const char -//----------------------------------------------------------------------------- -const char* ConVar::GetDefault(void) const -{ - return m_pParent->m_pszDefaultValue; -} - -//----------------------------------------------------------------------------- -// Purpose: sets the default ConVar value. -// Input : *pszDefault - -//----------------------------------------------------------------------------- -void ConVar::SetDefault(const char* pszDefault) -{ - static const char* pszEmpty = ""; - m_pszDefaultValue = pszDefault ? pszDefault : pszEmpty; - assert(m_pszDefaultValue); -} - -//----------------------------------------------------------------------------- -// Purpose: sets the ConVar color value from string. -// Input : *pszValue - -//----------------------------------------------------------------------------- -bool ConVar::SetColorFromString(const char* pszValue) -{ - bool bColor = false; - - // Try pulling RGBA color values out of the string. - int nRGBA[4]; - int nParamsRead = sscanf_s(pszValue, "%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) - { - //printf("*** WOW! Found a color!! ***\n"); - - // This is definitely a color! - bColor = true; - - // Stuff all the values into each byte of our int. - unsigned char* pColorElement = - (reinterpret_cast(&m_Value.m_nValue)); - - pColorElement[0] = (unsigned char)nRGBA[0]; - pColorElement[1] = (unsigned char)nRGBA[1]; - pColorElement[2] = (unsigned char)nRGBA[2]; - pColorElement[3] = (unsigned char)nRGBA[3]; - - // Copy that value into our float. - m_Value.m_fValue = static_cast(m_Value.m_nValue); - } - } - - return bColor; -} - -//----------------------------------------------------------------------------- -// Purpose: changes the ConVar string value. -// Input : *pszTempVal - flOldValue -//----------------------------------------------------------------------------- -void ConVar::ChangeStringValue(const char* pszTempVal) -{ - Assert(!(m_nFlags & FCVAR_NEVER_AS_STRING)); - - char* pszOldValue = (char*)stackalloc(m_Value.m_iStringLength); - memcpy(pszOldValue, m_Value.m_pszString, m_Value.m_iStringLength); - - size_t len = strlen(pszTempVal) + 1; - - if (len > m_Value.m_iStringLength) - { - if (m_Value.m_pszString) - { - delete[] m_Value.m_pszString; - } - - m_Value.m_pszString = new char[len]; - m_Value.m_iStringLength = len; - } - - memcpy(reinterpret_cast(m_Value.m_pszString), pszTempVal, len); - - // Invoke any necessary callback function - for (int i = 0; i < m_fnChangeCallbacks.Count(); ++i) - { - m_fnChangeCallbacks[i](this, pszOldValue, NULL); - } - - if (g_pCVar) - { - g_pCVar->CallGlobalChangeCallbacks(this, pszOldValue); - } - - stackfree(pszOldValue); -} - -//----------------------------------------------------------------------------- -// Purpose: Install a change callback (there shouldn't already be one....) -// Input : callback - -// bInvoke - -//----------------------------------------------------------------------------- -void ConVar::InstallChangeCallback(FnChangeCallback_t callback, bool bInvoke /*=true*/) -{ - if (!callback) - { - Warning(eDLL_T::COMMON, "%s: Called with NULL callback; ignoring!!!\n", - __FUNCTION__); - return; - } - - if (m_pParent->m_fnChangeCallbacks.Find(callback) - != m_pParent->m_fnChangeCallbacks.InvalidIndex()) - { - // Same ptr added twice, sigh... - Warning(eDLL_T::COMMON, "%s: Ignoring duplicate change callback!!!\n", - __FUNCTION__); - 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); - } -} - -//----------------------------------------------------------------------------- -// Purpose: Install a change callback (there shouldn't already be one....) -// Input : callback - -//----------------------------------------------------------------------------- -void ConVar::RemoveChangeCallback(FnChangeCallback_t callback) -{ - m_pParent->m_fnChangeCallbacks.FindAndRemove(callback); -} #define SET_CONVARFLAG(x, y) SetFlag(FCVAR_##x, #x, y) //----------------------------------------------------------------------------- @@ -1064,212 +678,6 @@ int CCvarUtilities::CvarFindFlagsCompletionCallback(const char* partial, /////////////////////////////////////////////////////////////////////////////// CCvar* g_pCVar = nullptr; - -//----------------------------------------------------------------------------- -// Console command hash data structure -//----------------------------------------------------------------------------- -CConCommandHash::CConCommandHash() -{ - Purge(true); -} - -CConCommandHash::~CConCommandHash() -{ - Purge(false); -} - -void CConCommandHash::Purge(bool bReinitialize) -{ - m_aBuckets.Purge(); - m_aDataPool.Purge(); - if (bReinitialize) - { - Init(); - } -} - -// Initialize. -void CConCommandHash::Init(void) -{ - // kNUM_BUCKETS must be a power of two. - COMPILE_TIME_ASSERT((kNUM_BUCKETS & (kNUM_BUCKETS - 1)) == 0); - - // Set the bucket size. - m_aBuckets.SetSize(kNUM_BUCKETS); - for (int iBucket = 0; iBucket < kNUM_BUCKETS; ++iBucket) - { - m_aBuckets[iBucket] = m_aDataPool.InvalidIndex(); - } - - // Calculate the grow size. - int nGrowSize = 4 * kNUM_BUCKETS; - m_aDataPool.SetGrowSize(nGrowSize); -} - -//----------------------------------------------------------------------------- -// Purpose: Insert data into the hash table given its key (unsigned int), -// WITH a check to see if the element already exists within the hash. -//----------------------------------------------------------------------------- -CConCommandHash::CCommandHashHandle_t CConCommandHash::Insert(ConCommandBase* cmd) -{ - // Check to see if that key already exists in the buckets (should be unique). - CCommandHashHandle_t hHash = Find(cmd); - if (hHash != InvalidHandle()) - return hHash; - - return FastInsert(cmd); -} -//----------------------------------------------------------------------------- -// Purpose: Insert data into the hash table given its key (unsigned int), -// WITHOUT a check to see if the element already exists within the hash. -//----------------------------------------------------------------------------- -CConCommandHash::CCommandHashHandle_t CConCommandHash::FastInsert(ConCommandBase* cmd) -{ - // Get a new element from the pool. - intptr_t iHashData = m_aDataPool.Alloc(true); - HashEntry_t* RESTRICT pHashData = &m_aDataPool[iHashData]; - if (!pHashData) - return InvalidHandle(); - - HashKey_t key = Hash(cmd); - - // Add data to new element. - pHashData->m_uiKey = key; - pHashData->m_Data = cmd; - - // Link element. - int iBucket = key & kBUCKETMASK; // HashFuncs::Hash( uiKey, m_uiBucketMask ); - m_aDataPool.LinkBefore(m_aBuckets[iBucket], iHashData); - m_aBuckets[iBucket] = iHashData; - - return iHashData; -} - -//----------------------------------------------------------------------------- -// Purpose: Remove a given element from the hash. -//----------------------------------------------------------------------------- -void CConCommandHash::Remove(CCommandHashHandle_t hHash) /*RESTRICT*/ -{ - HashEntry_t* /*RESTRICT*/ entry = &m_aDataPool[hHash]; - HashKey_t iBucket = entry->m_uiKey & kBUCKETMASK; - if (m_aBuckets[iBucket] == hHash) - { - // It is a bucket head. - m_aBuckets[iBucket] = m_aDataPool.Next(hHash); - } - else - { - // Not a bucket head. - m_aDataPool.Unlink(hHash); - } - - // Remove the element. - m_aDataPool.Remove(hHash); -} - -//----------------------------------------------------------------------------- -// Purpose: Remove all elements from the hash -//----------------------------------------------------------------------------- -void CConCommandHash::RemoveAll(void) -{ - m_aBuckets.RemoveAll(); - m_aDataPool.RemoveAll(); -} - -//----------------------------------------------------------------------------- -// Find hash entry corresponding to a string name -//----------------------------------------------------------------------------- -CConCommandHash::CCommandHashHandle_t CConCommandHash::Find( - const char* name, HashKey_t hashkey) const /*RESTRICT*/ -{ - // hash the "key" - get the correct hash table "bucket" - int iBucket = hashkey & kBUCKETMASK; - - for (datapool_t::IndexLocalType_t iElement = m_aBuckets[iBucket]; - iElement != m_aDataPool.InvalidIndex(); iElement = m_aDataPool.Next(iElement)) - { - const HashEntry_t& element = m_aDataPool[iElement]; - if (element.m_uiKey == hashkey && // if hashes of strings match, - Q_stricmp(name, element.m_Data->GetName()) == 0) // then test the actual strings - { - return iElement; - } - } - - // found nuffink - return InvalidHandle(); -} - -//----------------------------------------------------------------------------- -// Find a command in the hash. -//----------------------------------------------------------------------------- -CConCommandHash::CCommandHashHandle_t CConCommandHash::Find(const ConCommandBase* cmd) const /*RESTRICT*/ -{ - // Set this #if to 1 if the assert at bottom starts whining -- - // that indicates that a console command is being double-registered, - // or something similarly non-fatally bad. With this #if 1, we'll search - // by name instead of by pointer, which is more robust in the face - // of double registered commands, but obviously slower. -#if 0 - return Find(cmd->GetName()); -#else - HashKey_t hashkey = Hash(cmd); - int iBucket = hashkey & kBUCKETMASK; - - // hunt through all entries in that bucket - for (datapool_t::IndexLocalType_t iElement = m_aBuckets[iBucket]; - iElement != m_aDataPool.InvalidIndex(); iElement = m_aDataPool.Next(iElement)) - { - const HashEntry_t& element = m_aDataPool[iElement]; - if (element.m_uiKey == hashkey && // if the hashes match... - element.m_Data == cmd) // and the pointers... - { - // in debug, test to make sure we don't have commands under the same name - // or something goofy like that - Assert(iElement == Find(cmd->GetName()), - "ConCommand %s had two entries in the hash!", cmd->GetName()); - - // return this element - return iElement; - } - } - - // found nothing. -#ifdef DBGFLAG_ASSERT // double check against search by name - CCommandHashHandle_t dbghand = Find(cmd->GetName()); - - Assert(InvalidHandle() == dbghand, - "ConCommand %s couldn't be found by pointer, but was found by name!", cmd->GetName()); -#endif - return InvalidHandle(); -#endif -} - - -//#ifdef _DEBUG -// Dump a report to MSG -void CConCommandHash::Report(void) -{ - DevMsg(eDLL_T::COMMON, "Console command hash bucket load:\n"); - int total = 0; - for (int iBucket = 0; iBucket < kNUM_BUCKETS; ++iBucket) - { - int count = 0; - CCommandHashHandle_t iElement = m_aBuckets[iBucket]; // get the head of the bucket - while (iElement != m_aDataPool.InvalidIndex()) - { - ++count; - iElement = m_aDataPool.Next(iElement); - } - - DevMsg(eDLL_T::COMMON, "%d: %d\n", iBucket, count); - total += count; - } - - DevMsg(eDLL_T::COMMON, "\tAverage: %.1f\n", total / ((float)(kNUM_BUCKETS))); -} -//#endif - /////////////////////////////////////////////////////////////////////////////// void VCVar::Attach() const { diff --git a/r5dev/vstdlib/CMakeLists.txt b/r5dev/vstdlib/CMakeLists.txt index 58b9dc5b..c6aa9c7c 100644 --- a/r5dev/vstdlib/CMakeLists.txt +++ b/r5dev/vstdlib/CMakeLists.txt @@ -6,6 +6,7 @@ start_sources() add_sources( SOURCE_GROUP "Private" "autocompletefilelist.cpp" "autocompletefilelist.h" + "concommandhash.cpp" "concommandhash.h" "keyvaluessystem.cpp" "keyvaluessystem.h" diff --git a/r5dev/vstdlib/concommandhash.cpp b/r5dev/vstdlib/concommandhash.cpp new file mode 100644 index 00000000..2fdd8009 --- /dev/null +++ b/r5dev/vstdlib/concommandhash.cpp @@ -0,0 +1,211 @@ +//=============================================================================// +// +// Purpose: +// +//=============================================================================// +#include "concommandhash.h" + +//----------------------------------------------------------------------------- +// Console command hash data structure +//----------------------------------------------------------------------------- +CConCommandHash::CConCommandHash() +{ + Purge(true); +} + +CConCommandHash::~CConCommandHash() +{ + Purge(false); +} + +void CConCommandHash::Purge(bool bReinitialize) +{ + m_aBuckets.Purge(); + m_aDataPool.Purge(); + if (bReinitialize) + { + Init(); + } +} + +// Initialize. +void CConCommandHash::Init(void) +{ + // kNUM_BUCKETS must be a power of two. + COMPILE_TIME_ASSERT((kNUM_BUCKETS & (kNUM_BUCKETS - 1)) == 0); + + // Set the bucket size. + m_aBuckets.SetSize(kNUM_BUCKETS); + for (int iBucket = 0; iBucket < kNUM_BUCKETS; ++iBucket) + { + m_aBuckets[iBucket] = m_aDataPool.InvalidIndex(); + } + + // Calculate the grow size. + int nGrowSize = 4 * kNUM_BUCKETS; + m_aDataPool.SetGrowSize(nGrowSize); +} + +//----------------------------------------------------------------------------- +// Purpose: Insert data into the hash table given its key (unsigned int), +// WITH a check to see if the element already exists within the hash. +//----------------------------------------------------------------------------- +CConCommandHash::CCommandHashHandle_t CConCommandHash::Insert(ConCommandBase* cmd) +{ + // Check to see if that key already exists in the buckets (should be unique). + CCommandHashHandle_t hHash = Find(cmd); + if (hHash != InvalidHandle()) + return hHash; + + return FastInsert(cmd); +} +//----------------------------------------------------------------------------- +// Purpose: Insert data into the hash table given its key (unsigned int), +// WITHOUT a check to see if the element already exists within the hash. +//----------------------------------------------------------------------------- +CConCommandHash::CCommandHashHandle_t CConCommandHash::FastInsert(ConCommandBase* cmd) +{ + // Get a new element from the pool. + intptr_t iHashData = m_aDataPool.Alloc(true); + HashEntry_t* RESTRICT pHashData = &m_aDataPool[iHashData]; + if (!pHashData) + return InvalidHandle(); + + HashKey_t key = Hash(cmd); + + // Add data to new element. + pHashData->m_uiKey = key; + pHashData->m_Data = cmd; + + // Link element. + int iBucket = key & kBUCKETMASK; // HashFuncs::Hash( uiKey, m_uiBucketMask ); + m_aDataPool.LinkBefore(m_aBuckets[iBucket], iHashData); + m_aBuckets[iBucket] = iHashData; + + return iHashData; +} + +//----------------------------------------------------------------------------- +// Purpose: Remove a given element from the hash. +//----------------------------------------------------------------------------- +void CConCommandHash::Remove(CCommandHashHandle_t hHash) /*RESTRICT*/ +{ + HashEntry_t* /*RESTRICT*/ entry = &m_aDataPool[hHash]; + HashKey_t iBucket = entry->m_uiKey & kBUCKETMASK; + if (m_aBuckets[iBucket] == hHash) + { + // It is a bucket head. + m_aBuckets[iBucket] = m_aDataPool.Next(hHash); + } + else + { + // Not a bucket head. + m_aDataPool.Unlink(hHash); + } + + // Remove the element. + m_aDataPool.Remove(hHash); +} + +//----------------------------------------------------------------------------- +// Purpose: Remove all elements from the hash +//----------------------------------------------------------------------------- +void CConCommandHash::RemoveAll(void) +{ + m_aBuckets.RemoveAll(); + m_aDataPool.RemoveAll(); +} + +//----------------------------------------------------------------------------- +// Find hash entry corresponding to a string name +//----------------------------------------------------------------------------- +CConCommandHash::CCommandHashHandle_t CConCommandHash::Find( + const char* name, HashKey_t hashkey) const /*RESTRICT*/ +{ + // hash the "key" - get the correct hash table "bucket" + int iBucket = hashkey & kBUCKETMASK; + + for (datapool_t::IndexLocalType_t iElement = m_aBuckets[iBucket]; + iElement != m_aDataPool.InvalidIndex(); iElement = m_aDataPool.Next(iElement)) + { + const HashEntry_t& element = m_aDataPool[iElement]; + if (element.m_uiKey == hashkey && // if hashes of strings match, + Q_stricmp(name, element.m_Data->GetName()) == 0) // then test the actual strings + { + return iElement; + } + } + + // found nuffink + return InvalidHandle(); +} + +//----------------------------------------------------------------------------- +// Find a command in the hash. +//----------------------------------------------------------------------------- +CConCommandHash::CCommandHashHandle_t CConCommandHash::Find(const ConCommandBase* cmd) const /*RESTRICT*/ +{ + // Set this #if to 1 if the assert at bottom starts whining -- + // that indicates that a console command is being double-registered, + // or something similarly non-fatally bad. With this #if 1, we'll search + // by name instead of by pointer, which is more robust in the face + // of double registered commands, but obviously slower. +#if 0 + return Find(cmd->GetName()); +#else + HashKey_t hashkey = Hash(cmd); + int iBucket = hashkey & kBUCKETMASK; + + // hunt through all entries in that bucket + for (datapool_t::IndexLocalType_t iElement = m_aBuckets[iBucket]; + iElement != m_aDataPool.InvalidIndex(); iElement = m_aDataPool.Next(iElement)) + { + const HashEntry_t& element = m_aDataPool[iElement]; + if (element.m_uiKey == hashkey && // if the hashes match... + element.m_Data == cmd) // and the pointers... + { + // in debug, test to make sure we don't have commands under the same name + // or something goofy like that + Assert(iElement == Find(cmd->GetName()), + "ConCommand %s had two entries in the hash!", cmd->GetName()); + + // return this element + return iElement; + } + } + + // found nothing. +#ifdef DBGFLAG_ASSERT // double check against search by name + CCommandHashHandle_t dbghand = Find(cmd->GetName()); + + Assert(InvalidHandle() == dbghand, + "ConCommand %s couldn't be found by pointer, but was found by name!", cmd->GetName()); +#endif + return InvalidHandle(); +#endif +} + + +//#ifdef _DEBUG +// Dump a report to MSG +void CConCommandHash::Report(void) +{ + DevMsg(eDLL_T::COMMON, "Console command hash bucket load:\n"); + int total = 0; + for (int iBucket = 0; iBucket < kNUM_BUCKETS; ++iBucket) + { + int count = 0; + CCommandHashHandle_t iElement = m_aBuckets[iBucket]; // get the head of the bucket + while (iElement != m_aDataPool.InvalidIndex()) + { + ++count; + iElement = m_aDataPool.Next(iElement); + } + + DevMsg(eDLL_T::COMMON, "%d: %d\n", iBucket, count); + total += count; + } + + DevMsg(eDLL_T::COMMON, "\tAverage: %.1f\n", total / ((float)(kNUM_BUCKETS))); +} +//#endif \ No newline at end of file diff --git a/r5dev/vstdlib/concommandhash.h b/r5dev/vstdlib/concommandhash.h index cbcd5956..7da9d8a5 100644 --- a/r5dev/vstdlib/concommandhash.h +++ b/r5dev/vstdlib/concommandhash.h @@ -12,10 +12,10 @@ #pragma once #endif -#include "tier1/cmd.h" #include "tier1/utlvector.h" #include "tier1/utllinkedlist.h" #include "tier1/generichash.h" +#include "tier1/convar.h" // This is a hash table class very similar to the CUtlHashFast, but // modified specifically so that we can look up ConCommandBases