From 59cd2732c2bc7af5fe4e9614080f9ed97c79e4c3 Mon Sep 17 00:00:00 2001 From: Mika Rautanen Date: Sun, 10 Nov 2024 15:22:17 +0200 Subject: [PATCH 1/7] Refactor object requirements for building check --- .../Abstracts/AbstractBuildingsController.php | 3 +- .../Abstracts/AbstractUnitsController.php | 2 +- app/Http/Controllers/ResearchController.php | 3 +- app/Http/Traits/ObjectAjaxTrait.php | 2 +- app/Services/BuildingQueueService.php | 18 +-- app/Services/ObjectService.php | 136 ++++++++++++++---- app/Services/ResearchQueueService.php | 18 +-- app/Services/UnitQueueService.php | 2 +- tests/Feature/ResearchQueueTest.php | 4 +- 9 files changed, 136 insertions(+), 52 deletions(-) diff --git a/app/Http/Controllers/Abstracts/AbstractBuildingsController.php b/app/Http/Controllers/Abstracts/AbstractBuildingsController.php index 617b6fba..800669b4 100644 --- a/app/Http/Controllers/Abstracts/AbstractBuildingsController.php +++ b/app/Http/Controllers/Abstracts/AbstractBuildingsController.php @@ -93,9 +93,10 @@ public function index(Request $request, PlayerService $player): View // Get current level of building $current_level = $this->planet->getObjectLevel($object_machine_name); + $next_level = $current_level + 1; // Check requirements of this building - $requirements_met = ObjectService::objectRequirementsMet($object_machine_name, $this->planet, $player); + $requirements_met = ObjectService::objectRequirementsMetWithQueue($object_machine_name, $next_level, $this->planet, $player); // Check if the current planet has enough resources to build this building. $enough_resources = $this->planet->hasResources(ObjectService::getObjectPrice($object_machine_name, $this->planet)); diff --git a/app/Http/Controllers/Abstracts/AbstractUnitsController.php b/app/Http/Controllers/Abstracts/AbstractUnitsController.php index aebb79f9..eebd421e 100644 --- a/app/Http/Controllers/Abstracts/AbstractUnitsController.php +++ b/app/Http/Controllers/Abstracts/AbstractUnitsController.php @@ -93,7 +93,7 @@ public function index(Request $request, PlayerService $player): View $amount = $planet->getObjectAmount($object->machine_name); // Check requirements of this building - $requirements_met = ObjectService::objectRequirementsMet($object->machine_name, $planet, $player, 0, false); + $requirements_met = ObjectService::objectRequirementsMet($object->machine_name, $planet, $player); // Check if the current planet has enough resources to build this building. $enough_resources = $planet->hasResources(ObjectService::getObjectPrice($object->machine_name, $planet)); diff --git a/app/Http/Controllers/ResearchController.php b/app/Http/Controllers/ResearchController.php index 329f08c9..2ac59e94 100644 --- a/app/Http/Controllers/ResearchController.php +++ b/app/Http/Controllers/ResearchController.php @@ -77,9 +77,10 @@ public function index(PlayerService $player): View // Get current level of building $current_level = $player->getResearchLevel($object->machine_name); + $next_level = $current_level + 1; // Check requirements of this building - $requirements_met = ObjectService::objectRequirementsMet($object->machine_name, $planet, $player); + $requirements_met = ObjectService::objectRequirementsMetWithQueue($object->machine_name, $next_level, $planet, $player); // Check if the current planet has enough resources to build this building. $enough_resources = $planet->hasResources(ObjectService::getObjectPrice($object->machine_name, $planet)); diff --git a/app/Http/Traits/ObjectAjaxTrait.php b/app/Http/Traits/ObjectAjaxTrait.php index f015af2b..e3532ddd 100644 --- a/app/Http/Traits/ObjectAjaxTrait.php +++ b/app/Http/Traits/ObjectAjaxTrait.php @@ -42,7 +42,7 @@ public function ajaxHandler(Request $request, PlayerService $player): JsonRespon $next_level = $current_level + 1; // Check requirements of this object - $requirements_met = ObjectService::objectRequirementsMet($object->machine_name, $planet, $player); + $requirements_met = ObjectService::objectRequirementsMetWithQueue($object->machine_name, $next_level, $planet, $player); $price = ObjectService::getObjectPrice($object->machine_name, $planet); diff --git a/app/Services/BuildingQueueService.php b/app/Services/BuildingQueueService.php index 2693dddc..d79018a4 100644 --- a/app/Services/BuildingQueueService.php +++ b/app/Services/BuildingQueueService.php @@ -77,13 +77,6 @@ public function add(PlanetService $planet, int $building_id): void // Check if user satisfies requirements to build this object. $building = ObjectService::getObjectById($building_id); - // Check if user satisfies requirements to build this object. - // TODO: refactor throw exception into a more user-friendly message. - $requirements_met = ObjectService::objectRequirementsMet($building->machine_name, $planet, $planet->getPlayer()); - if (!$requirements_met) { - throw new Exception('Requirements not met to build this object.'); - } - // @TODO: add checks that current logged in user is owner of planet // and is able to add this object to the building queue. $current_level = $planet->getObjectLevel($building->machine_name); @@ -93,6 +86,13 @@ public function add(PlanetService $planet, int $building_id): void $amount = $this->activeBuildingQueueItemCount($planet, $building->id); $next_level = $current_level + $amount + 1; + // Check if user satisfies requirements to build this object. + // TODO: refactor throw exception into a more user-friendly message. + $requirements_met = ObjectService::objectRequirementsMetWithQueue($building->machine_name, $next_level, $planet, $planet->getPlayer()); + if (!$requirements_met) { + throw new Exception('Requirements not met to build this object.'); + } + $queue = new BuildingQueue(); $queue->planet_id = $planet->getPlanetId(); $queue->object_id = $building->id; @@ -227,7 +227,7 @@ public function start(PlanetService $planet, int $time_start = 0): void // Sanity check: check if the building requirements are still met. If not, // then cancel build request. - if (!ObjectService::objectRequirementsMet($object->machine_name, $planet, $planet->getPlayer(), $queue_item->object_level_target, false)) { + if (!ObjectService::objectRequirementsWithLevelsMet($object->machine_name, $queue_item->object_level_target, $planet, $planet->getPlayer())) { $this->cancel($planet, $queue_item->id, $queue_item->object_id); continue; @@ -341,7 +341,7 @@ public function cancelItemMissingRequirements(PlanetService $planet): void foreach ($build_queue_items as $build_queue_item) { $object = ObjectService::getObjectById($build_queue_item->object_id); - if (!ObjectService::objectRequirementsMet($object->machine_name, $planet, $planet->getPlayer(), $build_queue_item->object_level_target)) { + if (!ObjectService::objectRequirementsMetWithQueue($object->machine_name, $build_queue_item->object_level_target, $planet, $planet->getPlayer())) { $this->cancel($planet, $build_queue_item->id, $object->id); break; } diff --git a/app/Services/ObjectService.php b/app/Services/ObjectService.php index 07123421..3377ce4e 100644 --- a/app/Services/ObjectService.php +++ b/app/Services/ObjectService.php @@ -329,41 +329,109 @@ public static function getBuildingObjectsWithStorage(): array * @param string $machine_name * @param PlanetService $planet * @param PlayerService $player - * @param int $level - * @param bool $queued * @return bool */ - public static function objectRequirementsMet(string $machine_name, PlanetService $planet, PlayerService $player, int $level = 0, bool $queued = true): bool + public static function objectRequirementsMet(string $machine_name, PlanetService $planet, PlayerService $player): bool + { + try { + $object = self::getObjectByMachineName($machine_name); + + foreach ($object->requirements as $requirement) { + // Load required object and check if requirements are met. + $object_required = self::getObjectByMachineName($requirement->object_machine_name); + + if ($object_required->type === GameObjectType::Research) { + // Check if requirements are met with existing technology. + if ($player->getResearchLevel($object_required->machine_name) < $requirement->level) { + return false; + } + } else { + // Check if requirements are met with existing buildings. + if ($planet->getObjectLevel($object_required->machine_name) < $requirement->level) { + return false; + } + } + } + } catch (Exception $e) { + return false; + } + + return true; + } + + /** + * Check if object requirements are met (for building it). + * + * @param string $machine_name + * @param PlanetService $planet + * @param PlayerService $player + * @param int $target_level + * @return bool + */ + public static function objectRequirementsWithLevelsMet(string $machine_name, int $target_level, PlanetService $planet, PlayerService $player): bool { try { $object = self::getObjectByMachineName($machine_name); - // Check required prior levels - if ($level) { - if (!self::objectLevelsMet($object, $planet, $player, $level, $queued)) { + // Check that the object's previous levels exist. + if ($target_level) { + if (!self::hasRequiredLevels($target_level, $object, $planet, $player)) { return false; } } + } catch (Exception $e) { + return false; + } + + return self::objectRequirementsMet($machine_name, $planet, $player); + } + + /** + * Check if object requirements are met with existing and queued items (for building it). + * + * @param string $machine_name + * @param PlanetService $planet + * @param PlayerService $player + * @param int $target_level + * @return bool + */ + public static function objectRequirementsMetWithQueue(string $machine_name, int $target_level, PlanetService $planet, PlayerService $player): bool + { + // Check the object's requirements against the existing objects + if (self::objectRequirementsWithLevelsMet($machine_name, $target_level, $planet, $player)) { + return true; + } + + // Check the object’s requirements against the queued objects. + try { + $object = self::getObjectByMachineName($machine_name); + + if (!self::hasRequiredLevelsInQueue($target_level, $object, $planet, $player)) { + return false; + } foreach ($object->requirements as $requirement) { // Load required object and check if requirements are met. $object_required = self::getObjectByMachineName($requirement->object_machine_name); - $check_queue = $queued; - // Skip queue check for research lab as it must be present for research objects + // Skip the queue check for the research lab, as it must be present for research objects. if ($object_required->machine_name === 'research_lab') { - $check_queue = false; + if ($planet->getObjectLevel('research_lab') === $requirement->level) { + continue; + } else { + return false; + } } if ($object_required->type === GameObjectType::Research) { - // Check if requirements are met with existing technology or with research items in build queue. - if ($player->getResearchLevel($object_required->machine_name) < $requirement->level && (!$check_queue || !$player->isResearchingTech($requirement->object_machine_name, $requirement->level))) { + // Check if the requirements are met by the items in the research queue. + if (!$player->isResearchingTech($requirement->object_machine_name, $requirement->level)) { return false; } } else { - // Check if requirements are met with existing buildings or with buildings in build queue. - // Building queue is checked only for building queue objects, not for unit queue objects. - if ($planet->getObjectLevel($object_required->machine_name) < $requirement->level && (!$check_queue || !$planet->isBuildingObject($requirement->object_machine_name, $requirement->level))) { + // Check if the requirements are met by the items in the building queue. + // The building queue is checked only for building queue objects, not for unit queue objects. + if (!$planet->isBuildingObject($requirement->object_machine_name, $requirement->level)) { return false; } } @@ -508,17 +576,15 @@ public static function getObjectRawPrice(string $machine_name, int $level = 0): } /** - * Check if object prior level requirements are met (for building it). - * Prior levels can be already built or in queues + * Check if object previous level requirements are met (for building it). * + * @param int $target_level * @param GameObject $object * @param PlanetService $planet * @param PlayerService $player - * @param int $level - * @param bool $queued * @return bool */ - private static function objectLevelsMet(GameObject $object, PlanetService $planet, PlayerService $player, int $level, bool $queued): bool + private static function hasRequiredLevels(int $target_level, GameObject $object, PlanetService $planet, PlayerService $player): bool { $current_level = 0; @@ -528,19 +594,35 @@ private static function objectLevelsMet(GameObject $object, PlanetService $plane $current_level = $planet->getObjectLevel($object->machine_name); } - // Check if target level is next level - if ($current_level + 1 === $level) { + // Check if target level is current or next level + if ($current_level === $target_level || $current_level + 1 === $target_level) { return true; } - // Check if items in queues should be included or not - if (!$queued) { - // There are prior levels, but queue should not be included - return false; - } + return false; + } + /** + * Check if object previous level requirements are met (for building it). + * + * @param int $target_level + * @param GameObject $object + * @param PlanetService $planet + * @param PlayerService $player + * @return bool + */ + private static function hasRequiredLevelsInQueue(int $target_level, GameObject $object, PlanetService $planet, PlayerService $player): bool + { // Check prior levels from queues - for ($i = $current_level + 1; $i < $level; $i++) { + $current_level = 0; + + if ($object->type === GameObjectType::Research) { + $current_level = $planet->getPlayer()->getResearchLevel($object->machine_name); + } else { + $current_level = $planet->getObjectLevel($object->machine_name); + } + + for ($i = $current_level + 1; $i < $target_level; $i++) { if (!$planet->isBuildingObject($object->machine_name, $i) && !$player->isResearchingTech($object->machine_name, $i)) { return false; } diff --git a/app/Services/ResearchQueueService.php b/app/Services/ResearchQueueService.php index 14bc1b17..ac289998 100644 --- a/app/Services/ResearchQueueService.php +++ b/app/Services/ResearchQueueService.php @@ -116,13 +116,6 @@ public function add(PlayerService $player, PlanetService $planet, int $research_ $object = ObjectService::getResearchObjectById($research_object_id); - // Check if user satisifes requirements to research this object. - // TODO: refactor throw exception into a more user-friendly message. - $requirements_met = ObjectService::objectRequirementsMet($object->machine_name, $planet, $planet->getPlayer()); - if (!$requirements_met) { - throw new Exception('Requirements not met to build this object.'); - } - // @TODO: add checks that current logged in user is owner of planet // and is able to add this object to the research queue. $current_level = $player->getResearchLevel($object->machine_name); @@ -132,6 +125,13 @@ public function add(PlayerService $player, PlanetService $planet, int $research_ $amount = $this->activeBuildingQueueItemCount($player, $research_object_id); $next_level = $current_level + $amount + 1; + // Check if user satisifes requirements to research this object. + // TODO: refactor throw exception into a more user-friendly message. + $requirements_met = ObjectService::objectRequirementsMetWithQueue($object->machine_name, $next_level, $planet, $planet->getPlayer()); + if (!$requirements_met) { + throw new Exception('Requirements not met to build this object.'); + } + $queue = new $this->model(); $queue->planet_id = $planet->getPlanetId(); $queue->object_id = $research_object_id; @@ -286,7 +286,7 @@ public function start(PlayerService $player, int $time_start = 0): void // Sanity check: check if the researching requirements are still met. If not, // then cancel research request. - if (!ObjectService::objectRequirementsMet($object->machine_name, $planet, $player, $queue_item->object_level_target, false)) { + if (!ObjectService::objectRequirementsWithLevelsMet($object->machine_name, $queue_item->object_level_target, $planet, $player)) { $this->cancel($player, $queue_item->id, $queue_item->object_id); continue; @@ -427,7 +427,7 @@ public function cancelItemMissingRequirements(PlayerService $player, PlanetServi foreach ($research_queue_items as $research_queue_item) { $object = ObjectService::getObjectById($research_queue_item->object_id); - if (!ObjectService::objectRequirementsMet($object->machine_name, $planet, $player, $research_queue_item->object_level_target)) { + if (!ObjectService::objectRequirementsMetWithQueue($object->machine_name, $research_queue_item->object_level_target, $planet, $player)) { $this->cancel($player, $research_queue_item->id, $object->id); break; } diff --git a/app/Services/UnitQueueService.php b/app/Services/UnitQueueService.php index b4dce52f..547dcb0f 100644 --- a/app/Services/UnitQueueService.php +++ b/app/Services/UnitQueueService.php @@ -150,7 +150,7 @@ public function add(PlanetService $planet, int $object_id, int $requested_build_ $object = ObjectService::getUnitObjectById($object_id); // Check if user satisifes requirements to build this object. - $requirements_met = ObjectService::objectRequirementsMet($object->machine_name, $planet, $planet->getPlayer(), 0, false); + $requirements_met = ObjectService::objectRequirementsMet($object->machine_name, $planet, $planet->getPlayer()); // Sanity check: check if the planet has enough resources to build // the amount requested. If not, then adjust the ordered amount. diff --git a/tests/Feature/ResearchQueueTest.php b/tests/Feature/ResearchQueueTest.php index 1abaab37..d19cc08e 100644 --- a/tests/Feature/ResearchQueueTest.php +++ b/tests/Feature/ResearchQueueTest.php @@ -192,7 +192,7 @@ public function testResearchLabRequirement(): void // Assert that research requirements for Energy Technology are not met as Research Lab is missing $response = $this->get('/research'); $response->assertStatus(200); - $this->assertRequirementsNotMet($response, 'energy_technology', 'Energy Technology research requirements not met.'); + $this->assertRequirementsNotMet($response, 'energy_technology', 'Energy Technology research requirements met.'); // Add Research Lab level 1 to build queue $this->addFacilitiesBuildRequest('research_lab'); @@ -200,7 +200,7 @@ public function testResearchLabRequirement(): void // Assert that research requirements for Energy Technology are not met as Research Lab is in build queue $response = $this->get('/research'); $response->assertStatus(200); - $this->assertRequirementsNotMet($response, 'energy_technology', 'Energy Technology research requirements not met.'); + $this->assertRequirementsNotMet($response, 'energy_technology', 'Energy Technology research requirements met.'); // Verify that Energy Technology can be added to research queue 2 minute later. $this->travel(2)->minutes(); From 109ea92e3be1c940004d4a932166c834b68cc22d Mon Sep 17 00:00:00 2001 From: Mika Rautanen Date: Sun, 10 Nov 2024 17:49:36 +0200 Subject: [PATCH 2/7] Disallow researching when research lab is upgrading --- app/Http/Controllers/ResearchController.php | 29 ++++++++++++------- app/Http/Traits/ObjectAjaxTrait.php | 6 ++++ app/ViewModels/BuildingViewModel.php | 10 +------ app/ViewModels/QueueViewModel.php | 15 ++++++++++ app/ViewModels/ResearchViewModel.php | 8 +++++ resources/views/ingame/ajax/object.blade.php | 2 +- .../views/ingame/research/index.blade.php | 8 ++--- .../ingame/research/research-item.blade.php | 27 +++++++++-------- 8 files changed, 68 insertions(+), 37 deletions(-) create mode 100644 app/ViewModels/QueueViewModel.php create mode 100644 app/ViewModels/ResearchViewModel.php diff --git a/app/Http/Controllers/ResearchController.php b/app/Http/Controllers/ResearchController.php index 2ac59e94..e11fc294 100644 --- a/app/Http/Controllers/ResearchController.php +++ b/app/Http/Controllers/ResearchController.php @@ -11,7 +11,7 @@ use OGame\Services\PlanetService; use OGame\Services\PlayerService; use OGame\Services\ResearchQueueService; -use OGame\ViewModels\BuildingViewModel; +use OGame\ViewModels\ResearchViewModel; class ResearchController extends OGameController { @@ -38,6 +38,7 @@ public function __construct(ResearchQueueService $queue) { $this->route_view_index = 'research.index'; $this->queue = $queue; + parent::__construct(); } @@ -63,10 +64,14 @@ public function index(PlayerService $player): View $count = 0; - // Parse build queue for this planet + // Parse research queue for this planet $research_full_queue = $this->queue->retrieveQueue($planet); - $build_active = $research_full_queue->getCurrentlyBuildingFromQueue(); - $build_queue = $research_full_queue->getQueuedFromQueue(); + $research_active = $research_full_queue->getCurrentlyBuildingFromQueue(); + $research_queue = $research_full_queue->getQueuedFromQueue(); + + // Researching is disallowed when Research Lab is upgrading + $research_lab_level = $planet->getObjectLevel('research_lab'); + $research_lab_upgrading = $planet->isBuildingObject('research_lab', $research_lab_level + 1); $research = []; foreach ($screen_objects as $key_row => $objects_row) { @@ -75,23 +80,24 @@ public function index(PlayerService $player): View $object = ObjectService::getResearchObjectByMachineName($object_machine_name); - // Get current level of building + // Get current level of technology $current_level = $player->getResearchLevel($object->machine_name); $next_level = $current_level + 1; - // Check requirements of this building + // Check requirements of this technology $requirements_met = ObjectService::objectRequirementsMetWithQueue($object->machine_name, $next_level, $planet, $player); - // Check if the current planet has enough resources to build this building. + // Check if the current planet has enough resources to research this technology. $enough_resources = $planet->hasResources(ObjectService::getObjectPrice($object->machine_name, $planet)); - $view_model = new BuildingViewModel(); + $view_model = new ResearchViewModel(); $view_model->object = $object; $view_model->current_level = $current_level; $view_model->requirements_met = $requirements_met; $view_model->count = $count; $view_model->enough_resources = $enough_resources; - $view_model->currently_building = (!empty($build_active) && $build_active->object->machine_name == $object->machine_name); + $view_model->currently_building = (!empty($research_active) && $research_active->object->machine_name === $object->machine_name); + $view_model->research_lab_upgrading = $research_lab_upgrading; $research[$key_row][$object->id] = $view_model; } @@ -107,9 +113,10 @@ public function index(PlayerService $player): View 'planet_id' => $planet->getPlanetId(), 'planet_name' => $planet->getPlanetName(), 'research' => $research, - 'build_active' => $build_active, - 'build_queue' => $build_queue, + 'build_active' => $research_active, + 'build_queue' => $research_queue, 'build_queue_max' => $build_queue_max, + 'research_lab_upgrading' => $research_lab_upgrading, ]); } diff --git a/app/Http/Traits/ObjectAjaxTrait.php b/app/Http/Traits/ObjectAjaxTrait.php index e3532ddd..fedced02 100644 --- a/app/Http/Traits/ObjectAjaxTrait.php +++ b/app/Http/Traits/ObjectAjaxTrait.php @@ -52,6 +52,7 @@ public function ajaxHandler(Request $request, PlayerService $player): JsonRespon // Switch $production_time = ''; $production_datetime = ''; + $research_lab_upgrading = false; switch ($object->type) { case GameObjectType::Building: case GameObjectType::Station: @@ -66,6 +67,10 @@ public function ajaxHandler(Request $request, PlayerService $player): JsonRespon case GameObjectType::Research: $production_time = AppUtil::formatTimeDuration($planet->getTechnologyResearchTime($object->machine_name)); $production_datetime = AppUtil::formatDateTimeDuration($planet->getTechnologyResearchTime($object->machine_name)); + + // Researching is disallowed when Research Lab is upgrading + $research_lab_level = $planet->getObjectLevel('research_lab'); + $research_lab_upgrading = $planet->isBuildingObject('research_lab', $research_lab_level + 1); break; default: // Unknown object type, throw error. @@ -153,6 +158,7 @@ public function ajaxHandler(Request $request, PlayerService $player): JsonRespon 'max_storage' => $max_storage, 'max_build_amount' => $max_build_amount, 'current_amount' => $current_amount, + 'research_lab_upgrading' => $research_lab_upgrading, ]); return response()->json([ diff --git a/app/ViewModels/BuildingViewModel.php b/app/ViewModels/BuildingViewModel.php index 22e78c73..b77b918a 100644 --- a/app/ViewModels/BuildingViewModel.php +++ b/app/ViewModels/BuildingViewModel.php @@ -2,14 +2,6 @@ namespace OGame\ViewModels; -use OGame\GameObjects\Models\Abstracts\GameObject; - -class BuildingViewModel +class BuildingViewModel extends QueueViewModel { - public GameObject $object; - public int $current_level; - public bool $requirements_met; - public int $count; - public bool $enough_resources; - public bool $currently_building; } diff --git a/app/ViewModels/QueueViewModel.php b/app/ViewModels/QueueViewModel.php new file mode 100644 index 00000000..60492d65 --- /dev/null +++ b/app/ViewModels/QueueViewModel.php @@ -0,0 +1,15 @@ +