diff --git a/app/GameMessages/BattleReport.php b/app/GameMessages/BattleReport.php index c4bbf3585..866bc73c7 100644 --- a/app/GameMessages/BattleReport.php +++ b/app/GameMessages/BattleReport.php @@ -183,15 +183,15 @@ private function getBattleReportParams(): array $attacker_planet_coords = $attackerPlanet->getPlanetCoordinates()->asString(); $attacker_planet_type = $attackerPlanet->getPlanetType() === PlanetType::Moon ? 'Moon' : 'Planet'; } else { - $attacker_planet_name = __('Unknown'); - $attacker_planet_coords = ''; - $attacker_planet_type = ''; + $attacker_planet_name = $this->battleReportModel->attacker['planet_name'] ?? __('Unknown'); + $attacker_planet_coords = $this->battleReportModel->attacker['planet_coords'] ?? ''; + $attacker_planet_type = $this->battleReportModel->attacker['planet_type'] ?? ''; } } catch (Throwable $e) { - // If attacker planet can't be loaded (e.g., planet deleted), use defaults - $attacker_planet_name = __('Unknown'); - $attacker_planet_coords = ''; - $attacker_planet_type = ''; + // If attacker planet can't be loaded (e.g., planet deleted), use snapshotted data + $attacker_planet_name = $this->battleReportModel->attacker['planet_name'] ?? __('Unknown'); + $attacker_planet_coords = $this->battleReportModel->attacker['planet_coords'] ?? ''; + $attacker_planet_type = $this->battleReportModel->attacker['planet_type'] ?? ''; } } else { // No planet info available diff --git a/app/GameMissions/Abstracts/GameMission.php b/app/GameMissions/Abstracts/GameMission.php index 4bfdbd2b8..b20cdc207 100644 --- a/app/GameMissions/Abstracts/GameMission.php +++ b/app/GameMissions/Abstracts/GameMission.php @@ -21,6 +21,7 @@ use OGame\Models\FleetUnion; use OGame\Models\Planet\Coordinate; use OGame\Models\Resources; +use OGame\Support\FleetMissionPlanetFormatter; use OGame\Services\FleetMissionService; use OGame\Services\FleetUnionService; use OGame\Services\MessageService; @@ -592,21 +593,8 @@ protected function sendFleetReturnMessage(FleetMission $mission, PlayerService $ { $return_resources = $this->fleetMissionService->getResources($mission); - // Define from string based on whether the planet is available or not. - $from = "[coordinates]{$mission->galaxy_from}:{$mission->system_from}:{$mission->position_from}[/coordinates]"; - switch ($mission->type_from) { - case PlanetType::Planet->value: - case PlanetType::Moon->value: - if ($mission->planet_id_from !== null) { - $from = __('planet') . " [planet]{$mission->planet_id_from}[/planet]"; - } - break; - case PlanetType::DebrisField->value: - $from = "[debrisfield]{$mission->galaxy_from}:{$mission->system_from}:{$mission->position_from}[/debrisfield]"; - break; - } - - $to = __('planet') . " [planet]{$mission->planet_id_to}[/planet]"; + $from = FleetMissionPlanetFormatter::returnEndpointLabel($mission, 'from'); + $to = FleetMissionPlanetFormatter::returnEndpointLabel($mission, 'to'); if ($return_resources->any()) { $params = [ @@ -735,4 +723,25 @@ abstract protected function processArrival(FleetMission $mission): void; * @return void */ abstract protected function processReturn(FleetMission $mission): void; + + /** + * @return array{planet_coords?: string, planet_name?: string, planet_type?: string} + */ + protected function buildAttackerPlanetSnapshot(int|null $planetId): array + { + if ($planetId === null) { + return []; + } + + $planet = $this->planetServiceFactory->make($planetId, true); + if ($planet === null) { + return []; + } + + return [ + 'planet_coords' => $planet->getPlanetCoordinates()->asString(), + 'planet_name' => $planet->getPlanetName(), + 'planet_type' => $planet->getPlanetType() === PlanetType::Moon ? 'Moon' : 'Planet', + ]; + } } diff --git a/app/GameMissions/AttackMission.php b/app/GameMissions/AttackMission.php index 954ea4bf1..d01a4af57 100644 --- a/app/GameMissions/AttackMission.php +++ b/app/GameMissions/AttackMission.php @@ -16,6 +16,7 @@ use OGame\Models\BattleReport; use OGame\Models\Enums\PlanetType; use OGame\Models\FleetMission; +use OGame\Support\FleetMissionPlanetFormatter; use OGame\Models\Planet\Coordinate; use OGame\Models\Resources; use OGame\Services\CharacterClassService; @@ -466,7 +467,7 @@ protected function processArrival(FleetMission $mission): void $reaperCargoCapacity = $reaperObject->properties->capacity->calculate($attackerPlayer)->totalValue * $reaperCount; $this->messageService->sendSystemMessageToPlayer($attackerPlayer, DebrisFieldHarvest::class, [ - 'from' => '[planet]' . $mission->planet_id_from . '[/planet]', + 'from' => FleetMissionPlanetFormatter::tag($mission, 'from'), 'to' => '[debrisfield]' . $defenderPlanet->getPlanetCoordinates()->asString(). '[/debrisfield]', 'coordinates' => '[coordinates]' . $defenderPlanet->getPlanetCoordinates()->asString() . '[/coordinates]', 'ship_name' => $reaperObject->title, @@ -685,7 +686,7 @@ private function createBattleReport(PlayerService $attackPlayer, PlanetService $ $attackerCharacterClass = $characterClassService->getCharacterClass($attackPlayer->getUser()); $defenderCharacterClass = $characterClassService->getCharacterClass($defenderPlayer->getUser()); - $report->attacker = [ + $report->attacker = array_merge([ 'player_id' => $attackPlayer->getId(), 'resource_loss' => $battleResult->attackerResourceLoss->sum(), 'units' => $battleResult->attackerUnitsStart->toArray(), @@ -694,7 +695,7 @@ private function createBattleReport(PlayerService $attackPlayer, PlanetService $ 'armor_technology' => $battleResult->attackerArmorLevel, 'planet_id' => $battleResult->attackerPlanetId, 'character_class' => $attackerCharacterClass?->getName(), - ]; + ], $this->buildAttackerPlanetSnapshot($battleResult->attackerPlanetId)); // TODO: Enhance battle reports to show individual participating fleets/defenders // Currently shows aggregated defender data (combined units, planet owner's tech, single player_id) diff --git a/app/GameMissions/DeploymentMission.php b/app/GameMissions/DeploymentMission.php index f267b4cfb..c91ad64c0 100644 --- a/app/GameMissions/DeploymentMission.php +++ b/app/GameMissions/DeploymentMission.php @@ -11,6 +11,7 @@ use OGame\GameObjects\Models\Units\UnitCollection; use OGame\Models\Enums\PlanetType; use OGame\Models\FleetMission; +use OGame\Support\FleetMissionPlanetFormatter; use OGame\Models\Planet\Coordinate; use OGame\Services\PlanetService; use RuntimeException; @@ -85,16 +86,16 @@ protected function processArrival(FleetMission $mission): void // Send a message to the player that the mission has arrived if ($resources->any()) { $this->messageService->sendSystemMessageToPlayer($targetPlayer, FleetDeploymentWithResources::class, [ - 'from' => '[planet]' . $mission->planet_id_from . '[/planet]', - 'to' => '[planet]' . $mission->planet_id_to . '[/planet]', + 'from' => FleetMissionPlanetFormatter::tag($mission, 'from'), + 'to' => FleetMissionPlanetFormatter::tag($mission, 'to'), 'metal' => (string)$mission->metal, 'crystal' => (string)$mission->crystal, 'deuterium' => (string)($mission->deuterium + ($mission->deuterium_consumption / 2)), //if mission deployment: Add half of the consumed deuterium ]); } else { $this->messageService->sendSystemMessageToPlayer($targetPlayer, FleetDeployment::class, [ - 'from' => '[planet]' . $mission->planet_id_from . '[/planet]', - 'to' => '[planet]' . $mission->planet_id_to . '[/planet]', + 'from' => FleetMissionPlanetFormatter::tag($mission, 'from'), + 'to' => FleetMissionPlanetFormatter::tag($mission, 'to'), ]); } diff --git a/app/GameMissions/EspionageMission.php b/app/GameMissions/EspionageMission.php index 3a8e57600..6a9170c81 100644 --- a/app/GameMissions/EspionageMission.php +++ b/app/GameMissions/EspionageMission.php @@ -18,6 +18,7 @@ use OGame\Models\Enums\PlanetType; use OGame\Models\EspionageReport; use OGame\Models\FleetMission; +use OGame\Support\FleetMissionPlanetFormatter; use OGame\Models\Planet\Coordinate; use OGame\Models\Resources; use OGame\Services\CounterEspionageService; @@ -182,8 +183,8 @@ protected function processArrival(FleetMission $mission): void $params = [ // IMPORTANT: pass the raw mission planet id inside [planet]...[/planet] - 'planet' => '[planet]' . $mission->planet_id_from . '[/planet]', - 'defender' => '[planet]' . $mission->planet_id_to . '[/planet]', // defender planet + 'planet' => FleetMissionPlanetFormatter::tag($mission, 'from'), + 'defender' => FleetMissionPlanetFormatter::tag($mission, 'to'), 'attacker_name' => $attackerName, 'chance' => $counterEspionageChance, ]; diff --git a/app/GameMissions/MoonDestructionMission.php b/app/GameMissions/MoonDestructionMission.php index ec1647eb6..41ed1098b 100644 --- a/app/GameMissions/MoonDestructionMission.php +++ b/app/GameMissions/MoonDestructionMission.php @@ -445,7 +445,7 @@ private function createBattleReport(PlayerService $attackPlayer, PlanetService $ 'moon_created' => false, ]; - $report->attacker = [ + $report->attacker = array_merge([ 'player_id' => $attackPlayer->getId(), 'resource_loss' => $battleResult->attackerResourceLoss->sum(), 'units' => $battleResult->attackerUnitsStart->toArray(), @@ -453,7 +453,7 @@ private function createBattleReport(PlayerService $attackPlayer, PlanetService $ 'shielding_technology' => $battleResult->attackerShieldLevel, 'armor_technology' => $battleResult->attackerArmorLevel, 'planet_id' => $battleResult->attackerPlanetId, - ]; + ], $this->buildAttackerPlanetSnapshot($battleResult->attackerPlanetId)); $report->defender = [ 'player_id' => $defenderPlayer->getId(), diff --git a/app/GameMissions/RecycleMission.php b/app/GameMissions/RecycleMission.php index cf397b3ac..701fc367d 100644 --- a/app/GameMissions/RecycleMission.php +++ b/app/GameMissions/RecycleMission.php @@ -14,6 +14,7 @@ use OGame\Models\FleetMission; use OGame\Models\Planet\Coordinate; use OGame\Models\Resources; +use OGame\Support\FleetMissionPlanetFormatter; use OGame\Services\DebrisFieldService; use OGame\Services\ObjectService; use OGame\Services\PlanetService; @@ -133,7 +134,7 @@ protected function processArrival(FleetMission $mission): void // Send a message to the player that the mission has arrived and the resources (if any) have been collected. $this->messageService->sendSystemMessageToPlayer($originPlayer, DebrisFieldHarvest::class, [ - 'from' => '[planet]' . $mission->planet_id_from . '[/planet]', + 'from' => FleetMissionPlanetFormatter::tag($mission, 'from'), 'to' => '[debrisfield]' . $targetCoordinate->asString(). '[/debrisfield]', 'coordinates' => '[coordinates]' . $targetCoordinate->asString() . '[/coordinates]', 'ship_name' => $harvesterShip->title, diff --git a/app/GameMissions/TransportMission.php b/app/GameMissions/TransportMission.php index eca0c215b..f173bad01 100644 --- a/app/GameMissions/TransportMission.php +++ b/app/GameMissions/TransportMission.php @@ -11,6 +11,7 @@ use OGame\GameObjects\Models\Units\UnitCollection; use OGame\Models\Enums\PlanetType; use OGame\Models\FleetMission; +use OGame\Support\FleetMissionPlanetFormatter; use OGame\Models\Planet\Coordinate; use OGame\Models\Resources; use OGame\Services\PlanetService; @@ -78,8 +79,8 @@ protected function processArrival(FleetMission $mission): void // Send a message to the origin player that the mission has arrived $this->messageService->sendSystemMessageToPlayer($originPlayer, TransportArrived::class, [ - 'from' => '[planet]' . $mission->planet_id_from . '[/planet]', - 'to' => '[planet]' . $mission->planet_id_to . '[/planet]', + 'from' => FleetMissionPlanetFormatter::tag($mission, 'from'), + 'to' => FleetMissionPlanetFormatter::tag($mission, 'to'), 'metal' => (string)$mission->metal, 'crystal' => (string)$mission->crystal, 'deuterium' => (string)$mission->deuterium, @@ -88,8 +89,8 @@ protected function processArrival(FleetMission $mission): void if ($originPlayer->getId() !== $targetPlayer->getId()) { // Send a message to the target player that the mission has arrived $this->messageService->sendSystemMessageToPlayer($targetPlayer, TransportReceived::class, [ - 'from' => '[planet]' . $mission->planet_id_from . '[/planet]', - 'to' => '[planet]' . $mission->planet_id_to . '[/planet]', + 'from' => FleetMissionPlanetFormatter::tag($mission, 'from'), + 'to' => FleetMissionPlanetFormatter::tag($mission, 'to'), 'metal' => (string)$mission->metal, 'crystal' => (string)$mission->crystal, 'deuterium' => (string)$mission->deuterium, diff --git a/app/Services/FleetMissionService.php b/app/Services/FleetMissionService.php index de9c5a38b..d308904ac 100644 --- a/app/Services/FleetMissionService.php +++ b/app/Services/FleetMissionService.php @@ -17,6 +17,7 @@ use OGame\Models\FleetMission; use OGame\Models\Planet\Coordinate; use OGame\Models\Resources; +use OGame\Support\FleetMissionPlanetFormatter; /** * Class FleetMissionService. @@ -650,12 +651,12 @@ private function sendAcsDefendArrivalMessages(FleetMission $mission): void // Send message to sender (Fleet Command) $this->messageService->sendSystemMessageToPlayer($origin_player, AcsDefendArrivalSender::class, [ - 'to' => '[planet]' . $mission->planet_id_to . '[/planet]', + 'to' => FleetMissionPlanetFormatter::tag($mission, 'to'), ]); // Send message to host/target (Space Monitoring) $this->messageService->sendSystemMessageToPlayer($target_player, AcsDefendArrivalHost::class, [ - 'to' => '[planet]' . $mission->planet_id_to . '[/planet]', + 'to' => FleetMissionPlanetFormatter::tag($mission, 'to'), ]); } diff --git a/app/Services/PlanetService.php b/app/Services/PlanetService.php index 815de45cb..d593ae710 100644 --- a/app/Services/PlanetService.php +++ b/app/Services/PlanetService.php @@ -248,7 +248,7 @@ public function abandonPlanet(): void // Moon-origin fleets must keep a valid home planet so they can still return after the moon is gone. if ($this->isMoon()) { - $this->redirectActiveOutgoingMoonMissionsToParentPlanet(); + $this->redirectActiveMoonMissionsToParentPlanet(); } // Fleet missions @@ -280,10 +280,9 @@ public function abandonPlanet(): void } /** - * Rebind active missions launched from a moon to its parent planet before the moon is deleted. - * This preserves the original flight while ensuring the fleet returns to the planet instead. + * Rebind active missions involving a moon to its parent planet before the moon is deleted. */ - private function redirectActiveOutgoingMoonMissionsToParentPlanet(): void + private function redirectActiveMoonMissionsToParentPlanet(): void { $parentPlanet = $this->getParentPlanet(); if ($parentPlanet === null) { @@ -301,6 +300,16 @@ private function redirectActiveOutgoingMoonMissionsToParentPlanet(): void 'position_from' => $parentCoordinates->position, 'type_from' => PlanetType::Planet->value, ]); + + FleetMission::where('planet_id_to', $this->planet->id) + ->where('processed', 0) + ->update([ + 'planet_id_to' => $parentPlanet->getPlanetId(), + 'galaxy_to' => $parentCoordinates->galaxy, + 'system_to' => $parentCoordinates->system, + 'position_to' => $parentCoordinates->position, + 'type_to' => PlanetType::Planet->value, + ]); } /** diff --git a/app/Support/FleetMissionPlanetFormatter.php b/app/Support/FleetMissionPlanetFormatter.php new file mode 100644 index 000000000..efcd449a0 --- /dev/null +++ b/app/Support/FleetMissionPlanetFormatter.php @@ -0,0 +1,44 @@ +planet_id_from : $mission->planet_id_to; + $galaxy = $endpoint === 'from' ? $mission->galaxy_from : $mission->galaxy_to; + $system = $endpoint === 'from' ? $mission->system_from : $mission->system_to; + $position = $endpoint === 'from' ? $mission->position_from : $mission->position_to; + $type = $endpoint === 'from' ? $mission->type_from : $mission->type_to; + + if ($type === PlanetType::DebrisField->value) { + return "[debrisfield]{$galaxy}:{$system}:{$position}[/debrisfield]"; + } + + if ($planetId !== null) { + return "[planet]{$planetId}[/planet]"; + } + + return "[coordinates]{$galaxy}:{$system}:{$position}[/coordinates]"; + } + + public static function returnEndpointLabel(FleetMission $mission, string $endpoint): string + { + $tag = self::tag($mission, $endpoint); + $type = $endpoint === 'from' ? $mission->type_from : $mission->type_to; + + if (in_array($type, [PlanetType::Planet->value, PlanetType::Moon->value], true) + && str_starts_with($tag, '[planet]')) { + return __('planet') . ' ' . $tag; + } + + return $tag; + } +} diff --git a/tests/Unit/FleetMissionPlanetFormatterTest.php b/tests/Unit/FleetMissionPlanetFormatterTest.php new file mode 100644 index 000000000..ca02597e6 --- /dev/null +++ b/tests/Unit/FleetMissionPlanetFormatterTest.php @@ -0,0 +1,47 @@ +planet_id_from = 42; + $mission->galaxy_from = 1; + $mission->system_from = 2; + $mission->position_from = 3; + $mission->type_from = PlanetType::Planet->value; + + $this->assertSame('[planet]42[/planet]', FleetMissionPlanetFormatter::tag($mission, 'from')); + } + + public function testTagFallsBackToCoordinatesWhenPlanetIdIsNull(): void + { + $mission = new FleetMission(); + $mission->planet_id_from = null; + $mission->galaxy_from = 1; + $mission->system_from = 2; + $mission->position_from = 3; + $mission->type_from = PlanetType::Moon->value; + + $this->assertSame('[coordinates]1:2:3[/coordinates]', FleetMissionPlanetFormatter::tag($mission, 'from')); + } + + public function testTagUsesDebrisFieldPlaceholder(): void + { + $mission = new FleetMission(); + $mission->planet_id_to = null; + $mission->galaxy_to = 4; + $mission->system_to = 5; + $mission->position_to = 6; + $mission->type_to = PlanetType::DebrisField->value; + + $this->assertSame('[debrisfield]4:5:6[/debrisfield]', FleetMissionPlanetFormatter::tag($mission, 'to')); + } +}