diff --git a/games/models.py b/games/models.py index a470478..2f2664e 100644 --- a/games/models.py +++ b/games/models.py @@ -16,6 +16,11 @@ class GameModel(models.Model): def start(self): self.started = True + def finish(self, winner_id): + self.winner_id = winner_id + self.finished = True + self.save() + def get_players_id(self): return [game_player.player_id for game_player in GameMembersModel.objects.filter(game_id = self.pk)] diff --git a/games/objects/Game.py b/games/objects/Game.py index b2ae180..0c284fa 100644 --- a/games/objects/Game.py +++ b/games/objects/Game.py @@ -22,15 +22,22 @@ from ..routine import routine import threading +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from .GameManager import GameManager + class Game(AbstractRoom): - def __init__(self, game_id): + def __init__(self, game_id: int, game_manager): super().__init__(None) + self.game_manager: GameManager = game_manager + self.ball: Ball = Ball() self.model: GameModel = GameModel.objects.get(pk = game_id) - self.started = False + self.stopped: bool = False radius: float = min(config.MAP_SIZE_X, config.MAP_SIZE_Y) / 2 - 10 @@ -105,6 +112,12 @@ class Game(AbstractRoom): return False return True + def nobody_is_here(self): + for player in self.players: + if player.is_connected(): + return False + return len(self.spectators) == 0 + def _player_join(self, user_id: int, socket: WebsocketConsumer): player = self.get_player_by_user_id(user_id) @@ -127,7 +140,14 @@ class Game(AbstractRoom): def _update_player(self, player: Player): self._updated_players.append(player) + def finish(self, winner: Player): + self.model.finish(winner.user_id) + def _player_leave(self, player: Player): + if (self.nobody_is_here()): + if (self.model.started): + self.finish(player) + return self._update_player(player) def _spectator_join(self, user_id: int, socket: WebsocketConsumer): @@ -149,9 +169,8 @@ class Game(AbstractRoom): return member def start(self): - if (self.started == True): + if (self.model.started == True): return - self.started = True self.model.start() def leave(self, member: AbstractRoomMember): @@ -159,6 +178,10 @@ class Game(AbstractRoom): self._player_leave(member) elif (isinstance(member, Spectator)): self._spectator_leave(member) + if (self.nobody_is_here()): + self.stopped = True + self.thread.join(10) + self.game_manager.remove(self) def to_dict(self): diff --git a/games/objects/GameManager.py b/games/objects/GameManager.py index 1f5eba5..0251f9e 100644 --- a/games/objects/GameManager.py +++ b/games/objects/GameManager.py @@ -1,12 +1,15 @@ +from ..models import GameModel from .Game import Game -from ..models import GameModel class GameManager(): def __init__(self) -> None: self._game_list: list[Game] = [] + def remove(self, game: Game): + self._game_list.remove(game) + def get(self, game_id: int) -> Game: if (not GameModel.objects.filter(pk = game_id, finished = False).exists()): @@ -17,7 +20,7 @@ class GameManager(): if (game.game_id == game_id): return game - game: Game = Game(game_id) + game: Game = Game(game_id, self) self._game_list.append(game) diff --git a/games/routine.py b/games/routine.py index fda9e84..1e551f5 100644 --- a/games/routine.py +++ b/games/routine.py @@ -253,7 +253,7 @@ async def update_ball(game: Game, impact_data: dict) -> None: await SyncToAsync(game.broadcast)("update_ball", game.ball.to_dict()) -async def render(game: Game): +async def render_ball(game: Game): while True: @@ -262,16 +262,30 @@ async def render(game: Game): impact_data: dict = get_impact_data(segments, game.ball) await update_ball(game, impact_data) - - -def routine(game: Game): - - asyncio.run(render(game)) - + +async def render_players(game: Game): + while True: + for player in game._updated_players: game.broadcast("update_paddle", player.to_dict(), [player]) game._updated_players.clear() - sleep(1 / config.SERVER_TPS) \ No newline at end of file + await asyncio.sleep(1 / config.SERVER_TPS) + +async def render(game: Game): + + routine_ball = asyncio.create_task(render_ball(game)) + routine_players = asyncio.create_task(render_players(game)) + + while(True): + if (game.stopped): + routine_ball.cancel() + routine_players.cancel() + return + await asyncio.sleep(0.3) + +def routine(game: Game): + + asyncio.run(render(game))