parent
4a7f633a28
commit
319da9746f
68
async-bot.py
68
async-bot.py
|
@ -1,5 +1,5 @@
|
|||
import asyncio
|
||||
from typing import NewType, Optional
|
||||
from typing import Callable, NewType, Optional
|
||||
from socketio import AsyncClient, AsyncSimpleClient
|
||||
from aiohttp import ClientSession
|
||||
from aiohttp_socks import ProxyConnector
|
||||
|
@ -8,6 +8,7 @@ from base64 import b64decode
|
|||
from random import choice, randint
|
||||
from json import load
|
||||
from time import time as time_now
|
||||
import datetime
|
||||
|
||||
|
||||
PixelMap = NewType("PixelMap", dict[int, bool])
|
||||
|
@ -29,6 +30,8 @@ class AsyncBotManager:
|
|||
self.avoid: set[int] = set()
|
||||
|
||||
self.animations: list[Animation] = []
|
||||
self.animation_functions: list[Callable[[], PixelMap]] = []
|
||||
|
||||
self._written_boxes = 0
|
||||
self._read_boxes = 0
|
||||
self._last_printout = time_now()
|
||||
|
@ -38,10 +41,11 @@ class AsyncBotManager:
|
|||
@staticmethod
|
||||
def get_text_image(text: str, font: ImageFont.ImageFont | ImageFont.FreeTypeFont) -> Image.Image:
|
||||
left, top, right, bottom = font.getbbox(text)
|
||||
with Image.new("LA", (int(right - left) + 4, int(bottom - top) + 4), 0) as im:
|
||||
with Image.new("LA", (int(right - left) + 4, int(bottom - top) + 8), 0) as im:
|
||||
draw = ImageDraw.Draw(im)
|
||||
draw.rectangle((0, 0, im.width, im.height), (0, 0))
|
||||
draw.text((left + 2, top + 2), text, font=font, fill=(255, 0))
|
||||
draw.text((left + 2, top + 2), text, font=font, fill=(255, 0),
|
||||
anchor="lt")
|
||||
|
||||
alpha = im.convert("L").filter(ImageFilter.MaxFilter(5))
|
||||
im.putalpha(alpha)
|
||||
|
@ -60,6 +64,17 @@ class AsyncBotManager:
|
|||
def put_text(self, x: int, y: int, text: str, font: str, size: int = 8):
|
||||
self.put_image(x, y, self.get_text_image(text, self.get_font(font, size)))
|
||||
|
||||
|
||||
def get_image_diff(self, ox: int, oy: int, im: Image.Image) -> PixelMap:
|
||||
pixmap = PixelMap({})
|
||||
for y in range(im.height):
|
||||
for x in range(im.width):
|
||||
l, a = im.getpixel((x, y)) # type: ignore
|
||||
index = x + ox + (y + oy) * 1000
|
||||
if a and index not in self.avoid:
|
||||
pixmap[index] = l > 0
|
||||
return pixmap
|
||||
|
||||
def put_image(self, ox: int, oy: int, im: Image.Image):
|
||||
for y in range(im.height):
|
||||
for x in range(im.width):
|
||||
|
@ -174,6 +189,10 @@ class AsyncBotManager:
|
|||
print(f"I/O: {incoming:7.2f}/s | {outgoing:7.2f}/s")
|
||||
print(f"Alive workers: {len(self._active)}")
|
||||
|
||||
if len(self._active) < 5:
|
||||
self._shutdown = True
|
||||
return
|
||||
|
||||
n_correct, n_wrong = 0, 0
|
||||
for index, expected in self.difference.items():
|
||||
y, x = divmod(index, 1000)
|
||||
|
@ -193,6 +212,10 @@ class AsyncBotManager:
|
|||
self.difference.update(
|
||||
pixmaps[frame_index % len(pixmaps)]
|
||||
)
|
||||
|
||||
for func in self.animation_functions:
|
||||
self.difference.update(func())
|
||||
|
||||
except Exception as e:
|
||||
print(f"Listener died: {e!r}")
|
||||
self._shutdown = True
|
||||
|
@ -208,22 +231,21 @@ 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)
|
||||
offset = 0
|
||||
while not self._shutdown:
|
||||
diff = list(self.difference.items())
|
||||
diff = sorted(diff, key=lambda kv: kv[0])
|
||||
for _ in range(100):
|
||||
index, expected = diff[offset % len(diff)]
|
||||
offset += randint(0, 100)
|
||||
offset += randint(0, 1000)
|
||||
y, x = divmod(index, 1000)
|
||||
current = self.canvas.getpixel((x, y)) > 0 # type: ignore
|
||||
if current != expected:
|
||||
# print(f"[{bot_index:2d}] swap {x:3d} {y:3d}")
|
||||
self._written_boxes += 1
|
||||
await sio.emit("toggle_bit", {"index": index})
|
||||
await asyncio.sleep(delay)
|
||||
break
|
||||
self._active.add(bot_index)
|
||||
await asyncio.sleep(0.01)
|
||||
self._active.add(bot_index)
|
||||
await sio.receive(0.1)
|
||||
|
||||
async def __aenter__(self):
|
||||
self._listener_task = asyncio.create_task(self.listener())
|
||||
|
@ -277,13 +299,27 @@ async def amain() -> None:
|
|||
mgr.put_image(elem["x"], elem["y"], im)
|
||||
print("ADD image", elem)
|
||||
|
||||
elif elem["type"] == "time":
|
||||
time_format = elem["format"]
|
||||
pos_x, pos_y = elem["x"], elem["y"]
|
||||
font = mgr.get_font(elem.get("font", "default"), elem.get("size", 8))
|
||||
def update() -> PixelMap:
|
||||
now = datetime.datetime.now(datetime.timezone.utc)
|
||||
txt = now.strftime(time_format)
|
||||
img = mgr.get_text_image(txt, font)
|
||||
pixmap = mgr.get_image_diff(pos_x, pos_y, img)
|
||||
img.close()
|
||||
return pixmap
|
||||
mgr.animation_functions.append(update)
|
||||
elif elem["type"] == "tile":
|
||||
with Image.open(elem["path"]).convert("LA") as im:
|
||||
for i in range(elem.get("ry", 1)):
|
||||
for j in range(elem.get("rx", 1)):
|
||||
x = elem["x"] + im.width * j
|
||||
y = elem["y"] + im.height * i
|
||||
mgr.put_image(x, y, im)
|
||||
for oy in range(elem.get("h", im.height)):
|
||||
for ox in range(elem.get("w", im.width)):
|
||||
l, a = im.getpixel((ox % im.width, oy % im.height)) # type: ignore
|
||||
if a:
|
||||
x, y = elem["x"] + ox, elem["y"] + oy
|
||||
index = x + y * 1000
|
||||
mgr.put_bit(index, l > 0)
|
||||
print("ADD tile", elem)
|
||||
elif elem["type"] == "animation":
|
||||
with Image.open(elem["path"]) as anim:
|
||||
|
@ -371,7 +407,9 @@ async def amain() -> None:
|
|||
)
|
||||
|
||||
for ret in res:
|
||||
print(ret)
|
||||
print("RETURN", repr(ret))
|
||||
|
||||
mgr._shutdown = True
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 19 KiB |
Binary file not shown.
After Width: | Height: | Size: 802 B |
Binary file not shown.
After Width: | Height: | Size: 491 B |
Binary file not shown.
After Width: | Height: | Size: 991 B |
Binary file not shown.
After Width: | Height: | Size: 2.3 KiB |
|
@ -35,14 +35,6 @@
|
|||
"stop": 1000000,
|
||||
"description": "catgirls.win text (both b64 and plain)"
|
||||
},
|
||||
{
|
||||
"type": "rect",
|
||||
"x": 400,
|
||||
"y": 750,
|
||||
"w": 400,
|
||||
"h": 128,
|
||||
"description": "'be gay do crime' sign"
|
||||
},
|
||||
{
|
||||
"type": "image",
|
||||
"path": "./avoid_masks/noita.png",
|
||||
|
@ -50,16 +42,25 @@
|
|||
}
|
||||
],
|
||||
"elements": [
|
||||
{
|
||||
"type": "time",
|
||||
"x": 75,
|
||||
"y": 100,
|
||||
"format": "And time is: %Y-%m-%d %H:%M:%S UTC",
|
||||
"spf": 20,
|
||||
"font": "/usr/share/fonts/TTF/TerminusTTF.ttf",
|
||||
"size": 12
|
||||
},
|
||||
{
|
||||
"type": "image",
|
||||
"path": "./pictures/casey.png",
|
||||
"x": 32,
|
||||
"y": 420
|
||||
"x": 0,
|
||||
"y": 128
|
||||
},
|
||||
{
|
||||
"type": "rgb565",
|
||||
"path": "./pictures/niko_standing.png",
|
||||
"x": 106,
|
||||
"x": 116,
|
||||
"y": 132
|
||||
},
|
||||
{
|
||||
|
@ -67,6 +68,21 @@
|
|||
"path": "./pictures/hello.png",
|
||||
"x": 112,
|
||||
"y": 203
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"font": "/usr/share/fonts/TTF/comic.ttf",
|
||||
"size": 20,
|
||||
"x": 250,
|
||||
"y": 492,
|
||||
"text": "You like kissing, don't you?"
|
||||
},
|
||||
{
|
||||
"type": "animation",
|
||||
"path": "./pictures/neko.gif",
|
||||
"spf": 30,
|
||||
"x": 625,
|
||||
"y": 496
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue