Raised This Month: $ Target: $400
 0% 

get_pcvar_num returning different number?


Post New Thread Reply   
 
Thread Tools Display Modes
Author Message
Elusive138
Senior Member
Join Date: Dec 2010
Old 10-27-2011 , 03:37   get_pcvar_num returning different number?
Reply With Quote #1

I needed a way to detect when people are armed. To do this, and have a cvar for easier customisation, I used a sum of bits shifted using CSW_* constants. For some reason, this doesn't work for HE grenades. It works as expected for knife, smoke, flash.

PHP Code:
#define DEFAULT_SKIPWEAPONS (1 << CSW_KNIFE) | (1 << CSW_C4) | (1 << CSW_FLASHBANG) | (1 << CSW_SMOKEGRENADE) | (1 << CSW_HEGRENADE)

---------------------------------

new 
bitsum[16];
num_to_str(DEFAULT_SKIPWEAPONSbitsumcharsmax(bitsum));
cvarSkipWeapons register_cvar("jb_rebel_skipweapons"bitsum);

---------------------------------

stock PlayerIsArmed(id) {
    new 
weapons[32];
    new 
weaponsnum;
    
get_user_weapons(idweaponsweaponsnum);
    new 
isArmed;
    for (new 
iweaponsnumi++) {
        
// Ignore these weapons
        
if (!((<< weapons[i]) & get_pcvar_num(cvarSkipWeapons))) {
            
client_print(0print_chat"Armed: %i, Skip: %i"weapons[i], get_pcvar_num(cvarSkipWeapons));
            
isArmed 1;
            break;
        }
    }
    return 
isArmed;

Code:
Armed: 4, Skip: 570425920
] amx_cvar jb_rebel_skipweapons
[AMXX] Cvar "jb_rebel_skipweapons" is "570425936"
Manually calculating the sum (Windows Calculator) gives me 570425936, as expected. Why is the number get_pcvar_num is giving me missing (1 << 4) (16)? If I only have a knife, it passes fine. With any gun, e.g. scout:
Code:
Armed: 3, Skip: 570425920
Which is also fine. The problem is HE grenades still pass the check when they shouldn't.

Is there any reason get_pcvar_num is giving me a different number from expected, and checked with amx_cvar and through the server console?

Thanks.

Last edited by Elusive138; 10-27-2011 at 06:51.
Elusive138 is offline
Bugsy
AMX Mod X Moderator
Join Date: Feb 2005
Location: NJ, USA
Old 10-27-2011 , 08:21   Re: get_pcvar_num returning different number?
Reply With Quote #2

That is very weird, I thought at first it was a problem with your code but I tested it myself and you're correct. get_pcvar_num() is not returning just that one bit yet the cvar is holding the correct value including the bit. I put together a small function for you which basically reads the cvar as a string then converts to a number. It's silly to have to do it that way but get_pcvar_num() isn't working properly so it'll have to do. I don't have time now but I will look into this further and report any findings.

Output:
Code:
DEFAULT_SKIPWEAPONS=570425936
bitsum=570425936
get_cvar_num()=570425920
get_pcvar_num()=570425920
get_pcvar_string()=570425936
getcvarbits()=570425936
PHP Code:
#include <amxmodx>

const DEFAULT_SKIPWEAPONS = (<< CSW_KNIFE) | (<< CSW_C4) | (<< CSW_FLASHBANG) | (<< CSW_SMOKEGRENADE) | (<< CSW_HEGRENADE)

public 
plugin_init() 
{
    new 
bitsum16 ] , cvarSkipWeapons;
    
    
num_to_str(DEFAULT_SKIPWEAPONSbitsumcharsmax(bitsum));
    
cvarSkipWeapons register_cvar("jb_rebel_skipweapons"bitsum);
    
    new 
szCVar16 ];
    
server_print"DEFAULT_SKIPWEAPONS=%d" DEFAULT_SKIPWEAPONS );
    
server_print"bitsum=%s" bitsum );
    
server_print"get_cvar_num()=%d" get_cvar_num"jb_rebel_skipweapons" ) );
    
server_print"get_pcvar_num()=%d" get_pcvar_numcvarSkipWeapons ) );
    
get_pcvar_stringcvarSkipWeapons szCVar charsmaxszCVar ) );
    
server_print"get_pcvar_string()=%s"szCVar );
    
server_print"getcvarbits()=%d"GetCVarBitscvarSkipWeapons ) );
}

