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:
parent
26e8b804ee
commit
c286990f75
32
async-bot.py
32
async-bot.py
|
@ -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"]:
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
Loading…
Reference in New Issue