pong-game/PongGame/Hubs/PongLobbyCollection.cs

95 lines
3.1 KiB
C#
Raw Normal View History

using System.Numerics;
using System.Text.RegularExpressions;
using Microsoft.AspNetCore.SignalR;
2022-11-03 12:29:35 +01:00
namespace PongGame.Hubs;
public class PongLobby {
private readonly HashSet<PongPlayer> connectedPlayers = new();
private readonly Dictionary<string, PongRoom> PongRooms = new();
public PongLobby(ILogger<PongLobby> logger)
=> Logger = logger;
public const int ROOM_ID_LENGTH = 4;
public PongPlayer CreatePlayer() {
var player = new PongPlayer();
lock (connectedPlayers)
connectedPlayers.Add(player);
return player;
}
public void RemovePlayer(PongPlayer player) {
if (player.ConnectedRoom is PongRoom room)
room.Leave(player);
lock (connectedPlayers)
_ = connectedPlayers.Remove(player);
}
public PongRoom CreateRoom(PongPlayer player) {
PongRoom room;
lock (PongRooms) {
room = new(GenerateRoomId(), Logger);
PongRooms.Add(room.ID, room);
}
room.Join(player);
return room;
}
public Task<PongRoom> JoinRoom(PongPlayer player, string roomId) {
2022-11-03 12:29:35 +01:00
PongRoom? room;
lock (PongRooms) {
room = PongRooms.GetValueOrDefault(roomId);
}
if (room is null) throw new HubException($"Room [{roomId}] not found!");
room.Join(player);
return Task.FromResult(room);
2022-11-03 12:29:35 +01:00
}
public Task LeaveRoom(PongPlayer player) {
if (player.ConnectedRoom is PongRoom room) {
2022-11-03 12:29:35 +01:00
room.Leave(player);
if (room.IsEmpty)
lock (PongRooms)
_ = PongRooms.Remove(room.ID);
}
return Task.CompletedTask;
2022-11-03 12:29:35 +01:00
}
private readonly Random random = new();
private readonly ILogger<PongLobby> Logger;
private const string ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
private string GenerateRoomId() {
string id;
do {
id = string.Concat(Enumerable.Range(0, ROOM_ID_LENGTH).Select(_ => ALPHABET[random.Next(ALPHABET.Length)]));
} while (PongRooms.ContainsKey(id));
return id;
}
public async Task ChangeUsername(PongPlayer player, string username) {
username = ValidateUsername(username);
if (player.Username == username) {
await player.Client.UsernameChanged(username);
return;
}
lock (connectedPlayers) {
// TODO: separate hashset for usernames
if (connectedPlayers.Select(i => i.Username).Contains(username))
throw new HubException($"Username {username} is already taken!");
}
Logger.LogInformation("Player {Player} requested username change to [{username}]", player, username);
player.Username = username;
}
private static readonly Regex UsernameRegex = new(@"^(?!.*[._ -]{2})[\w._ -]{3,20}$", RegexOptions.Compiled, TimeSpan.FromMilliseconds(200));
private static string ValidateUsername(string username) {
username = username.Trim();
if (!UsernameRegex.IsMatch(username))
throw new HubException($"At most 20 characters, no two consecutive symbols");
return username;
}
2022-11-03 12:29:35 +01:00
}