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 


Execute code while process is paused

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

Joined: 05 Mar 2025
Posts: 6

PostPosted: Wed Mar 05, 2025 3:13 am    Post subject: Execute code while process is paused Reply with quote

I want to execute assembly code while the process is paused and have tried the following:

Code:
[enable]
{$lua}
pause()

{$asm}
createthreadandwait(symbol)

{$lua}
unpause()
[disable]


The problem with this is if the executed assembly accesses an address that CE is currently monitoring, it freezes both the process and CE. If I add a timeout, it will eventually recover, but I want it to wait as long as it takes for the thread to finish. The "execute asynchronous" checkbox is also toggled off in case that matters.
Back to top
View user's profile Send private message
Dark Byte
Site Admin
Reputation: 470

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

PostPosted: Wed Mar 05, 2025 4:36 am    Post subject: Reply with quote

first off, you're not pausing

first
Code:

{$lua}
pause()

{$asm}

is executed and the result will be put at that spot

then
Code:

{$lua}
unpause()

gets executed and it's result will be put at that spot as well

then it assembles
Code:

<luascript1 result>
<luascript2 result>


then createthreadandwait(symbol) is handled which creates a thread at symbol and won't return until it's done

As for why Ce would be freezing for an async record i'm not sure. Do you try to touch the addresslist in other code ?

_________________
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
christin50
How do I cheat?
Reputation: 0

Joined: 05 Mar 2025
Posts: 6

PostPosted: Wed Mar 05, 2025 5:33 am    Post subject: Reply with quote

I am surprised it's possible to put an asm block in the middle of a lua block if it is not going to execute in the middle of it anyway. I think this is kind of confusing. I would expect some kind of error or at least a warning in such a case.

If I do:
Code:
[enable]
createthreadandwait(symbol)

[disable]


and use "find out what accesses this address" on an address which this assembly code is going to access, it will freeze both the process and CE forever (unless I use the optional timeout argument). The same happens if I set a breakpoint inside the assembly code. Is this expected? I am not running any other code that accesses the address list.

Also what would be the proper way to do what I am trying to do? As in pause the process, execute a function at a specific address, then unpause the process again.
Back to top
View user's profile Send private message
HenryEx
Expert Cheater
Reputation: 2

Joined: 18 Dec 2011
Posts: 100

PostPosted: Wed Mar 05, 2025 9:11 am    Post subject: Reply with quote

The asm block isn't in the middle of a lua block. It's actually exactly the opposite. It's an asm block with two lua scripts in it.

The parser gets your AA script and sees that there's lua sections in it. Before parsing the AA commands and converting those to assembly, it executes the lua script portion. in this case, a simple "pause()". The lua code gets compiled, executed, and its return value gets put into the AA script at this place.
Then the second (and third etc) lua script get compiled and executed and their return values placed into the AA script.

Afterwards, the parser starts working and putting the AA commands and the results from your lua scripts into machine code and assembles them into the target process.

In your case, this gets assembled into asm:
Code:

<return value of pause()>
createthreadandwait(symbol)
<return value of pause()>
Back to top
View user's profile Send private message
christin50
How do I cheat?
Reputation: 0

Joined: 05 Mar 2025
Posts: 6

PostPosted: Wed Mar 05, 2025 10:52 am    Post subject: Reply with quote

Interesting. I didn't know it worked like that. I had assumed that it would only get compiled, not executed directly. Thanks for the explanation.

Do you know how to accomplish what I was trying to do? I didn't find anything in the wiki.
Back to top
View user's profile Send private message
HenryEx
Expert Cheater
Reputation: 2

Joined: 18 Dec 2011
Posts: 100

PostPosted: Wed Mar 05, 2025 1:24 pm    Post subject: Reply with quote

christin50 wrote:
Interesting. I didn't know it worked like that. I had assumed that it would only get compiled, not executed directly. Thanks for the explanation.

Do you know how to accomplish what I was trying to do? I didn't find anything in the wiki.


If you absolutely have to execute some lua code during assembler runtime, you should take a look at {LUACODE}. Very slow and inefficient if you just want to pause the process though.

Maybe a better idea would be to execute your AA commands during the lua script instead of the other way around. Which means you only use {lua} blocks, and use the autoAssemble() lua command to assemble an AA script during lua runtime.
Back to top
View user's profile Send private message
christin50
How do I cheat?
Reputation: 0

