diff --git a/public/assets/js/game.js b/public/assets/js/game.js index 83a0402ab..c67852cc3 100644 --- a/public/assets/js/game.js +++ b/public/assets/js/game.js @@ -117,6 +117,14 @@ function closeModal() { background.classList.add("hidden"); } +function generateUUID() { + return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) { + const r = Math.random() * 16 | 0; + const v = c === 'x' ? r : (r & 0x3 | 0x8); + return v.toString(16); + }); +} + // WebSocket const chatConnection = new WebSocket('ws://sockets.comus-party.com/chat/' + gameCode); chatConnection.onopen = function (e) { @@ -130,7 +138,28 @@ const gameConnection = new WebSocket('ws://localhost:8315/game/' + gameCode); gameConnection.onopen = function (e) { console.log("Connexion établie avec GAME_SOCKET !"); - gameConnection.send(JSON.stringify({uuid: playerUuid, command: 'joinGame', game: gameCode})); + // génère un uuid et un username + const guestUuid = generateUUID(); + const guestUsername = "Guest_" + Math.floor(Math.random() * 9000 + 1000); + + // stock les informations du guest en session + sessionStorage.setItem('uuid', guestUuid); + sessionStorage.setItem('username', guestUsername); + sessionStorage.setItem('elo', '0'); + sessionStorage.setItem('xp', '0'); + sessionStorage.setItem('pfpPath', 'default-pfp.jpg'); + sessionStorage.setItem('is_guest', 'true'); + + const sessionData = { + uuid: sessionStorage.getItem('uuid'), + username: sessionStorage.getItem('username'), + elo: sessionStorage.getItem('elo'), + xp: sessionStorage.getItem('xp'), + pfpPath: sessionStorage.getItem('pfpPath'), + is_guest: sessionStorage.getItem('is_guest') + }; + + gameConnection.send(JSON.stringify({uuid: playerUuid, command: 'joinGame', game: gameCode, sessionData: sessionData})); }; gameConnection.onmessage = function (e) { const data = JSON.parse(e.data); diff --git a/src/App/Sockets/Game.php b/src/App/Sockets/Game.php index ec4166b8b..7e603c103 100644 --- a/src/App/Sockets/Game.php +++ b/src/App/Sockets/Game.php @@ -46,6 +46,7 @@ function onMessage(ConnectionInterface $from, $msg): void $uuid = $data['uuid']; $game = $data['game']; $command = $data['command']; + $sessionData = $data['sessionData']; if (!isset($this->games[$game])) { $this->games[$game] = []; @@ -58,7 +59,7 @@ function onMessage(ConnectionInterface $from, $msg): void switch ($command) { case 'quitGame': case 'joinGame': - $this->updatePlayer($game); + $this->updatePlayer($game, $sessionData); break; case 'startGame': $this->redirectUserToGame($game, $uuid); @@ -68,7 +69,7 @@ function onMessage(ConnectionInterface $from, $msg): void } } - private function updatePlayer(string $game): void + private function updatePlayer(string $game, array | null $sessionData): void { $gameRecord = (new GameRecordDAO(Db::getInstance()->getConnection()))->findByCode($game); @@ -79,6 +80,17 @@ private function updatePlayer(string $game): void "pfp" => $player['player']->getActivePfp() ], $players); + if (isset($sessionData['is_guest']) && $sessionData['is_guest'] === 'true') { + $guestPlayer = [ + "uuid" => $sessionData['uuid'], + "username" => $sessionData['username'], + "elo" => $sessionData['elo'], + "xp" => $sessionData['xp'], + "pfp" => $sessionData['pfpPath'] + ]; + $jsonPlayer[] = $guestPlayer; + } + $this->sendToGame($game, "updatePlayer", json_encode($jsonPlayer)); } @@ -104,7 +116,7 @@ public function onClose(ConnectionInterface $conn): void foreach ($this->games as $game => $clients) { $key = array_search($conn, $clients); if ($key !== false) { - $this->updatePlayer($game); + $this->updatePlayer($game, null); unset($this->games[$game][$key]); } } diff --git a/src/Controllers/controllerGame.class.php b/src/Controllers/controllerGame.class.php index 8b24ca7c0..15e5b0b8c 100644 --- a/src/Controllers/controllerGame.class.php +++ b/src/Controllers/controllerGame.class.php @@ -30,6 +30,7 @@ use Twig\Error\RuntimeError; use Twig\Error\SyntaxError; use Twig\Loader\FilesystemLoader; +use Ramsey\Uuid\Uuid; /** * @brief Classe ControllerGame @@ -296,20 +297,40 @@ private function showGameSettings(GameRecord $gameRecord): void } else { $settings = []; } - $template = $this->getTwig()->load('player/game-settings.twig'); - echo $template->render([ - "code" => $gameRecord->getCode(), - "isHost" => $gameRecord->getHostedBy()->getUuid() == $_SESSION['uuid'], - "players" => array_map(fn($player) => $player['player'], $gameRecord->getPlayers()), - "game" => $gameRecord->getGame(), - "chat" => $gameSettings["settings"]["allowChat"], - "gameFileInfos" => $gameSettings["game"], - "settings" => $settings, - "isPrivate" => $gameRecord->isPrivate(), - ]); + + // récupération des joueurs de la base de données + $players = array_map(fn($player) => $player['player'], $gameRecord->getPlayers()); + + // si le joueur est un guest, créer un player guest avec les informations en session et l'ajouter au tableau des joueurs + if (isset($_SESSION['is_guest']) && $_SESSION['is_guest'] === true) { + $guestPlayer = [ + 'uuid' => $_SESSION['uuid'], + 'username' => $_SESSION['username'], + 'comusCoin' => $_SESSION['comusCoin'], + 'elo' => $_SESSION['elo'], + 'xp' => $_SESSION['xp'], + 'pfpPath' => $_SESSION['pfpPath'] + ]; + $players[] = (object) $guestPlayer; + } + + // créer le gameState avec toutes les informations + $gameState = [ + "code" => $gameRecord->getCode(), + "isHost" => $gameRecord->getHostedBy()->getUuid() == $_SESSION['uuid'], + "players" => $players, + "game" => $gameRecord->getGame(), + "chat" => $gameSettings["settings"]["allowChat"], + "gameFileInfos" => $gameSettings["game"], + "settings" => $settings, + "isPrivate" => $gameRecord->isPrivate(), + ]; + + echo $template->render($gameState); } + /** * @brief Rejoint une partie avec un code (Méthode GET ou POST autorisée) * @param string $method Méthode HTTP utilisée @@ -358,14 +379,13 @@ private function joinGame(string $code, ?string $playerUuid = null): string $player = (new PlayerDAO($this->getPdo()))->findByUuid($playerUuid); - // TODO: Fonctionnement pour un joueur non connecté a insérer ici - if ($gameRecord->getState() != GameRecordState::WAITING) { throw new GameUnavailableException("La partie a déjà commencé"); } if (!in_array($playerUuid, array_map(fn($player) => $player['player']->getUuid(), $gameRecord->getPlayers()))) { - $gameRecordManager->addPlayer($gameRecord, $player); + if(!isset($_SESSION['is_guest']) || $_SESSION['is_guest'] === false) { + $gameRecordManager->addPlayer($gameRecord, $player);} } return json_encode([ diff --git a/src/Models/player.dao.php b/src/Models/player.dao.php index ea59ee03f..ac771f735 100644 --- a/src/Models/player.dao.php +++ b/src/Models/player.dao.php @@ -290,6 +290,37 @@ public function createPlayer(string $username, string $email): bool return $stmtPlayer->execute(); } + /** + * @brief Crée un nouveau joueur invité dans la base de données + * + * @details Cette méthode génère un UUID unique pour le joueur, et insère un nouvel enregistrement dans la table des joueurs avec l'UUID et le nom d'utilisateur. + * + * @param string $username Le nom d'utilisateur du joueur + * @return bool Retourne true si le joueur a été créé avec succès, false sinon + * @throws DateMalformedStringException Exception levée dans le cas d'une date malformée + */ + public function createGuestPlayer(string $username): bool + { + // Récupère l'ID du dernier joueur enregistré + $stmt = $this->pdo->query('SELECT MAX(id) as max_id FROM ' . DB_PREFIX . 'user'); + $stmt->setFetchMode(PDO::FETCH_ASSOC); + $result = $stmt->fetch(); + + $userId = $result['max_id'] + 1; + + + // Genération de l'uuid du joueur guest + $uuid = "guest" . Uuid::uuid4()->toString(); + + $stmtPlayer = $this->pdo->prepare("INSERT INTO " . DB_PREFIX . "player (uuid, username, user_id) VALUES (:uuid, :username, :user_id)"); + + $stmtPlayer->bindParam(':uuid', $uuid); + $stmtPlayer->bindParam(':username', $username); + $stmtPlayer->bindParam(':user_id', $userId); + + return $stmtPlayer->execute(); + } + /** * @brief Retourne un objet Player (ou null) à partir du nom d'utilisateur passé en paramètre * @param string|null $username Le nom d'utilisateur du joueur à retrouver