Давным давно, еще в те времена когда на персональных компьютерах жил MsDOS довелось играть в игру Settlers II. Игра меня тронула, и я с удовольствием провел наедине с ней несколько дней. Много позже прошел ее повторно, а затем и еще раз, и каждый раз несмотря на древность этой игры с удовольствием проводил время играя в нее. Не так давно увидел рекламу онлайн игры The Settlers Online и поддавшись ностальгии зарегистрировался в ней. Первым впечатлением был восторг, настолько все было похоже на полюбившееся мне Settlers II. Но радужная эйфория быстро прошла. Я не буду рассказывать в этой статье о всех плюсах и минусах, расскажу только об одном минусе — торговле. О самой игре более подробно вы можете прочитать в статье The Settlers: теперь Online.
Торговля в игре реализована так, что требует постоянного присутствия. Любой торговый лот выставляется всего на 10 минут, а затем становится недоступен для других игроков. Как следствие, для того что-бы торговля принесла хоть сколько нибудь ощутимую прибыль необходимо провести в торговом интерфейсе не один час.
Так и родилась идея написать бота который будет выставлять лот автоматически.
Так как на моем десктопе установлен Linux, в качестве инструментов разработки был выбран язык программирования Perl, и утилита управления курсором мыши xdotool.
И так приступим.
бот будет состоять из 2-х файлов:
Начнем с файла trade.guns.pl. В этом файле содержится список HASH (именованных) массивов содержащих координаты кнопок которые необходимо нажать чтобы выставить лот, и другую дополнительную информацию.
В более детальном описании помимо того что дано в комментариях данный файл не нуждается. Поэтому приступим к рассмотрению simple.trade.bot.pl. Это и есть сам бот.
Бот готов.
Данный бот очень простой. Он пока еще не имеет множество необходимых возможностей. Вот краткий список идей как сделать бота более совершенным:
Причина
Торговля в игре реализована так, что требует постоянного присутствия. Любой торговый лот выставляется всего на 10 минут, а затем становится недоступен для других игроков. Как следствие, для того что-бы торговля принесла хоть сколько нибудь ощутимую прибыль необходимо провести в торговом интерфейсе не один час.
Следствие
Так и родилась идея написать бота который будет выставлять лот автоматически.
Пишем бота
Так как на моем десктопе установлен Linux, в качестве инструментов разработки был выбран язык программирования Perl, и утилита управления курсором мыши xdotool.
И так приступим.
бот будет состоять из 2-х файлов:
- simple.trade.bot.pl — непосредственно сам бот.
- trade.guns.pl — файл с координатами кнопок и дополнительными данными для торговли выбранным товаром (в моем случае это были пушки продаваемые за футбольные мячи).
Начнем с файла trade.guns.pl. В этом файле содержится список HASH (именованных) массивов содержащих координаты кнопок которые необходимо нажать чтобы выставить лот, и другую дополнительную информацию.
( { x=>'288', y=>'852'}, # Кнопка [добавить]. Инициирует интерфейс выставления торгового лота { x=>'790', y=>'667'}, # Кнопка [выбрать]. Интерфейс выбора продаваемого товара. { x=>'1126', y=>'658'}, # Кнопка [искусные]. Выбор категории продаваемого товара. { x=>'871', y=>'594'}, # Кнопка [пушки]. Непосредственно выбор самого товара. { # Действия с бегунком выставляющим количество продаваемого товара. # Приведенные ниже данные соответствуют 100 единицам товара. # По умолчанию выставляется 400 единиц. x=>'983', y=>'742', # Координаты нажатия ЛКМ. dx=>'874', dy=>'750', # Координаты отжатия ЛКМ. # Получаем 99 единиц. inc=>{ # Данный элемент содержит: x=>'1010', y=>'745', # Координаты кнопки увеличивающей значение бегунка на 1. inc=>'1', # На сколько увеличить значение бегунка. rnd=>'0', # Если не 0 то рандомное значение от 0 до rnd добавляется к inc. timer => [ # Содержит поправку цены в зависимости от времени суток. { sh=>0, eh=>24, inc=>0 } # В данном случае поправка равна 0 на весь день. ] } }, { x=>'1064', y=>'733', rx=>'20', ry=>'10'}, # Кнопка [ОК]. Завершает выбор товара для продажи. { x=>'1131', y=>'668', rx=>'10', ry=>'2'}, # Кнопка [выбрать]. Интерфейс выбора покупаемого товара. # Так как необходимый товар находится в категории по умолчанию # выбор категории опущен. { x=>'1016', y=>'548', rx=>'20', ry=>'10'}, # Кнопка [мячики]. Непосредственно выбор покупаемого товара. { # Действия с бегунком выставляющим количество покупаемого товара. # Приведенные ниже данные соответствуют 20 единицам товара + 0, 2, 4 или 8 в зависимости # от времени суток + рандомно от 0 до 15 . # По умолчанию выставляется 400 единиц. x=>'988', y=>'743', # Координаты нажатия ЛКМ. dx=>'804', dy=>'746', # Координаты отжатия ЛКМ. # Получаем 1 единицу. inc=>{ # Данный элемент содержит: x=>'1010', y=>'745', # Координаты кнопки увеличивающей значение бегунка на 1. inc=>'19', # На сколько увеличить значение бегунка. rnd=>'15', # Если не 0 то рандомное значение от 0 до rnd добавляется к inc. timer => [ # Содержит поправку цены в зависимости от времени суток. # Если поправок несколько - то каждая последующая обладает более высоким приоритетом. { sh=>0, eh=>24, inc=>0 },# 0 на весь день. { sh=>0, eh=>8, inc=>8 },# +8 c 00.00 до 08.00. { sh=>8, eh=>9, inc=>4 },# +4 c 08.00 до 09.00. { sh=>9, eh=>10, inc=>2 } # +2 c 09.00 до 10.00. ] } }, { x=>'1083', y=>'736', rx=>'20', ry=>'10' }, # Кнопка [ОК]. Завершает выбор товара для покупки. { x=>'961', y=>'596', rx=>'14', ry=>'12' } # Кнопка [применить]. Отправляет лот на торг. );
В более детальном описании помимо того что дано в комментариях данный файл не нуждается. Поэтому приступим к рассмотрению simple.trade.bot.pl. Это и есть сам бот.
#!/usr/bin/perl # После запуска скрипт дает пользователю 20 секунд для того чтобы он открыл окно с игрой и зашел в торговый интерфейс sleep 20; # Получаем список из файла с координатами в массив my @g_trade = do "trade.guns.pl"; # Далее главный цикл программы. Он бесконечен. # Для прерывания работы программы перейдите в консоль и нажмите [Ctrl]+c. while(){ # Пишем в консоль о постановке нового лота на торги. print "NEXT TRADE\n"; # Данный цикл последовательно проходит все элементы из массива с координатами. for my $l_cur ( @g_trade ){ sleep(1); if( defined $l_cur->{dx} ){ # Если в текущем элементе определен ключ dx значит данный элемент - оперирует бегунком # выставляющим колличество товара. # Расчитываем количество выставляемого товара ($l_count). # Добавляем статическую поправку к количеству товара. my $l_count=$l_cur->{inc}{inc}; # Получаем текущее время. В ячейке №2 - часы. my @l_curtime=localtime(time); # Перемещаем курсор в координаты x, y текущего элемента. move($l_cur); # Получаем поправку к цене зависящую от времени суток. my $l_inc=0; # Последовательно перебираем массив с поправками к цене. for my $l_timer ( @{$l_cur->{inc}{timer}} ){ # Если текущее время попадает в заданный интервал, запоминаеми поправку. $l_inc=$l_timer->{inc} if $l_curtime[2] >= $l_timer->{sh} && $l_curtime[2] <= $l_timer->{eh}; } # Расчитываем рандомную поправку к количеству товара. my $l_rnd=int(rand($l_cur->{inc}{rnd})); # Добавляем вычисленые поправки к общему количеству товара. $l_count+=$l_inc; $l_count+=$l_rnd; # Выводим в консоль данные о количестве товара и состовляющие из которых это количество складывается. print "\tSET: [$l_count] [$l_cur->{inc}{inc} + $l_up + $l_rnd\($l_cur->{inc}{rnd})]\n"; # Увеличеваем значение бегунка на величину поправки. while ($l_count){ $l_count--; clicktoxy($l_cur->{inc}); usleep(80); } }else{ # Если ключ dx не определен - значит это просто клик мыши по заданным в текущем елементе координатам. clicktoxy($l_cur); } } # Лот выставлен. Ожидаем 11 минут + рандомно от 0 до 4 минут (человек ведь никогда не ставит лот секунда в секунду). my $l_time=11+int(rand(4)); my $count=0; # По прошествии каждой минуты пошевеливаем курсором мыши чтобы система не уснула. for($count=0;$count<$l_time;$count++){ sleep 60; mousemove(400,500); sleep 1; mousemove(1400,500); sleep 1; } # Ждем еще рандомное количество секунд от 0 до 60 sleep(int(rand(60))); # Цикл возвращается в начало и выставляется новый лот } sub usleep{ # Функция дает задержку в млилисекундах (Не работает в Ms Windows). my $l_ptr=shift; $l_ptr*=1000; `usleep $l_ptr`; } sub move{ # Функция принимает текущий элемент и перемещает курсор мыши по заданным в элементе координатам. my $l_coord=shift; mousemove($l_coord->{x},$l_coord->{y}); mousedown(1); usleep(600); mousemove($l_coord->{dx},$l_coord->{dy}); mouseup(1); } sub click{ # Функция производит клик ЛКМ в текущей позиции курсора. mousedown(1); mouseup(1); } sub clicktoxy{ # Функция принимает текущий элемент, перемещает курсор мыши по заданным в элементе координатам # и производит клик ЛКМ. my $l_coord=shift; mousemove($l_coord->{x},$l_coord->{y}); mousedown(1); mouseup(1); usleep(300); } sub mousedown{ # Функция отдает команду утилите xdotool имитировать нажатие кнопки мыши. # Принимает значения: # 1 - левая кнопка мыши (ЛКМ) # 2 - правая кнопка мыши (ПКМ) my $l_key = shift; if( $l_key ){ `xdotool mousedown $l_key`; } } sub mouseup{ # Функция отдает команду утилите xdotool имитировать отжатие кнопки мыши. # Принимает значения: # 1 - левая кнопка мыши (ЛКМ) # 2 - правая кнопка мыши (ПКМ) my $l_key = shift; if( $l_key ){ `xdotool mouseup $l_key`; } } sub mousemove{ # Функция отдает команду утилите xdotool переместить курсор мыши по координатам x, y. my $l_x = shift; my $l_y = shift; my $l_com='xdotool mousemove'; $l_com.=" $l_x $l_y"; `$l_com`; }
Бот готов.
В завершение
Данный бот очень простой. Он пока еще не имеет множество необходимых возможностей. Вот краткий список идей как сделать бота более совершенным:
- Научить бота видеть с экрана. Для этого можно использовать ImageMagick.
- Научить бота настраиваться под разные разрешения экрана и разные браузеры. Поиск границ и кнопок с помощью утилиты compare из состава ImageMagick.
- Научить бота читать с экрана. Для этого можно использовать ImageMagick + gocr.
- Научить бота принимать сделки. Но так как в игре практикуется передача обманных сделок — бот прежде чем принять сделку должен ее проверить. Для этого можно использовать ImageMagick + gocr.
- Научить бота знать заранее все лоты выставленные в торговом интерфейсе. Лоты передаются браузеру в открытом виде как XML. Для перехвата можно использовать perl модуль Net::Pcap. Для поиска в торговом интерфейсе выбранного на этапе перехвата пакетов товара можно использовать ImageMagick + gocr.
Следует учесть
- Данный бот написан под Linux. Для того чтобы заставить его работать под Ms Windows необходимо использовать вместо xdotool аналог для Ms Windows. Возможно подойдет утилита autoit. Также в Ms Windows необходимо будет установить Perl.
- Файл с координатами trade.guns.pl рассчитан на конкретный товар (100 пушек меняем на 20 — 34 мяча), на мое разрешение экрана и мой браузер. Для использования бота вам нужно будет вычислить свои координаты кнопок.
- По установленным в игре правилам за использование даже такого простого бота наказание бан без права восстановления. пункт 6.4.
