Пишем бота для онлайн-игры на JavaScript с применением AOP

в 13:40, , рубрики: Без рубрики

Пишем бота для онлайн игры на JavaScript с применением AOP
Если вы как и я любите онлайн игры, но не любите тратить на них сильно много времени, добро пожаловать под кат. Мы не будем обсуждать боты это хорошо или нет, а просто разберем как можно для конкретной онлайн игры сделать бота. Он будет не тупо клацать по кнопке по таймауту, а будет реагировать на события в браузере. Это мы сделаем с помощью Аспектно-ориентированного программирования (далее AOP). Для примера я выбрал полюбившуюся хабром игру Пернатск.

1. Готовим ингредиенты

Нам потребуются:

  • Собствена сама игра. Я буду показывать на примере Пернатска
  • Браузер. У меня все стандартно — Chrome
  • Текстовый редактор или в чем вы будете редактировать JS код. Notepad++ подойдет
  • Аккаунт для тестов, который не жалко будет потерять в результате бана

Важно! Игра должна работать в браузере, а не в клиенте. Причем не на Flash, а на HTML+JavaScript.
На выходе у нас должно получиться расширение для Chrome, которое будет играть вместо нас.

2. Делаем расширение

О том как делается расширение я не буду подробно расписывать. На хабре об этом уже писали, например, тут.
Приведу лишь коды, нужных нам файлов.
В manifest.json

{
  "name": "BOT for pernatsk",
  "version": "0.1",
  "manifest_version": 2,
  "content_scripts": [
    {
      "matches": [ "http://pernatsk.ru/*" ],
      "js": [ "background.js" ],
	  "run_at": "document_end"
    }
  ],
  "permissions": [
          "storage"
  ],
  "web_accessible_resources": [
    "/injected.js"
  ]
}

