async def on_spectate(self, sid: SpectatorSID, msg: SpectateMessage) -> Tuple[str, Dict]: room, _ = get_room_player(sid, msg.roomid, None, check_server=False) self.enter_room(sid, room.broadcast_sid) self.enter_room(sid, room.spectator_sid) return ( "message", { "board": room.board, "status": room.status, "players": {player.id: player.name for player in room.players}, "turn": room.turn, "states": [{ "id": state.id, "timestamp": state.timestamp.isoformat(), "epoch": state.epoch, "move": state.move, "board": state.board, "turn": state.turn, } for state in room.states], }, )
async def on_joinsuccess(self, sid: GameServerSID, msg: JoinSuccessMessage) -> None: """ Server confirmed a player joining the lobby """ room, player = get_room_player(sid, msg.roomid, msg.playerid) assert player is not None player.update(joined=True, gamerole=msg.gamerole) self.enter_room(player.sid, room.broadcast_sid) await JoinedMessage( roomid=msg.roomid, playerid=msg.playerid, name=player.name, gamerole=msg.gamerole, broadcast=False, ).send( self, to=player.sid, callback=partial(self.acknowledge_join, room_id=msg.roomid, player_id=msg.playerid), ) await JoinedMessage( roomid=msg.roomid, playerid=msg.playerid, name=player.name, gamerole=msg.gamerole, broadcast=True, ).send( self, to=room.broadcast_sid, )
async def on_joinfail(self, sid: GameServerSID, msg: JoinFailMessage) -> None: """ Server responds that a player failed to join the lobby """ room, player = get_room_player(sid, msg.roomid, msg.playerid) assert player is not None await self.emit( "fail", { "error": "registrationFailed", "reason": msg.reason }, room=player.sid, )
async def on_move(self, sid: PlayerSID, msg: MoveMessage) -> None: """ Player sends a move request """ room, player = get_room_player(sid, msg.roomid, msg.playerid, check_server=False) if room.status != "playing": raise GameNotRunning elif room.turn != msg.playerid: raise NotPlayersTurn else: state = GameState.create(player_id=msg.playerid, room=msg.roomid, move=msg.move) await PlayerMoveMessage( roomid=msg.roomid, playerid=msg.playerid, move=msg.move, stateid=state.id, ).send(self, to=room.server_sid)
async def on_gameupdate(self, sid: GameServerSID, msg: GameUpdateMessage) -> None: """ Server notifies of a game state change """ if msg.visibility == "private": if msg.playerid is None: raise InputValidationError( details= "error: 'playerid' must be provided when visibility is private" ) else: if msg.playerid is not None: raise InputValidationError( details= "error: 'playerid' cannot be provided unless visibility is private" ) if msg.epoch is None: raise InputValidationError( details= "error: 'epoch' is required for non-private messages") room, player = get_room_player(sid, msg.roomid, msg.playerid) with room.lock(timeout=0.5, sleep=0.02): if msg.finish is not None: logger.info("Game finished") await GamestateMessage.parse_obj(msg.to_dict() ).send(self, to=room.broadcast_sid) room.update(status="finished") new_status = "finished" if room.status == "finished" else "playing" if msg.visibility == "private": room.update(status=new_status, turn=msg.turn) assert player is not None await GamestateMessage( board=msg.board, turn=msg.turn, roomid=msg.roomid, playerid=msg.playerid, epoch=msg.epoch, ).send(self, to=player.sid) else: if room.status == "finished": room.update(board=msg.board, turn=None) else: room.update(status=new_status, turn=msg.turn) if msg.visibility == "broadcast": r = GamestateMessage( board=msg.board, turn=msg.turn, roomid=msg.roomid, playerid=msg.playerid, epoch=msg.epoch, ) logger.debug( f"room.id={room.id}, room.broadcast_sid={room.broadcast_sid}" ) await r.send(sio=self, to=room.broadcast_sid) try: state = GameState.get(msg.stateid) if state.room is not None and state.room.id != msg.roomid: raise InstanceNotFound except InstanceNotFound: state_args = { "room_id": msg.roomid, "epoch": msg.epoch, "board": msg.board, "turn": msg.turn, } GameState.create( **{k: v for k, v in state_args.items() if v is None}) else: state.update(epoch=msg.epoch, board=msg.board, turn=msg.turn) room.update( status=new_status, board=msg.board, turn=msg.turn, )