Posted: Wed May 10, 2023 8:26 pm Post subject: Time critical timers
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?
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.
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