from fastapi import WebSocket
from typing import Dict, Set
import uuid
class WebSocketManager:
"""Manages WebSocket connections for multiplayer"""
def __init__(self):
self.active_connections: Dict[str, WebSocket] = {}
self.player_nicknames: Dict[str, str] = {}
self.nickname_to_id: Dict[str, str] = {}
async def connect(self, websocket: WebSocket, nickname: str):
"""Connect a new player"""
await websocket.accept()
# Generate or reuse player ID
if nickname in self.nickname_to_id:
player_id = self.nickname_to_id[nickname]
else:
player_id = str(uuid.uuid4())
self.nickname_to_id[nickname] = player_id
self.active_connections[player_id] = websocket
self.player_nicknames[player_id] = nickname
# Broadcast player joined
await self.broadcast({
"type": "player_joined",
"player_id": player_id,
"nickname": nickname
})
async def disconnect(self, websocket: WebSocket):
"""Disconnect a player"""
player_id = None
for pid, ws in self.active_connections.items():
if ws == websocket:
player_id = pid
break
if player_id:
del self.active_connections[player_id]
nickname = self.player_nicknames.pop(player_id, None)
# Broadcast player left
await self.broadcast({
"type": "player_left",
"player_id": player_id,
"nickname": nickname
})
async def broadcast(self, message: dict, exclude: WebSocket = None):
"""Broadcast message to all connected players"""
disconnected = []
for player_id, websocket in self.active_connections.items():
if websocket == exclude:
continue
try:
await websocket.send_json(message)
except Exception:
disconnected.append(player_id)
# Clean up disconnected websockets
for player_id in disconnected:
if player_id in self.active_connections:
del self.active_connections[player_id]
if player_id in self.player_nicknames:
del self.player_nicknames[player_id]
async def broadcast_game_state(self, state: dict):
"""Broadcast full game state"""
await self.broadcast({
"type": "game_state_update",
"state": state
})
async def get_player_id(self, websocket: WebSocket) -> str:
"""Get player ID from websocket"""
for player_id, ws in self.active_connections.items():
if ws == websocket:
return player_id
return None
async def get_nickname(self, websocket: WebSocket) -> str:
"""Get nickname from websocket"""
player_id = await self.get_player_id(websocket)
return self.player_nicknames.get(player_id, "Unknown")