feat: client/server game messages, WIP GameManager

parent 4a774722
<template>
<div id="app">
<HelloWorld msg="Salut Menteur !"/>
<ListenToSockets/>
<Sockets/>
<div id="game">
<label for="messages"> Choose a message:</label>
<select v-model="message" name="message" id="messages">
<option value="WAITING">J'attends</option>
<option value="READY">Prêt à jouer !</option>
<option value="BET">Pari plus haut</option>
<option value="MENTEUR">Menteur !</option>
</select>
<button v-on:click="sendMessage(message)">Envoyer</button>
</div>
</div>
</template>
......@@ -11,9 +21,8 @@
import Vuex from 'vuex'
import 'es6-promise/auto' // Needed for Promise polyfill
import VueSocketIO from 'vue-socket.io'
// import Game from "./components/Game";
import HelloWorld from "./components/HelloWorld";
import ListenToSockets from "./Sockets";
import Sockets from "./Sockets";
Vue.use(Vuex);
......@@ -54,7 +63,18 @@
name: "App",
components: {
HelloWorld,
ListenToSockets
Sockets
},
data: function () {
return {
message: "WAITING"
}
},
methods: {
sendMessage: function(message) {
console.log("User wants to send", message);
this.$socket.emit("message", message);
}
}
};
......@@ -69,4 +89,8 @@
color: #2c3e50;
margin-top: 60px;
}
#game {
margin-top: 20px;
}
</style>
......@@ -44,10 +44,15 @@
pingServer() {
// Send the "pingServer" event to the server.
if (this.isConnected) {
this.$socket.emit('pingServer', 'PING!');
this.sendMessage("Ping!");
console.log("Ping sent!");
}
},
sendMessage(message) {
this.$socket.emit('pingServer', message);
console.log("Message sent:", message);
},
logOn() {
this.$socket.onconnect();
},
......
......@@ -2,6 +2,7 @@
<div class="hello">
<h1>Game on!</h1>
<h2>{{ msg }}</h2>
<h3>Count: {{ count }}</h3>
<button @click="increment">+</button>
<button @click="decrement">-</button>
</div>
......
......@@ -6,12 +6,12 @@ from fastapi.exceptions import RequestValidationError
from starlette.exceptions import HTTPException
from starlette.responses import PlainTextResponse
from server.game.lobby import LobbyManager
from server.model.data import Game
# Game state
from server.model.players import RandomPlayer
from server.ws import sio
game = Game()
# Server
app = FastAPI()
......
from collections import defaultdict
from typing import List, Dict
from socketio import AsyncServer
from server.game.manager import ClientManager
from server.game.message import MessageToPlayer
from server.model.data import Game
from server.model.players import Player, Announce
class LobbyManager(ClientManager):
""" A ClientManager that handles a lobby, then orchestrates games.
"""
def __init__(self, sio: AsyncServer):
super().__init__()
self.last_announces: Dict[Player, Announce] = {}
self.lobby: Dict[Player, bool] = {}
self.games: List[Game] = []
self.sio = sio
@property
def nb_ready(self):
return len(self.players_ready)
@property
def players_ready(self):
return [k for k, v in self.lobby.items() if v]
async def add_player(self, player: Player, is_ready: bool = False) -> None:
self.lobby[player] = is_ready
print(f"Added {player} to a lobby with {len(self.lobby)} players.")
await self.sio.emit('messageChannel', "PONG")
def wants_to_play(self, player: Player):
self.lobby[player] = True
print(f"{player} ready to play! ({self.nb_ready} people ready)")
def announces(self, player: Player, announce: Announce):
self.last_announces[player] = announce
print(f"{player} ready to play! ({self.nb_ready} people ready)")
def start_game(self, max_players=2):
players = self.players_ready[:max_players]
self.games.append(Game(players, manager=self))
print(f"Game started : {' vs '.join([p.name for p in players])}")
def send(self, to: Player, message: MessageToPlayer, extra=None):
self.sio.send(message)
pass
from abc import ABC, abstractmethod
from typing import List, Optional
from server.game.message import MessageToPlayer
from server.model.players import Player
class ClientManager(ABC):
"""
A listener of game state that notifies clients.
"""
def __init__(self):
self.players: List[Player] = []
def notify(self, message: MessageToPlayer, only_for: Optional[Player] = None) -> None:
to = [only_for] if only_for else self.players
for p in to:
self.send(p, message)
@abstractmethod
def send(self, to: Player, message: MessageToPlayer, extra=None):
raise NotImplementedError("Send a message to clients ")
from enum import Enum
class MessageToPlayer(Enum):
Waiting = "WAITING_ROOM"
Ready = "READY_ROOM"
WaitTurn = "WAITING_TURN"
YourTurn = "YOUR_TURN"
Win = "WINNER"
Lose = "LOSER"
class MessageFromPlayer(Enum):
Wating = "WAITING"
Ready = "READY"
Bet = "BET"
Menteur = "MENTEUR"
......@@ -2,6 +2,7 @@ import itertools
from collections import defaultdict
from typing import List, Dict, Optional
from server.game.manager import ClientManager
from server.model.card import Card
from server.model.deck import Deck
from server.model.hand import Hand
......@@ -9,7 +10,11 @@ from server.model.players import Player
class Game:
def __init__(self, players=None, deck: Deck = Deck()):
def __init__(self,
players=None,
deck: Deck = Deck(),
manager: Optional[ClientManager] = None
):
if players is None:
players = []
......
from typing import Optional
import socketio
from server.game.lobby import LobbyManager
from server.model.hand import Hand
from server.model.players import Player, Announce
sio = socketio.AsyncServer(
async_mode='asgi',
logger=True,
cors_allowed_origins="*" # FIXME: CSRF Vulnerability
)
lobby = LobbyManager(sio)
class ClientPlayer(Player):
def __init__(self, lobby: LobbyManager):
super().__init__()
self.lobby = lobby
async def announce(self, current_bet: Optional[Hand]) -> Announce:
return lobby.last_announces[self]
@sio.event
def connect(sid, environ):
async def connect(sid, environ):
print("[WS] Connect ", sid, environ)
player = ClientPlayer(lobby)
await lobby.add_player(player)
@sio.event
async def chat_message(sid, data):
async def message(sid, data):
print("[WS] Message ", data)
await sio.emit('reply', room=sid)
await sio.emit('messageChannel', "OK", room=sid)
@sio.on("pingServer")
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment