AlliedModders

AlliedModders (https://forums.alliedmods.net/index.php)
-   Scripting Help (https://forums.alliedmods.net/forumdisplay.php?f=11)
-   -   get_pcvar_num returning different number? (https://forums.alliedmods.net/showthread.php?t=170608)

Elusive138 10-27-2011 03:37

get_pcvar_num returning different number?
 
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.

Bugsy 10-27-2011 08:21

Re: get_pcvar_num returning different number?
 
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 );



Arkshine 10-27-2011 10:38

Re: get_pcvar_num returning different number?
 
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.

Elusive138 10-28-2011 01:48

Re: get_pcvar_num returning different number?
 
Quote:

Originally Posted by Bugsy (Post 1584157)
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 (Post 1584242)
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 :).


All times are GMT -4. The time now is 14:22.

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