В строчке «matches»: [ «pernatsk.ru/*» ] вам нужно будет указать адрес вашей игры.
Файл background.js я использую для случаев, когда хочу инджектить на сайте свой JS кода. Собственно код background.js:

$.get(chrome.extension.getURL('/injected.js'), 
    function(data) {
        var script = document.createElement("script");
        script.setAttribute("type", "text/javascript");
        script.innerHTML = data;
        document.getElementsByTagName("head")[0].appendChild(script);
        document.getElementsByTagName("body")[0].setAttribute("onLoad", "ai_on();");
    }
);

Важно! Если вы не понимаете, что мы делаем в этой единственной функции, то делать бота вам пока рано. Почитайте основы JavaScript.
Вся работа у нас будет вестись в файле injected.js Его код пока такой:


function ai_on(){
        console.log("Hello world")
}

Все эти файлы сохраняем в одной папке bot.

3. Первый пуск бота

Заходим в Chomre в Настройки — Инструменты — Расширения, жмем на «Загрузить распакованное расширение». У вас должна быть стоять галочка на «Режим разработчика». Указываем папку с нашими файлами.
Теперь зайдем в нашу игру. Включим консоль разработчика (нам это придется делать часто) — жмем F12 и увидим «Hello Wolrd». Приложение заработало.
Теперь все, что мы пропишем в функции ai_on будет обрабатываться после загрузки страницы.

4. Добавляем AOP

Для работы бота нам потребуются библиотеки. Мой любимый jQuery уже используется на Пернатске, поэтому добавлять его не будет.
Добавим плагин AOP for Jquery. По хорошему это стоило запаковать в само расширение в виде отдельного файла, но я ленив. Поэтому просто добавим код bin/aop.pack.js первой строкой в наш injected.js.
Проверим, что это работает изменив ai_on


function ai_on(){
	bot = jQuery.aop.after( {target: window, method: '$'}, function(result){
		console.log('jQuery detected!');
		bot[0].unweave();
		return result;
	});
}

Проверяем, что AOP нормально подключилось. В консоле разработчика теперь будет строчка «jQuery detected!» Сообщение будет только один раз, так как я отключаю совет после первого же срабатывания.
Важно! Прочитайте документацию AOP for Jquery, чтобы понять jQuery.aop.after и bot[0].unweave().

5. Зачем мы будем использовать AOP

Суть AOP можно очень примерно выразить следующим образом: "После функции_1, надо сделать функция_2. Что это за функция_1 нас крайне мало волнует. Она отработала, значит надо должна отработь наша. Лезть в функцию_1 мы не будем." Еще раз повторюсь это очень примерно. Лучше прочитайте нормальное описание например тут
Как это использовать? Мы после любой функции можем запустить нашу. Например, в браузере отработала функция о том, что в зоне видимости появился монстр. Запускаем функцию напасть на него, которую мы уже написали сами.

6. Учим бота первой команде

В injected.js добавим такой код:


var commands = {
	conessearch:function(){
		if( window.location.pathname != "/location/conessearch") {
			window.location.pathname = "/location/conessearch";
			return false;
		}
		var buttons = $('form').eq(0).find('button');
		for (var index = 0; index < buttons.length; ++index) {
			if(buttons.eq(index).css('display') == "inline-block") {
				buttons.eq(index).mouseenter();
				buttons.eq(index).click();
				return true;
			}
		}
		return false;		
	},	
}

По этой команде наша бот-птичка будет лететь в Пернатске за шишками. Код слегка мудренный, так как в Пернатске есть небольшая защита от ботов.
Когда вы будете писать свои команды я рекомендую сначала опробовать их работоспособность в console, а уже потом переносить код в редактор.
Чтобы протестировать и проверить работу нашей команды запустим в косноле код commands.conessearch() Все работает.

7. Ищем событие на которое должен реагировать бот

Тут есть два метода первый — анализируем код игры. Долго :(
Второй метод — воспользоваться AOP, и после всех функций, который срабатывали вывести в лог их имя. Потом выбрать нужные.
Меняем ai_on()


function ai_on(){
	bot = jQuery.aop.around( {target: window, method: ''}, function(invocation){
		console.log(invocation.method);
		return invocation.proceed();
	});
}

У нас пойдет много-много функция. Там будет $ от jQuery или стандартная setTimeout.
Работать с этим очень не удобно изменим код еще раз.


function ai_on(){
	fnList = [];
	bot = jQuery.aop.around( {target: window, method: ''}, function(invocation){
		var fnName = invocation.method.toString();
		if(fnList.indexOf(fnName) == -1) {
			console.log(fnName);
			fnList.push(fnName);			
		}
	});
}

Теперь у нас отражаются только те функции, которые еще не отображались. Их полный список мы храним в fnList.
После пары минут там будут такие варианты функции для прицепки ["clearInterval", "$", "setTimeout", "timerTick", "serverTimeUpdate", "getComputedStyle", "setInterval", "tutorialArr", "showQ", "showQc", "updateBirdData", "viz", "unviz", "weatherUpdate"]
Меняя target и регулярное выражение в method мы можем подобрать ту функцию, которая нам подойдет, чтобы к ней прицепиться. Для примера, я выбираю функцию weatherUpdate теперь каждый раз как будет меняться погода наша птичка будет лететь за шишками.

7. Учим бота реагировать на события

Мы снова меняем код функции ai_on()


function ai_on(){
	bot = jQuery.aop.after( {target: window, method: 'weatherUpdate'}, commands.conessearch());
}
function ai_off(){
	bot[0].unweave();
}

Функцияю ai_off нужна, чтобы через консоль выключить бота.

8. Направления для дальнейшего развития

Надеюсь данный материал был для вас полезен. Что можно делать еще?

  • Сделать включение выключение бота по кнопке. С помощью функций ai_on, ai_off
  • Сделать полноценного бота
  • Сделать расширение, работающим в любом браузере. Например, с помощью Kango
  • И так далее

Код ничего толком не делает, поэтому его не выкладываю.

Автор: galk_in

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js