Joined: 05 Mar 2025
Posts: 6

PostPosted: Wed Mar 05, 2025 3:38 pm    Post subject: Reply with quote

Well, it's not like I want to execute Lua code. It's more like I have to as there is no auto assembler command to pause and unpause the target process.

I cannot use "{luacode}" since as soon as I use "pause", it will not process the next assembly code block. It doesn't matter whether I have the "execute asynchronous" checkbox ticked or not.

I have found 2 methods to accomplish what I wanted to:

Method 1 (lua)
Code:
[enable]
{$lua}
pause()
local scriptStr = [[createthreadandwait(symbol)]]
autoAssemble(scriptStr)
unpause()
[disable]


The functions "pause" and "unpause" handle the target process, while the "createthreadandwait" command handles the CE process, just as expected.

Method 2 (auto assembler)
Code:
[enable]
{$lua}
local function stop()
  pause()
end

local function resume()
  unpause()
end

registerAutoAssemblerCommand('stop', stop)
registerAutoAssemblerCommand('resume', resume)
[disable]

and then
Code:
[enable]
stop()
createthreadandwait(symbol)
resume()
[disable]


Both of these methods must have the "execute asynchronous" checkbox ticked. Otherwise setting a breakpoint inside the executed assembly code will freeze the CE process forever. I think it would be better if breakpoints were ignored in such a case.

Also, saving the script by clicking on the "OK" button will also always execute it synchronously, regardless of the "execute asynchronous" checkbox value. This then also causes a freeze like in the example from above.

Finally, if the checkbox is ticked, it's not possible to do "memrec.active = false" afterwards. I have tried:

Code:
...
unpause()
createTimer(100, function() memrec.active = false end)


but no matter how high I set the timer, the checkbox is always ticked afterwards. Am I missing something?
Back to top
View user's profile Send private message
ParkourPenguin
I post too much
Reputation: 152

Joined: 06 Jul 2014
Posts: 4695

PostPosted: Wed Mar 05, 2025 5:03 pm    Post subject: Reply with quote

christin50 wrote:
since as soon as I use "pause", it will not process the next assembly code block
There is no "next assembly code block". The {$asm} tag only indicates the end of the {$lua} block.

christin50 wrote:
It doesn't matter whether I have the "execute asynchronous" checkbox ticked or not.
"Execute asynchronous" means CE tries to enable / disable the AA script in another thread.

