diff --git a/Server/__init__.py b/Server/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/Server/player.py b/Server/player.py index cba1f10..0d5abfc 100644 --- a/Server/player.py +++ b/Server/player.py @@ -5,12 +5,25 @@ class Player: Represents a player in the game. Attributes: - _id (int): The unique identifier of the player. display_name (str): The name displayed for the player. - statistics (Statistics): The statistics of the player. + color (int): The color of the player. + uuid (str): The unique identifier of the player. + ready (bool): Whether the player is ready to start the game. """ def __init__(self, display_name: str, color: int, uuid: str, ready:bool = False): self.uuid: UUID = UUID(uuid) self.display_name = display_name self.color = color - self.ready = ready \ No newline at end of file + self.ready = ready + + def __dict__(self) -> dict: + return { + "display_name": self.display_name, + "color": self.color, + "uuid": str(self.uuid), + "ready": self.ready + } + + @classmethod + def from_dict(cls, player_dict: dict): + return cls(player_dict["display_name"], player_dict["color"], player_dict["uuid"], player_dict["ready"]) \ No newline at end of file diff --git a/Server/websocket_server.py b/Server/websocket_server.py index 19c88b0..c48d557 100644 --- a/Server/websocket_server.py +++ b/Server/websocket_server.py @@ -7,7 +7,8 @@ import json from jsonschema import validate, ValidationError -logger = logging.getLogger() +logging.basicConfig(level=logging.INFO) +logger = logging.getLogger(__name__) class Lobby: def __init__(self, admin:Player, port: int = 8765) -> None: @@ -15,83 +16,88 @@ def __init__(self, admin:Player, port: int = 8765) -> None: self._game = None self._inprogress = False self._port = port + self._connections = set() with open("./json_schema/client_to_server.json", "r") as f: self._json_schema = json.load(f) async def handler(self, websocket): + + self._connections.add(websocket) + while True: try: message = await websocket.recv() - except websockets.ConnectionClosedOK: - logger.info("Connection Closed from Client-Side") - # TODO: Add handling when game is not over yet - break - - # TODO: Catch other errors for disconnects - logger.info(f"Received: {message}") + logger.info(f"Received: {message}") - message_json = json.loads(message) - - # Validate JSON - try: - validate(instance=message_json, schema=self._json_schema) - except ValidationError as e: - logger.error(e) - break + message_json = json.loads(message) + + # Validate JSON + try: + validate(instance=message_json, schema=self._json_schema) + except ValidationError as e: + logger.error(e) + continue - match message_json["message_type"]: + match message_json["message_type"]: - case "lobby/join": + case "lobby/join": - if self._inprogress: - await websocket.send("Game in progress, cannot join") # TODO jsonify - break + if self._inprogress: + await websocket.send("Game in progress, cannot join") # TODO jsonify + break - self._players[message_json["profile"]["uuid"]] = Player(uuid=message_json["profile"]["uuid"], display_name=message_json["profile"]["display_name"], color=message_json["profile"]["color"]) + self._players[message_json["profile"]["uuid"]] = Player(uuid=message_json["profile"]["uuid"], display_name=message_json["profile"]["display_name"], color=message_json["profile"]["color"]) - # await websocket.send( ## STATISTICS ## ) - await websocket.broadcast(json.dumps({ - "message_type": "lobby/status", - "players": self._players.values(), - })) - + # await websocket.send( ## STATISTICS ## ) + websockets.broadcast(self._connections, json.dumps({ + "message_type": "lobby/status", + "players": [player.__dict__() for player in self._players.values()], + })) + - case "lobby/kick": - pass - - - case "lobby/ready": - - self._players[message_json["player_uuid"]].ready = True - - await websocket.broadcast(json.dumps({ - "message_type": "lobby/status", - "players": self._players.values(), - })) - - if all([player.ready for player in self._players.values()]) & len(self._players) == 2: - # TODO add error messages for why game cant start with not enough or too many ready players - # all players are ready, start the game - rulebase = RuleBase() - self._game = Game(player1 = self._players.values()[0], player2 = self._players.values()[1], rulebase = rulebase) - await websocket.broadcast(json.dumps({ - "message_type": "game/start", - "starting_player_uuid": self._game.current_player_uuid, + case "lobby/kick": + pass + + + case "lobby/ready": + + self._players[message_json["player_uuid"]].ready = True + + websockets.broadcast(self._connections, json.dumps({ + "message_type": "lobby/status", + "players": [player.__dict__() for player in self._players.values()], })) - - - case "game/make_move": - pass - - - case "chat/message": - pass - - - case _: - await websocket.send("Invalid Message Type") + + if all([player.ready for player in self._players.values()]) & len(self._players) == 2: + # TODO add error messages for why game cant start with not enough or too many ready players + # all players are ready, start the game + rulebase = RuleBase() + self._game = Game(player1 = self._players.values()[0], player2 = self._players.values()[1], rulebase = rulebase) + + websockets.broadcast(self._connections, json.dumps({ + "message_type": "game/start", + "starting_player_uuid": self._game.current_player_uuid, + })) + + + case "game/make_move": + pass + + + case "chat/message": + pass + + + case _: + await websocket.send("Invalid Message Type") + + except websockets.ConnectionClosedOK: + logger.info("Connection Closed from Client-Side") + # TODO: Add handling when game is not over yet + break + # TODO: Catch other errors for disconnects async def start_server(self):