core: fix: matchmaking and game
This commit is contained in:
parent
d31d3e053e
commit
e125eb16c7
@ -21,12 +21,12 @@ class MatchMaking
|
|||||||
* @param {Number} mode The number of players in a game
|
* @param {Number} mode The number of players in a game
|
||||||
* @returns {Promise<?>}
|
* @returns {Promise<?>}
|
||||||
*/
|
*/
|
||||||
async start(receive_func, disconnect_func, gamemode, mode)
|
async start(receive_func, disconnect_func, game_type, mode)
|
||||||
{
|
{
|
||||||
if (!await this.client.isAuthenticated())
|
if (!await this.client.isAuthenticated())
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
let url = `${window.location.protocol[4] === 's' ? 'wss' : 'ws'}://${window.location.host}/ws/matchmaking/${gamemode}/${mode}`;
|
let url = `${window.location.protocol[4] === 's' ? 'wss' : 'ws'}://${window.location.host}/ws/matchmaking/${game_type}/${mode}`;
|
||||||
|
|
||||||
this._socket = new WebSocket(url);
|
this._socket = new WebSocket(url);
|
||||||
|
|
||||||
|
@ -19,7 +19,7 @@ export default class extends AbstractAuthenticatedView {
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
await client.matchmaking.start(this.onreceive.bind(this), this.ondisconnect.bind(this), this.gamemode_input.value, this.nb_players_input.value);
|
await client.matchmaking.start(this.onreceive.bind(this), this.ondisconnect.bind(this), this.game_type_input.value, this.nb_players_input.value);
|
||||||
|
|
||||||
this.button.innerHTML = lang.get("matchmakingStopSearch");
|
this.button.innerHTML = lang.get("matchmakingStopSearch");
|
||||||
}
|
}
|
||||||
@ -34,10 +34,10 @@ export default class extends AbstractAuthenticatedView {
|
|||||||
{
|
{
|
||||||
if (data.detail === "game_found")
|
if (data.detail === "game_found")
|
||||||
{
|
{
|
||||||
if (this.gamemode_input.value == "pong")
|
if (this.game_type_input.value == "pong")
|
||||||
navigateTo(`/games/${data.gamemode}/${data.game_id}`);
|
navigateTo(`/games/${data.game_type}/${data.game_id}`);
|
||||||
else
|
else
|
||||||
navigateTo(`/games/${data.gamemode}/${data.game_id}`);
|
navigateTo(`/games/${data.game_type}/${data.game_id}`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.display_data(data);
|
this.display_data(data);
|
||||||
@ -51,7 +51,7 @@ export default class extends AbstractAuthenticatedView {
|
|||||||
|
|
||||||
addEnterEvent()
|
addEnterEvent()
|
||||||
{
|
{
|
||||||
[this.nb_players_input, this.gamemode_input].forEach((input) => {
|
[this.nb_players_input, this.game_type_input].forEach((input) => {
|
||||||
|
|
||||||
input.addEventListener('keydown', async ev => {
|
input.addEventListener('keydown', async ev => {
|
||||||
|
|
||||||
@ -74,13 +74,13 @@ export default class extends AbstractAuthenticatedView {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
addChangeGameModeEvent()
|
addChangegame_typeEvent()
|
||||||
{
|
{
|
||||||
let nb_players_div = document.getElementById("nb-players-div");
|
let nb_players_div = document.getElementById("nb-players-div");
|
||||||
|
|
||||||
this.gamemode_input.addEventListener("change", () => {
|
this.game_type_input.addEventListener("change", () => {
|
||||||
|
|
||||||
if (this.gamemode_input.value === "tictactoe")
|
if (this.game_type_input.value === "tictactoe")
|
||||||
{
|
{
|
||||||
nb_players_div.style.display = 'none';
|
nb_players_div.style.display = 'none';
|
||||||
this.nb_players_input.value = 2;
|
this.nb_players_input.value = 2;
|
||||||
@ -96,7 +96,7 @@ export default class extends AbstractAuthenticatedView {
|
|||||||
addEvents()
|
addEvents()
|
||||||
{
|
{
|
||||||
this.addEnterEvent();
|
this.addEnterEvent();
|
||||||
this.addChangeGameModeEvent();
|
this.addChangegame_typeEvent();
|
||||||
this.addChangeNbPlayersEvent();
|
this.addChangeNbPlayersEvent();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -104,7 +104,7 @@ export default class extends AbstractAuthenticatedView {
|
|||||||
{
|
{
|
||||||
this.button = document.getElementById("toggle-search");
|
this.button = document.getElementById("toggle-search");
|
||||||
this.nb_players_input = document.getElementById("nb-players-input");
|
this.nb_players_input = document.getElementById("nb-players-input");
|
||||||
this.gamemode_input = document.getElementById("gamemode-input");
|
this.game_type_input = document.getElementById("game-type-input");
|
||||||
|
|
||||||
this.button.onclick = this.toggle_search.bind(this);
|
this.button.onclick = this.toggle_search.bind(this);
|
||||||
|
|
||||||
@ -117,12 +117,12 @@ export default class extends AbstractAuthenticatedView {
|
|||||||
<div class='border border-2 rounded bg-light-subtle mx-auto p-2 col-md-7 col-lg-4'>
|
<div class='border border-2 rounded bg-light-subtle mx-auto p-2 col-md-7 col-lg-4'>
|
||||||
<h4 class='text-center fw-semibold mb-4' id="title">${lang.get("matchmakingTitle")}</h4>
|
<h4 class='text-center fw-semibold mb-4' id="title">${lang.get("matchmakingTitle")}</h4>
|
||||||
<div>
|
<div>
|
||||||
<div class='form-floating mb-2' id='gamemode-div'>
|
<div class='form-floating mb-2' id='game_type-div'>
|
||||||
<select class='form-control' id='gamemode-input'>
|
<select class='form-control' id='game-type-input'>
|
||||||
<option value='pong'>Pong</option>
|
<option value='pong'>Pong</option>
|
||||||
<option value='tictactoe'>ticTacToe</option>
|
<option value='tictactoe'>ticTacToe</option>
|
||||||
</select>
|
</select>
|
||||||
<label for='gamemode-input'>${lang.get("gamemodeChoice")}</label>
|
<label for='game-type-input'>${lang.get("game_typeChoice")}</label>
|
||||||
</div>
|
</div>
|
||||||
<div class='form-floating mb-2' id='nb-players-div'>
|
<div class='form-floating mb-2' id='nb-players-div'>
|
||||||
<input type='number' min='2' value='2' max='4' class='form-control' id='nb-players-input' placeholder='${lang.get("matchmakingNbPlayers")}'>
|
<input type='number' min='2' value='2' max='4' class='form-control' id='nb-players-input' placeholder='${lang.get("matchmakingNbPlayers")}'>
|
||||||
|
@ -3,25 +3,24 @@ from __future__ import annotations
|
|||||||
from django.db import models
|
from django.db import models
|
||||||
from django.db.models import QuerySet, CASCADE
|
from django.db.models import QuerySet, CASCADE
|
||||||
|
|
||||||
from profiles.models import ProfileModel
|
from django.contrib.auth.models import User
|
||||||
|
|
||||||
import time
|
import time
|
||||||
|
|
||||||
# Create your models here.
|
|
||||||
|
|
||||||
class GameModel(models.Model):
|
class GameModel(models.Model):
|
||||||
|
|
||||||
finished = models.BooleanField(default = False)
|
finished = models.BooleanField(default = False)
|
||||||
started = models.BooleanField(default = False)
|
started = models.BooleanField(default = False)
|
||||||
winner = models.ForeignKey(ProfileModel, on_delete=CASCADE, null=True, blank=True)
|
winner = models.ForeignKey(User, on_delete=CASCADE, null=True, blank=True)
|
||||||
start_timestamp = models.BigIntegerField(null = True, blank = True)
|
start_timestamp = models.BigIntegerField(null = True, blank = True)
|
||||||
stop_timestamp = models.BigIntegerField(null = True, blank = True)
|
stop_timestamp = models.BigIntegerField(null = True, blank = True)
|
||||||
game_type = models.CharField(max_length = 60, default = "pong")
|
game_type = models.CharField(max_length = 60, default = "pong")
|
||||||
|
|
||||||
def create(self, players: list[ProfileModel]):
|
def create(self, players: list[User]):
|
||||||
self.save()
|
self.save()
|
||||||
for player in players:
|
for player in players:
|
||||||
GameMembersModel(game = self.pk, player=player).save()
|
GameMembersModel(game = self, player=player).save()
|
||||||
return self.pk
|
return self.pk
|
||||||
|
|
||||||
def start(self):
|
def start(self):
|
||||||
@ -35,9 +34,12 @@ class GameModel(models.Model):
|
|||||||
self.stop_timestamp = round(time.time() * 1000, 1)
|
self.stop_timestamp = round(time.time() * 1000, 1)
|
||||||
self.save()
|
self.save()
|
||||||
|
|
||||||
def get_players(self) -> list[ProfileModel]:
|
def get_players(self) -> list[User]:
|
||||||
return [game_player.player for game_player in GameMembersModel.objects.filter(game = self)]
|
return [game_player.player for game_player in GameMembersModel.objects.filter(game = self)]
|
||||||
|
|
||||||
|
def get_players_profiles(self) -> list[User]:
|
||||||
|
return [game_player.player.profilemodel for game_player in GameMembersModel.objects.filter(game = self)]
|
||||||
|
|
||||||
def get_score_by_player_id(self, player_id: int) -> list[int]:
|
def get_score_by_player_id(self, player_id: int) -> list[int]:
|
||||||
query: QuerySet = GameGoalModel.objects.filter(game_id = self.pk, player_id = player_id)
|
query: QuerySet = GameGoalModel.objects.filter(game_id = self.pk, player_id = player_id)
|
||||||
score_data: list[int] = [game_goal.timestamp for game_goal in query]
|
score_data: list[int] = [game_goal.timestamp for game_goal in query]
|
||||||
@ -56,10 +58,10 @@ class GameModel(models.Model):
|
|||||||
|
|
||||||
class GameMembersModel(models.Model):
|
class GameMembersModel(models.Model):
|
||||||
game = models.ForeignKey(GameModel, on_delete=CASCADE)
|
game = models.ForeignKey(GameModel, on_delete=CASCADE)
|
||||||
player = models.ForeignKey(ProfileModel, on_delete=CASCADE)
|
player = models.ForeignKey(User, on_delete=CASCADE)
|
||||||
|
|
||||||
class GameGoalModel(models.Model):
|
class GameGoalModel(models.Model):
|
||||||
|
|
||||||
game = models.ForeignKey(GameModel, on_delete=CASCADE)
|
game = models.ForeignKey(GameModel, on_delete=CASCADE)
|
||||||
player = models.ForeignKey(ProfileModel, on_delete=CASCADE)
|
player = models.ForeignKey(User, on_delete=CASCADE)
|
||||||
timestamp = models.IntegerField()
|
timestamp = models.IntegerField()
|
@ -6,6 +6,8 @@ from .ASpectator import ASpectator
|
|||||||
|
|
||||||
from ..models import GameModel
|
from ..models import GameModel
|
||||||
|
|
||||||
|
from django.contrib.auth.models import User
|
||||||
|
|
||||||
class AGame(AbstractRoom):
|
class AGame(AbstractRoom):
|
||||||
|
|
||||||
def __init__(self, game_type: str, game_id: int, game_manager):
|
def __init__(self, game_type: str, game_id: int, game_manager):
|
||||||
@ -16,23 +18,23 @@ class AGame(AbstractRoom):
|
|||||||
|
|
||||||
self.model: GameModel = GameModel.objects.get(pk = game_id, game_type = game_type)
|
self.model: GameModel = GameModel.objects.get(pk = game_id, game_type = game_type)
|
||||||
|
|
||||||
players_id: list[int] = self.model.get_players_id()
|
players: list[User] = self.model.get_players()
|
||||||
|
|
||||||
self.players: list[APlayer] = [APlayer(player_id, None, self) for player_id in players_id]
|
self.players: list[APlayer] = [APlayer(player.pk, None, self) for player in players]
|
||||||
|
|
||||||
self.spectators: list[ASpectator] = []
|
self.spectators: list[ASpectator] = []
|
||||||
|
|
||||||
self.game_id: int = game_id
|
self.game_id: int = game_id
|
||||||
|
|
||||||
def get_players_id(self) -> list[int]:
|
def get_players_id(self) -> list[int]:
|
||||||
return [player.user_id for player in self.players]
|
return [player.pk for player in self.players]
|
||||||
|
|
||||||
def get_players_connected(self) -> list[APlayer]:
|
def get_players_connected(self) -> list[APlayer]:
|
||||||
return [player for player in self.players if player.is_connected()]
|
return [player for player in self.players if player.is_connected()]
|
||||||
|
|
||||||
def get_player_by_user_id(self, user_id: int) -> APlayer:
|
def get_player_by_user_id(self, user_id: int) -> APlayer:
|
||||||
for player in self.players:
|
for player in self.players:
|
||||||
if (player.user_id == user_id):
|
if (player.user.pk == user_id):
|
||||||
return player
|
return player
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
@ -10,9 +10,6 @@ if TYPE_CHECKING:
|
|||||||
|
|
||||||
class APlayer(ASpectator):
|
class APlayer(ASpectator):
|
||||||
|
|
||||||
def __init__(self, user_id: int, socket: WebsocketConsumer, game: AGame):
|
|
||||||
super().__init__(user_id, socket, game)
|
|
||||||
|
|
||||||
def is_connected(self) -> bool:
|
def is_connected(self) -> bool:
|
||||||
return self.socket != None
|
return self.socket != None
|
||||||
|
|
||||||
|
@ -3,6 +3,8 @@ from channels.generic.websocket import WebsocketConsumer
|
|||||||
|
|
||||||
from transcendence.abstract.AbstractRoomMember import AbstractRoomMember
|
from transcendence.abstract.AbstractRoomMember import AbstractRoomMember
|
||||||
|
|
||||||
|
from django.contrib.auth.models import User
|
||||||
|
|
||||||
from typing import TYPE_CHECKING
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
@ -10,8 +12,8 @@ if TYPE_CHECKING:
|
|||||||
|
|
||||||
class ASpectator(AbstractRoomMember):
|
class ASpectator(AbstractRoomMember):
|
||||||
|
|
||||||
def __init__(self, user_id: int, socket: WebsocketConsumer, game):
|
def __init__(self, user: User, socket: WebsocketConsumer, game):
|
||||||
|
|
||||||
super().__init__(user_id, socket)
|
super().__init__(user, socket)
|
||||||
|
|
||||||
self.game: AGame = game
|
self.game: AGame = game
|
@ -22,7 +22,7 @@ import threading
|
|||||||
from typing import TYPE_CHECKING
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
pass
|
from profiles.models import ProfileModel
|
||||||
|
|
||||||
class PongGame(AGame):
|
class PongGame(AGame):
|
||||||
|
|
||||||
@ -36,7 +36,7 @@ class PongGame(AGame):
|
|||||||
|
|
||||||
radius: float = min(config.MAP_SIZE_X, config.MAP_SIZE_Y) / 2 - 10
|
radius: float = min(config.MAP_SIZE_X, config.MAP_SIZE_Y) / 2 - 10
|
||||||
|
|
||||||
players_id: list[int] = self.model.get_players_id()
|
players: list[ProfileModel] = self.model.get_players()
|
||||||
|
|
||||||
nb_sides = 4
|
nb_sides = 4
|
||||||
|
|
||||||
@ -58,16 +58,16 @@ class PongGame(AGame):
|
|||||||
self.walls: list[Wall]
|
self.walls: list[Wall]
|
||||||
self.players: list[PongPlayer]
|
self.players: list[PongPlayer]
|
||||||
|
|
||||||
nb_players: int = len(players_id)
|
nb_players: int = len(players)
|
||||||
if (nb_players == 2):
|
if (nb_players == 2):
|
||||||
self.players = [PongPlayer(self, players_id[0], None, segments[0]), PongPlayer(self, players_id[1], None, segments[2])]
|
self.players = [PongPlayer(self, players[0], None, segments[0]), PongPlayer(self, players[1], None, segments[2])]
|
||||||
self.walls = [Wall(segments[1].start, segments[1].stop), Wall(segments[3].start, segments[3].stop)]
|
self.walls = [Wall(segments[1].start, segments[1].stop), Wall(segments[3].start, segments[3].stop)]
|
||||||
else:
|
else:
|
||||||
self.players = []
|
self.players = []
|
||||||
self.walls = []
|
self.walls = []
|
||||||
for i in range(4):
|
for i in range(4):
|
||||||
if (i < nb_players):
|
if (i < nb_players):
|
||||||
self.players.append(PongPlayer(self, players_id[i], None, segments[i]))
|
self.players.append(PongPlayer(self, players[i], None, segments[i]))
|
||||||
else:
|
else:
|
||||||
self.walls.append(Wall(segments[i]))
|
self.walls.append(Wall(segments[i]))
|
||||||
|
|
||||||
|
@ -17,9 +17,9 @@ if TYPE_CHECKING:
|
|||||||
|
|
||||||
class PongPlayer(APlayer):
|
class PongPlayer(APlayer):
|
||||||
|
|
||||||
def __init__(self, game: PongGame, user_id: int, socket: WebsocketConsumer, rail: Segment) -> None:
|
def __init__(self, game: PongGame, user: User, socket: WebsocketConsumer, rail: Segment) -> None:
|
||||||
|
|
||||||
super().__init__(user_id, socket, game)
|
super().__init__(user, socket, game)
|
||||||
|
|
||||||
self.position: Position = Position(0.5, 0)
|
self.position: Position = Position(0.5, 0)
|
||||||
|
|
||||||
@ -29,8 +29,6 @@ class PongPlayer(APlayer):
|
|||||||
|
|
||||||
self.game: PongGame
|
self.game: PongGame
|
||||||
|
|
||||||
self.username: str = User.objects.get(pk = self.user_id).username
|
|
||||||
|
|
||||||
def eliminate(self):
|
def eliminate(self):
|
||||||
|
|
||||||
self.disconnect(1000)
|
self.disconnect(1000)
|
||||||
@ -119,8 +117,8 @@ class PongPlayer(APlayer):
|
|||||||
def to_dict(self) -> dict:
|
def to_dict(self) -> dict:
|
||||||
|
|
||||||
data = {
|
data = {
|
||||||
"username": self.username,
|
"username": self.user.username,
|
||||||
"id": self.user_id,
|
"id": self.user.pk,
|
||||||
"position": self.position.to_dict(),
|
"position": self.position.to_dict(),
|
||||||
"score": self.score,
|
"score": self.score,
|
||||||
|
|
||||||
|
@ -270,7 +270,6 @@ async def render_ball(game: PongGame):
|
|||||||
async def render_players(game: PongGame):
|
async def render_players(game: PongGame):
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
|
|
||||||
for player in game._updated_players:
|
for player in game._updated_players:
|
||||||
await SyncToAsync(game.broadcast)("update_player", player.to_dict(), [player])
|
await SyncToAsync(game.broadcast)("update_player", player.to_dict(), [player])
|
||||||
|
|
||||||
|
@ -3,7 +3,8 @@ from rest_framework import serializers
|
|||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
from django.db.models import QuerySet
|
from django.db.models import QuerySet
|
||||||
|
|
||||||
from .models import GameModel, GameMembersModel
|
from .models import GameModel
|
||||||
|
from profiles.serializers.ProfileSerializer import ProfileSerializer
|
||||||
|
|
||||||
class GameSerializer(serializers.ModelSerializer):
|
class GameSerializer(serializers.ModelSerializer):
|
||||||
|
|
||||||
@ -28,19 +29,4 @@ class GameSerializer(serializers.ModelSerializer):
|
|||||||
return "waiting"
|
return "waiting"
|
||||||
|
|
||||||
def get_players(self, instance: GameModel):
|
def get_players(self, instance: GameModel):
|
||||||
players_data: list = []
|
return ProfileSerializer(instance.get_players_profiles(), many=True).data
|
||||||
for player_id in instance.get_players_id():
|
|
||||||
query: QuerySet = User.objects.filter(pk = player_id)
|
|
||||||
username: str = "Deleted User"
|
|
||||||
if (query.exists()):
|
|
||||||
username = query[0].username
|
|
||||||
|
|
||||||
data: dict = {
|
|
||||||
"id": player_id,
|
|
||||||
"username": username,
|
|
||||||
"score": instance.get_score_by_player_id(player_id)
|
|
||||||
}
|
|
||||||
|
|
||||||
players_data.append(data)
|
|
||||||
|
|
||||||
return players_data
|
|
@ -6,15 +6,10 @@ from games.models import GameModel
|
|||||||
|
|
||||||
import json
|
import json
|
||||||
|
|
||||||
from .models import Waiter, WaitingRoom, WaitingRoomManager, normal
|
from .models import Waiter, WaitingRoom, waiting_room_manager
|
||||||
|
|
||||||
class MatchMaking(WebsocketConsumer):
|
class MatchMaking(WebsocketConsumer):
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
|
||||||
super().__init__(*args, **kwargs)
|
|
||||||
self.channel_name = "matchmaking"
|
|
||||||
self.group_name = "matchmaking"
|
|
||||||
|
|
||||||
def connect(self):
|
def connect(self):
|
||||||
|
|
||||||
user: User = self.scope["user"]
|
user: User = self.scope["user"]
|
||||||
@ -22,14 +17,12 @@ class MatchMaking(WebsocketConsumer):
|
|||||||
if (user.is_anonymous or not user.is_authenticated):
|
if (user.is_anonymous or not user.is_authenticated):
|
||||||
return
|
return
|
||||||
|
|
||||||
self.channel_layer.group_add(self.group_name, self.channel_name)
|
|
||||||
|
|
||||||
self.mode: int = int(self.scope['url_route']['kwargs']['mode'])
|
self.mode: int = int(self.scope['url_route']['kwargs']['mode'])
|
||||||
self.gamemode: str = self.scope['url_route']['kwargs']['gamemode']
|
self.game_type: str = self.scope['url_route']['kwargs']['game_type']
|
||||||
self.group_name = self.mode
|
self.group_name = self.mode
|
||||||
|
|
||||||
waiting_room: WaitingRoom = normal.get(self.gamemode, self.mode)
|
self.waiting_room: WaitingRoom = waiting_room_manager.get(self.game_type, self.mode)
|
||||||
waiting_room.append(Waiter(user.pk, self))
|
self.waiting_room.append(Waiter(user, self))
|
||||||
|
|
||||||
if (self.mode < 2 or self.mode > 4):
|
if (self.mode < 2 or self.mode > 4):
|
||||||
data: dict = {
|
data: dict = {
|
||||||
@ -39,23 +32,22 @@ class MatchMaking(WebsocketConsumer):
|
|||||||
self.disconnect(1000)
|
self.disconnect(1000)
|
||||||
return
|
return
|
||||||
|
|
||||||
if (self.gamemode not in ["tictactoe", "pong"]):
|
if (self.game_type not in ["tictactoe", "pong"]):
|
||||||
data: dict = {
|
data: dict = {
|
||||||
"detail": "The gamemode must 'pong' or 'tictactoe'.",
|
"detail": "The game_type must 'pong' or 'tictactoe'.",
|
||||||
}
|
}
|
||||||
self.send(json.dumps(data))
|
self.send(json.dumps(data))
|
||||||
self.disconnect(1000)
|
self.disconnect(1000)
|
||||||
return
|
return
|
||||||
|
|
||||||
waiting_room.broadcast(f"{len(waiting_room)} / {waiting_room.mode}")
|
self.waiting_room.broadcast(f"{len(self.waiting_room)} / {self.waiting_room.mode}")
|
||||||
if (len(waiting_room) == waiting_room.mode):
|
if (len(self.waiting_room) == self.waiting_room.mode):
|
||||||
game_id: int = GameModel().create(self.gamemode, waiting_room.get_users_id())
|
game_id: int = GameModel(game_type=self.game_type).create(self.waiting_room.get_members())
|
||||||
waiting_room.broadcast("game_found", {"game_id": game_id, "gamemode": self.gamemode})
|
self.waiting_room.broadcast("game_found", {"game_id": game_id, "game_type": self.game_type})
|
||||||
waiting_room.clear()
|
|
||||||
|
|
||||||
def disconnect(self, close_code):
|
def disconnect(self, close_code):
|
||||||
super().close(close_code)
|
super().disconnect(close_code)
|
||||||
waiting_room: WaitingRoom = normal.get(self.gamemode, self.mode)
|
waiting_room: WaitingRoom = waiting_room_manager.get(self.game_type, self.mode)
|
||||||
waiter: Waiter = waiting_room.get_member_by_socket(self)
|
waiter: Waiter = waiting_room.get_member_by_socket(self)
|
||||||
if (waiter is not None):
|
if (waiter is not None):
|
||||||
waiting_room.remove(waiter, close_code)
|
waiting_room.remove(waiter)
|
@ -13,29 +13,44 @@ class Waiter(AbstractRoomMember):
|
|||||||
|
|
||||||
class WaitingRoom(AbstractRoom):
|
class WaitingRoom(AbstractRoom):
|
||||||
|
|
||||||
def __init__(self, room_manager, gamemode: str, mode: int):
|
def __init__(self, room_manager, game_type: str, mode: int):
|
||||||
|
|
||||||
super().__init__(room_manager)
|
super().__init__(room_manager)
|
||||||
self.mode = mode
|
self._member_list: set[Waiter]
|
||||||
self.gamemode = gamemode
|
|
||||||
|
self.mode: int = mode
|
||||||
|
self.game_type: str = game_type
|
||||||
|
|
||||||
def append(self, waiter: Waiter):
|
def append(self, waiter: Waiter):
|
||||||
tmp: Waiter = self.get_member_by_user_id(waiter.user_id)
|
|
||||||
|
tmp: Waiter = self.get_member_by_user(waiter.user)
|
||||||
if (tmp is not None):
|
if (tmp is not None):
|
||||||
tmp.send("Connection close: Another connection open with the same user id.")
|
tmp.send("Connection close: Another connection open with the same user id.")
|
||||||
self.remove(tmp)
|
self.remove(tmp)
|
||||||
|
|
||||||
waiter.socket.accept()
|
waiter.socket.accept()
|
||||||
self._member_list.append(waiter)
|
|
||||||
|
super().append(waiter)
|
||||||
|
|
||||||
class WaitingRoomManager(AbstractRoomManager):
|
class WaitingRoomManager(AbstractRoomManager):
|
||||||
|
|
||||||
def get(self, gamemode: str, mode: int):
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
|
||||||
|
self._room_list: set[WaitingRoom]
|
||||||
|
|
||||||
|
|
||||||
|
def get(self, game_type: str, mode: int) -> WaitingRoom:
|
||||||
|
|
||||||
for waiting_room in self._room_list:
|
for waiting_room in self._room_list:
|
||||||
waiting_room: WaitingRoom
|
waiting_room: WaitingRoom
|
||||||
if (waiting_room.mode == mode and waiting_room.gamemode == gamemode):
|
if (waiting_room.mode == mode and waiting_room.game_type == game_type):
|
||||||
return waiting_room
|
return waiting_room
|
||||||
tmp: WaitingRoom = WaitingRoom(self, gamemode, mode)
|
|
||||||
|
tmp: WaitingRoom = WaitingRoom(self, game_type, mode)
|
||||||
|
|
||||||
super().append(tmp)
|
super().append(tmp)
|
||||||
|
|
||||||
return tmp
|
return tmp
|
||||||
|
|
||||||
normal: WaitingRoomManager = WaitingRoomManager()
|
waiting_room_manager: WaitingRoomManager = WaitingRoomManager()
|
@ -2,5 +2,5 @@ from django.urls import re_path
|
|||||||
from . import consumers
|
from . import consumers
|
||||||
|
|
||||||
websocket_urlpatterns = [
|
websocket_urlpatterns = [
|
||||||
re_path(r'ws/matchmaking/(?P<gamemode>\w+)/(?P<mode>\d+)$', consumers.MatchMaking.as_asgi())
|
re_path(r'ws/matchmaking/(?P<game_type>\w+)/(?P<mode>\d+)$', consumers.MatchMaking.as_asgi())
|
||||||
]
|
]
|
||||||
|
@ -1,51 +1,57 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
from channels.generic.websocket import WebsocketConsumer
|
from channels.generic.websocket import WebsocketConsumer
|
||||||
|
|
||||||
from .AbstractRoomMember import AbstractRoomMember
|
from .AbstractRoomMember import AbstractRoomMember
|
||||||
|
|
||||||
|
from django.contrib.auth.models import User
|
||||||
|
|
||||||
|
from profiles.models import ProfileModel
|
||||||
|
|
||||||
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from .AbstractRoomManager import AbstractRoomManager
|
||||||
|
|
||||||
class AbstractRoom:
|
class AbstractRoom:
|
||||||
|
|
||||||
def __init__(self, room_manager):
|
def __init__(self, room_manager: AbstractRoomManager):
|
||||||
self._member_list: list[AbstractRoomMember] = []
|
self._member_list: set[AbstractRoomMember] = set()
|
||||||
self.room_manager = room_manager
|
self._room_manager: AbstractRoomManager = room_manager
|
||||||
|
|
||||||
def broadcast(self, detail: str, data: dict = {}):
|
def broadcast(self, detail: str, data: dict = {}, excludes: set[AbstractRoomMember] = set()) -> None:
|
||||||
for member in self._member_list:
|
|
||||||
member: AbstractRoomMember
|
members: set[AbstractRoomMember] = self._member_list - excludes
|
||||||
|
|
||||||
|
for member in members:
|
||||||
member.send(detail, data)
|
member.send(detail, data)
|
||||||
|
|
||||||
def clear(self):
|
def get_member_by_socket(self, socket: WebsocketConsumer) -> AbstractRoomMember | None:
|
||||||
self._member_list.clear()
|
|
||||||
|
|
||||||
def get_member_by_socket(self, socket: WebsocketConsumer):
|
|
||||||
for member in self._member_list:
|
for member in self._member_list:
|
||||||
member: AbstractRoomMember
|
if member.socket is socket:
|
||||||
if (member.socket is socket):
|
|
||||||
return member
|
return member
|
||||||
return None
|
|
||||||
|
|
||||||
def get_member_by_user_id(self, user_id: int):
|
def get_member_by_user(self, user: User) -> AbstractRoomMember:
|
||||||
|
|
||||||
for member in self._member_list:
|
for member in self._member_list:
|
||||||
member: AbstractRoomMember
|
if member.user == user:
|
||||||
if (member.user_id == user_id):
|
|
||||||
return member
|
return member
|
||||||
return None
|
|
||||||
|
|
||||||
|
def get_members_profiles(self) -> set[ProfileModel]:
|
||||||
|
return set(member.user.profilemodel for member in self._member_list)
|
||||||
|
|
||||||
def append(self, member: AbstractRoomMember):
|
def get_members(self) -> set[ProfileModel]:
|
||||||
self._member_list.append(member)
|
return set(member.user for member in self._member_list)
|
||||||
member.accept()
|
|
||||||
|
|
||||||
def remove(self, member: AbstractRoomMember, code: int = 1000):
|
def append(self, member: AbstractRoomMember) -> None:
|
||||||
|
self._member_list.add(member)
|
||||||
|
|
||||||
|
def remove(self, member: AbstractRoomMember) -> None:
|
||||||
self._member_list.remove(member)
|
self._member_list.remove(member)
|
||||||
member.socket.disconnect(code)
|
|
||||||
|
|
||||||
def empty(self):
|
def get_users(self) -> set[User]:
|
||||||
for _ in self._member_list:
|
return set(member.user for member in self._member_list)
|
||||||
return False
|
|
||||||
return True
|
|
||||||
|
|
||||||
def get_users_id(self):
|
def __len__(self) -> int:
|
||||||
return [member.user_id for member in self._member_list]
|
|
||||||
|
|
||||||
def __len__(self):
|
|
||||||
return len(self._member_list)
|
return len(self._member_list)
|
||||||
|
@ -5,8 +5,8 @@ class AbstractRoomManager:
|
|||||||
def __init__(self):
|
def __init__(self):
|
||||||
self._room_list: list[AbstractRoom] = []
|
self._room_list: list[AbstractRoom] = []
|
||||||
|
|
||||||
def remove(self, room: AbstractRoom):
|
def remove(self, room: AbstractRoom) -> None:
|
||||||
self._room_list.remove(room)
|
self._room_list.remove(room)
|
||||||
|
|
||||||
def append(self, room: AbstractRoom):
|
def append(self, room: AbstractRoom) -> None:
|
||||||
self._room_list.append(room)
|
self._room_list.append(room)
|
||||||
|
@ -1,14 +1,16 @@
|
|||||||
from channels.generic.websocket import WebsocketConsumer
|
from channels.generic.websocket import WebsocketConsumer
|
||||||
|
|
||||||
|
from django.contrib.auth.models import User
|
||||||
|
|
||||||
import json
|
import json
|
||||||
|
|
||||||
class AbstractRoomMember:
|
class AbstractRoomMember:
|
||||||
|
|
||||||
def __init__(self, user_id: int, socket: WebsocketConsumer):
|
def __init__(self, user: User, socket: WebsocketConsumer):
|
||||||
self.user_id: int = user_id
|
self.user: User = user
|
||||||
self.socket: WebsocketConsumer = socket
|
self.socket: WebsocketConsumer = socket
|
||||||
|
|
||||||
def send(self, detail: str, data: dict = {}):
|
def send(self, detail: str, data: dict = {}) -> None:
|
||||||
raw_data: dict = {"detail": detail}
|
raw_data: dict = {"detail": detail}
|
||||||
raw_data.update(data)
|
raw_data.update(data)
|
||||||
self.socket.send(text_data=json.dumps(raw_data))
|
self.socket.send(text_data=json.dumps(raw_data))
|
Loading…
Reference in New Issue
Block a user