def handle_player_leave(): player = self.players_by_session.get( session.get("connection_id", None), None) requests_logger.debug( f"{session.get('connection_id', None)} disconnected from {self.lobby_name} " f"at /{self.lobby_slug}") if player: del self.players_by_session[session["connection_id"]] #################### def player_leave(self, p): # NOTE: Backend will only make one copy per player for certain (except for reconnects) if p in self.participants: print('before:', self.participants) self.participants.remove(p) print('after:', self.participants) else: raise logic.Game.InvalidPlayer if len(self.participants) == 0: self.quit_game() elif p == self.host: self.host = self.participants[0] if self.rules.finish_game_on_disconnect: self.finish_game()
def vote_on_rules(json=None): player = self.players_by_session.get( session.get("connection_id", None), None) if player: requests_logger.debug( f'Player {player} is trying to vote on rules on {self.name_space}' ) if json: if jsonschema.validate(json, schema.game_action_schema): pass else: return jsonify({ "Error": { "type": "schema_error", "message": "The json data provided does not match the required schema.", } }) else: return jsonify({ "Error": { "type": "data_missing", "message": "You need to provide json data.", } }) else: requests_logger.debug( f'A foreign connection has tried to vote on rules on {self.name_space}' )
def handle_chat_message(json=None): player = self.players_by_session.get( session.get("connection_id", None), None) if json: if jsonschema.validate(json, schema.player_schema): pass else: return JSON.dumps({ "Error": { "type": "schema_error", "message": "The json data provided does not match the required schema." } }) else: return JSON.dumps({ "Error": { "type": "data_missing", "message": "You need to provide json data." } }) requests_logger.debug( f"A player has tried to send a chat message to game {self.lobby_name}" )
def handle_player_join(json=None): if "connection_id" not in session: session["connection_id"] = b64encode(os.urandom(2**5)) requests_logger.debug( f"{session.get('connection_id', None)} connected to game {self.lobby_name} at /{self.lobby_slug}." ) if json: if jsonschema.validate(json, schema.player_schema): token_style_data = json["token_style"] token_style = data.TokenStyle( color=tuple(token_style_data["color"])) player = data.Player(json['player_name'], token_style) if not self.current_game and len( self.players_by_session) < max_number_of_players: self.players_by_session[ session["connection_id"]] = player ######## def player_join(self, p): if self._game_state == logic.Game.State.started: if not self.rules.allow_reconnect: raise logic.Game.InvalidPlayer() else: if p not in self.participants: if not any(p.name == x.name for x in self.initial_players): self.participants.append(p) else: if any([ not data.TokenStyle.distinguishable( x.token_style, p.token_style) for x in self.participants ]) or any( [p.name == x.name for x in self.participants]): raise logic.Game.InvalidPlayer() if not len(self.participants ) < self.rules.number_of_players: raise logic.Game.LobbyFull( len(self.participants)) self.participants.append(p) else: return JSON.dumps({ "Error": { "type": "schema_error", "message": "The json data provided does not match the required schema." } }) else: return JSON.dumps({ "Error": { "type": "data_missing", "message": "You need to provide json data." } })
def retrieve_game(slug=None): slug = slugify(slug) requests_logger.debug( f"GET request to /games/{{{slug}}}. Sending game info…") if slug: try: game = RequestHandler.lobbies.get(slug) response = jsonify(game) except KeyError: response = exceptions.NotFound( f"Game with slug {slug} not found.") else: response = exceptions.BadRequest("Need to specify game slug") return response
def handle_quit_game(json=None): requests_logger.debug( f"A player has tried to quit the game {self.lobby_name}") player = self.players_by_session.get( session.get("connection_id", None), None) if player: requests_logger.debug( f'Player {player} is trying to quit {self.name_space}') else: requests_logger.debug( f'A foreign connection has tried to quit {self.name_space}' )
def create_lobby(): request_data = request.json try: jsonschema.validate(instance=request_data, schema=schema.create_lobby_schema) lobby_name = request_data.get("lobby_name") lobby_slug = "lobby-" + slugify(request_data.get("lobby_name")) allow_rule_voting = request_data.get("allow_rule_voting") list_publicly = request_data.get("list_publicly") max_number_of_players = request_data.get("max_number_of_players") if all(x is not None for x in [ lobby_name, lobby_slug, allow_rule_voting, list_publicly, max_number_of_players ]): with RequestHandler.lobbies_lock: if lobby_slug in RequestHandler.lobbies: raise ValueError("Game slug has been used already") lobby = Lobby(lobby_name, lobby_slug, allow_rule_voting, list_publicly, max_number_of_players) RequestHandler.lobbies.update({lobby_slug: lobby}) requests_logger.debug(f"POST request to /games successful. " f"Created new Game \"{lobby_slug}\"") return jsonify(lobby.json()) else: raise ValueError() except jsonschema.exceptions.SchemaError as e: requests_logger.debug( "POST request to /games failed. Data incomplete.") return exceptions.BadRequest( f"Data incomplete, Key Error: {e.args}") except ValueError as e: requests_logger.debug( "POST request to /games failed. Invalid Data.") return exceptions.BadRequest(f"Data invalid. {e.args}") except Exception as e: requests_logger.debug( "POST request to /games failed with unhandled Error.") raise e
def handle_game_action(json=None): requests_logger.debug( f"A player has tried to make a game action in game {self.lobby_name}" ) player = self.players_by_session.get( session.get("connection_id", None), None) if player: requests_logger.debug( f'Player {player} is trying to commit a game action on {self.name_space}' ) if json: if jsonschema.validate(json, schema.game_action_schema): pass else: return jsonify({ "Error": { "type": "schema_error", "message": "The json data provided does not match the required schema.", } }) else: return jsonify({ "Error": { "type": "data_missing", "message": "You need to provide json data.", } }) else: requests_logger.debug( f'A foreign connection has tried to commit a game action on {self.name_space}' ) return jsonify({ "Error": { "type": "insufficient_authorization", "message": "you are not a player an hence not allowed to commit a game action.", } })
def list_games(): requests_logger.debug("GET request to /games. Serving list of games…") response = jsonify(list(RequestHandler.lobbies.values())) return response
def handle_disconnect(): requests_logger.debug( f"{session.get('connection_id', 0)} has been disconnected.")
def handle_connect(): if session.get("connection_id", None) is None: session["connection_id"] = b64encode(os.urandom(2**5)) requests_logger.debug( f"{session['connection_id']} connected. The sid is: {request.sid}, request: {request}" )
def handle_start_game(json=None): requests_logger.debug( f"A player has tried to start the game {self.lobby_name}") player = self.players_by_session.get( session.get("connection_id", None), None) if player: requests_logger.debug( f'Player {player} is trying to start {self.name_space}') # no data is needed as the rules for a new game are stored in the lobby object def start_game(self, host_decision=False): def game_can_be_started(_host_decision): """Decide if the game can be started. Otherwise raise an exception stating the reason for the failure to be handled by the backend.""" if self.rules.start_game_if_all_ready: # Case 1: All Players are ready if all(p.is_ready for p in self.participants): # Case 1.1: Number of players variable if self.rules.variable_player_count: # Case 1.1.1: Enough Players in Lobby → start game if len(self.participants) > 1: return True # Case 1.1.2: Not enough players for a game → Game cannot be started else: raise logic.Game.CannotBeStarted( logic.Game.CannotBeStarted.Reason. not_enough_players) # Case 1.2: Number of Players fixed else: # Case 1.2.1: Lobby is full → start game if len(self.participants ) == self.rules.number_of_players: return True # Case 1.2.2: Not enough players → Game cannot be started else: # Case 1.2.2.1: Host decided for the game to start → start game if _host_decision: return True # Case 1.2.2.2: No host decision → Game cannot be started else: raise logic.Game.CannotBeStarted( logic.Game.CannotBeStarted. Reason.not_enough_players) # Case 2: Not all players are ready → Game cannot be started else: raise logic.Game.CannotBeStarted( logic.Game.CannotBeStarted.Reason. not_all_players_ready) else: # Case 1: Lobby full → start game if len(self.participants ) == self.rules.number_of_players: return True # Case 2: Lobby not full (Host initiated start) else: # Case 2.1: Enough players → start game if len(self.participants) > 1: return True # Case 2.2: Not enough players → Game cannot be started else: raise logic.Game.CannotBeStarted( logic.Game.CannotBeStarted.Reason. not_enough_players) if game_can_be_started(host_decision): self._game_state = logic.Game.State.started self._current_turn = 0 # if self.rules.shuffle_turn_order_on_start: # random.shuffle(self.participants) # replaced by: # self.rules.apply(game=self) self.initial_players = self.participants[:] else: requests_logger.debug( f'A foreign connection has tried to start {self.name_space}' ) quit() ############################################################################ if json: try: jsonschema.validate(instance=json, schema=schema.create_game_schema) game_name = json.get("game_name") rules = data.Rules(**json.get("rules")) card_deck = data.CardDeck(**json.get("card_deck")) host_player_data = json.get("player") host_player = data.Player( host_player_data["name"], data.TokenStyle(**host_player_data["token_style"])) if game_name and rules and card_deck and host_player: new_game = logic.Game(game_name, host_player, rules, card_deck) with RequestHandler.game_sockets_lock: if new_game.slug in RequestHandler.game_sockets: raise ValueError() connection = GameSocket(game=new_game) RequestHandler.game_sockets.update( {new_game.slug: connection}) requests_logger.debug( f"POST request to /games successful. " f"Created new Game \"{new_game.slug}\"") return JSON.dumps(new_game.json()) else: raise ValueError() except jsonschema.exceptions.SchemaError as e: requests_logger.debug( "POST request to /games failed. Data incomplete.") return exceptions.BadRequest( f"Data incomplete, Key Error: {e.args}") except ValueError as e: requests_logger.debug( "POST request to /games failed. Invalid Data.") return exceptions.BadRequest(f"Data invalid. {e.args}") except Exception as e: requests_logger.debug( f"Start game request by {session['connection_id']} to {self.name_space}" f"failed with unhandled Error.") raise e else: return exceptions.BadRequest("You need to provide json data.")