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 


Ultimate Float Script WANTED

 
Post new topic   Reply to topic    Cheat Engine Forum Index -> Cheat Engine Lua Scripting
View previous topic :: View next topic  
Author Message
theboy181
Advanced Cheater
Reputation: 0

Joined: 26 Jan 2018
Posts: 91

PostPosted: Sat Jan 27, 2018 12:48 pm    Post subject: Ultimate Float Script WANTED Reply with quote

I was wondering if someone with the knowledge could help me with a script.

I would like to have two different types of functionality with float searches.

The ability to do a search for floats that are whole numbers only (no decimals)

A range of whole numbered floats, (example 1000 - 5550)

Would pay for this script if its too much work.
PM me.
Back to top
View user's profile Send private message
OldCheatEngineUser
Whateven rank
Reputation: 20

Joined: 01 Feb 2016
Posts: 1586

PostPosted: Sat Jan 27, 2018 1:03 pm    Post subject: Reply with quote

im not sure why would you need a script while CE have it own function of searching ranged value, for sure you might use truncated search too. (you will get 1 or 2 decimals)
_________________
About Me;
I Use CE Since Version 1.X, And Still Learning How To Use It Well!
Jul 26, 2020
STN wrote:
i am a sweetheart.
Back to top
View user's profile Send private message Visit poster's website
TheyCallMeTim13
Wiki Contributor
Reputation: 51

Joined: 24 Feb 2017
Posts: 976
Location: Pluto

PostPosted: Sat Jan 27, 2018 1:19 pm    Post subject: Reply with quote

I just do #.0 for whole numbers on floats (100.0 -> 500.0), just use a range or exact value scan.
_________________
Back to top
View user's profile Send private message Visit poster's website
FreeER
Grandmaster Cheater Supreme
Reputation: 53

Joined: 09 Aug 2013
Posts: 1091

PostPosted: Sat Jan 27, 2018 2:21 pm    Post subject: Reply with quote

As mentioned for a single whole number you can just add .0 (I usually use 3-5 0s lol) but yeah, a value between scan still returns non-whole numbers when using that method....

You can make up something like this easily enough:

