Page 1 of 1

Optimize code, make it run faster

Posted: 16 Jul 2017, 08:51
by kyuuuri
Hi, first of all thank you!.
I made an autopot/autobuff for a game, (it's 100% legal as long as you don't mess with games delays, etc.), they gave us an autopot but on virustotal it detects 44/47 virus. And i don't really want to use it.
I prefer to learn how to do those things and do my own.
I want it to run as fast as possible, and i don't know what things i can change. I mean, i read eveything about ahk and how to make scripts faster, but now i don't know what should i change, what parts of the code can be reduced. This is why i'm asking for help, my script works, but slow.

So here is the code:

Code: Select all

#NoEnv
#MaxHotkeysPerInterval 99000000
#HotkeyInterval 99000000
#KeyHistory 0
ListLines Off
Process, Priority, , A
SetBatchLines, -1
SetKeyDelay, -1, -1
SetMouseDelay, -1
SetDefaultMouseSpeed, 0
SetWinDelay, -1
SetControlDelay, -1
SendMode Input
ReadMemory(MADDRESS=0,PROGRAM="")
{
	Static OLDPROC, ProcessHandle
	VarSetCapacity(MVALUE,4,0)
	If PROGRAM != %OLDPROC%
	{
		WinGet, pid, pid, % OLDPROC := PROGRAM
		ProcessHandle := ( ProcessHandle ? 0*(closed:=DllCall("CloseHandle"
		,"UInt",ProcessHandle)) : 0 )+(pid ? DllCall("OpenProcess"
		,"Int",16,"Int",0,"UInt",pid) : 0)
	}
	If (ProcessHandle) && DllCall("ReadProcessMemory","UInt"
	,ProcessHandle,"UInt",MADDRESS,"Str",MVALUE,"UInt",4,"UInt *",0)
	return *(&MVALUE+3)<<24 | *(&MVALUE+2)<<16 | *(&MVALUE+1)<<8 | *(&MVALUE)
	return !ProcessHandle ? "Handle Closed: " closed : "Fail"
}

ReadMemoryString(MADDRESS,PROGRAM) 
{ 
	winget, pid, PID, %PROGRAM% 

			ProcessHandle := DllCall("OpenProcess", "Int", 24, "Char", 0, "UInt", pid, "Uint")
			teststr =
			Loop 32
			{
			   Output := "x"  ; Put exactly one character in as a placeholder. used to break loop on null
			   tempVar := DllCall("ReadProcessMemory", "UInt", ProcessHandle, "UInt", MADDRESS, "str", Output, "Uint", 1, "Uint *", 0)
			   if (ErrorLevel or !tempVar)
			   {
				  DllCall("CloseHandle", "int", ProcessHandle)
				  return teststr
			   }
			  ; if Output =
			  ;  break
			
			   teststr = %teststr%%Output%
			   MADDRESS++
			}
			DllCall("CloseHandle", "int", ProcessHandle)
			return, teststr  
}

on := 0
, Map:= 0x00000000
, HP := 0x00000000
, SP := 0x00000000
, MAX_HP := 0x00000000
, MAX_SP := 0x00000000
, Chat := 0x00000000
, Base_lvl := 0x00000000
, Job_lvl := 0x00000000
, Ch_Name :=0x00000000 
, Abn_Status := 0x00000000
, HPp:= 0x00000000
, SPp:=0x00000000
, Map3:= 0x00000000
, Mapc:= 0x00000000
, HPm:= 0x00000000
, SPm:=0x00000000
, HPm:=ReadMemory(MAX_HP,"program")
, Spm:=ReadMemory(MAX_SP,"program")
, buff1:=0x00000000
, buff2:=0x00000000
, buff3:=0x00000000
, btn1:="r"
, btn2:="t"
, btn3:="5"
, buf:="0"