GetCVarBitspCVar )
{
    new 
szCVar16 ];
    
get_pcvar_stringpCVar szCVar charsmaxszCVar ) );
    return 
str_to_numszCVar );

__________________

Last edited by Bugsy; 10-27-2011 at 09:08.
Bugsy is offline
Arkshine
AMX Mod X Plugin Approver
Join Date: Oct 2005
Old 10-27-2011 , 10:38   Re: get_pcvar_num returning different number?
Reply With Quote #3

I've searched/debugged a bit and the problem is most likely a loss of precision double -> float. Let me explain.

The bug is not from AMXX, all the native does is returning (int)ptr->value, so the float value converted to an integer.
This float value is set when you register a cvar, in the engine, using Q_atof(). This function itself works fine. The functions looks like :

PHP Code:
float Q_atof (char *str)
{
    
double    val;
    
int        sign;
    
int        c;
    
int        decimaltotal;
    
    if (*
str == '-')
    {
        
sign = -1;
        
str++;
    }
    else
        
sign 1;
        
    
val 0;

//
// check for hex
//
    
if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X') )
    {
        
str += 2;
        while (
1)
        {
            
= *str++;
            if (
>= '0' && <= '9')
                
val = (val*16) + '0';
            else if (
>= 'a' && <= 'f')
                
val = (val*16) + 'a' 10;
            else if (
>= 'A' && <= 'F')
                
val = (val*16) + 'A' 10;
            else
                return 
val*sign;
        }
    }
    
//
// check for character
//
    
if (str[0] == '\'')
    {
        return 
sign str[1];
    }
    
//
// assume decimal
//
    
decimal = -1;
    
total 0;
    while (
1)
    {
        
= *str++;
        if (
== '.')
        {
            
decimal total;
            continue;
        }
        if (
<'0' || '9')
            break;
        
val val*10 '0';
        
total++;
    }

    if (
decimal == -1)
        return 
val*sign;
    while (
total decimal)
    {
        
val /= 10;
        
total--;
    }
    
    return 
val*sign;

The problem is it returns a float, when you're working with double. The value is right when it's about to be returned, but it's lost precision once it has been converted to float.
I don't know much why and how such things are handled but the problem is that.

Since from the engine, you can't fix directly. It's possible to fix amxmodx by overwriting this value using atof() from the string, in register_cvar native, it will work.

Another way is to use a common way where you use the letters as flags then you could use read_flags() to get the bits sum from the letters.
I don't remember seeing a plugin dealing with such big number in a cvar.
__________________

Last edited by Arkshine; 10-27-2011 at 10:44.
Arkshine is offline
Elusive138
Senior Member
Join Date: Dec 2010
Old 10-28-2011 , 01:48   Re: get_pcvar_num returning different number?
Reply With Quote #4

Quote:
Originally Posted by Bugsy View Post
That is very weird, I thought at first it was a problem with your code but I tested it myself and you're correct. get_pcvar_num() is not returning just that one bit yet the cvar is holding the correct value including the bit. I put together a small function for you which basically reads the cvar as a string then converts to a number. It's silly to have to do it that way but get_pcvar_num() isn't working properly so it'll have to do. I don't have time now but I will look into this further and report any findings.
Thanks! It seemed I'll probably get the value and cache it during plugin_cfg() or something.

Quote:
Originally Posted by Arkshine View Post
I've searched/debugged a bit and the problem is most likely a loss of precision double -> float. Let me explain.

The bug is not from AMXX, all the native does is returning (int)ptr->value, so the float value converted to an integer.
This float value is set when you register a cvar, in the engine, using Q_atof(). This function itself works fine.
The problem is it returns a float, when you're working with double. The value is right when it's about to be returned, but it's lost precision once it has been converted to float.
I don't know much why and how such things are handled but the problem is that.

Since from the engine, you can't fix directly. It's possible to fix amxmodx by overwriting this value using atof() from the string, in register_cvar native, it will work.

Another way is to use a common way where you use the letters as flags then you could use read_flags() to get the bits sum from the letters.
I don't remember seeing a plugin dealing with such big number in a cvar.
Thanks for the additional insight into the problem. I had considered using letter flags, as it would also be easier to configure, but CSW_* weapon constants go up to 32 (CSW_KNIFE is 29), with only 26 characters (unless A = 27, etc?). I'll just use the get_pcvar_string() and str_to_num() solution.

And again, thanks for all the help .
Elusive138 is offline
Reply



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 14:22.


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