193 lines
5.7 KiB
Python
193 lines
5.7 KiB
Python
from transcendence.abstract.AbstractRoom import AbstractRoom
|
|
from transcendence.abstract.AbstractRoomMember import AbstractRoomMember
|
|
|
|
from channels.generic.websocket import WebsocketConsumer
|
|
|
|
from asgiref.sync import async_to_sync
|
|
|
|
from .Ball import Ball
|
|
from .Player import Player
|
|
from .Spectator import Spectator
|
|
from .Wall import Wall
|
|
from .Point import Point
|
|
from .Segment import Segment
|
|
|
|
import math
|
|
|
|
from .. import config
|
|
|
|
from ..models import GameModel
|
|
|
|
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: 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.stopped: bool = False
|
|
|
|
radius: float = min(config.MAP_SIZE_X, config.MAP_SIZE_Y) / 2 - 10
|
|
|
|
players_id: list[int] = self.model.get_players_id()
|
|
|
|
nb_sides = len(players_id) * 2
|
|
|
|
polygon: list[Point] = []
|
|
|
|
for i in range(nb_sides):
|
|
|
|
angle: float = (i * 2 * math.pi / nb_sides) + (math.pi * 3 / nb_sides)
|
|
|
|
x: float = round(config.MAP_CENTER_X + radius * math.cos(angle))
|
|
y: float = round(config.MAP_CENTER_Y + radius * math.sin(angle))
|
|
|
|
polygon.append(Point(x, y))
|
|
|
|
segments: list[Point] = []
|
|
for i in range(nb_sides):
|
|
segments.append(Segment(polygon[i], polygon[(i + 1) % nb_sides]))
|
|
|
|
self.players: list[Player] = []
|
|
for i, player_id in enumerate(players_id):
|
|
player = Player(self, player_id, None, segments[i * 2])
|
|
self.players.append(player)
|
|
|
|
self.spectators: list[Spectator] = []
|
|
|
|
self.walls: list[Wall] = []
|
|
|
|
for i in range(1, nb_sides, 2):
|
|
self.walls.append(Wall(segments[i]))
|
|
|
|
self._updated_players: list[Player] = []
|
|
|
|
self.game_id: int = game_id
|
|
|
|
self.thread = threading.Thread(target = routine, args=(self,))
|
|
|
|
self.thread.start()
|
|
|
|
def get_players_id(self):
|
|
return [player.user_id for player in self.players]
|
|
|
|
def get_players_connected(self) -> list[Player]:
|
|
return [player for player in self.players if player.is_connected()]
|
|
|
|
def broadcast(self, detail: str, data: dict = {}, excludeds: list[Spectator | Player] = []):
|
|
|
|
members: list[Player | Spectator] = self.get_players_connected() + self.spectators
|
|
|
|
for excluded in excludeds:
|
|
if (excluded in members):
|
|
members.remove(excluded)
|
|
|
|
for member in members:
|
|
member.send(detail, data)
|
|
|
|
def get_player_by_user_id(self, user_id: int) -> Player:
|
|
for player in self.players:
|
|
if (player.user_id == user_id):
|
|
return player
|
|
return None
|
|
|
|
def _send_game_data(self, member: Spectator | Player):
|
|
member.send("init_game", self.to_dict())
|
|
|
|
def everbody_is_here(self):
|
|
for player in self.players:
|
|
if not player.is_connected():
|
|
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)
|
|
if (player is None):
|
|
return None
|
|
|
|
# check if player is already connected
|
|
if (player.is_connected()):
|
|
player.disconnect(1001)
|
|
|
|
player.socket = socket
|
|
|
|
if (self.everbody_is_here()):
|
|
self.start()
|
|
|
|
self._update_player(player)
|
|
|
|
return player
|
|
|
|
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):
|
|
|
|
spectator: Spectator = Spectator(user_id, socket, self)
|
|
|
|
self.spectators.append(spectator)
|
|
|
|
return spectator
|
|
|
|
def _spectator_leave(self, spectator: Spectator):
|
|
self.spectators.remove(spectator)
|
|
|
|
def join(self, user_id: int, socket: WebsocketConsumer) -> Spectator | Player:
|
|
member: Player = self._player_join(user_id, socket)
|
|
if (member is None):
|
|
member: Spectator = self._spectator_join(user_id, socket)
|
|
self._send_game_data(member)
|
|
return member
|
|
|
|
def start(self):
|
|
if (self.model.started == True):
|
|
return
|
|
self.model.start()
|
|
|
|
def leave(self, member: AbstractRoomMember):
|
|
if (isinstance(member, Player)):
|
|
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):
|
|
|
|
data: dict = {"ball": self.ball.to_dict(),
|
|
"players": [player.to_dict() for player in self.players],
|
|
"walls": [wall.to_dict() for wall in self.walls],
|
|
}
|
|
|
|
return data |