citizenfx / fivem

The source code for the Cfx.re modification frameworks, such as FiveM, RedM and LibertyM, as well as FXServer.
https://cfx.re/
3.47k stars 2.05k forks source link

StatGetInt return a 32 bits value but Stats can be 64 bits #2489

Open ArdentLeKhey opened 4 months ago

ArdentLeKhey commented 4 months ago

What happened?

To know if a stuntjump is done, GTA use a binary mask system in the stat : MP0_USJS_COMPLETED_MASK (for male, and use MP1 for female)

When you never did stuntjump, MP0_USJS_COMPLETED_MASK is binary : 0 For exemple if you success stunt jump number 6, MP0_USJS_COMPLETED_MASK will be binary : 100000 (decimal 32) An other name that you can give to this is "flags", for 6 it will be 2^(6-1) because we begin at 0, not 1, and you add all flags you want in your final number.

So i tryed this theory, i did stunjump 6 and my script returned 0 0 0 0 0 1 (because my script count binary right to left) I reseted the Stat using : StatSetInt(GetHashKey("MP0_USJS_COMPLETED_MASK"), 0) I tryed stunjump 32 and my script returned 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 (1073741824 in decimal)

At this moment all is cool, but the problem is that there is 50 stunjumps, so i tryed stuntjump 42 The number returned was the same because this stat is only returned with 32 bits (there is an overflow)

Expected result

64 bits return value

Reproduction steps

You can use : StatSetInt(GetHashKey("MP0_USJS_COMPLETED_MASK"), 0) to set the stat to 0 Use : StatSetMaskedInt(GetHashKey("MP0_USJS_COMPLETED_MASK"), 1, 42, 1, true) to set the 42th bit to 1 Use this to get the Stat value : local isValid, returnedInt = StatGetInt(GetHashKey("MP0_USJS_COMPLETED_MASK"), -1)

Use this function on returnedInt to have it in binary :

function ToBits(num)
    local t={}
    while num>0 do
        rest=math.fmod(num,2)
        t[#t+1]=math.floor(rest+0.5)
        num=(num-rest)/2
    end
    return table.concat(t, " ")
end

You will get a 32 bits value

Importancy

Slight inconvenience

Area(s)

FiveM, Natives, ScRT: Lua

Specific version(s)

FiveM 7990 (and other versions)

Additional information

For Native : StatSetMaskedInt Parameters are : int keyHash, int data, int shift, int numberOfBits, bool save

For Native : StatGetMaskedInt Parameters are : int keyHash, int shift, int numberOfBits, I don't know the last I tryed this Native to choose bit one by one, but it didn't wotk : [ 3037531] [ GTAProcess] MainThrd/ __Lua_InvokeNative: execution failed: Error executing native 0x655185a06d9eeaab at address FiveM_GTAProcess.exe+CF2A83. [ 3037531] [ GTAProcess] MainThrd/ Execution of native 655185a06d9eeaab in script host failed: Error executing native 0x655185a06d9eeaab at address FiveM_GTAProcess.exe+CF2A83.

The FiveM implementation of the Native StatGetInt is :

--- p2 appears to always be -1
function Global.StatGetInt(statHash, p2)
    return _in(0x767FBC2AC802EF3D, _ch(statHash), _i, p2, _r)
end

So i hunderstand it return a lightuserdata that is a pointer, and by default it seems to be 32 bit data, i will try to pass float pointer. Eddit : Floats are 32 bits and we don't have access to long that are 64 bits

A solution can be to add Citizen.PointerValueInt64() and use this for the Native.

ArdentLeKhey commented 4 months ago

I saw that 2take1 menu added a Native stat_get_i64 to get a 64 bits int, it can be a good solution.

ArdentLeKhey commented 4 months ago

I found a workaround Use StatGetBool It works on int and will give you binary bit of this int

Gogsi commented 4 months ago

I think this should stay open as the workaround of using Bool for Int is a bit weird. There's still some problem with StatGetInt that should be fixed

ArdentLeKhey commented 4 months ago

I think this should stay open as the workaround of using Bool for Int is a bit weird. There's still some problem with StatGetInt that should be fixed

Ok i re-open it