diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 22c489a..9d4a09f 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -22,19 +22,30 @@ jobs: - name: Install MAUI workload run: dotnet workload install maui - - name: Restore + - name: Restore (Windows) + if: runner.os == 'Windows' run: dotnet restore SlipItIn.slnx - - name: Build Server-Stack + - name: Restore (non-Windows) + if: runner.os != 'Windows' + # Skip restoring the Windows target frameworks to avoid requiring Windows runtime packs in non-Windows CI/tooling environments + run: dotnet restore SlipItIn.slnx -p:SkipWindowsTargetFramework=true + + - name: Build Server-Stack (core projects) run: | dotnet build SlipItIn.Shared/SlipItIn.Shared.csproj --no-restore --configuration Release dotnet build SlipItIn.ServiceDefaults/SlipItIn.ServiceDefaults.csproj --no-restore --configuration Release dotnet build SlipItIn.Server/SlipItIn.Server.csproj --no-restore --configuration Release dotnet build SlipItIn.Server.Tests/SlipItIn.Server.Tests.csproj --no-restore --configuration Release + + - name: Build AppHost + if: runner.os == 'Windows' + run: | dotnet build SlipItIn.AppHost/SlipItIn.AppHost.csproj --no-restore --configuration Release - name: Build MAUI Client - run: dotnet build SlipItIn/SlipItIn.csproj --no-restore --configuration Debug + # Build the MAUI project for Android only in CI to avoid requiring Windows runtime packs + run: dotnet build SlipItIn/SlipItIn.csproj --no-restore --configuration Debug -f net10.0-android - name: Run Server Tests run: dotnet test SlipItIn.Server.Tests/SlipItIn.Server.Tests.csproj --no-restore --configuration Release diff --git a/SlipItIn.AppHost/SlipItIn.AppHost.csproj b/SlipItIn.AppHost/SlipItIn.AppHost.csproj index f78ea9f..690c337 100644 --- a/SlipItIn.AppHost/SlipItIn.AppHost.csproj +++ b/SlipItIn.AppHost/SlipItIn.AppHost.csproj @@ -15,7 +15,7 @@ - + TargetFramework=net10.0-windows10.0.19041.0 diff --git a/SlipItIn.Server.Tests/GameHubTests.cs b/SlipItIn.Server.Tests/GameHubTests.cs index 0b9ab7b..669a609 100644 --- a/SlipItIn.Server.Tests/GameHubTests.cs +++ b/SlipItIn.Server.Tests/GameHubTests.cs @@ -108,6 +108,7 @@ public class GameHubTests { GameId = game.Id, LobbyCode = game.LobbyCode, + HostUserId = game.HostId, Players = [new PlayerInfoDto { Username = user.Username }] }); @@ -151,7 +152,7 @@ public class GameHubTests var game = new Game { Id = 3, LobbyCode = "JOIN42", HostId = 99 }; _gameService.Setup(s => s.JoinGameAsync("JOIN42", user.Id, ConnectionId)).ReturnsAsync(game); - _gameService.Setup(s => s.GetGameStateAsync(game.Id)).ReturnsAsync(new GameStateDto { GameId = 3 }); + _gameService.Setup(s => s.GetGameStateAsync(game.Id)).ReturnsAsync(new GameStateDto { GameId = 3, HostUserId = 99 }); await _hub.JoinLobby("JOIN42"); @@ -205,7 +206,7 @@ public class GameHubTests _gameService.Setup(s => s.SetPlayerReadyAsync(game.Id, player.Id)) .ReturnsAsync(new Game { Id = game.Id, LobbyCode = game.LobbyCode }); - _gameService.Setup(s => s.GetGameStateAsync(game.Id)).ReturnsAsync(new GameStateDto { GameId = game.Id }); + _gameService.Setup(s => s.GetGameStateAsync(game.Id)).ReturnsAsync(new GameStateDto { GameId = game.Id, HostUserId = game.HostId }); await _hub.PlayerReady(game.Id, player.Id); @@ -540,7 +541,9 @@ public class GameHubTests SeedGameWithPlayers((user, ConnectionId)); var gameId = db.Games.Single().Id; - _gameService.Setup(s => s.GetGameStateAsync(gameId)).ReturnsAsync(new GameStateDto { GameId = gameId }); + var hostId = db.Games.Single().HostId; + + _gameService.Setup(s => s.GetGameStateAsync(gameId)).ReturnsAsync(new GameStateDto { GameId = gameId, HostUserId = hostId }); await _hub.RequestGameState(gameId); diff --git a/SlipItIn.Server.Tests/GameServiceTests.cs b/SlipItIn.Server.Tests/GameServiceTests.cs index a97b32d..f9fab2a 100644 --- a/SlipItIn.Server.Tests/GameServiceTests.cs +++ b/SlipItIn.Server.Tests/GameServiceTests.cs @@ -40,6 +40,18 @@ public class GameServiceTests await Assert.ThrowsAsync(() => _sut.CreateGameAsync(999)); } + [Fact] + public async Task GetGameStateAsync_IncludesHostUserId() + { + using var db = _factory.CreateDbContext(); + var host = TestDbHelper.SeedUser(db); + var (game, _) = TestDbHelper.SeedGame(db, host); + + var dto = await _sut.GetGameStateAsync(game.Id); + + Assert.Equal(game.HostId, dto.HostUserId); + } + // ---------- JoinGameAsync ---------- [Fact] diff --git a/SlipItIn.Server/Services/GameService.cs b/SlipItIn.Server/Services/GameService.cs index b57f4ff..50ee4a8 100644 --- a/SlipItIn.Server/Services/GameService.cs +++ b/SlipItIn.Server/Services/GameService.cs @@ -293,6 +293,7 @@ public class GameService : IGameService LobbyCode = game.LobbyCode, Status = game.Status.ToString(), Players = playerInfos, + HostUserId = game.HostId, CurrentRound = currentRound?.RoundNumber ?? 0, RoundTimeRemaining = roundTimeRemaining }; diff --git a/SlipItIn.Shared/DTOs/GameStateDto.cs b/SlipItIn.Shared/DTOs/GameStateDto.cs index 8bbccbb..7ca3424 100644 --- a/SlipItIn.Shared/DTOs/GameStateDto.cs +++ b/SlipItIn.Shared/DTOs/GameStateDto.cs @@ -6,6 +6,8 @@ public class GameStateDto public string LobbyCode { get; set; } = string.Empty; public string Status { get; set; } = string.Empty; public List Players { get; set; } = []; + // Host user id to let clients determine whether the current user is the host + public int HostUserId { get; set; } public int CurrentRound { get; set; } public int RoundTimeRemaining { get; set; } } diff --git a/SlipItIn/SlipItIn.csproj b/SlipItIn/SlipItIn.csproj index 8d2acfa..f58135f 100644 --- a/SlipItIn/SlipItIn.csproj +++ b/SlipItIn/SlipItIn.csproj @@ -3,7 +3,9 @@ net10.0-android $(TargetFrameworks); - $(TargetFrameworks);net10.0-windows10.0.19041.0 + + $(TargetFrameworks);net10.0-windows10.0.19041.0 preview