Tier1: properly implement ConVar change callbacks

Change callbacks actually take a structure of 2 pointers, one being for the callback itself, and the other being 'userdata' which typically is used to sync the ConVar with VGUI slider elements. This issue was noticed after implementing the ADS scalars and attempting to hook them up to VGUI, only to find out it would crash due to this lacking detail. All change callback prototypes had to be adjusted.
This commit is contained in:
Kawe Mazidjatari 2024-08-05 00:45:30 +02:00
parent 2fd2873536
commit d95d071afd
12 changed files with 60 additions and 46 deletions

View File

@ -78,7 +78,7 @@
MP_GameMode_Changed_f
=====================
*/
void MP_GameMode_Changed_f(IConVar* pConVar, const char* pOldString)
void MP_GameMode_Changed_f(IConVar* pConVar, const char* pOldString, float flOldValue, ChangeUserData_t pUserData)
{
v_SetupGamemode(mp_gamemode->GetString());
}
@ -228,7 +228,7 @@ void VPK_Unmount_f(const CCommand& args)
FileSystem()->UnmountVPKFile(args.Arg(1));
}
void LanguageChanged_f(IConVar* pConVar, const char* pOldString)
void LanguageChanged_f(IConVar* pConVar, const char* pOldString, float flOldValue, ChangeUserData_t pUserData)
{
if (ConVar* pConVarRef = g_pCVar->FindVar(pConVar->GetName()))
{

View File

@ -9,7 +9,7 @@ inline void(*v__UIScript_Reset_f)();
#endif // !DEDICATED
///////////////////////////////////////////////////////////////////////////////
void MP_GameMode_Changed_f(IConVar* pConVar, const char* pOldString);
void MP_GameMode_Changed_f(IConVar* pConVar, const char* pOldString, float flOldValue, ChangeUserData_t pUserData);
#ifndef CLIENT_DLL
void Host_Changelevel_f(const CCommand& args);
#endif // !CLIENT_DLL
@ -19,9 +19,9 @@ void VPK_Mount_f(const CCommand& args);
void VPK_Unmount_f(const CCommand& args);
#ifndef DEDICATED
void GFX_NVN_Changed_f(IConVar* pConVar, const char* pOldString);
void GFX_NVN_Changed_f(IConVar* pConVar, const char* pOldString, float flOldValue, ChangeUserData_t pUserData);
#endif // !DEDICATED
void LanguageChanged_f(IConVar* pConVar, const char* pOldString);
void LanguageChanged_f(IConVar* pConVar, const char* pOldString, float flOldValue, ChangeUserData_t pUserData);
#ifndef DEDICATED
void Mat_CrossHair_f(const CCommand& args);
void Line_f(const CCommand& args);

View File

@ -273,11 +273,10 @@ void ConVar_InitShipped(void)
base_tickinterval_mp->RemoveFlags(FCVAR_DEVELOPMENTONLY);
mp_gamemode->RemoveFlags(FCVAR_DEVELOPMENTONLY);
mp_gamemode->RemoveChangeCallback(mp_gamemode->m_fnChangeCallbacks[0]);
mp_gamemode->InstallChangeCallback(MP_GameMode_Changed_f, false);
mp_gamemode->InstallChangeCallback(MP_GameMode_Changed_f, nullptr, false);
net_usesocketsforloopback->RemoveFlags(FCVAR_DEVELOPMENTONLY);
#ifndef DEDICATED
language_cvar->InstallChangeCallback(LanguageChanged_f, false);
language_cvar->InstallChangeCallback(LanguageChanged_f, nullptr, false);
#endif // !DEDICATED
}

View File

@ -18,8 +18,8 @@
//-----------------------------------------------------------------------------
// Purpose: console variables
//-----------------------------------------------------------------------------
static void RCON_AddressChanged_f(IConVar* pConVar, const char* pOldString);
static void RCON_InputOnlyChanged_f(IConVar* pConVar, const char* pOldString);
static void RCON_AddressChanged_f(IConVar* pConVar, const char* pOldString, float flOldValue, ChangeUserData_t pUserData);
static void RCON_InputOnlyChanged_f(IConVar* pConVar, const char* pOldString, float flOldValue, ChangeUserData_t pUserData);
static ConVar cl_rcon_address("cl_rcon_address", "", FCVAR_SERVER_CANNOT_QUERY | FCVAR_DONTRECORD | FCVAR_RELEASE, "Remote server access address (rcon client is disabled if empty)", &RCON_AddressChanged_f);
static ConVar cl_rcon_inputonly("cl_rcon_inputonly", "0", FCVAR_RELEASE, "Tells the rcon server whether or not we are input only.", RCON_InputOnlyChanged_f);
@ -254,7 +254,7 @@ RCON_AddressChanged_f
to it
=====================
*/
static void RCON_AddressChanged_f(IConVar* pConVar, const char* pOldString)
static void RCON_AddressChanged_f(IConVar* pConVar, const char* pOldString, float flOldValue, ChangeUserData_t pUserData)
{
if (ConVar* pConVarRef = g_pCVar->FindVar(pConVar->GetName()))
{
@ -290,7 +290,7 @@ RCON_InputOnlyChanged_f
changes
=====================
*/
static void RCON_InputOnlyChanged_f(IConVar* pConVar, const char* pOldString)
static void RCON_InputOnlyChanged_f(IConVar* pConVar, const char* pOldString, float flOldValue, ChangeUserData_t pUserData)
{
RCONClient()->RequestConsoleLog(RCONClient()->ShouldReceive());
}

View File

@ -37,7 +37,7 @@ static void NET_GenerateKey_f()
NET_GenerateKey();
}
void NET_UseRandomKeyChanged_f(IConVar* pConVar, const char* pOldString)
void NET_UseRandomKeyChanged_f(IConVar* pConVar, const char* pOldString, float flOldValue, ChangeUserData_t pUserData)
{
if (ConVar* pConVarRef = g_pCVar->FindVar(pConVar->GetName()))
{

View File

@ -29,10 +29,10 @@ static const char s_BannedMessage[] = "Go away.\n";
//-----------------------------------------------------------------------------
// Purpose: console variables
//-----------------------------------------------------------------------------
static void RCON_PasswordChanged_f(IConVar* pConVar, const char* pOldString);
static void RCON_WhiteListAddresChanged_f(IConVar* pConVar, const char* pOldString);
static void RCON_ConnectionCountChanged_f(IConVar* pConVar, const char* pOldString);
static void RCON_UseLoopbackSocketChanged_f(IConVar* pConVar, const char* pOldString);
static void RCON_PasswordChanged_f(IConVar* pConVar, const char* pOldString, float flOldValue, ChangeUserData_t pUserData);
static void RCON_WhiteListAddresChanged_f(IConVar* pConVar, const char* pOldString, float flOldValue, ChangeUserData_t pUserData);
static void RCON_ConnectionCountChanged_f(IConVar* pConVar, const char* pOldString, float flOldValue, ChangeUserData_t pUserData);
static void RCON_UseLoopbackSocketChanged_f(IConVar* pConVar, const char* pOldString, float flOldValue, ChangeUserData_t pUserData);
static ConVar sv_rcon_password("sv_rcon_password", "", FCVAR_RELEASE, "Remote server access password (rcon server is disabled if empty)", &RCON_PasswordChanged_f);
static ConVar sv_rcon_sendlogs("sv_rcon_sendlogs", "0", FCVAR_RELEASE, "Network console logs to connected and authenticated sockets");
@ -674,7 +674,7 @@ int CRConServer::GetAuthenticatedCount(void) const
//-----------------------------------------------------------------------------
// Purpose: change RCON password on server and drop all connections
//-----------------------------------------------------------------------------
static void RCON_PasswordChanged_f(IConVar* pConVar, const char* pOldString)
static void RCON_PasswordChanged_f(IConVar* pConVar, const char* pOldString, float flOldValue, ChangeUserData_t pUserData)
{
if (ConVar* pConVarRef = g_pCVar->FindVar(pConVar->GetName()))
{
@ -697,7 +697,7 @@ static void RCON_PasswordChanged_f(IConVar* pConVar, const char* pOldString)
//-----------------------------------------------------------------------------
// Purpose: change whitelist address on RCON server
//-----------------------------------------------------------------------------
static void RCON_WhiteListAddresChanged_f(IConVar* pConVar, const char* pOldString)
static void RCON_WhiteListAddresChanged_f(IConVar* pConVar, const char* pOldString, float flOldValue, ChangeUserData_t pUserData)
{
if (ConVar* pConVarRef = g_pCVar->FindVar(pConVar->GetName()))
{
@ -714,7 +714,7 @@ static void RCON_WhiteListAddresChanged_f(IConVar* pConVar, const char* pOldStri
//-----------------------------------------------------------------------------
// Purpose: change max connection count on RCON server
//-----------------------------------------------------------------------------
static void RCON_ConnectionCountChanged_f(IConVar* pConVar, const char* pOldString)
static void RCON_ConnectionCountChanged_f(IConVar* pConVar, const char* pOldString, float flOldValue, ChangeUserData_t pUserData)
{
if (!RCONServer()->IsInitialized())
return; // Not initialized; no sockets at this point.
@ -753,7 +753,7 @@ static void RCON_ConnectionCountChanged_f(IConVar* pConVar, const char* pOldStri
//-----------------------------------------------------------------------------
// Purpose: change whether to bind on loopback socket
//-----------------------------------------------------------------------------
static void RCON_UseLoopbackSocketChanged_f(IConVar* pConVar, const char* pOldString)
static void RCON_UseLoopbackSocketChanged_f(IConVar* pConVar, const char* pOldString, float flOldValue, ChangeUserData_t pUserData)
{
if (ConVar* pConVarRef = g_pCVar->FindVar(pConVar->GetName()))
{

View File

@ -319,8 +319,8 @@ SocketHandle_t NetconShared_GetSocketHandle(CNetConBase* pBase, const int iSocke
#include "engine/client/cl_rcon.h"
#endif // !DEDICATED
void RCON_KeyChanged_f(IConVar* pConVar, const char* pOldString);
void RCON_PasswordChanged_f(IConVar* pConVar, const char* pOldString);
void RCON_KeyChanged_f(IConVar* pConVar, const char* pOldString, float flOldValue, ChangeUserData_t pUserData);
void RCON_PasswordChanged_f(IConVar* pConVar, const char* pOldString, float flOldValue, ChangeUserData_t pUserData);
ConVar rcon_debug("rcon_debug", "0", FCVAR_RELEASE, "Show rcon debug information ( !slower! )");
ConVar rcon_encryptframes("rcon_encryptframes", "1", FCVAR_RELEASE, "Whether to encrypt RCON messages");
@ -329,7 +329,7 @@ ConVar rcon_key("rcon_key", "", FCVAR_SERVER_CANNOT_QUERY | FCVAR_DONTRECORD | F
//-----------------------------------------------------------------------------
// Purpose: change RCON key on server and client
//-----------------------------------------------------------------------------
void RCON_KeyChanged_f(IConVar* pConVar, const char* pOldString)
void RCON_KeyChanged_f(IConVar* pConVar, const char* pOldString, float flOldValue, ChangeUserData_t pUserData)
{
if (ConVar* pConVarRef = g_pCVar->FindVar(pConVar->GetName()))
{

View File

@ -177,7 +177,7 @@ void CEngineAPI::PumpMessages()
//-----------------------------------------------------------------------------
// Purpose: force update NVIDIA Reflex Low Latency parameters
//-----------------------------------------------------------------------------
static void GFX_NVN_Changed_f(IConVar* pConVar, const char* pOldString)
static void GFX_NVN_Changed_f(IConVar* pConVar, const char* pOldString, float flOldValue, ChangeUserData_t pUserData)
{
GFX_MarkLowLatencyParametersOutOfDate();
}

View File

@ -96,11 +96,11 @@ public:
};
//-----------------------------------------------------------------------------
// Called when a ConVar changes value
// Called and provided when a ConVar changes value
// NOTE: For FCVAR_NEVER_AS_STRING ConVars, pOldValue == NULL
//-----------------------------------------------------------------------------
typedef void (*FnChangeCallback_t)(IConVar* var, const char* pOldValue);
typedef void* ChangeUserData_t;
typedef void (*FnChangeCallback_t)(IConVar* var, const char* pOldValue, float flOldValue, ChangeUserData_t pUserData);
//-----------------------------------------------------------------------------
// Abstract interface for ConVars

View File

@ -191,11 +191,11 @@ public:
virtual bool IsRegistered(void) const;
// Install a change callback (there shouldn't already be one....)
void InstallChangeCallback(FnChangeCallback_t callback, bool bInvoke);
void RemoveChangeCallback(FnChangeCallback_t callback);
void InstallChangeCallback(FnChangeCallback_t callback, ChangeUserData_t userData, bool bInvoke);
void RemoveChangeCallback(FnChangeCallback_t callback, ChangeUserData_t userData);
int GetChangeCallbackCount() const { return m_pParent->m_fnChangeCallbacks.Count(); }
FnChangeCallback_t GetChangeCallback(int slot) const { return m_pParent->m_fnChangeCallbacks[slot]; }
FnChangeCallback_t GetChangeCallback(int slot) const { return m_pParent->m_fnChangeCallbacks[slot].m_pCallback; }
FORCEINLINE bool GetBool(void) const;
FORCEINLINE float GetFloat(void) const;
@ -254,8 +254,7 @@ private:
const char* pHelpString = 0, bool bMin = false, float fMin = 0.0, bool bMax = false, float fMax = false,
FnChangeCallback_t callback = 0, const char* pszUsageString = 0);
//protected:
public: // TODO: make protected!
protected:
struct CVValue_t
{
char* m_pszString;
@ -264,6 +263,17 @@ public: // TODO: make protected!
int m_nValue;
};
struct CVChange_t
{
bool operator ==(const CVChange_t& other) const
{
return (other.m_pCallback == m_pCallback && !m_pUserData);
}
FnChangeCallback_t m_pCallback;
ChangeUserData_t m_pUserData; // Typically used for syncing cvars with VGUI sliders.
};
ConVar* m_pParent; //0x0048
const char* m_pszDefaultValue; //0x0050
CVValue_t m_Value; //0c0058
@ -271,7 +281,7 @@ public: // TODO: make protected!
float m_fMinVal; //0x0074
bool m_bHasMax; //0x0078
float m_fMaxVal; //0x007C
CUtlVector<FnChangeCallback_t> m_fnChangeCallbacks; //0x0080
CUtlVector<CVChange_t> m_fnChangeCallbacks; //0x0080
};
static_assert(sizeof(ConVar) == 0xA0);

View File

@ -14,19 +14,19 @@
//-----------------------------------------------------------------------------
// change callbacks
//-----------------------------------------------------------------------------
static void LiveAPI_EnabledChangedCallback(IConVar* var, const char* pOldValue)
static void LiveAPI_EnabledChangedCallback(IConVar* var, const char* pOldValue, float flOldValue, ChangeUserData_t pUserData)
{
LiveAPISystem()->ToggleInit();
}
static void LiveAPI_WebSocketEnabledChangedCallback(IConVar* var, const char* pOldValue)
static void LiveAPI_WebSocketEnabledChangedCallback(IConVar* var, const char* pOldValue, float flOldValue, ChangeUserData_t pUserData)
{
LiveAPISystem()->ToggleInitWebSocket();
}
static void LiveAPI_ParamsChangedCallback(IConVar* var, const char* pOldValue)
static void LiveAPI_ParamsChangedCallback(IConVar* var, const char* pOldValue, float flOldValue, ChangeUserData_t pUserData)
{
LiveAPISystem()->UpdateParams();
}
static void LiveAPI_AddressChangedCallback(IConVar* var, const char* pOldValue)
static void LiveAPI_AddressChangedCallback(IConVar* var, const char* pOldValue, float flOldValue, ChangeUserData_t pUserData)
{
LiveAPISystem()->RebootWebSocket();
}

View File

@ -950,7 +950,8 @@ void ConVar::ChangeStringValue(const char* tempVal)
// Invoke any necessary callback function
for (int i = 0; i < m_fnChangeCallbacks.Count(); ++i)
{
m_fnChangeCallbacks[i](this, pszOldValue);
const CVChange_t& targetCB = m_fnChangeCallbacks[i];
targetCB.m_pCallback(this, pszOldValue, NULL, targetCB.m_pUserData);
}
if (g_pCVar)
@ -982,7 +983,7 @@ void ConVar::Create(const char* pName, const char* pDefaultValue, int flags /*=
if (callback)
{
m_fnChangeCallbacks.AddToTail(callback);
InstallChangeCallback(callback, NULL, false);
}
m_Value.m_iStringLength = strlen(m_pszDefaultValue) + 1;
@ -1059,9 +1060,10 @@ void ConVar::SetDefault(const char* pszDefault)
//-----------------------------------------------------------------------------
// Purpose: Install a change callback (there shouldn't already be one....)
// Input : callback -
// userData -
// bInvoke -
//-----------------------------------------------------------------------------
void ConVar::InstallChangeCallback(FnChangeCallback_t callback, bool bInvoke /*=true*/)
void ConVar::InstallChangeCallback(FnChangeCallback_t callback, ChangeUserData_t userData, bool bInvoke /*=true*/)
{
if (!callback)
{
@ -1070,7 +1072,9 @@ void ConVar::InstallChangeCallback(FnChangeCallback_t callback, bool bInvoke /*=
return;
}
if (m_pParent->m_fnChangeCallbacks.Find(callback)
const CVChange_t newCB{ callback, userData };
if (m_pParent->m_fnChangeCallbacks.Find(newCB)
!= m_pParent->m_fnChangeCallbacks.InvalidIndex())
{
// Same ptr added twice, sigh...
@ -1079,12 +1083,12 @@ void ConVar::InstallChangeCallback(FnChangeCallback_t callback, bool bInvoke /*=
return;
}
m_pParent->m_fnChangeCallbacks.AddToTail(callback);
m_pParent->m_fnChangeCallbacks.AddToTail(newCB);
// Call it immediately to set the initial value...
if (bInvoke)
{
callback(this, m_Value.m_pszString);
callback(this, m_Value.m_pszString, NULL, userData);
}
}
@ -1092,7 +1096,8 @@ void ConVar::InstallChangeCallback(FnChangeCallback_t callback, bool bInvoke /*=
// Purpose: Install a change callback (there shouldn't already be one....)
// Input : callback -
//-----------------------------------------------------------------------------
void ConVar::RemoveChangeCallback(FnChangeCallback_t callback)
void ConVar::RemoveChangeCallback(FnChangeCallback_t callback, ChangeUserData_t userData)
{
m_pParent->m_fnChangeCallbacks.FindAndRemove(callback);
const CVChange_t targetCB{ callback, userData };
m_pParent->m_fnChangeCallbacks.FindAndRemove(targetCB);
}