Предисловие


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


Когда-то в школьные годы был увлечен одной из популярных 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)


Морфологические преобразования:


  1. Фильтровать будем по прямоугольнику размером 50x5. Такой прямоугольник подошел лучше всех.
  2. Убираем шум внутри прямоугольников с текстом (по сути закрашиваем всё между букв белым)
  3. Еще раз убираем шум, размывая и растягивая с применением фильтра

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. Неужели придется вспоминать математику?


Немного поразмыслив, всё-таки решил погуглить. Оказалось, что ничего придумывать не надо — задачу решает алгоритм Брезенхэма, один из старейших алгоритмов в компьютерной графике:


Прямо с Википедии можно взять и реализацию


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


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


  1. Если монстр жив, продолжаем атаковать
  2. Если нет цели, найти цель и начать атаковать
  3. Если не удалось найти цель, немного повернемся
  4. Если 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)


  1. Mogost
    08.01.2018 18:30

    А сколько времени было потрачено на создание бота?


    1. maxeem Автор
      08.01.2018 21:18

      В часах немного, начал две недели назад.


  1. willy_the_fox
    08.01.2018 19:14

    Прикольно. Но, труднее ли это было бы реализовать на AutoHotkey?


    1. GnuriaN
      08.01.2018 19:18

      Она палится системой защиты =)


      1. CrewcutNet
        08.01.2018 21:14

        тестил?)


      1. bro-dev
        09.01.2018 10:02

        По какому признаку?


        1. maxeem Автор
          09.01.2018 21:14

          Это самый интересный вопрос :)


  1. GnuriaN
    08.01.2018 19:18

    Спасибо. Вспомнил молодость и кучу маленьких программ для обмана защиты =)


  1. KirEv
    08.01.2018 19:27
    +1

    прикольно получилось, играл когда-то :)

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

    в общем, интересная задумка.

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


    я бы здесь не согласился
    — ради «попробовать» — интересно и полезно, с чем Вы согласны,
    — помню, на некоторых серверах L2, пользователи покупали шмотки, аден, аккаунты за реальные деньги :)

    если довести бот до максимальной автономности, чтобы персонаж качался круглосуточно — оставив несколько клиентов L2 запущенных под управлением подобного бота в VM Ware, за месяцок можно набить нормальное количество аккаунтов с прокачанными и «одетыми» персонажами… останеться лишь продать :)


    1. Sevensenn
      08.01.2018 21:14

      Круглосуточно — очень быстро будет замечено.


      1. Belking
        08.01.2018 22:32

        Вы, видимо, просто не знакомы с Lineage 2)


        1. mickvav
          08.01.2018 23:02

          А в чем собственно проблема запрограммировать бота на «разлогиниться в 2 часа ночи и залогиниться в 8 утра»… А если добавить случайности (+- час тут, траекторию «мыши» сделать не ровно прямой, направление выбирать случайно, монстров «иногда» не замечать...) — то можно очень долго не палиться…


          1. DistortNeo
            09.01.2018 17:32

            А в чем собственно проблема запрограммировать бота на «разлогиниться в 2 часа ночи и залогиниться в 8 утра»…

            А зачем? Нахождение в онлайне 24/7 ещё не означает, что персонаж бот. Может, он просто торгует?


        1. Sevensenn
          08.01.2018 23:27

          Прекрасно знаком.
          Есть существенная разница между (на вскидку):
          — Персонаж 24 часа бегает в одном данже, бъет одних и тех же мобов 4 абилками, в чат не пишет, не делает релог.
          — Персонаж переписывается в чате, бегает в город, сидит мулом в Гиране или Одене, торгуя A-сетом.

          Как ниже написал mickvav, эмулирование действий человека, в том числе, ошибки, запланированные и случайные по длительности паузы — существенно увеличивают шанс не попасть под банхаммер. А вот 24/7 гринд — верный путь в бан.


          1. DistortNeo
            09.01.2018 17:35

            — Персонаж 24 часа бегает в одном данже, бъет одних и тех же мобов 4 абилками, в чат не пишет, не делает релог.

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


            Поэтому стандартный способ выявления ботов — вручную по репортам, либо через невалидные данные (невидимые мобы, например).


            1. alexr64
              09.01.2018 18:01

              стандартный способ выявления ботов —

              Группа опытных ботхантеров 24/7 ингейм, патрулирующих все локации. Невалидные мобы/итемы — мера против школьников и то, на 1-2 раза. А вот гейм-мастер, снимающий баф с чара — гораздо эффективный метод.


              1. DistortNeo
                09.01.2018 19:04

                На еврооффе, где я играл, ГМы так не заморачивались. Потому ботоводство там цвело и пахло. Но вообще, если владелец сервера действительно хочет избавиться от ботов, то он может это сделать. А вот с чем владелец сервера ничего не может сделать — это снифферы, совсем простая автоматизация и багоюз.


                Группа опытных ботхантеров 24/7 ингейм, патрулирующих все локации

                А ещё был GMChecker. ГМ в онлайне — боты прячутся.
                Ещё была технология определения местоположения любого игрока в игре.
                И да, с инстансами что делать?


                1. alexr64
                  09.01.2018 19:26
                  +1

                  А вот с чем владелец сервера ничего не может сделать — это снифферы, совсем простая автоматизация и багоюз.

                  Мы говорим про официальные сервера или все?
                  И да, с инстансами что делать?

                  Инстансы не создаются динамически и преград для доступа ГМов в инстансы нет.
                  А ещё был GMChecker.

                  /gmlist или /gmonline, точно не помню. Стандартная команда и, есессно, у ГМов есть опция «не отображать в списке онлайн» (с каких хроник — не скажу, но есть).
                  ГМы так не заморачивались


                  1. DistortNeo
                    09.01.2018 20:01

                    /gmlist или /gmonline, точно не помню. Стандартная команда и, есессно, у ГМов есть опция «не отображать в списке онлайн» (с каких хроник — не скажу, но есть).

                    Понятное дело, что эта команда не работала. Были косвенные признаки определения, находится ли ГМ в онлайне или нет. Например, зная ник игрока, можно легко понять, находится ли он в онлайне или нет, так, чтобы этот игрок об этом не узнал. Главное — просто вести актуальный список ГМов и перебирать их в бесконечном цикле со специального аккаунта.


                    Инстансы не создаются динамически и преград для доступа ГМов в инстансы нет.

                    Тем не менее, инстансы защищают от случайных прохожих, могущих зарепортить ботов.


                  1. KsamD
                    09.01.2018 20:42

                    Корея сильно отличается по менталитету гейминга от наших.
                    Они воют чутли не по договоренности, члены (боты в том числе) воющих кланов могут стоять на соседних полянах и еще мирно в чатике переписываться, наши с поляны выпрут любого исходя из принципа потому что могут), трейн не опытного ботовода разденут до гола и репортить не будут, если мозгов боту не добавят еще раз придет и оберет как липку.
                    P.S. NCSoft (как и сами видимо корейские игроки) ботов проблемой у себя не считают, соответственно плевали они и на защиту, что у себя, что на евро, что руоффе (локализатор ковырялся сам вроде всегда), отсюда и DLL-injection как вершина ботовского софта для линейки упомянутая товарищем DistortNeo ниже


                    1. DistortNeo
                      09.01.2018 21:27

                      > отсюда и DLL-injection как вершина ботовского софта

                      Скорее, имел место компромисс между уровнем зондирования и недовольством пользователей. Например, местный Frost банил игроков просто за сам факт наличия на жёстком диске бота. Для США/Европы такое немыслимо, поэтому GameGuard работал довольно мягко, просто не давая играть при определённых условиях

                      А ещё в GameGuard есть белый список приложений, которым можно отправлять нажатия клавиш в окно игры. В этом список входят, например, драйверы клавиатур, Fraps и т.д. Не знаю, как сейчас, но раньше проверка была простая — по имени. То есть достаточно было переименовать AutoHotKey.exe в какой-то-там-panel.exe (от Logitech), и опа — всё работает.

                      И, кстати, в случае невозможности использования инъекции DLL решение все равно бы было — сетевой шлюз внутри виртуальной машины, который у системы защиты вообще не было бы никаких шансов обнаружить, кроме самого факта запущенной виртуальной машины.


                      1. KsamD
                        09.01.2018 22:06

                        А ещё в GameGuard есть белый список приложений, которым можно отправлять нажатия клавиш в окно игры. В этом список входят, например, драйверы клавиатур, Fraps и т.д. Не знаю, как сейчас, но раньше проверка была простая — по имени.

                        И первые ребята с не вошедшим в список софтом, для бинда кнопок/макросов для мышки улетали по первости в бан и штурмовали саппорт) было дело)


      1. KirEv
        09.01.2018 01:36

        когда впервые познакомился с Л2, я был на 1курсе КПИ, тогда были лишь первые хроники, и рейты на все х1, и когда старый сервер Duron 900Mhz падал, пол-дня игры коту под хвост, что очень многих раздражало, и многие играли чуть ли не сутками :)

        самый заядлых игроков — отчислили в первом семестре, я был не из заядлых, но в придачу еще и бухал, потому и меня отчислили )


    1. alexr64
      09.01.2018 11:35

      помню, на некоторых серверах L2, пользователи покупали шмотки, аден, аккаунты за реальные деньги :)

      На всех. Цена зависит от даты старта сервера.


  1. kpa6uu
    08.01.2018 21:14

    Интересная штука!
    Было бы круто, если бы нашлось время на разбор бота с внедрением в процесс игры.
    Обходы защит и прочие плюшки :)


    1. 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.


      1. kpa6uu
        11.01.2018 19:23

        Интересно, спасибо!
        Будет круто увидеть это в виде сочного, жирного поста. Если будет желание и время.


  1. Naglec
    08.01.2018 21:29

    Как это сочетается, например, с Фростом и 4геем?


    1. KsamD
      08.01.2018 22:48

      бот явно писался не для L2 Classic, там явно требуется учесть и предугадать больше вариантов развития событий, весьма агрессивного «ареала обитания».
      P.S. для полностью автономного существования

      а Фрост кликеры и не палил, процесс clicker.exe переименовал в neygadal.exe на этом хак закончен


      1. Naglec
        08.01.2018 22:49

        Ну, в классике и нет кат, для которых этот бот и подходит :)


        1. KsamD
          08.01.2018 23:23

          есть места где появление мобов ограничено пятачком, + некоторые локации аля Forgotten Temple под Глудином, разбитое на комнаты.
          для ботовода 2 правила:
          1. правильное место)
          2. тихое место)


          1. IamNoExist
            09.01.2018 11:47

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


          1. alexr64
            09.01.2018 12:03

            Для ботовода могу выделить несколько правил:
            1) Не играть.
            2) Ваших чаров забанят. Когда — вопрос времени, к этому нужно быть готовым.
            3) Не пастись в одной локации.


        1. NullaCham
          09.01.2018 10:11

          Как это в классике нет кат? Прекрасные 60+ каты под ХВ :)


    1. maxeem Автор
      08.01.2018 22:52

      Я писал бота для Interlude, т.к. мне доводилось играть только на этих хрониках. Хроники на актуальных серверах давно ушли вперед.


  1. GoldAfonya
    08.01.2018 22:11

    Классная статья по старой доброй игре :) Интересно было прочитать, когда ни будь надеюсь повторить.


  1. forcam
    08.01.2018 23:51

    Знавал пару ботоводов, не знаю на сколько правда но в зависимости от сервера, обмундирования и противодействия зарабатывали от 500 до 1500$. Поэтому не такая уж и забава) подруга с Украины многие годы только так и зарабвтывала (с ее слов), нигде больше не работая. А по теме, ваш бот легко спалит админ поставив вдалеке мобов 80ур., впрочем это самый распространенный способ обнаружения, но т.к. мобы эти бордово-крассные, то конечно с этим не сложно бороться. Еще обычно смотрят по поведению, если оно прямо как у робота, то конечно будет бан, возможно даже перманентный. Вообще как задрот ла2 могу с уверенностью сказать, если делать избыточно-рандомные действия (ходить не по прямой, а свариациями, изменять угол смотрения камеры, не замирать на месте, а делать все как бы потоково, но не быстрее человека) — спалить очень сложно, потому что тогда отличить будет ну очень сложно, игроки там бегают почти всегда одинаково и делают это часами. Встречал такого бота когда еще играл на РуОфе, мне 15 минут понадобилось что бы понять, что это бот) кто-то подошел реально творчески к процессу, а конда я его пытался под мобами станить, что бы они его убивали, у него срабастывал авторелог, а если совсем все плохо было, то просто бсое :)


    1. Naglec
      09.01.2018 14:53

      Зарабатывать надо на продаже бота :)


      1. zartarn
        09.01.2018 15:05

        Сложно конкурировать с Адреналином :). Даже пока наращиваешь возможности, очень сложно демпинговать будет.


        1. KsamD
          09.01.2018 20:52

          Адреналин не просто софтина, а уже целый сервис с поддержкой, там грамотно все сделали, качество не проверял, но сам подход :)
          Крупные кланы обычно пользуются приватным софтом, настраиваемый под задачи, там такой человек на окладе сидит), к тому же все конвертируемое в вечно зеленые в их руках, сам бог велел как говорится, доход одинокого ботовода не сравнится с Топами, но в зависимости от периода развития игры на икру хватит


  1. Tihon_V
    09.01.2018 00:27

    На просторах интернета был найден способ решения проблемы: usb-устройство, которое можно запрограммировать на подачу нужного сигнала — Digispark.

    Есть ещё USBIP. И пример эмулятора HID-устройства к нему.
    Ещё можно реализовывать через отправку комманд Bluetooth HID и двух адаптеров версии от 2.0 :)


  1. isnofreedom
    09.01.2018 01:31

    В своё время не вылезал из l2. Ночи в катах, мамон… Ностальгия напала. :'0


  1. doom369
    09.01.2018 02:04

    В новой «линейке» Revolution разработчики полностью решили проблему ботов. Теперь там есть кнопка «автофарм» :).


    1. forcam
      09.01.2018 03:44

      ну есть Lineage ll classik, ну и куча фришек, где еще очень долго не будет этого обновления, на многих определенно никогда) а вообще фарм это конвертация твоего времени в ценности, поэтому теперь все решает только толщина кошелька, ла2 закатилась туда где решают только деньги, поэтому хочешь старую ламповую, либо на фриху, либо забивать, даже на руофе, на классике ввели магаз, хотя били пяткой в гпудь что не бывать этому никогда, короче и там видимо темная сторона все заруинит :( а раньше, это был несомненный шедевр, ни одна игра не приносила такое море эмоций…


      1. Tsimur_S
        09.01.2018 14:29

        lineage 2 revolution это не обновление а отдельная мобильная гриндилка не имеющая отношения к традиционной ла2, классику и фришкам(ну может кроме лора).


      1. sulla
        09.01.2018 16:16

        хорошо, что это «дедушки» не видели, которые до сих пор в Ultima Online играют :)
        и скрипты пишут под неё


  1. KMiNT21
    09.01.2018 02:30

    А я не так давно для FIFA 18 делал бота, который сам по ночам просто матчи запускал (результат там не важен) для фарминга монет.

    Тоже на Python (+ PyQT для удобства). Использовал OpenCV для анализа того, что ImageGrab «скринил». Пришлось сделать много скриншотов, из которых я удалял лишнее (делал прозрачным) и оставлял только то, что точно идентифицирует наше «состояние».

    Пытался сделать так, чтобы работало со свернутым окном — никак. :) Не придумал вообще как можно получить снимок неактивного DirectX приложения (и можно ли вообще). Да и клавиши все равно слать надо… Проще уже в виртуалке, если тянет.

    Ну а так работало все. Запустил, Alt+Enter, нажал «Start» боту, и погнало до утра играть. :)


    1. VagabundSketch
      09.01.2018 21:26

      Если есть свободный VGA порт, в windows можно добавить виртуальный монитор как описано здесь: superuser.com/questions/62051/is-there-a-way-to-fake-a-dual-second-monitor#796884.


  1. Areso
    09.01.2018 09:39

    Делал хардварный кликер. Нужна серва и ардуинка.
    Серву к клавиатуре крепил двумя саморезами.
    github.com/Areso/Arduino-clicker


    1. vvzvlad
      10.01.2018 02:30

      Припаять провод к контакту кнопки? Нет. Саморезы!


      1. Areso
        10.01.2018 12:42

        Безотносительно к ботам для ла2: ничто так не эмулирует аппаратный дребезг ключа, как аппаратный дребезг ключа (на правах шутки). Зато обеспечивает небольшой, но настоящий хардварный рандом при нажатии.


  1. DSLow
    09.01.2018 09:58

    Если в локации будут другие белые имена помимо мобов? NPC/Игроки.

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


    1. edge790
      09.01.2018 18:04

      Как я понял, при наведении мыши мобы иначе подсвечиваются (например красным)


      Теперь наводим курсор на найденного монстра и смотрим, появилась ли подсветка с помощью метода


      1. alexr64
        09.01.2018 18:19

        при наведении мыши мобы иначе подсвечиваются

        Нет. А вот как я понял — проверки на «моб — чар» просто нет. Потому первый же чар (по правилам игры, чаров с белым ником атаковать без зажатого Ctrl нельзя) уведет бота куда угодно (атака в «белого», на игровом сленге «не флагнутого» — не перешедшего в пвп режим (тогда ник чара розовеет), работает как атака в NPC: начать диалог).


    1. vladimirboiko
      09.01.2018 23:13

      Было написано про НПС, проверяется отклик при наведении, если он «правильный», то кликается левая кнопка мыши и идет атака, если же он «неправильный» то выбирается следующая цель.… Интересный актокликер, мне понравилась как логика реализации так и сама реализация, классненько, я когда-то делал кликер для пв, там было тоже не очень просто реализовать все эти логические комбинации, решил проблему почти также :)


  1. DistortNeo
    09.01.2018 17:06

    Аж передёрнуло от темы. В своё время (~10 лет назад) играл на еврооффе, и тоже писал своего бота. Причём писал тоже по-серьёзному: с кусей пользователей, сервером обновления бота. Собственно, для меня это был первый серьёзный проект, которых неплохо подтянул скилл программирования.

    Важный момент: система защиты на офсерверах (GameGuard) обходилась с полпинка, за ботами особо не следили, поэтому я работал непосредственно на уровне сетевого протокола.

    Ну и алгоритмы старался делать интересные:
    — глобальную навигацию: бот сам может добежать в точку с произвольными координатами, используя при необходимости телепорты, без необходимости задания вэйпоинтов (удобно для второоконного баффера, чтобы не переключаться на него);
    — обмен информацией между персонажами для оффпати режимов;
    — важной составляющей является активный багоюз, но это уже отдельная тема для разговора.

    Немного жалею, что в те времена ещё не было средств разработки, которые доступны сейчас — сделал бы гораздо больше всего интересного. Дико не хватало асинхронного программирования. Ну и сейчас я бы попробовал использовать не захардкоженные алгоритмы, а ИИ для более правдоподобных действий ботов.


  1. Crystal_HMR
    09.01.2018 17:25

    Ждем следующую статью про самообучающегося бота на нейросетях


  1. edge790
    09.01.2018 18:02

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

    Мое предположение, что автокликеры используют WinApi для кликов/хоткеев, а игра использует DirectInput


    1. DistortNeo
      09.01.2018 18:58
      +1

      > Мое предположение, что автокликеры используют WinApi для кликов/хоткеев, а игра использует DirectInput

      Именно так. Фильтр кликов внутри игры я делал, перехватывая соответствующие функции.


  1. Keinael
    09.01.2018 21:29

    Спасибо большое автору за эту чудесную статью) После просмотра видео подхватил ностальгию) Жаль только звуков нет в видосике ;( Теперь вот сегодня — завтра сам пойду катать, правда в HF. Заведу себе гномку — рабыню, которая круглосуточно будет фармить каты xD


  1. danzalux
    09.01.2018 21:31

    В юности какой-то кусок времени игрался в Silkroad где-то до 2008го года со всеми вытекающими систем free2p(l)ay — донаты, боты… Был отличный хак"testosterone" от товарища Rumata с небольшим изменением в клиенте, так же был слегка кАличный, но работающий TBot, который как-то навешивал хуки и пропускал через себя трафик игры, как через прокси, анализируя входные и добавляя команды на движения в выходные данные…
    Может кто помнит?


  1. public_static__void
    09.01.2018 23:12

    В классе 9м наткнулся на одну статью, где с помощью С и малых манипуляций с оджидебагером и ассемблером, было предложено сделать что то типа «робота для 3й GTA»
    все делалось только работая с памятью.
    Игра запускалась на виртуальной машине, и простор для фантазии был практически безграничен, правда обратной связи от игры получить я так и не смог.
    Вот сейчас задумался попробовать сделать что ни будь подобное и с современными играми


  1. Larrikin
    10.01.2018 12:22

    Этот алгоритм поиска моба думаю стоит применять после того, как перестанут выделяться мобы по /targetnext


    1. alexr64
      10.01.2018 12:40

      Первый же флагнутый чар — ваш. Мобы за стенкой — тоже ваши.


  1. Karakhan
    11.01.2018 10:42

    Давненько в Линейку не играл, но если мне не изменяет память, по умолчанию на TAB’е висит перебор целей, видимых на экране. Название и ХП текущей цели отображаются в прямоугольнике в верхней части экрана. Не проще ли работать с этим таргетным прямоугольником, а не со всем экраном?


    1. alexr64
      11.01.2018 13:04

      по умолчанию на TAB’е висит...

      инвентарь.


  1. Slysar7
    11.01.2018 10:42

    Не играл в линейку, но… почитал алгоритм бота:
    Если монстр жив, продолжаем атаковать
    Если нет цели, найти цель и начать атаковать
    Если не удалось найти цель, немного повернемся
    Если 5 раз никого не удалось найти — идём в сторону и начинаем заново

    Пока он ищет цель и вертится его не убьют?


    1. KsamD
      12.01.2018 00:55

      у каждого монстра есть так называемое время респа(с момента убийства до возрождения) и координаты респа (в данном случае в пределах комнаты)
      Самое сложное зачистить комнату, когда все монстры уже появились(на игрока налетает вся толпа), делается как правило в ручную
      цели убиваются поочередно,
      из этого следует что и появляются они по очереди, а не толпой после зачистки комнаты
      главное рассчитать время убийства моба с временем респа и вуаля)


  1. 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

    Естественно, скорость реакции и действий в случае пвп оставляли бы желать лучшего, но соль-то не в них.


  1. vladimir87
    11.01.2018 10:42

    у меня так, в свое время, пару десятков pvp за ночь бот нарубил