Archived
only legal actions can be taken
This commit is contained in:
@@ -1,8 +1,5 @@
|
||||
"""controller handles the translation between
|
||||
netcode messages and model functions"""
|
||||
|
||||
from controller.interfaces import ClientControllerInterface, GameControllerInterface
|
||||
from controller.object_controller import ObjectController
|
||||
from controller.card import Card
|
||||
from controller.client import ClientController
|
||||
from controller.game import GameController
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
from controller import ObjectController
|
||||
|
||||
|
||||
class Card(ObjectController):
|
||||
pass
|
||||
+80
-43
@@ -1,12 +1,16 @@
|
||||
from typing import Callable, Any
|
||||
"""Handles communication between one WebSocket tunnel and the game"""
|
||||
|
||||
from typing import Callable, Any, TYPE_CHECKING
|
||||
from pydantic import ValidationError
|
||||
|
||||
from websockets.server import WebSocketServerProtocol
|
||||
from controller import GameControllerInterface, ClientControllerInterface
|
||||
|
||||
from netcode.models import Message, LoginMessage
|
||||
|
||||
from model import Player, Team
|
||||
from model import Player
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from controller import GameController
|
||||
|
||||
|
||||
def vibe_check(t):
|
||||
@@ -26,10 +30,12 @@ def vibe_check(t):
|
||||
return decorator
|
||||
|
||||
|
||||
class ClientController(ClientControllerInterface):
|
||||
class ClientController:
|
||||
"""Handles communication between one WebSocket tunnel and the game"""
|
||||
|
||||
websocket: WebSocketServerProtocol
|
||||
|
||||
game_controller: GameControllerInterface
|
||||
game_controller: "GameController"
|
||||
|
||||
player: Player
|
||||
|
||||
@@ -37,7 +43,7 @@ class ClientController(ClientControllerInterface):
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
game_controller: GameControllerInterface,
|
||||
game_controller: "GameController",
|
||||
websocket: WebSocketServerProtocol,
|
||||
):
|
||||
self.websocket = websocket
|
||||
@@ -45,7 +51,8 @@ class ClientController(ClientControllerInterface):
|
||||
|
||||
self.game_controller = game_controller
|
||||
|
||||
async def listen(self):
|
||||
async def listen(self) -> None:
|
||||
"""Hooks the client to the correct listen callbacks"""
|
||||
await self.send(
|
||||
Message(
|
||||
type="context",
|
||||
@@ -59,10 +66,12 @@ class ClientController(ClientControllerInterface):
|
||||
async for message in self.websocket:
|
||||
await self.on_message(message)
|
||||
|
||||
async def send(self, message: Message):
|
||||
async def send(self, message: Message) -> None:
|
||||
"""Send a Message object to the connected client"""
|
||||
await self.websocket.send(message.model_dump_json())
|
||||
|
||||
async def send_error(self, error: str):
|
||||
async def send_error(self, error: str) -> None:
|
||||
"""Send an error string to the connected client"""
|
||||
await self.send(Message(type="error", data_type="error", data=error))
|
||||
|
||||
async def send_announce_dict(
|
||||
@@ -71,55 +80,83 @@ class ClientController(ClientControllerInterface):
|
||||
data: dict,
|
||||
player_filter: Callable[[Player], Any] = lambda x: True,
|
||||
):
|
||||
"""Send a, Object dict to the connected client
|
||||
|
||||
player_filter is a filter which is called using the connected player
|
||||
"""
|
||||
if hasattr(self, "player") is False or player_filter(self.player):
|
||||
await self.send(
|
||||
Message(type=notification_type, data_type="object", data=data)
|
||||
)
|
||||
|
||||
@vibe_check(Message)
|
||||
async def game_context(self, message: Message):
|
||||
if self.player.team != self.game_controller.game.turn:
|
||||
async def game_context(self, message: Message) -> None:
|
||||
"""Handles all messages related to when the current client is logged in
|
||||
and connected to a running game"""
|
||||
|
||||
if message.type == "temp_action":
|
||||
if message.data_type == "set_health":
|
||||
self.player.team.health = message.data
|
||||
return await self.game_controller.game.notify_controller(
|
||||
"update", self.player.team.serialize_guest()
|
||||
)
|
||||
|
||||
if self.player.team != self.game_controller.game.current_turn:
|
||||
return await self.send_error("it is not your turn to play!")
|
||||
if message.type == "action":
|
||||
if message.data_type == "buy":
|
||||
## TODO : pydantic type check for message.data
|
||||
await self.player.buy_cards(message.data)
|
||||
elif message.data_type == "play_cards":
|
||||
await self.player.play_cards(message.data)
|
||||
elif message.data_type == "discard":
|
||||
await self.player.discard_cards(message.data)
|
||||
elif message.data_type == "draw":
|
||||
await self.player.draw(message.data)
|
||||
elif message.data_type == "end_turn":
|
||||
# TODO : pydantic type check for message.data
|
||||
match message.data_type:
|
||||
case "play_card":
|
||||
return await self.player.play_card(message.data)
|
||||
|
||||
await self.player.end_turn()
|
||||
case "discard":
|
||||
return await self.player.turn.discard_card(message.data)
|
||||
|
||||
case "lock_card":
|
||||
return await self.player.turn.lock_card(message.data)
|
||||
|
||||
case "use_effect":
|
||||
return await self.player.turn.use_effect(
|
||||
message.data.effect_id, message.data.target
|
||||
)
|
||||
|
||||
case "buy":
|
||||
return await self.player.turn.buy_card(message.data)
|
||||
case "end_turn":
|
||||
return await self.player.turn.end_turn()
|
||||
|
||||
return await self.send_error(
|
||||
"Couldn't process action with data_type : " + message.data_type
|
||||
)
|
||||
|
||||
@vibe_check(LoginMessage)
|
||||
async def login_context(self, message: LoginMessage):
|
||||
|
||||
async def login_context(self, message: LoginMessage) -> None:
|
||||
"""Handles all messages related to when the current client isn't yet logged in"""
|
||||
username = message.data
|
||||
if self.game_controller.game.started:
|
||||
return await self.send_error(
|
||||
"you cannot interact with a game that has already started"
|
||||
)
|
||||
if message.type == "register":
|
||||
|
||||
if len(username) < 3:
|
||||
await self.send_error("username must be longer than 3 characters")
|
||||
return
|
||||
return await self.send_error(
|
||||
"username must be longer than 3 characters"
|
||||
)
|
||||
|
||||
if self.game_controller.game.get_player(username) is not None:
|
||||
await self.send_error("username already exists")
|
||||
return
|
||||
return await self.send_error("username already exists")
|
||||
|
||||
player = await self.game_controller.game.create_player(username)
|
||||
elif message.type == "login":
|
||||
player2 = self.game_controller.game.get_player(username)
|
||||
|
||||
if player2 is None:
|
||||
await self.send_error("player doesn't exists")
|
||||
return
|
||||
return await self.send_error("player doesn't exists")
|
||||
|
||||
player = player2
|
||||
|
||||
else:
|
||||
await self.send_error("invalid message type for context")
|
||||
return
|
||||
return await self.send_error("invalid message type for context")
|
||||
|
||||
self.player = player
|
||||
self.player.team.listeners.append(self.send_announce_dict)
|
||||
@@ -141,18 +178,18 @@ class ClientController(ClientControllerInterface):
|
||||
)
|
||||
)
|
||||
|
||||
# for player in self.game_controller.game.players:
|
||||
# if player.team != self.player.team:
|
||||
# continue
|
||||
|
||||
# await self.send(
|
||||
# Message(type="update", data_type="object", data=player.serialize_team())
|
||||
# )
|
||||
|
||||
@vibe_check(Message)
|
||||
async def pregame_context(self, message: Message):
|
||||
|
||||
async def pregame_context(self, message: Message) -> None:
|
||||
"""Handles all messages related to when the current client is logged in
|
||||
but the game isn't yet started"""
|
||||
if message.type == "ready":
|
||||
self.player.ready = bool(message.data)
|
||||
if all(p.ready for p in self.game_controller.game.players):
|
||||
await self.game_controller.start_game()
|
||||
|
||||
elif message.type == "temp_action":
|
||||
if message.data_type == "set_health":
|
||||
self.player.team.health = message.data
|
||||
await self.game_controller.game.notify_controller(
|
||||
"update", self.player.team.serialize_guest()
|
||||
)
|
||||
|
||||
+15
-5
@@ -6,18 +6,16 @@ from netcode.models import Message
|
||||
from model import Game, Player
|
||||
from controller import (
|
||||
ClientController,
|
||||
ClientControllerInterface,
|
||||
GameControllerInterface,
|
||||
)
|
||||
|
||||
|
||||
class GameController(GameControllerInterface):
|
||||
class GameController:
|
||||
server: WSServer
|
||||
game: Game
|
||||
|
||||
clients: List[ClientControllerInterface]
|
||||
clients: List[ClientController]
|
||||
|
||||
def __init__(self, game: Game, server: WSServer):
|
||||
def __init__(self, game: Game, server: WSServer) -> None:
|
||||
self.server: WSServer = server
|
||||
self.game: Game = game
|
||||
self.server.on_new_connection_callback = self.on_new_connection
|
||||
@@ -74,6 +72,13 @@ class GameController(GameControllerInterface):
|
||||
)
|
||||
|
||||
async def announce_game(self, websocket: WebSocketServerProtocol):
|
||||
for effect in self.game.effects:
|
||||
await self.announce_dict(
|
||||
"create",
|
||||
effect.serialize(),
|
||||
websocket,
|
||||
)
|
||||
|
||||
for card in self.game.cards:
|
||||
await self.announce_dict(
|
||||
"create",
|
||||
@@ -89,6 +94,11 @@ class GameController(GameControllerInterface):
|
||||
)
|
||||
|
||||
for player in self.game.players:
|
||||
await self.announce_dict(
|
||||
"create",
|
||||
player.turn.serialize(),
|
||||
websocket,
|
||||
)
|
||||
await self.announce_dict(
|
||||
"create",
|
||||
player.serialize_guest(),
|
||||
|
||||
@@ -1,95 +0,0 @@
|
||||
from abc import ABC, abstractmethod
|
||||
from typing import Callable, Any, List
|
||||
from model import Game, Player
|
||||
from netcode import WSServer
|
||||
from netcode.models import Message, LoginMessage
|
||||
from netcode.ws_server import WebSocketServerProtocol
|
||||
|
||||
|
||||
class ClientControllerInterface(ABC):
|
||||
|
||||
@abstractmethod
|
||||
async def listen(self):
|
||||
"""Initializes the client controller"""
|
||||
|
||||
@abstractmethod
|
||||
async def send(self, message: Message):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
async def send_error(self, error: str):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
async def send_announce_dict(
|
||||
self,
|
||||
notification_type: str,
|
||||
data: dict,
|
||||
player_filter: Callable[[Player], bool] = lambda x: True,
|
||||
):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
async def game_context(self, message: Message):
|
||||
"""Handles messages when the client is logged in"""
|
||||
|
||||
@abstractmethod
|
||||
async def login_context(self, message: LoginMessage):
|
||||
"""Handles messages when the client isn't logged in"""
|
||||
|
||||
@abstractmethod
|
||||
async def pregame_context(self, message: Message):
|
||||
"""Waits for players"""
|
||||
|
||||
|
||||
class GameControllerInterface(ABC):
|
||||
server: WSServer
|
||||
game: Game
|
||||
|
||||
clients: List[ClientControllerInterface]
|
||||
|
||||
@abstractmethod
|
||||
def __init__(self, game: Game, server: WSServer):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
async def on_new_connection(self, websocket, callback: Callable):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
async def send(self, message: Message, websocket: WebSocketServerProtocol):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
async def broadcast(self, message: Message):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
async def broadcast_announce_dict(
|
||||
self,
|
||||
notification_type: str,
|
||||
data: dict,
|
||||
player_filter: Callable[[Player], Any],
|
||||
):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
async def announce_dict(
|
||||
self,
|
||||
notification_type: str,
|
||||
data: dict,
|
||||
websocket: WebSocketServerProtocol,
|
||||
):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
async def announce_game(self, websocket: WebSocketServerProtocol):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
async def guest_handler(self, websocket: WebSocketServerProtocol):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
async def start_game(self):
|
||||
pass
|
||||
@@ -1,2 +0,0 @@
|
||||
class ObjectController:
|
||||
pass
|
||||
Reference in New Issue
Block a user