Split up methods in controllers, added tests for GameService, refactored GameGroup name to Game and directory Game to GameStuff

This commit is contained in:
Martin Berg Alstad 2023-07-18 17:09:27 +02:00
parent fab3e3d13f
commit c7bc473572
25 changed files with 243 additions and 164 deletions

View File

@ -5,7 +5,7 @@ using System.Text.Json;
using Microsoft.Extensions.Logging;
using NSubstitute;
using pacMan.Controllers;
using pacMan.Game;
using pacMan.GameStuff;
using pacMan.Services;
using pacMan.Utils;

View File

@ -1,4 +1,4 @@
using pacMan.Game.Items;
using pacMan.GameStuff.Items;
namespace BackendTests.Game.Items;
@ -11,7 +11,7 @@ public class DiceCupTests
var roll = diceCup.Roll;
Assert.That(roll, Has.Count.EqualTo(2));
}
[Test]
public void Roll_ReturnsNumbersInRange1To6()
{

View File

@ -1,4 +1,4 @@
using pacMan.Game.Items;
using pacMan.GameStuff.Items;
namespace BackendTests.Game.Items;

View File

@ -2,8 +2,8 @@ using System.Text.Json;
using BackendTests.TestUtils;
using Microsoft.Extensions.Logging;
using NSubstitute;
using pacMan.Game;
using pacMan.Game.Items;
using pacMan.GameStuff;
using pacMan.GameStuff.Items;
using pacMan.Services;
namespace BackendTests.Services;
@ -171,7 +171,8 @@ public class ActionServiceTests
[Test]
public void Ready_TwoReady()
{
var group = new GameGroup(new Queue<DirectionalPosition>()) { Players = { _blackPlayer, _whitePlayer } };
var group = new pacMan.Services.Game(new Queue<DirectionalPosition>())
{ Players = { _blackPlayer, _whitePlayer } };
_service.Group = group;
_service.Player = _blackPlayer;
@ -194,7 +195,7 @@ public class ActionServiceTests
[Test]
public void FindNextPlayer_NoPlayers()
{
_service.Group = new GameGroup(new Queue<DirectionalPosition>());
_service.Group = new pacMan.Services.Game(new Queue<DirectionalPosition>());
Assert.Throws<InvalidOperationException>(() => _service.FindNextPlayer());
}
@ -202,7 +203,7 @@ public class ActionServiceTests
public void FindNextPlayer_OnePlayer()
{
_service.Group =
new GameGroup(new Queue<DirectionalPosition>(
new pacMan.Services.Game(new Queue<DirectionalPosition>(
new[] { new DirectionalPosition { At = new Position { X = 3, Y = 3 }, Direction = Direction.Up } }))
{ Players = { _whitePlayer } };
@ -213,7 +214,7 @@ public class ActionServiceTests
[Test]
public void FindNextPlayer_TwoPlayers()
{
_service.Group = new GameGroup(new Queue<DirectionalPosition>(
_service.Group = new pacMan.Services.Game(new Queue<DirectionalPosition>(
new[]
{
new DirectionalPosition { At = new Position { X = 3, Y = 3 }, Direction = Direction.Up },

View File

@ -0,0 +1,100 @@
using BackendTests.TestUtils;
using Microsoft.Extensions.Logging;
using NSubstitute;
using pacMan.Exceptions;
using pacMan.GameStuff;
using pacMan.Services;
namespace BackendTests.Services;
public class GameServiceTests
{
private readonly DirectionalPosition _spawn3By3Up = new()
{ At = new Position { X = 3, Y = 3 }, Direction = Direction.Up };
private GameService _service = null!;
private Queue<DirectionalPosition> _spawns = null!;
[SetUp]
public void SetUp()
{
_service = new GameService(Substitute.For<ILogger<GameService>>());
_spawns = new Queue<DirectionalPosition>(new[]
{
_spawn3By3Up,
new DirectionalPosition { At = new Position { X = 7, Y = 7 }, Direction = Direction.Down },
new DirectionalPosition { At = new Position { X = 7, Y = 7 }, Direction = Direction.Down },
new DirectionalPosition { At = new Position { X = 7, Y = 7 }, Direction = Direction.Down }
});
}
#region JoinbyId(Guid id)
[Test]
public void JoinById_WhenIdNotExists()
{
var player = Players.Create("white");
_service.AddPlayer(player, _spawns);
Assert.Throws<GameNotFoundException>(() => _service.JoinById(Guid.NewGuid(), player));
}
[Test]
public void JoinById_WhenIdExists()
{
var player = Players.Create("white");
var group = _service.AddPlayer(player, _spawns);
var player2 = Players.Create("black");
var result = _service.JoinById(group.Id, player2);
Assert.Multiple(() =>
{
Assert.That(result, Is.EqualTo(group));
Assert.That(group.Players, Has.Count.EqualTo(2));
Assert.That(_service.Games, Has.Count.EqualTo(1));
});
}
#endregion
#region AddPlayer(IPlayer)
[Test]
public void AddPlayer_ToEmptyGroup()
{
var player = Players.Create("white");
var group = _service.AddPlayer(player, _spawns);
Assert.Multiple(() =>
{
Assert.That(group.Players, Has.Count.EqualTo(1));
Assert.That(group.NextPlayer, Is.EqualTo(player));
Assert.That(_service.Games, Has.Count.EqualTo(1));
});
}
[Test]
public void AddPlayer_ToFullGroup()
{
for (var i = 0; i < 4; i++)
{
var player = Players.Create(i.ToString());
_service.AddPlayer(player, _spawns);
}
var player5 = Players.Create("white");
var group = _service.AddPlayer(player5, new Queue<DirectionalPosition>(new[] { _spawn3By3Up }));
Assert.Multiple(() =>
{
Assert.That(group.Players, Has.Count.EqualTo(1));
Assert.That(group.NextPlayer, Is.EqualTo(player5));
Assert.That(_service.Games, Has.Count.EqualTo(2));
Assert.That(_service.Games.First(), Has.Count.EqualTo(Rules.MaxPlayers));
});
}
#endregion
}

View File

@ -1,13 +1,12 @@
using BackendTests.TestUtils;
using pacMan.Exceptions;
using pacMan.Game;
using pacMan.Game.Items;
using pacMan.Services;
using pacMan.GameStuff;
using pacMan.GameStuff.Items;
using pacMan.Utils;
namespace BackendTests.Services;
public class GameGroupTests
public class GameTests
{
private readonly DirectionalPosition _spawn3By3Up = new()
{ At = new Position { X = 3, Y = 3 }, Direction = Direction.Up };
@ -22,7 +21,7 @@ public class GameGroupTests
{ At = new Position { X = 7, Y = 7 }, Direction = Direction.Right };
private IPlayer _bluePlayer = null!;
private GameGroup _gameGroup = null!;
private pacMan.Services.Game _game = null!;
private IPlayer _greenPlayer = null!;
private IPlayer _purplePlayer = null!;
private IPlayer _redPlayer = null!;
@ -36,7 +35,7 @@ public class GameGroupTests
_spawns = new Queue<DirectionalPosition>(
new[] { _spawn3By3Up, _spawn7By7Left, _spawn7By7Down, _spawn7By7Right });
_gameGroup = new GameGroup(_spawns);
_game = new pacMan.Services.Game(_spawns);
_redPlayer = Players.Create("red");
_bluePlayer = Players.Create("blue");
_yellowPlayer = Players.Create("yellow");
@ -46,10 +45,10 @@ public class GameGroupTests
private void AddFullParty()
{
_gameGroup.AddPlayer(_bluePlayer);
_gameGroup.AddPlayer(_redPlayer);
_gameGroup.AddPlayer(_yellowPlayer);
_gameGroup.AddPlayer(_greenPlayer);
_game.AddPlayer(_bluePlayer);
_game.AddPlayer(_redPlayer);
_game.AddPlayer(_yellowPlayer);
_game.AddPlayer(_greenPlayer);
}
#region NextPlayer()
@ -57,7 +56,7 @@ public class GameGroupTests
[Test]
public void NextPlayer_WhenEmpty()
{
Assert.Throws<InvalidOperationException>(() => _gameGroup.NextPlayer());
Assert.Throws<InvalidOperationException>(() => _game.NextPlayer());
}
#endregion
@ -67,7 +66,7 @@ public class GameGroupTests
[Test]
public void AddPlayer_WhenEmpty()
{
var added = _gameGroup.AddPlayer(_redPlayer);
var added = _game.AddPlayer(_redPlayer);
Assert.That(added, Is.True);
}
@ -76,16 +75,16 @@ public class GameGroupTests
Assert.Multiple(() =>
{
AddFullParty();
Assert.That(_gameGroup.Players.Count, Is.EqualTo(Rules.MaxPlayers));
Assert.That(_gameGroup.AddPlayer(_purplePlayer), Is.False);
Assert.That(_game.Players.Count, Is.EqualTo(Rules.MaxPlayers));
Assert.That(_game.AddPlayer(_purplePlayer), Is.False);
});
[Test]
public void AddPlayer_WhenNameExists()
{
var redClone = Players.Clone(_redPlayer);
_gameGroup.AddPlayer(_redPlayer);
var added = _gameGroup.AddPlayer(redClone);
_game.AddPlayer(_redPlayer);
var added = _game.AddPlayer(redClone);
Assert.That(added, Is.True);
}
@ -93,14 +92,14 @@ public class GameGroupTests
public void AddPlayer_WhenStateIsNotWaitingForPlayers()
{
_redPlayer.State = State.InGame;
_gameGroup.AddPlayer(_redPlayer);
_game.AddPlayer(_redPlayer);
Assert.That(_redPlayer.State, Is.EqualTo(State.WaitingForPlayers));
}
[Test]
public void AddPlayer_AddSpawnPosition()
{
_gameGroup.AddPlayer(_redPlayer);
_game.AddPlayer(_redPlayer);
Assert.That(_redPlayer.PacMan.SpawnPosition, Is.Not.Null);
Assert.That(_redPlayer.PacMan.SpawnPosition, Is.EqualTo(_spawn3By3Up));
}
@ -108,16 +107,16 @@ public class GameGroupTests
[Test]
public void AddPlayer_WhenGameHasStarted()
{
_gameGroup.AddPlayer(_redPlayer);
_gameGroup.AddPlayer(_bluePlayer);
_game.AddPlayer(_redPlayer);
_game.AddPlayer(_bluePlayer);
_gameGroup.SetReady(_redPlayer);
_gameGroup.SetReady(_bluePlayer);
_gameGroup.SetAllInGame();
Assert.That(_gameGroup.AddPlayer(_greenPlayer), Is.False);
_game.SetReady(_redPlayer);
_game.SetReady(_bluePlayer);
_game.SetAllInGame();
Assert.That(_game.AddPlayer(_greenPlayer), Is.False);
}
#endregion
#region Sendtoall(ArraySegment<byte> segment)
@ -125,7 +124,7 @@ public class GameGroupTests
[Test]
public void SendToAll_WhenConnectionsIsNull()
{
Assert.DoesNotThrow(() => _gameGroup.SendToAll(new { }.ToArraySegment()));
Assert.DoesNotThrow(() => _game.SendToAll(new { }.ToArraySegment()));
}
[Test]
@ -134,10 +133,10 @@ public class GameGroupTests
var counter = 0;
async Task Send(ArraySegment<byte> segment) => await Task.Run(() => counter++);
_gameGroup.Connections += Send;
_gameGroup.Connections += Send;
_game.Connections += Send;
_game.Connections += Send;
_gameGroup.SendToAll(new { }.ToArraySegment());
_game.SendToAll(new { }.ToArraySegment());
// TODO timeout after n amount of time
while (counter < 2) { }
@ -152,10 +151,10 @@ public class GameGroupTests
[Test]
public void SetReady_ReturnsAllPlayers()
{
_gameGroup.AddPlayer(_redPlayer);
_gameGroup.AddPlayer(_bluePlayer);
_game.AddPlayer(_redPlayer);
_game.AddPlayer(_bluePlayer);
var players = _gameGroup.SetReady(_redPlayer).ToList();
var players = _game.SetReady(_redPlayer).ToList();
Assert.Multiple(() =>
{
@ -168,11 +167,11 @@ public class GameGroupTests
[Test]
public void SetReady_SetsStateToReady()
{
_gameGroup.AddPlayer(_redPlayer);
_game.AddPlayer(_redPlayer);
Assert.That(_redPlayer.State, Is.Not.EqualTo(State.Ready));
_gameGroup.SetReady(_redPlayer);
_game.SetReady(_redPlayer);
Assert.That(_redPlayer.State, Is.EqualTo(State.Ready));
}
@ -180,7 +179,7 @@ public class GameGroupTests
[Test]
public void SetReady_WhenPlayerIsNotInPlayers()
{
Assert.Throws<PlayerNotFoundException>(() => _gameGroup.SetReady(_redPlayer));
Assert.Throws<PlayerNotFoundException>(() => _game.SetReady(_redPlayer));
}
#endregion
@ -191,15 +190,15 @@ public class GameGroupTests
public void SetAllInGame_SetsStateToInGame()
{
AddFullParty();
_gameGroup.Players.ForEach(player => player.State = State.Ready);
Assert.That(_gameGroup.Players, Has.All.Property(nameof(IPlayer.State)).EqualTo(State.Ready));
_game.Players.ForEach(player => player.State = State.Ready);
Assert.That(_game.Players, Has.All.Property(nameof(IPlayer.State)).EqualTo(State.Ready));
var allInGame = _gameGroup.SetAllInGame();
var allInGame = _game.SetAllInGame();
Assert.Multiple(() =>
{
Assert.That(allInGame, Is.True);
Assert.That(_gameGroup.Players, Has.All.Property(nameof(IPlayer.State)).EqualTo(State.InGame));
Assert.That(_game.Players, Has.All.Property(nameof(IPlayer.State)).EqualTo(State.InGame));
});
}
@ -207,15 +206,15 @@ public class GameGroupTests
public void SetAllInGame_SetStateToInGame_WhenNotAllReady()
{
AddFullParty();
var allInGame = _gameGroup.SetAllInGame();
var allInGame = _game.SetAllInGame();
Assert.That(allInGame, Is.False);
}
[Test]
public void SetAllInGame_WhenPlayersIsEmpty()
{
_gameGroup.SetAllInGame();
Assert.That(_gameGroup.Players, Is.Empty);
_game.SetAllInGame();
Assert.That(_game.Players, Is.Empty);
}
#endregion
@ -226,15 +225,15 @@ public class GameGroupTests
public void IsGameStarted_AllWaiting()
{
AddFullParty();
Assert.That(_gameGroup.IsGameStarted, Is.False);
Assert.That(_game.IsGameStarted, Is.False);
}
[Test]
public void IsGameStarted_AllInGame()
{
AddFullParty();
_gameGroup.Players.ForEach(player => player.State = State.InGame);
Assert.That(_gameGroup.IsGameStarted, Is.True);
_game.Players.ForEach(player => player.State = State.InGame);
Assert.That(_game.IsGameStarted, Is.True);
}
#endregion

View File

@ -1,8 +1,7 @@
using System.Net.WebSockets;
using BackendTests.TestUtils;
using Microsoft.Extensions.Logging;
using NSubstitute;
using pacMan.Game;
using pacMan.Interfaces;
using pacMan.Services;
using pacMan.Utils;
@ -10,25 +9,12 @@ namespace BackendTests.Services;
public class WebSocketServiceTests
{
private readonly DirectionalPosition _spawn3By3Up = new()
{ At = new Position { X = 3, Y = 3 }, Direction = Direction.Up };
private GameService _service = null!;
private Queue<DirectionalPosition> _spawns = null!;
private IWebSocketService _service = null!;
[SetUp]
public void SetUp()
{
_service = new GameService(Substitute.For<ILogger<GameService>>());
_spawns = new Queue<DirectionalPosition>(new[]
{
_spawn3By3Up,
new DirectionalPosition { At = new Position { X = 7, Y = 7 }, Direction = Direction.Down },
new DirectionalPosition { At = new Position { X = 7, Y = 7 }, Direction = Direction.Down },
new DirectionalPosition { At = new Position { X = 7, Y = 7 }, Direction = Direction.Down }
});
_service = new WebSocketService(Substitute.For<ILogger<WebSocketService>>());
}
#region Send(Websocket, ArraySegment<byte>)
@ -140,44 +126,4 @@ public class WebSocketServiceTests
}
#endregion
#region AddPlayer(IPlayer)
[Test]
public void AddPlayer_ToEmptyGroup()
{
var player = Players.Create("white");
var group = _service.AddPlayer(player, _spawns);
Assert.Multiple(() =>
{
Assert.That(group.Players, Has.Count.EqualTo(1));
Assert.That(group.NextPlayer, Is.EqualTo(player));
Assert.That(_service.Games, Has.Count.EqualTo(1));
});
}
[Test]
public void AddPlayer_ToFullGroup()
{
for (var i = 0; i < 4; i++)
{
var player = Players.Create(i.ToString());
_service.AddPlayer(player, _spawns);
}
var player5 = Players.Create("white");
var group = _service.AddPlayer(player5, new Queue<DirectionalPosition>(new[] { _spawn3By3Up }));
Assert.Multiple(() =>
{
Assert.That(group.Players, Has.Count.EqualTo(1));
Assert.That(group.NextPlayer, Is.EqualTo(player5));
Assert.That(_service.Games, Has.Count.EqualTo(2));
Assert.That(_service.Games.First(), Has.Count.EqualTo(Rules.MaxPlayers));
});
}
#endregion
}

View File

@ -1,5 +1,5 @@
using pacMan.Game;
using pacMan.Game.Items;
using pacMan.GameStuff;
using pacMan.GameStuff.Items;
namespace BackendTests.TestUtils;

View File

@ -4,7 +4,7 @@ import {Button} from "../components/Button";
const fetchAtom = atom(async () => {
const response = await fetch(import.meta.env.VITE_API_HTTP + "/allGames");
return await response.json() as GameGroup[];
return await response.json() as Game[];
});
const LobbyPage: Component = () => (

View File

@ -35,7 +35,7 @@ type Path = {
Direction: import("../game/direction").Direction
}
type GameGroup = {
type Game = {
readonly id: string,
readonly count: number,
readonly isGameStarted: boolean,

View File

@ -1,6 +1,6 @@
using System.Net.WebSockets;
using Microsoft.AspNetCore.Mvc;
using pacMan.Game;
using pacMan.GameStuff;
using pacMan.Services;
using pacMan.Utils;
@ -11,19 +11,23 @@ namespace pacMan.Controllers;
public class GameController : GenericController // TODO reconnect using player id
{
private readonly IActionService _actionService;
private readonly GameService _gameService;
public GameController(ILogger<GameController> logger, GameService gameService, IActionService actionService) :
base(logger, gameService) =>
base(logger, gameService)
{
_gameService = gameService;
_actionService = actionService;
}
[HttpGet("connect")]
public override async Task Accept() => await base.Accept();
[HttpGet("allGames")]
public IEnumerable<GameGroup> GetAllGames()
public IEnumerable<Game> GetAllGames()
{
Logger.Log(LogLevel.Information, "Returning all games");
return GameService.Games;
return _gameService.Games;
}
@ -38,9 +42,23 @@ public class GameController : GenericController // TODO reconnect using player i
return action.ToArraySegment();
}
protected override void Send(ArraySegment<byte> segment) => _gameService.SendToAll(segment);
protected override Task Echo()
{
_gameService.Connections += WsServiceOnFire;
return base.Echo();
}
protected override void Disconnect()
{
base.Disconnect();
_gameService.Connections -= WsServiceOnFire;
_actionService.Disconnect();
}
private async Task WsServiceOnFire(ArraySegment<byte> segment)
{
if (WebSocket == null) return;
await GameService.Send(WebSocket, segment);
}
}

View File

@ -1,17 +1,17 @@
using System.Net.WebSockets;
using Microsoft.AspNetCore.Mvc;
using pacMan.Services;
using pacMan.Interfaces;
namespace pacMan.Controllers;
public abstract class GenericController : ControllerBase // TODO only use WebSocketService in this class
public abstract class GenericController : ControllerBase
{
private const int BufferSize = 1024 * 4;
protected readonly GameService GameService;
protected readonly IWebSocketService GameService;
protected readonly ILogger<GenericController> Logger;
private WebSocket? _webSocket;
protected WebSocket? WebSocket;
protected GenericController(ILogger<GenericController> logger, GameService gameService)
protected GenericController(ILogger<GenericController> logger, IWebSocketService gameService)
{
Logger = logger;
GameService = gameService;
@ -24,8 +24,7 @@ public abstract class GenericController : ControllerBase // TODO only use WebSoc
{
using var webSocket = await HttpContext.WebSockets.AcceptWebSocketAsync();
Logger.Log(LogLevel.Information, "WebSocket connection established to {}", HttpContext.Connection.Id);
_webSocket = webSocket;
GameService.Connections += WsServiceOnFire;
WebSocket = webSocket;
await Echo();
}
else
@ -34,32 +33,25 @@ public abstract class GenericController : ControllerBase // TODO only use WebSoc
}
}
private async Task WsServiceOnFire(ArraySegment<byte> segment)
{
if (_webSocket == null) return;
await GameService.Send(_webSocket, segment);
}
protected virtual async Task Echo()
{
if (_webSocket == null) return;
if (WebSocket == null) return;
try
{
WebSocketReceiveResult? result;
do
{
var buffer = new byte[BufferSize];
result = await GameService.Receive(_webSocket, buffer);
result = await GameService.Receive(WebSocket, buffer);
if (result.CloseStatus.HasValue) break;
var segment = Run(result, buffer);
GameService.SendToAll(segment);
Send(segment);
} while (true);
await GameService.Close(_webSocket, result.CloseStatus.Value, result.CloseStatusDescription);
await GameService.Close(WebSocket, result.CloseStatus.Value, result.CloseStatusDescription);
}
catch (WebSocketException e)
{
@ -69,7 +61,13 @@ public abstract class GenericController : ControllerBase // TODO only use WebSoc
Disconnect();
}
protected virtual async void Send(ArraySegment<byte> segment)
{
if (WebSocket == null) return;
await GameService.Send(WebSocket, segment);
}
protected abstract ArraySegment<byte> Run(WebSocketReceiveResult result, byte[] data);
protected virtual void Disconnect() => GameService.Connections -= WsServiceOnFire;
protected virtual void Disconnect() { }
}

View File

@ -0,0 +1,6 @@
namespace pacMan.Exceptions;
public class GameNotFoundException : Exception
{
public GameNotFoundException(string message = "Game not found") : base(message) { }
}

View File

@ -1,6 +1,6 @@
using System.Text.Json;
namespace pacMan.Game;
namespace pacMan.GameStuff;
public enum GameAction
{

View File

@ -1,4 +1,4 @@
namespace pacMan.Game;
namespace pacMan.GameStuff;
public class Character : IEquatable<Character>
{

View File

@ -1,4 +1,4 @@
namespace pacMan.Game.Items;
namespace pacMan.GameStuff.Items;
public class Box : IEquatable<Box>
{

View File

@ -1,4 +1,4 @@
namespace pacMan.Game.Items;
namespace pacMan.GameStuff.Items;
public interface IDice
{

View File

@ -1,4 +1,4 @@
namespace pacMan.Game.Items;
namespace pacMan.GameStuff.Items;
public interface IDiceCup
{

View File

@ -1,4 +1,4 @@
namespace pacMan.Game.Items;
namespace pacMan.GameStuff.Items;
public interface IPellet
{

View File

@ -1,4 +1,4 @@
namespace pacMan.Game.Items;
namespace pacMan.GameStuff.Items;
public interface IPlayer
{

View File

@ -1,4 +1,4 @@
namespace pacMan.Game;
namespace pacMan.GameStuff;
public class MovePath : IEquatable<MovePath>
{

View File

@ -1,4 +1,4 @@
namespace pacMan.Game;
namespace pacMan.GameStuff;
public class Rules
{
@ -6,4 +6,4 @@ public class Rules
public const int MaxPlayers = 4;
public const int NumGhosts = 2;
public const int BoardSize = 10;
}
}

View File

@ -1,14 +1,14 @@
using System.Text.Json;
using Microsoft.CSharp.RuntimeBinder;
using pacMan.Game;
using pacMan.Game.Items;
using pacMan.GameStuff;
using pacMan.GameStuff.Items;
namespace pacMan.Services;
public interface IActionService
{
IPlayer Player { set; }
GameGroup Group { set; }
Game Group { set; }
void DoAction(ActionMessage message);
List<int> RollDice();
List<IPlayer> SetPlayerInfo(ActionMessage message);
@ -30,7 +30,7 @@ public class ActionService : IActionService
_gameService = gameService;
}
public GameGroup? Group { get; set; }
public Game? Group { get; set; }
public IPlayer? Player { get; set; }

View File

@ -1,16 +1,16 @@
using System.Text.Json.Serialization;
using pacMan.Exceptions;
using pacMan.Game;
using pacMan.Game.Items;
using pacMan.GameStuff;
using pacMan.GameStuff.Items;
namespace pacMan.Services;
public class GameGroup // TODO handle disconnects and reconnects
public class Game // TODO handle disconnects and reconnects
{
private readonly Random _random = new();
private int _currentPlayerIndex;
public GameGroup(Queue<DirectionalPosition> spawns) => Spawns = spawns;
public Game(Queue<DirectionalPosition> spawns) => Spawns = spawns;
[JsonInclude] public Guid Id { get; } = Guid.NewGuid();

View File

@ -1,5 +1,6 @@
using pacMan.Game;
using pacMan.Game.Items;
using pacMan.Exceptions;
using pacMan.GameStuff;
using pacMan.GameStuff.Items;
namespace pacMan.Services;
@ -7,7 +8,7 @@ public class GameService : WebSocketService
{
public GameService(ILogger<GameService> logger) : base(logger) { }
public SynchronizedCollection<GameGroup> Games { get; } = new();
public SynchronizedCollection<Game> Games { get; } = new();
public event Func<ArraySegment<byte>, Task>? Connections; // TODO remove and use GameGroup
@ -16,7 +17,7 @@ public class GameService : WebSocketService
Connections?.Invoke(segment);
}
public GameGroup AddPlayer(IPlayer player, Queue<DirectionalPosition> spawns)
public Game AddPlayer(IPlayer player, Queue<DirectionalPosition> spawns)
{
var index = 0;
try
@ -25,11 +26,21 @@ public class GameService : WebSocketService
}
catch (ArgumentOutOfRangeException)
{
var game = new GameGroup(spawns);
var game = new Game(spawns);
game.AddPlayer(player);
Games.Add(game);
}
return Games[index];
}
public Game JoinById(Guid id, IPlayer player)
{
var game = Games.FirstOrDefault(g => g.Id == id) ?? throw new GameNotFoundException();
var added = game.AddPlayer(player);
if (!added) throw new ArgumentException("Game is full");
return game;
}
}