diff --git a/src/Game/Controller/GameController.php b/src/Game/Controller/GameController.php index 6060be0..9a1ab78 100644 --- a/src/Game/Controller/GameController.php +++ b/src/Game/Controller/GameController.php @@ -70,6 +70,17 @@ final class GameController extends AbstractController $this->addFlash('error', 'Could not leave session (game might have started).'); } } + } elseif ($request->request->has('start_session')) { + $sessionId = $request->request->get('session_id'); + $session = $sessionRepository->find($sessionId); + + if ($session) { + if ($dashboardService->startSession($session)) { + $this->addFlash('success', 'Session started! Screens have been assigned.'); + } else { + $this->addFlash('error', 'Could not start session. Make sure all players have joined.'); + } + } } return $this->redirectToRoute('game_dashboard'); diff --git a/src/Game/Entity/Player.php b/src/Game/Entity/Player.php index 2169d93..e9802f6 100644 --- a/src/Game/Entity/Player.php +++ b/src/Game/Entity/Player.php @@ -23,7 +23,7 @@ class Player #[ORM\JoinColumn(nullable: false)] private ?User $user = null; - #[ORM\Column] + #[ORM\Column(nullable: true)] private ?int $screen = null; public function getId(): ?int diff --git a/src/Game/Enum/SessionSettingType.php b/src/Game/Enum/SessionSettingType.php index 17abbdf..da0c464 100644 --- a/src/Game/Enum/SessionSettingType.php +++ b/src/Game/Enum/SessionSettingType.php @@ -7,19 +7,54 @@ enum SessionSettingType: string case PWD_FOR_PLAYER1 = 'PwdForPlayer1'; case PWD_FOR_PLAYER2 = 'PwdForPlayer2'; case PWD_FOR_PLAYER3 = 'PwdForPlayer3'; + case PWD_FOR_PLAYER4 = 'PwdForPlayer4'; + case PWD_FOR_PLAYER5 = 'PwdForPlayer5'; + case PWD_FOR_PLAYER6 = 'PwdForPlayer6'; + case PWD_FOR_PLAYER7 = 'PwdForPlayer7'; + case PWD_FOR_PLAYER8 = 'PwdForPlayer8'; + case PWD_FOR_PLAYER9 = 'PwdForPlayer9'; + case PWD_FOR_PLAYER10 = 'PwdForPlayer10'; case RIGHTS_FOR_PLAYER1 = 'RightsForPlayer1'; case RIGHTS_FOR_PLAYER2 = 'RightsForPlayer2'; case RIGHTS_FOR_PLAYER3 = 'RightsForPlayer3'; + case RIGHTS_FOR_PLAYER4 = 'RightsForPlayer4'; + case RIGHTS_FOR_PLAYER5 = 'RightsForPlayer5'; + case RIGHTS_FOR_PLAYER6 = 'RightsForPlayer6'; + case RIGHTS_FOR_PLAYER7 = 'RightsForPlayer7'; + case RIGHTS_FOR_PLAYER8 = 'RightsForPlayer8'; + case RIGHTS_FOR_PLAYER9 = 'RightsForPlayer9'; + case RIGHTS_FOR_PLAYER10 = 'RightsForPlayer10'; case INVITE_CODE = 'InviteCode'; case SET_OF_DELETED_FILES = 'SetOfDeletedFiles'; case CHAT_TRACKING_FOR_PLAYER1 = 'ChatTrackingForPlayer1'; case CHAT_TRACKING_FOR_PLAYER2 = 'ChatTrackingForPlayer2'; case CHAT_TRACKING_FOR_PLAYER3 = 'ChatTrackingForPlayer3'; + case CHAT_TRACKING_FOR_PLAYER4 = 'ChatTrackingForPlayer4'; + case CHAT_TRACKING_FOR_PLAYER5 = 'ChatTrackingForPlayer5'; + case CHAT_TRACKING_FOR_PLAYER6 = 'ChatTrackingForPlayer6'; + case CHAT_TRACKING_FOR_PLAYER7 = 'ChatTrackingForPlayer7'; + case CHAT_TRACKING_FOR_PLAYER8 = 'ChatTrackingForPlayer8'; + case CHAT_TRACKING_FOR_PLAYER9 = 'ChatTrackingForPlayer9'; + case CHAT_TRACKING_FOR_PLAYER10 = 'ChatTrackingForPlayer10'; case VERIFY_CODES_FOR_PLAYER1 = 'VerifyCodesForPlayer1'; case VERIFY_CODES_FOR_PLAYER2 = 'VerifyCodesForPlayer2'; case VERIFY_CODES_FOR_PLAYER3 = 'VerifyCodesForPlayer3'; + case VERIFY_CODES_FOR_PLAYER4 = 'VerifyCodesForPlayer4'; + case VERIFY_CODES_FOR_PLAYER5 = 'VerifyCodesForPlayer5'; + case VERIFY_CODES_FOR_PLAYER6 = 'VerifyCodesForPlayer6'; + case VERIFY_CODES_FOR_PLAYER7 = 'VerifyCodesForPlayer7'; + case VERIFY_CODES_FOR_PLAYER8 = 'VerifyCodesForPlayer8'; + case VERIFY_CODES_FOR_PLAYER9 = 'VerifyCodesForPlayer9'; + case VERIFY_CODES_FOR_PLAYER10 = 'VerifyCodesForPlayer10'; case VERIFICATION_PROGRESS_FOR_PLAYER1 = 'VerificationProgressForPlayer1'; case VERIFICATION_PROGRESS_FOR_PLAYER2 = 'VerificationProgressForPlayer2'; case VERIFICATION_PROGRESS_FOR_PLAYER3 = 'VerificationProgressForPlayer3'; + case VERIFICATION_PROGRESS_FOR_PLAYER4 = 'VerificationProgressForPlayer4'; + case VERIFICATION_PROGRESS_FOR_PLAYER5 = 'VerificationProgressForPlayer5'; + case VERIFICATION_PROGRESS_FOR_PLAYER6 = 'VerificationProgressForPlayer6'; + case VERIFICATION_PROGRESS_FOR_PLAYER7 = 'VerificationProgressForPlayer7'; + case VERIFICATION_PROGRESS_FOR_PLAYER8 = 'VerificationProgressForPlayer8'; + case VERIFICATION_PROGRESS_FOR_PLAYER9 = 'VerificationProgressForPlayer9'; + case VERIFICATION_PROGRESS_FOR_PLAYER10 = 'VerificationProgressForPlayer10'; case EVERYONE_VERIFIED = 'EveryoneVerified'; } diff --git a/src/Game/Service/GameDashboardService.php b/src/Game/Service/GameDashboardService.php index 93d2d93..543ca07 100644 --- a/src/Game/Service/GameDashboardService.php +++ b/src/Game/Service/GameDashboardService.php @@ -67,13 +67,10 @@ final class GameDashboardService $player = new Player(); $player->setUser($user); $player->setSession($session); - $player->setScreen(1); $this->entityManager->persist($session); $this->entityManager->persist($player); - $this->initializePlayerSettings($player); - $this->entityManager->flush(); return $session; @@ -104,17 +101,15 @@ final class GameDashboardService } $playerCount = count($session->getPlayers()); - if ($playerCount >= 3) { + if ($playerCount >= $session->getGame()->getNumberOfPlayers()) { return false; // Session full } $player = new Player(); $player->setUser($user); $player->setSession($session); - $player->setScreen($playerCount + 1); $this->entityManager->persist($player); - $this->initializePlayerSettings($player); $this->entityManager->flush(); @@ -170,12 +165,7 @@ final class GameDashboardService private function initializePlayerSettings(Player $player): void { $screen = $player->getScreen(); - $rightsSettingName = match ($screen) { - 1 => SessionSettingType::RIGHTS_FOR_PLAYER1, - 2 => SessionSettingType::RIGHTS_FOR_PLAYER2, - 3 => SessionSettingType::RIGHTS_FOR_PLAYER3, - default => null, - }; + $rightsSettingName = SessionSettingType::tryFrom('RightsForPlayer' . $screen); if ($rightsSettingName) { $setting = new SessionSetting(); @@ -186,12 +176,7 @@ final class GameDashboardService $this->entityManager->persist($setting); } - $pwdSettingName = match ($screen) { - 1 => SessionSettingType::PWD_FOR_PLAYER1, - 2 => SessionSettingType::PWD_FOR_PLAYER2, - 3 => SessionSettingType::PWD_FOR_PLAYER3, - default => null, - }; + $pwdSettingName = SessionSettingType::tryFrom('PwdForPlayer' . $screen); if ($pwdSettingName) { $setting = new SessionSetting(); @@ -202,12 +187,7 @@ final class GameDashboardService $this->entityManager->persist($setting); } - $chatTrackingSettingName = match ($screen) { - 1 => SessionSettingType::CHAT_TRACKING_FOR_PLAYER1, - 2 => SessionSettingType::CHAT_TRACKING_FOR_PLAYER2, - 3 => SessionSettingType::CHAT_TRACKING_FOR_PLAYER3, - default => null, - }; + $chatTrackingSettingName = SessionSettingType::tryFrom('ChatTrackingForPlayer' . $screen); if ($chatTrackingSettingName) { $setting = new SessionSetting(); @@ -218,16 +198,12 @@ final class GameDashboardService $this->entityManager->persist($setting); } - $verifyCodesSettingName = match ($screen) { - 1 => SessionSettingType::VERIFY_CODES_FOR_PLAYER1, - 2 => SessionSettingType::VERIFY_CODES_FOR_PLAYER2, - 3 => SessionSettingType::VERIFY_CODES_FOR_PLAYER3, - default => null, - }; + $verifyCodesSettingName = SessionSettingType::tryFrom('VerifyCodesForPlayer' . $screen); if ($verifyCodesSettingName) { $codes = []; - for ($i = 1; $i <= 3; $i++) { + $numPlayers = $player->getSession()->getGame()->getNumberOfPlayers(); + for ($i = 1; $i <= $numPlayers; $i++) { if ($i !== $screen) { $codes[$i] = bin2hex(random_bytes(3)); // 6 characters code } @@ -241,12 +217,7 @@ final class GameDashboardService $this->entityManager->persist($setting); } - $verificationProgressSettingName = match ($screen) { - 1 => SessionSettingType::VERIFICATION_PROGRESS_FOR_PLAYER1, - 2 => SessionSettingType::VERIFICATION_PROGRESS_FOR_PLAYER2, - 3 => SessionSettingType::VERIFICATION_PROGRESS_FOR_PLAYER3, - default => null, - }; + $verificationProgressSettingName = SessionSettingType::tryFrom('VerificationProgressForPlayer' . $screen); if ($verificationProgressSettingName) { $setting = new SessionSetting(); @@ -258,6 +229,34 @@ final class GameDashboardService } } + public function startSession(Session $session): bool + { + if ($session->getStatus() !== SessionStatus::CREATED) { + return false; + } + + $players = $session->getPlayers()->toArray(); + if (count($players) < $session->getGame()->getNumberOfPlayers()) { + return false; + } + + // Shuffle players to assign random screens + shuffle($players); + + foreach ($players as $index => $player) { + $screen = $index + 1; + $player->setScreen($screen); + $this->initializePlayerSettings($player); + $this->entityManager->persist($player); + } + + $session->setStatus(SessionStatus::READY); + $this->entityManager->persist($session); + $this->entityManager->flush(); + + return true; + } + public function generateInviteCode(Session $session, UserInterface $user, bool $isAdmin): ?string { // Security check: is user part of this session? diff --git a/src/Game/Service/GameResponseService.php b/src/Game/Service/GameResponseService.php index bf33f8d..d4bd1ae 100644 --- a/src/Game/Service/GameResponseService.php +++ b/src/Game/Service/GameResponseService.php @@ -59,12 +59,7 @@ class GameResponseService private function getRechten(Player $player): array { - $settingName = match($player->getScreen()) { - 1 => SessionSettingType::RIGHTS_FOR_PLAYER1, - 2 => SessionSettingType::RIGHTS_FOR_PLAYER2, - 3 => SessionSettingType::RIGHTS_FOR_PLAYER3, - default => null, - }; + $settingName = SessionSettingType::tryFrom('RightsForPlayer' . $player->getScreen()); if (!$settingName) { return []; @@ -269,7 +264,7 @@ class GameResponseService if (isset($messageParts[1]) && is_numeric($messageParts[1]) && $messageParts[1] >= 1 && - $messageParts[1] <= 3) { + $messageParts[1] <= $player->getSession()->getGame()->getNumberOfPlayers()) { $toSingle = true; } @@ -309,12 +304,7 @@ class GameResponseService $screen = $player->getScreen(); $session = $player->getSession(); - $verifyCodesSettingName = match ($screen) { - 1 => SessionSettingType::VERIFY_CODES_FOR_PLAYER1, - 2 => SessionSettingType::VERIFY_CODES_FOR_PLAYER2, - 3 => SessionSettingType::VERIFY_CODES_FOR_PLAYER3, - default => null, - }; + $verifyCodesSettingName = SessionSettingType::tryFrom('VerifyCodesForPlayer' . $screen); if (!$verifyCodesSettingName) { return; @@ -354,12 +344,7 @@ class GameResponseService if(in_array('verify', $rights)) return; - $trackingSettingName = match ($player->getScreen()) { - 1 => SessionSettingType::CHAT_TRACKING_FOR_PLAYER1, - 2 => SessionSettingType::CHAT_TRACKING_FOR_PLAYER2, - 3 => SessionSettingType::CHAT_TRACKING_FOR_PLAYER3, - default => null, - }; + $trackingSettingName = SessionSettingType::tryFrom('ChatTrackingForPlayer' . $player->getScreen()); if (!$trackingSettingName) { return; @@ -389,7 +374,8 @@ class GameResponseService { $screen = $player->getScreen(); $requiredTargets = [0]; // Everyone - for ($i = 1; $i <= 3; $i++) { + $numPlayers = $player->getSession()->getGame()->getNumberOfPlayers(); + for ($i = 1; $i <= $numPlayers; $i++) { if ($i !== $screen) { $requiredTargets[] = $i; } @@ -403,12 +389,7 @@ class GameResponseService } // Grant verify right - $rightsSettingName = match ($screen) { - 1 => SessionSettingType::RIGHTS_FOR_PLAYER1, - 2 => SessionSettingType::RIGHTS_FOR_PLAYER2, - 3 => SessionSettingType::RIGHTS_FOR_PLAYER3, - default => null, - }; + $rightsSettingName = SessionSettingType::tryFrom('RightsForPlayer' . $screen); if (!$rightsSettingName) { return; @@ -480,12 +461,7 @@ class GameResponseService $screen = $player->getScreen(); $session = $player->getSession(); - $progressSettingName = match ($screen) { - 1 => SessionSettingType::VERIFICATION_PROGRESS_FOR_PLAYER1, - 2 => SessionSettingType::VERIFICATION_PROGRESS_FOR_PLAYER2, - 3 => SessionSettingType::VERIFICATION_PROGRESS_FOR_PLAYER3, - default => null, - }; + $progressSettingName = SessionSettingType::tryFrom('VerificationProgressForPlayer' . $screen); if (!$progressSettingName) { return 'Error: Invalid player screen.'; @@ -505,12 +481,7 @@ class GameResponseService } $otherScreen = $otherPlayer->getScreen(); - $codesSettingName = match ($otherScreen) { - 1 => SessionSettingType::VERIFY_CODES_FOR_PLAYER1, - 2 => SessionSettingType::VERIFY_CODES_FOR_PLAYER2, - 3 => SessionSettingType::VERIFY_CODES_FOR_PLAYER3, - default => null, - }; + $codesSettingName = SessionSettingType::tryFrom('VerifyCodesForPlayer' . $otherScreen); if (!$codesSettingName) { continue; @@ -554,12 +525,7 @@ class GameResponseService private function grantVerificationRights(Player $player): void { $screen = $player->getScreen(); - $rightsSettingName = match ($screen) { - 1 => SessionSettingType::RIGHTS_FOR_PLAYER1, - 2 => SessionSettingType::RIGHTS_FOR_PLAYER2, - 3 => SessionSettingType::RIGHTS_FOR_PLAYER3, - default => null, - }; + $rightsSettingName = SessionSettingType::tryFrom('RightsForPlayer' . $screen); if (!$rightsSettingName) { return; @@ -600,18 +566,18 @@ class GameResponseService } $allVerified = true; - foreach ([1, 2, 3] as $screen) { - $progressSettingName = match ($screen) { - 1 => SessionSettingType::VERIFICATION_PROGRESS_FOR_PLAYER1, - 2 => SessionSettingType::VERIFICATION_PROGRESS_FOR_PLAYER2, - 3 => SessionSettingType::VERIFICATION_PROGRESS_FOR_PLAYER3, - default => null, - }; + foreach ($session->getPlayers() as $otherPlayer) { + $otherScreen = $otherPlayer->getScreen(); + $progressSettingName = SessionSettingType::tryFrom('VerificationProgressForPlayer' . $otherScreen); - $progressSetting = $this->sessionSettingRepository->getSetting($session, $progressSettingName, $player); + if (!$progressSettingName) { + continue; + } + + $progressSetting = $this->sessionSettingRepository->getSetting($session, $progressSettingName, $otherPlayer); $progress = json_decode($progressSetting?->getValue() ?? '[]', true) ?? []; - if (count($progress) < 2) { + if (count($progress) < $session->getGame()->getNumberOfPlayers() - 1) { $allVerified = false; break; } diff --git a/src/Game/Service/PlayerService.php b/src/Game/Service/PlayerService.php index 4f43c63..10fed4b 100644 --- a/src/Game/Service/PlayerService.php +++ b/src/Game/Service/PlayerService.php @@ -40,12 +40,7 @@ class PlayerService } public function getCurrentPwdOfPlayer(Player $player) : ?string { - $settingName = match($player->getScreen()) { - 1 => SessionSettingType::PWD_FOR_PLAYER1, - 2 => SessionSettingType::PWD_FOR_PLAYER2, - 3 => SessionSettingType::PWD_FOR_PLAYER3, - default => null, - }; + $settingName = SessionSettingType::tryFrom('PwdForPlayer' . $player->getScreen()); if (!$settingName) { return null; @@ -57,12 +52,7 @@ class PlayerService public function saveCurrentPwdOfPlayer(Player $player, string $newLocation) { - $settingName = match($player->getScreen()) { - 1 => SessionSettingType::PWD_FOR_PLAYER1, - 2 => SessionSettingType::PWD_FOR_PLAYER2, - 3 => SessionSettingType::PWD_FOR_PLAYER3, - default => null, - }; + $settingName = SessionSettingType::tryFrom('PwdForPlayer' . $player->getScreen()); if (!$settingName) { return; diff --git a/templates/game/dashboard.html.twig b/templates/game/dashboard.html.twig index e177c42..4836688 100644 --- a/templates/game/dashboard.html.twig +++ b/templates/game/dashboard.html.twig @@ -69,11 +69,19 @@ Enter Game - {% if session.status.value == 'created' and session.timer == 0 %} -
- - -
+ {% if session.status.value == 'created' %} + {% if session.players|length >= session.game.numberOfPlayers %} +
+ + +
+ {% endif %} + {% if session.timer == 0 %} +
+ + +
+ {% endif %} {% endif %} diff --git a/tests/Game/GameDashboardServiceTest.php b/tests/Game/GameDashboardServiceTest.php index e1aba6b..53caef5 100644 --- a/tests/Game/GameDashboardServiceTest.php +++ b/tests/Game/GameDashboardServiceTest.php @@ -36,7 +36,7 @@ class GameDashboardServiceTest extends TestCase ); } - public function testCreateSessionInitializesRightsAndPwd(): void + public function testCreateSessionDoesNotInitializeSettings(): void { $game = new Game(); $game->setStatus(GameStatus::OPEN); @@ -44,20 +44,23 @@ class GameDashboardServiceTest extends TestCase $user = new User(); $user->setUsername('testuser'); - $this->entityManager->expects($this->exactly(7)) + $this->entityManager->expects($this->exactly(2)) ->method('persist'); - // 1. Session, 2. Player, 3. SessionSetting (rights), 4. SessionSetting (pwd), 5. SessionSetting (chat tracking), 6. SessionSetting (verify codes), 7. SessionSetting (verification progress) + // 1. Session, 2. Player $session = $this->service->createSession($game, $user, false); $this->assertInstanceOf(Session::class, $session); } - public function testJoinSessionInitializesRightsAndPwd(): void + public function testJoinSessionDoesNotInitializeSettings(): void { $user = new User(); $user->setUsername('testuser'); + $game = new Game(); + $game->setNumberOfPlayers(3); $session = new Session(); + $session->setGame($game); $setting = new SessionSetting(); $setting->setSession($session); @@ -71,15 +74,93 @@ class GameDashboardServiceTest extends TestCase $repo->method('findOneBy') ->willReturn($setting); - $this->entityManager->expects($this->exactly(6)) + $this->entityManager->expects($this->exactly(1)) ->method('persist'); - // 1. Player, 2. SessionSetting (rights), 3. SessionSetting (pwd), 4. SessionSetting (chat tracking), 5. SessionSetting (verify codes), 6. SessionSetting (verification progress) + // 1. Player $result = $this->service->joinSession('abc-123', $user); $this->assertTrue($result); } + public function testStartSessionAssignsScreensAndInitializesSettings(): void + { + $game = new Game(); + $game->setNumberOfPlayers(2); + $session = new Session(); + $session->setGame($game); + $session->setStatus(\App\Game\Enum\SessionStatus::CREATED); + + $user1 = new User(); + $user1->setUsername('user1'); + $player1 = new Player(); + $player1->setUser($user1); + $session->addPlayer($player1); + + $user2 = new User(); + $user2->setUsername('user2'); + $player2 = new Player(); + $player2->setUser($user2); + $session->addPlayer($player2); + + // For each player (2): + // Player (persist) + // SessionSetting (rights) + // SessionSetting (pwd) + // SessionSetting (chat tracking) + // SessionSetting (verify codes) + // SessionSetting (verification progress) + // Total = 2 * 6 = 12 + // PLUS Session (persist) + // Total = 13 + + $this->entityManager->expects($this->exactly(13)) + ->method('persist'); + + $result = $this->service->startSession($session); + + $this->assertTrue($result); + $this->assertEquals(\App\Game\Enum\SessionStatus::READY, $session->getStatus()); + $this->assertNotNull($player1->getScreen()); + $this->assertNotNull($player2->getScreen()); + $this->assertNotEquals($player1->getScreen(), $player2->getScreen()); + } + + public function testStartSessionWithFourPlayers(): void + { + $game = new Game(); + $game->setNumberOfPlayers(4); + $session = new Session(); + $session->setGame($game); + $session->setStatus(\App\Game\Enum\SessionStatus::CREATED); + + for ($i = 1; $i <= 4; $i++) { + $user = new User(); + $user->setUsername('user' . $i); + $player = new Player(); + $player->setUser($user); + $session->addPlayer($player); + } + + // For each player (4): + // Player (persist) + 5 Settings = 6 persists + // Total = 4 * 6 = 24 + // PLUS Session (persist) + // Total = 25 + + $this->entityManager->expects($this->exactly(25)) + ->method('persist'); + + $result = $this->service->startSession($session); + + $this->assertTrue($result); + foreach ($session->getPlayers() as $player) { + $this->assertNotNull($player->getScreen()); + $this->assertGreaterThanOrEqual(1, $player->getScreen()); + $this->assertLessThanOrEqual(4, $player->getScreen()); + } + } + public function testLeaveSession(): void { $user = new User();