34f683854b
Send a GameInformationDto from the GameManager when broadcasting FieldUpdated (includes players, current field, state and current turn) and move currentTurn toggle before the broadcast. Update client code (GameConnection and LocalGame) to accept GameInformationDto for FieldUpdated, rename handler to updateState and apply the full game state payload. This ensures clients receive consistent game metadata (including current turn) with each field update.
179 lines
5.1 KiB
C#
179 lines
5.1 KiB
C#
using API.Controllers;
|
|
using API.Models.DataClasses;
|
|
using API.Models.Game;
|
|
using API.Repository.GameRepo;
|
|
using Microsoft.AspNetCore.SignalR;
|
|
|
|
namespace API.Services.GameManager;
|
|
|
|
public class GameManager(IGameRepository gameRepository, IHubContext<GameHubSocket> hubContext) : IGameManager
|
|
{
|
|
public (string, int) CreateGame(Coordinates gFs, Player player)
|
|
{
|
|
var game = gameRepository.Create(gFs);
|
|
game.AddPlayer(player);
|
|
return (game.Id, game.GameCode);
|
|
}
|
|
|
|
public async Task<string?> JoinGame(Player player, int gameCode)
|
|
{
|
|
var game = gameRepository.GetOne(new SixDigitInt(gameCode));
|
|
|
|
var success = game != null && game.State == GameState.Lobby && game.AddPlayer(player);
|
|
|
|
if (!success) return null;
|
|
|
|
if (game.Players.Count == 2)
|
|
{
|
|
game.StartGame();
|
|
|
|
var gameInfoDto = new GameInformationDto
|
|
{
|
|
Players = game?.Players,
|
|
CurrentField = ConvertField(game?.Field.CurrentField),
|
|
State = game?.State,
|
|
CurrentTurn = game?.CurrentTurn ?? 0
|
|
};
|
|
|
|
await hubContext.Clients.Group(game.Id).SendAsync("GameStarted", gameInfoDto);
|
|
}
|
|
|
|
return game.Id;
|
|
}
|
|
|
|
public async Task RequestGameInformation(string gameId, string playerConnectionId)
|
|
{
|
|
var game = gameRepository.GetOne(gameId);
|
|
if (game == null)
|
|
return;
|
|
|
|
var gameInfoDto = new GameInformationDto
|
|
{
|
|
Players = game?.Players,
|
|
CurrentField = ConvertField(game?.Field.CurrentField),
|
|
State = game?.State,
|
|
CurrentTurn = game?.CurrentTurn ?? 0
|
|
};
|
|
|
|
await hubContext.Clients.Client(playerConnectionId).SendAsync("GameInformation", gameInfoDto);
|
|
}
|
|
|
|
public async Task Drop(string gameCode, int column, string playerConnectionId)
|
|
{
|
|
var game = gameRepository.GetOne(gameCode);
|
|
|
|
var player = game?.GetPlayerByConnectionId(playerConnectionId);
|
|
if (player == null)
|
|
return;
|
|
|
|
if(game.CurrentTurn != player.PlayerTag)
|
|
return;
|
|
|
|
var result = game.Field.Drop(column, player.PlayerTag);
|
|
|
|
if (result != DropResult.Placed)
|
|
{
|
|
await hubContext.Clients.Client(playerConnectionId).SendAsync("Error", "Ungültiger Zug.");
|
|
return;
|
|
}
|
|
|
|
game.CurrentTurn = game.CurrentTurn == 1 ? 2 : 1;
|
|
var gameInfoDto = new GameInformationDto
|
|
{
|
|
Players = game?.Players,
|
|
CurrentField = ConvertField(game?.Field.CurrentField),
|
|
State = game?.State,
|
|
CurrentTurn = game?.CurrentTurn ?? 0
|
|
};
|
|
|
|
await hubContext.Clients.Group(game.Id).SendAsync("FieldUpdated", gameInfoDto);
|
|
|
|
var winResult = game.Field.CheckForWin();
|
|
if (winResult != 0)
|
|
{
|
|
var winPlayer = game.GetPlayerByTag(winResult);
|
|
game.EndGame();
|
|
await hubContext.Clients.Group(game.Id).SendAsync("GameEnded", new
|
|
{
|
|
Method = "Win",
|
|
Player = winPlayer
|
|
});
|
|
|
|
ScheduleGameDeletion(game.Id, TimeSpan.FromSeconds(5));
|
|
}
|
|
|
|
if (game.Field.IsFull())
|
|
{
|
|
game.EndGame();
|
|
|
|
await hubContext.Clients.Group(game.Id).SendAsync("GameEnded", new
|
|
{
|
|
Method = "Draw"
|
|
});
|
|
|
|
ScheduleGameDeletion(game.Id, TimeSpan.FromSeconds(5));
|
|
}
|
|
}
|
|
|
|
public Task DisconnectedPlayer(string playerConnectionId)
|
|
{
|
|
var game = gameRepository.GetOneByConnectionId(playerConnectionId);
|
|
if (game == null)
|
|
return Task.CompletedTask;
|
|
|
|
var player = game.GetPlayerByConnectionId(playerConnectionId);
|
|
if (player == null)
|
|
return Task.CompletedTask;
|
|
|
|
game.RemovePlayer(playerConnectionId);
|
|
game.EndGame();
|
|
hubContext.Clients.Group(game.Id).SendAsync("GameEnded", new
|
|
{
|
|
Method = "PlayerDisconnected",
|
|
Player = player
|
|
});
|
|
|
|
ScheduleGameDeletion(game.Id, TimeSpan.FromSeconds(5));
|
|
|
|
return Task.CompletedTask;
|
|
}
|
|
|
|
private static int[][] ConvertField(int[,]? field)
|
|
{
|
|
if (field == null)
|
|
return Array.Empty<int[]>();
|
|
|
|
var rows = field.GetLength(0);
|
|
var cols = field.GetLength(1);
|
|
var convertedField = new int[rows][];
|
|
|
|
for (var y = 0; y < rows; y++)
|
|
{
|
|
convertedField[y] = new int[cols];
|
|
|
|
for (var x = 0; x < cols; x++)
|
|
{
|
|
convertedField[y][x] = field[y, x];
|
|
}
|
|
}
|
|
|
|
return convertedField;
|
|
}
|
|
|
|
private void ScheduleGameDeletion(string gameId, TimeSpan delay)
|
|
{
|
|
_ = Task.Run(async () =>
|
|
{
|
|
await Task.Delay(delay);
|
|
|
|
var g = gameRepository.GetOne(gameId);
|
|
if (g != null && g.State == GameState.Ended)
|
|
{
|
|
gameRepository.Destroy(gameId);
|
|
|
|
await hubContext.Clients.Group(gameId).SendAsync("GameDestroyed");
|
|
}
|
|
});
|
|
}
|
|
}
|