Некоторое время, я размышлял, о чём бы написать свою первую статейку. Хотел написать о программировании микроконтроллеров, но оказалось трудно отделить части рабочих проектов от тех, что можно опубликовать без оглядки на коллег 🙂 Остановился на идее о ботах.
Введение
Боты для онлайн игр я бы грубо разделил на 3 разновидности по способам реализации:
1. Боты не использующие приложение игры. Имитирующие протокол обмена с сервером.
2. Боты работающие с процессом приложения игры. В случае с Web, работающие с окном браузера.
3. Боты работающие со скриншотом и имитирующие устройства ввода мышь и клавиатуру.
Первая разновидность скорее гипотетическая, т.к. протоколы, как правило, закрыты и не тривиальны.
Вторая разновидность более реальна и может быть реализована. Бот второго вида получает полезную информацию из памяти процесса игры. Недостаток — версии клиентов могут регулярно обновляться и тогда может потребоваться заново искать интересующие адреса памяти.
Мы рассмотрим третюю разновидность ботов, т.к. ИМХО они более привлекательны, хоть и не лишены недостатков.
В этой статье я рассмотрю набор инструментов для самого простого бота для Windows.
Для самого простого бота достаточно эмитировать события мыши и клавиатуры. В большинстве случаев этого оказывается достаточно для решения (не самого эффективного, но не требующего участия человека) рутинных дел в различных играх. Для более эффективной работы бота требуется обратная связь с игрой, т.е. получение и обработка скриншотов игры.
Код
Для разработки приложений я буду использовать Qt Creator + Qt 5 либы (так мне привычнее) и раз бот для Виндовс то + windows.h (WinAPI).
Инклуды:
#include <windows.h> // WinAPI #include <iostream> // std::cout #include <unistd.h> // sleep(), usleep() #include <math.h>
Хидер бота:
// Индексы точек enum { menu=0, elm_1, points_cnt }; class MyBot { public: MyBot(); void run(); void move_to(int inx); void lclick_to(int inx); void rclick_to(int inx); void drag(int from_inx,int to_inx); POINT point[points_cnt]; };
Конструктор:
MyBot::MyBot() : // Массив координат органов управления (по которым мы будем кликать мышкой) point({ {100,100}, // 0 - menu {130,130}, // 1 - elm_1 }) { }
Регистрация горячих кнопок для управления ботом:
RegisterHotKey((HWND)Widget::winId(), 101, MOD_ALT, VK_F1); // Запуск бота RegisterHotKey((HWND)Widget::winId(), 102, MOD_ALT, VK_F2); // inx++ RegisterHotKey((HWND)Widget::winId(), 103, MOD_ALT, VK_F3); // Проверить точку inx RegisterHotKey((HWND)Widget::winId(), 104, MOD_ALT, VK_F4); // Запомнить точку inx RegisterHotKey((HWND)Widget::winId(), 105, MOD_ALT, VK_F5); // Вывести в консоль массив координат
Обработка событий нажатия кнопок управления ботом:
int inx=0; MyBot bot; bool Widget::nativeEvent(const QByteArray & eventType, void * message, long * result){ Q_UNUSED(result); Q_UNUSED(eventType); MSG* msg = reinterpret_cast<MSG*>(message); if(msg->message!=WM_HOTKEY)return false; switch(msg->wParam){ case 101: // Alt-F1 - запуск бота bot.run(); return true; case 102: // Alt-F2 - inx++ if(inx<points_cnt-1)inx++; return true; case 103: // Alt-F3 - Проверить точку inx bot.move_to(inx); return true; case 104: // Alt-F4 - Запомнить точку inx GetCursorPos(&point[inx]); return true; case 105: // Alt-F5 - Вывести в консоль массив координат for(i=0;i<points_cnt;i++){ std::cout << "{" << bot.point[i].x << "," << bot.point[i].y << "}, //" << i << std::endl; } return true; } return false; }
Перемещение указателя мыши к нужной точке:
(выполнено не очень аккуратно, обещаю исправиться :-))
#define width 1920 #define height 1080 void MyBot::move_to(int inx){ int x=point[id].x; int y=point[id].y; POINT pt; GetCursorPos(&pt); int from_x=pt.x; int from_y=pt.y; int to_x=x; int to_y=y; int dx=to_x-from_x; int dy=to_y-from_y; float fdx; float fdy; int loop_cnt; if(abs(dx)>abs(dy) && dx!=0){ fdx=dx<0? -1.0 :1.0; fdy=(float)dy/abs(dx); loop_cnt=abs(dx); } else if(dy!=0){ fdy=dy<0? -1.0 :1.0; fdx=(float)dx/abs(dy); loop_cnt=abs(dy); } else return; // двинуть за 1 секунду int time=1000000/loop_cnt; float fx=from_x; float fy=from_y; for(int i=0;i<loop_cnt;i++){ fy+=fdy; fx+=fdx; int nx=(fx)*(65536 / width); int ny=(fy)*(65536 / height); mouse_event(MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE,nx,ny,0,0); usleep(time); } usleep(50000); }
Клики:
void MyBot::lclick_to(int inx){ move_to(inx); mouse_event(MOUSEEVENTF_LEFTDOWN,0,0,0,0); usleep(50000); mouse_event(MOUSEEVENTF_LEFTUP,0,0,0,0); usleep(100000); } void MyBot::rclick_to(int inx){ move_to(inx); mouse_event(MOUSEEVENTF_RIGHTDOWN,0,0,0,0); usleep(50000); mouse_event(MOUSEEVENTF_RIGHTUP,0,0,0,0); usleep(100000); }
Перетаскивание:
void MyBot::drag(int from_inx, to_inx){ move_to(from_inx); usleep(50000); mouse_event(MOUSEEVENTF_LEFTDOWN,0,0,0,0); usleep(70000); move_to(to_inx); mouse_event(MOUSEEVENTF_LEFTUP,0,0,0,0); usleep(30000); }
Работа бота:
void MyBot::run(){ rclick_to(menu); // кликнем правой кнопкой для вызова контекстного меню lclick_to(elm_1); // кликнем левой кнопкой по строке меню }
Мануал юзера
Перед запуском бота горячей кнопкой Alt-F1, бот следует сначала настроить, определив верные координаты органов управления по которым бот будет кликать.
Для запоминания координат точки наводим указатель месту и жмём Alt-F4.
Для проверки корректности точки отводим указатель в сторону и жмём Alt-F3.
Для настройки следующей точки жмём Alt-F2.
Для сохранения верных координат жмём Alt-F5.
Подводные камни
Опыт показывает, что не стоит торопиться кликать по органам управления и двигать указатель. Часто игры притормаживают, при наведении мыши на кнопку срабатывает отрисовка подсветки и прочие неведанные процессы и торопливость приводит к несрабатыванию клика или захвата при перетягивании и т.п. и как следствие неработоспособность бота. При ручном управлении, люди обычно таких досадных мелочей даже не замечают, так как работает обратная связь через органы зрения. Решение — делать паузы после всех элементарных действий.
Окно игры может произвольно свернуться в следствии появления сообщения от виндозы или ещё по каким причинам. В программе последовательности кликов и пауз стоит предусмотреть клик по иконке свёрнутой игры.
Qt Creator: qt-project.org/downloads
Исходный код проекта на гитхабе: github.com/rumaster/my_bot_v1
P.S. Не подумайте что я ярый противник онлайн игр, раз публикую исходники ботов. Я противник дискриминации ИИ (ботов) и за развитие онного. А ещё, игры — двигатель прогресса.
P.P.S. Говоря ИИ, я подразумеваю программу способную получать и обрабатывать (анализировать) информацию, планировать и выполнять действия в соответствии с целями и результатами анализа ситуации.
ссылка на оригинал статьи http://habrahabr.ru/post/212779/
Добавить комментарий