0

我正在为在线动态游戏创建机器人。在这种情况下,动态意味着游戏中的英雄可以四处移动,并且在移动时背景会发生变化。像这样的全局变量monsters在移动时也会动态变化。

我的机器人正在使用 puppeteer。因为我需要这个怪物对象,所以我有每 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 可以实现的最快的。第三个功能与此相同,但另外过滤了我想避免的特殊怪物。

现在我的问题是:

  • 有没有办法在每个 this 对象上获取这个对象并且只有这个对象改变?我知道 puppeteer 中有可以监视 DOM 更改的功能,但是有什么可以监视全局窗口对象吗?
  • 我还能做些什么来加快速度吗?我在 NodeJS 中读到过worker_threads,它可以帮助摆脱这种微滞后或其他什么吗?聚类?
4

1 回答 1

0

一段时间后我意识到机器人“落后”了,因为我将这个巨大的g.npc数组作为参数传递给函数。我的意思是我正在解决它getAllNpc,然后将它传递给filterMonsters.

当我更改它时,我.filtergetAllNpc页面上下文中执行内部评估脚本,然后解析和传递具有数亿而不是数百万元素的数组,它更快并且不会导致任何滞后或冻结。

于 2019-08-03T11:56:11.040 回答