Raised This Month: $12 Target: $400
 3% 

To hook or not to hook, that is the question.


Post New Thread Reply   
 
Thread Tools Display Modes
Author Message
PatriotGames
AlliedModders Donor
Join Date: Feb 2012
Location: root@irs:/# rm -rf /
Old 02-05-2019 , 14:52   To hook or not to hook, that is the question.
Reply With Quote #1

Please help a new coder understand the current recommended practice for tracking convar changes in both transitional and methodmap syntax.

In this example we have several different approaches:
PHP Code:
ConVar g_cvMyCvar;
bool g_bMyCvar;

public 
void OnPluginStart()
{
    
g_cvMyCvar CreateConVar("my_cvar""0""This cvar does something. 0 = Disable, 1 = Enable"FCVAR_NOTIFY);
    
    
g_bMyCvar GetConVarBool(g_cvMyCvar); //set bool var to cvar value
    
HookConvarChange(g_cvMyCvar CvarsChanged); // transitional hook cvar change function
    
    
g_cvMyCvar.AddChangeHook(CvarsChanged); //methodmap hook cvar change property
    
}

public 
void CvarsChanged(Handle convar, const char oldValue[], const char newValue[])
{
    
GetCvars();
}

public 
void GetCvars()
{
    
g_bMyCvar GetConVarBool(g_cvMyCvar); //transitional syntax
    
g_bMyCvar g_cvMyCvar.BoolValue;    //methodmap property
}

void MyCvarFunction()
{
    if (
GetConvarBool(g_cvMyCvar)); //does not use a cvar hook at all. Is this sub-optimal?
    
{
        
//code
    
}
}

