Probably last commit

Added more stats, created streamer from logs file to retroactively make
timelapses, removed most of images off of the board.
This commit is contained in:
Casey 2024-07-07 10:17:53 +03:00
parent 26e8b804ee
commit c286990f75
Signed by: hkc
GPG Key ID: F0F6CFE11CDB0960
3 changed files with 67 additions and 51 deletions

View File

@ -5,7 +5,7 @@ from aiohttp import ClientSession
from aiohttp_socks import ProxyConnector from aiohttp_socks import ProxyConnector
from PIL import Image, ImageFont, ImageDraw, ImageFilter, ImageSequence, ImageChops from PIL import Image, ImageFont, ImageDraw, ImageFilter, ImageSequence, ImageChops
from base64 import b64decode from base64 import b64decode
from random import choice from random import choice, randint
from json import load from json import load
from time import time as time_now from time import time as time_now
@ -33,6 +33,8 @@ class AsyncBotManager:
self._read_boxes = 0 self._read_boxes = 0
self._last_printout = time_now() self._last_printout = time_now()
self._active: set[int] = set()
@staticmethod @staticmethod
def get_text_image(text: str, font: ImageFont.ImageFont | ImageFont.FreeTypeFont) -> Image.Image: def get_text_image(text: str, font: ImageFont.ImageFont | ImageFont.FreeTypeFont) -> Image.Image:
left, top, right, bottom = font.getbbox(text) left, top, right, bottom = font.getbbox(text)
@ -155,12 +157,26 @@ class AsyncBotManager:
else: else:
print("unknown event", event, data) print("unknown event", event, data)
now = time_now() now = time_now()
if (now - self._last_printout) > 1: if (now - self._last_printout) > 10:
outgoing = self._written_boxes / (now - self._last_printout) outgoing = self._written_boxes / (now - self._last_printout)
incoming = self._read_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"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._written_boxes = 0
self._read_boxes = 0 self._read_boxes = 0
self._active.clear()
self._last_printout = now self._last_printout = now
for pixmaps, spf in self.animations: for pixmaps, spf in self.animations:
frame_index = int(now / spf) frame_index = int(now / spf)
@ -182,10 +198,12 @@ class AsyncBotManager:
async with ClientSession(connector=proxy) as http: async with ClientSession(connector=proxy) as http:
async with AsyncSimpleClient(http_session=http) as sio: async with AsyncSimpleClient(http_session=http) as sio:
await sio.connect(f"{self.base}/socket.io") await sio.connect(f"{self.base}/socket.io")
offset = randint(0, 1000000)
while not self._shutdown: while not self._shutdown:
diff = list(self.difference.items()) diff = list(self.difference.items())
for _ in range(100): for _ in range(100):
index, expected = choice(diff) index, expected = diff[offset % len(diff)]
offset += randint(0, 100)
y, x = divmod(index, 1000) y, x = divmod(index, 1000)
current = self.canvas.getpixel((x, y)) > 0 # type: ignore current = self.canvas.getpixel((x, y)) > 0 # type: ignore
if current != expected: if current != expected:
@ -194,7 +212,8 @@ class AsyncBotManager:
await sio.emit("toggle_bit", {"index": index}) await sio.emit("toggle_bit", {"index": index})
await asyncio.sleep(delay) await asyncio.sleep(delay)
break break
await asyncio.sleep(0.1) self._active.add(bot_index)
await asyncio.sleep(0.01)
async def __aenter__(self): async def __aenter__(self):
self._listener_task = asyncio.create_task(self.listener()) self._listener_task = asyncio.create_task(self.listener())
@ -215,10 +234,12 @@ async def amain() -> None:
mgr.add_avoid_rect( mgr.add_avoid_rect(
avoid["x"], avoid["y"], avoid["w"], avoid["h"] avoid["x"], avoid["y"], avoid["w"], avoid["h"]
) )
print("AVOID rectangle {w}x{h}+{x}+{y}".format(**avoid))
elif avoid["type"] == "range": elif avoid["type"] == "range":
mgr.add_avoid_range( mgr.add_avoid_range(
avoid["start"], avoid["stop"], avoid.get("step", 1) avoid["start"], avoid["stop"], avoid.get("step", 1)
) )
print("AVOID range {start}-{stop}".format(**avoid))
elif avoid["type"] == "image": elif avoid["type"] == "image":
with Image.open(avoid["path"]).convert("LA") as im: with Image.open(avoid["path"]).convert("LA") as im:
assert im.width == 1000 and im.height == 1000 assert im.width == 1000 and im.height == 1000
@ -227,9 +248,12 @@ async def amain() -> None:
l, a = im.getpixel((x, y)) # type: ignore l, a = im.getpixel((x, y)) # type: ignore
if a > 128: if a > 128:
mgr.add_avoid_index(x + y * 1000) mgr.add_avoid_index(x + y * 1000)
print("AVOID image", avoid["path"])
for elem in settings["elements"]: for elem in settings["elements"]:
if elem["type"] == "text": if elem["type"] == "text":
mgr.put_text(elem["x"], elem["y"], elem["text"], elem.get("font", "default"), elem.get("size", 8)) 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": elif elem["type"] == "text_anim":
frames: list[Image.Image] = [] frames: list[Image.Image] = []
for text in elem["lines"]: for text in elem["lines"]:

View File

@ -13,14 +13,6 @@
"h": 10, "h": 10,
"description": "Not ruining fun for normal users" "description": "Not ruining fun for normal users"
}, },
{
"type": "rect",
"x": 732,
"y": 184,
"w": 231,
"h": 326,
"description": "The Bald Critic"
},
{ {
"type": "rect", "type": "rect",
"x": 0, "x": 0,
@ -47,56 +39,20 @@
"type": "image", "type": "image",
"path": "./avoid_masks/noita.png", "path": "./avoid_masks/noita.png",
"description": "Noita logo by Cr4xy" "description": "Noita logo by Cr4xy"
},
{
"type": "image",
"path": "./avoid_masks/fnf.png",
"description": "FNF by vshab"
} }
], ],
"elements": [ "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", "type": "image",
"path": "./pictures/casey.png", "path": "./pictures/casey.png",
"x": 256, "x": 32,
"y": 256 "y": 420
}, },
{ {
"type": "rgb565", "type": "rgb565",
"path": "./pictures/niko.png", "path": "./pictures/niko.png",
"x": 48, "x": 48,
"y": 12 "y": 48
} }
] ]
} }

36
stream-from-stdin.py Normal file
View File

@ -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