diff --git a/ProChess/Client/Client.csproj b/ProChess/Client/Client.csproj index e63adef..985b370 100644 --- a/ProChess/Client/Client.csproj +++ b/ProChess/Client/Client.csproj @@ -15,9 +15,10 @@ - - - + + + + diff --git a/ProChess/Client/Components/Board/Chessboard.razor.cs b/ProChess/Client/Components/Board/Chessboard.razor.cs index 17b1122..501ece8 100644 --- a/ProChess/Client/Components/Board/Chessboard.razor.cs +++ b/ProChess/Client/Components/Board/Chessboard.razor.cs @@ -2,6 +2,7 @@ using Blazored.Modal.Services; using Microsoft.AspNetCore.Components; using Microsoft.AspNetCore.Components.Web; +using Microsoft.AspNetCore.SignalR.Client; using Shared.Data; using Shared.Rules; @@ -9,29 +10,67 @@ namespace Client.Components.Board { public partial class Chessboard { - [CascadingParameter] - IModalService Modal { get; set; } = default!; - private bool _whiteTurn { get; set; } = true; - Piece? activePiece = null; - List cellsPossible = new(); + #region Parameters + + [CascadingParameter] IModalService Modal { get; set; } = default!; + [Parameter] public HubConnection HubConnection { get; set; } = default!; + [Parameter] public string TableId { get; set; } = default!; + [Parameter] public bool IsWhitePlayer { get; set; } + + #endregion + + #region Private filds and properties + + #region Fields + private readonly int[] _positionsTransformation = { 0, 7 }; private readonly string[] _horizontalAxis = { "a", "b", "c", "d", "e", "f", "g", "h" }; private readonly string[] _verticalAxis = { "1", "2", "3", "4", "5", "6", "7", "8" }; - private readonly int[] _positionsTransformation = { 0, 7 }; + #endregion + + #region Property + + private bool _whiteTurn { get; set; } = true; private List _whitePieces { get; set; } = new List(); private List _blackPieces { get; set; } = new List(); + #endregion + + #endregion + + Piece? activePiece = null; + List cellsPossible = new(); + protected override void OnInitialized() { GamePieces gamePieces = new GamePieces(); _blackPieces = gamePieces.InitializationBlackPieces(); _whitePieces = gamePieces.InitializationWhitePieces(); + + HubConnection.On("Move", ServerMoveAsync); + } + + private async Task ServerMoveAsync(int previousRow, int previousColumn, int newRow, int newColumn) + { + var piece = _blackPieces.FirstOrDefault(x => x.StartColumn == previousColumn && x.StartRow == previousRow); + if (piece == null) + { + piece = _whitePieces.FirstOrDefault(x => x.StartColumn == previousColumn && x.StartRow == previousRow); + } + activePiece = piece; + EvaluatePieceSpots(); + await MoveOrAttackPiece(new Cell(newRow, newColumn)); } private void ClickOnPiece(MouseEventArgs e, Piece piece) { + if (_whiteTurn != IsWhitePlayer) + { + return; + } + if (activePiece == piece) { activePiece = null; @@ -74,6 +113,8 @@ private async Task MoveOrAttackPiece(Cell cell) if (activePiece != null) { + await HubConnection.SendAsync("Move", TableId, activePiece.StartRow, activePiece.StartColumn, cell.Row, cell.Column); + activePiece.MoveOrAttack(cell, _whitePieces, _blackPieces); if (activePiece as Pawn != null && (activePiece.StartRow == _positionsTransformation[0] || @@ -85,7 +126,7 @@ private async Task MoveOrAttackPiece(Cell cell) var infoPiece = await modal.Result; var newPiece = (infoPiece.Data as Piece) ?? throw new InvalidOperationException("Bad"); - if (activePiece.Color == PieceColor.White) + if (activePiece.Color == PieceColor.White) { _whitePieces.Remove(activePiece); _whitePieces.Add(newPiece); @@ -100,6 +141,7 @@ private async Task MoveOrAttackPiece(Cell cell) activePiece = null; _whiteTurn = !_whiteTurn; EvaluatePieceSpots(); + StateHasChanged(); } } } diff --git a/ProChess/Client/Pages/Index.razor b/ProChess/Client/Pages/Index.razor index a64654c..37083c8 100644 --- a/ProChess/Client/Pages/Index.razor +++ b/ProChess/Client/Pages/Index.razor @@ -1,5 +1,22 @@ @page "/" +@using Microsoft.AspNetCore.SignalR.Client; +@inject HttpClient Http -
- -
+@if (@inGame) +{ +
+ +
+} +else +{ + + + @if (tables != null) + { + @foreach (string tableId in tables) + { + + } + } +} diff --git a/ProChess/Client/Pages/Index.razor.cs b/ProChess/Client/Pages/Index.razor.cs new file mode 100644 index 0000000..2c2eb28 --- /dev/null +++ b/ProChess/Client/Pages/Index.razor.cs @@ -0,0 +1,45 @@ +using System.Net.Http.Json; +using Microsoft.AspNetCore.SignalR.Client; + +namespace Client.Pages +{ + public partial class Index + { + HubConnection hubConnection = new HubConnectionBuilder().WithUrl("https://localhost:7197/connect").Build(); + + bool inGame = false; + bool isWhitePlayer = true; + string tableId = ""; + + List? tables = new List(); + + protected override async Task OnInitializedAsync() + { + await RefreshTables(); + } + + public async Task RefreshTables() + { + tables = await Http.GetFromJsonAsync>("/table/getTables"); + } + + public async Task CreateGame() + { + await hubConnection.StartAsync(); + + tableId = Guid.NewGuid().ToString(); + await hubConnection.SendAsync("JoinTable", tableId); + inGame = true; + } + + public async Task JoinGame(string gameId) + { + await hubConnection.StartAsync(); + this.tableId = gameId; + isWhitePlayer = false; + await hubConnection.SendAsync("JoinTable", gameId); + inGame = true; + } + } +} + diff --git a/ProChess/Client/Program.cs b/ProChess/Client/Program.cs index bb6b230..5960430 100644 --- a/ProChess/Client/Program.cs +++ b/ProChess/Client/Program.cs @@ -2,8 +2,8 @@ using Microsoft.AspNetCore.Components.Web; using Microsoft.AspNetCore.Components.WebAssembly.Hosting; using Client; -using Blazored.Modal; using Client.Auth; +using Blazored.Modal; using Blazored.LocalStorage; using Client.Auth.Service; diff --git a/ProChess/Domain/Domain.csproj b/ProChess/Domain/Domain.csproj index 2d39ad8..5fedccc 100644 --- a/ProChess/Domain/Domain.csproj +++ b/ProChess/Domain/Domain.csproj @@ -13,8 +13,8 @@
- - + + diff --git a/ProChess/Shared/Data/TableManager.cs b/ProChess/Shared/Data/TableManager.cs new file mode 100644 index 0000000..e67b476 --- /dev/null +++ b/ProChess/Shared/Data/TableManager.cs @@ -0,0 +1,7 @@ +namespace Shared.Data +{ + public class TableManager + { + public Dictionary Tables { get; set; } = new(); + } +} diff --git a/ProChess/Shared/Shared.csproj b/ProChess/Shared/Shared.csproj index 23f7122..678d50d 100644 --- a/ProChess/Shared/Shared.csproj +++ b/ProChess/Shared/Shared.csproj @@ -7,7 +7,7 @@ - + diff --git a/ProChess/Tests/Shared.Test/Shared.Test.csproj b/ProChess/Tests/Shared.Test/Shared.Test.csproj index af67685..a775e09 100644 --- a/ProChess/Tests/Shared.Test/Shared.Test.csproj +++ b/ProChess/Tests/Shared.Test/Shared.Test.csproj @@ -9,7 +9,7 @@ - + diff --git a/ProChess/WebAPI/Controllers/TableController.cs b/ProChess/WebAPI/Controllers/TableController.cs new file mode 100644 index 0000000..8a5f5e4 --- /dev/null +++ b/ProChess/WebAPI/Controllers/TableController.cs @@ -0,0 +1,23 @@ +using Microsoft.AspNetCore.Mvc; +using Shared.Data; + +namespace WebAPI.Controllers +{ + [Route("table")] + [ApiController] + public class TableController : ControllerBase + { + private readonly TableManager _tableManager; + + public TableController(TableManager tableManager) + { + _tableManager = tableManager; + } + + [HttpGet("getTables")] + public IEnumerable GetTables() + { + return _tableManager.Tables.Where(x => x.Value < 2).Select(x => x.Key); + } + } +} diff --git a/ProChess/WebAPI/Hubs/MultiplayerHub.cs b/ProChess/WebAPI/Hubs/MultiplayerHub.cs new file mode 100644 index 0000000..4e60ef2 --- /dev/null +++ b/ProChess/WebAPI/Hubs/MultiplayerHub.cs @@ -0,0 +1,40 @@ +using Microsoft.AspNetCore.SignalR; +using Shared.Data; + +namespace WebAPI.Hubs +{ + public class MultiplayerHub : Hub + { + private readonly TableManager _tableManager; + + public MultiplayerHub(TableManager tableManager) + { + _tableManager = tableManager; + } + + public async Task JoinTable(string tableId) + { + if (_tableManager.Tables.ContainsKey(tableId)) + { + if (_tableManager.Tables[tableId] < 2) + { + await Groups.AddToGroupAsync(Context.ConnectionId, tableId); + + await Clients.GroupExcept(tableId, Context.ConnectionId).SendAsync("TableJoined"); + + _tableManager.Tables[tableId]++; + } + } + else + { + await Groups.AddToGroupAsync(Context.ConnectionId, tableId); + _tableManager.Tables.Add(tableId, 1); + } + } + + public async Task Move(string tableId, int previousRow, int previousColumn, int newRow, int newColumn) + { + await Clients.GroupExcept(tableId, Context.ConnectionId).SendAsync("Move", previousRow, previousColumn, newRow, newColumn); + } + } +} diff --git a/ProChess/WebAPI/Program.cs b/ProChess/WebAPI/Program.cs index d960b74..43f6033 100644 --- a/ProChess/WebAPI/Program.cs +++ b/ProChess/WebAPI/Program.cs @@ -5,7 +5,9 @@ using Microsoft.AspNetCore.Identity; using Microsoft.EntityFrameworkCore; using Microsoft.IdentityModel.Tokens; +using Shared.Data; using System.Text; +using WebAPI.Hubs; var builder = WebApplication.CreateBuilder(args); @@ -14,6 +16,7 @@ builder.Services.AddControllersWithViews(); builder.Services.AddRazorPages(); +builder.Services.AddSignalR(); builder.Services.AddDbContext(options => options.UseNpgsql(builder.Configuration.GetConnectionString("ChessDatabase"))); @@ -35,15 +38,10 @@ }; }); -//builder.Services.AddSwaggerGen(options => options.SwaggerDoc("v1", -// new Microsoft.OpenApi.Models.OpenApiInfo -// { -// Title = "ProChess", -// Version = "v1", -// })); builder.Services.AddSwaggerGen(); builder.Services.AddScoped(); +builder.Services.AddSingleton(); var app = builder.Build(); @@ -65,7 +63,6 @@ app.UseStaticFiles(); app.UseSwagger(); -//app.UseSwaggerUI(options => options.SwaggerEndpoint("/swagger/v1/swagger.json", "ProChess")); app.UseSwaggerUI(); app.UseRouting(); @@ -75,6 +72,7 @@ app.MapRazorPages(); app.MapControllers(); +app.MapHub("/connect"); app.MapFallbackToFile("index.html"); app.Run(); diff --git a/ProChess/WebAPI/WebAPI.csproj b/ProChess/WebAPI/WebAPI.csproj index fafe6a5..42a6142 100644 --- a/ProChess/WebAPI/WebAPI.csproj +++ b/ProChess/WebAPI/WebAPI.csproj @@ -9,10 +9,10 @@ - - - - + + + + all runtime; build; native; contentfiles; analyzers; buildtransitive