AHK Multiple Timers, but asynchronous Topic is solved

Ask gaming related questions
Arnes
Posts: 7
Joined: 13 Jan 2018, 19:14

AHK Multiple Timers, but asynchronous

Post by Arnes » 13 Jan 2018, 19:19

Hi everyone,

I'm trying to make a Keybind for a game. Basically all it does is hold 1 and 2 down for 1000ms and then stop for 1200ms, then repeat. Numpad0 toggles it.

However, i want it to be asynchronous. So i tried adding a sleep between the timers. But it only works one time and then starts to execute both loops at the same time.

I hope someone can help! :)

Code: Select all

Numpad0::
autofire := !autofire

if autofire
{
SetTimer, gun1, 1200
sleep 600
SetTimer, gun2, 1200
}
else
{
settimer, gun1, off
settimer, gun2, off
}
Return

gun1:
sendinput {1 down}
sleep 1000
sendinput {1 up}
return

gun2:
sendinput {2 down}
sleep 1000
sendinput {2 up}
return

User avatar
KuroiLight
Posts: 327
Joined: 12 Apr 2015, 20:24
GitHub: KuroiLight

Re: AHK Multiple Timers, but asynchronous

Post by KuroiLight » 13 Jan 2018, 19:41

Not sure what your intention is, but this working exactly how you describe.
settimer, gun1 is executed then sleep for 600ms then settimer, gun2 then 600ms and gun1 will run, then 600ms to gun2, and so on...
This can however be prone to timing drift caused by the inaccuracy of sleep, putting both sendinputs into one label would be better.
Windows 10, Ryzen 1600, 16GB G.Skill DDR4, 8GB RX 480 | [MyScripts][MySublimeSettings] [Unlicense][MIT License]
01/24/18
[/color]

User avatar
Exaskryz
Posts: 2876
Joined: 17 Oct 2015, 20:28

Re: AHK Multiple Timers, but asynchronous

Post by Exaskryz » 13 Jan 2018, 19:55

I get the feeling you need the Critical command, but because I don't use it often, I'm not confident.

