From 6a0abfbaddf44451242142d0b421a77371ec3492 Mon Sep 17 00:00:00 2001 From: Giovani Date: Wed, 14 Jul 2021 19:38:55 -0400 Subject: [PATCH] feat: complete connection scene --- config.yaml | 3 ++- tetri5/entity.py | 2 ++ tetri5/online.py | 46 +++++++++++++++++++++++++++++++++++++++++++--- tetri5/scene.py | 41 +++++++++++++++++++++++++++++++++++++---- 4 files changed, 84 insertions(+), 8 deletions(-) diff --git a/config.yaml b/config.yaml index af07dd0..9d32c31 100644 --- a/config.yaml +++ b/config.yaml @@ -38,7 +38,7 @@ position: # connection scene game-id-label: [200, 300] connecting-label: [280, 300] - waiting-opponent-label: [200, 300] + waiting-for-opponent-label: [200, 300] # multi player game scene well-player-1: [80, 80] well-player-2: [480, 80] @@ -61,6 +61,7 @@ engine: cursor-blink-interval: 150 period-blink-interval: 300 lines-per-level: 55 + ping-interval: 1500 # piece piece-drop-delay: 600 piece-lock-delay: 1000 diff --git a/tetri5/entity.py b/tetri5/entity.py index e6e9463..f408ecf 100644 --- a/tetri5/entity.py +++ b/tetri5/entity.py @@ -342,6 +342,8 @@ class Stack(Entity): vertex_four = (square[3][0] + (self._tile_size // 10), square[3][1] - (self._tile_size // 10)) new_square = (vertex_one, vertex_two, vertex_three, vertex_four) pygame.draw.polygon(surface, pygame.Color(square_design.inner_color), new_square, max(self._tile_size // 6, 1)) + + # draw square glimmer surface.set_at((square[0][0]+3, square[0][1]+3), pygame.Color(255, 255, 255)) surface.set_at((square[0][0]+4, square[0][1]+4), pygame.Color(255, 255, 255)) surface.set_at((square[0][0]+4, square[0][1]+5), pygame.Color(255, 255, 255)) diff --git a/tetri5/online.py b/tetri5/online.py index b77ad87..5f73a78 100644 --- a/tetri5/online.py +++ b/tetri5/online.py @@ -10,9 +10,14 @@ class MultiplayerService(): _thread = None _receive_piece_queue = queue.Queue() _send_piece_queue = queue.Queue() + _receive_message_queue = queue.Queue() + _send_message_queue = queue.Queue() _current_game_id = None _client_id = str(uuid.uuid4()) + WAIT_FOR_OPPONENT = "wait_for_opponent" + START_GAME = "start_game" + @classmethod def init(cls) -> None: thread = Thread(target=asyncio.get_event_loop().run_until_complete,\ @@ -28,12 +33,28 @@ class MultiplayerService(): def send_piece(cls, piece: "PieceDto") -> None: cls._send_piece_queue.put(piece) + @classmethod + def send_message(cls, message: str) -> None: + cls._send_message_queue.put(message) + @classmethod def try_receive_piece(cls) -> "PieceDto": + if cls._receive_piece_queue.empty(): + return None + result = cls._receive_piece_queue.get() cls._receive_piece_queue.task_done() return result + @classmethod + def try_receive_message(cls) -> str: + if cls._receive_message_queue.empty(): + return None + + result = cls._receive_message_queue.get() + cls._receive_message_queue.task_done() + return result + @classmethod def quit(cls) -> None: _NetworkConnectionService.close_connection() @@ -61,6 +82,7 @@ class _NetworkConnectionService(): await cls._try_enter_game() await cls._try_send_piece() + await cls._try_send_message() await cls._try_receive_message() # if conection is closed, exit loop @@ -97,6 +119,18 @@ class _NetworkConnectionService(): await cls._websocket.send(json_message) MultiplayerService._send_piece_queue.task_done() + @classmethod + async def _try_send_message(cls) -> None: + # if no messages to proccess, return + if MultiplayerService._send_message_queue.empty(): + return + + # get next message to send and send to server + message = MultiplayerService._send_message_queue.get() + + await cls._websocket.send(message) + MultiplayerService._send_message_queue.task_done() + @classmethod async def _try_receive_message(cls) -> None: try: @@ -104,13 +138,19 @@ class _NetworkConnectionService(): done, pending = await asyncio.wait({task}, timeout=8e-3) # TODO experiment with the timeout if task in done: - data = json.loads(await task) + json_str = await task + if json_str == "pong": + print("pong") + cls._pending_receive_task = None + return + + data = json.loads(json_str) print(data) if data["type"] == "wait_for_opponent": - print("Wait for my opponent!") + MultiplayerService._receive_message_queue.put(MultiplayerService.WAIT_FOR_OPPONENT) if data["type"] == "start_game": - print("Start the game!") + MultiplayerService._receive_message_queue.put(MultiplayerService.START_GAME) if data["type"] == "receive_piece": print("Receive a piece!") MultiplayerService._receive_piece_queue.put(PieceDto.create(data["piece"])) diff --git a/tetri5/scene.py b/tetri5/scene.py index 71f6ced..7e61da5 100644 --- a/tetri5/scene.py +++ b/tetri5/scene.py @@ -170,6 +170,7 @@ class ConnectionScene(Scene): def __init__(self, change_scene: FunctionType) -> None: self._background_color = pygame.Color(ConfigurationManager.get("color", "window-bg")) self._is_connecting = False + self._waiting_for_opponent = False self._game_id_label_pos = ConfigurationManager.get("position", "game-id-label") self._game_id_label = "Enter Game Id: " self._game_id = "_" @@ -177,16 +178,24 @@ class ConnectionScene(Scene): self._cursor_blink_acc = 0 # blink accumulator self._connecting_label_pos = ConfigurationManager.get("position", "connecting-label") self._connecting_label = "Connecting" + self._waiting_for_opponent_label_pos = ConfigurationManager.get("position", "waiting-for-opponent-label") + self._waiting_for_opponent_label = "Waiting for opponent" self._period_blink_interval = ConfigurationManager.get("engine", "period-blink-interval") self._period_blink_acc = 0 # period accumulator + self._ping_interval = ConfigurationManager.get("engine", "ping-interval") + self._ping_acc = 0 # ping accumulator + + self._change_scene = change_scene def draw(self, surface: pygame.Surface) -> None: surface.fill(self._background_color) - if not self._is_connecting: + if not self._is_connecting and not self._waiting_for_opponent: TextGenerator.draw(self._game_id_label + self._game_id, self._game_id_label_pos, surface) - else: + elif self._is_connecting and not self._waiting_for_opponent: TextGenerator.draw(self._connecting_label, self._connecting_label_pos, surface) + else: + TextGenerator.draw(self._waiting_for_opponent_label, self._waiting_for_opponent_label_pos, surface) def update(self, elapsed_time: int) -> None: # cursor blink logic @@ -198,8 +207,8 @@ class ConnectionScene(Scene): else: self._game_id += "_" - # period ellipsis logic - if self._is_connecting: + # period ellipsis logic for connecting + if self._is_connecting and not self._waiting_for_opponent: self._period_blink_acc += elapsed_time if self._period_blink_acc >= self._period_blink_interval: self._period_blink_acc = 0 @@ -209,6 +218,17 @@ class ConnectionScene(Scene): else: self._connecting_label = self._connecting_label.replace(".", "") + # period ellipsis logic for waiting on opponent + if self._waiting_for_opponent: + self._period_blink_acc += elapsed_time + if self._period_blink_acc >= self._period_blink_interval: + self._period_blink_acc = 0 + period_count = self._waiting_for_opponent_label.count(".") + if period_count < self.MAX_PERIOD_COUNT: + self._waiting_for_opponent_label += "." + else: + self._waiting_for_opponent_label = self._waiting_for_opponent_label.replace(".", "") + # keyboard input for event in pygame.event.get(pygame.KEYDOWN): # user input logic @@ -225,6 +245,19 @@ class ConnectionScene(Scene): self._is_connecting = True MultiplayerService.init() MultiplayerService.enter_game(self._game_id) + + # server messaging logic + self._ping_acc += elapsed_time + message = MultiplayerService.try_receive_message(); + if message: # TODO remove later, only for testing + print(message) + if message == MultiplayerService.WAIT_FOR_OPPONENT: + self._waiting_for_opponent = True + if message == MultiplayerService.START_GAME: + self._change_scene(MultiplayerScene(self._change_scene)) + if message is None and self._ping_acc >= self._ping_interval: + self._ping_acc = 0 + MultiplayerService.send_message("ping") """ TODO """