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 


Help programming interactivity into infinite loop

 
Post new topic   Reply to topic    Cheat Engine Forum Index -> Cheat Engine Lua Scripting
View previous topic :: View next topic  
Author Message
WeaMas
How do I cheat?
Reputation: 0

Joined: 29 Jan 2018
Posts: 4

PostPosted: Mon Jan 29, 2018 10:31 am    Post subject: Help programming interactivity into infinite loop Reply with quote

I'm trying to write a LUA script to help search through bones data in DOA5 to make life easier than staring at a memory map and losing track of my place all the time. The problem is, I have no clue how to code user interactivity into a script.

I have shoved my code in a while(true) loop, I think I have a way to break the loop, but when I execute the infinite loop just causes cheat engine to say not responding. I've tried using a delay() to have the loop execute once a second, but still causes "not responding".

Code:
BaseAddress = "46566e80"
VectorSize = 3
NumVectors = 3
Indicies = VectorSize * NumVectors
Offset = 0
AddressTable = {}
FloatTable = {}
UpdateAddress = 1

openProcess("game.exe")

while(true) do
  if(UpdateAddress)
    then
    for i = 1,Indicies
      do
      AddressTable[i] = BaseAddress .. "+" .. 4*(i-1) .. "+" .. Indicies*Offset*4
      FloatTable[i] = readFloat(AddressTable[i])
      print(FloatTable[i])
      end
    UpdateAddress = 0

    end
  if(isKeyPressed(VK_NUMPAD6))
    then
    Offset = Offset+1
    UpdateAddress = 1
    end
  if(isKeyPressed(VK_NUMPAD4))
    then
    Offset = Offset-1
    UpdateAddress = 1
    end
  if(isKeyPressed(VK_SUBTRACT))
    then
    break
    end
  --break
  end


This is my skeleton code that I'm working with right now, if I don't uncomment the final break then my script gets stuck in the infinite loop. Some guidance would be nice, the stickied tutorials don't deal with interactivity or how to make your script not take up 100% cpu time.
Back to top
View user's profile Send private message
FreeER
Grandmaster Cheater Supreme
Reputation: 53

Joined: 09 Aug 2013
Posts: 1091

PostPosted: Mon Jan 29, 2018 11:35 am    Post subject: Reply with quote

Yeah lua scripts are ran in the same thread as the GUI by default so an infinite loop is going to freeze things, similarly having the code constantly looping is going to eat the CPU

The solution is to A) use a thread and B) "sleep" so the processor can run a different thread for awhile

Code:
createThread(function()
  while true do
    ... -- do whatever
    sleep(100)
  end
end)


btw, you'll probably want to check input before using it (Offset/UpdateAddress), that way the user doesn't change press a key and then have to wait 100 milliseconds or whatever your loop's delay is before it actually takes affect.

Oh, and 0 is considered "true" in lua, eg. if 0 then print('hi') end will print "hi". Use the boolean values true and false (my preference) or explicitly check == 1 / ~= 0 / not (... == 0). You can also use nil instead of false but that can have unintended effects, particularly with tables, since it's the implicit value for anything not given a value.
Back to top
View user's profile Send private message
WeaMas
How do I cheat?
Reputation: 0

Joined: 29 Jan 2018
Posts: 4

PostPosted: Mon Jan 29, 2018 3:38 pm    Post subject: Reply with quote

Is there any quick reference you can link for createThread()? I've looked through the Lua 5.3 reference and I only see coroutine.create() for threads, and it looks significantly more complicated to use.

0 acting as true makes me a little bit peeved if that's true. I had a little bit of experience in C++ before trying to do this and I'm used to 0 being cast as false (although my textbook made sure to state many times that False != 0).

And yeah, I know that I'd probably want to check for input first before running any code, I just wanted to get the most important parts of the code up and working before I organized. I actually had to debug the address and float tables for a while because I didn't realize that readFloat doesn't read decimal. Is there a way to get it to read decimal/integers properly?
Back to top
View user's profile Send private message
TheyCallMeTim13
Wiki Contributor
Reputation: 50

Joined: 24 Feb 2017
Posts: 976
Location: Pluto

PostPosted: Mon Jan 29, 2018 4:19 pm    Post subject: Reply with quote

createThread is added by Cheat Engine, The wiki is an ok place to check (no thread class yet) but the best place is the "celua.txt" text file in the CE folder.

And yeah, I just tend to try and be more explicit, you tend to find a lot of odd ball behavior in a verity of languages. So less duck typing and more direct checks. But I think in Lua and some others any thing that's not false, nil, or none is true.

WeaMas wrote:
... readFloat doesn't read decimal. Is there a way to get it to read decimal/integers properly?


Not sure what you mean, but "readFloat" just reads the bytes at a given address as a single precision floating point and returns a Lua number object, in Lua there are no decimal types and all numbers are in decimal format. Maybe "readInteger" is what you need.

_________________
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: Mon Jan 29, 2018 4:36 pm    Post subject: Reply with quote

Hm, apparently the only place it's documented for lua is in the celua.txt file in the CE install directory, while the built-in help has a lot I don't see it there (just the createThread of AA code, same purpose essentially, just assembly not lua), nor is it mentioned on the wiki (TheyCallMeTim13 has been updating it lately). I've pasted the documentation below.

Yeah, there are a couple things like that in lua, for example tables start at 1. While you can put things in index 0, things like ipairs will skip it. In a way I applaud Lua for not doing something just because that's how some other language did it, but it can cause a couple issues if you don't realize that there can be differences. (note: many CE functions return userdata objects that start at 0, but a few do return lua tables that start at 1, so... yeah lol)

Also false is 0, though for things that return a failure code 0 is probably "success" so that actual values can be used for looking up actual error messages. That's different from false not being 0. A "true" value however can be any non-zero value, though the explicit true macro/keyword is almost always 1; As are normalized booleans which I believe C++ forces on assignment now, essentially equivalent to !!((bool)x).

readFloat should read decimals, readInteger exists but it won't read a floating point value in the way one might hope for. Once you've read a float you can use math.floor / ceil / round to make it an integer.



Code:
Thread Class: (Inheritance: Object)
createThread(function(Thread,...), ...) :
  Executes the given function in another thread using the systems thread mechanism
  The function returns the Thread class object
  function declaration: function (Thread, ...)

createThreadSuspended(function(Thread,...), ...) :
  Same as createNativeThread but it won't run until resume is called on it


properties
  name: string - This name will be shown when the thread terminated abnormally
  Finished: boolean - Returns true if the thread has reached the end.  Do not rely on this if the thread is freeOnTerminate(true) (which is the default)
  Terminated: boolean - Returns true if the Terminate method has been called

methods
  freeOnTerminate(state) :
    When set to true the thread object will free itself when the function ends (default=true)
    Note: Use this only from inside the thread function as the thread might have already terminated and freed itself when called

  synchronize(function(thread, ...), ...) :
    Called from inside the thread. This wil cause the tread to get the main thread to execute the given function and wait for it to finish.
    Usually for GUI access
    Returns the return value of the given function

  waitfor() :
    Waits for the given thread to finish (Not recommended to call this from inside the thread itself)

  suspend() :
    Suspend the thread's execution

  resume() :
    Resume the thread;s executionmm

  terminate() :
    Tells the thread it should terminate. The Terminated property will become true
Back to top
View user's profile Send private message
WeaMas
How do I cheat?
Reputation: 0

Joined: 29 Jan 2018
Posts: 4

PostPosted: Mon Jan 29, 2018 5:02 pm    Post subject: Reply with quote

I should have been more specific when I asked if readFloat could read integers or decimal. I meant instead of the address of the float to be read being formatted as hex (46566e80 in my example code), the address could be converted to a decimal number (0x46566e80 => 1180069504). It's just easier to work with integers than to treat the addresses as strings.

