Статьи

Как написать бота на Python для онлайн-игр (Lineage 2)

  1. предисловие Как можно повеселиться на новогодние каникулы? Играть в компьютерные игры? Нет! Лучше...
  2. Поиск монстров
  3. Щелчок
  4. Перемещение курсора
  5. Логика работы
  6. Прекратить работу
  7. Заключение

предисловие

Как можно повеселиться на новогодние каникулы? Играть в компьютерные игры? Нет! Лучше написать бота, который сделает это за вас, и большинство отправится лепить снеговика и пить глинтвейн.

Однажды в школе я был очарован одной из популярных MMORPG - Lineage 2 , В игре вы можете вступать в кланы, группы, заводить друзей и сражаться с соперниками, но в целом игра наполнена монотонными действиями: выполнение квестов и фарм (сбор ресурсов, получение опыта).

  • В результате я решил, что бот должен решить одну задачу: ферма. Для управления будут использоваться эмулированные щелчки мыши и нажатия клавиш клавиатуры, а для компьютерной ориентации Python будет использоваться для ориентации в пространстве.

В общем, создание бота для L2 не новость, и готовых уже немало. Они делятся на 2 основные группы: те, которые реализованы в работе клиента и кликеры.

Первый - это жесткий чит, с точки зрения игры использовать их слишком неспортивно. Второй вариант более интересен, учитывая, что его можно применять с некоторыми модификациями к любой другой игре, и реализация будет более интересной. Те кликеры, которые я нашел по разным причинам, не работали или работали нестабильно.

Примечания: Вся информация здесь только для познавательных целей. Специально для разработчиков игр, чтобы помочь им лучше справляться с ботами.

Работа с окном

Все просто Будем работать со скриншотами из окна с игрой.
Для этого мы определяем координаты окна. С окном мы работаем с модулем win32gui. Требуемое окно определяется заголовком - «Lineage 2».

Код методов получения позиции окна

def get_window_info (): # установить информацию о окне win32gui.GetWindowText (hwnd): rect = win32gui.GetWindowRect (hwnd) x = rect [0] y = rect [1] w = rect [2] - xh = 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 = массив (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) серый = cv2.cvtColor (img, cv2.COLOR_BGR2GRAY)

COLOR_BGR2GRAY)

Давайте найдем все объекты белого цвета (это белый текст с именами монстров)

ret, threshold1 = cv2.threshold (серый, 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 (закрыто, ядро, итерации = 1) закрыто = cv2.dlate ( закрытый, ядро, итерации = 1)

Найдите середину полученного пятна

(_, центры, иерархия) = cv2.findContours (закрыто, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

Это работает, но это можно сделать веселее (например, для монстров, имена которых не видны, потому что они далеко) - с помощью TensorFlow Object Detection, как здесь, но когда-нибудь в следующей жизни.

Теперь наведем курсор на найденного монстра и посмотрим, появилась ли подсветка с помощью метода cv2.matchTemplate. Осталось нажать ЛКМ и кнопку атаки.

Щелчок

С поиском монстра выяснили, бот уже может найти цели на экране и навести на них мышь. Чтобы атаковать цель, нужно щелкнуть левой кнопкой мыши и нажать «атака» (кнопка «1» может атаковать атаку). Щелкните правой кнопкой мыши, чтобы повернуть камеру.

На сервере, где я тестировал бота, я вызывал клик через AutoIt, но он как-то не работал.

Как оказалось, игры защищены от автоматических кликеров разными способами:

  • Поиск процессов, эмулирующих клики
  • Запишите клики и определите, на какой цвет кликает бот
  • Определение шаблонов кликов
  • Определение бота по частоте кликов

И некоторые приложения, такие как клиент этого сервера, могут определить источник щелчка на уровне ОС. (будет здорово, если кто-то скажет вам, как именно).

Были опробованы некоторые фреймворки, которые можно щелкнуть (включая pyautogui, фреймворк робота и что-то еще), но ни один из вариантов не сработал. Мысль проскользнула в идею создания устройства, которое будет нажимать кнопку (кто-то даже сделал это). Кажется, вам нужно нажать на большинство аппаратных средств. В результате я начал искать пишущий драйвер.

В Интернете был найден способ решить проблему: запрограммировать устройство USB на выдачу нужного сигнала - Digispark ,

Во время моего исследования для хорошей языковой библиотеки:

Библиотека python 3.6 не работала для меня хорошо - я все время получал ошибку нарушения доступа. Поэтому мне пришлось перейти на Python 2.7, все работало как шарм.

Перемещение курсора

Библиотека может отправлять любые команды, в том числе, куда двигать мышью. Но похоже на телепортацию курсора. Нам нужно заставить курсор двигаться плавно, чтобы нас не забанили.

По сути, задача сводится к перемещению курсора из точки A в точку B с помощью оболочки AutoHotPy. Вы действительно должны помнить математику?

После небольшого размышления он решил погуглить. Оказалось, что изобретать ничего не нужно - проблему решает алгоритм Бренхема, один из старейших алгоритмов компьютерной графики.

Логика работы

Все инструменты есть, самое простое, что нужно написать сценарий.

  • Если монстр жив, мы продолжаем атаковать.
  • Если цели нет, найдите цель и начните атаковать.
  • Если мы не смогли найти цель, мы немного повернем.
  • Если 5 раз никто не смог найти - идите в сторону и начните снова.

Из более-менее интересных опишу, как я получил состояние здоровья пострадавшего. В общих чертах: из паттерна, использующего OpenCV, мы находим элемент управления, который показывает состояние здоровья цели, берёт полосу высотой в один пиксель и подсчитывает в процентах, сколько красного.

Код метода получения уровня здоровья пострадавшего

def get_targeted_hp (self): "" "вернуть hp жертвы или -1, если цели нет" "" hp_color = [214, 24, 65] target_widget_coordinates = {} заполнено_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) порог = 0,8 loc = np.where (res & gt; = порог), если count_nonzero (loc) == 2: для точки в 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) если нет target_widget_coordinates: вернуть -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) пикселя = pil_image_hp [0] .tolist () для пикселя в пикселях: если пиксель == hp_color: fill_red_pixels + = 1 процент = 100 * fill_red_pixels / 150 процентов возврата

Теперь бот понимает, сколько HP имеет жертва и жив ли он.

Основная логика готова, вот как это выглядит сейчас в действии:

Прекратить работу

Вся работа с курсором и клавиатурой выполняется с помощью объекта 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)) # начать потоки 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 ()

А в логическом цикле персонажа проверьте, установлено ли событие:

пока не stop_event.is_set ():

Теперь спокойно остановите бот на кнопке ESC.

Заключение

Казалось бы, зачем тратить время на продукт, который не приносит никакой практической выгоды?

Фактически, компьютерная игра с точки зрения компьютерного зрения почти такая же, как реалити-шоу на камеру, и там возможности для применения огромны. А также. Надеюсь, вам было интересно.

Ссылка на репозиторий

Предисловие Как можно повеселиться на новогодние каникулы?
Играть в компьютерные игры?
Играть в компьютерные игры?
Вы действительно должны помнить математику?

Новости

Блог по SEO-продвижению
Всем доброго времени суток! С вами на связи Макс Метелев и порадую я вас сегодня свеженьким постом на тему — как раскрутить блог в интернете. Мало просто создать блог, для этого необходимо провести

Встраиваемые вытяжки
Современные кухни обустроены полным комплектом оборудования, чтоб хозяйка и домочадцы ощущали себя очень комфортабельно. Одним из нужных компонент современных кухонь является вытяжка. Тяжело представить,

Контроль герметичности
Течь - этo канал либо пористый участок издeлия либо егo частей, нарушающих их плотность. Кaк правило, малые соответствующие размeры течей исключают возможность иx зрительного наблюдения либо обнаружения

Кымдан 2 купить
Доныне Кымдан-2 Инъекция более 30 раз была представлена на муниципальных и интернациональных выставках и удостоена золотых медалей и премий, сначала золотой медали WIPO (Глобальная организация умственной

Анализ сайта школы
За последние несколько лет школьные сайты перешли из разряда инновационных технологий, доступных и используемых единичными лидерами информационного движения, в категорию массовой практики. Более того,

Отдых в Париже
Туристский бизнес переживает не наилучшее время, туристические агентства запираются одна за другой, при этом не только лишь малые, да и достаточно прочные и размеренно стоящие на ногах. Потому давайте

Доставка контейнера из китая
телефон: +86 13999179145 Гуанчжоу телефон: +86 18609000245 ТЕКУЩЕЕ ВРЕМЯ Новосибирск Китай USD/RUB63. 907410

Помощь в подборе автомобиля
Наша компания предлагает Вам помощь в подборе автомобиля. В ближайшее время число автомобилей на дорогах Рф постоянно возрастает, неограниченное количество машин продаётся и покупается. К огорчению не

Регистрация доменов
Обычно любая работа над созданием сайта начинается на компьютере, но после того, как сайт готов, его необходимо разместить во всемирной паутине интернет. Естественно, что у тех новичков, кто создал свой

Капитальный ремонт квартир
Ремонт — дело не только лишь не дешевое, да и долгое. Время от времени есть возможность переработать интерьер квартиры при помощи косметического ремонта, который обходится существенно дешевле, чем серьезный.

Карта