Автокликер, авто-нажатие на клавиши, скрипт, имитирующий клавиатуру
(Всего: 119 424, сегодня: 5 )
За пару минут вы запустите свой кликер по клавишам. Когда понадобилось автоматом нажимать на кнопки клавиатуры, нормального решения в сети именно для клавиш я так и не нашел и случайно нашел ролик на Ютубе вот с этим.
Мы будем писать циклический скрипт, который будет обрабатывать программа AutoHotKey (AHK). Скрипт будет выполнять цикл и запускаться бесконечное количество раз. Итак, поехали.
В моем случае я использую всего две клавиши – пробел (space) и эскейп (esc). Коды всех остальных клавиш и других возможностей программы можно найти в документации AutoHotKey
Скрипт цикла нажатия на клавиши
Home::
Loop
{
send, {Esc}
sleep, 2000
send, {Space}
sleep, 2000
}
Return
End::
ExitApp
Return
Описание к коду выше
Home:: - а-ля "Паскалевское" начало программы - ключевое слово, которое изменять нельзя
Loop - слово, указывающее на начало цикла
{ - открытие цикла
send, {Esc) - дословно - нажимаить на
sleep, 2000 - ждать 2 тыс. миллисекунд (2 секунды)
} - закрытие цикла
Return - обязательное слово, для зацикливания кода
End::
ExitApp
Return - - обязательное слово, для зацикливания всего кода в целом
Сохраняем файл в формате *.ahk и скачиваем и устанавливаем программу AutoHotKey
Теперь ваш скрипт понятен для ОС Windows. Для удобства его можно скомпилировать в *.exe нажав правой кнопкой мыши и выбрав соответствующий пункт контекстного меню.
Файл запускается сразу в трей, активируется кнопкой HOME, деактивируется (удаляется из трея) – End.
In this article, we will see how to create an auto-clicker using Python. The code will take input from the keyboard when the user clicks on the start key and terminates auto clicker when the user clicks on exit key, the auto clicker starts clicking wherever the pointer is placed on the screen. We are going to use the pynput module here.
What is Auto Clicker?
Auto-Clicker is a script where you can auto control mouse and keyboard as many numbers of times as you want. It is controlled using user-defined keys. It works on various platforms like Windows, Mac and Linux. Auto clicker is present in pywin32 module.
Approach:
In this project, we will use a cross-platform module pynput to control the mouse and monitor the keyboard at the same time to create simple auto-clicker. To check for mouse events we will install pynput module (used to control the mouse) for this execute, pip install pynput in cmd.
Note: If you’re stuck on how to set up python-pip package on your system then click here
Installation of pynput module
Verify whether the pynput module has been successfully installed into your working environment for this, open IDLE on the system that is cmd or Python Shell. Execute the command import pynput, after executing this the output should give zero errors which means your module is successfully installed.
Verifying module installation
Implementation:
Let’s now proceed with the code that is required to build an Auto-clicker using Python. Follow the below steps to create an auto-clicker:
Step 1: Import time and threading then import Button and Controller from pynput.mouse module. Import Listener and KeyCode from pynput.keyboard.
Python3
import
time
import
threading
from
pynput.mouse
import
Button, Controller
from
pynput.keyboard
import
Listener, KeyCode
Step 2: Create four variables as mentioned below,
- delay: Delay between each click (in seconds)
- button: Button is used to click in whatever direction you want to. Button.left | Button.middle | Button.right
- start_stop_key: The key used for start and stop of the click while you run the program for executing the auto clicker. It should be from a key class or set using KeyCode.
- exit_key: The key used to terminate the auto clicker that is being executed. This should be from the key class or set using KeyCode.
Python3
delay
=
0.001
button
=
Button.right
start_stop_key
=
KeyCode(char
=
'a'
)
stop_key
=
KeyCode(char
=
'b'
)
Step 3: Create a class extending threading.Thread. Pass delay and button to the class that have two flags to check if the program is executed or not.
Python3
class
ClickMouse(threading.Thread):
def
__init__(
self
, delay, button):
super
(ClickMouse,
self
).__init__()
self
.delay
=
delay
self
.button
=
button
self
.running
=
False
self
.program_running
=
True
Step 4: Add methods to control the threads externally.
Python3
def
start_clicking(
self
):
self
.running
=
True
def
stop_clicking(
self
):
self
.running
=
False
def
exit(
self
):
self
.stop_clicking()
self
.program_running
=
False
Step 5: A method is created when the thread starts, the program_running runs on loop until the value comes out to be true and also create another loop inside the existing loop where it checks if running is set to true or not. In case, we are inside both loops, it will click on the set button and sleep for the set delay.
Python3
def
run(
self
):
while
self
.program_running:
while
self
.running:
mouse.click(
self
.button)
time.sleep(
self
.delay)
time.sleep(
0.1
)
Step 6: Creating an instance for the mouse controller, then create ClickMouse thread. Start the instance to move into the loop inside the run method.
Python3
mouse
=
Controller()
click_thread
=
ClickMouse(delay, button)
click_thread.start()
Step 7: Create a method on_press which takes a key as an argument and sets up a keyboard listener. The start_stop_key matches with a start key (a) when it is executed. Then the click is to be terminated when running flag is set to True in the thread. Exit method is called in the method if the exit key (b) is executed and stop the listener.
Python3
def
on_press(key):
if
key
=
=
start_stop_key:
if
click_thread.running:
click_thread.stop_clicking()
else
:
click_thread.start_clicking()
elif
key
=
=
stop_key:
click_thread.exit()
listener.stop()
with Listener(on_press
=
on_press) as listener:
listener.join()
After the code is run we can see in the output as shown below, it shows the number of clicks the auto-clicker has made after the code is implemented. It is compatible with Windows, Mac and Linux. Auto-Clicker is helpful software for the systems as it let’s save a reasonable amount of time that is spent on repeated amount of clicks.
Below is the complete program:
Python3
import
time
import
threading
from
pynput.mouse
import
Button, Controller
from
pynput.keyboard
import
Listener, KeyCode
delay
=
0.001
button
=
Button.right
start_stop_key
=
KeyCode(char
=
'a'
)
stop_key
=
KeyCode(char
=
'b'
)
class
ClickMouse(threading.Thread):
def
__init__(
self
, delay, button):
super
(ClickMouse,
self
).__init__()
self
.delay
=
delay
self
.button
=
button
self
.running
=
False
self
.program_running
=
True
def
start_clicking(
self
):
self
.running
=
True
def
stop_clicking(
self
):
self
.running
=
False
def
exit(
self
):
self
.stop_clicking()
self
.program_running
=
False
def
run(
self
):
while
self
.program_running:
while
self
.running:
mouse.click(
self
.button)
time.sleep(
self
.delay)
time.sleep(
0.1
)
mouse
=
Controller()
click_thread
=
ClickMouse(delay, button)
click_thread.start()
def
on_press(key):
if
key
=
=
start_stop_key:
if
click_thread.running:
click_thread.stop_clicking()
else
:
click_thread.start_clicking()
elif
key
=
=
stop_key:
click_thread.exit()
listener.stop()
with Listener(on_press
=
on_press) as listener:
listener.join()
Now let’s execute the python program we’ve written and then press the start (a) and stop (a) keys in order to initiate the auto clicker.
Output:
In this article, we will see how to create an auto-clicker using Python. The code will take input from the keyboard when the user clicks on the start key and terminates auto clicker when the user clicks on exit key, the auto clicker starts clicking wherever the pointer is placed on the screen. We are going to use the pynput module here.
What is Auto Clicker?
Auto-Clicker is a script where you can auto control mouse and keyboard as many numbers of times as you want. It is controlled using user-defined keys. It works on various platforms like Windows, Mac and Linux. Auto clicker is present in pywin32 module.
Approach:
In this project, we will use a cross-platform module pynput to control the mouse and monitor the keyboard at the same time to create simple auto-clicker. To check for mouse events we will install pynput module (used to control the mouse) for this execute, pip install pynput in cmd.
Note: If you’re stuck on how to set up python-pip package on your system then click here
Installation of pynput module
Verify whether the pynput module has been successfully installed into your working environment for this, open IDLE on the system that is cmd or Python Shell. Execute the command import pynput, after executing this the output should give zero errors which means your module is successfully installed.
Verifying module installation
Implementation:
Let’s now proceed with the code that is required to build an Auto-clicker using Python. Follow the below steps to create an auto-clicker:
Step 1: Import time and threading then import Button and Controller from pynput.mouse module. Import Listener and KeyCode from pynput.keyboard.
Python3
import
time
import
threading
from
pynput.mouse
import
Button, Controller
from
pynput.keyboard
import
Listener, KeyCode
Step 2: Create four variables as mentioned below,
- delay: Delay between each click (in seconds)
- button: Button is used to click in whatever direction you want to. Button.left | Button.middle | Button.right
- start_stop_key: The key used for start and stop of the click while you run the program for executing the auto clicker. It should be from a key class or set using KeyCode.
- exit_key: The key used to terminate the auto clicker that is being executed. This should be from the key class or set using KeyCode.
Python3
delay
=
0.001
button
=
Button.right
start_stop_key
=
KeyCode(char
=
'a'
)
stop_key
=
KeyCode(char
=
'b'
)
Step 3: Create a class extending threading.Thread. Pass delay and button to the class that have two flags to check if the program is executed or not.
Python3
class
ClickMouse(threading.Thread):
def
__init__(
self
, delay, button):
super
(ClickMouse,
self
).__init__()
self
.delay
=
delay
self
.button
=
button
self
.running
=
False
self
.program_running
=
True
Step 4: Add methods to control the threads externally.
Python3
def
start_clicking(
self
):
self
.running
=
True
def
stop_clicking(
self
):
self
.running
=
False
def
exit(
self
):
self
.stop_clicking()
self
.program_running
=
False
Step 5: A method is created when the thread starts, the program_running runs on loop until the value comes out to be true and also create another loop inside the existing loop where it checks if running is set to true or not. In case, we are inside both loops, it will click on the set button and sleep for the set delay.
Python3
def
run(
self
):
while
self
.program_running:
while
self
.running:
mouse.click(
self
.button)
time.sleep(
self
.delay)
time.sleep(
0.1
)
Step 6: Creating an instance for the mouse controller, then create ClickMouse thread. Start the instance to move into the loop inside the run method.
Python3
mouse
=
Controller()
click_thread
=
ClickMouse(delay, button)
click_thread.start()
Step 7: Create a method on_press which takes a key as an argument and sets up a keyboard listener. The start_stop_key matches with a start key (a) when it is executed. Then the click is to be terminated when running flag is set to True in the thread. Exit method is called in the method if the exit key (b) is executed and stop the listener.
Python3
def
on_press(key):
if
key
=
=
start_stop_key:
if
click_thread.running:
click_thread.stop_clicking()
else
:
click_thread.start_clicking()
elif
key
=
=
stop_key:
click_thread.exit()
listener.stop()
with Listener(on_press
=
on_press) as listener:
listener.join()
After the code is run we can see in the output as shown below, it shows the number of clicks the auto-clicker has made after the code is implemented. It is compatible with Windows, Mac and Linux. Auto-Clicker is helpful software for the systems as it let’s save a reasonable amount of time that is spent on repeated amount of clicks.
Below is the complete program:
Python3
import
time
import
threading
from
pynput.mouse
import
Button, Controller
from
pynput.keyboard
import
Listener, KeyCode
delay
=
0.001
button
=
Button.right
start_stop_key
=
KeyCode(char
=
'a'
)
stop_key
=
KeyCode(char
=
'b'
)
class
ClickMouse(threading.Thread):
def
__init__(
self
, delay, button):
super
(ClickMouse,
self
).__init__()
self
.delay
=
delay
self
.button
=
button
self
.running
=
False
self
.program_running
=
True
def
start_clicking(
self
):
self
.running
=
True
def
stop_clicking(
self
):
self
.running
=
False
def
exit(
self
):
self
.stop_clicking()
self
.program_running
=
False
def
run(
self
):
while
self
.program_running:
while
self
.running:
mouse.click(
self
.button)
time.sleep(
self
.delay)
time.sleep(
0.1
)
mouse
=
Controller()
click_thread
=
ClickMouse(delay, button)
click_thread.start()
def
on_press(key):
if
key
=
=
start_stop_key:
if
click_thread.running:
click_thread.stop_clicking()
else
:
click_thread.start_clicking()
elif
key
=
=
stop_key:
click_thread.exit()
listener.stop()
with Listener(on_press
=
on_press) as listener:
listener.join()
Now let’s execute the python program we’ve written and then press the start (a) and stop (a) keys in order to initiate the auto clicker.
Output:
What is an auto clicking program? Well, an auto clicker is basically an application that will automatically click on the screen for the number of times you want. You can use the auto clicker software to play incremental or clicker games, to do data entry work, or to literally do any process that requires a lot of constant clicking on the screen. There are a lot of free auto clickers available on the Internet that you can download and install easily. But how to make your own auto clicker program if you don’t want to download one? The auto clicker that you will code yourself will surely be free from all types of malware and viruses.
Below is the complete process to make an auto-clicking program on your computer.
You can easily write down a code in Python language to make your auto clicker application. Make sure that you have installed the latest version of Python on your computer. The pip function will be active on your machine through which you can download and install third party Python modules.
Firstly, install the pynput module from your Command Prompt window (cmd). Type cmd in Windows Search bar and hit enter. Then type in pip install pynput. This will load the module to the Python library. What this module does is listens to the mouse events. Once you load this, time to write the code:
Source Code (https://nitratine.net/blog/post/python-auto-clicker/#final-code)
import time
import threading
from pynput.mouse import Button, Controller
from pynput.keyboard import Listener, KeyCode
delay = 0.001
button = Button.left
start_stop_key = KeyCode(char=’s’)
exit_key = KeyCode(char=’e’)
class ClickMouse(threading.Thread):
def __init__(self, delay, button):
super(ClickMouse, self).__init__()
self.delay = delay
self.button = button
self.running = False
self.program_running = True
def start_clicking(self):
self.running = True
def stop_clicking(self):
self.running = False
def exit(self):
self.stop_clicking()
self.program_running = False
def run(self):
while self.program_running:
while self.running:
mouse.click(self.button)
time.sleep(self.delay)
time.sleep(0.1)
mouse = Controller()
click_thread = ClickMouse(delay, button)
click_thread.start()
def on_press(key):
if key == start_stop_key:
if click_thread.running:
click_thread.stop_clicking()
else:
click_thread.start_clicking()
elif key == exit_key:
click_thread.exit()
listener.stop()
with Listener(on_press=on_press) as listener:
listener.join()
In the second section from the top, you can edit that according to your preferences.
For the “delay”, enter the time delay in seconds between two mouse clicks.
For the “button”, you can enter Button.left or Button.middle or Button.right according to the mouse button you want to automatically click.
For the “start_stop_key”, enter the keyboard key that you want to press to automate the clicking process and to stop it.
For exit_key, set the exit keyboard key that will shutdown the auto clicking program.
Java Auto Clicker
A simple code written in Java that will let you choose the rate of clicking, the location of the cursor, and will also display the count of the clicks.
Make sure that you have the latest version of Java installed on your computer. Also, download and install JDK SE to load extended features and functions to the library. Once this is done, below is the code that you need to compile and run. Unlike the Python clicker, this one will ask you for the input like number of clicks, time delay between clicks, location, etc.
Source Code (https://github.com/Demonic/AutoClicker/blob/master/src/me/Demonly/auto/clicker.java)
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.util.concurrent.ThreadLocalRandom;
public class clicker {
public static boolean clicking = true;
public static int amountclicked = 0;
public static int rate = 0;
public static int rate1 = 0;
public static void main(String[] args) throws InterruptedException {
while (rate1 == 0) {
try {
System.out.println(“How many clicks are you wanting to do?:”);
BufferedReader xyz = new BufferedReader(new InputStreamReader(System.in));
try {
rate1 = Integer.parseInt(xyz.readLine());
if (rate1 == 0) {
rate1 = 0;
System.out.println(“Must be at least 1 click.”);
}
} catch (NumberFormatException ex) {
System.out.println(“Error – please try again.”);
}
} catch (IOException e) {
}
}
while (rate == 0) {
try {
System.out.println(“Max speed of the autoclicker?: (in miliseconds):”);
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
try {
rate = Integer.parseInt(in.readLine());
if (rate < 500) {
rate = 0;
System.out.println(“Must be at least 500 miliseconds.”);
}
} catch (NumberFormatException ex) {
System.out.println(“Error – please try again.”);
}
} catch (IOException e) {
}
}
try {
System.out.println(“*!*!*!*! PLEASE MOVE YOUR MOUSE INTO POSITION! !*!*!*!*”);
System.out.println(“*!*!*!*! MOVE MOUSE TO END AUTOCLICK! !*!*!*!*”);
System.out.println(“*!*!*!*! Sleeping for 10 seconds !*!*!*!*”);
Thread.sleep(10000);
Point p = MouseInfo.getPointerInfo().getLocation();
System.out.println(“Current Mouse Location: “+p);
Robot robot = new Robot();
while (clicking == true) {
try {
Point z = MouseInfo.getPointerInfo().getLocation();
System.out.println(“Current Mouse Location: “+z);
int randomNum = ThreadLocalRandom.current().nextInt(15000, rate + 1);
System.out.println(“Current Rate: ” + randomNum);
Thread.sleep(randomNum);
robot.mousePress(InputEvent.BUTTON1_MASK);
robot.mouseRelease(InputEvent.BUTTON1_MASK);
amountclicked++;
System.out.println(“Amount Clicked So Far: ” + amountclicked);
if (Math.round(z.getX()+z.getY()) != Math.round(p.getX()+p.getY())) {
System.out.println(“MOUSE MOVED!: “+z);
clicking = false;
}
if (amountclicked == rate1) {
clicking = false;
}
} catch (InterruptedException ex) {
}
}
} catch (AWTException e) {
}
}
}
So, that is how you make your own auto-clicking program. To get into depth like making a proper application with different panels and buttons, it will need some knowledge of C# programming language. Till then, you can get the auto clicking done with the help of the two clickers mentioned above. The codes are not lengthy and will compile easily. If any error comes up, then there must be a problem in installing the package or the latest version of the software is not installed. Update it from the official website of Python/Java and then try it again.
Go on and make your own auto clicking program and enjoy the clicker games at a super fast speed. Happy programming! Happy clicking!
I love playing incremental games and creating tools & software. Connecting both my passions, I wrote down the code for Auto clicker and published it for free for you all on autoclicker.io, feel free to reach out to me on [email protected] to suggest new features and suggestions.
This is a script that allows you to click your mouse repeatedly with a small delay. It works on Windows, Mac and Linux and can be controlled with user-defined keys.
- What is this?
- PIP
- Installing Pynput
- Writing the Code
- Using the Script
- Final Code
- Common Issues and Questions
- ModuleNotFoundError/ImportError: No module named ‘pynput’
- I got a SyntaxError
- ‘python’ is not recognized as an internal or external command
What is this?
This project uses the cross-platform module pynput to control the mouse and monitor the keyboard at the same time to create a simple auto clicker.
PIP
If you haven’t used or setup pip before, look at my tutorial on how to setup python’s pip to setup pip.
Installing Pynput
We will be using the pynput module to listen to mouse events. To install this module execute pip install pynput
in cmd. Watch the output to make sure no errors have occurred; it will tell you when the module has been successfully installed.
To double-check that it was installed successfully, open up IDLE and execute the command import pynput
; no errors should occur.
.
Writing the Code
First, we need to import time and threading. Then import Button and Controller from pynput.mouse so we can control the mouse and import Listener and KeyCode from pynput.keyboard so we can watch for keyboard events to start and stop the auto clicker.
import time
import threading
from pynput.mouse import Button, Controller
from pynput.keyboard import Listener, KeyCode
Next create four variables as shown below. ‘delay’ will be the delay between each button click. ‘button’ will be the button to click, this can be either ‘Button.left’, ‘Button.right’ or even ‘Button.middle’. ‘start_stop_key’ is the key you want to use to start and stop the auto clicker. I have set it to the key ‘s’ to make it nice and simple, you can use any key here. Finally, the ‘exit_key’ is the key to close the program set it like before, but make sure it is a different key.
delay = 0.001
button = Button.left
start_stop_key = KeyCode(char='s')
exit_key = KeyCode(char='e')
Now create a class that extends threading.Thread that will allow us to control the mouse clicks. Pass they delay and button to this and have two flags that determine whether it is running or if the whole program is stopping.
class ClickMouse(threading.Thread):
def __init__(self, delay, button):
super(ClickMouse, self).__init__()
self.delay = delay
self.button = button
self.running = False
self.program_running = True
Next, add the methods shown below to control the thread externally.
def start_clicking(self):
self.running = True
def stop_clicking(self):
self.running = False
def exit(self):
self.stop_clicking()
self.program_running = False
Now we need to create the method that is run when the thread starts. We need to keep looping while the program_running is true and then create another loop inside that checks if the running is set to true. If we are inside both loops, click the set button and then sleep for the set delay.
def run(self):
while self.program_running:
while self.running:
mouse.click(self.button)
time.sleep(self.delay)
time.sleep(0.1)
Now we want to create an instance of the mouse controller, create a ClickMouse thread and start it to get into the loop in the run method.
mouse = Controller()
click_thread = ClickMouse(delay, button)
click_thread.start()
Now create a method called on_press that takes a key as an argument and setup the keyboard listener.
def on_press(key):
pass
with Listener(on_press=on_press) as listener:
listener.join()
Now modify the on_press method. If the key pressed is the same as the start_stop_key, stop clicking if the running flag is set to true in the thread otherwise start it. If the key pressed is the exit key, call the exit method in the thread and stop the listener. The new method will look like this:
def on_press(key):
if key == start_stop_key:
if click_thread.running:
click_thread.stop_clicking()
else:
click_thread.start_clicking()
elif key == exit_key:
click_thread.exit()
listener.stop()
This script can be saved as a .pyw to run in the background. It can easily be still closed using the set exit key even when no dialog is shown.
Using the Script
To use this script set the variables at the top to what you want.
delay
: They delay between each mouse click (in seconds)button
: The mouse button to click;Button.left
|Button.middle
|Button.right
start_stop_key
: They key to start and stop clicking. Make sure this is either from the Key class or set using a KeyCode as shown.exit_key
: The key to stop the program. Make sure this is either from the Key class or set using a KeyCode as shown.
Then run the script and use the start/stop key when wanted. Press the set exit key to exit.
Final Code
import time
import threading
from pynput.mouse import Button, Controller
from pynput.keyboard import Listener, KeyCode
delay = 0.001
button = Button.left
start_stop_key = KeyCode(char='s')
exit_key = KeyCode(char='e')
class ClickMouse(threading.Thread):
def __init__(self, delay, button):
super(ClickMouse, self).__init__()
self.delay = delay
self.button = button
self.running = False
self.program_running = True
def start_clicking(self):
self.running = True
def stop_clicking(self):
self.running = False
def exit(self):
self.stop_clicking()
self.program_running = False
def run(self):
while self.program_running:
while self.running:
mouse.click(self.button)
time.sleep(self.delay)
time.sleep(0.1)
mouse = Controller()
click_thread = ClickMouse(delay, button)
click_thread.start()
def on_press(key):
if key == start_stop_key:
if click_thread.running:
click_thread.stop_clicking()
else:
click_thread.start_clicking()
elif key == exit_key:
click_thread.exit()
listener.stop()
with Listener(on_press=on_press) as listener:
listener.join()
Common Issues and Questions
ModuleNotFoundError/ImportError: No module named ‘pynput’
Did you install pynput? This error will not occur if you installed it properly. If you have multiple versions of Python, make sure you are installing pynput on the same version as what you are running the script with.
I got a SyntaxError
Syntax errors are caused by you and there is nothing I can offer to fix it apart from telling you to read the error. They always say where the error is in the output using a ^. Generally, people that get this issue have incorrect indentation, brackets in the wrong place or something spelt wrong. You can read about SyntaxError on Python’s docs here.
‘python’ is not recognized as an internal or external command
Python hasn’t been installed or it hasn’t been installed properly. Go to /blog/post/how-to-setup-pythons-pip/ and follow the tutorial. Just before you enter the scripts folder into the path variable, remove the «scripts» part at the end. You will also want to add another path with «scripts» to have pip.
Edited 11/08/18: Added Python 2 support
Время на прочтение
7 мин
Количество просмотров 148K
Предисловие
Как можно развлечься в новогодние праздники? Поиграть в компьютерные игры? Нет! Лучше написать бота, который это будет делать за тебя, а самому пойти лепить снеговика и пить глинтвейн.
Когда-то в школьные годы был увлечен одной из популярных MMORPG — Lineage 2. В игре можно объединяться в кланы, группы, заводить друзей и сражаться с соперниками, но в общем игра наполнена однообразными действиями: выполнением квестов и фармом (сбор ресурсов, получение опыта).
В итоге решил, что бот должен решать одну задачу: фарм. Для управления будут использоваться эмулированные клики мыши и нажатия клавиш клавиатуры, а для ориентирования в пространстве — компьютерное зрение, язык программирования — Python.
Вообще, создание бота для L2 дело не новое и их готовых есть довольно много. Делятся они на 2 основные группы: те, которые внедряются в работу клиента и кликеры.
Первые — это жёсткий чит, в плане игры пользоваться ими слишком уж неспортивно. Второй вариант интереснее, учитывая, что его можно будет с некоторыми доработками применить к любой другой игре, да и реализация будет интереснее. Те кликеры, которых я находил, по разным причинам не работали, либо работали нестабильно.
Внимание: вся информация здесь изложена только в познавательных целях. Особенно для разработчиков игр, чтобы помочь им лучше бороться с ботами.
Итак, к делу.
Работа с окном
Тут все просто. Будем работать со скриншотами из окна с игрой.
Для этого определим координаты окна. С окном работаем с помощью модуля win32gui. Нужное окно определим по заголовку — “Lineage 2”.
Код методов получения положения окна
def get_window_info():
# set window info
window_info = {}
win32gui.EnumWindows(set_window_coordinates, window_info)
return window_info
# EnumWindows handler
# sets L2 window coordinates
def set_window_coordinates(hwnd, window_info):
if win32gui.IsWindowVisible(hwnd):
if WINDOW_SUBSTRING in win32gui.GetWindowText(hwnd):
rect = win32gui.GetWindowRect(hwnd)
x = rect[0]
y = rect[1]
w = rect[2] - x
h = rect[3] - y
window_info['x'] = x
window_info['y'] = y
window_info['width'] = w
window_info['height'] = h
window_info['name'] = win32gui.GetWindowText(hwnd)
win32gui.SetForegroundWindow(hwnd)
Получаем картинку нужного окна с помощью ImageGrab:
def get_screen(x1, y1, x2, y2):
box = (x1 + 8, y1 + 30, x2 - 8, y2)
screen = ImageGrab.grab(box)
img = array(screen.getdata(), dtype=uint8).reshape((screen.size[1], screen.size[0], 3))
return img
Теперь будем работать с содержимым.
Поиск монстра
Самое интересное. Те реализации, которые я находил, мне не подошли. Например, в одном из популярных и даже платном это сделано через игровой макрос. И “игрок” должен для каждого типа монстра прописывать в макросе типа “/target Monster Name Bla Bla”.
В нашем случае мы последуем такой логике: в первую очередь найдём все тексты белого цвета на экране. Белый текст может быть не только названием монстра, но и именем самого персонажа, именем NPC или других игроков. Поэтому надо навести курсор на объект и если появится подсветка с нужным нам паттерном, то можно атаковать цель.
Вот исходная картинка, с который будем работать:
Закрасим черным своё имя, чтобы не мешало и переведем картинку в ч/б. Исходная картинка в RGB — каждый пиксель это массив из трёх значений от 0 до 255, когда ч/б — это одно значение. Так мы значительно уменьшим объем данных:
img[210:230, 350:440] = (0, 0, 0)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
Найдем все объекты белого цвета (это белый текст с названиями монстров)
ret, threshold1 = cv2.threshold(gray, 252, 255, cv2.THRESH_BINARY)
Морфологические преобразования:
- Фильтровать будем по прямоугольнику размером 50×5. Такой прямоугольник подошел лучше всех.
- Убираем шум внутри прямоугольников с текстом (по сути закрашиваем всё между букв белым)
- Еще раз убираем шум, размывая и растягивая с применением фильтра
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (50, 5))
closed = cv2.morphologyEx(threshold1, cv2.MORPH_CLOSE, kernel)
closed = cv2.erode(closed, kernel, iterations=1)
closed = cv2.dilate(closed, kernel, iterations=1)
Находим середины получившихся пятен
(_, centers, hierarchy) = cv2.findContours(closed, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
Работает, но можно сделать прикольнее (например, для монстров, имена которых не видны, т.к. находятся далеко) — с помощью TensorFlow Object Detection, как тут, но когда-нибудь в следующей жизни.
Теперь наводим курсор на найденного монстра и смотрим, появилась ли подсветка с помощью метода cv2.matchTemplate. Осталось нажать ЛКМ и кнопку атаки.
Клик
С поиском монстра разобрались, бот уже может найти цели на экране и навести на них мышь. Чтобы атаковать цель, нужно кликнуть левой кнопкой мыши и нажать «атаковать» (на кнопку «1» можно забиндить атаку). Клик правой кнопкой мыши нужен для того, чтобы вращать камеру.
На сервере, где я тестировал бота, я вызвал клик через AutoIt, но он почему-то не сработал.
Как оказалось, игры защищаются от автокликеров разными способами:
- поиск процессов, которые эмулируют клики
- запись кликов и определение, какого цвета объект, на который кликает бот
- определение паттернов кликов
- определение бота по периодичности кликов
А некоторые приложения, как клиент этого сервера, могут определять источник клика на уровне ОС. (будет здорово, если кто-нибудь подскажет как именно).
Были перепробованы некоторые фреймворки, которые могут кликать (в т.ч. pyautogui, robot framework и что-то еще), но ни один из вариантов не сработал. Проскользнула мысль соорудить устройство, которое будет нажимать кнопку (кто-то даже так делал). Похоже, что нужен клик максимально хардварный. В итоге стал смотреть в сторону написания своего драйвера.
На просторах интернета был найден способ решения проблемы: usb-устройство, которое можно запрограммировать на подачу нужного сигнала — Digispark.
Ждать несколько недель с Алиэкспресса не хочется, поэтому поиски продолжились.
В итоге была найдена замечательная библиотека на C
Нашлась для неё и обёртка на Python
Библиотека у меня не завелась на питоне 3.6 — вываливалась ошибка Access violation что-то там. Поэтому пришлось соскочить на питон 2.7, там всё заработало like a charm.
Движение курсора
Библиотека может посылать любые команды, в том числе, куда переместить мышь. Но выглядит это как телепортация курсора. Нужно сделать движение курсора плавным, чтобы нас не забанили.
По сути задача сводится к тому, чтобы перемещать курсор из точки A в точку B с помощью обертки AutoHotPy. Неужели придется вспоминать математику?
Немного поразмыслив, всё-таки решил погуглить. Оказалось, что ничего придумывать не надо — задачу решает алгоритм Брезенхэма, один из старейших алгоритмов в компьютерной графике:
Прямо с Википедии можно взять и реализацию
Логика работы
Все инструменты есть, осталось самое простое — написать сценарий.
- Если монстр жив, продолжаем атаковать
- Если нет цели, найти цель и начать атаковать
- Если не удалось найти цель, немного повернемся
- Если 5 раз никого не удалось найти — идём в сторону и начинаем заново
Из более-менее интересного опишу, как я получал статус здоровья жертвы. В общих чертах: находим по паттерну с помощью OpenCV элемент управления, показывающий статус здоровья цели, берём полоску высотой в один пиксель и считаем в процентах, сколько закрашено красным.
Код метода получения уровня здоровья жертвы
def get_targeted_hp(self):
"""
return victim's hp
or -1 if there is no target
"""
hp_color = [214, 24, 65]
target_widget_coordinates = {}
filled_red_pixels = 1
img = get_screen(
self.window_info["x"],
self.window_info["y"],
self.window_info["x"] + self.window_info["width"],
self.window_info["y"] + self.window_info["height"] - 190
)
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
template = cv2.imread('img/target_bar.png', 0)
# w, h = template.shape[::-1]
res = cv2.matchTemplate(img_gray, template, cv2.TM_CCOEFF_NORMED)
threshold = 0.8
loc = np.where(res >= threshold)
if count_nonzero(loc) == 2:
for pt in zip(*loc[::-1]):
target_widget_coordinates = {"x": pt[0], "y": pt[1]}
# cv2.rectangle(img, pt, (pt[0] + w, pt[1] + h), (255, 255, 255), 2)
if not target_widget_coordinates:
return -1
pil_image_hp = get_screen(
self.window_info["x"] + target_widget_coordinates['x'] + 15,
self.window_info["y"] + target_widget_coordinates['y'] + 31,
self.window_info["x"] + target_widget_coordinates['x'] + 164,
self.window_info["y"] + target_widget_coordinates['y'] + 62
)
pixels = pil_image_hp[0].tolist()
for pixel in pixels:
if pixel == hp_color:
filled_red_pixels += 1
percent = 100 * filled_red_pixels / 150
return percent
Теперь бот понимает, сколько HP у жертвы и жива ли она еще.
Основная логика готова, вот как теперь он выглядит в действии:
Для занятых я ускорил на 1.30
Остановка работы
Вся работа с курсором и клавиатурой ведется через объект autohotpy, работу которого в любой момент можно остановить нажатием кнопки ESC.
Проблема в том, что всё время бот занят выполнением цикла, отвечающим за логику действий персонажа и обработчики событий объекта и autohotpy не начинают слушать события, пока цикл не закончится. Работу программы не остановить и с помощью мыши, т.к. бот управляет ей и уводит курсор куда ему нужно.
Нам это не подходит, поэтому пришлось разделить бота на 2 потока: слушание событий и выполнение логики действий персонажа.
Создадим 2 потока
# init bot stop event
self.bot_thread_stop_event = threading.Event()
# init threads
self.auto_py_thread = threading.Thread(target=self.start_auto_py, args=(auto_py,))
self.bot_thread = threading.Thread(target=self.start_bot, args=(auto_py, self.bot_thread_stop_event, character_class))
# start threads
self.auto_py_thread.start()
self.bot_thread.start()
и теперь вешаем обработчик на ESC:
auto_py.registerExit(auto_py.ESC, self.stop_bot_event_handler)
при нажатии ESC устанавливаем событие
self.bot_thread_stop_event.set()
и в цикле логики персонажа проверяем, установлено ли событие:
while not stop_event.is_set():
Теперь спокойно останавливаем бота по кнопке ESC.
Заключение
Казалось бы, зачем тратить время на продукт, который не приносит никакой практической пользы?
На самом деле компьютерная игра с точки зрения компьютерного зрения — почти то же самое, что и снятая на камеру реальность, а там возможности для применения огромны. Отличный пример описан в статье про подводных роботов, которые лазером стреляют по лососям. Также статья может помочь разработчикам игр в борьбе с ботоводами.
Ну а я ознакомился с Python, прикоснулся к компьютерному зрению, написал свой первый слабоумный искусственный интеллект и получил массу удовольствия.
Надеюсь, было интересно и вам.
P.S. Ссылка на репозиторий