Gui, -MaximizeBox -MinimizeBox
Gui, Add, DropDownList, x62 y40 w40 h21 vhpb r10, F1|F2|F3|F4|F5|F6|F7|F8|F9|F10|F11|F12|0|1|2|3|4|5|6|7|8|9|a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z
Gui, Add, DropDownList, x62 y80 w40 h21 vspb r10, F1|F2|F3|F4|F5|F6|F7|F8|F9|F10|F11|F12|0|1|2|3|4|5|6|7|8|9|a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z
Gui, Add, DropDownList, x62 y120 w40 h21 vstb r10, F1|F2|F3|F4|F5|F6|F7|F8|F9|F10|F11|F12|0|1|2|3|4|5|6|7|8|9|a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z
Gui, Add, Text, x32 y40 w20 h20 , HP:
Gui, Add, Text, x32 y80 w20 h20 , SP:
Gui, Add, Text, x2 y120 w50 h20 , Cure stat:
Gui, Add, Button, x22 y240 w100 h30 gOK, Submit
Gui, Add, Edit, x112 y40 w30 h20 vhpc, 
Gui, Add, Edit, x112 y80 w30 h20 vspc, 
Gui, Add, Text, x12 y150 w120 h20 , Don't Pot in this Map
Gui, Add, Button, x2 y170 w70 h30 gMap_Check, This Map
Gui, Add, Button, x72 y170 w70 h30 gMap_Uncheck, Delete Map
Gui, Add, Text, x32 y210 w80 h20 +Center vMap4, -
Gui, Font, cD9D900 s15, Tahoma
Gui, Add, Text, x2 y0 w60 h30 , Kyuuuri
Gui, Font, cLime s15, Tahoma
Gui, Add, Text, x72 y0 w70 h30 , Autopot
Gui, Show, x127 y87 h277 w149, Kyuuuri Autopot
Return


f8::
if on = 0
{
on := 1
Settimer Update, 10
}
else
{
Settimer Update, delete
on := 0
}
return


Update:
Map3:=ReadMemory(Map,"program")
Chat2:=ReadMemory(Chat,"program")
if (on=1) and (chat2 <> 1) and (Map3 <> Mapc)
{
HPm:=ReadMemory(MAX_HP,"program")
Spm:=ReadMemory(MAX_SP,"program")
HP2:=ReadMemory(HP,"program")
if (HP2 < HPp)
goto pothp
SP2:=ReadMemory(SP,"program")
if (SP2 < SPp)
goto potsp
Stt:=ReadMemory(Abn_Status,"program")
if (stt = 0) or (stt = 1) or (stt = 2) or (stt = 3) and (stb)
goto potstt
buff01:=ReadMemory(buff1,"program")
buff02:=ReadMemory(buff2,"program")
buff03:=ReadMemory(buff3,"program")
con1 = 0
con2 = 0
con3 = 0
loop, 3
{
if % buff0%A_Index% <> 4
con1++
if % buff0%A_Index% <> 5
con2++
if % buff0%A_Index% <> 6
con3++
}
loop, 3
{
if % con%A_Index% = 3
{
buf = % btn%A_Index%
gosub, bufff
}
}
}
else
{}
return

potsp:
sendinput {%spb%}
return

pothp:
sendinput {%hpb%}
return

potstt:
sendinput {%stb%}
return

bufff:
sendinput {%buf%}
return


Map_Check:
Mapc:=ReadMemory(Map,"program")
Mapstr:=ReadMemoryString(Map,"program")
guicontrol,,Map4, %Mapstr%
return

Map_Uncheck:
Mapstr:=0
guicontrol,,Map4, -
return

OK:
gui submit
HPp:= HPm * hpc /100
SPp:= SPm * spc /100
return

GuiClose:
ExitApp

