48 lines
2.1 KiB
Python
48 lines
2.1 KiB
Python
"""Compact wire format for the place websocket.
|
|
|
|
Same convention as clock/wire.py (kept separate on purpose - the two games
|
|
don't share code, mirroring how the clock and place apps don't share code
|
|
either). Each message is a short string: a one-letter type tag followed by
|
|
'|'-separated fields, in a fixed order the client already knows from this
|
|
table:
|
|
|
|
s|<next>|<width>|<height>|<end>
|
|
initial personal state, once per connection
|
|
(next = epoch ms cooldown ends, or empty if free now;
|
|
end = epoch ms placement ends, or empty if never)
|
|
p|<x>|<y>|<c> a pixel was placed - broadcast to everyone,
|
|
including the placer (no separate ack needed)
|
|
k|<next> your own placement was accepted; carries your
|
|
new cooldown end
|
|
r|c|<next> rejected: still on cooldown
|
|
r|a rejected: not logged in
|
|
r|i rejected: invalid x/y/color
|
|
r|d rejected: placement is over (past <end>)
|
|
e|<width>|<height>|<end>
|
|
an admin edited this event's settings (grid size
|
|
and/or end time) - broadcast to everyone.
|
|
If the size changed, a client should re-fetch
|
|
/api/.../place/canvas rather than try to remap its
|
|
local pixels.
|
|
w placement just ended - broadcast to everyone at
|
|
<end> (see tasks.py). Clients play the wipe wave
|
|
and blank their board.
|
|
|
|
Client -> server has exactly one message shape, the same as the broadcast:
|
|
p|<x>|<y>|<c>
|
|
|
|
Whether the game is enabled at all for this event (EventGame.enabled) is
|
|
checked once, at connect time - a connection is refused outright rather than
|
|
accepted-but-disabled, so there's no "disabled" case in this wire format.
|
|
"""
|
|
|
|
DELIMITER = "|"
|
|
|
|
|
|
def encode(*parts) -> str:
|
|
return DELIMITER.join("" if p is None else str(p) for p in parts)
|
|
|
|
|
|
def to_epoch_ms(dt) -> int:
|
|
return int(dt.timestamp() * 1000)
|