Предисловие
Как можно развлечься в новогодние праздники? Поиграть в компьютерные игры? Нет! Лучше написать бота, который это будет делать за тебя, а самому пойти лепить снеговика и пить глинтвейн.
Когда-то в школьные годы был увлечен одной из популярных 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)
Морфологические преобразования:
- Фильтровать будем по прямоугольнику размером 50x5. Такой прямоугольник подошел лучше всех.
- Убираем шум внутри прямоугольников с текстом (по сути закрашиваем всё между букв белым)
- Еще раз убираем шум, размывая и растягивая с применением фильтра
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. Ссылка на репозиторий
Комментарии (70)
willy_the_fox
08.01.2018 19:14Прикольно. Но, труднее ли это было бы реализовать на AutoHotkey?
KirEv
08.01.2018 19:27+1прикольно получилось, играл когда-то :)
бот для развлечения, не хватает обработок ситуаций:
— фармишь лес, тебя убили, появился в городе дать направление куда бежать (в зависимости от города)
— если попадаешь на мостра:
— выше твоего уровня — на таких, скорее всего, не стоит нападать
— обходить агрессивных монстров, если они выше твоего уровня
— обходить группы монстров
— если монстры все вокруг убиты и не спавняться — дать новое направление
— избегать игроков и отличать их от монстров — чтобы нас не убили и наш бот не запалили :)
в общем, интересная задумка.
Казалось бы, зачем тратить время на продукт, который не приносит никакой практической пользы?
я бы здесь не согласился
— ради «попробовать» — интересно и полезно, с чем Вы согласны,
— помню, на некоторых серверах L2, пользователи покупали шмотки, аден, аккаунты за реальные деньги :)
если довести бот до максимальной автономности, чтобы персонаж качался круглосуточно — оставив несколько клиентов L2 запущенных под управлением подобного бота в VM Ware, за месяцок можно набить нормальное количество аккаунтов с прокачанными и «одетыми» персонажами… останеться лишь продать :)Sevensenn
08.01.2018 21:14Круглосуточно — очень быстро будет замечено.
Belking
08.01.2018 22:32Вы, видимо, просто не знакомы с Lineage 2)
mickvav
08.01.2018 23:02А в чем собственно проблема запрограммировать бота на «разлогиниться в 2 часа ночи и залогиниться в 8 утра»… А если добавить случайности (+- час тут, траекторию «мыши» сделать не ровно прямой, направление выбирать случайно, монстров «иногда» не замечать...) — то можно очень долго не палиться…
DistortNeo
09.01.2018 17:32А в чем собственно проблема запрограммировать бота на «разлогиниться в 2 часа ночи и залогиниться в 8 утра»…
А зачем? Нахождение в онлайне 24/7 ещё не означает, что персонаж бот. Может, он просто торгует?
Sevensenn
08.01.2018 23:27Прекрасно знаком.
Есть существенная разница между (на вскидку):
— Персонаж 24 часа бегает в одном данже, бъет одних и тех же мобов 4 абилками, в чат не пишет, не делает релог.
— Персонаж переписывается в чате, бегает в город, сидит мулом в Гиране или Одене, торгуя A-сетом.
Как ниже написал mickvav, эмулирование действий человека, в том числе, ошибки, запланированные и случайные по длительности паузы — существенно увеличивают шанс не попасть под банхаммер. А вот 24/7 гринд — верный путь в бан.DistortNeo
09.01.2018 17:35— Персонаж 24 часа бегает в одном данже, бъет одних и тех же мобов 4 абилками, в чат не пишет, не делает релог.
И как вы сможете это проверить? Насколько я помню, сервер L2 не пишет насколько детальную информацию в логи. Ну и даже если бы и писал, то автоматическое выявление ботов было бы серьёзной BigData задачей.
Поэтому стандартный способ выявления ботов — вручную по репортам, либо через невалидные данные (невидимые мобы, например).
alexr64
09.01.2018 18:01стандартный способ выявления ботов —
Группа опытных ботхантеров 24/7 ингейм, патрулирующих все локации. Невалидные мобы/итемы — мера против школьников и то, на 1-2 раза. А вот гейм-мастер, снимающий баф с чара — гораздо эффективный метод.DistortNeo
09.01.2018 19:04На еврооффе, где я играл, ГМы так не заморачивались. Потому ботоводство там цвело и пахло. Но вообще, если владелец сервера действительно хочет избавиться от ботов, то он может это сделать. А вот с чем владелец сервера ничего не может сделать — это снифферы, совсем простая автоматизация и багоюз.
Группа опытных ботхантеров 24/7 ингейм, патрулирующих все локации
А ещё был GMChecker. ГМ в онлайне — боты прячутся.
Ещё была технология определения местоположения любого игрока в игре.
И да, с инстансами что делать?alexr64
09.01.2018 19:26+1А вот с чем владелец сервера ничего не может сделать — это снифферы, совсем простая автоматизация и багоюз.
Мы говорим про официальные сервера или все?
И да, с инстансами что делать?
Инстансы не создаются динамически и преград для доступа ГМов в инстансы нет.
А ещё был GMChecker.
/gmlist или /gmonline, точно не помню. Стандартная команда и, есессно, у ГМов есть опция «не отображать в списке онлайн» (с каких хроник — не скажу, но есть).
ГМы так не заморачивались
KirEv
09.01.2018 01:36когда впервые познакомился с Л2, я был на 1курсе КПИ, тогда были лишь первые хроники, и рейты на все х1, и когда старый сервер Duron 900Mhz падал, пол-дня игры коту под хвост, что очень многих раздражало, и многие играли чуть ли не сутками :)
самый заядлых игроков — отчислили в первом семестре, я был не из заядлых, но в придачу еще и бухал, потому и меня отчислили )
alexr64
09.01.2018 11:35помню, на некоторых серверах L2, пользователи покупали шмотки, аден, аккаунты за реальные деньги :)
На всех. Цена зависит от даты старта сервера.
kpa6uu
08.01.2018 21:14Интересная штука!
Было бы круто, если бы нашлось время на разбор бота с внедрением в процесс игры.
Обходы защит и прочие плюшки :)DistortNeo
09.01.2018 17:24+1Могу вкратце написать, как я обходил GameGuard на еврооффе. Особенности GameGuard:
Сразу после старта клиента, но до старта GameGuard (около секунды) клиент является абсолютно незащищённым — можно делать что угодно. После старта GameGuard последний ограничивает внешний доступ к процессу, мониторит сетевые соединения и проверяет консистентность системных библиотек.
Для перехвата соединений внутри клиента я использовал обычный DLL-injection и JMP-хуки (при этом меняется код системной библиотеки в памяти процесса). Всё это успешно делалось в первую секунду после старта процесса. При этом был обнаружен интересный факт: GameGuard препятствет установке хуков на recv(), send() — даже если они были установлены ранее, то GG восстанавлияет исходный код библиотеки, но позволяет устанавливать JMP-hook на функцию connect().
Но не всё так просто: мы не можем просто взять и перенаправить вызов connect() на адрес, отличный от сервера L2 — это спалит система защиты. Но оказалось, что GameGuard нормально пропускает сокеты, переданные из другого процесса с помощью DuplicateAndClose. Поэтому внутри процесса настраивался pipe, а затем оба сокета передаётся в процесс-бот, ну а дальше дело техники.
Ну и ещё мелочь: перехват кликов мышки для того, чтобы клики, сделанные поверх окна бота, не доходили до клиента. Здесь всё аналогично, но хуки навешивались уже на одну из библиотек DirectX.kpa6uu
11.01.2018 19:23Интересно, спасибо!
Будет круто увидеть это в виде сочного, жирного поста. Если будет желание и время.
Naglec
08.01.2018 21:29Как это сочетается, например, с Фростом и 4геем?
KsamD
08.01.2018 22:48бот явно писался не для L2 Classic, там явно требуется учесть и предугадать больше вариантов развития событий, весьма агрессивного «ареала обитания».
P.S. для полностью автономного существования
а Фрост кликеры и не палил, процесс clicker.exe переименовал в neygadal.exe на этом хак законченNaglec
08.01.2018 22:49Ну, в классике и нет кат, для которых этот бот и подходит :)
KsamD
08.01.2018 23:23есть места где появление мобов ограничено пятачком, + некоторые локации аля Forgotten Temple под Глудином, разбитое на комнаты.
для ботовода 2 правила:
1. правильное место)
2. тихое место)IamNoExist
09.01.2018 11:47На самом деле правил гораздо больше, если хочешь максимально снизить вероятность бана, какое бы тихое место ни было, рано или поздно может пробежать случайный игрок, спалить тебя, написать петицию, приходит модератор, всё твоего аккаунта больше нет)
alexr64
09.01.2018 12:03Для ботовода могу выделить несколько правил:
1) Не играть.
2) Ваших чаров забанят. Когда — вопрос времени, к этому нужно быть готовым.
3) Не пастись в одной локации.
maxeem Автор
08.01.2018 22:52Я писал бота для Interlude, т.к. мне доводилось играть только на этих хрониках. Хроники на актуальных серверах давно ушли вперед.
GoldAfonya
08.01.2018 22:11Классная статья по старой доброй игре :) Интересно было прочитать, когда ни будь надеюсь повторить.
forcam
08.01.2018 23:51Знавал пару ботоводов, не знаю на сколько правда но в зависимости от сервера, обмундирования и противодействия зарабатывали от 500 до 1500$. Поэтому не такая уж и забава) подруга с Украины многие годы только так и зарабвтывала (с ее слов), нигде больше не работая. А по теме, ваш бот легко спалит админ поставив вдалеке мобов 80ур., впрочем это самый распространенный способ обнаружения, но т.к. мобы эти бордово-крассные, то конечно с этим не сложно бороться. Еще обычно смотрят по поведению, если оно прямо как у робота, то конечно будет бан, возможно даже перманентный. Вообще как задрот ла2 могу с уверенностью сказать, если делать избыточно-рандомные действия (ходить не по прямой, а свариациями, изменять угол смотрения камеры, не замирать на месте, а делать все как бы потоково, но не быстрее человека) — спалить очень сложно, потому что тогда отличить будет ну очень сложно, игроки там бегают почти всегда одинаково и делают это часами. Встречал такого бота когда еще играл на РуОфе, мне 15 минут понадобилось что бы понять, что это бот) кто-то подошел реально творчески к процессу, а конда я его пытался под мобами станить, что бы они его убивали, у него срабастывал авторелог, а если совсем все плохо было, то просто бсое :)
Naglec
09.01.2018 14:53Зарабатывать надо на продаже бота :)
zartarn
09.01.2018 15:05Сложно конкурировать с Адреналином :). Даже пока наращиваешь возможности, очень сложно демпинговать будет.
KsamD
09.01.2018 20:52Адреналин не просто софтина, а уже целый сервис с поддержкой, там грамотно все сделали, качество не проверял, но сам подход :)
Крупные кланы обычно пользуются приватным софтом, настраиваемый под задачи, там такой человек на окладе сидит), к тому же все конвертируемое в вечно зеленые в их руках, сам бог велел как говорится, доход одинокого ботовода не сравнится с Топами, но в зависимости от периода развития игры на икру хватит
Tihon_V
09.01.2018 00:27
isnofreedom
09.01.2018 01:31В своё время не вылезал из l2. Ночи в катах, мамон… Ностальгия напала. :'0
doom369
09.01.2018 02:04В новой «линейке» Revolution разработчики полностью решили проблему ботов. Теперь там есть кнопка «автофарм» :).
forcam
09.01.2018 03:44ну есть Lineage ll classik, ну и куча фришек, где еще очень долго не будет этого обновления, на многих определенно никогда) а вообще фарм это конвертация твоего времени в ценности, поэтому теперь все решает только толщина кошелька, ла2 закатилась туда где решают только деньги, поэтому хочешь старую ламповую, либо на фриху, либо забивать, даже на руофе, на классике ввели магаз, хотя били пяткой в гпудь что не бывать этому никогда, короче и там видимо темная сторона все заруинит :( а раньше, это был несомненный шедевр, ни одна игра не приносила такое море эмоций…
Tsimur_S
09.01.2018 14:29lineage 2 revolution это не обновление а отдельная мобильная гриндилка не имеющая отношения к традиционной ла2, классику и фришкам(ну может кроме лора).
sulla
09.01.2018 16:16хорошо, что это «дедушки» не видели, которые до сих пор в Ultima Online играют :)
и скрипты пишут под неё
KMiNT21
09.01.2018 02:30А я не так давно для FIFA 18 делал бота, который сам по ночам просто матчи запускал (результат там не важен) для фарминга монет.
Тоже на Python (+ PyQT для удобства). Использовал OpenCV для анализа того, что ImageGrab «скринил». Пришлось сделать много скриншотов, из которых я удалял лишнее (делал прозрачным) и оставлял только то, что точно идентифицирует наше «состояние».
Пытался сделать так, чтобы работало со свернутым окном — никак. :) Не придумал вообще как можно получить снимок неактивного DirectX приложения (и можно ли вообще). Да и клавиши все равно слать надо… Проще уже в виртуалке, если тянет.
Ну а так работало все. Запустил, Alt+Enter, нажал «Start» боту, и погнало до утра играть. :)VagabundSketch
09.01.2018 21:26Если есть свободный VGA порт, в windows можно добавить виртуальный монитор как описано здесь: superuser.com/questions/62051/is-there-a-way-to-fake-a-dual-second-monitor#796884.
Areso
09.01.2018 09:39Делал хардварный кликер. Нужна серва и ардуинка.
Серву к клавиатуре крепил двумя саморезами.
github.com/Areso/Arduino-clicker
DSLow
09.01.2018 09:58Если в локации будут другие белые имена помимо мобов? NPC/Игроки.
И мне показалось, что работает (обрабатывает события) медленно. Очень много времени занимает нахождение цели, выделение, повороты.edge790
09.01.2018 18:04Как я понял, при наведении мыши мобы иначе подсвечиваются (например красным)
Теперь наводим курсор на найденного монстра и смотрим, появилась ли подсветка с помощью метода
alexr64
09.01.2018 18:19при наведении мыши мобы иначе подсвечиваются
Нет. А вот как я понял — проверки на «моб — чар» просто нет. Потому первый же чар (по правилам игры, чаров с белым ником атаковать без зажатого Ctrl нельзя) уведет бота куда угодно (атака в «белого», на игровом сленге «не флагнутого» — не перешедшего в пвп режим (тогда ник чара розовеет), работает как атака в NPC: начать диалог).
vladimirboiko
09.01.2018 23:13Было написано про НПС, проверяется отклик при наведении, если он «правильный», то кликается левая кнопка мыши и идет атака, если же он «неправильный» то выбирается следующая цель.… Интересный актокликер, мне понравилась как логика реализации так и сама реализация, классненько, я когда-то делал кликер для пв, там было тоже не очень просто реализовать все эти логические комбинации, решил проблему почти также :)
DistortNeo
09.01.2018 17:06Аж передёрнуло от темы. В своё время (~10 лет назад) играл на еврооффе, и тоже писал своего бота. Причём писал тоже по-серьёзному: с кусей пользователей, сервером обновления бота. Собственно, для меня это был первый серьёзный проект, которых неплохо подтянул скилл программирования.
Важный момент: система защиты на офсерверах (GameGuard) обходилась с полпинка, за ботами особо не следили, поэтому я работал непосредственно на уровне сетевого протокола.
Ну и алгоритмы старался делать интересные:
— глобальную навигацию: бот сам может добежать в точку с произвольными координатами, используя при необходимости телепорты, без необходимости задания вэйпоинтов (удобно для второоконного баффера, чтобы не переключаться на него);
— обмен информацией между персонажами для оффпати режимов;
— важной составляющей является активный багоюз, но это уже отдельная тема для разговора.
Немного жалею, что в те времена ещё не было средств разработки, которые доступны сейчас — сделал бы гораздо больше всего интересного. Дико не хватало асинхронного программирования. Ну и сейчас я бы попробовал использовать не захардкоженные алгоритмы, а ИИ для более правдоподобных действий ботов.
edge790
09.01.2018 18:02А некоторые приложения, как клиент этого сервера, могут определять источник клика на уровне ОС. (будет здорово, если кто-нибудь подскажет как именно).
Мое предположение, что автокликеры используют WinApi для кликов/хоткеев, а игра использует DirectInput
DistortNeo
09.01.2018 18:58+1> Мое предположение, что автокликеры используют WinApi для кликов/хоткеев, а игра использует DirectInput
Именно так. Фильтр кликов внутри игры я делал, перехватывая соответствующие функции.
Keinael
09.01.2018 21:29Спасибо большое автору за эту чудесную статью) После просмотра видео подхватил ностальгию) Жаль только звуков нет в видосике ;( Теперь вот сегодня — завтра сам пойду катать, правда в HF. Заведу себе гномку — рабыню, которая круглосуточно будет фармить каты xD
danzalux
09.01.2018 21:31В юности какой-то кусок времени игрался в Silkroad где-то до 2008го года со всеми вытекающими систем free2p(l)ay — донаты, боты… Был отличный хак"testosterone" от товарища Rumata с небольшим изменением в клиенте, так же был слегка кАличный, но работающий TBot, который как-то навешивал хуки и пропускал через себя трафик игры, как через прокси, анализируя входные и добавляя команды на движения в выходные данные…
Может кто помнит?
public_static__void
09.01.2018 23:12В классе 9м наткнулся на одну статью, где с помощью С и малых манипуляций с оджидебагером и ассемблером, было предложено сделать что то типа «робота для 3й GTA»
все делалось только работая с памятью.
Игра запускалась на виртуальной машине, и простор для фантазии был практически безграничен, правда обратной связи от игры получить я так и не смог.
Вот сейчас задумался попробовать сделать что ни будь подобное и с современными играми
Karakhan
11.01.2018 10:42Давненько в Линейку не играл, но если мне не изменяет память, по умолчанию на TAB’е висит перебор целей, видимых на экране. Название и ХП текущей цели отображаются в прямоугольнике в верхней части экрана. Не проще ли работать с этим таргетным прямоугольником, а не со всем экраном?
Slysar7
11.01.2018 10:42Не играл в линейку, но… почитал алгоритм бота:
Если монстр жив, продолжаем атаковать
Если нет цели, найти цель и начать атаковать
Если не удалось найти цель, немного повернемся
Если 5 раз никого не удалось найти — идём в сторону и начинаем заново
Пока он ищет цель и вертится его не убьют?KsamD
12.01.2018 00:55у каждого монстра есть так называемое время респа(с момента убийства до возрождения) и координаты респа (в данном случае в пределах комнаты)
Самое сложное зачистить комнату, когда все монстры уже появились(на игрока налетает вся толпа), делается как правило в ручную
цели убиваются поочередно,
из этого следует что и появляются они по очереди, а не толпой после зачистки комнаты
главное рассчитать время убийства моба с временем респа и вуаля)
Rammix
11.01.2018 10:42Было бы прекрасно увидеть нечто подобное, но не для автономного бота, а для текстового клиента. Т.е., например, на одной машине: определение мобов и окружающих объектов с помощью оптического распознавания, совершение действий. На другой — управление действиями первой машины (и чатом в ней) с помощью коротких команд, пример (утрированный):
find target
«targets found 6, names: monster Nephilim (2), monster OtherName(2), monster YetAnotherName(1), player VasyaBigOrc»
attack -player VasyaBigOrc &
useskillbutton -row 3 -number 7
Естественно, скорость реакции и действий в случае пвп оставляли бы желать лучшего, но соль-то не в них.
Mogost
А сколько времени было потрачено на создание бота?
maxeem Автор
В часах немного, начал две недели назад.