Cheat Engine Forum Index Cheat Engine
The Official Site of Cheat Engine
 
 FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 


Parsing a number from an address (Double~Int)

 
Post new topic   Reply to topic    Cheat Engine Forum Index -> Cheat Engine Lua Scripting
View previous topic :: View next topic  
Author Message
AylinCE
Grandmaster Cheater Supreme
Reputation: 37

Joined: 16 Feb 2017
Posts: 1522

PostPosted: Wed Oct 01, 2025 6:57 am    Post subject: Parsing a number from an address (Double~Int) Reply with quote

We aim to contribute to the CE and CEF archives as much as possible.

Please support further sharing on this topic.

I have a project where I need to parse whether a number retrieved from an address is a "Double" or an "Integer."

I'll probably compare the results of a vtAll scan of a mixture of 4 bytes and Doubles and add them to the address list.

Here's the parsing method I want to use:

Code:
function getAOB(address, length)
    local bytestring1={}
    local str=''
    bytestring1=readBytes(address, tonumber(length), true)

    for i,k in pairs(bytestring1) do
        str=str..string.format('%02x ',bytestring1[i])
    end
    return str:upper()
end

function isLikelyDouble(d, i, aob)
    if math.abs(d) < 1e-100 and i ~= 0 then
        return false
    end

    if d == 0.0 and i == 0 then
        if aob:match("^00 00 00 00 00 00 00 00$") then
            return true
        else
            return false
        end
    end

    if d ~= math.floor(d) then
        return true
    end

    local maxInt32 = 2147483648
    if math.abs(d) >= maxInt32 then
        return true
    end

    local leading4Bytes = aob:match("^%x%x %x%x %x%x %x%x")
    if d == math.floor(d) and leading4Bytes:match("^00 00 00 00$") then
        return true
    end

    return false
end

function readUnsignedInt(addr, opt)
    local signed = readInteger(addr, true)
    if opt then
       if signed < 0 then
          return signed + 4294967296 -- 2^32
       else
          return signed
       end
    else
       return signed
    end
end

function checkType(addr)
    local d = readDouble(addr)
    local i = readInteger(addr, true)
    local aob = getAOB(addr, 8)
    local res = ""

    if isLikelyDouble(d, i, aob) then
        res = string.format("Likely DOUBLE: %.12f - %s", d, aob)
    else
        res = string.format("Likely INT: %d - %s", readUnsignedInt(addr, true), aob)
    end

    print(res)
end


addr1 = "14C14398F50" -- Double
checkType(addr1)
addr2 = "7B589EF2D8" -- Int
checkType(addr2)
addr3 = "14C03478FA0" -- Double
checkType(addr3)
addr4 = "7B589FEC38" -- Int
checkType(addr4)
addr5 = "7B589FECF0" -- Int ( unsigned: 2863311530, true / signed: -1431655766, false )
checkType(addr5)


result:
Likely DOUBLE: 999.125000000000 - 02 00 00 00 00 39 8F 40
Likely INT: 100 - 64 00 00 00 00 00 00 00
Likely DOUBLE: 1000.876464843750 - 01 00 00 00 03 47 8F 40
Likely INT: 2863311530 - AA AA AA AA AA AA AA AA
Likely INT: 0 - 00 00 00 00 00 00 00 00

If you have an idea for a better approach to this issue, please contribute to improve the code.

_________________
Hi Hitler Different Trainer forms for you!
https://forum.cheatengine.org/viewtopic.php?t=619279
Enthusiastic people: Always one step ahead
Do not underestimate me Master: You were a beginner in the past
Back to top
View user's profile Send private message Visit poster's website MSN Messenger
ParkourPenguin
I post too much
Reputation: 152

Joined: 06 Jul 2014
Posts: 4702

PostPosted: Wed Oct 01, 2025 11:00 am    Post subject: Reply with quote

CE has the Lua function autoGuess that guesses what type the value at some address is.