christin50 wrote:
Both of these methods must have the "execute asynchronous" checkbox ticked. Otherwise setting a breakpoint inside the executed assembly code will freeze the CE process forever.
As expected since you used `createthreadandwait`. CE must wait for the thread to finish (infinitely, since you didn't specify a timeout), and the thread needs to wait for CE to handle the breakpoint. Classic deadlock scenario.
As you said, you should disable the relevant breakpoints before `createthreadandwait`. CE can't do that for you since it doesn't know which ones should or shouldn't be active.

christin50 wrote:
Also, saving the script by clicking on the "OK" button will also always execute it synchronously, regardless of the "execute asynchronous" checkbox value.
You're missing `if syntaxcheck then return end` at the top of all the {$lua} blocks. Since {$lua} blocks can return a string that gets substituted into the AA script, they need to be run during syntax checks. Any side effects of {$lua} blocks should probably be skipped during this syntax check stage.

christin50 wrote:
Finally, if the checkbox is ticked, it's not possible to do "memrec.active = false" afterwards
All GUI accesses must be done from the main thread. Both timers and several memory record operations access the GUI. When a memory record is executed asynchronously, {$lua} blocks are run in a separate thread. Use `synchronize`

Example:
Code:
[ENABLE]
{$lua}
if syntaxcheck then return end

pause()

if inMainThread() then
  createThread(function()
    executeCode'symbol'
  end)

  createTimer(1, function()
    memrec.Active = false
  end)
else
  executeCode'symbol'

  synchronize(function()
    createTimer(1, function()
      memrec.Active = false
    end)
  end)

end

unpause()

{$asm}

[DISABLE]

_________________
I don't know where I'm going, but I'll figure it out when I get there.


Last edited by ParkourPenguin on Wed Mar 05, 2025 7:37 pm; edited 1 time in total
Back to top
View user's profile Send private message
HenryEx
Expert Cheater
Reputation: 2

Joined: 18 Dec 2011
Posts: 100

PostPosted: Wed Mar 05, 2025 5:52 pm    Post subject: Reply with quote

ParkourPenguin wrote:
All GUI accesses must be done from the main thread. Both timers and several memory record operations access the GUI. When a memory record is executed asynchronously, {$lua} blocks are run in a separate thread. Use `synchronize`

Example:
Code:
[ENABLE]
{$lua}
if syntaxcheck then return end

pause()

if inMainThread() then
  createThread(function()
    executeCode'symbol'
  end)

  createTimer(1, function()
    memrec.Active = false
  end)
else
  executeCode'symbol'

  synchronize(function()
    createTimer(function()
      memrec.Active = false
    end)
  end)

end

unpause()

{$asm}

[DISABLE]


Thank you. This (probably) solves a problem i was having, in that i was having trouble with a function that sets up several threads, then creates a timer that watches for all threads' completion. The timer was not working when i used the function in my (async) memrec script, but it worked when running tests directly from Lua engine, which had me pulling my hair out.

Is the problem that said timer was orphaned / destroyed when the thread running the memrec script ends, or do timers in general only ever work when not created asynchronously?

And the wiki lists synchronize as a Timer class method, do i not have to call it with something like self.synchronize() within the thread?



As for the "untick checkbox after firing script" (is what i assume you want, i do something similar), you can also set the OnActivate property of that memory record to switch off automatically after activation.
Code:

local toggledelay = 100
local function AutoOff ( this, before, state )
  if before then return true end
  createThread( function() sleep(toggledelay) this.Active = false end )
end

local mr = getAddressList().getMemoryRecordByDescription('Record Name Here')
mr.OnActivate = AutoOff

This gives you a configurable delay (100ms is enough to see a little blink of activatoin to know it worked), but you can also remove the delay and instead of creating a thread that waits for deactivation, just deactivate the memory record right away.
Back to top
View user's profile Send private message
ParkourPenguin
I post too much
Reputation: 152

Joined: 06 Jul 2014
Posts: 4695

PostPosted: Wed Mar 05, 2025 7:37 pm    Post subject: Reply with quote

HenryEx wrote:
Is the problem that said timer was orphaned / destroyed when the thread running the memrec script ends, or do timers in general only ever work when not created asynchronously?
Timers need to be created from the main thread. I'm not familiar enough with pascal / lazarus to know why.

HenryEx wrote:
And the wiki lists synchronize as a Timer class method, do i not have to call it with something like self.synchronize() within the thread?
It's also a global function
celua.txt:
Quote:
synchronize(function(...), ...): Calls the given function from the main thread. Returns the return value of the given function


HenryEx wrote:
Code:
createThread( function() sleep(toggledelay) this.Active = false end )
Don't set memrec.Active in another thread. That runs code that accesses the GUI.
_________________
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
HenryEx
Expert Cheater
Reputation: 2

Joined: 18 Dec 2011
Posts: 100

PostPosted: Thu Mar 06, 2025 1:51 am    Post subject: Reply with quote

ParkourPenguin wrote:
HenryEx wrote:
Code:
createThread( function() sleep(toggledelay) this.Active = false end )
Don't set memrec.Active in another thread. That runs code that accesses the GUI.

For whatever it's worth, i know that the auto-disable via thread works despite not running on main thread, because i've been using it without problems for a while now.
I know, it's weird.


And when it comes to timers, do you only have to create them on main thread or do you also need to set all their variables with synchronize? I'm assuming when using a timer you want this:
Code:
if inMainThread() then
  myTimer = createTimer(nil, false)
else
  myTimer = synchronize( function() return createTimer(nil, false) end )
end

If you want to set Inteval, onTimer, Enabled etc. later on, does that also require synchronize or can you do that in a thread?
Back to top
View user's profile Send private message
christin50
How do I cheat?
Reputation: 0

Joined: 05 Mar 2025
Posts: 6

PostPosted: Thu Mar 06, 2025 2:52 am    Post subject: Reply with quote

Quote:
As you said, you should disable the relevant breakpoints before `createthreadandwait`. CE can't do that for you since it doesn't know which ones should or shouldn't be active.

If CE is waiting for a thread to finish, it shouldn't be trying to handle breakpoints from the same thread in the first place. It knows it's waiting, where breakpoints are set and which thread is executing code at a breakpoint. Sounds like a simple "if waiting for a thread, do not break on same thread". Maybe it's more complicated due to the way CE is coded, but I don't see how it should be impossible to prevent the deadlock if you really wanted to.

Quote:
You're missing `if syntaxcheck then return end` at the top of all the {$lua} blocks. Since {$lua} blocks can return a string that gets substituted into the AA script, they need to be run during syntax checks. Any side effects of {$lua} blocks should probably be skipped during this syntax check stage.

I am using "{luacode}" not "{lua}". Or does that not make a difference? Also, is it necessary to run the lua block instead of just compiling it when I am not even returning anything? Or is this behavior intended?

Quote:
"Execute asynchronous" means CE tries to enable / disable the AA script in another thread.

Quote:
All GUI accesses must be done from the main thread.

Quote:
When a memory record is executed asynchronously, {$lua} blocks are run in a separate thread. Use `synchronize`

All of this is useful information, thanks.

As for your examples, the "else part" of the code is exactly what I was looking for. However, in the "if part", your code does not work as expected as "createThread" does not wait for the code executed at "symbol" to finish. So you pause the target process, create a thread that executes code, do not wait for it (in the main thread), create a timer and then unpause. So in theory, it's possible for the target process to be unpaused before the code in the other thread is finished which is exactly what I wanted to avoid. I think it should be like this instead:

Code:
local func = function()
  pause()
  executeCode("symbol")

  synchronize(function()
    createTimer(100, function()
      memrec.Active = false
    end)
  end)

  unpause()
end

if inMainThread() then
  createThread(func)
else
  func()
end

Now the script executes as expected, regardless of whether the "execute asynchronously" checkbox is ticked or not. Not that I needed it, but it's good to still learn how it works in either case.
Back to top
View user's profile Send private message
ParkourPenguin
I post too much
Reputation: 152

Joined: 06 Jul 2014
Posts: 4695

PostPosted: Thu Mar 06, 2025 1:41 pm    Post subject: Reply with quote

christin50 wrote:
If CE is waiting for a thread to finish, it shouldn't be trying to handle breakpoints from the same thread in the first place. It knows it's waiting, where breakpoints are set and which thread is executing code at a breakpoint. Sounds like a simple "if waiting for a thread, do not break on same thread". Maybe it's more complicated due to the way CE is coded, but I don't see how it should be impossible to prevent the deadlock if you really wanted to.
There are circumstances where you do want newly created threads to trigger breakpoints even if you're waiting on that thread to finish. CE's API isn't really suitable to handle such circumstances now. It would be nice if there was concurrency and CE could both handle breakpoints and wait for the thread to finish on the main thread, but that would involve a lot of refactoring that probably won't ever happen.

christin50 wrote:
I am using "{luacode}" not "{lua}". Or does that not make a difference?
{$luacode} is used when the game should have CE run some Lua code when a code injection is run. {$lua} is basically a preprocessor macro for AA scripts.
{$luacode} doesn't need `if syntaxcheck then return end` since it can't substitute anything into the AA script like {$lua} blocks can.

christin50 wrote:
Also, is it necessary to run the lua block instead of just compiling it when I am not even returning anything?
Lua is interpreted, not compiled. This includes {$luacode}- it works via synchronous IPC from the game that's running the code injection to CE that runs the {$luacode} and back again.
{$lua} blocks must be run during the syntax check stage. The fact that a block doesn't return anything can't be used (similar to the halting problem).

christin50 wrote:
However, in the "if part", your code does not work as expected as "createThread" does not wait for the code executed at "symbol" to finish.
Yep, my bad. Even with your code, the memrec can still be toggled off and on again before the thread is finished. You could use a global and refuse to enable/disable the script if it's running via the `memrec.OnActivate` callback, but checking "execute asynchronous" is much easier.
_________________
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
christin50
How do I cheat?
Reputation: 0

Joined: 05 Mar 2025
Posts: 6

PostPosted: Fri Mar 07, 2025 6:18 am    Post subject: Reply with quote

Quote:
Even with your code, the memrec can still be toggled off and on again before the thread is finished.

This is good to know, but I am not worried much about it as the thread should finish faster than a user is able to press the checkbox to execute the script again.

As for your other points, there were all understandable and useful, thanks.
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 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