From b21316248572cb27ed1f504529ad6680a473022e Mon Sep 17 00:00:00 2001 From: Daniel Weipert Date: Tue, 2 Jan 2024 20:42:01 +0100 Subject: gemini --- src/http/Controller/Building.php | 47 ++++++++ src/http/Controller/Event.php | 85 ++++++++++++++ src/http/Controller/Login.php | 55 +++++++++ src/http/Controller/Map.php | 43 +++++++ src/http/Controller/Unit.php | 242 +++++++++++++++++++++++++++++++++++++++ src/http/Controller/Village.php | 146 +++++++++++++++++++++++ src/http/Http.php | 37 ++++++ src/http/Router.php | 80 +++++++++++++ src/http/Support/RouteLoader.php | 24 ++++ 9 files changed, 759 insertions(+) create mode 100644 src/http/Controller/Building.php create mode 100644 src/http/Controller/Event.php create mode 100644 src/http/Controller/Login.php create mode 100644 src/http/Controller/Map.php create mode 100644 src/http/Controller/Unit.php create mode 100644 src/http/Controller/Village.php create mode 100644 src/http/Http.php create mode 100644 src/http/Router.php create mode 100644 src/http/Support/RouteLoader.php (limited to 'src/http') diff --git a/src/http/Controller/Building.php b/src/http/Controller/Building.php new file mode 100644 index 0000000..4a59f0e --- /dev/null +++ b/src/http/Controller/Building.php @@ -0,0 +1,47 @@ +get('x'), $request->get('y')); + $building = Model::getByVillage($village->id, $request->get('type')) ?? Model::getEmpty($village->id, $request->get('type')); + + // resources + foreach ($building->getResourceRequirements() as $resourceType => $resourceValue) { + $village->{$resourceType} -= $resourceValue; + } + $village->updateResources(); + + // event + $event = new Event(); + $event->time = (new \DateTime())->add(\DateInterval::createFromDateString( + $building->getBuildTimeForLevel($building->getEffectiveLevel() + 1) . ' seconds' + )); + $event->villageId = $building->villageId; + $upgradeBuildingEvent = new UpgradeBuilding(); + $upgradeBuildingEvent->event = $event; + $upgradeBuildingEvent->type = $building->type; + $upgradeBuildingEvent->dbInsert(); + + return new RedirectResponse( + Router::generate( + 'village.show', + ['x' => $request->get('x'), 'y' => $request->get('y')] + ) + ); + } +} diff --git a/src/http/Controller/Event.php b/src/http/Controller/Event.php new file mode 100644 index 0000000..070d449 --- /dev/null +++ b/src/http/Controller/Event.php @@ -0,0 +1,85 @@ + $request->get('x'), 'y' => $request->get('y')] + ) + ); + } + + #[Route(path: '/event/{id}/cancel', methods: ['POST'])] + public function cancel(Request $request): Response + { + $event = DB::fetch(Model::class, 'select * from events where id=:id', ['id' => $request->get('id')])[0] ?? null; + $village = Village::get($event->villageId); + + /**@var SendUnits $sendUnitsEvent*/ + $sendUnitsEvent = DB::fetch(SendUnits::class, 'select * from events_send_units where event_id=:id', ['id' => $event->id])[0] ?? null; + if (! empty($sendUnitsEvent)) { + if ($sendUnitsEvent->type === 'SendBack') { + $cancelTimeDiff = $event->createdAt->diff(new \DateTime()); + $cancelTime = (new \DateTime())->add($cancelTimeDiff); + + $sendUnitsEvent->isCanceled = true; + $sendUnitsEvent->home = $sendUnitsEvent->destination; + $sendUnitsEvent->residence = $sendUnitsEvent->source; + + DB::query( + 'update events set time=:time where id=:id', + ['time' => $cancelTime->format('c'), 'id' => $request->get('id')] + ); + DB::query( + 'update events_send_units set is_canceled=:is_canceled, home=:home, residence=:residence where id=:id', + ['is_canceled' => $sendUnitsEvent->isCanceled, 'home' => $sendUnitsEvent->home, 'residence' => $sendUnitsEvent->residence, 'id' => $sendUnitsEvent->id] + ); + } + + else if ($sendUnitsEvent->type === 'Recall') { + $cancelTimeDiff = $event->createdAt->diff(new \DateTime()); + $cancelTime = (new \DateTime())->add($cancelTimeDiff); + + $sendUnitsEvent->isCanceled = true; + $sendUnitsEvent->home = $sendUnitsEvent->destination; + $sendUnitsEvent->residence = $sendUnitsEvent->source; + + DB::query( + 'update events set time=:time where id=:id', + ['time' => $cancelTime->format('c'), 'id' => $request->get('id')] + ); + DB::query( + 'update events_send_units set is_canceled=:is_canceled, home=:home, residence=:residence where id=:id', + ['is_canceled' => $sendUnitsEvent->isCanceled, 'home' => $sendUnitsEvent->home, 'residence' => $sendUnitsEvent->residence, 'id' => $sendUnitsEvent->id] + ); + } + } + + else { + DB::query('delete from event where id=:id', ['id' => $request->get('id')]); + } + + return new RedirectResponse( + Router::generate( + 'village.show', + ['x' => $village->x, 'y' => $village->y] + ) + ); + } +} diff --git a/src/http/Controller/Login.php b/src/http/Controller/Login.php new file mode 100644 index 0000000..8c04d85 --- /dev/null +++ b/src/http/Controller/Login.php @@ -0,0 +1,55 @@ +get('email'); + $user = DB::query('select id,username,password from users where email=:email or username=:email', ['email' => $email])->fetch(); + + if (empty($user)) { + $password = password_hash($request->get('password'), PASSWORD_DEFAULT); + DB::query('insert into users (username, password, email) values (:username, :password, :email)', ['username' => $email, 'password' => $password, 'email' => $email]); + + // TODO: also insert new village at random free coordinates + } else { + $password = $user['password']; + } + + if (password_verify($request->get('password'), $password)) { + $_SESSION['user'] = [ + 'id' => $user['id'], + 'username' => $user['username'], + ]; + + return new RedirectResponse('/villages'); + } + + return new RedirectResponse('/login'); + } + + #[Route(path: '/logout', methods: ['GET'])] + public function logout(Request $request): Response + { + session_unset(); + session_destroy(); + + return new RedirectResponse('/login'); + } +} diff --git a/src/http/Controller/Map.php b/src/http/Controller/Map.php new file mode 100644 index 0000000..69d23e1 --- /dev/null +++ b/src/http/Controller/Map.php @@ -0,0 +1,43 @@ + 1], methods: ['GET'])] + public function region(Request $request): Response + { + $x = $request->get('x'); + $y = $request->get('y'); + $range = $request->get('range'); + + $statement = DB::query( + 'select * from villages where x>=:x1 and x<=:x2 and y>=:y1 and y<=:y2', + [ + 'x1' => $x - $range, + 'x2' => $x + $range, + 'y1' => $y - $range, + 'y2' => $y + $range, + ] + ); + $villages = $statement->fetchAll(); + + $map = []; + foreach ($villages as $village) { + $map[$village['x']][$village['y']] = $village; + } + + return new Response(View::render('map.twig', [ + 'x' => $x, + 'y' => $y, + 'range' => $range, + 'map' => $map, + ])); + } +} diff --git a/src/http/Controller/Unit.php b/src/http/Controller/Unit.php new file mode 100644 index 0000000..c314cda --- /dev/null +++ b/src/http/Controller/Unit.php @@ -0,0 +1,242 @@ +get('x'), $request->get('y')); + + /**@var Model $unit*/ + $unit = new (Model::resolveType($request->get('type')))(); + $unit->type = $request->get('type'); + $unit->homeVillageId = $village->id; + + $amount = intval($request->get('amount')); + + if (! Village::canTrain($village, $unit, $amount)) { + return new RedirectResponse( + Router::generate( + 'village.show', + ['x' => $request->get('x'), 'y' => $request->get('y')] + ) + ); + } + + // resources + foreach (Model::getResourceRequirements($unit, $amount) as $resourceType => $resourceValue) { + $village->{$resourceType} -= $resourceValue; + } + $village->updateResources(); + + // event + $event = new Event(); + $event->time = (new \DateTime())->add(\DateInterval::createFromDateString($unit->getBuildTime($amount) . ' seconds')); + $event->villageId = $village->id; + $trainUnitsEvent = new TrainUnits(); + $trainUnitsEvent->event = $event; + $trainUnitsEvent->type = $request->get('type'); + $trainUnitsEvent->amount = $amount; + $trainUnitsEvent->dbInsert(); + + return new RedirectResponse( + Router::generate( + 'village.show', + ['x' => $request->get('x'), 'y' => $request->get('y')] + ) + ); + } + + #[Route(path: '/village/{x}/{y}/unit/{type}/location/{lx}/{ly}/recall', methods: ['POST'])] + public function recall(Request $request): Response + { + $village = Village::getByCoordinates($request->get('x'), $request->get('y')); + $location = Village::getByCoordinates($request->get('lx'), $request->get('ly')); + + /**@var Model $unit*/ + $unit = new (Model::resolveType($request->get('type')))(); + + $amount = intval($request->get('amount')); + $amountUnits = DB::query( + 'select amount from village_units where home_village_id=:home and residence_village_id=:residence and type=:type', + ['home' => $village->id, 'residence' => $location->id, 'type' => $request->get('type')] + )->fetchColumn(); + + if ($amountUnits - $amount > 0) { + $statement = DB::query( + << $amountUnits - $amount, 'home' => $village->id, 'residence' => $location->id, 'type' => $request->get('type')] + ); + } else if ($amountUnits - $amount === 0) { + DB::query( + << $village->id, 'residence' => $location->id, 'type' => $request->get('type')] + ); + } + + // event + $event = new Event(); + $event->time = (new \DateTime())->add( + \DateInterval::createFromDateString( + Model::getTravelTime($unit, Village::getDistance($village->x, $village->y, $location->x, $location->y)) + . ' seconds' + ) + ); + $event->villageId = $village->id; + $sendUnitsEvent = new SendUnits(); + $sendUnitsEvent->event = $event; + $sendUnitsEvent->type = 'Recall'; + $sendUnitsEvent->unit = $request->get('type'); + $sendUnitsEvent->amount = $amount; + $sendUnitsEvent->source = $location->id; + $sendUnitsEvent->destination = $village->id; + $sendUnitsEvent->dbInsert(); + + + return new RedirectResponse( + Router::generate( + 'village.show', + ['x' => $request->get('x'), 'y' => $request->get('y')] + ) + ); + } + + #[Route(path: '/village/{x}/{y}/unit/{type}/location/{lx}/{ly}/send-back', methods: ['POST'])] + public function sendBack(Request $request): Response + { + $village = Village::getByCoordinates($request->get('x'), $request->get('y')); + $location = Village::getByCoordinates($request->get('lx'), $request->get('ly')); + + /**@var Model $unit*/ + $unit = new (Model::resolveType($request->get('type')))(); + + $amount = intval($request->get('amount')); + $amountUnits = DB::query( + 'select amount from village_units where home_village_id=:home and residence_village_id=:residence and type=:type', + ['home' => $location->id, 'residence' => $village->id, 'type' => $request->get('type')] + )->fetchColumn(); + + if ($amountUnits - $amount > 0) { + $statement = DB::query( + << $amountUnits - $amount, 'home' => $location->id, 'residence' => $village->id, 'type' => $request->get('type')] + ); + } else if ($amountUnits - $amount === 0) { + DB::query( + << $location->id, 'residence' => $village->id, 'type' => $request->get('type')] + ); + } + + // event + $event = new Event(); + $event->time = (new \DateTime())->add( + \DateInterval::createFromDateString( + Model::getTravelTime($unit, Village::getDistance($village->x, $village->y, $location->x, $location->y)) + . ' seconds' + ) + ); + $event->villageId = $village->id; + $sendUnitsEvent = new SendUnits(); + $sendUnitsEvent->event = $event; + $sendUnitsEvent->type = 'SendBack'; + $sendUnitsEvent->unit = $request->get('type'); + $sendUnitsEvent->amount = $amount; + $sendUnitsEvent->source = $village->id; + $sendUnitsEvent->destination = $location->id; + $sendUnitsEvent->dbInsert(); + + + return new RedirectResponse( + Router::generate( + 'village.show', + ['x' => $request->get('x'), 'y' => $request->get('y')] + ) + ); + } + + #[Route(path: '/village/{x}/{y}/send-units', methods: ['POST'])] + public function sendUnits(Request $request): Response + { + $village = Village::getByCoordinates($request->get('x'), $request->get('y')); + $destination = Village::get($request->get('village')); + + /**@var Model $unit*/ + $unit = new (Model::resolveType($request->get('unit')))(); + + $amount = intval($request->get('amount')); + $amountUnits = DB::query( + 'select amount from village_units where home_village_id=:home and residence_village_id=:home and type=:type', + ['home' => $village->id, 'type' => $request->get('unit')] + )->fetchColumn(); + + if ($amountUnits - $amount > 0) { + $statement = DB::query( + << $amountUnits - $amount, 'home' => $village->id, 'type' => $request->get('unit')] + ); + } else if ($amountUnits - $amount === 0) { + DB::query( + << $village->id, 'type' => $request->get('unit')] + ); + } + + DB::query( + 'insert into village_units (amount, type, home_village_id, residence_village_id, is_traveling) values (:amount, :type, :home, :home, true)', + ['amount' => $amount, 'type' => $request->get('unit'), 'home' => $village->id] + ); + + // event + $event = new Event(); + $event->time = (new \DateTime())->add( + \DateInterval::createFromDateString( + Model::getTravelTime($unit, Village::getDistance($village->x, $village->y, $destination->x, $destination->y)) + . ' seconds' + ) + ); + $event->villageId = $village->id; + $sendUnitsEvent = new SendUnits(); + $sendUnitsEvent->event = $event; + $sendUnitsEvent->type = $request->get('type'); + $sendUnitsEvent->unit = $request->get('unit'); + $sendUnitsEvent->amount = $amount; + $sendUnitsEvent->source = $village->id; + $sendUnitsEvent->destination = $destination->id; + $sendUnitsEvent->dbInsert(); + + + return new RedirectResponse( + Router::generate( + 'village.show', + ['x' => $request->get('x'), 'y' => $request->get('y')] + ) + ); + } +} diff --git a/src/http/Controller/Village.php b/src/http/Controller/Village.php new file mode 100644 index 0000000..cd38442 --- /dev/null +++ b/src/http/Controller/Village.php @@ -0,0 +1,146 @@ + $_SESSION['user']['id']] + ); + + return new Response(View::render('villages.twig', [ + 'villages' => $villages, + ])); + } + + #[Route(path: '/village/{x}/{y}', methods: ['GET'])] + public function show(Request $request): Response + { + $village = Model::getByCoordinates($request->get('x'), $request->get('y')); + + if (! Guard::ownsVillage($village->id)) { + return new Response(View::render('error.twig', ['message' => 'Insufficient permission']), 403); + } + + $events = []; + + $eventsBuilding = DB::query( + << $village->id] + )->fetchAll(); + + foreach ($eventsBuilding as $row) { + $events['UpgradeBuilding'][$row['type']][] = DB::convertToModel(UpgradeBuilding::class, $row); + } + + $eventsUnits = DB::query( + << $village->id] + )->fetchAll(); + + foreach ($eventsUnits as $row) { + $events['TrainUnits'][] = DB::convertToModel(TrainUnits::class, $row); + } + + $eventsUnitsSendOwn = DB::query( + << $village->id] + )->fetchAll(); + + $eventsUnitsSendOther = DB::query( + << $village->id] + )->fetchAll(); + + foreach ([...$eventsUnitsSendOwn, ...$eventsUnitsSendOther] as $row) { + $events['SendUnits'][] = DB::convertToModel(SendUnits::class, $row);; + } + + $buildings = []; + foreach (Model::getBuildings($village->id, true) as $building) { + $buildings[$building->type] = $building; + } + + + return new Response(View::render('village.twig', [ + 'village' => $village, + 'events' => $events, + 'buildings' => $buildings, + 'villages' => DB::fetch(Model::class, "select * from villages where id!=:id", ['id' => $village->id]), + ])); + } + + #[Route(path: '/village/{x}/{y}/storage/config', methods: ['POST'])] + public function storageConfig(Request $request): Response + { + $village = Model::getByCoordinates($request->get('x'), $request->get('y')); + + // calculate to max 100% + $wood = intval($request->get('wood')); + $clay = intval($request->get('clay')); + $iron = intval($request->get('iron')); + $food = intval($request->get('food')); + $total = $wood + $clay + $iron + $food; + $woodPercent = $wood / $total; + $clayPercent = $clay / $total; + $ironPercent = $iron / $total; + $foodPercent = $food / $total; + + $wood = round($woodPercent * 100); + $clay = round($clayPercent * 100); + $iron = round($ironPercent * 100); + $food = round($foodPercent * 100); + $newTotal = $wood+$clay+$iron+$food; + $food += (100 - $newTotal); + + DB::query( + << $wood, 'clay' => $clay, 'iron' => $iron, 'food' => $food, 'id' => $village->id] + ); + + return new RedirectResponse( + Router::generate( + 'village.show', + ['x' => $request->get('x'), 'y' => $request->get('y')] + ) + ); + } +} diff --git a/src/http/Http.php b/src/http/Http.php new file mode 100644 index 0000000..1867eb4 --- /dev/null +++ b/src/http/Http.php @@ -0,0 +1,37 @@ +send(); + } +} diff --git a/src/http/Router.php b/src/http/Router.php new file mode 100644 index 0000000..db75f81 --- /dev/null +++ b/src/http/Router.php @@ -0,0 +1,80 @@ +fromRequest($request); + + self::$routes = new RouteCollection(); + $loader = new AnnotationFileLoader(new FileLocator(), new RouteLoader()); + $iterator = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator(__DIR__ . '/Controller')); + foreach ($iterator as $file) { + /**@var \SplFileInfo $file*/ + if (in_array($file->getFilename(), ['.', '..'])) continue; + + $collection = $loader->load($file->getPathname(), 'attribute'); + self::$routes->addCollection($collection); + } + } + + public static function execute(): Response + { + try { + $matcher = new UrlMatcher(self::$routes, self::$context); + $match = $matcher->matchRequest(self::$request); + + foreach ($match as $key => $value) { + if (str_starts_with($key, '_')) continue; + + self::$request->query->set($key, $value); + } + + /**@var \ReflectionClass $class*/ + $class = $match['_']['class']; + /**@var \ReflectionMethod $method*/ + $method = $match['_']['method']; + + return ($class->newInstance())->{$method->getName()}(self::$request); + } catch (ResourceNotFoundException $exception) { + return new Response('404', 404); + } catch (MethodNotAllowedException $exception) { + return new Response('403', 403); + } catch (\Exception $exception) { + return new Response('500: ' . $exception->getMessage(), 500); + } + } + + /** + * @param string $name + * @param array $parameters + * @param int $referenceType + */ + public static function generate(string $name, array $parameters = [], int $referenceType = 1): string + { + $generator = new UrlGenerator(self::$routes, self::$context); + + return $generator->generate($name, $parameters, $referenceType); + } +} diff --git a/src/http/Support/RouteLoader.php b/src/http/Support/RouteLoader.php new file mode 100644 index 0000000..b0e74cb --- /dev/null +++ b/src/http/Support/RouteLoader.php @@ -0,0 +1,24 @@ +setDefault('_', compact('class', 'method', 'annotation')); + } + + protected function getDefaultRouteName(\ReflectionClass $class, \ReflectionMethod $method) + { + $name = parent::getDefaultRouteName($class, $method); + + return str_replace( + '_', + '.', + str_replace('app_controller_', '', $name) + ); + } +} -- cgit v1.2.3