Code:
function byteTableToAOB(bt)
  local t = {}
  for i,b in ipairs(bt) do
    t[i] = ('%02X'):format(b)
  end
  return table.concat(t, ' ')
end

function checkType(addr)
  local g = autoGuess(addr)
  if g == vtDouble then
    local bt = readBytes(addr, 8, true)
    print(('double: %.12f - %s'):format(byteTableToDouble(bt), byteTableToAOB(bt)))
  elseif g == vtDword then
    local bt = readBytes(addr, 4, true)
    print(('int: %d - %s'):format(byteTableToDword(bt), byteTableToAOB(bt)))
  else
    print('Other type:', g)  -- see defines.lua
  end
end

_________________
I don't know where I'm going, but I'll figure it out when I get there.
Back to top
View user's profile Send private message
AylinCE
Grandmaster Cheater Supreme
Reputation: 37

Joined: 16 Feb 2017
Posts: 1522

PostPosted: Wed Oct 01, 2025 2:37 pm    Post subject: Reply with quote

ParkourPenguin wrote:
CE has the Lua function autoGuess ...


This is promising code, thanks.

But there's a global bug in "autoGuess" in 7.5.
Has this been defined?

_________________
Hi Hitler Different Trainer forms for you!
https://forum.cheatengine.org/viewtopic.php?t=619279
Enthusiastic people: Always one step ahead
Do not underestimate me Master: You were a beginner in the past
Back to top
View user's profile Send private message Visit poster's website MSN Messenger
Dark Byte
Site Admin
Reputation: 470

Joined: 09 May 2003
Posts: 25796
Location: The netherlands

PostPosted: Wed Oct 01, 2025 3:38 pm    Post subject: Reply with quote

you can always use onAutoGuess to fix whatever bug you think it has

e.g when CE thinks something is a pointer, because the value it represents is dividable by 8 and the address it represents is readable , you can tell it, no, it's a double/float/int/whatever

_________________
Do not ask me about online cheats. I don't know any and wont help finding them.

Like my help? Join me on Patreon so i can keep helping
Back to top
View user's profile Send private message MSN Messenger
AylinCE
Grandmaster Cheater Supreme
Reputation: 37

Joined: 16 Feb 2017
Posts: 1522

PostPosted: Wed Oct 01, 2025 4:28 pm    Post subject: Reply with quote

So why "nil"?

Code:
function byteTableToAOB(bt)
  local t = {}
  for i,b in ipairs(bt) do
    t[i] = ('%02X'):format(b)
  end
  return table.concat(t, ' ')
end

function checkType(addr)
  local g = onAutoGuess(addr) -- > g = nil ..
  if g == vtDouble then
    local bt = readBytes(addr, 8, true)
    print(('double: %.12f - %s'):format(byteTableToDouble(bt), byteTableToAOB(bt)))
  elseif g == vtDword then
    local bt = readBytes(addr, 4, true)
    print(('int: %d - %s'):format(byteTableToDword(bt), byteTableToAOB(bt)))
  else
    print(('Other type: %s'):format(g))  -- see defines.lua
  end
end

addr1 = 0x1824006473F8 -- Double
checkType(addr1)
addr2 = "29AA1FEE10" -- Int
checkType(addr2)
addr3 = "3220047A352" -- Double
checkType(addr3)
addr4 = "3220018B4EC" -- Int
checkType(addr4)


result:

Other type: nil
Other type: nil
Other type: nil
Other type: nil

_________________
Hi Hitler Different Trainer forms for you!
https://forum.cheatengine.org/viewtopic.php?t=619279
Enthusiastic people: Always one step ahead
Do not underestimate me Master: You were a beginner in the past
Back to top
View user's profile Send private message Visit poster's website MSN Messenger
ParkourPenguin
I post too much
Reputation: 152

Joined: 06 Jul 2014
Posts: 4702

PostPosted: Wed Oct 01, 2025 4:31 pm    Post subject: Reply with quote

