我正在为在线动态游戏创建机器人。在这种情况下,动态意味着游戏中的英雄可以四处移动,并且在移动时背景会发生变化。像这样的全局变量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
,它可以帮助摆脱这种微滞后或其他什么吗?聚类?