void MyCvarBoolFunction()
{
    If (
g_bMyCvar//transitional syntax and methodmap property use the bool var for g_cvMyCvar. Any advantage of one over the other?
    
{
        
// code
    
}

void MyCvarMethodMapFunction()
{
    If (
g_cvMyCvar.BoolValue))    // A methodmap that uses the cvar directly without the hook property. Is this ok?
    
{
        
// code
    
}

What is the recommended practice?

Bonus question: what's the optimal method for using cvars to calculate another cvars new value?

Exmple:
PHP Code:
void SomeFunction()
{
    
SetConVarInt(g_cvSomeCvar, (g_iAnotherCvar + (g_iYetAnotherCvar g_iSomeConstant)));

Thanks,
PG

Last edited by PatriotGames; 02-05-2019 at 15:55.
PatriotGames is offline
Neuro Toxin
Veteran Member
Join Date: Oct 2013
Location: { closing the void; }
Old 02-05-2019 , 15:48   Re: To hook or not to hook, that is the question.
Reply With Quote #2

It is my understanding that it's now better practise to not hook convar changes. When using the new ConVar methodmap, it apparently caches the values and updates itself.

Im sure a dev will jump in if anything stated is wrong.
__________________
Neuro Toxin is offline
impossible_cc
Senior Member
Join Date: Sep 2018
Location: Ukraine
Old 02-05-2019 , 16:36   Re: To hook or not to hook, that is the question.
Reply With Quote #3

Quote:
Originally Posted by PatriotGames View Post
Bonus question: what's the optimal method for using cvars to calculate another cvars new value?

Exmple:
PHP Code:
void SomeFunction()
{
    
SetConVarInt(g_cvSomeCvar, (g_iAnotherCvar + (g_iYetAnotherCvar g_iSomeConstant)));

Thanks,
PG

PHP Code:
void SomeFunction()
{
    
g_cvSomeCvar.IntValue g_iAnotherCvar.IntValue g_iYetAnotherCvar.IntValue g_iSomeConstant;
    
//If g_iSomeConstant is also a cvar, then you need g_iSomeConstant.IntValue

Edit:
if all of that is int, not convar, then do like this
PHP Code:
void SomeFunction()
{
    
g_cvSomeCvar.IntValue =  g_iAnotherCvar g_iYetAnotherCvar g_iSomeConstant;


Last edited by impossible_cc; 02-05-2019 at 16:39.
impossible_cc is offline
asherkin
SourceMod Developer
Join Date: Aug 2009
Location: OnGameFrame()
Old 02-05-2019 , 19:04   Re: To hook or not to hook, that is the question.
Reply With Quote #4

Quote:
Originally Posted by Neuro Toxin View Post
It is my understanding that it's now better practise to not hook convar changes. When using the new ConVar methodmap, it apparently caches the values and updates itself.

Im sure a dev will jump in if anything stated is wrong.
There is no difference pre- or post-methodmaps, convar handles have always been cached, and convars do the value conversions when they're set so getting values is just copying memory.
__________________
asherkin is offline
PatriotGames
AlliedModders Donor
Join Date: Feb 2012
Location: root@irs:/# rm -rf /
Old 02-05-2019 , 21:37   Re: To hook or not to hook, that is the question.
Reply With Quote #5

Quote:
Originally Posted by impossible_cc View Post
Edit:
if all of that is int, not convar, then do like this
PHP Code:
void SomeFunction()
{
    
g_cvSomeCvar.IntValue =  g_iAnotherCvar g_iYetAnotherCvar g_iSomeConstant;

Thank you, impossible_cc. So the IntValue methodmap property can work like both GetConVarInt and SetConVarInt functions even in the same statement. Interesting...

Quote:
Originally Posted by asherkin View Post
There is no difference pre- or post-methodmaps, convar handles have always been cached, and convars do the value conversions when they're set so getting values is just copying memory.
So there's no performance advantage to hooking cvar change and creating a var (bool, int, float) to track it over simply calling the cvar value? And...
PHP Code:
void SomeFunction()
{
    
g_cvSomeCvar.IntValue g_iAnotherCvar.IntValue g_iYetAnotherCvar.IntValue g_iSomeConstant;

    
// and...
    
    
SetConVarInt(g_cvSomeCvar) = (GetConVarInt(g_iAnotherCvar) + GetConVarInt(g_iYetAnotherCvar) * g_iSomeConstant);

    
// are equivalent and one has no performance advantage over the other?

So, when and why would we use:
PHP Code:
g_cvMyCvar.AddChangeHook(MyCallback); 
Thank you for the help,
PG

Last edited by PatriotGames; 02-05-2019 at 21:58.
PatriotGames is offline
Dragokas
Veteran Member
Join Date: Nov 2017
Location: Ukraine on fire
Old 02-10-2019 , 13:33   Re: To hook or not to hook, that is the question.
Reply With Quote #6

Quote:
Originally Posted by PatriotGames View Post
So, when and why would we use:
PHP Code:
g_cvMyCvar.AddChangeHook(MyCallback); 
PG
When you need instantly execute some method, e.g. change player color when cvarColor is changed.
__________________
Expert of CMD/VBS/VB6. Malware analyst. L4D fun (Bloody Witch & FreeZone)
[My plugins] [My tools] [GitHub] [Articles] [HiJackThis+] [Donate]

Last edited by Dragokas; 02-10-2019 at 13:35.
Dragokas is offline
PatriotGames
AlliedModders Donor
Join Date: Feb 2012
Location: root@irs:/# rm -rf /
Old 02-11-2019 , 14:32   Re: To hook or not to hook, that is the question.
Reply With Quote #7

Quote:
Originally Posted by Dragokas View Post
When you need instantly execute some method, e.g. change player color when cvarColor is changed.
Thanks, Dragokas, that makes sense.

PG
PatriotGames is offline
Psyk0tik
Veteran Member
Join Date: May 2012
Location: Homeless
Old 02-13-2019 , 03:46   Re: To hook or not to hook, that is the question.
Reply With Quote #8

Quote:
Originally Posted by PatriotGames View Post
Thanks, Dragokas, that makes sense.

PG
To add more to this, we hook a cvar handle to a changehook if we want something to happen as soon as the value of that cvar is changed. (i.e. g_cvIsOn.AddChangeHook(vIsOnHook) or HookConVarChange(g_hIsOn, vIsOnHook))

If we just want to check the current value of the cvar, we can just call it when we need it (or cache it to a variable if you prefer that). (i.e. bIsOn = g_cvIsOn.BoolValue or bIsOn = GetConVarBool(g_hIsOn))

In this example, we're going to check the initial value of the "mp_gamemode" cvar and then hook it so we can check for the value whenever it changes:

PHP Code:
ConVar g_cvMPGameMode;
bool g_bIsCampaign;

public 
void OnPluginStart()
{
    
g_cvMPGameMode FindConVar("mp_gamemode");

    if (
g_cvMPGameMode != null)
    {
        
g_cvMPGameMode.AddChangeHook(vMPGameModeHook);
    }
}

public 
void OnMapStart()
{
    if (
g_cvMPGameMode != null)
    {
        
char sGameMode[32];
        
g_cvMPGameMode.GetString(sGameModesizeof(sGameMode));

        if (
StrEqual(sGameMode"versus"))
        {
            
g_bIsCampaign false;
        }
    }
}

public 
void vMPGameModeHook(ConVar convar, const char[] oldVal, const char[] newVal)
{
    if (
StrEqual(newVal"versus"))
    {
        
g_bIsCampaign false;
    }
    else
    {
        
g_bIsCampaign true;
    }

I assume you've made this thread due to the changes I made to your plugin last week. I'm sorry for not explaining it to you or adding comments in the code to help you. If you want, we can discuss any other questions you may have in private chat or on Discord.
__________________
Psyk0tik is offline
Ilusion9
Veteran Member
Join Date: Jun 2018
Location: Romania
Old 02-13-2019 , 05:35   Re: To hook or not to hook, that is the question.
Reply With Quote #9

Quote:
Originally Posted by Crasher_3637 View Post
To add more to this, we hook a cvar handle to a changehook if we want something to happen as soon as the value of that cvar is changed.
Or to block that change to happen.

PHP Code:

public void OnPluginStart() 

    
g_cvMPGameMode FindConVar("mp_gamemode"); 

    if (
g_cvMPGameMode != null
    { 
        
g_cvMPGameMode.AddChangeHook(vMPGameModeHook); 
    } 



public 
void vMPGameModeHook(ConVar convar, const char[] oldVal, const char[] newVal

    if (!
StrEqual(newVal"versus")) 
    { 
        
g_cvMPGameMode.SetString("versus"));
    } 

__________________
Ilusion9 is offline
PatriotGames
AlliedModders Donor
Join Date: Feb 2012
Location: root@irs:/# rm -rf /
Old 02-15-2019 , 20:41   Re: To hook or not to hook, that is the question.
Reply With Quote #10

Quote:
Originally Posted by Crasher_3637 View Post
To add more to this, we hook a cvar handle to a changehook if we want something to happen as soon as the value of that cvar is changed. (i.e. g_cvIsOn.AddChangeHook(vIsOnHook) or HookConVarChange(g_hIsOn, vIsOnHook))

If we just want to check the current value of the cvar, we can just call it when we need it (or cache it to a variable if you prefer that). (i.e. bIsOn = g_cvIsOn.BoolValue or bIsOn = GetConVarBool(g_hIsOn))

In this example, we're going to check the initial value of the "mp_gamemode" cvar and then hook it so we can check for the value whenever it changes:

PHP Code:
ConVar g_cvMPGameMode;
bool g_bIsCampaign;

public 
void OnPluginStart()
{
    
g_cvMPGameMode FindConVar("mp_gamemode");

    if (
g_cvMPGameMode != null)
    {
        
g_cvMPGameMode.AddChangeHook(vMPGameModeHook);
    }
}

public 
void OnMapStart()
{
    if (
g_cvMPGameMode != null)
    {
        
char sGameMode[32];
        
g_cvMPGameMode.GetString(sGameModesizeof(sGameMode));

        if (
StrEqual(sGameMode"versus"))
        {
            
g_bIsCampaign false;
        }
    }
}

public 
void vMPGameModeHook(ConVar convar, const char[] oldVal, const char[] newVal)
{
    if (
StrEqual(newVal"versus"))
    {
        
g_bIsCampaign false;
    }
    else
    {
        
g_bIsCampaign true;
    }

I assume you've made this thread due to the changes I made to your plugin last week. I'm sorry for not explaining it to you or adding comments in the code to help you. If you want, we can discuss any other questions you may have in private chat or on Discord.
Thanks for the explanation, Crasher_3637, and no need to apologize. I just appreciated your taking the time to review my code and offer suggested changes. Sure, comments would have been helpful, but I don't feel comfortable pressing someone for more effort when they're already graciously giving their time to help me.

This thread was made in part due to your removing the convar hook and check section from the early version of my plugin, but also because of comments (not necessarily yours) made in other threads which gave the impression that hooking cvars is really not needed except in very specific cases, such as the one you've detailed here and in Ilusion9's example.

That revelation was perplexing because of the number of plugins from very competent authors that include large cvar hook sections. For me, understanding why something is done is as important as learning how it is done. I'm not comfortable applying practices or using code if I don't understand the "why" behind it. Your above example and explanation has helped my understanding of when to hook or not to hook cvars and why.

Thanks again for your help and if the need arises, I will definitely contact you to discuss this topic further.

Kind regards,
Patriot
PatriotGames is offline
Reply


Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT -4. The time now is 00:32.


Powered by vBulletin®
Copyright ©2000 - 2024, vBulletin Solutions, Inc.
Theme made by Freecode