I think `autoGuess` became a global function in 7.6. I can't find it in the github repository.

`onAutoGuess` is used to override CE's default type-guessing behaviour.

_________________
I don't know where I'm going, but I'll figure it out when I get there.
Back to top
View user's profile Send private message
Dark Byte
Site Admin
Reputation: 470

Joined: 09 May 2003
Posts: 25796
Location: The netherlands

PostPosted: Wed Oct 01, 2025 4:59 pm    Post subject: Reply with quote

right.
in 7.5 you'd have to use the structure class
Code:

function autoGuess(address)
  local sf=enumStructureForms()
  if #sf==0 then --autoGuess needs a dissect struct form to exist in ce 7.5
    f=createStructureForm()
    f.hide()
  end

  local s=createStructure('temp')

  local as
  if type(address)~='string' then
    as=string.format('%x',address)
  else
    as=address
  end

  s.autoGuess(as,0,16)
  local result
  if s.Count>0 then
    result=s[0].VarType
  else
    result=nil
  end
  s.destroy()
  return result
end

_________________
Do not ask me about online cheats. I don't know any and wont help finding them.

Like my help? Join me on Patreon so i can keep helping
Back to top
View user's profile Send private message MSN Messenger
AylinCE
Grandmaster Cheater Supreme
Reputation: 37

Joined: 16 Feb 2017
Posts: 1522

PostPosted: Wed Oct 01, 2025 6:47 pm    Post subject: Reply with quote

I think it defines fractional numbers as bytes.

Code:
function autoGuess(address)
  local sf = enumStructureForms()
  if #sf == 0 then
    local f = createStructureForm()
    f.hide()
  end

  local s = createStructure('temp')
  local as = type(address) == 'string' and address or string.format('%x', address)

  s:autoGuess(as, 0, 16)

  local result = nil
  local e = s:getElement(0)
  if e and e.Vartype then
    print("Element 0 type:", e.VarType)
    result = e.VarType
  end

  s:destroy()
  return result
end


addr1 = "1824006473F8" -- Double
checkType(addr1)
addr2 = "29AA1FEE10" -- Int
checkType(addr2)
addr3 = "3220047A352" -- Double >> 100.000000079162
checkType(addr3)
addr4 = "3220018B4EC" -- Int
checkType(addr4)
addr3 = "3220056F62B" -- float >> 1001.015625
checkType(addr3)

result:

Element 0 type: vtDouble
double: 100.000000000000 - 00 00 00 00 00 00 59 40
Element 0 type: vtDword
int: 1000 - E8 03 00 00
Element 0 type: vtByte
Other type: vtByte
Element 0 type: vtDword
int: 1000 - E8 03 00 00
Element 0 type: vtByte
Other type: vtByte

_________________
Hi Hitler Different Trainer forms for you!
https://forum.cheatengine.org/viewtopic.php?t=619279
Enthusiastic people: Always one step ahead
Do not underestimate me Master: You were a beginner in the past
Back to top
View user's profile Send private message Visit poster's website MSN Messenger
Dark Byte
Site Admin
Reputation: 470

Joined: 09 May 2003
Posts: 25796
Location: The netherlands

PostPosted: Wed Oct 01, 2025 11:18 pm    Post subject: Reply with quote

compilers generally never put floats in an address not dividable by at least 4 (8 or 16 is actually more common) so CE doesn't detect that as a float and just uses bytes to pad to the next alignment
_________________
Do not ask me about online cheats. I don't know any and wont help finding them.

Like my help? Join me on Patreon so i can keep helping
Back to top
View user's profile Send private message MSN Messenger
Display posts from previous:   
Post new topic   Reply to topic    Cheat Engine Forum Index -> Cheat Engine Lua Scripting All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


Powered by phpBB © 2001, 2005 phpBB Group

CE Wiki   IRC (#CEF)   Twitter
Third party websites