diff --git a/.gitignore b/.gitignore index 9491a2fda..8eca71a56 100644 --- a/.gitignore +++ b/.gitignore @@ -360,4 +360,5 @@ MigrationBackup/ .ionide/ # Fody - auto-generated XML schema -FodyWeavers.xsd \ No newline at end of file +FodyWeavers.xsd +/Properties/VersionInfo.cs diff --git a/Hubs/CrowGameHub.cs b/Hubs/CrowGameHub.cs deleted file mode 100644 index a5384c3ed..000000000 --- a/Hubs/CrowGameHub.cs +++ /dev/null @@ -1,62 +0,0 @@ -using Microsoft.AspNetCore.SignalR; - -namespace TheOmenDen.CrowsAgainstHumility.Hubs; - -public class CrowGameHub : Hub -{ - public const string HubUrl = "/games"; - - private static readonly Dictionary> Games= new (100, StringComparer.OrdinalIgnoreCase); - - public Task CreateGame(String gameName) - { - var currentConnection = Context.ConnectionId; - - var players = new HashSet { currentConnection }; - - Games.Add(gameName, players); - - Groups.AddToGroupAsync(gameName, currentConnection); - - return Clients.Group(gameName).SendAsync("Send", $"{currentConnection} has created the game {gameName}"); - } - - public Task JoinGame(String gameName) - { - var currentConnection = Context.ConnectionId; - - if (!Games.TryGetValue(gameName, out var players)) - { - Games.Add(gameName, new HashSet{ currentConnection }); - } - - players!.Add(currentConnection); - - return Groups.AddToGroupAsync(currentConnection, gameName); - } - - public Task LeaveGame(String gameName) - { - var currentConnection = Context.ConnectionId; - - if (!Games.TryGetValue(gameName, out var players)) - { - players?.Remove(currentConnection); - } - - return Groups.RemoveFromGroupAsync(currentConnection, gameName); - } - - public override Task OnDisconnectedAsync(Exception? exception) - { - //var currentConnection = Context.ConnectionId; - return base.OnDisconnectedAsync(exception); - } - - public override Task OnConnectedAsync() - { - var currentConnection = Context.ConnectionId; - - return base.OnConnectedAsync(); - } -} diff --git a/Program.cs b/Program.cs index e1083f293..2d8e176d9 100644 --- a/Program.cs +++ b/Program.cs @@ -31,6 +31,8 @@ using Microsoft.AspNetCore.Authentication.Cookies; using Microsoft.AspNetCore.Components.Server; using Microsoft.Identity.Web; +using TheOmenDen.CrowsAgainstHumility.Services.Hubs; + #endregion #region Bootstrap Logger Log.Logger = new LoggerConfiguration() @@ -52,21 +54,13 @@ { var builder = WebApplication.CreateBuilder(args); - builder.Host - .ConfigureAppConfiguration((context, config) => - { - config - .SetBasePath(Directory.GetCurrentDirectory()) - .AddJsonFile("appsettings.json", true, true) - .AddJsonFile($"appsettings.{builder.Environment.EnvironmentName}.json", true) - .AddEnvironmentVariables() - .AddAzureKeyVault( - new Uri(builder.Configuration["VaultUri"]), - new DefaultAzureCredential()); - - }) - .UseDefaultServiceProvider(options => options.ValidateScopes = false) - .UseSerilog((context, services, configuration) => configuration + builder.Configuration.AddAzureKeyVault( + new Uri(builder.Configuration["VaultUri"]), + new DefaultAzureCredential()); + + + builder.Host.UseDefaultServiceProvider(options => options.ValidateScopes = false) + .UseSerilog((context, services, configuration) => configuration .ReadFrom.Configuration(context.Configuration) .ReadFrom.Services(services) .Enrich.FromLogContext() @@ -122,7 +116,7 @@ .AddTwitch(options => { options.ClientId = twitchStrings.ClientId; - options.ClientSecret = twitchStrings.Key; + options.ClientSecret = twitchStrings.Key; options.SaveTokens = true; }) .AddDiscord(options => @@ -256,7 +250,7 @@ builder.Services.AddScoped(sp => { // this is safe because - // the `RevalidatingIdentityAuthenticationStateProvider` extends the `ServerAuthenticationStateProvider` + // the `RevalidatingIdentityAuthenticationStateProvider` extends the `ServerAuthenticationStateProvider` var provider = (ServerAuthenticationStateProvider)sp.GetRequiredService(); return provider; }); @@ -283,15 +277,12 @@ app.UseAuthentication(); app.UseAuthorization(); - app.UseEndpoints(endpoints => - { - endpoints.MapControllers(); - endpoints.MapRazorPages(); - endpoints.MapBlazorHub(); - endpoints.MapHub(CawHub.HubUrl); - endpoints.MapHub(CrowGameHub.HubUrl); - endpoints.MapFallbackToPage("/_Host"); - }); + app.MapControllers(); + app.MapRazorPages(); + app.MapBlazorHub(); + app.MapHub(CawHub.HubUrl); + app.MapHub(CrowGameHub.HubUrl); + app.MapFallbackToPage("/_Host"); await app.RunAsync(); } diff --git a/Properties/VersionInfo.cs b/Properties/VersionInfo.cs deleted file mode 100644 index 6d25e177e..000000000 --- a/Properties/VersionInfo.cs +++ /dev/null @@ -1,3 +0,0 @@ -[assembly:System.Reflection.AssemblyFileVersion("1.11.23.0012")] -[assembly:System.Reflection.AssemblyCompany("The Omen Den L.L.C.")] -[assembly:System.Reflection.AssemblyTitle("Crows Against Humility")] diff --git a/TheOmenDen.CrowsAgainstHumility.Core/Models/GamePlay.cs b/TheOmenDen.CrowsAgainstHumility.Core/Models/GamePlay.cs index bf2749d7c..199e4ca70 100644 --- a/TheOmenDen.CrowsAgainstHumility.Core/Models/GamePlay.cs +++ b/TheOmenDen.CrowsAgainstHumility.Core/Models/GamePlay.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace TheOmenDen.CrowsAgainstHumility.Core.Models; +namespace TheOmenDen.CrowsAgainstHumility.Core.Models; public sealed class GamePlay { public string HubConnectionId { get; set; } diff --git a/TheOmenDen.CrowsAgainstHumility.Core/Models/Player.cs b/TheOmenDen.CrowsAgainstHumility.Core/Models/Player.cs index 2a41a6315..10746659c 100644 --- a/TheOmenDen.CrowsAgainstHumility.Core/Models/Player.cs +++ b/TheOmenDen.CrowsAgainstHumility.Core/Models/Player.cs @@ -1,11 +1,9 @@ -using Microsoft.EntityFrameworkCore.ChangeTracking; -using System.Linq; -using System.Reflection.Metadata.Ecma335; - -namespace TheOmenDen.CrowsAgainstHumility.Core.Models; +namespace TheOmenDen.CrowsAgainstHumility.Core.Models; public sealed class Player : IEquatable { + private const int MaxHandSize = 10; + public Player() {} public Player(String connectionId) { @@ -17,15 +15,21 @@ public Player(String connectionId) public String ConnectionId { get; set; } + public int AwesomePoints { get; set; } = 2; + public string Name { get; set; } = String.Empty; - public String ConnectionGuid { get; } + public string Username { get; set; } = String.Empty; + + public List Hand { get; } = new (MaxHandSize); + + public Guid ConnectionGuid { get; } public Guid Id { get; set;} public bool IsConnected { get; set; } - public bool IsCardTsar { get; set; } = false; + public bool IsCardCzar { get; set; } = false; public bool Equals(Player? other) => other is not null && (ReferenceEquals(this, other) diff --git a/TheOmenDen.CrowsAgainstHumility.Services/CardPoolBuilding/BlackCardProvider.cs b/TheOmenDen.CrowsAgainstHumility.Services/CardPoolBuilding/BlackCardProvider.cs new file mode 100644 index 000000000..497d390cb --- /dev/null +++ b/TheOmenDen.CrowsAgainstHumility.Services/CardPoolBuilding/BlackCardProvider.cs @@ -0,0 +1,45 @@ +using Microsoft.Extensions.Logging; +using TheOmenDen.CrowsAgainstHumility.Core.Models; +using TheOmenDen.CrowsAgainstHumility.Services.Rooms; +using TheOmenDen.Shared.Extensions; + +namespace TheOmenDen.CrowsAgainstHumility.Services.CardPoolBuilding; +public static class BlackCardProvider +{ + private static readonly object SyncObject = new (); + + private static readonly Dictionary> BlackCardToRoomDictionary = new(StringComparer.OrdinalIgnoreCase); + + public static void AddRoomReference(CrowGameRoom room, IEnumerable blackCards) + { + var blackCardList = blackCards.ToList(); + + if (!BlackCardToRoomDictionary.ContainsKey(room.RoomName)) + { + BlackCardToRoomDictionary.Add(room.RoomName, blackCardList); + } + + BlackCardToRoomDictionary[room.RoomName] = blackCardList; + } + + public static BlackCard GetBlackCardForRound(String roomName) + { + if (!BlackCardToRoomDictionary.TryGetValue(roomName, out var blackCardPool)) + { + throw new ArgumentOutOfRangeException(nameof(roomName)); + } + + var blackCardToPlay = blackCardPool.GetRandomElement(); + + lock (SyncObject) + { + RemoveUsedCardFromPool(roomName, blackCardToPlay); + } + + return blackCardToPlay; + } + + private static void RemoveUsedCardFromPool(String roomName, BlackCard blackCardToRemove) => + _ = BlackCardToRoomDictionary.TryGetValue(roomName, out var blackCards) + && blackCards.Remove(blackCardToRemove); +} diff --git a/TheOmenDen.CrowsAgainstHumility.Services/CardPoolBuilding/WhiteCardProvider.cs b/TheOmenDen.CrowsAgainstHumility.Services/CardPoolBuilding/WhiteCardProvider.cs new file mode 100644 index 000000000..0b9a4796f --- /dev/null +++ b/TheOmenDen.CrowsAgainstHumility.Services/CardPoolBuilding/WhiteCardProvider.cs @@ -0,0 +1,50 @@ + +using TheOmenDen.CrowsAgainstHumility.Core.Models; +using TheOmenDen.CrowsAgainstHumility.Services.Rooms; +using TheOmenDen.Shared.Extensions; + +namespace TheOmenDen.CrowsAgainstHumility.Services.CardPoolBuilding; +public static class WhiteCardProvider +{ + private static readonly Dictionary> WhiteCardPoolByRoomDictionary = new(StringComparer.OrdinalIgnoreCase); + private const int MaxHandSize = 10; + + public static void CreateCardPoolProviderForRoom(CrowGameRoom room, IEnumerable whiteCards) + { + if (WhiteCardPoolByRoomDictionary.ContainsKey(room.RoomName)) + { + WhiteCardPoolByRoomDictionary.Add(room.RoomName, whiteCards); + } + } + + public static bool RemoveCardPoolFromRoom(CrowGameRoom room) => WhiteCardPoolByRoomDictionary.Remove(room.RoomName); + + public static void AddHandsToPlayers(CrowGameRoom room) + { + var cardPool = WhiteCardPoolByRoomDictionary[room.RoomName].ToArray(); + + foreach (var player in room.Players) + { + player.Hand.AddRange(cardPool.GetRandomElements(10)); + } + } + + public static void ReplenishPlayerHand(CrowGameRoom room) + { + var cardPool = WhiteCardPoolByRoomDictionary[room.RoomName].ToArray(); + + foreach (var playerHand in room.Players + .Where(p => !p.IsCardCzar) + .Select(p => p.Hand)) + { + if (playerHand.Count >= MaxHandSize) + { + continue; + } + + var lessThanHandSize = MaxHandSize - playerHand.Count; + + playerHand.AddRange(cardPool.GetRandomElements(lessThanHandSize)); + } + } +} diff --git a/TheOmenDen.CrowsAgainstHumility.Services/Hubs/CrowGameHub.cs b/TheOmenDen.CrowsAgainstHumility.Services/Hubs/CrowGameHub.cs index 97e3130d4..3bfc1449d 100644 --- a/TheOmenDen.CrowsAgainstHumility.Services/Hubs/CrowGameHub.cs +++ b/TheOmenDen.CrowsAgainstHumility.Services/Hubs/CrowGameHub.cs @@ -1,28 +1,207 @@ -using Microsoft.AspNetCore.SignalR; +using Microsoft.AspNetCore.Http.Connections.Features; +using Microsoft.AspNetCore.SignalR; +using Microsoft.Extensions.Configuration.EnvironmentVariables; using Microsoft.Extensions.Logging; using TheOmenDen.CrowsAgainstHumility.Core.Models; using TheOmenDen.CrowsAgainstHumility.Services.Lobbies; using TheOmenDen.CrowsAgainstHumility.Services.Rooms; namespace TheOmenDen.CrowsAgainstHumility.Services.Hubs; -public sealed class CrowGameHub: Hub +public sealed class CrowGameHub : Hub { - public const string HubUrl = "/game"; + public const string HubUrl = "/games"; + private static readonly Dictionary ConnectionPlayers = new(10); - private static Dictionary ConnectionPlayers = new(10); - - private CrowGameLobby _lobby; - private ILogger _logger; + private readonly CrowGameLobby _lobby; + private readonly ILogger _logger; public CrowGameHub(CrowGameLobby lobby, ILogger logger) { _lobby = lobby; _logger = logger; } - + #region Methods that Concern Rooms public List GetRooms() => _lobby.GetRooms().ToList(); public Task CreateRoom(String roomName, CrowRoomSettings roomSettings, CancellationToken cancellationToken = default) => _lobby.CreateRoom(roomName, roomSettings, cancellationToken); + + public async Task JoinRoom(String roomName, String roomCode) + { + var player = GetPlayer(Context.ConnectionId); + + if (player is null) + { + return null; + } + + var newRoom = _lobby.GetRoom(roomName); + + return newRoom is not null + ? await _lobby.JoinRoom(player, newRoom, roomCode) + : null; + } + + public async Task LeaveRoom() + { + var player = GetPlayer(Context.ConnectionId); + + var room = _lobby.GetRoom(player); + + if (player is null || room is null) + { + return false; + } + + await _lobby.LeaveRoom(player, room); + await _lobby.AddPlayer(player); + + return true; + } + #endregion + #region Connection Methods + public override async Task OnConnectedAsync() + { + var transportType = Context.Features.Get()?.TransportType; + + _logger.LogDebug("OnConnected SignalR TransportType: {TransportType}", transportType); + + Player? player = null; + + lock (ConnectionPlayers) + { + if (!ConnectionPlayers.TryGetValue(Context.ConnectionId, out player)) + { + player = new Player(Context.ConnectionId); + ConnectionPlayers.Add(Context.ConnectionId, player); + } + } + + if (player is not null) + { + await _lobby.AddPlayer(player); + } + + await base.OnConnectedAsync(); + } + + public override async Task OnDisconnectedAsync(Exception? exception) + { + if (exception is not null) + { + _logger.LogWarning("Player disconnected with exception {@Ex}", exception); + } + + var player = GetPlayer(Context.ConnectionId); + + if (player is null) + { + await base.OnDisconnectedAsync(exception); + return; + } + + var room = _lobby.GetRoom(player); + + if (room is not null) + { + await _lobby.PlayerDisconnected(player, room); + await base.OnDisconnectedAsync(exception); + return; + } + + await _lobby.RemovePlayer(player); + lock (ConnectionPlayers) + { + ConnectionPlayers.Remove(Context.ConnectionId); + } + + await base.OnDisconnectedAsync(exception); + } + + public async Task TryToReconnect(String username, Guid connectionId) + { + Player? existingPlayer; + lock (ConnectionPlayers) + { + existingPlayer = ConnectionPlayers.Values.SingleOrDefault(player => player.ConnectionGuid.Equals(connectionId) + || player.Username == username); + } + + if (existingPlayer is null || existingPlayer.IsConnected) + { + return new ReconnectionStateDto(Guid.Empty, null); + } + + lock (ConnectionPlayers) + { + ConnectionPlayers.Remove(Context.ConnectionId); + ConnectionPlayers.Remove(existingPlayer.ConnectionId); + + existingPlayer.ConnectionId = Context.ConnectionId; + existingPlayer.IsConnected = true; + + ConnectionPlayers.Add(Context.ConnectionId, existingPlayer); + } + + var room = _lobby.GetRoom(existingPlayer); + + if (room is null || room.RoomState is CrowRoomStateLobby) + { + return new ReconnectionStateDto(Guid.Empty, null); + } + + await _lobby.PlayerReconnected(existingPlayer, room); + return new ReconnectionStateDto(existingPlayer.Id, room.ToRoomStateDto()); + } + #endregion + #region Methods that concern game states + public async Task StartGame() + { + var player = GetPlayer(Context.ConnectionId); + var room = _lobby.GetRoom(player); + + if (room is not null && player is not null) + { + return await _lobby.StartGame(room, player); + } + + return false; + } + + public void ChooseWhiteCard(int cardIndex) + { + var player = GetPlayer(Context.ConnectionId); + var room = _lobby.GetRoom(player); + + if (room is not null && player is not null) + { + room.ChooseWhiteCard(cardIndex, player); + } + } + + public async Task PlayWhiteCard(WhiteCard card) + { + var player = GetPlayer(Context.ConnectionId); + var room = _lobby.GetRoom(player); + + if (room is not null && player is not null) + { + await room.AddWhiteCardToPlayedWhiteCards(card); + } + } + #endregion + + private static Player? GetPlayer(String connectionId) + { + lock (ConnectionPlayers) + { + if (ConnectionPlayers.TryGetValue(connectionId, out var player)) + { + return player; + } + } + + return null; + } } diff --git a/TheOmenDen.CrowsAgainstHumility.Services/Lobbies/CrowGameLobby.cs b/TheOmenDen.CrowsAgainstHumility.Services/Lobbies/CrowGameLobby.cs index c8fa69a37..a47c8172a 100644 --- a/TheOmenDen.CrowsAgainstHumility.Services/Lobbies/CrowGameLobby.cs +++ b/TheOmenDen.CrowsAgainstHumility.Services/Lobbies/CrowGameLobby.cs @@ -10,17 +10,15 @@ namespace TheOmenDen.CrowsAgainstHumility.Services.Lobbies; public sealed class CrowGameLobby { private readonly ILogger _logger; - private IHubContext _hubContext; - private List _rooms = new(10); - private Dictionary _playersInRooms = new(10); - private string _lobbyGroupName = Guid.NewGuid().ToString(); + private readonly IHubContext _hubContext; + private readonly List _rooms = new(10); + private readonly Dictionary _playersInRooms = new(10); + private readonly string _lobbyGroupName = Guid.NewGuid().ToString(); public CrowGameLobby(IHubContext hubContext, ILogger logger) { _hubContext= hubContext; _logger= logger; - - } internal void AddRoom(CrowGameRoom room) @@ -83,7 +81,7 @@ await _hubContext.Clients.GroupExcept(room.RoomName, player.ConnectionId) await room.AddPlayer(player, true); } - + #region Room State Altering Methods internal async Task CreateRoom(string roomName, CrowRoomSettings roomSettings, CancellationToken cancellationToken = default) { @@ -124,6 +122,39 @@ player is not null } } + internal async Task JoinRoom(Player? player, CrowGameRoom? newRoom, String roomCode) + { + if (newRoom is null || player is null) + { + return null; + } + + if (newRoom.RoomSettings.IsPrivateRoom && + !newRoom.RoomSettings.RoomCode.Equals(roomCode)) + { + return null; + } + + if (!_playersInRooms.TryGetValue(player, out var oldRoom)) + { + await _hubContext.Groups.RemoveFromGroupAsync(player.ConnectionId, _lobbyGroupName); + } + else + { + await LeaveRoom(player, oldRoom); + } + + _playersInRooms.Add(player, newRoom); + await newRoom.AddPlayer(player); + await _hubContext.Groups.AddToGroupAsync(player.ConnectionId, newRoom.RoomName); + await _hubContext.Clients.GroupExcept(newRoom.RoomName, player.ConnectionId).SendAsync("PlayerJoined", player.ToPlayerDto()); + + var newRoomState = newRoom.ToRoomStateDto(); + + await _hubContext.Clients.Group(_lobbyGroupName).SendAsync("RoomStateChanged", newRoomState); + return newRoomState; + } + internal async Task LeaveRoom(Player player, CrowGameRoom room) { if (_playersInRooms.Remove(player)) @@ -146,7 +177,8 @@ await _hubContext.Clients.GroupExcept(room.RoomName, player.ConnectionId) await _hubContext.Clients.Group(_lobbyGroupName).SendAsync("RoomStateChanged", room.ToRoomStateDto()); } } - + #endregion + #region Game State Altering Methods internal async Task StartGame(CrowGameRoom room, Player player) { if (!room.StartGame(player)) @@ -171,4 +203,5 @@ private async Task GameEnded(CrowGameRoom room, CancellationToken cancellationTo await LeaveRoom(player, room); } } + #endregion } diff --git a/TheOmenDen.CrowsAgainstHumility.Services/Rooms/CrowGameRoom.cs b/TheOmenDen.CrowsAgainstHumility.Services/Rooms/CrowGameRoom.cs index af726a81f..d00c66fce 100644 --- a/TheOmenDen.CrowsAgainstHumility.Services/Rooms/CrowGameRoom.cs +++ b/TheOmenDen.CrowsAgainstHumility.Services/Rooms/CrowGameRoom.cs @@ -1,16 +1,18 @@ using Microsoft.AspNetCore.SignalR; +using TheOmenDen.CrowsAgainstHumility.Core.Enumerations; using TheOmenDen.CrowsAgainstHumility.Core.Models; +using TheOmenDen.CrowsAgainstHumility.Services.CardPoolBuilding; using TheOmenDen.CrowsAgainstHumility.Services.Hubs; namespace TheOmenDen.CrowsAgainstHumility.Services.Rooms; public class CrowGameRoom { - private static int _roomCounter; - private List _unusedWhiteCards = new(4000); - private List _unusedBlackCards = new(50); - private List _usedBlackCards = new(50); + private static int _roomCounter = 0; + private readonly List _unusedWhiteCards = new(4000); + private readonly List _unusedBlackCards = new(50); + private readonly List _usedBlackCards = new(50); private List _usedWhiteCards = new(4000); - private List _players = new(10); + private readonly List _players = new(10); private ICrowRoomState _roomState; public CrowGameRoom(IHubContext context, String roomName, Func gameEndCallback) @@ -63,7 +65,7 @@ internal ICrowRoomState RoomState internal RoomStateDto ToRoomStateDto() { - var playersDto = Enumerable.Empty().ToList(); + List playersDto; lock (_players) { @@ -73,6 +75,19 @@ internal RoomStateDto ToRoomStateDto() return new(RoomName, playersDto, RoomSettings, IsGameInProgress); } + internal async Task PlayWhiteCard(Player player, WhiteCard whiteCard) + { + if (RoomState is RoomStateBlackCard rbc) + { + await rbc.SubmitCard(player, whiteCard); + return; + } + + var cm = new CrowChatMessage(CrowChatMessageType.Chat, "Played a card", player.Name); + + await SendAll("ChatMessage", cm); + } + internal void AddWhiteCardToPlayedWhiteCards(WhiteCard whiteCard) { _usedWhiteCards.Add(whiteCard); @@ -150,7 +165,7 @@ internal bool StartGame(Player player) lock (_players) { - isCardTsar = _players.FirstOrDefault(p => p.Id == player.Id)?.IsCardTsar ?? false; + isCardTsar = _players.FirstOrDefault(p => p.Id == player.Id)?.IsCardCzar ?? false; } if (!isCardTsar || RoomState is not CrowRoomStateLobby rsl) @@ -163,6 +178,10 @@ internal bool StartGame(Player player) } + internal async Task SetRoomSettings(CrowRoomSettings settings, Player player) => + RoomState is CrowRoomStateLobby rsl + && await rsl.SetRoomSettings(settings, player); + public Int32 RoundCount => RoomSettings.Rounds; public Boolean IsGameInProgress => _roomState is not CrowRoomStateLobby; @@ -197,6 +216,15 @@ internal Task SendPlayer(Player player, string method, object? arg1, object? arg => HubContext.Clients.Client(player.ConnectionId).SendAsync(method, arg1, arg2, arg3, arg4, cancellationToken: cancellationToken); #endregion + private void GetNewBlackCard() + { + var randomizedProvider = new BlackCardProvider(_unusedBlackCards); + + _unusedBlackCards.Add(randomizedProvider.GetBlackCardForRound()); + + _usedWhiteCards = new (10); + } + private static void IncrementRoomCount() { _roomCounter++; diff --git a/TheOmenDen.CrowsAgainstHumility.Services/Rooms/CrowGameRound.cs b/TheOmenDen.CrowsAgainstHumility.Services/Rooms/CrowGameRound.cs index 14f6be81a..becf8e51c 100644 --- a/TheOmenDen.CrowsAgainstHumility.Services/Rooms/CrowGameRound.cs +++ b/TheOmenDen.CrowsAgainstHumility.Services/Rooms/CrowGameRound.cs @@ -1,5 +1,6 @@ using TheOmenDen.CrowsAgainstHumility.Core.Enumerations; using TheOmenDen.CrowsAgainstHumility.Core.Models; +using TheOmenDen.CrowsAgainstHumility.Services.CardPoolBuilding; namespace TheOmenDen.CrowsAgainstHumility.Services.Rooms; internal sealed class CrowGameRound: ICrowRoomState @@ -34,8 +35,9 @@ public async Task Enter(CancellationToken cancellationToken = default) { var player = remainingPlayers.First(); _playersThatHavePlayedACard.Add(player); - _room.RoomState = new RoomStateCardTsarTurn(player, _room, this); + _room.RoomState = new RoomStateCardCzarTurn(player, _room, this); _entryCount++; + ReplenishHands(); return; } @@ -59,4 +61,9 @@ public Task RemoveCrow(Player player, CancellationToken cancellationToken = defa internal Task AddScore(List> scores) => _roomStateGame.AddScore(scores); + + private void ReplenishHands() + { + WhiteCardProvider.ReplenishPlayerHand(_room); + } } diff --git a/TheOmenDen.CrowsAgainstHumility.Services/Rooms/CrowRoomStateLobby.cs b/TheOmenDen.CrowsAgainstHumility.Services/Rooms/CrowRoomStateLobby.cs index 244fd8795..6769e23d5 100644 --- a/TheOmenDen.CrowsAgainstHumility.Services/Rooms/CrowRoomStateLobby.cs +++ b/TheOmenDen.CrowsAgainstHumility.Services/Rooms/CrowRoomStateLobby.cs @@ -15,7 +15,7 @@ internal CrowRoomStateLobby(CrowGameRoom room, Func SetRoomSettings(CrowRoomSettings settings, Player player) { - var cardTsar = _room.Players.FirstOrDefault(p => p.IsCardTsar); + var cardTsar = _room.Players.FirstOrDefault(p => p.IsCardCzar); if (cardTsar is null || cardTsar == player) { diff --git a/TheOmenDen.CrowsAgainstHumility.Services/Rooms/RoomStateBlackCard.cs b/TheOmenDen.CrowsAgainstHumility.Services/Rooms/RoomStateBlackCard.cs index 2b2b29a90..be7eaea2f 100644 --- a/TheOmenDen.CrowsAgainstHumility.Services/Rooms/RoomStateBlackCard.cs +++ b/TheOmenDen.CrowsAgainstHumility.Services/Rooms/RoomStateBlackCard.cs @@ -11,7 +11,7 @@ internal sealed class RoomStateBlackCard: ICrowRoomState private readonly Player _cardTsar; private readonly CrowGameRoom _room; private readonly WhiteCard _chosenWhiteCard; - private readonly RoomStateCardTsarTurn _roomStateCardTsarTurn; + private readonly RoomStateCardCzarTurn _roomStateCardCzarTurn; private bool _turnEnded = false; private int _turnTime; @@ -21,12 +21,12 @@ internal sealed class RoomStateBlackCard: ICrowRoomState private readonly List> _playerResults = Enumerable.Empty>().ToList(); private readonly List _chatLog = Enumerable.Empty().ToList(); - public RoomStateBlackCard(Player player, CrowGameRoom room, WhiteCard chosenWhiteCard, RoomStateCardTsarTurn roomStateCardTsarTurn) + public RoomStateBlackCard(Player player, CrowGameRoom room, WhiteCard chosenWhiteCard, RoomStateCardCzarTurn roomStateCardCzarTurn) { _cardTsar = player; _room = room; _chosenWhiteCard = chosenWhiteCard; - _roomStateCardTsarTurn = roomStateCardTsarTurn; + _roomStateCardCzarTurn = roomStateCardCzarTurn; _playersSubmitting = room.Players.Where(p => !p.Equals(_cardTsar)).ToList(); _timer = new(_turnTime * 1000, TimerElapsed); @@ -43,7 +43,7 @@ public async Task Enter(CancellationToken cancellationToken = default) public async Task AddCrow(Player player, bool isReconnection, CancellationToken cancellationToken = default) { - await _roomStateCardTsarTurn.AddCrow(player, isReconnection, cancellationToken); + await _roomStateCardCzarTurn.AddCrow(player, isReconnection, cancellationToken); switch (isReconnection) { @@ -78,7 +78,7 @@ public async Task AddCrow(Player player, bool isReconnection, CancellationToken public async Task RemoveCrow(Player player, CancellationToken cancellationToken = default) { - await _roomStateCardTsarTurn.RemoveCrow(player, cancellationToken); + await _roomStateCardCzarTurn.RemoveCrow(player, cancellationToken); if (!player.Equals(_cardTsar)) { @@ -132,7 +132,7 @@ private void EndTurn() _ = _room.SendAll("ChatMessage", cm); - _room.RoomState = new RoomStateScoring(_cardTsar, _room, _chosenWhiteCard, _playerResults, _playersSubmitting, _roomStateCardTsarTurn); + _room.RoomState = new RoomStateScoring(_cardTsar, _room, _chosenWhiteCard, _playerResults, _playersSubmitting, _roomStateCardCzarTurn); } } diff --git a/TheOmenDen.CrowsAgainstHumility.Services/Rooms/RoomStateCardTsarTurn.cs b/TheOmenDen.CrowsAgainstHumility.Services/Rooms/RoomStateCardCzarTurn.cs similarity index 94% rename from TheOmenDen.CrowsAgainstHumility.Services/Rooms/RoomStateCardTsarTurn.cs rename to TheOmenDen.CrowsAgainstHumility.Services/Rooms/RoomStateCardCzarTurn.cs index 2c80b05e8..6b06582b1 100644 --- a/TheOmenDen.CrowsAgainstHumility.Services/Rooms/RoomStateCardTsarTurn.cs +++ b/TheOmenDen.CrowsAgainstHumility.Services/Rooms/RoomStateCardCzarTurn.cs @@ -2,14 +2,14 @@ using TheOmenDen.CrowsAgainstHumility.Core.Models; namespace TheOmenDen.CrowsAgainstHumility.Services.Rooms; -internal sealed class RoomStateCardTsarTurn: ICrowRoomState +internal sealed class RoomStateCardCzarTurn: ICrowRoomState { private readonly Player _player; private readonly CrowGameRoom _room; private readonly CrowGameRound _roomRoundState; private int _entryCount = 0; - public RoomStateCardTsarTurn(Player player, CrowGameRoom room, CrowGameRound roomRoundState) + public RoomStateCardCzarTurn(Player player, CrowGameRoom room, CrowGameRound roomRoundState) { _player= player; _room= room; diff --git a/TheOmenDen.CrowsAgainstHumility.Services/Rooms/RoomStateCrowGame.cs b/TheOmenDen.CrowsAgainstHumility.Services/Rooms/RoomStateCrowGame.cs index 50d573e5a..f94194a80 100644 --- a/TheOmenDen.CrowsAgainstHumility.Services/Rooms/RoomStateCrowGame.cs +++ b/TheOmenDen.CrowsAgainstHumility.Services/Rooms/RoomStateCrowGame.cs @@ -32,7 +32,7 @@ public async Task Enter(CancellationToken cancellationToken = default) if (_entryCount < _room.RoundCount) { - _room.RoomState = new RoomStateRound(_entryCount, _room, this); + _room.RoomState = new CrowGameRound(_entryCount, _room, this); _entryCount++; return; } diff --git a/TheOmenDen.CrowsAgainstHumility.Services/Rooms/RoomStateScoring.cs b/TheOmenDen.CrowsAgainstHumility.Services/Rooms/RoomStateScoring.cs index 59e820852..70362dc55 100644 --- a/TheOmenDen.CrowsAgainstHumility.Services/Rooms/RoomStateScoring.cs +++ b/TheOmenDen.CrowsAgainstHumility.Services/Rooms/RoomStateScoring.cs @@ -9,20 +9,20 @@ internal sealed class RoomStateScoring: ICrowRoomState private readonly CrowGameRoom _room; private readonly WhiteCard _chosenWhiteCard; private readonly List _playersSubmitting; - private readonly RoomStateCardTsarTurn _roomStateCardTsarTurn; + private readonly RoomStateCardCzarTurn _roomStateCardCzarTurn; private readonly CrowGameTimer _turnEndTimer; private readonly List<(Player player, WhiteCard chosenCard)> _playerResults; private readonly int _timeout; private List<(Player player, Int32 score)> _playerScores; - public RoomStateScoring(Player player, CrowGameRoom room, WhiteCard chosenWhiteCard, List> playerResults, List playersSubmitting, RoomStateCardTsarTurn roomStateCardTsarTurn) + public RoomStateScoring(Player player, CrowGameRoom room, WhiteCard chosenWhiteCard, List> playerResults, List playersSubmitting, RoomStateCardCzarTurn roomStateCardCzarTurn) { _room = room; _chosenWhiteCard = chosenWhiteCard; _playersSubmitting = playersSubmitting; _playerResults = playerResults; - _roomStateCardTsarTurn = roomStateCardTsarTurn; + _roomStateCardCzarTurn = roomStateCardCzarTurn; _cardTsar = player; CalculateScores(); _timeout = 10 + _playerScores!.Count; @@ -32,13 +32,13 @@ public RoomStateScoring(Player player, CrowGameRoom room, WhiteCard chosenWhiteC public async Task Enter(CancellationToken cancellationToken = default) { await SendScores(_timeout, cancellationToken); - _roomStateCardTsarTurn.Scores = _playerScores; + _roomStateCardCzarTurn.Scores = _playerScores; _turnEndTimer.StartTimer(); } public async Task AddCrow(Player player, bool isReconnection, CancellationToken cancellationToken = default) { - await _roomStateCardTsarTurn.AddCrow(player, isReconnection, cancellationToken); + await _roomStateCardCzarTurn.AddCrow(player, isReconnection, cancellationToken); var turnScores = _playerScores.Select(s => new PlayerScore(s.player.ToPlayerDto(), s.score)).ToArray(); @@ -52,7 +52,7 @@ public async Task AddCrow(Player player, bool isReconnection, CancellationToken private void TurnEndTimerElapsed(object? sender, ElapsedEventArgs e) { _turnEndTimer.Dispose(); - _room.RoomState = _roomStateCardTsarTurn; + _room.RoomState = _roomStateCardCzarTurn; } private void CalculateScores() @@ -64,9 +64,9 @@ private void CalculateScores() _playerScores.Add(new(p, 0)); } - var playerResult = _playerResults.First(p => p.chosenCard == _chosenWhiteCard); + var (player, _) = _playerResults.First(p => p.chosenCard == _chosenWhiteCard); - _playerScores.Add(new(playerResult.player, 1)); + _playerScores.Add(new(player, 1)); } private async Task SendScores(int timeout, CancellationToken cancellationToken = default) diff --git a/TheOmenDen.CrowsAgainstHumility.Services/Rooms/RoomStateWinningWhiteCard.cs b/TheOmenDen.CrowsAgainstHumility.Services/Rooms/RoomStateWinningWhiteCard.cs index b565cd39d..15eeb0122 100644 --- a/TheOmenDen.CrowsAgainstHumility.Services/Rooms/RoomStateWinningWhiteCard.cs +++ b/TheOmenDen.CrowsAgainstHumility.Services/Rooms/RoomStateWinningWhiteCard.cs @@ -14,18 +14,18 @@ internal sealed class RoomStateWinningWhiteCard: ICrowRoomState private readonly Player _cardTsar; private readonly CrowGameRoom _room; - private readonly RoomStateCardTsarTurn _roomStateCardTsarTurn; + private readonly RoomStateCardCzarTurn _roomStateCardCzarTurn; private readonly List _chosenWhiteCards = new(10); private readonly CrowGameTimer _readingTimer; private bool _hasWhiteCardBeenChosen = false; - public RoomStateWinningWhiteCard(Player player, CrowGameRoom room, RoomStateCardTsarTurn roomStateCardTsarTurn) + public RoomStateWinningWhiteCard(Player player, CrowGameRoom room, RoomStateCardCzarTurn roomStateCardCzarTurn) { _cardTsar= player; _room= room; - _roomStateCardTsarTurn= roomStateCardTsarTurn; + _roomStateCardCzarTurn= roomStateCardCzarTurn; _readingTimer = new(WhiteCardChoiceTimeout * 1000, WhiteCardChoiceTimerElapsed); } @@ -54,7 +54,7 @@ public Task RemoveCrow(Player player, CancellationToken cancellationToken = defa { if (player == _cardTsar) { - _room.RoomState = _roomStateCardTsarTurn; + _room.RoomState = _roomStateCardCzarTurn; } return Task.CompletedTask; @@ -86,7 +86,7 @@ internal void WhiteCardChosen(Int32 whiteCardIndex, Player player) _room.AddRejectedWhiteCardsToPlayedWhiteCards(rejectedCards); - _room.RoomState = new RoomStateBlackCard(player, _room, chosenWhiteCard, _roomStateCardTsarTurn); + _room.RoomState = new RoomStateBlackCard(player, _room, chosenWhiteCard, _roomStateCardCzarTurn); } } diff --git a/TheOmenDen.CrowsAgainstHumility.csproj b/TheOmenDen.CrowsAgainstHumility.csproj index 4b3f00e18..d1937efaa 100644 --- a/TheOmenDen.CrowsAgainstHumility.csproj +++ b/TheOmenDen.CrowsAgainstHumility.csproj @@ -84,15 +84,15 @@ - - - - - - - - - + + + + + + + + + @@ -108,7 +108,7 @@ - + @@ -121,15 +121,15 @@ - - + + all runtime; build; native; contentfiles; analyzers; buildtransitive - +