The original problem I was having was just that, I formatted all hex values as integers and then put them into readFloat, which obviously caused them to return nil because it's way out of bounds when read as a hexadecimal input.
Back to top
View user's profile Send private message
TheyCallMeTim13
Wiki Contributor
Reputation: 50

Joined: 24 Feb 2017
Posts: 976
Location: Pluto

PostPosted: Mon Jan 29, 2018 5:10 pm    Post subject: Reply with quote

readFloat
readFloat takes integers or strings for the address.
Code:
local flt = readFloat(1180069504)

Code:
local flt = readFloat(0x46566E80)

Code:
local flt = readFloat('46566E80')

Code:
local flt = readFloat('[[00123ABC]+4]+18')


But numbers in address strings are interpreted as hexadecimal.

You can use "getAddress" to just return the integer value. getAddress

_________________
Back to top
View user's profile Send private message Visit poster's website
WeaMas
How do I cheat?
Reputation: 0

Joined: 29 Jan 2018
Posts: 4

PostPosted: Mon Jan 29, 2018 5:51 pm    Post subject: Reply with quote

I'm getting it to work now, odd. I think before I was trying to reference the AddressTable in the readFloat function by doing:

Code:
FloatTable.i = readFloat(AddressTable.i)


So you can't use variables/index in the dot notation for arrays?


Last edited by WeaMas on Mon Jan 29, 2018 6:09 pm; edited 1 time in total
Back to top
View user's profile Send private message
FreeER
Grandmaster Cheater Supreme
Reputation: 53

Joined: 09 Aug 2013
Posts: 1091

PostPosted: Mon Jan 29, 2018 5:59 pm    Post subject: Reply with quote

AddressTable.i is equivalent to addressTable['i'] (string/hash table) not addressTable[i] (number/array), which is not the same as addressTable[tostring(i)]

example

Code:
local i = 123
local AddressTable = {}
AddressTable.i = "I'm I!"
AddressTable[i] = "No I'm i!"
--AddressTable['i'] = "I'm really I too!"
AddressTable[tostring(i)] = 'I wanna be i!'
for k,v in pairs(AddressTable) do
  print(k,'-', type(k),'-', v)
end
result
Code:
123 - string - I wanna be i!
i - string - I'm I!
123 - number - No I'm i!

-- uncommented
123 - string - I wanna be i!
i - string - I'm really I too!
123 - number - No I'm i!


edit: note that lua strings in lua are immutable (so you can't change a string, only create a new one) but lua will check if the string already exists in memory before recreating it. So two strings with the same content will be equal, unlike C where strings can have the same content but be in different memory locations and so compare as different because the pointers are different.

Tables however are much like you might think of strings
Code:
local AddressTable = {}
local oneString = 'Hello World!'
local multiple = 'Hello' .. " World" .. '!'
AddressTable[oneString] = 1
AddressTable[multiple] = 2
AddressTable[multiple .. '1'] = 3
for k,v in pairs(AddressTable) do
  print(k,'-', type(k),'-', v)
end
print(('-'):rep(30))

local t1 = {['cat']=1,['dog']=2}
local t2 = {['cat']=1,['dog']=2}
local t3 = t1 -- reference
t3.cat = 5
t3.dog = 32
t3.answer = 42
AddressTable[t1] = 'catdog!'
AddressTable[t2] = 'dogcat!'
AddressTable[t3] = 'what?'
for k,v in pairs(AddressTable) do
  -- answer index from key, if it exists
  local answer = type(k) == 'table' and k.answer
  print(tostring(k),'-', type(k),'-', v, answer)
end
print(tostring(AddressTable[tostring(t1)]))
result
Code:
Hello World!1 - string - 3
Hello World! - string - 2
------------------------------
Hello World!1 - string - 3 
table: 00000000033156F0 - table - dogcat! 
table: 00000000033156B0 - table - what? 42
Hello World! - string - 2
nil


edit: oh, and like tostring(i) is different from i, AddressTable[t1] is not the same as AddressTable[tostring(t1)], just to cover that potential case as well Smile
Back to top
View user's profile Send private message
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