Я создаю бота для динамической онлайн-игры. В этом случае динамический означает, что игра героя может перемещаться, и фон меняется при движении. Глобальные переменные, такие как monsters
, также изменяют динамику при движении.
Мой бот использует кукловода. Так как мне нужен этот объект монстров, у меня есть функция, которая получает этих монстров из контекста страницы каждые 2 - 3 секунды (рандомизирует для обнаружения).
Это решение далеко от совершенства. Два основных недостатка:
- Мой бот убивает монстра, и я хочу перейти к следующему, он все еще видит этого монстра, который был убит, потому что следующее обновление, например, через 1500 мс с того времени.
- Производительность получения монстров плохая.
Чтобы решить первый, я мог просто выполнить функцию, которая загружает монстров каждый раз после убийства одного. С другой стороны, второй даунсайд будет еще сильнее, потому что я сделаю гораздо больше, получая монстра, который уже медленный.
Все это касается второй проблемы - производительности. Вы можете спросить, откуда мне знать, что производительность плохая?
Когда герой движется, он относительно плавный, но когда загружаются монстры, я вижу микро-лаг, как часть остановки второго героя. Это действительно может быть 100 мс лага, но я могу видеть это человеческим глазом, и если я буду выполнять получение монстра чаще, это лаг будет становиться сильнее (чтобы быть ясным - лаг не будет длиннее, но чаще).
Загрузка объекта из глобального окна занимает много времени. Причина в том, что разработчики игр разработали его так, чтобы monsters
находились внутри большого объекта npc
, который содержит все, что находится на приборной панели, и содержит даже пустые элементы, поэтому общее количество этого npc
объекта находится между 100k-200k элементами. Я делаю много фильтров, чтобы получить окончательные данные монстров, которые меня волнуют.
Я покажу, как я на самом деле получаю этих монстров. Поэтому я выполняю 3 асинхронные функции:
const allNpc = await getAllNpc(page);
let monsters = await filterMonsters(page, allNpc, monstersToHunt);
monsters.hunt = await deleteAvoidedMonsters(page, monsters.hunt, monstersToOmit);
Первый getAllNpc
просто получить весь объект NPC (этот большой, который я упоминал выше)
return await page.evaluate(() => {
if(window.g) return g.npc;
});
вторая функция фильтра реальных монстров и монстров, которых я хочу убить из NPC:
return new Promise((resolve, reject) => {
const validNpc = allNpc.filter(el => !!el);
const allMonsters = validNpc.filter(e => e.lvl !== 0);
const names = new Set(monstersNames);
const huntMonsters = validNpc
.filter(it => names.has(it.nick))
.map(({ nick, x, y, grp, id }) => ({ nick, x, y, grp, id }));
resolve({all: allMonsters, hunt: huntMonsters});
});
Я использую Set
здесь, чтобы избавиться от алгоритмов O (n) / O (n ^ 2), и я думаю, что это быстрее всего я могу достичь с помощью JavaScript. Третья функция такая же, как эта, но дополнительно фильтрует специальных монстров, которых я хочу избежать.
Теперь мои вопросы:
- есть ли способ получить этот объект на каждом этом объекте, и только этот объект изменяется? Я знаю, что в кукловоде есть функция, которая может наблюдать за изменениями DOM, но есть ли что-то, чтобы наблюдать глобальный объект окна?
- Могу ли я сделать что-нибудь еще, чтобы ускорить его? Я читал о
worker_threads
в NodeJS, может ли это помочь избавиться от этой микро-задержки или чего-то еще? Кластеризация?