Code:
function findWholeValue(min, max, findType, protectionflags, numDigitsAfterDecimal)
  -- handle not having required arguments
  if not min or not max then return nil end
  if tonumber(min) > tonumber(max) then min,max = max, min end
  -- default values
  findType = findType or vtSingle
  protectionflags = protectionflags or "+W-X-C"
  numDigitsAfterDecimal = numDigitsAfterDecimal or 0

  -- do scan
  memscan = createMemScan()
  memscan.firstScan(soValueBetween, findType, rtRounded, min, max,
               "0", "7fffffffffffffff", protectionflags,
               fsmAligned,"4", false, false, false, false)
  local done = {}
  done.results = {}
  done.finished = false
  memscan.OnScanDone = function(memscan)
    print('done')
    local results = done.results
    foundlist = createFoundList(memscan)
    foundlist.initialize()
    local rf = findType == vtSingle and readFloat or readDouble
    for i=0,foundlist.Count-1 do
      local value = rf(foundlist[i])
      local strValue = tostring(value)
      local fraction = strValue:match('%.(.+)')
      if fraction == '0' then fraction = '' end
      if not fraction or #fraction <= numDigitsAfterDecimal then
        results[#results+1] = {foundlist[i],value}
        print(foundlist[i], value)
      end
    end
    foundlist.deinitialize()
    foundlist.destroy()
    memscan.destroy()
    done.finished = true
  end
  done.memscan = memscan
  memscan.waitTillDone()
  print('returning')
  return done
end
local info = findWholeValue(100,500, vtDouble, nil, 5)
info.memscan.waitTillDone()
print('displaying')
return info.results
which when I run it results in:
Code:
returning
displaying
:table
[
]
done
0168D09C 179.2
016933F0 100.0
But it should result in something like
Code:
done
0168D09C 179.2
016933F0 100.0
returning
displaying
:table
[
   1 = table
   [
      1 = 0168D09C
      2 = 179.2
   ]
   2 = table
   [
      1 = 016933F0
      2 = 100.0
   ]
]

and I have no idea why it's not actually waiting until the memory scan is complete before continuing on with the code....
Back to top
View user's profile Send private message
theboy181
Advanced Cheater
Reputation: 0

Joined: 26 Jan 2018
Posts: 91

PostPosted: Sat Jan 27, 2018 3:33 pm    Post subject: Reply with quote

How do I do a range scan with floats? I can't seem to find it anywhere, and the example 100.0 -> 500.0 doesn't seem to work.
Back to top
View user's profile Send private message
TheyCallMeTim13
Wiki Contributor
Reputation: 51

Joined: 24 Feb 2017
Posts: 976
Location: Pluto

PostPosted: Sat Jan 27, 2018 4:45 pm    Post subject: Reply with quote

Range scan is just a "Value Between" scan, and "100.0 -> 500.0" was just my way of showing the range values, but I guess when I do this I actually use "Exact value" and just undo the scan after adding the addresses to the address list, I just assumed that it works for "Value Between" scans, I should have tested it first I guess.
<-- That's way the heads hanging.

_________________
Back to top
View user's profile Send private message Visit poster's website
theboy181
Advanced Cheater
Reputation: 0

Joined: 26 Jan 2018
Posts: 91

PostPosted: Sat Jan 27, 2018 5:55 pm    Post subject: Reply with quote

Thanks, I figured that is what you meant. It kinda work as expected, but I still got a large amount of decimals.. Sad


Thanks you.

I tried running that script above, and I was unable to figure out how to use it,


A cool feature for Cheat Engine would be able to save a preferred cheat list search.

Run a list of common searches.. this would be very helpful when Looking for common areas in N64 Roms.
Back to top
View user's profile Send private message
ParkourPenguin
I post too much
Reputation: 152

Joined: 06 Jul 2014
Posts: 4697

PostPosted: Sat Jan 27, 2018 6:52 pm    Post subject: Reply with quote

Here's a custom type that'll treat every float with a fractional part as a QNaN (i.e. won't be found in searches):
Code:
alloc(ConvertRoutine,1024)
alloc(ConvertBackRoutine,1024)
alloc(TypeName,256)
alloc(ByteSize,4)
alloc(UsesFloat,1)
alloc(CallMethod,1)

TypeName:
db 'Float (Integers)',0

ByteSize:
dd 4

UsesFloat:
db 1

CallMethod:
db 1

//cdecl int ConvertRoutine(unsigned char *input, PTR_UINT address);
ConvertRoutine:
[64-bit]
mov eax,7fc00000
mov edx,[rcx]
mov ecx,edx
shr ecx,17
inc cl
jns @f
  mov r8d,edx
  and ecx,7F
  add ecx,9
  and r8d,007fffff
  shl r8d,cl
  test cl,60
  cmovnz eax,edx
  test r8d,r8d
  cmovz eax,edx
@@:
ret
[/64-bit]

[32-bit]
push ebx
mov eax,[esp+8]
mov edx,[eax]
mov eax,7fc00000
mov ecx,edx
shr ecx,17
inc cl
jns @f
  and ecx,7f
  mov ebx,edx
  and ebx,007fffff
  add ecx,09
  shl ebx,cl
  test cl,60
  cmovnz eax,edx
  test ebx,ebx
  cmovz eax,edx
@@:
pop ebx
ret
[/32-bit]

// cdecl void ConvertBackRoutine(int i, PTR_UINT address, unsigned char *output);
ConvertBackRoutine:
[64-bit]
mov [r8],ecx
ret
[/64-bit]

[32-bit]
mov eax,[esp+4]
mov ecx,[esp+C]
mov [ecx],eax
ret
[/32-bit]

Right click the value type combobox (e.g. where it says "4 Bytes"), select "Define new custom type (Auto Assembler)", and copy/paste the above code into that window.

_________________
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
FreeER
Grandmaster Cheater Supreme
Reputation: 53

Joined: 09 Aug 2013
Posts: 1091

PostPosted: Sat Jan 27, 2018 9:29 pm    Post subject: Reply with quote

Thanks ParkourPenguin though... I don't fully understand how it works lol

I understand the high level concept of it returning a Not A Number value which will fail the compare and not be kept in the search results but how it actually determines whether it's a whole number escapes me in a few key parts lol

Here's how I've commented the x64 code

Code:
// http://steve.hollasch.net/cgindex/coding/ieeefloat.html
// anatomy of a float / real32
// 1 Sign Bit, 8 Exponent bits, 23 mantissa bits
// S EEEEEEEE MMMMMMMM MMMMMMMM MMMMMMM_
//   SEEEEEEE EMMMMMMM MMMMMMMM MMMMMMMM
// shr 0x17 = remove mantissa, S EEEEEEEE
mov eax,7fc00000 // QNaN default return value
mov edx,[rcx]    // read float into edx
mov ecx,edx      // copy float into ecx
shr ecx,0x17     // remove mantissa and put expontent into cl
inc cl           // increment exponent
jns @f           // return NaN if exponent is less than 127, which is actually 0 because reasons
// since negative exponents = dividing and if you're dividing you're not going to end up with a whole number
// this also excludes infinity and NaN which have an exponent of all 1s, +1 = 0, which is not signed
  and ecx,7F       // remove original sign bit and exponent sign bit (which was 1 or we'd have jumped ^)
// so 0 = 127, +1 = 128, &7F = 0
// 22 = 127+22 = 149, +1 = 150, &7F = 22 etc.
  add ecx,9        // add 9 to exponent...  why???
  mov r8d,edx      // copy original value
  and r8d,007fffff // keep only 23 mantissa bits
  shl r8d,cl       // shift mantissa by exponent (at least 9)
  test cl,60       // test exponent for bits 0110 0000  ???
  cmovnz eax,edx   // if set return original value
  test r8d,r8d     // if 0
  cmovz eax,edx    // return original value
@@:
ret


I almost feel like I understand enough to create one for doubles but...I've spent enough hours trying to wrap my head around this for now (stupid +127 bias caused a lot of it Mad Mad Laughing )

oh, and I noticed this treats 0 as non-integer... not sure if that's useful because it could lead to false positives but trivial to change by explicitly checking for 0 if desired.
Back to top
View user's profile Send private message
mgr.inz.Player
I post too much
Reputation: 222

Joined: 07 Nov 2008
Posts: 4438
Location: W kraju nad Wisla. UTC+01:00

PostPosted: Sun Jan 28, 2018 3:18 am    Post subject: This post has 1 review(s) Reply with quote

Simpler "Float (Integers)"

Code:
alloc(ConvertRoutine,1024)
alloc(ConvertBackRoutine,1024)
alloc(TypeName,256)
alloc(ByteSize,4)
alloc(UsesFloat,1)
alloc(CallMethod,1)

TypeName:
db 'Float (Integers)',0

ByteSize:
dd 4

UsesFloat:
db 1

CallMethod:
db 1

ConvertRoutine:
[64-bit]
mov eax,[rcx]
[/64-bit]

[32-bit]
mov eax,[esp+4]
mov eax,[eax]
[/32-bit]

movd xmm0,eax
cvtps2dq xmm1,xmm0 // convert single to integer
cvtdq2ps xmm1,xmm1 // convert integer to single

ucomiss xmm0,xmm1
je @f
mov eax,NaN

@@:
ret


ConvertBackRoutine:
// read only
ret




EDIT:
"Double (Integers)"

Code:
alloc(ConvertRoutine,1024)
alloc(ConvertBackRoutine,1024)
alloc(TypeName,256)
alloc(ByteSize,4)
alloc(PreferedAlignment,4)
alloc(UsesFloat,1)
alloc(CallMethod,1)

TypeName:
db 'Double (Integers)',0

ByteSize:
dd 8

PreferedAlignment:
dd 4

UsesFloat:
db 1

CallMethod:
db 1

ConvertRoutine:
[64-bit]
movsd xmm0,[rcx]
[/64-bit]

[32-bit]
mov eax,[esp+4]
movsd xmm0,[eax]
[/32-bit]

cvtsd2ss xmm0,xmm0 // convert double to single
movd eax,xmm0

cvtps2dq xmm1,xmm0 // convert single to integer
cvtdq2ps xmm1,xmm1 // convert integer to single

ucomiss xmm0,xmm1
je @f
mov eax,NaN

@@:
ret


ConvertBackRoutine:
// read only
ret

_________________
Back to top
View user's profile Send private message MSN Messenger
ParkourPenguin
I post too much
Reputation: 152

Joined: 06 Jul 2014
Posts: 4697

PostPosted: Sun Jan 28, 2018 10:03 am    Post subject: Reply with quote

FreeER:
Here's some similar C code with documentation.
Code:
uint32_t modify(uint32_t *n)
{
    const uint32_t value = *n;  // the value (CE passes a pointer)
    const uint32_t bad_value = 0x7FC00000;  // QNaN

    uint8_t exponent = (value >> 23) & 0xff;  // extract the 8 exponent bits
    uint32_t mantissa = value & 0x7fffff;    // extract the 23 fractional bits (aka mantissa)

    // if the exponent is FF or <7F, it's not an integer
    // so, increment it and if the most significant bit is 0, it's not an integer
    // (note that I forgot about the integer 0, so this fails in that case)
    ++exponent;
    if ((exponent & 0x80) == 0)
        return bad_value;

    // this is effectively getting the true exponent
    exponent &= 0x7f;
    // here, the most significant bit of the exponent must be 1, so equivalent code would be:
    // exponent -= 128;   // -127 for the exponent bias, -1 for the previous increment


    // (for brevity, let exp = exponent)
    // the value is now in the form value = 2^exp * mantissa
    //
    // this can be seen as fixed point arithmetic
    // the mantissa, as a 32-bit fixed point binary number, is 000000000.MMMMMMMMMMMMMMMMMMMMMMM
    // it is being multiplied by 2^exp (0 <= exp <= 7F), so just shift it left by exp
    // after that, if any bit to the right of the decimal point is set, there is a fractional part
    // those first 9 bits would contribute to the integral part of the value, so they don't matter
    // I shifted them away, but they could also be masked away with 0x007fffff

    // with regards to C, it's undefined behaviour to shift a 32-bit value by >=32 positions
    // check Intel's documentation for what happens with shl; regardless, it must be dealt with
    // in this case, there can't be a fractional part for exp >= 23, so assume it's an integer
    // in assembly, it's probably faster to check if any of bits 5-7 are set

    if (((exponent + 9) & 0xE0) != 0)
        return value;

    uint32_t frac = mantissa << (exponent + 9);
   
    // at this point, there will only be a fractional part if any bit is set in frac
    // if frac == 0, there isn't a fractional part; else, there is, so return QNaN
    return frac == 0 ? value : bad_value;
}


mgr.inz.Player:
SSE / x87 would've been simpler, but my way was more fun Razz

_________________
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
FreeER
Grandmaster Cheater Supreme
Reputation: 53

Joined: 09 Aug 2013
Posts: 1091

PostPosted: Sun Jan 28, 2018 12:06 pm    Post subject: Reply with quote

Thanks alot ParkourPenguin, though I'm afraid I don't completely understand the +9 still lol It'd kind of make sense for the mantissa to shift out the sign and exponent bits but... they were already masked out at the start so it seems unnecessary.

Oh and mgr.inz.Player good reminder that you can use existing instructions to do a lot of the work lol
I still enjoyed learning from the more complicated script though Razz
Back to top
View user's profile Send private message
mgr.inz.Player
I post too much
Reputation: 222

Joined: 07 Nov 2008
Posts: 4438
Location: W kraju nad Wisla. UTC+01:00

PostPosted: Sun Jan 28, 2018 2:11 pm    Post subject: Reply with quote

@ParkourPenguin, I know. I also enjoyed making some custom types, for example population count (link to algo) and it worked very well. For 32bit type I used generic CPU registers, for 64bit type I used MMX registers (in 64bit CE I used RAX and RBX).
http://forum.cheatengine.org/viewtopic.php?t=565981


But, modern CPU have SSE4.2 and above, so I just tried POPCNT. I made few speed benchmarks...

Currently, CE Assembler doesn't recognize this instruction, I had to use:
Code:
dd C0B80FF3 // popcnt eax,eax


Anyway, population count, a neat tool when you want to search for flags. E.g. Dead Space 3 flags like: isVacum, isNoGravity, isPlayerStandingOnPowerPlate, or Metro: Last Light flag: bShowCrosshair.


@FreeER, I agree.

_________________
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