diff --git a/async-bot.py b/async-bot.py index 8d1798a..7fbd273 100644 --- a/async-bot.py +++ b/async-bot.py @@ -5,7 +5,7 @@ from aiohttp import ClientSession from aiohttp_socks import ProxyConnector from PIL import Image, ImageFont, ImageDraw, ImageFilter, ImageSequence, ImageChops from base64 import b64decode -from random import choice +from random import choice, randint from json import load from time import time as time_now @@ -33,6 +33,8 @@ class AsyncBotManager: self._read_boxes = 0 self._last_printout = time_now() + self._active: set[int] = set() + @staticmethod def get_text_image(text: str, font: ImageFont.ImageFont | ImageFont.FreeTypeFont) -> Image.Image: left, top, right, bottom = font.getbbox(text) @@ -155,12 +157,26 @@ class AsyncBotManager: else: print("unknown event", event, data) now = time_now() - if (now - self._last_printout) > 1: + if (now - self._last_printout) > 10: outgoing = self._written_boxes / (now - self._last_printout) incoming = self._read_boxes / (now - self._last_printout) + print() print(f"Incoming: {incoming:7.2f}/s Outgoing: {outgoing:7.2f}/s") + print(f"Alive workers: {len(self._active)}") + + n_correct, n_wrong = 0, 0 + for index, expected in self.difference.items(): + y, x = divmod(index, 1000) + actual = self.canvas.getpixel((x, y)) > 0 # type: ignore + if expected != actual: + n_wrong += 1 + else: + n_correct += 1 + + print(f"Invalid: {n_wrong:4d} Valid: {n_correct:4d}") self._written_boxes = 0 self._read_boxes = 0 + self._active.clear() self._last_printout = now for pixmaps, spf in self.animations: frame_index = int(now / spf) @@ -182,10 +198,12 @@ class AsyncBotManager: async with ClientSession(connector=proxy) as http: async with AsyncSimpleClient(http_session=http) as sio: await sio.connect(f"{self.base}/socket.io") + offset = randint(0, 1000000) while not self._shutdown: diff = list(self.difference.items()) for _ in range(100): - index, expected = choice(diff) + index, expected = diff[offset % len(diff)] + offset += randint(0, 100) y, x = divmod(index, 1000) current = self.canvas.getpixel((x, y)) > 0 # type: ignore if current != expected: @@ -194,7 +212,8 @@ class AsyncBotManager: await sio.emit("toggle_bit", {"index": index}) await asyncio.sleep(delay) break - await asyncio.sleep(0.1) + self._active.add(bot_index) + await asyncio.sleep(0.01) async def __aenter__(self): self._listener_task = asyncio.create_task(self.listener()) @@ -215,10 +234,12 @@ async def amain() -> None: mgr.add_avoid_rect( avoid["x"], avoid["y"], avoid["w"], avoid["h"] ) + print("AVOID rectangle {w}x{h}+{x}+{y}".format(**avoid)) elif avoid["type"] == "range": mgr.add_avoid_range( avoid["start"], avoid["stop"], avoid.get("step", 1) ) + print("AVOID range {start}-{stop}".format(**avoid)) elif avoid["type"] == "image": with Image.open(avoid["path"]).convert("LA") as im: assert im.width == 1000 and im.height == 1000 @@ -227,9 +248,12 @@ async def amain() -> None: l, a = im.getpixel((x, y)) # type: ignore if a > 128: mgr.add_avoid_index(x + y * 1000) + print("AVOID image", avoid["path"]) + for elem in settings["elements"]: if elem["type"] == "text": mgr.put_text(elem["x"], elem["y"], elem["text"], elem.get("font", "default"), elem.get("size", 8)) + print("ADD text", elem["x"], elem["y"], elem["text"]) elif elem["type"] == "text_anim": frames: list[Image.Image] = [] for text in elem["lines"]: diff --git a/settings.json b/settings.json index 79b905e..b985155 100644 --- a/settings.json +++ b/settings.json @@ -13,14 +13,6 @@ "h": 10, "description": "Not ruining fun for normal users" }, - { - "type": "rect", - "x": 732, - "y": 184, - "w": 231, - "h": 326, - "description": "The Bald Critic" - }, { "type": "rect", "x": 0, @@ -47,56 +39,20 @@ "type": "image", "path": "./avoid_masks/noita.png", "description": "Noita logo by Cr4xy" - }, - { - "type": "image", - "path": "./avoid_masks/fnf.png", - "description": "FNF by vshab" } ], "elements": [ - { - "type": "rgb111", - "path": "./pictures/trans.png", - "x": 200, - "y": 200 - }, - { - "type": "image", - "path": "./pictures/kangel.png", - "x": 256, - "y": 360 - }, - { - "type": "image", - "path": "./pictures/boykisser.png", - "x": 69, - "y": 420 - }, - { - "type": "image", - "path": "./pictures/colon3.png", - "x": 333, - "y": 333 - }, - { - "type": "animation", - "path": "./pictures/neko.gif", - "x": 263, - "y": 225, - "spf": 5 - }, { "type": "image", "path": "./pictures/casey.png", - "x": 256, - "y": 256 + "x": 32, + "y": 420 }, { "type": "rgb565", "path": "./pictures/niko.png", "x": 48, - "y": 12 + "y": 48 } ] } diff --git a/stream-from-stdin.py b/stream-from-stdin.py new file mode 100644 index 0000000..ade97f6 --- /dev/null +++ b/stream-from-stdin.py @@ -0,0 +1,36 @@ +# x-run: cat _junk/logs.txt | python3 % + +from base64 import b64decode +from sys import stdout, stdin, stderr +from json import loads + +canvas = bytearray(125000) + +last_update: int = 0 +last_frame: int = 0 + +n_frames = 0 + +for line in stdin: + _, data = line.strip().split(" ", 1) + event, data = loads(data) + + if event == "full_state": + buffer = b64decode(data["full_state"].encode() + b"=") + last_update = data["timestamp"] + canvas[:] = buffer + elif event == "batched_bit_toggles": + bits_on, bits_off, timestamp = data + if timestamp >= last_update: + for ndx in bits_on: + byte, bit = divmod(ndx, 8) + canvas[byte] |= (1 << bit) + for ndx in bits_off: + byte, bit = divmod(ndx, 8) + canvas[byte] &= 0xFF ^ (1 << bit) + last_update = timestamp + + if (last_update - last_frame) > 6_000: + stdout.buffer.write(canvas) + stdout.buffer.flush() + last_frame = last_update