using System.Net.WebSockets; using System.Text.Json; using System.Text.RegularExpressions; using MauMau_Server.Mau; namespace MauMau_Server.Websockets; public class Room { private readonly IRoomManager _roomManager; private readonly string _roomId; private readonly List _connections = new(); private ConnectionInstance? _host; private readonly Chat _chat; private Game? _game; private RoomState _state = RoomState.LOBBY; public Room(IRoomManager roomManager, string roomId) { _roomManager = roomManager; _chat = new Chat(this); _roomId = roomId; } public async Task InstantiateConnection(WebSocket socket, string name) { var connection = AddConnection(socket, name); _game?.AddPlayerToGame(connection); await HandleConnection(connection); } private async Task HandleConnection(ConnectionInstance connection) { BroadcastState(); var webSocketResponse = await WebsocketManager.ReceiveAsync(connection.Socket); while (!webSocketResponse.Result!.CloseStatus.HasValue) { var message = JsonSerializer.Deserialize(webSocketResponse.SlicedBuffer); switch (message.Type) { case "GAME": { if (_state != RoomState.GAME) break; var gameInput = JsonSerializer.Deserialize(message.Payload); _game.HandleAction(connection.ConnectionId, gameInput); break; } case "CHAT": { var cleanedMessage = StripHTML(message.Payload); if (string.IsNullOrWhiteSpace(cleanedMessage)) { cleanedMessage = "Mau!"; }; _chat.SendChatMessage(connection, cleanedMessage); break; } case "LOBBY": { if (connection.ConnectionId == _host?.ConnectionId) { ChangeLobbyState(RoomState.GAME); } break; } } BroadcastState(); webSocketResponse = await WebsocketManager.ReceiveAsync(connection.Socket); } WebsocketManager.CloseAsync(connection.Socket, webSocketResponse.Result); HandleDisconnect(connection.ConnectionId); } private ConnectionInstance AddConnection(WebSocket socket, string name) { var connectionId = Guid.NewGuid().ToString(); var connection = new ConnectionInstance(name, connectionId, socket); if (IsEmpty()) _host = connection; _connections.Add(connection); return connection; } private void RemoveConnection(string socketId) { _connections.RemoveAll(connection => connection.ConnectionId == socketId); } private void BroadcastGameState() { if (_game == null) { return; } foreach (var connection in _connections) { var gameState = new GameState(_game, connection.ConnectionId); var message = new MessageDTO("GAME", JsonSerializer.Serialize(gameState)); WebsocketManager.SendAsync(connection.Socket, JsonSerializer.Serialize(message)); } } private void BroadcastState() { switch (_state) { case RoomState.LOBBY: var message = new MessageDTO("LOBBY", JsonSerializer.Serialize("a")); WebsocketManager.BroadcastAsync(GetWebsockets(), JsonSerializer.Serialize(message)); break; case RoomState.GAME: BroadcastGameState(); break; default: // break; } } private void ChangeLobbyState(RoomState targetState) { switch (targetState) { case RoomState.LOBBY: _state = RoomState.LOBBY; _game = null; break; case RoomState.GAME: { _state = RoomState.GAME; _game = new Game(this); foreach (var connectionInstance in _connections) { _game.AddPlayerToGame(connectionInstance); } break; } default: throw new ArgumentOutOfRangeException(nameof(targetState), targetState, null); } } private void HandleDisconnect(string socketId) { RemoveConnection(socketId); _game?.RemovePlayer(socketId); if (IsEmpty()) { _roomManager.RemoveRoom(_roomId); } else if (socketId == _host.ConnectionId) { _host = _connections.First(); } } public List GetWebsockets() { return _connections.Select(connection => connection.Socket).ToList(); } public bool IsEmpty() { return _connections.Count == 0; } private static string StripHTML(string input) { return Regex.Replace(input, "<.*?>", string.Empty); } public void EndGame(Player player) { var message = new MessageDTO("END", JsonSerializer.Serialize(new PlayerDTO(player))); WebsocketManager.BroadcastAsync(GetWebsockets(), JsonSerializer.Serialize(message)); ChangeLobbyState(RoomState.LOBBY); } } public enum RoomState { LOBBY, GAME }