pong-game/PongGame/Hubs/PongRoom.cs
2022-11-04 01:46:48 +01:00

99 lines
3.6 KiB
C#

using System.ComponentModel;
using Microsoft.AspNetCore.SignalR;
namespace PongGame.Hubs;
public class PongRoom {
public string ID { get; }
private readonly ILogger Logger;
private const string JOIN_LOG_TEMPLATE = "[{ID}] {Player} joined pong room as player {Number}!";
private const string LEAVE_LOG_TEMPLATE = "[{ID}] Player {Number} {Player} left pong room!";
private const string DIRECTION_LOG_TEMPLATE = "[{ID}] Player {Number} {player} moves paddle in direction: {direction}!";
public PongRoom(string id, ILogger logger) {
ID = id;
Logger = logger;
gameWorker.DoWork += GameLoop;
}
public PongPlayer? Player1 { get; private set; }
public PongPlayer? Player2 { get; private set; }
private PongGameState State = PongGameState.Initial;
public void Join(PongPlayer player) {
// TODO: synchronize this
if (Player1 is null) {
Player1 = player;
Logger.LogInformation(JOIN_LOG_TEMPLATE, ID, player, 1);
} else if (Player2 is null) {
Player2 = player;
Logger.LogInformation(JOIN_LOG_TEMPLATE, ID, player, 1);
} else
throw new HubException($"Lobby [{ID}] is already full!");
_ = Task.Run(PlayersChanged);
player.ConnectedRoom = this;
}
public void Leave(PongPlayer player) {
if (Player1 == player) {
Player1 = null;
Logger.LogInformation(LEAVE_LOG_TEMPLATE, ID, 1, player);
} else if (Player2 == player) {
Player2 = null;
Logger.LogInformation(LEAVE_LOG_TEMPLATE, ID, 2, player);
}
player.ConnectedRoom = null;
_ = Task.Run(PlayersChanged);
}
private BackgroundWorker gameWorker = new() {
WorkerSupportsCancellation = true
};
private void GameLoop(object? sender, DoWorkEventArgs e) {
while (!gameWorker.CancellationPending
&& Player1 is PongPlayer p1
&& Player2 is PongPlayer p2
&& State.Status is GameStatus.InProgress) {
PongGameState.Update(ref State);
_ = Task.Run(() => Task.WhenAll(
p1.Client.ReceiveGameState(State),
p2.Client.ReceiveGameState(State)));
Thread.Sleep(1000 / 60);
}
}
private Task PlayersChanged() {
if (Player1 is PongPlayer player1 && Player2 is PongPlayer player2) {
Logger.LogInformation("[{ID}] Pong game started: {player1} vs. {player2}", ID, player1, player2);
ResumeGame();
} else if (Player1 is null && Player2 is null) {
CloseRoom();
} else
PauseGame();
return Task.CompletedTask;
}
private void ResumeGame() {
State.Status = GameStatus.InProgress;
if (!gameWorker.IsBusy) gameWorker.RunWorkerAsync();
}
private void PauseGame() => State.Status = GameStatus.Paused;
private void CloseRoom() => State.Status = GameStatus.Finished;
public override string ToString() => $"[{ID}]";
public void MovePaddle(PongPlayer player, PongPaddleDirection direction) {
if (Player1 == player) {
State.Paddle1.Direction = direction;
Logger.LogInformation(DIRECTION_LOG_TEMPLATE, ID, 1, player, direction);
return;
} else if (Player2 == player) {
State.Paddle2.Direction = direction;
Logger.LogInformation(DIRECTION_LOG_TEMPLATE, ID, 2, player, direction);
return;
}
throw new InvalidOperationException("Player is not in this room, but moved! Assumably players room wasn't deleted.");
}
}