@@ -1,15 +0,0 @@
|
|||||||
using System.Text.Json;
|
|
||||||
using Microsoft.AspNetCore.Mvc;
|
|
||||||
|
|
||||||
namespace MauMau_Server.Controllers;
|
|
||||||
|
|
||||||
[ApiController]
|
|
||||||
[Route("[controller]")]
|
|
||||||
public class AuthController : ControllerBase
|
|
||||||
{
|
|
||||||
[HttpGet]
|
|
||||||
public async Task<IActionResult> Get()
|
|
||||||
{
|
|
||||||
return Ok(JsonSerializer.Serialize(Guid.NewGuid()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
using System.Net.WebSockets;
|
using System.Net.WebSockets;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
|
using MauMau_Server.Websockets;
|
||||||
|
|
||||||
namespace MauMau_Server.Mau;
|
namespace MauMau_Server.Mau;
|
||||||
|
|
||||||
@@ -17,9 +18,9 @@ public class Game
|
|||||||
Deck.AddCardToUsedDeck(CurrentCard);
|
Deck.AddCardToUsedDeck(CurrentCard);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AddPlayerToGame(string playerId, WebSocket socket)
|
public void AddPlayerToGame(ConnectionInstance connection)
|
||||||
{
|
{
|
||||||
var player = new Player("Koetje " + playerId.Split('-')[0], playerId, socket)
|
var player = new Player(connection)
|
||||||
{
|
{
|
||||||
Hand = Deck.DrawCards(8)
|
Hand = Deck.DrawCards(8)
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ public class GameState
|
|||||||
public GameState(Game game, string playerId)
|
public GameState(Game game, string playerId)
|
||||||
{
|
{
|
||||||
var p = game.GetPlayer(playerId);
|
var p = game.GetPlayer(playerId);
|
||||||
PlayerName = p.Name;
|
PlayerName = p.Connection.ConnectionId;
|
||||||
foreach (var card in p.Hand)
|
foreach (var card in p.Hand)
|
||||||
{
|
{
|
||||||
Hand.Add(card.ToString());
|
Hand.Add(card.ToString());
|
||||||
@@ -19,10 +19,10 @@ public class GameState
|
|||||||
|
|
||||||
foreach (var player in game.Players)
|
foreach (var player in game.Players)
|
||||||
{
|
{
|
||||||
Players.Add(player.Name);
|
Players.Add(player.Connection.ConnectionId);
|
||||||
}
|
}
|
||||||
|
|
||||||
CurrentCard = game.CurrentCard.ToString();
|
CurrentCard = game.CurrentCard.ToString();
|
||||||
CurrentPlayer = game.CurrentPlayer.Name;
|
CurrentPlayer = game.CurrentPlayer.Connection.ConnectionId;;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,20 +1,17 @@
|
|||||||
using System.Net.WebSockets;
|
using System.Net.WebSockets;
|
||||||
|
using MauMau_Server.Websockets;
|
||||||
|
|
||||||
namespace MauMau_Server.Mau;
|
namespace MauMau_Server.Mau;
|
||||||
|
|
||||||
public class Player
|
public class Player
|
||||||
{
|
{
|
||||||
public string Name { get; set; }
|
public ConnectionInstance Connection { get; set; }
|
||||||
public string PlayerId { get; set; }
|
|
||||||
public WebSocket Socket { get; set; }
|
|
||||||
public List<Card> Hand { get; set; } = new();
|
public List<Card> Hand { get; set; } = new();
|
||||||
|
|
||||||
public Player(string name, string playerId, WebSocket socket)
|
public Player(ConnectionInstance connection)
|
||||||
{
|
{
|
||||||
Name = name;
|
Connection = connection;
|
||||||
PlayerId = playerId;
|
|
||||||
Socket = socket;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool IsMe(string playerId) => PlayerId == playerId;
|
public bool IsMe(string playerId) => Connection.ConnectionId == playerId;
|
||||||
}
|
}
|
||||||
22
Room/Chat/Chat.cs
Normal file
22
Room/Chat/Chat.cs
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
using System.Net.WebSockets;
|
||||||
|
using System.Text.Json;
|
||||||
|
using MauMau_Server.Websockets;
|
||||||
|
|
||||||
|
namespace MauMau_Server.Mau;
|
||||||
|
|
||||||
|
public class Chat
|
||||||
|
{
|
||||||
|
private readonly Room _room;
|
||||||
|
|
||||||
|
public Chat(Room room)
|
||||||
|
{
|
||||||
|
_room = room;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SendChatMessage(string connectionId, string message)
|
||||||
|
{
|
||||||
|
var chatMessage = new ChatOutput(connectionId, message);
|
||||||
|
var formattedMessage = new MessageDTO("CHAT", JsonSerializer.Serialize(chatMessage));
|
||||||
|
WebsocketManager.BroadcastAsync(_room.GetWebsockets(), JsonSerializer.Serialize(formattedMessage));
|
||||||
|
}
|
||||||
|
}
|
||||||
18
Room/Chat/ChatOutput.cs
Normal file
18
Room/Chat/ChatOutput.cs
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
namespace MauMau_Server.Mau;
|
||||||
|
|
||||||
|
public class ChatOutput
|
||||||
|
{
|
||||||
|
public string PlayerName { get; set; }
|
||||||
|
public string Message { get; set; }
|
||||||
|
|
||||||
|
public ChatOutput(string playerName, string message)
|
||||||
|
{
|
||||||
|
PlayerName = playerName;
|
||||||
|
Message = message;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ChatOutput()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
18
Room/MessageDTO.cs
Normal file
18
Room/MessageDTO.cs
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
namespace MauMau_Server.Mau;
|
||||||
|
|
||||||
|
public class MessageDTO
|
||||||
|
{
|
||||||
|
public string Type { get; set; }
|
||||||
|
public string Payload { get; set; }
|
||||||
|
|
||||||
|
public MessageDTO(string type, string payload)
|
||||||
|
{
|
||||||
|
Type = type;
|
||||||
|
Payload = payload;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MessageDTO()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
106
Room/Room.cs
Normal file
106
Room/Room.cs
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
using System.Net.WebSockets;
|
||||||
|
using System.Text.Json;
|
||||||
|
using MauMau_Server.Mau;
|
||||||
|
|
||||||
|
namespace MauMau_Server.Websockets;
|
||||||
|
|
||||||
|
public class Room
|
||||||
|
{
|
||||||
|
private readonly IRoomManager _roomManager;
|
||||||
|
private readonly string _roomId;
|
||||||
|
private readonly List<ConnectionInstance> _connections = new();
|
||||||
|
private ConnectionInstance _host;
|
||||||
|
private readonly Chat _chat;
|
||||||
|
private readonly Game _game = new();
|
||||||
|
|
||||||
|
public Room(IRoomManager roomManager, string roomId)
|
||||||
|
{
|
||||||
|
_roomManager = roomManager;
|
||||||
|
_chat = new Chat(this);
|
||||||
|
_roomId = roomId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task InstantiateConnection(WebSocket socket)
|
||||||
|
{
|
||||||
|
var connection = AddConnection(socket);
|
||||||
|
if (IsEmpty()) _host = connection;
|
||||||
|
_game.AddPlayerToGame(connection);
|
||||||
|
await HandleConnection(connection);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task HandleConnection(ConnectionInstance connection)
|
||||||
|
{
|
||||||
|
BroadcastGameState();
|
||||||
|
var webSocketResponse = await WebsocketManager.ReceiveAsync(connection.Socket);
|
||||||
|
while (!webSocketResponse.Result!.CloseStatus.HasValue)
|
||||||
|
{
|
||||||
|
var message = JsonSerializer.Deserialize<MessageDTO>(webSocketResponse.SlicedBuffer);
|
||||||
|
switch (message.Type)
|
||||||
|
{
|
||||||
|
case "GAME":
|
||||||
|
{
|
||||||
|
var gameInput = JsonSerializer.Deserialize<ActionDTO>(message.Payload);
|
||||||
|
_game.HandleAction(connection.ConnectionId, gameInput);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "CHAT":
|
||||||
|
{
|
||||||
|
_chat.SendChatMessage(connection.ConnectionId, message.Payload);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BroadcastGameState();
|
||||||
|
webSocketResponse = await WebsocketManager.ReceiveAsync(connection.Socket);
|
||||||
|
}
|
||||||
|
WebsocketManager.CloseAsync(connection.Socket, webSocketResponse.Result);
|
||||||
|
HandleDisconnect(connection.ConnectionId);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ConnectionInstance AddConnection(WebSocket socket)
|
||||||
|
{
|
||||||
|
var connectionId = Guid.NewGuid().ToString();
|
||||||
|
var connection = new ConnectionInstance(connectionId, socket);
|
||||||
|
_connections.Add(connection);
|
||||||
|
return connection;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RemoveConnection(string socketId)
|
||||||
|
{
|
||||||
|
_connections.RemoveAll(connection => connection.ConnectionId == socketId);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void BroadcastGameState()
|
||||||
|
{
|
||||||
|
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 HandleDisconnect(string socketId)
|
||||||
|
{
|
||||||
|
RemoveConnection(socketId);
|
||||||
|
_game.RemovePlayer(socketId);
|
||||||
|
if (IsEmpty())
|
||||||
|
{
|
||||||
|
_roomManager.RemoveRoom(_roomId);
|
||||||
|
}
|
||||||
|
else if (socketId == _host.ConnectionId)
|
||||||
|
{
|
||||||
|
_host = _connections.First();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<WebSocket> GetWebsockets()
|
||||||
|
{
|
||||||
|
return _connections.Select(connection => connection.Socket).ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool IsEmpty()
|
||||||
|
{
|
||||||
|
return _connections.Count == 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
15
Websockets/ConnectionInstance.cs
Normal file
15
Websockets/ConnectionInstance.cs
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
using System.Net.WebSockets;
|
||||||
|
|
||||||
|
namespace MauMau_Server.Websockets;
|
||||||
|
|
||||||
|
public class ConnectionInstance
|
||||||
|
{
|
||||||
|
public string ConnectionId { get; set; }
|
||||||
|
public WebSocket Socket { get; set; }
|
||||||
|
|
||||||
|
public ConnectionInstance(string connectionId, WebSocket socket)
|
||||||
|
{
|
||||||
|
ConnectionId = connectionId;
|
||||||
|
Socket = socket;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,131 +0,0 @@
|
|||||||
using System.Collections;
|
|
||||||
using System.Net.WebSockets;
|
|
||||||
using System.Text;
|
|
||||||
using System.Text.Json;
|
|
||||||
using MauMau_Server.Mau;
|
|
||||||
|
|
||||||
namespace MauMau_Server.Websockets;
|
|
||||||
|
|
||||||
public class Room
|
|
||||||
{
|
|
||||||
private readonly IRoomManager _roomManager;
|
|
||||||
private readonly string _roomId;
|
|
||||||
private readonly Dictionary<string, WebSocket> _connections = new();
|
|
||||||
private string _host;
|
|
||||||
private readonly Game _game = new();
|
|
||||||
|
|
||||||
public Room(IRoomManager roomManager, string roomId)
|
|
||||||
{
|
|
||||||
_roomManager = roomManager;
|
|
||||||
_roomId = roomId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task InstantiateConnection(WebSocket socket)
|
|
||||||
{
|
|
||||||
var socketId = AddConnection(socket);
|
|
||||||
await HandleConnection(socket, socketId);
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task HandleConnection(WebSocket socket, string socketId)
|
|
||||||
{
|
|
||||||
BroadcastGameState();
|
|
||||||
var buffer = EmptyBuffer();
|
|
||||||
var result = await ReceiveAsync(socket, buffer);
|
|
||||||
while (!result.CloseStatus.HasValue)
|
|
||||||
{
|
|
||||||
var slicedBuffer = buffer[0..result.Count];
|
|
||||||
var action = JsonSerializer.Deserialize<ActionDTO>(slicedBuffer);
|
|
||||||
_game.HandleAction(socketId, action);
|
|
||||||
BroadcastGameState();
|
|
||||||
buffer = EmptyBuffer();
|
|
||||||
result = await ReceiveAsync(socket, buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
await socket.CloseAsync(result.CloseStatus.Value, result.CloseStatusDescription, CancellationToken.None);
|
|
||||||
HandleDisconnect(socketId);
|
|
||||||
}
|
|
||||||
|
|
||||||
private string AddConnection(WebSocket socket)
|
|
||||||
{
|
|
||||||
var socketId = Guid.NewGuid().ToString();
|
|
||||||
if (_connections.Count == 0)
|
|
||||||
{
|
|
||||||
_host = socketId;
|
|
||||||
}
|
|
||||||
|
|
||||||
_connections.Add(socketId, socket);
|
|
||||||
_game.AddPlayerToGame(socketId, socket);
|
|
||||||
return socketId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public WebSocket GetConnection(string socketId)
|
|
||||||
{
|
|
||||||
return _connections[socketId];
|
|
||||||
}
|
|
||||||
|
|
||||||
public Dictionary<string, WebSocket> GetAllConnections()
|
|
||||||
{
|
|
||||||
return _connections;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void RemoveConnection(string socketId)
|
|
||||||
{
|
|
||||||
_connections.Remove(socketId);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static async Task<WebSocketReceiveResult?> ReceiveAsync(WebSocket webSocket, byte[] buffer)
|
|
||||||
{
|
|
||||||
var arraySegment = new ArraySegment<byte>(buffer);
|
|
||||||
var result = await webSocket.ReceiveAsync(arraySegment, CancellationToken.None);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void BroadcastGameState()
|
|
||||||
{
|
|
||||||
foreach (var (id, socket) in GetAllConnections())
|
|
||||||
{
|
|
||||||
var gameState = new GameState(_game, id);
|
|
||||||
var message = JsonSerializer.Serialize(gameState);
|
|
||||||
SendAsync(socket, message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void BroadcastAsync(string message)
|
|
||||||
{
|
|
||||||
foreach (var (id, socket) in GetAllConnections())
|
|
||||||
{
|
|
||||||
SendAsync(socket, message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void SendAsync(WebSocket socket, string message)
|
|
||||||
{
|
|
||||||
var bytes = Encoding.Default.GetBytes(message);
|
|
||||||
var arraySegment = new ArraySegment<byte>(bytes);
|
|
||||||
socket.SendAsync(arraySegment, WebSocketMessageType.Text, true, CancellationToken.None);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void HandleDisconnect(string socketId)
|
|
||||||
{
|
|
||||||
RemoveConnection(socketId);
|
|
||||||
_game.RemovePlayer(socketId);
|
|
||||||
if (IsEmpty())
|
|
||||||
{
|
|
||||||
_roomManager.RemoveRoom(_roomId);
|
|
||||||
}
|
|
||||||
else if (socketId == _host)
|
|
||||||
{
|
|
||||||
_host = _connections.First().Key;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static byte[] EmptyBuffer()
|
|
||||||
{
|
|
||||||
return new byte[4096];
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsEmpty()
|
|
||||||
{
|
|
||||||
return _connections.Count == 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
15
Websockets/WebSocketResponse.cs
Normal file
15
Websockets/WebSocketResponse.cs
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
using System.Net.WebSockets;
|
||||||
|
|
||||||
|
namespace MauMau_Server.Websockets;
|
||||||
|
|
||||||
|
public class WebSocketResponse
|
||||||
|
{
|
||||||
|
public readonly WebSocketReceiveResult? Result;
|
||||||
|
public readonly byte[] SlicedBuffer;
|
||||||
|
|
||||||
|
public WebSocketResponse(WebSocketReceiveResult? result, byte[] slicedBuffer)
|
||||||
|
{
|
||||||
|
Result = result;
|
||||||
|
SlicedBuffer = slicedBuffer;
|
||||||
|
}
|
||||||
|
}
|
||||||
36
Websockets/WebsocketManager.cs
Normal file
36
Websockets/WebsocketManager.cs
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
using System.Net.WebSockets;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace MauMau_Server.Websockets;
|
||||||
|
|
||||||
|
public static class WebsocketManager
|
||||||
|
{
|
||||||
|
public static void SendAsync(WebSocket socket, string message)
|
||||||
|
{
|
||||||
|
var bytes = Encoding.Default.GetBytes(message);
|
||||||
|
var arraySegment = new ArraySegment<byte>(bytes);
|
||||||
|
socket.SendAsync(arraySegment, WebSocketMessageType.Text, true, CancellationToken.None);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void BroadcastAsync(List<WebSocket> sockets, string message)
|
||||||
|
{
|
||||||
|
foreach (var socket in sockets)
|
||||||
|
{
|
||||||
|
SendAsync(socket, message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async Task<WebSocketResponse> ReceiveAsync(WebSocket webSocket)
|
||||||
|
{
|
||||||
|
var buffer = new byte[4096];
|
||||||
|
var arraySegment = new ArraySegment<byte>(buffer);
|
||||||
|
var result = await webSocket.ReceiveAsync(arraySegment, CancellationToken.None);
|
||||||
|
var slicedBuffer = buffer[0..result.Count];
|
||||||
|
return new WebSocketResponse(result, slicedBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async void CloseAsync(WebSocket webSocket, WebSocketReceiveResult result)
|
||||||
|
{
|
||||||
|
await webSocket.CloseAsync(result.CloseStatus.Value, result.CloseStatusDescription, CancellationToken.None);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user