Skip to content

Commit

Permalink
Fix(Server): TTTK-44 Broadcast now works, fixed invalid JSON dumps pa…
Browse files Browse the repository at this point in the history
…rameter (Player objects), made server a python module
  • Loading branch information
Petzys committed Feb 23, 2024
1 parent bb0bfd0 commit 4d70563
Show file tree
Hide file tree
Showing 3 changed files with 83 additions and 64 deletions.
Empty file added Server/__init__.py
Empty file.
19 changes: 16 additions & 3 deletions Server/player.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
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"])
128 changes: 67 additions & 61 deletions Server/websocket_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,91 +7,97 @@
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:
self._players = {admin.uuid : admin}
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):
Expand Down

0 comments on commit 4d70563

Please sign in to comment.