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 


Time critical timers

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

Joined: 17 Mar 2023
Posts: 6

PostPosted: Wed May 10, 2023 8:26 pm    Post subject: Time critical timers Reply with quote

Hello! I am running two timers with the interval of one millisecond each. They listen for certain game states, since I'm not supposed to use code injection. Their code is mostly identical. Once they detect that a certain gamestate has been reached, they calculate a bunch of pointers in order to figure out unit location data, and then they setMousePos to the position they calculated, and then they mouse_event leftclick.

This process needs to happen very very quickly. And somehow the code works well most of the time. But about 10% of the time it just happens a dozen milliseconds too late. I tried really hard to optimize this, but I'm still running into the issue where it sometimes just does not work. I've already offloaded all the calculations to not happen on the same tick as the time critical mouse movement and leftclick, in fact, that happens a full second before it's time to move the mouse. My issue is that I'm running out of ideas on how to optimize/troubleshoot this.

The time critical part of the script looks like this:

Code:
 if tonumber(condition1) == 3 then
      if tonumber(condition2) ~= nil then
           if tonumber(globalVariable1.Caption) ~= nil then
           -- Basically checking if the state is satisfied but only the first time the timer loops
              if tonumber(condition2) == tonumber(globalVariable1.Caption)+1 or tonumber(condition2) == tonumber(globalVariable1.Caption)+2 then
                     setMousePos(tonumber(coordinatex.Caption), tonumber(coordinatey.Caption))
                     mouse_event(MOUSEEVENTF_LEFTDOWN | MOUSEEVENTF_LEFTUP)
                     speak("Success")
                     control_setCaption(globalVariable1, tostring(condition2))
              end
           end
      end
   end



Could you please suggest something? Is there perhaps some way I could run the timers faster than every 1ms?
Back to top
View user's profile Send private message
ParkourPenguin
I post too much
Reputation: 138

Joined: 06 Jul 2014
Posts: 4275

PostPosted: Wed May 10, 2023 9:44 pm    Post subject: Reply with quote

TalkToMe wrote:
I am running two timers with the interval of one millisecond each.
Timers typically don't have millisecond-level precision.
Benchmark:
Code:
if not qpc_freq then
  local buffer = createMemoryStream()
  buffer.Size = 8
  executeCodeLocal("QueryPerformanceFrequency", buffer.Memory)
  qpc_freq = buffer.readQword()
  buffer.destroy()
  assert(qpc_freq ~= 0, 'QPCF error')
  assert(qpc_freq >= 1000, 'QPC Frequency not enough for millisecond precision')
end

function qpc()
  local buffer = createMemoryStream()
  buffer.Size = 8
  executeCodeLocal("QueryPerformanceCounter", buffer.Memory)
  local result = buffer.readQword()
  buffer.destroy()
  assert(result ~= 0, 'QPC error')
  return result
end

local last_qpc
-- will return nil on first call (initialize last_qpc)
local function timeDelta()
  local new_qpc = qpc()
  local result
  if last_qpc then
    result = 1000 * (new_qpc - last_qpc) / qpc_freq
  end
  last_qpc = new_qpc
  return result
end


print('all numbers are in milliseconds')
local i = 0
mytimer = createTimer()
mytimer.Interval = 1
mytimer.OnTimer = function(t)
  if i > 20 then
    t.destroy()
    return
  end

  local ms = timeDelta()
  if ms then
    print(ms)
  end

  i = i + 1
end
On my machine (linux running CE via wine), the median is around 6, the mean is around 10, and the min and max are around 1 and 48. It varies by a lot.

You left out the definition of `condition1` and `condition2`. Any form of ReadProcessMemory invocation is going to take several magnitudes longer to execute than any tonumber call. Don't only show what you think is important.

I don't know if `speak` is synchronous by default, but if it is, that call will take a long time to return.

You could create a native thread and run it in a busy loop, but eating an entire CPU core for that is ridiculous and it might not work that well anyway since Lua is single-threaded and other Lua things can interrupt it. Also you can't directly access the GUI from a separate thread.

Why can't you use code injection? It's certainly the most optimal way of doing this. Finding the right injection point might be mildly annoying, but it'll save your CPU from doing a ridiculous amount of work.

_________________
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
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