t0: Turned on gun1
t600: Turned on gun2
t1200: gun1 executes
t1800: gun2 executes, interrupting gun1 (400 seconds remain on the Sleep in gun1)
t2800: gun2 ends, resume gun1
t3000: gun2 executes again, interrupting gun1 (200 seconds remain on Sleep in gun1)
t4000: gun2 ends, resume gun1
t4200: Both gun1 should end and try to fire again (Because it's backlogged, been well over 1200 seconds since it last fired) and gun2 tries to execute again!

If using Critical (with NoTimers? parameter?) doesn't work by itself, you may need to make routine all in one:

Code: Select all

SetTimer, guns, 1800
return

guns:
Send {1 down}
Sleep 600
Send {2 down}
Sleep 400
Send {1 up}
Sleep 600
Send {2 up}
return
There'd be a 200 ms gap between the 2 release and the 1 down.

Arnes
Posts: 7
Joined: 13 Jan 2018, 19:14

Re: AHK Multiple Timers, but asynchronous

Post by Arnes » 14 Jan 2018, 13:22

First of, thanks for your answers!

So i did some more research and i found out, that i actually can use smaller sleeps.

Heres what i wanna do:

I have 2 guns. Each gun has the following rotation: Hold for 800ms, wait for 400ms, repeat. As i already said, it should be perfectly asynchronous.

So i tried using Exaskryz' method, but im stuck.

Code: Select all

Numpad0::
loop
{
	sendinput {1 down}
	sleep 600 ; half the time of comeplete duration
	sendinput {2 down}
	sleep 200 ; rest of 800ms for 1st gun
	sendinput {1 up}
	sleep 600 ; now heres the issue: gun 1 need to be pressed 200ms earlier. basically i lose 200ms here, which screws the rotation and isnt optimal for me!
	sendinput {2 up}
}
I hope im being precize enough with this!

Noesis
Posts: 299
Joined: 26 Apr 2014, 07:57

Re: AHK Multiple Timers, but asynchronous

Post by Noesis » 15 Jan 2018, 01:15

Hi Arnes,

Seems your code changed in the latest post. I don't mean the timings, but the methodology, i.e. using a loop instead of a timer. Probably not the best way, using a timer (or two) was a better approach IMO.

The issue IMO is due to the sleeping within the timers. Essentially you want the timers to do the work, but you need them to complete quickly otherwise they end up conflicting with each other, which is what seems to be happening. When you sleep in the timer, that timer is still active, so you need to avoid them. I'd go for an approach where you store and use the actual times of each action. i.e something like this:

Code: Select all

timerGun1(flg:="")
{
	static key:= {time:0,state:0,hold:800,wait:400}
	if (flg = "")
	 {
		if (key.state && A_TickCount - key.time >= key.hold)
		{
			Send {1 up}
			key.state := 0
			key.time := A_TickCount
		}
		Else if (!key.state && A_TickCount - key.time >= key.wait)
		{
			Send {1 down}
			key.state := 1
			key.time := A_TickCount
		}
	}
	Else if (flg) ;use to start the timer, i.e. call TimerGun1(true)
	{
		key.time := A_TickCount
		SetTimer, %A_ThisFunc%, 100 ; period won't actually matter, as long as it's less than and divisible by the wait and hold times
	}
	Else ; used to stop the timer, and force any keys up if they are down. TimerGun1(false)
	{
		if key.state
			Send {1 up}
		key.state := 0
		SetTimer, %A_ThisFunc%, Off ; could delete it instead if you want.
	}
	Return
}

User avatar
evilC
Posts: 4791
Joined: 27 Feb 2014, 12:30

Re: AHK Multiple Timers, but asynchronous

Post by evilC » 15 Jan 2018, 07:33

It is the sleep commands that are making it not able to properly run asynch

AHK is NOT a multi-threaded language, it fakes it.

Code: Select all

SetTimer, gun1, 1200
sleep 600
SetTimer, gun2, 1200
so @ 1200, it fires Gun1

Code: Select all

sendinput {1 down}
sleep 1000
sendinput {1 up}
Gun1 presses 1, then sleeps for 600ms.
Gun2 should run 600ms after Gun1, but it does not, because the Sleep 600 command in Gun1 is BLOCKING.

A much much better way to handle this:

Code: Select all

#SingleInstance force

input_state := 0

return

Numpad0::
	if (input_state)
		return	; input button already held. Ignore the key repeat
	input_state := 1
	gosub, B1Press
	SetTimer, B2Press, -600
	return

Numpad0 up::
	input_state := 0
	; Stop all timers
	SetTimer, B1Press, Off
	SetTimer, B2Press, Off
	SetTimer, B1Release, Off
	SetTimer, B2Release, Off
	; Release any held keys
	Send {1 up}{2 up}
	return

B1Press:
	SetTimer, B1Release, -600
	Send {1 Down}
	return

B2Press:
	SetTimer, B2Release, -600
	Send {2 Down}
	return

B1Release:
	SetTimer, B1Press, -600
	Send {1 up}
	return

B2Release:
	SetTimer, B2Press, -600
	Send {2 up}
	return
FYI a negative value for SetTimer means "Run only once". ie it does not repeat.
What I am doing here is that when the button is pressed, I start a timer to send release.
When it releases, I start a timer to press

Arnes
Posts: 7
Joined: 13 Jan 2018, 19:14

Re: AHK Multiple Timers, but asynchronous

Post by Arnes » 15 Jan 2018, 15:10

So i tried both of the codes, but neither of them seems to work for me.

Noesis' one does only toggle gun1, which it does well. However it doesnt include gun2, letalone rotate both of them endlessly (until toggled off).

evilC's code does that better. it rotates both of the guns, but not for long enough, meaning it doesnt hold down either of the gunbuttons long enough. Also it doesnt wait for the cooldown.

Now both of those codes are being executed while holding down the hotkey, which isnt optimal for me. I need them to be a toggle. Basically the rotation should be started and stopped by pressing numpad0


I dont know if either of you play videogames, but im just gonna assume so.
Here's another explanation of what exactly i need:
--> Numpad0 toggles the following rotation:
--> Hold down 1 for 800ms and afterwards wait for 400ms (weapon cooldown)
--> Hold down 2 for 800ms and also wair 400ms
--> Gun1 and Gun2 should trigger alternating while being repeated as soon as the cooldown allowes to (to get maximum dmg output)

The Guns im using are both identical and shoot a salve of bullets at the same time. Therefore each one needs to be "charged" 800ms. Afterwards both have a 400ms cooldown until i can repeat the charge.
At the moment im using both guns at the same trigger, which shoots both of them at the same time. So if i miss, no dmg is done to the enemy.
Thats why im trying to create a code that makes them shoot alternating, creating an almost constant dmg chain. So i kind of just have to follow the enemy with the crosshair and deal low but constant damage.


Im very grateful for your help, especially because seeing your codes made me realize how little i actually understand.

Im open for new suggestions! Thank you!

User avatar
evilC
Posts: 4791
Joined: 27 Feb 2014, 12:30

Re: AHK Multiple Timers, but asynchronous  Topic is solved

Post by evilC » 15 Jan 2018, 15:43

Changed to toggle instead of hold
Changed press time to 800ms
Changed release time to 400ms

Still not 100% sure on what timing you want between firing of Gun1 and Gun2
ie when it starts the Gun1 timer, how long should it wait before kicking off the Gun2 timer? At the moment it is 800ms.
I indicated in the code where to change this with the comment ; <-- controls delay between Gun1 firing and Gun2 firing

Code: Select all

#SingleInstance force

toggle := 0

return

Numpad0::
	toggle := !toggle
	if (toggle){
		gosub, B1Press
		SetTimer, B2Press, -800	; <-- controls delay between Gun1 firing and Gun2 firing
	} else {
		; Stop all timers
		SetTimer, B1Press, Off
		SetTimer, B2Press, Off
		SetTimer, B1Release, Off
		SetTimer, B2Release, Off
		; Release any held keys
		Send {1 up}{2 up}
	}
	return

B1Press:
	SetTimer, B1Release, -400
	Send {1 Down}
	return

B2Press:
	SetTimer, B2Release, -400
	Send {2 Down}
	return

B1Release:
	SetTimer, B1Press, -800
	Send {1 up}
	return

B2Release:
	SetTimer, B2Press, -800
	Send {2 up}
	return


Arnes
Posts: 7
Joined: 13 Jan 2018, 19:14

Re: AHK Multiple Timers, but asynchronous

Post by Arnes » 15 Jan 2018, 15:55

No i dont play MWO. Its for another game that has those type of weapons. I looked up pretty much every result google was giving me, but none of them are as good as i want my script to be.
In case you're wondering, im not planning on selling it or something. I just wanna make my pve grinding easier.

User avatar
evilC
Posts: 4791
Joined: 27 Feb 2014, 12:30

Re: AHK Multiple Timers, but asynchronous

Post by evilC » 15 Jan 2018, 16:03

Nah I was just asking cos if it was MWO, there are other ready-made macros for that.

eg there is my "Fire Control" macro, but that is not really geared towards holding down buttons for prolonged periods, it's more about tapping them at a pre-defined rate.
I wrote it for MWO, but it should work for any game where you need to hit buttons at a specific rate.
https://mwomercs.com/forums/topic/12545 ... -jan-2017/

Arnes
Posts: 7
Joined: 13 Jan 2018, 19:14

Re: AHK Multiple Timers, but asynchronous

Post by Arnes » 15 Jan 2018, 16:18

Sorry man i didnt even see your code before!

So i changed the delay to 600ms and switched the timings, since you switched the charge time and the cooldown time.

Now this is what i came up with:

Code: Select all

toggle := 0

return

Numpad0::
	toggle := !toggle
	if (toggle){
		gosub, B1Press
		SetTimer, B2Press, -600	; <-- controls delay between Gun1 firing and Gun2 firing
	} else {
		; Stop all timers
		SetTimer, B1Press, Off
		SetTimer, B2Press, Off
		SetTimer, B1Release, Off
		SetTimer, B2Release, Off
		; Release any held keys
		Send {1 up}{2 up}
	}
	return

B1Press:
	SetTimer, B1Release, -800
	Send {1 Down}
	return

B2Press:
	SetTimer, B2Release, -800
	Send {2 Down}
	return

B1Release:
	SetTimer, B1Press, -400
	Send {1 up}
	return

B2Release:
	SetTimer, B2Press, -400
	Send {2 up}
	return
And im happy to announce, it WORKS!
Man im so happy with the result, its just exactly as i wanted it to be! Thanks a lot!

Arnes
Posts: 7
Joined: 13 Jan 2018, 19:14

Re: AHK Multiple Timers, but asynchronous

Post by Arnes » 15 Jan 2018, 16:30

Now i tried to edit that code to make it do the same thing with 3 guns.
I did this:

Code: Select all

toggle := 0

return

Numpad0::
	toggle := !toggle
	if (toggle){
		gosub, B1Press
		SetTimer, B2Press, -400	; <-- controls delay between Gun1 firing and Gun2 firing
		SetTimer, B2Press, -800
	} else {
		; Stop all timers
		SetTimer, B1Press, Off
		SetTimer, B2Press, Off
		SetTimer, B3Press, Off
		SetTimer, B1Release, Off
		SetTimer, B2Release, Off
		SetTimer, B3Release, Off
		; Release any held keys
		Send {1 up}{2 up}{f up}
	}
	return

B1Press:
	SetTimer, B1Release, -800
	Send {1 Down}
	return

B2Press:
	SetTimer, B2Release, -800
	Send {2 Down}
	return
B3Press:
	SetTimer, B3Release, -800
	Send {f Down}
	return

B1Release:
	SetTimer, B1Press, -400
	Send {1 up}
	return

B2Release:
	SetTimer, B2Press, -400
	Send {2 up}
	return
B3Release:
	SetTimer, B3Press, -400
	Send {f up}
	return
The third gun is used by pressing f and is just the same gun with same roations. I tried adding another timer and reducing the delays to 400 (1200/3), to make those 3 guns rotate.

But it doesnt work, since the third gun isnt executed at all. I guess its because timers interrupt each other (learned that today). Can you tell me what to do here?

Arnes
Posts: 7
Joined: 13 Jan 2018, 19:14

Re: AHK Multiple Timers, but asynchronous

Post by Arnes » 15 Jan 2018, 16:34

Actually im just stupid. I miss spelled the third timer. I just changed the label from B2Press to B3Press and now it runs perfectly. Dealing like HUGE damage, thanks to you!

Now i finally found some help for my problem and can return to play!

Thanks to everyone for your answers. This can be closed now.

Noesis
Posts: 299
Joined: 26 Apr 2014, 07:57

Re: AHK Multiple Timers, but asynchronous

Post by Noesis » 16 Jan 2018, 03:15

Hi Arnes,
Just an FYI, the code I did was only for the one gun. For the other guns you just needed to copy the function and change the name of it (eg the 1 to 2) and change the key being sent in the other copy(s), then call each function after whatever delay you wanted between each gun. Hope that makes sense, probably should have said so in the other post. Anyway, glad you got it sorted. :)

Post Reply

Return to “Gaming”