src/Controller/GameController.php line 143

Open in your IDE?
  1. <?php
  2. namespace App\Controller;
  3. use App\Entity\Area;
  4. use App\Entity\PveAreaTicker;
  5. use App\Entity\PvpAreaTicker;
  6. use App\Entity\User;
  7. use App\Form\Type\LoginType;
  8. use App\Model\AreaService;
  9. use App\Model\DiscordTriggerService;
  10. use App\Model\Game\GameUserService;
  11. use App\Model\GameService;
  12. use App\Model\Helper\GameHelper;
  13. use App\Model\UserService;
  14. use Exception;
  15. use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
  16. use Symfony\Component\HttpFoundation\Request;
  17. use Symfony\Component\HttpFoundation\Response;
  18. use Symfony\Component\HttpKernel\KernelInterface;
  19. use Symfony\Component\Routing\Annotation\Route;
  20. use Symfony\Component\Routing\RouterInterface;
  21. /**
  22.  * @Route("/game")
  23.  */
  24. class GameController extends AbstractController
  25. {
  26.     /**
  27.      * @var AreaService
  28.      */
  29.     private $gameService;
  30.     /**
  31.      * @var GameHelper
  32.      */
  33.     private $gameHelper;
  34.     /**
  35.      * @var GameUserService
  36.      */
  37.     private $userService;
  38.     /**
  39.      * @var DiscordTriggerService
  40.      */
  41.     private $discordTriggerService;
  42.     public function __construct(GameService $gameServiceGameHelper $gameHelperGameUserService $userServiceDiscordTriggerService $discordTriggerService)
  43.     {
  44.         $this->gameService $gameService;
  45.         $this->gameHelper $gameHelper;
  46.         $this->userService $userService;
  47.         $this->discordTriggerService $discordTriggerService;
  48.     }
  49.     /**
  50.      * @Route("", name="game_index")
  51.      *
  52.      * @return Response
  53.      */
  54.     public function index(): Response
  55.     {
  56.         /** @var User $user */
  57.         $user $this->getUser();
  58.         if (!$user) {
  59.             $form $this->createForm(LoginType::class);
  60.             return $this->render('game/login.html.twig', [
  61.                 'form' => $form->createView(),
  62.                 'page' => 'game',
  63.             ]);
  64.         }
  65.         if (!$user->hasArea()) {
  66.             return $this->redirectToRoute('area_index');
  67.         }
  68.         return $this->redirectToRoute('game_townhall');
  69.     }
  70.     /**
  71.      * @Route("/hold", name="game_tick_hold")
  72.      *
  73.      * @param Request         $request
  74.      * @param RouterInterface $router
  75.      *
  76.      * @return Response
  77.      */
  78.     public function tickHold(Request $requestRouterInterface $router): Response
  79.     {
  80.         /** @var User $user */
  81.         $user $this->getUser();
  82.         if (!$user) {
  83.             return $this->redirectToRoute('game_index');
  84.         }
  85.         $route null;
  86.         try {
  87.             $route $router->match($request->get('ref'));
  88.         } catch (Exception $e) {
  89.             // route requires params, show townhall route instead
  90.         }
  91.         return $this->render('game/tick_hold.html.twig', [
  92.             'ref' => is_array($route) && isset($route['_route']) ? $route['_route'] : 'game_index'
  93.         ]);
  94.     }
  95.     /**
  96.      * @Route("/choose-area/{areaId}", name="game_choose_area")
  97.      *
  98.      * @param int $areaId
  99.      *
  100.      * @return Response
  101.      */
  102.     public function chooseArea(int $areaId 0): Response
  103.     {
  104.         /** @var User $user */
  105.         $user $this->getUser();
  106.         if (!$user) {
  107.             return $this->redirectToRoute("game_index");
  108.         }
  109.         if ($areaId 0) {
  110.             $area $this->gameService->areaService->getArea($areaId);
  111.             if ($user->isInArea($area)) {
  112.                 $this->userService->setActiveArea($user$area->getName());
  113.                 return $this->redirectToRoute('game_index');
  114.             }
  115.         }
  116.         return $this->render('game/choose_area.html.twig', [
  117.             'user' => $user,
  118.             'areas' => $this->gameService->areaService->getActiveAreas(),
  119.             'page' => 'game',
  120.         ]);
  121.     }
  122.     /**
  123.      * @Route("/tick/{key}", name="game_tick")
  124.      *
  125.      * @param string $key
  126.      * @return Response
  127.      */
  128.     public function tick(string $keyKernelInterface $kernel): Response
  129.     {
  130.         if ($key != $this->getParameter('tickkey')) {
  131.             // TODO report unauthorized access
  132.             return new Response(""Response::HTTP_NOT_FOUND);
  133.         }
  134.         $errors = [];
  135.         $areas $this->gameService->areaService->getActiveAreas();
  136.         foreach ($areas as $area) {
  137.             $lock $kernel->getProjectDir() . "/tickarealock_{$area->getId()}.lock";
  138.             if (!file_exists($lock) || filemtime($lock) > time() + 300) {
  139.                 fopen($lock'w');
  140.                 $e null;
  141.                 $this->handleTick($area$e);
  142.                 unlink($lock);
  143.                 if ($e != null) {
  144.                     $errors[] = $e;
  145.                 }
  146.             } else {
  147.                 $errors[] = "Tick lock file found: $lock";
  148.             }
  149.         }
  150.         // Restart bot (poor mans solution)
  151.         $this->discordTriggerService->addTrigger(nullDiscordTriggerService::TRIGGER_CLAN_INTEGRATE0);
  152.         if (count($errors) > 0) {
  153.             throw new \RuntimeException(count($errors) . " errors while ticking"500$errors[0] instanceof Exception $errors[0] : null);
  154.         }
  155.         return new Response(""Response::HTTP_OK);
  156.     }
  157.     /**
  158.      * @Route("/tick-manual/{areaId}", name="game_tick_manual")
  159.      *
  160.      * @param int             $areaId
  161.      * @param KernelInterface $kernel
  162.      * @param Request         $request
  163.      *
  164.      * @return Response
  165.      * @throws Exception
  166.      */
  167.     public function manualTick(int $areaIdKernelInterface $kernelRequest $request): Response
  168.     {
  169.         if ($kernel->getEnvironment() == 'prod') {
  170.             $this->addFlash('notice'"Naughty naughty");
  171.             return $this->redirectToRoute('game_townhall');
  172.         }
  173.         // Lock process
  174.         $lock $kernel->getProjectDir() . "/tickarealock_{$areaId}.lock";
  175.         if (!file_exists($lock) || filemtime($lock) > time() + 300) {
  176.             fopen($lock'w');
  177.             $e null;
  178.             $area $this->gameService->areaService->getArea($areaId);
  179.             $this->addFlash('notice'"Ticking " . ($area->getSettings()->turn 1));
  180.             $this->handleTick($area$e);
  181.             unlink($lock);
  182.             if ($e != null) {
  183.                 throw $e;
  184.             }
  185.         } else {
  186.             $this->addFlash('notice'"Tick lock file found");
  187.         }
  188.         if (!empty($request->server->all()['HTTP_REFERER'])) {
  189.             return $this->redirect($request->server->all()['HTTP_REFERER']);
  190.         }
  191.         return $this->redirectToRoute('game_townhall');
  192.     }
  193.     private function handleTick(Area $area, &$e)
  194.     {
  195.         if (!$area->isRunning()) {
  196.             return;
  197.         }
  198.         try {
  199.             // Set the area manually on the service layer, don't rely on pulling it from session
  200.             $this->gameService->setArea($area);
  201.             $this->gameHelper->setServices($this->gameService);
  202.             $this->gameHelper->log = []; // reset log
  203.             if ($area->getType() == Area::TYPE_PVP) {
  204.                 $ticker = new PvpAreaTicker($area);
  205.             } else {
  206.                 $ticker = new PveAreaTicker($area);
  207.             }
  208.             $start microtime(true);
  209.             $this->gameService->areaDb()->begin_transaction();
  210.             $this->gameHelper->tick($ticker);
  211.             $time microtime(true) - $start;
  212.             $this->gameService->areaService->insertTurnLog($area"Total Execution Time: {$time} seconds. " date("d/m/Y H:i") . "\nLog:\n" implode("\n"$this->gameHelper->log));
  213.             $this->gameService->commit();
  214.         } catch (Exception $e) {
  215.             $this->gameService->areaDb()->rollback();
  216.             $this->gameHelper->log[] = $e->getTraceAsString();
  217.             $this->gameService->areaService->insertTurnLog($area"Tick failed. " $e->getMessage() .  "\nLog:\n" implode("\n"$this->gameHelper->log));
  218.             $this->gameService->commit();
  219.             // TODO Log error
  220.         }
  221.     }
  222. }