request = $request; $this->pdm = new PersistentDataManager(); $this->multiConnector = new MultiConnector(); $this->multiRoomRepository = new MultiRoomRepository(); $this->mapRepository = new MapRepository(); $this->placeRepository = new PlaceRepository(); $this->challengeRepository = new ChallengeRepository(); $this->userInChallengeRepository = new UserInChallengeRepository(); } public function isAuthenticationRequired(): bool { return empty($_ENV['ENABLE_GAME_FOR_GUESTS']); } public function getGame(): IContent { $mapId = (int) $this->request->query('mapId'); return new HtmlContent('game', ['mapId' => $mapId]); } public function getNewMultiGame(): IRedirect { $mapId = (int) $this->request->query('mapId'); $map = $this->mapRepository->getById($mapId); $roomId = bin2hex(random_bytes(3)); $token = $this->getMultiToken($roomId); $room = new MultiRoom(); $room->setRoomId($roomId); $room->setStateArray([ 'mapId' => $mapId, 'area' => $map->getArea(), 'rounds' => [], 'currentRound' => -1 ]); $room->setMembersArray(['owner' => $token, 'all' => []]); $room->setUpdatedDate(new DateTime()); $this->pdm->saveToDb($room); $this->multiConnector->sendMessage('create_room', ['roomId' => $roomId]); return new Redirect( \Container::$routeCollection ->getRoute('multiGame') ->generateLink(['roomId' => $roomId]), IRedirect::TEMPORARY ); } public function getMultiGame(): IContent { $roomId = $this->request->query('roomId'); return new HtmlContent('game', ['roomId' => $roomId]); } public function getChallenge(): IContent { $challengeToken = $this->request->query('challengeToken'); return new HtmlContent('game', ['challengeToken' => $challengeToken]); } public function createNewChallenge(): IContent { // create Challenge do { // initiliaze or if a challenge with the same token already exists $challengeToken = mt_rand(); } while ($this->challengeRepository->getByToken($challengeToken)); $challenge = new Challenge(); $challenge->setToken($challengeToken); $challenge->setCreatedDate(new DateTime()); if ($this->request->post('timerEnabled') !== null && $this->request->post('timeLimit') !== null) { $challenge->setTimeLimit($this->request->post('timeLimit')); } if ($this->request->post('timeLimitType') !== null) { $challenge->setTimeLimitType($this->request->post('timeLimitType')); } if ($this->request->post('noMove') !== null) { $challenge->setNoMove(true); } if ($this->request->post('noPan') !== null) { $challenge->setNoPan(true); } if ($this->request->post('noZoom') !== null) { $challenge->setNoZoom(true); } $this->pdm->saveToDb($challenge); // save owner/creator $session = $this->request->session(); $userId = $session->get('userId'); $userInChallenge = new UserInChallenge(); $userInChallenge->setUserId($userId); $userInChallenge->setChallenge($challenge); $userInChallenge->setTimeLeft($challenge->getTimeLimit()); $userInChallenge->setIsOwner(true); $this->pdm->saveToDb($userInChallenge); // select places $mapId = (int) $this->request->post('mapId'); // $map = $this->mapRepository->getById($mapId); $places = $this->placeRepository->getRandomNPlaces($mapId, static::NUMBER_OF_ROUNDS, $userId); $round = 0; foreach ($places as $place) { $placeInChallenge = new PlaceInChallenge(); $placeInChallenge->setPlace($place); $placeInChallenge->setChallenge($challenge); $placeInChallenge->setRound($round++); $this->pdm->saveToDb($placeInChallenge); } return new JsonContent(['challengeToken' => dechex($challengeToken)]); } public function prepareGame(): IContent { $mapId = (int) $this->request->query('mapId'); $map = $this->mapRepository->getById($mapId); $session = $this->request->session(); if (!($state = $session->get('state')) || $state['mapId'] !== $mapId) { $session->set('state', [ 'mapId' => $mapId, 'area' => $map->getArea(), 'rounds' => [], 'currentRound' => -1 ]); } else { // update the area of the map in the session in any case $state['area'] = $map->getArea(); $session->set('state', $state); } return new JsonContent([ 'mapId' => $mapId, 'mapName' => $map->getName(), 'bounds' => $map->getBounds()->toArray() ]); } public function prepareMultiGame(): IContent { $roomId = $this->request->query('roomId'); $userName = $this->request->post('userName'); if (empty($userName)) { $faker = Factory::create(); $userName = $faker->userName; } $room = $this->multiRoomRepository->getByRoomId($roomId); if (!isset($room)) { return new JsonContent(['error' => 'game_not_found']); } $state = $room->getStateArray(); $map = $this->mapRepository->getById($state['mapId']); $token = $this->getMultiToken($roomId); $members = $room->getMembersArray(); if (!in_array($token, $members['all'])) { if ($state['currentRound'] >= 0) { return new JsonContent(['error' => 'game_already_started']); } $members['all'][] = $token; } $room->setMembersArray($members); $room->setUpdatedDate(new DateTime()); $this->pdm->saveToDb($room); $this->multiConnector->sendMessage('join_room', [ 'roomId' => $roomId, 'token' => $token, 'userName' => $userName ]); return new JsonContent([ 'roomId' => $roomId, 'token' => $token, 'owner' => $members['owner'] == $token, 'mapId' => $state['mapId'], 'mapName' => $map->getName(), 'bounds' => $map->getBounds()->toArray() ]); } public function prepareChallenge(): IContent { $challengeToken_str = $this->request->query('challengeToken'); $session = $this->request->session(); $userId = $session->get('userId'); if (!isset($userId)) { return new JsonContent(['error' => 'anonymous_user']); } $challenge = $this->challengeRepository->getByTokenStr($challengeToken_str); if (!isset($challenge)) { return new JsonContent(['error' => 'game_not_found']); } if (!$this->userInChallengeRepository->isUserParticipatingInChallenge($userId, $challenge)) { // new player is joining $userInChallenge = new UserInChallenge(); $userInChallenge->setUserId($userId); $userInChallenge->setChallenge($challenge); $userInChallenge->setTimeLeft($challenge->getTimeLimit()); $this->pdm->saveToDb($userInChallenge); } $map = $this->mapRepository->getByChallenge($challenge); return new JsonContent([ 'mapId' => $map->getId(), 'mapName' => $map->getName(), 'bounds' => $map->getBounds()->toArray() ]); } private function getMultiToken(string $roomId): string { $session = $this->request->session(); if (!($multiState = $session->get('multiState')) || $multiState['roomId'] !== $roomId) { $token = bin2hex(random_bytes(16)); $session->set('multiState', [ 'roomId' => $roomId, 'token' => $token ]); } else { $token = $multiState['token']; } return $token; } }