2022-08-13 12:39:57 +02:00
|
|
|
#include "tier1/utlrbtree.h"
|
2023-07-03 13:48:13 +02:00
|
|
|
#include "tier1/utlmap.h"
|
2023-04-16 00:32:50 +02:00
|
|
|
#include "tier1/NetAdr.h"
|
2022-04-09 16:16:40 +02:00
|
|
|
#include "tier1/cvar.h"
|
2023-03-28 01:05:23 +02:00
|
|
|
#include "public/const.h"
|
2021-12-25 22:36:38 +01:00
|
|
|
#include "engine/sys_dll2.h"
|
2022-08-13 12:39:57 +02:00
|
|
|
#include "filesystem/filesystem.h"
|
2022-08-13 19:41:45 +02:00
|
|
|
#include "vstdlib/concommandhash.h"
|
2022-11-27 20:44:17 +00:00
|
|
|
|
2023-03-28 01:05:23 +02:00
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// Purpose: create
|
|
|
|
//-----------------------------------------------------------------------------
|
2023-06-19 22:42:25 +02:00
|
|
|
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)
|
2023-03-28 01:05:23 +02:00
|
|
|
{
|
2023-06-26 22:34:24 +02:00
|
|
|
ConVar* pNewConVar = (ConVar*)malloc(sizeof(ConVar));
|
2023-03-28 01:05:23 +02:00
|
|
|
|
|
|
|
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();
|
|
|
|
|
2023-06-19 22:42:25 +02:00
|
|
|
v_ConVar_Register(pNewConVar, pszName, pszDefaultValue, nFlags,
|
|
|
|
pszHelpString, bMin, fMin, bMax, fMax, pCallback, pszUsageString);
|
2023-03-28 01:05:23 +02:00
|
|
|
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)
|
|
|
|
// {
|
2023-06-26 22:34:24 +02:00
|
|
|
// delete[] m_Value.m_pszString);
|
2023-03-28 01:05:23 +02:00
|
|
|
// 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<ConVar*>(m_pParent);
|
|
|
|
pCVar->InternalSetIntValue(nValue);
|
|
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// Purpose: sets the ConVar float value.
|
|
|
|
// Input : flValue -
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
void ConVar::SetValue(float flValue)
|
|
|
|
{
|
|
|
|
ConVar* pCVar = reinterpret_cast<ConVar*>(m_pParent);
|
|
|
|
pCVar->InternalSetFloatValue(flValue);
|
|
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// Purpose: sets the ConVar string value.
|
|
|
|
// Input : *szValue -
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
void ConVar::SetValue(const char* pszValue)
|
|
|
|
{
|
|
|
|
ConVar* pCVar = reinterpret_cast<ConVar*>(m_pParent);
|
|
|
|
pCVar->InternalSetValue(pszValue);
|
|
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// Purpose: sets the ConVar color value.
|
|
|
|
// Input : value -
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
void ConVar::SetValue(Color value)
|
|
|
|
{
|
|
|
|
ConVar* pCVar = reinterpret_cast<ConVar*>(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<unsigned char*>(&nValue));
|
|
|
|
pColorElement[0] = value[0];
|
|
|
|
pColorElement[1] = value[1];
|
|
|
|
pColorElement[2] = value[2];
|
|
|
|
pColorElement[3] = value[3];
|
|
|
|
|
|
|
|
// Call the int internal set
|
|
|
|
InternalSetIntValue(nValue);
|
|
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// Purpose: 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];
|
2023-06-19 22:42:25 +02:00
|
|
|
int nParamsRead = sscanf_s(pszValue, "%i %i %i %i",
|
|
|
|
&(nRGBA[0]), &(nRGBA[1]), &(nRGBA[2]), &(nRGBA[3]));
|
2023-03-28 01:05:23 +02:00
|
|
|
|
|
|
|
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.
|
2023-06-19 22:42:25 +02:00
|
|
|
unsigned char* pColorElement =
|
|
|
|
(reinterpret_cast<unsigned char*>(&m_Value.m_nValue));
|
|
|
|
|
2023-04-02 17:34:42 +02:00
|
|
|
pColorElement[0] = (unsigned char)nRGBA[0];
|
|
|
|
pColorElement[1] = (unsigned char)nRGBA[1];
|
|
|
|
pColorElement[2] = (unsigned char)nRGBA[2];
|
|
|
|
pColorElement[3] = (unsigned char)nRGBA[3];
|
2023-03-28 01:05:23 +02:00
|
|
|
|
|
|
|
// Copy that value into our float.
|
|
|
|
m_Value.m_fValue = static_cast<float>(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)
|
|
|
|
{
|
2023-06-26 22:34:24 +02:00
|
|
|
delete[] m_Value.m_pszString;
|
2023-03-28 01:05:23 +02:00
|
|
|
}
|
|
|
|
|
2023-06-26 22:34:24 +02:00
|
|
|
m_Value.m_pszString = new char[len];
|
2023-03-28 01:05:23 +02:00
|
|
|
m_Value.m_iStringLength = len;
|
|
|
|
}
|
|
|
|
|
|
|
|
memcpy(reinterpret_cast<void*>(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)
|
|
|
|
{
|
2023-06-19 22:42:25 +02:00
|
|
|
Warning(eDLL_T::ENGINE, "%s: Called with NULL callback; ignoring!!!\n",
|
|
|
|
__FUNCTION__);
|
2023-03-28 01:05:23 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-06-19 22:42:25 +02:00
|
|
|
if (m_pParent->m_fnChangeCallbacks.Find(callback)
|
|
|
|
!= m_pParent->m_fnChangeCallbacks.InvalidIndex())
|
2023-03-28 01:05:23 +02:00
|
|
|
{
|
|
|
|
// Same ptr added twice, sigh...
|
2023-06-19 22:42:25 +02:00
|
|
|
Warning(eDLL_T::ENGINE, "%s: Ignoring duplicate change callback!!!\n",
|
|
|
|
__FUNCTION__);
|
2023-03-28 01:05:23 +02:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2023-07-03 13:48:13 +02:00
|
|
|
#define SET_CONVARFLAG(x, y) SetFlag(FCVAR_##x, #x, y)
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// Purpose:
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
ConVarFlags::ConVarFlags() : m_StringToFlags(DefLessFunc(const char*))
|
|
|
|
{
|
|
|
|
m_Count = 0;
|
|
|
|
|
|
|
|
SET_CONVARFLAG(NONE, "none");
|
|
|
|
SET_CONVARFLAG(UNREGISTERED, "unregistered");
|
|
|
|
SET_CONVARFLAG(DEVELOPMENTONLY, "development_only");
|
|
|
|
SET_CONVARFLAG(GAMEDLL, "server");
|
|
|
|
SET_CONVARFLAG(CLIENTDLL, "client");
|
|
|
|
SET_CONVARFLAG(HIDDEN, "hidden");
|
|
|
|
SET_CONVARFLAG(PROTECTED, "protected");
|
|
|
|
SET_CONVARFLAG(SPONLY, "singleplayer");
|
|
|
|
SET_CONVARFLAG(ARCHIVE, "archive");
|
|
|
|
SET_CONVARFLAG(NOTIFY, "notify");
|
|
|
|
SET_CONVARFLAG(USERINFO, "userinfo");
|
|
|
|
SET_CONVARFLAG(PRINTABLEONLY, "printable_only");
|
|
|
|
SET_CONVARFLAG(UNLOGGED, "unlogged");
|
|
|
|
SET_CONVARFLAG(NEVER_AS_STRING, "never_as_string");
|
|
|
|
SET_CONVARFLAG(REPLICATED, "replicated");
|
|
|
|
SET_CONVARFLAG(CHEAT, "cheat");
|
|
|
|
SET_CONVARFLAG(SS, "splitscreen");
|
|
|
|
SET_CONVARFLAG(DEMO, "demo");
|
|
|
|
SET_CONVARFLAG(DONTRECORD, "dont_record");
|
|
|
|
SET_CONVARFLAG(SS_ADDED, "splitscreen_added");
|
|
|
|
SET_CONVARFLAG(RELEASE, "release");
|
|
|
|
SET_CONVARFLAG(RELOAD_MATERIALS, "reload_materials");
|
|
|
|
SET_CONVARFLAG(RELOAD_TEXTURES, "reload_textures");
|
|
|
|
SET_CONVARFLAG(NOT_CONNECTED, "not_connected");
|
2023-07-20 21:02:27 +02:00
|
|
|
SET_CONVARFLAG(MATERIAL_SYSTEM_THREAD, "material_system_thread");
|
2023-07-03 13:48:13 +02:00
|
|
|
SET_CONVARFLAG(ARCHIVE_PLAYERPROFILE, "playerprofile");
|
2023-07-20 21:02:27 +02:00
|
|
|
SET_CONVARFLAG(ACCESSIBLE_FROM_THREADS, "accessible_from_threads");
|
|
|
|
SET_CONVARFLAG(STUDIO_SYSTEM, "studio_system");
|
|
|
|
SET_CONVARFLAG(SERVER_FRAME_THREAD, "server_frame_thread");
|
2023-07-03 13:48:13 +02:00
|
|
|
SET_CONVARFLAG(SERVER_CAN_EXECUTE, "server_can_execute");
|
|
|
|
SET_CONVARFLAG(SERVER_CANNOT_QUERY, "server_cannot_query");
|
|
|
|
SET_CONVARFLAG(CLIENTCMD_CAN_EXECUTE, "clientcmd_can_execute");
|
2023-07-20 21:02:27 +02:00
|
|
|
SET_CONVARFLAG(PLATFORM_SYSTEM, "platform_system");
|
2023-07-03 13:48:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// Purpose:
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
void ConVarFlags::SetFlag(const int nFlag, const char* szDesc, const char* szShortDesc)
|
|
|
|
{
|
|
|
|
Assert(m_Count < SDK_ARRAYSIZE(m_FlagsToDesc));
|
|
|
|
|
|
|
|
m_StringToFlags.Insert(szDesc, nFlag);
|
|
|
|
m_FlagsToDesc[m_Count] = { nFlag, szDesc, szShortDesc };
|
|
|
|
|
|
|
|
m_Count++;
|
|
|
|
}
|
|
|
|
|
|
|
|
ConVarFlags g_ConVarFlags;
|
|
|
|
|
2023-05-02 19:26:49 +01:00
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// Purpose: Parse input flag string into bitfield
|
2023-07-03 13:48:13 +02:00
|
|
|
// Input : *pszFlags -
|
|
|
|
// &nFlags -
|
|
|
|
// *pszConVarName -
|
2023-05-02 19:26:49 +01:00
|
|
|
//-----------------------------------------------------------------------------
|
2023-07-03 13:48:13 +02:00
|
|
|
bool ConVar_ParseFlagString(const char* pszFlags, int& nFlags, const char* pszConVarName)
|
2023-05-02 19:26:49 +01:00
|
|
|
{
|
2023-07-03 13:48:13 +02:00
|
|
|
size_t len = V_strlen(pszFlags);
|
2023-05-14 02:11:29 +02:00
|
|
|
int flags = FCVAR_NONE;
|
2023-05-02 19:26:49 +01:00
|
|
|
|
2023-07-03 13:48:13 +02:00
|
|
|
CUtlString sFlag;
|
|
|
|
|
2023-05-14 02:11:29 +02:00
|
|
|
for (size_t i = 0; i < len; ++i)
|
2023-05-02 19:26:49 +01:00
|
|
|
{
|
|
|
|
char c = pszFlags[i];
|
|
|
|
|
2023-07-03 13:48:13 +02:00
|
|
|
if (V_isspace(c))
|
2023-05-02 19:26:49 +01:00
|
|
|
continue;
|
|
|
|
|
|
|
|
if (c != '|')
|
|
|
|
sFlag += c;
|
|
|
|
|
|
|
|
if (c == '|' || i == len - 1)
|
|
|
|
{
|
|
|
|
if (sFlag == "")
|
|
|
|
continue;
|
|
|
|
|
2023-07-03 13:48:13 +02:00
|
|
|
int find = g_ConVarFlags.m_StringToFlags.FindElement(sFlag.Get(), -1);
|
|
|
|
if (find == -1)
|
2023-05-02 19:26:49 +01:00
|
|
|
{
|
2023-06-19 22:42:25 +02:00
|
|
|
Warning(eDLL_T::ENGINE,
|
|
|
|
"%s: Attempted to parse invalid flag '%s' for convar '%s'\n",
|
2023-07-03 13:48:13 +02:00
|
|
|
__FUNCTION__, sFlag.Get(), pszConVarName);
|
2023-06-19 22:42:25 +02:00
|
|
|
|
2023-05-02 19:26:49 +01:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2023-07-03 13:48:13 +02:00
|
|
|
flags |= find;
|
2023-05-02 19:26:49 +01:00
|
|
|
sFlag = "";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
nFlags = flags;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2023-03-28 01:05:23 +02:00
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// Purpose:
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
void ConVar_AppendFlags(ConCommandBase* var, char* buf, size_t bufsize)
|
|
|
|
{
|
2023-07-03 13:48:13 +02:00
|
|
|
for (int i = 0; i < ARRAYSIZE(g_ConVarFlags.m_FlagsToDesc); ++i)
|
2023-03-28 01:05:23 +02:00
|
|
|
{
|
2023-07-03 13:48:13 +02:00
|
|
|
const ConVarFlags::FlagDesc_t& info = g_ConVarFlags.m_FlagsToDesc[i];
|
|
|
|
if (var->IsFlagSet(info.bit))
|
2023-03-28 01:05:23 +02:00
|
|
|
{
|
|
|
|
char append[128];
|
2023-07-03 13:48:13 +02:00
|
|
|
V_snprintf(append, sizeof(append), " %s", info.shortdesc);
|
2023-03-28 01:05:23 +02:00
|
|
|
V_strncat(buf, append, bufsize);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// Purpose:
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
void ConVar_PrintDescription(ConCommandBase* pVar)
|
|
|
|
{
|
|
|
|
bool bMin, bMax;
|
|
|
|
float fMin, fMax;
|
|
|
|
const char* pStr;
|
|
|
|
|
|
|
|
Assert(pVar);
|
|
|
|
|
|
|
|
Color clr(255, 100, 100, 255);
|
|
|
|
|
|
|
|
char outstr[4096];
|
|
|
|
outstr[0] = 0;
|
|
|
|
|
|
|
|
if (!pVar->IsCommand())
|
|
|
|
{
|
|
|
|
ConVar* var = (ConVar*)pVar;
|
|
|
|
|
|
|
|
bMin = var->GetMin(fMin);
|
|
|
|
bMax = var->GetMax(fMax);
|
|
|
|
|
|
|
|
const char* value = NULL;
|
|
|
|
char tempVal[256];
|
|
|
|
|
|
|
|
if (var->IsFlagSet(FCVAR_NEVER_AS_STRING))
|
|
|
|
{
|
|
|
|
value = tempVal;
|
|
|
|
|
|
|
|
int intVal = var->GetInt();
|
|
|
|
float floatVal = var->GetFloat();
|
|
|
|
|
|
|
|
if (fabs((float)intVal - floatVal) < 0.000001)
|
|
|
|
{
|
|
|
|
V_snprintf(tempVal, sizeof(tempVal), "%d", intVal);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
V_snprintf(tempVal, sizeof(tempVal), "%f", floatVal);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
value = var->GetString();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (value)
|
|
|
|
{
|
|
|
|
AppendPrintf(outstr, sizeof(outstr), "\"%s\" = \"%s\"", var->GetName(), value);
|
|
|
|
|
|
|
|
if (V_stricmp(value, var->GetDefault()))
|
|
|
|
{
|
|
|
|
AppendPrintf(outstr, sizeof(outstr), " ( def. \"%s\" )", var->GetDefault());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (bMin)
|
|
|
|
{
|
|
|
|
AppendPrintf(outstr, sizeof(outstr), " min. %f", fMin);
|
|
|
|
}
|
|
|
|
if (bMax)
|
|
|
|
{
|
|
|
|
AppendPrintf(outstr, sizeof(outstr), " max. %f", fMax);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ConCommand* var = (ConCommand*)pVar;
|
|
|
|
|
|
|
|
AppendPrintf(outstr, sizeof(outstr), "\"%s\" ", var->GetName());
|
|
|
|
}
|
|
|
|
|
|
|
|
ConVar_AppendFlags(pVar, outstr, sizeof(outstr));
|
|
|
|
|
|
|
|
pStr = pVar->GetHelpText();
|
|
|
|
if (pStr && *pStr)
|
|
|
|
{
|
|
|
|
DevMsg(eDLL_T::ENGINE, "%-80s - %.80s\n", outstr, pStr);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
DevMsg(eDLL_T::ENGINE, "%-80s\n", outstr);
|
|
|
|
}
|
|
|
|
}
|
2021-12-25 22:36:38 +01:00
|
|
|
|
2022-08-13 12:39:57 +02:00
|
|
|
static void PrintListHeader(FileHandle_t& f)
|
|
|
|
{
|
|
|
|
char csvflagstr[1024];
|
|
|
|
|
|
|
|
csvflagstr[0] = 0;
|
|
|
|
|
2023-07-03 13:48:13 +02:00
|
|
|
int c = ARRAYSIZE(g_ConVarFlags.m_FlagsToDesc);
|
2022-08-13 12:39:57 +02:00
|
|
|
for (int i = 0; i < c; ++i)
|
|
|
|
{
|
|
|
|
char csvf[64];
|
|
|
|
|
2023-07-03 13:48:13 +02:00
|
|
|
ConVarFlags::FlagDesc_t& entry = g_ConVarFlags.m_FlagsToDesc[i];
|
2022-08-28 23:54:52 +02:00
|
|
|
Q_snprintf(csvf, sizeof(csvf), "\"%s\",", entry.desc);
|
|
|
|
Q_strncat(csvflagstr, csvf, sizeof(csvflagstr) - strlen(csvflagstr) - 1);
|
2022-08-13 12:39:57 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
FileSystem()->FPrintf(f, "\"%s\",\"%s\",%s,\"%s\"\n", "Name", "Value", csvflagstr, "Help Text");
|
|
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// Purpose:
|
|
|
|
// Input : *var -
|
|
|
|
// *f -
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
static void PrintCvar(ConVar* var, bool logging, FileHandle_t& fh)
|
|
|
|
{
|
|
|
|
char flagstr[128];
|
|
|
|
char csvflagstr[1024];
|
|
|
|
|
|
|
|
flagstr[0] = 0;
|
|
|
|
csvflagstr[0] = 0;
|
|
|
|
|
2023-07-03 13:48:13 +02:00
|
|
|
int c = ARRAYSIZE(g_ConVarFlags.m_FlagsToDesc);
|
2022-08-13 12:39:57 +02:00
|
|
|
for (int i = 0; i < c; ++i)
|
|
|
|
{
|
|
|
|
char f[32];
|
|
|
|
char csvf[64];
|
2022-08-28 23:54:52 +02:00
|
|
|
size_t flen = sizeof(csvflagstr) - strlen(csvflagstr) - 1;
|
2022-08-13 12:39:57 +02:00
|
|
|
|
2023-07-03 13:48:13 +02:00
|
|
|
ConVarFlags::FlagDesc_t& entry = g_ConVarFlags.m_FlagsToDesc[i];
|
2022-08-13 12:39:57 +02:00
|
|
|
if (var->IsFlagSet(entry.bit))
|
|
|
|
{
|
2022-08-28 23:54:52 +02:00
|
|
|
Q_snprintf(f, sizeof(f), ", %s", entry.shortdesc);
|
|
|
|
Q_strncat(flagstr, f, sizeof(flagstr) - strlen(flagstr) - 1);
|
|
|
|
Q_snprintf(csvf, sizeof(csvf), "\"%s\",", entry.desc);
|
2022-08-13 12:39:57 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2022-08-28 23:54:52 +02:00
|
|
|
Q_snprintf(csvf, sizeof(csvf), ",");
|
2022-08-13 12:39:57 +02:00
|
|
|
}
|
|
|
|
|
2022-08-28 23:54:52 +02:00
|
|
|
Q_strncat(csvflagstr, csvf, flen);
|
2022-08-13 12:39:57 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
char valstr[32];
|
|
|
|
char tempbuff[512] = { 0 };
|
|
|
|
|
|
|
|
// Clean up integers
|
|
|
|
if (var->GetInt() == (int)var->GetFloat())
|
|
|
|
{
|
2022-08-28 23:54:52 +02:00
|
|
|
Q_snprintf(valstr, sizeof(valstr), "%-8i", var->GetInt());
|
2022-08-13 12:39:57 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2022-08-28 23:54:52 +02:00
|
|
|
Q_snprintf(valstr, sizeof(valstr), "%-8.3f", var->GetFloat());
|
2022-08-13 12:39:57 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// Print to console
|
2023-06-19 22:42:25 +02:00
|
|
|
DevMsg(eDLL_T::ENGINE, "%-40s : %-8s : %-16s : %s\n", var->GetName(),
|
|
|
|
valstr, flagstr, StripTabsAndReturns(var->GetHelpText(), tempbuff, sizeof(tempbuff)));
|
2022-08-13 12:39:57 +02:00
|
|
|
if (logging)
|
|
|
|
{
|
2023-06-19 22:42:25 +02:00
|
|
|
FileSystem()->FPrintf(fh, "\"%s\",\"%s\",%s,\"%s\"\n", var->GetName(),
|
|
|
|
valstr, csvflagstr, StripQuotes(var->GetHelpText(), tempbuff, sizeof(tempbuff)));
|
2022-08-13 12:39:57 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// Purpose:
|
|
|
|
// Input :
|
|
|
|
// Output :
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
static void PrintCommand(const ConCommand* cmd, bool logging, FileHandle_t& f)
|
|
|
|
{
|
|
|
|
// Print to console
|
|
|
|
char tempbuff[512] = { 0 };
|
2023-06-19 22:42:25 +02:00
|
|
|
DevMsg(eDLL_T::ENGINE, "%-40s : %-8s : %-16s : %s\n", cmd->GetName(),
|
|
|
|
"cmd", "", StripTabsAndReturns(cmd->GetHelpText(), tempbuff, sizeof(tempbuff)));
|
|
|
|
|
2022-08-13 12:39:57 +02:00
|
|
|
if (logging)
|
|
|
|
{
|
|
|
|
char emptyflags[256];
|
|
|
|
|
|
|
|
emptyflags[0] = 0;
|
|
|
|
|
2023-07-03 13:48:13 +02:00
|
|
|
int c = ARRAYSIZE(g_ConVarFlags.m_FlagsToDesc);
|
2022-08-13 12:39:57 +02:00
|
|
|
for (int i = 0; i < c; ++i)
|
|
|
|
{
|
|
|
|
char csvf[64];
|
2022-08-28 23:54:52 +02:00
|
|
|
size_t len = sizeof(emptyflags) - strlen(emptyflags) - 1;
|
|
|
|
|
2022-08-13 12:39:57 +02:00
|
|
|
Q_snprintf(csvf, sizeof(csvf), ",");
|
2022-08-28 23:54:52 +02:00
|
|
|
Q_strncat(emptyflags, csvf, len);
|
2022-08-13 12:39:57 +02:00
|
|
|
}
|
|
|
|
// Names staring with +/- need to be wrapped in single quotes
|
2023-04-28 23:48:30 +02:00
|
|
|
char nameBuf[256];
|
|
|
|
Q_snprintf(nameBuf, sizeof(nameBuf), "%s", cmd->GetName());
|
|
|
|
if (nameBuf[0] == '+' || nameBuf[0] == '-')
|
2022-08-13 12:39:57 +02:00
|
|
|
{
|
2023-04-28 23:48:30 +02:00
|
|
|
Q_snprintf(nameBuf, sizeof(nameBuf), "'%s'", cmd->GetName());
|
2022-08-13 12:39:57 +02:00
|
|
|
}
|
2023-06-19 22:42:25 +02:00
|
|
|
FileSystem()->FPrintf(f, "\"%s\",\"%s\",%s,\"%s\"\n", nameBuf, "cmd",
|
|
|
|
emptyflags, StripQuotes(cmd->GetHelpText(), tempbuff, sizeof(tempbuff)));
|
2022-08-13 12:39:57 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// Purpose:
|
|
|
|
// Input :
|
|
|
|
// Output : bool
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
static bool ConCommandBaseLessFunc(ConCommandBase* const& lhs, ConCommandBase* const& rhs)
|
|
|
|
{
|
|
|
|
const char* left = lhs->GetName();
|
|
|
|
const char* right = rhs->GetName();
|
|
|
|
|
|
|
|
if (*left == '-' || *left == '+')
|
|
|
|
left++;
|
|
|
|
if (*right == '-' || *right == '+')
|
|
|
|
right++;
|
|
|
|
|
|
|
|
return (Q_stricmp(left, right) < 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// Singleton CCvarUtilities
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
static CCvarUtilities g_CvarUtilities;
|
|
|
|
CCvarUtilities* cv = &g_CvarUtilities;
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// Purpose:
|
|
|
|
// Input :
|
|
|
|
// Output : int
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
int CCvarUtilities::CountVariablesWithFlags(int flags)
|
|
|
|
{
|
|
|
|
int i = 0;
|
|
|
|
ConCommandBase* var;
|
2022-08-14 02:51:15 +02:00
|
|
|
CCvar::CCVarIteratorInternal* itint = g_pCVar->FactoryInternalIterator();
|
2022-08-13 12:39:57 +02:00
|
|
|
|
2022-08-14 02:51:15 +02:00
|
|
|
for (itint->SetFirst(); itint->IsValid(); itint->Next()) // Loop through cvars...
|
2022-08-13 12:39:57 +02:00
|
|
|
{
|
2022-08-14 02:51:15 +02:00
|
|
|
var = itint->Get();
|
2022-08-13 12:39:57 +02:00
|
|
|
if (!var->IsCommand())
|
|
|
|
{
|
|
|
|
if (var->IsFlagSet(flags))
|
|
|
|
{
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-06-26 22:34:24 +02:00
|
|
|
delete itint;
|
2022-08-13 12:39:57 +02:00
|
|
|
return i;
|
|
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// Purpose: Removes the FCVAR_DEVELOPMENTONLY flag from all cvars, making them accessible
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
void CCvarUtilities::EnableDevCvars()
|
|
|
|
{
|
|
|
|
// Loop through cvars...
|
2022-08-14 02:51:15 +02:00
|
|
|
CCvar::CCVarIteratorInternal* itint = g_pCVar->FactoryInternalIterator();
|
2022-08-13 12:39:57 +02:00
|
|
|
|
2022-08-14 02:51:15 +02:00
|
|
|
for (itint->SetFirst(); itint->IsValid(); itint->Next())
|
2022-08-13 12:39:57 +02:00
|
|
|
{
|
|
|
|
// remove flag from all cvars
|
2022-08-14 02:51:15 +02:00
|
|
|
ConCommandBase* pCommandBase = itint->Get();
|
2022-08-13 12:39:57 +02:00
|
|
|
pCommandBase->RemoveFlags(FCVAR_DEVELOPMENTONLY);
|
|
|
|
}
|
|
|
|
|
2023-06-26 22:34:24 +02:00
|
|
|
delete itint;
|
2022-08-13 19:41:45 +02:00
|
|
|
}
|
|
|
|
|
2022-08-13 12:39:57 +02:00
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// Purpose:
|
|
|
|
// Output : void CCvar::CvarList_f
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
void CCvarUtilities::CvarList(const CCommand& args)
|
|
|
|
{
|
|
|
|
ConCommandBase* var; // Temporary Pointer to cvars
|
2022-11-24 15:41:52 +01:00
|
|
|
int64 iArgs; // Argument count
|
2022-08-13 12:39:57 +02:00
|
|
|
const char* partial = NULL; // Partial cvar to search for...
|
|
|
|
// E.eg
|
2022-11-24 15:41:52 +01:00
|
|
|
size_t ipLen = 0; // Length of the partial cvar
|
2022-08-13 12:39:57 +02:00
|
|
|
|
|
|
|
FileHandle_t f = FILESYSTEM_INVALID_HANDLE; // FilePointer for logging
|
|
|
|
bool bLogging = false;
|
|
|
|
// Are we logging?
|
|
|
|
iArgs = args.ArgC(); // Get count
|
|
|
|
|
|
|
|
// Print usage?
|
|
|
|
if (iArgs == 2 && !Q_strcasecmp(args[1], "?"))
|
|
|
|
{
|
2022-11-02 14:30:43 +01:00
|
|
|
DevMsg(eDLL_T::ENGINE, "convar_list: [ log logfile ] [ partial ]\n");
|
2022-08-13 12:39:57 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!Q_strcasecmp(args[1], "log") && iArgs >= 3)
|
|
|
|
{
|
|
|
|
char fn[256];
|
|
|
|
Q_snprintf(fn, sizeof(fn), "%s", args[2]);
|
|
|
|
f = FileSystem()->Open(fn, "wb", nullptr, 0);
|
|
|
|
if (f)
|
|
|
|
{
|
|
|
|
bLogging = true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
DevMsg(eDLL_T::ENGINE, "Couldn't open '%s' for writing!\n", fn);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (iArgs == 4)
|
|
|
|
{
|
|
|
|
partial = args[3];
|
|
|
|
ipLen = Q_strlen(partial);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
partial = args[1];
|
|
|
|
ipLen = Q_strlen(partial);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Banner
|
2022-11-02 14:30:43 +01:00
|
|
|
DevMsg(eDLL_T::ENGINE, "convar list\n--------------\n");
|
2022-08-13 12:39:57 +02:00
|
|
|
|
|
|
|
CUtlRBTree< ConCommandBase* > sorted(0, 0, ConCommandBaseLessFunc);
|
2022-08-14 02:51:15 +02:00
|
|
|
CCvar::CCVarIteratorInternal* itint = g_pCVar->FactoryInternalIterator();
|
2022-08-13 12:39:57 +02:00
|
|
|
|
2022-08-14 02:51:15 +02:00
|
|
|
for (itint->SetFirst(); itint->IsValid(); itint->Next()) // Loop through all instances.
|
2022-08-13 12:39:57 +02:00
|
|
|
{
|
2022-08-14 02:51:15 +02:00
|
|
|
var = itint->Get();
|
2022-08-13 12:39:57 +02:00
|
|
|
|
|
|
|
if (!var->IsFlagSet(FCVAR_DEVELOPMENTONLY) &&
|
|
|
|
!var->IsFlagSet(FCVAR_HIDDEN))
|
|
|
|
{
|
|
|
|
bool print = false;
|
|
|
|
|
|
|
|
if (partial) // Partial string searching?
|
|
|
|
{
|
|
|
|
if (!Q_strncasecmp(var->GetName(), partial, ipLen))
|
|
|
|
{
|
|
|
|
print = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
print = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (print)
|
|
|
|
{
|
|
|
|
sorted.Insert(var);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-06-26 22:34:24 +02:00
|
|
|
delete itint;
|
2022-08-14 02:51:15 +02:00
|
|
|
|
2022-08-13 12:39:57 +02:00
|
|
|
if (bLogging)
|
|
|
|
{
|
|
|
|
PrintListHeader(f);
|
|
|
|
}
|
2023-06-19 22:42:25 +02:00
|
|
|
for (unsigned short i = sorted.FirstInorder();
|
|
|
|
i != sorted.InvalidIndex(); i = sorted.NextInorder(i))
|
2022-08-13 12:39:57 +02:00
|
|
|
{
|
|
|
|
var = sorted[i];
|
|
|
|
if (var->IsCommand())
|
|
|
|
{
|
|
|
|
PrintCommand((ConCommand*)var, bLogging, f);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
PrintCvar((ConVar*)var, bLogging, f);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Show total and syntax help...
|
|
|
|
if (partial && partial[0])
|
|
|
|
{
|
2023-06-19 22:42:25 +02:00
|
|
|
DevMsg(eDLL_T::ENGINE, "--------------\n%3i convars/concommands for [%s]\n",
|
|
|
|
sorted.Count(), partial);
|
2022-08-13 12:39:57 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2023-06-19 22:42:25 +02:00
|
|
|
DevMsg(eDLL_T::ENGINE, "--------------\n%3i total convars/concommands\n",
|
|
|
|
sorted.Count());
|
2022-08-13 12:39:57 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (bLogging)
|
|
|
|
{
|
|
|
|
FileSystem()->Close(f);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// Purpose:
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
void CCvarUtilities::CvarHelp(const CCommand& args)
|
|
|
|
{
|
|
|
|
const char* search;
|
|
|
|
ConCommandBase* var;
|
|
|
|
|
|
|
|
if (args.ArgC() != 2)
|
|
|
|
{
|
|
|
|
DevMsg(eDLL_T::ENGINE, "Usage: help <cvarname>\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get name of var to find
|
|
|
|
search = args[1];
|
|
|
|
|
|
|
|
// Search for it
|
|
|
|
var = g_pCVar->FindCommandBase(search);
|
|
|
|
if (!var)
|
|
|
|
{
|
2022-08-13 12:53:08 +02:00
|
|
|
DevMsg(eDLL_T::ENGINE, "help: no cvar or command named %s\n", search);
|
2022-08-13 12:39:57 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Show info
|
|
|
|
ConVar_PrintDescription(var);
|
|
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// Purpose:
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
void CCvarUtilities::CvarDifferences(const CCommand& args)
|
|
|
|
{
|
2022-08-14 02:51:15 +02:00
|
|
|
CCvar::CCVarIteratorInternal* itint = g_pCVar->FactoryInternalIterator();
|
2022-08-13 12:53:08 +02:00
|
|
|
int i = 0;
|
2022-08-13 12:39:57 +02:00
|
|
|
|
2022-08-14 02:51:15 +02:00
|
|
|
for (itint->SetFirst(); itint->IsValid(); itint->Next()) // Loop through all instances.
|
2022-08-13 12:39:57 +02:00
|
|
|
{
|
2022-08-14 02:51:15 +02:00
|
|
|
ConCommandBase* pCommandBase = itint->Get();
|
2022-08-13 12:39:57 +02:00
|
|
|
|
|
|
|
if (!pCommandBase->IsCommand() &&
|
|
|
|
!pCommandBase->IsFlagSet(FCVAR_HIDDEN))
|
|
|
|
{
|
|
|
|
ConVar* pConVar = reinterpret_cast<ConVar*>(pCommandBase);
|
|
|
|
|
2022-08-13 12:53:08 +02:00
|
|
|
if (V_strcmp(pConVar->GetString(), "FCVAR_NEVER_AS_STRING") != NULL)
|
2022-08-13 12:39:57 +02:00
|
|
|
{
|
2022-08-13 12:53:08 +02:00
|
|
|
if (V_stricmp(pConVar->GetString(), pConVar->GetDefault()) != NULL)
|
|
|
|
{
|
|
|
|
ConVar_PrintDescription(pConVar);
|
|
|
|
i++;
|
|
|
|
}
|
2022-08-13 12:39:57 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-08-14 02:51:15 +02:00
|
|
|
|
2023-06-26 22:34:24 +02:00
|
|
|
delete itint;
|
2022-08-13 12:53:08 +02:00
|
|
|
DevMsg(eDLL_T::ENGINE, "--------------\n%3i changed convars\n", i);
|
2022-08-13 12:39:57 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// Purpose:
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
void CCvarUtilities::CvarFindFlags_f(const CCommand& args)
|
|
|
|
{
|
|
|
|
if (args.ArgC() < 2)
|
|
|
|
{
|
2022-11-02 14:30:43 +01:00
|
|
|
DevMsg(eDLL_T::ENGINE, "Usage: convar_findByFlags <string>\n");
|
2022-08-13 12:39:57 +02:00
|
|
|
DevMsg(eDLL_T::ENGINE, "Available flags to search for: \n");
|
|
|
|
|
2023-07-03 13:48:13 +02:00
|
|
|
for (int i = 0; i < ARRAYSIZE(g_ConVarFlags.m_FlagsToDesc); i++)
|
2022-08-13 12:39:57 +02:00
|
|
|
{
|
2023-07-03 13:48:13 +02:00
|
|
|
DevMsg(eDLL_T::ENGINE, " - %s\n", g_ConVarFlags.m_FlagsToDesc[i].desc);
|
2022-08-13 12:39:57 +02:00
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get substring to find
|
|
|
|
const char* search = args[1];
|
|
|
|
ConCommandBase* var;
|
|
|
|
|
|
|
|
// Loop through vars and print out findings
|
2022-08-14 02:51:15 +02:00
|
|
|
CCvar::CCVarIteratorInternal* itint = g_pCVar->FactoryInternalIterator();
|
2022-08-13 12:39:57 +02:00
|
|
|
|
2022-08-14 02:51:15 +02:00
|
|
|
for (itint->SetFirst(); itint->IsValid(); itint->Next())
|
2022-08-13 12:39:57 +02:00
|
|
|
{
|
2022-08-14 02:51:15 +02:00
|
|
|
var = itint->Get();
|
2022-08-13 12:39:57 +02:00
|
|
|
|
|
|
|
if (!var->IsFlagSet(FCVAR_DEVELOPMENTONLY) || !var->IsFlagSet(FCVAR_HIDDEN))
|
|
|
|
{
|
2023-07-03 13:48:13 +02:00
|
|
|
for (int i = 0; i < ARRAYSIZE(g_ConVarFlags.m_FlagsToDesc); i++)
|
2022-08-13 12:39:57 +02:00
|
|
|
{
|
2023-07-03 13:48:13 +02:00
|
|
|
if (var->IsFlagSet(g_ConVarFlags.m_FlagsToDesc[i].bit))
|
2022-08-13 12:39:57 +02:00
|
|
|
{
|
2023-07-03 13:48:13 +02:00
|
|
|
if (V_stristr(g_ConVarFlags.m_FlagsToDesc[i].desc, search))
|
2022-08-13 12:39:57 +02:00
|
|
|
{
|
|
|
|
ConVar_PrintDescription(var);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-08-14 02:51:15 +02:00
|
|
|
|
2023-06-26 22:34:24 +02:00
|
|
|
delete itint;
|
2022-08-13 12:39:57 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// Purpose:
|
|
|
|
//-----------------------------------------------------------------------------
|
2023-06-19 22:42:25 +02:00
|
|
|
int CCvarUtilities::CvarFindFlagsCompletionCallback(const char* partial,
|
|
|
|
char commands[COMMAND_COMPLETION_MAXITEMS][COMMAND_COMPLETION_ITEM_LENGTH])
|
2022-08-13 12:39:57 +02:00
|
|
|
{
|
2023-07-03 13:48:13 +02:00
|
|
|
int flagC = ARRAYSIZE(g_ConVarFlags.m_FlagsToDesc);
|
2022-08-13 12:39:57 +02:00
|
|
|
char const* pcmd = "findflags ";
|
2022-11-24 15:41:52 +01:00
|
|
|
size_t len = Q_strlen(partial);
|
2022-08-13 12:39:57 +02:00
|
|
|
|
|
|
|
if (len < Q_strlen(pcmd))
|
|
|
|
{
|
|
|
|
int i = 0;
|
|
|
|
for (; i < MIN(flagC, COMMAND_COMPLETION_MAXITEMS); i++)
|
|
|
|
{
|
2023-06-19 22:42:25 +02:00
|
|
|
Q_snprintf(commands[i], sizeof(commands[i]), "%s %s",
|
2023-07-03 13:48:13 +02:00
|
|
|
pcmd, g_ConVarFlags.m_FlagsToDesc[i].desc);
|
2022-08-13 12:39:57 +02:00
|
|
|
Q_strlower(commands[i]);
|
|
|
|
}
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
|
|
|
|
char const* pSub = partial + Q_strlen(pcmd);
|
2022-11-24 15:41:52 +01:00
|
|
|
size_t nSubLen = Q_strlen(pSub);
|
2022-08-13 12:39:57 +02:00
|
|
|
|
|
|
|
int values = 0;
|
|
|
|
for (int i = 0; i < flagC; ++i)
|
|
|
|
{
|
2023-07-03 13:48:13 +02:00
|
|
|
if (Q_strnicmp(g_ConVarFlags.m_FlagsToDesc[i].desc, pSub, nSubLen))
|
2022-08-13 12:39:57 +02:00
|
|
|
continue;
|
|
|
|
|
2023-06-19 22:42:25 +02:00
|
|
|
Q_snprintf(commands[values], sizeof(commands[values]),
|
2023-07-03 13:48:13 +02:00
|
|
|
"%s %s", pcmd, g_ConVarFlags.m_FlagsToDesc[i].desc);
|
2022-08-13 12:39:57 +02:00
|
|
|
Q_strlower(commands[values]);
|
|
|
|
++values;
|
|
|
|
|
|
|
|
if (values >= COMMAND_COMPLETION_MAXITEMS)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return values;
|
|
|
|
}
|
|
|
|
|
2021-12-25 22:36:38 +01:00
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
2022-08-13 19:41:45 +02:00
|
|
|
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.
|
|
|
|
//-----------------------------------------------------------------------------
|
2023-04-01 13:09:02 +02:00
|
|
|
void CConCommandHash::Remove(CCommandHashHandle_t hHash) /*RESTRICT*/
|
2022-08-13 19:41:45 +02:00
|
|
|
{
|
2023-04-01 13:09:02 +02:00
|
|
|
HashEntry_t* /*RESTRICT*/ entry = &m_aDataPool[hHash];
|
2022-08-13 19:41:45 +02:00
|
|
|
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
|
|
|
|
//-----------------------------------------------------------------------------
|
2023-06-19 22:42:25 +02:00
|
|
|
CConCommandHash::CCommandHashHandle_t CConCommandHash::Find(
|
|
|
|
const char* name, HashKey_t hashkey) const /*RESTRICT*/
|
2022-08-13 19:41:45 +02:00
|
|
|
{
|
|
|
|
// hash the "key" - get the correct hash table "bucket"
|
|
|
|
int iBucket = hashkey & kBUCKETMASK;
|
|
|
|
|
2023-06-19 22:42:25 +02:00
|
|
|
for (datapool_t::IndexLocalType_t iElement = m_aBuckets[iBucket];
|
|
|
|
iElement != m_aDataPool.InvalidIndex(); iElement = m_aDataPool.Next(iElement))
|
2022-08-13 19:41:45 +02:00
|
|
|
{
|
|
|
|
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.
|
|
|
|
//-----------------------------------------------------------------------------
|
2023-04-01 13:09:02 +02:00
|
|
|
CConCommandHash::CCommandHashHandle_t CConCommandHash::Find(const ConCommandBase* cmd) const /*RESTRICT*/
|
2022-08-13 19:41:45 +02:00
|
|
|
{
|
|
|
|
// Set this #if to 1 if the assert at bottom starts whining --
|
|
|
|
// that indicates that a console command is being double-registered,
|
2022-09-09 19:47:31 +02:00
|
|
|
// or something similarly non-fatally bad. With this #if 1, we'll search
|
2022-08-13 19:41:45 +02:00
|
|
|
// 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
|
2023-06-19 22:42:25 +02:00
|
|
|
for (datapool_t::IndexLocalType_t iElement = m_aBuckets[iBucket];
|
|
|
|
iElement != m_aDataPool.InvalidIndex(); iElement = m_aDataPool.Next(iElement))
|
2022-08-13 19:41:45 +02:00
|
|
|
{
|
|
|
|
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());
|
|
|
|
|
2022-08-14 00:48:29 +02:00
|
|
|
Assert(InvalidHandle() == dbghand,
|
2022-08-13 19:41:45 +02:00
|
|
|
"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::ENGINE, "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::ENGINE, "%d: %d\n", iBucket, count);
|
|
|
|
total += count;
|
|
|
|
}
|
|
|
|
|
|
|
|
DevMsg(eDLL_T::ENGINE, "\tAverage: %.1f\n", total / ((float)(kNUM_BUCKETS)));
|
|
|
|
}
|
|
|
|
//#endif
|
2023-03-28 01:05:23 +02:00
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
void VCVar::Attach() const
|
|
|
|
{
|
|
|
|
DetourAttach((LPVOID*)&v_ConVar_PrintDescription, &ConVar_PrintDescription);
|
|
|
|
}
|
|
|
|
void VCVar::Detach() const
|
|
|
|
{
|
|
|
|
DetourDetach((LPVOID*)&v_ConVar_PrintDescription, &ConVar_PrintDescription);
|
|
|
|
}
|