*esc::ExitAPP
What it does:
1_ Opens gui, you input the keys for potions, % of hp/sp, the button for a cure item, and the map where you don't want it to run.
2_ press f8 to start, when you press f8 it does the same:
  • 1. Checks current map and if chat is opened.
    2. If its on, and chat is not opened and map is not selected then it checks actual hp and maximum hp.
    3. If it's lower than the % selected then it goes to pothp that works like a loop, it sends the key and goes back to the check until hp is higher than % selected.
    4. Then if hp is above the % selected, it checks sp, same as hp check but with potsp.
    5. Then if both hp and sp are above the % selected, checks for status to cure, same as hp but with potstt
    6. Then if hp, sp and stt are okay, it checks buffs.
    7. This part is the one i have to explain the most: buffs are asigned to a range of memory address that never vary (for example, if initial one is 20 then the following is 24 then 28 then 30 then 34 then 38, etc). Buffs are not always assigned to the same memory address, let's say i have buff 1 on address 20, then somebody gives me buff 2, and now buff 1 goes to address 24 and buff 2 goes to 20. That's why i check the entire range of addresses and do a +1 on a variable everytime it detects that the buff is not there. If it reachs the maximum amount then it's because the buff wasn't found on any address.
    8_ Checks what buffs were not found on the range of addresses, when one was not found it goes to bufff. But then it comes back and checks the rest of the buffs (that's why i use gosub and not goto there).
    9_ Then all starts again.
Right now i don't know how to optimize this. Feel free to ask everything, I changed all the address because they don't really matter to optimize the code.

Re: Optimize code, make it run faster  Topic is solved

Posted: 16 Jul 2017, 21:43
by Exaskryz
Look into what is repeated, but never changes. I notice that you have a part in the ReadMemory() function that chekc sot see if OLDPROC and PROGRAM differ -- but does that variable ever change in your script? I mean, do you ever pass a different value to the PROGRAM parameter? I'm not seeing that you do; I see "program" for all the ReadMemory() function calls at a glance. But if there are multiple programs you're calling, and in this published script in your post you changed the name of the program to a generic "program", then maybe you do still need it.

Also for the ReadMemoryString() function, something similar goes on - do you need to keep getting the pid for the program with winget? If it's the same program every time, then the pid should always be the same. So it looks like you should be able to move the winget and ProcessHandle := lines into the auto-execute section of your script and just make them global variables for the function to access when it does the loop to populate teststr.

Also while I don't know the significance of it's impact on performance, do you need the Output := "x" bit? The comment here says it would be used if Output becomes null, where the loop would break. However, you commented out the if Output = and break. Though if you still need the Output variable as a delimiter, that should be OK.

You might consider just using teststr.=output to append the variable output to the current value of teststr (see operators), rather than the teststr = %teststr%%Output%.

That's what I'm seeing at a glance, though I was not thorough.

Re: Optimize code, make it run faster

Posted: 17 Jul 2017, 05:22
by kyuuuri
Exaskryz wrote:Look into what is repeated, but never changes. I notice that you have a part in the ReadMemory() function that chekc sot see if OLDPROC and PROGRAM differ -- but does that variable ever change in your script? I mean, do you ever pass a different value to the PROGRAM parameter? I'm not seeing that you do; I see "program" for all the ReadMemory() function calls at a glance. But if there are multiple programs you're calling, and in this published script in your post you changed the name of the program to a generic "program", then maybe you do still need it.

Also for the ReadMemoryString() function, something similar goes on - do you need to keep getting the pid for the program with winget? If it's the same program every time, then the pid should always be the same. So it looks like you should be able to move the winget and ProcessHandle := lines into the auto-execute section of your script and just make them global variables for the function to access when it does the loop to populate teststr.

Also while I don't know the significance of it's impact on performance, do you need the Output := "x" bit? The comment here says it would be used if Output becomes null, where the loop would break. However, you commented out the if Output = and break. Though if you still need the Output variable as a delimiter, that should be OK.

You might consider just using teststr.=output to append the variable output to the current value of teststr (see operators), rather than the teststr = %teststr%%Output%.

That's what I'm seeing at a glance, though I was not thorough.
First of all thank you!, those functions i used are not mine, i found them on the forum when i had the problem that i didn't know how to read process memory address.
Made the changes you said and came up with this:

Code: Select all

WinGet, pid, pid, program
ProcessHandle := ( ProcessHandle ? 0*(closed:=DllCall("CloseHandle","UInt",ProcessHandle)) : 0 )+(pid ? DllCall("OpenProcess","Int",16,"Int",0,"UInt",pid) : 0)

ReadMemory(MADDRESS=0,PROGRAM="")
{
	VarSetCapacity(MVALUE,4,0)
	return *(&MVALUE+3)<<24 | *(&MVALUE+2)<<16 | *(&MVALUE+1)<<8 | *(&MVALUE)
}
I moved outside WinGet, and ProcessHandle declaration. Removed the if checks because it won't fail, and if it does i don't want to know :D, as said those are not my functions so idk if the changes i made are okay, i'm not at home right now to check it.

And on the other function changed:

Code: Select all

ProcessHandle1 := DllCall("OpenProcess", "Int", 24, "Char", 0, "UInt", pid, "Uint")

ReadMemoryString(MADDRESS,PROGRAM) 
{ 
			teststr =
			Loop -
			{
			   tempVar := DllCall("ReadProcessMemory", "UInt", ProcessHandle, "UInt", MADDRESS, "str", Output, "Uint", 1, "Uint *", 0)
			   if (ErrorLevel or !tempVar)
			   {
				  DllCall("CloseHandle", "int", ProcessHandle)
				  return teststr
			   }			
			   teststr.=Output
			   MADDRESS++
			}
			return, teststr
I moved out ProcessHandle1 declaration. Didn't remove x var because it ends the loop when its null (forgot to remove the ";"), but now that i think about what string i'm reading it can only contain up to 15 characters. I think that 15 loops without the output = x and the if to check that, is faster than X loops with those things.

Idk if i should use ProcessHandle1 or if i can use the same i used for the other function. I don't understand the difference between them).

That will improve the speed for sure, thanks for that.

I think that the code still can be optimized, i mean when i look in all those "if" i have to use i feel like i'm losing a lot of speed there.