Passed
Push — dev ( 117aec...fd7324 )
by Janko
15:18
created

RepairUtil   D

Complexity

Total Complexity 58

Size/Duplication

Total Lines 374
Duplicated Lines 0 %

Test Coverage

Coverage 18.45%

Importance

Changes 0
Metric Value
eloc 203
dl 0
loc 374
ccs 38
cts 206
cp 0.1845
rs 4.5599
c 0
b 0
f 0
wmc 58

How to fix   Complexity   

Complex Class

Complex classes like RepairUtil often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use RepairUtil, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
declare(strict_types=1);
4
5
namespace Stu\Component\Spacecraft\Repair;
6
7
use Override;
8
use RuntimeException;
9
use Stu\Component\Building\BuildingFunctionEnum;
10
use Stu\Component\Colony\ColonyFunctionManagerInterface;
11
use Stu\Component\Crew\CrewEnum;
12
use Stu\Component\Spacecraft\SpacecraftStateEnum;
13
use Stu\Lib\Transfer\Storage\StorageManagerInterface;
14
use Stu\Component\Spacecraft\System\SpacecraftSystemTypeEnum;
15
use Stu\Module\Commodity\CommodityTypeEnum;
16
use Stu\Module\Message\Lib\PrivateMessageFolderTypeEnum;
17
use Stu\Module\Message\Lib\PrivateMessageSenderInterface;
18
use Stu\Module\PlayerSetting\Lib\UserEnum;
19
use Stu\Module\Spacecraft\Lib\SpacecraftWrapperInterface;
20
use Stu\Orm\Entity\ColonyInterface;
21
use Stu\Orm\Entity\RepairTaskInterface;
22
use Stu\Orm\Entity\SpacecraftInterface;
23
use Stu\Orm\Repository\ColonyShipRepairRepositoryInterface;
24
use Stu\Orm\Repository\RepairTaskRepositoryInterface;
25
use Stu\Orm\Repository\SpacecraftSystemRepositoryInterface;
26
27
//TODO unit tests
28
final class RepairUtil implements RepairUtilInterface
29
{
30
    public const int REPAIR_RATE_PER_TICK = 100;
0 ignored issues
show
Bug introduced by
A parse error occurred: Syntax error, unexpected T_STRING, expecting '=' on line 30 at column 21
Loading history...
31
32 9
    public function __construct(
33
        private SpacecraftSystemRepositoryInterface $shipSystemRepository,
34
        private RepairTaskRepositoryInterface $repairTaskRepository,
35
        private ColonyShipRepairRepositoryInterface $colonyShipRepairRepository,
36
        private StorageManagerInterface $storageManager,
37
        private ColonyFunctionManagerInterface $colonyFunctionManager,
38
        private PrivateMessageSenderInterface $privateMessageSender
39 9
    ) {}
40
41
    //REPAIR STUFF
42
    #[Override]
43
    public function determineSpareParts(SpacecraftWrapperInterface $wrapper, bool $tickBased): array
44
    {
45
        $isRepairStationBonus = $this->isRepairStationBonus($wrapper);
46
47
        $neededSpareParts = $this->calculateNeededSpareParts($wrapper, $isRepairStationBonus, $tickBased);
48
        $neededSystemComponents = $this->calculateNeededSystemComponents($wrapper, $isRepairStationBonus, $tickBased);
49
50
        return [
51
            CommodityTypeEnum::COMMODITY_SPARE_PART => $neededSpareParts,
52
            CommodityTypeEnum::COMMODITY_SYSTEM_COMPONENT => $neededSystemComponents
53
        ];
54
    }
55
56
    private function calculateNeededSpareParts(SpacecraftWrapperInterface $wrapper, bool $isRepairStationBonus, bool $tickBased): int
57
    {
58
        $neededSpareParts = 0;
59
        $ship = $wrapper->get();
60
        $hull = $ship->getCondition()->getHull();
61
        $maxHull = $ship->getMaxHull();
62
63
        if ($hull < $maxHull) {
64
            if ($tickBased) {
65
                $neededSpareParts += 1;
66
            } else {
67
                $hullRepairParts = ($maxHull - $hull) / RepairTaskConstants::HULL_HITPOINTS_PER_SPARE_PART;
68
                if ($isRepairStationBonus) {
69
                    $neededSpareParts += (int)ceil($hullRepairParts / 2);
70
                } else {
71
                    $neededSpareParts += (int)ceil($hullRepairParts);
72
                }
73
            }
74
        }
75
76
        $damagedSystems = $wrapper->getDamagedSystems();
77
        $maxSystems = $tickBased ? ($isRepairStationBonus ? 4 : 2) : count($damagedSystems);
78
        $systemCount = min(count($damagedSystems), $maxSystems);
79
80
        for ($i = 0; $i < $systemCount; $i++) {
81
            $system = $damagedSystems[$i];
82
            $systemLvl = $system->determineSystemLevel();
83
            $healingPercentage = (100 - $system->getStatus()) / 100;
84
            $systemRepairParts = $healingPercentage * RepairTaskConstants::SHIPYARD_PARTS_USAGE[$systemLvl][RepairTaskConstants::SPARE_PARTS_ONLY];
85
            if ($isRepairStationBonus) {
86
                $neededSpareParts += (int)ceil($systemRepairParts / 2);
87
            } else {
88
                $neededSpareParts += (int)ceil($systemRepairParts);
89
            }
90
        }
91
92
        return $neededSpareParts;
93
    }
94
95
    private function calculateNeededSystemComponents(SpacecraftWrapperInterface $wrapper, bool $isRepairStationBonus, bool $tickBased): int
96
    {
97
        $neededSystemComponents = 0;
98
        $damagedSystems = $wrapper->getDamagedSystems();
99
        $maxSystems = $tickBased ? ($isRepairStationBonus ? 4 : 2) : count($damagedSystems);
100
        $systemCount = min(count($damagedSystems), $maxSystems);
101
102
        for ($i = 0; $i < $systemCount; $i++) {
103
            $system = $damagedSystems[$i];
104
            $systemLvl = $system->determineSystemLevel();
105
            $healingPercentage = (100 - $system->getStatus()) / 100;
106
            $systemComponents = $healingPercentage * RepairTaskConstants::SHIPYARD_PARTS_USAGE[$systemLvl][RepairTaskConstants::SYSTEM_COMPONENTS_ONLY];
107
            if ($isRepairStationBonus) {
108
                $neededSystemComponents += (int)ceil($systemComponents / 2);
109
            } else {
110
                $neededSystemComponents += (int)ceil($systemComponents);
111
            }
112
        }
113
114
        return $neededSystemComponents;
115
    }
116
117
    #[Override]
118
    public function enoughSparePartsOnEntity(
119
        array $neededParts,
120
        ColonyInterface|SpacecraftInterface $entity,
121
        SpacecraftInterface $spacecraft
122
    ): bool {
123
        $neededSpareParts = $neededParts[CommodityTypeEnum::COMMODITY_SPARE_PART];
124
        $neededSystemComponents = $neededParts[CommodityTypeEnum::COMMODITY_SYSTEM_COMPONENT];
125
126
        if ($neededSpareParts > 0) {
127
            $spareParts = $entity->getStorage()->get(CommodityTypeEnum::COMMODITY_SPARE_PART);
128
129
            if ($spareParts === null || $spareParts->getAmount() < $neededSpareParts) {
130
                $this->sendNeededAmountMessage($neededSpareParts, $neededSystemComponents, $spacecraft, $entity);
131
                return false;
132
            }
133
        }
134
135
        if ($neededSystemComponents > 0) {
136
            $systemComponents = $entity->getStorage()->get(CommodityTypeEnum::COMMODITY_SYSTEM_COMPONENT);
137
138
            if ($systemComponents === null || $systemComponents->getAmount() < $neededSystemComponents) {
139
                $this->sendNeededAmountMessage($neededSpareParts, $neededSystemComponents, $spacecraft, $entity);
140
                return false;
141
            }
142
        }
143
144
        return true;
145
    }
146
147
    private function sendNeededAmountMessage(
148
        int $neededSpareParts,
149
        int $neededSystemComponents,
150
        SpacecraftInterface $spacecraft,
151
        ColonyInterface|SpacecraftInterface $entity
152
    ): void {
153
        $neededPartsString = sprintf(
154
            "%d %s%s",
155
            $neededSpareParts,
156
            CommodityTypeEnum::getDescription(CommodityTypeEnum::COMMODITY_SPARE_PART),
157
            ($neededSystemComponents > 0 ? sprintf(
158
                "\n%d %s",
159
                $neededSystemComponents,
160
                CommodityTypeEnum::getDescription(CommodityTypeEnum::COMMODITY_SYSTEM_COMPONENT)
161
            ) : '')
162
        );
163
164
        $isColony = $entity instanceof ColonyInterface;
165
166
        //PASSIVE REPAIR OF STATION BY WORKBEES
167
        if ($entity === $spacecraft) {
168
            $entityOwnerMessage = sprintf(
169
                "Die Reparatur der %s %s wurde in Sektor %s angehalten.\nEs werden folgende Waren benötigt:\n%s",
170
                $entity->getRump()->getName(),
171
                $spacecraft->getName(),
172
                $spacecraft->getSectorString(),
173
                $neededPartsString
174
            );
175
        } else {
176
            $entityOwnerMessage = $isColony ? sprintf(
177
                "Die Reparatur der %s von Siedler %s wurde in Sektor %s bei der Kolonie %s angehalten.\nEs werden folgende Waren benötigt:\n%s",
178
                $spacecraft->getName(),
179
                $spacecraft->getUser()->getName(),
180
                $spacecraft->getSectorString(),
181
                $entity->getName(),
182
                $neededPartsString
183
            ) : sprintf(
184
                "Die Reparatur der %s von Siedler %s wurde in Sektor %s bei der %s %s angehalten.\nEs werden folgende Waren benötigt:\n%s",
185
                $spacecraft->getName(),
186
                $spacecraft->getUser()->getName(),
187
                $spacecraft->getSectorString(),
188
                $entity->getRump()->getName(),
189
                $entity->getName(),
190
                $neededPartsString
191
            );
192
        }
193
        $this->privateMessageSender->send(
194
            UserEnum::USER_NOONE,
195
            $entity->getUser()->getId(),
196
            $entityOwnerMessage,
197
            $isColony ? PrivateMessageFolderTypeEnum::SPECIAL_COLONY : PrivateMessageFolderTypeEnum::SPECIAL_STATION
198
        );
199
    }
200
201
    #[Override]
202
    public function consumeSpareParts(array $neededParts, ColonyInterface|SpacecraftInterface $entity): void
203
    {
204
        foreach ($neededParts as $commodityKey => $amount) {
205
            //$this->loggerUtil->log(sprintf('consume, cid: %d, amount: %d', $commodityKey, $amount));
206
207
            if ($amount < 1) {
208
                continue;
209
            }
210
211
            $storage = $entity->getStorage()->get($commodityKey);
212
            if ($storage === null) {
213
                throw new RuntimeException('enoughSparePartsOnEntity should be called beforehand!');
214
            }
215
            $commodity = $storage->getCommodity();
216
            $this->storageManager->lowerStorage($entity, $commodity, $amount);
217
        }
218
    }
219
220
221
    //SELFREPAIR STUFF
222
223 1
    #[Override]
224
    public function determineFreeEngineerCount(SpacecraftInterface $ship): int
225
    {
226 1
        $engineerCount = 0;
227
228 1
        $engineerOptions = [];
229 1
        $nextNumber = 1;
230 1
        foreach ($ship->getCrewAssignments() as $shipCrew) {
231
            if (
232 1
                $shipCrew->getSlot() === CrewEnum::CREW_TYPE_TECHNICAL
233
                //&& $shipCrew->getRepairTask() === null
234
            ) {
235
                $engineerOptions[] = $nextNumber;
236
                $nextNumber++;
237
                $engineerCount++;
238
            }
239
        }
240
241 1
        return $engineerCount; //$engineerOptions;
242
    }
243
244 1
    #[Override]
245
    public function determineRepairOptions(SpacecraftWrapperInterface $wrapper): array
246
    {
247 1
        $repairOptions = [];
248
249 1
        $ship = $wrapper->get();
250
251
        //check for hull option
252 1
        $hullPercentage = (int) ($ship->getCondition()->getHull() * 100 / $ship->getMaxHull());
253 1
        if ($hullPercentage < RepairTaskConstants::BOTH_MAX) {
254
            $hullSystem = $this->shipSystemRepository->prototype();
255
            $hullSystem->setSystemType(SpacecraftSystemTypeEnum::HULL);
256
            $hullSystem->setStatus($hullPercentage);
257
258
            $repairOptions[SpacecraftSystemTypeEnum::HULL->value] = $hullSystem;
259
        }
260
261
        //check for system options
262 1
        foreach ($wrapper->getDamagedSystems() as $system) {
263
            if ($system->getStatus() < RepairTaskConstants::BOTH_MAX) {
264
                $repairOptions[$system->getSystemType()->value] = $system;
265
            }
266
        }
267
268 1
        return $repairOptions;
269
    }
270
271
    #[Override]
272
    public function createRepairTask(SpacecraftInterface $ship, SpacecraftSystemTypeEnum $systemType, int $repairType, int $finishTime): void
273
    {
274
        $obj = $this->repairTaskRepository->prototype();
275
276
        $obj->setUser($ship->getUser());
277
        $obj->setSpacecraft($ship);
278
        $obj->setSystemType($systemType);
279
        $obj->setHealingPercentage($this->determineHealingPercentage($repairType));
280
        $obj->setFinishTime($finishTime);
281
282
        $this->repairTaskRepository->save($obj);
283
    }
284
285
    #[Override]
286
    public function determineHealingPercentage(int $repairType): int
287
    {
288
        $percentage = 0;
289
290
        if ($repairType === RepairTaskConstants::SPARE_PARTS_ONLY) {
291
            $percentage += random_int(RepairTaskConstants::SPARE_PARTS_ONLY_MIN, RepairTaskConstants::SPARE_PARTS_ONLY_MAX);
292
        } elseif ($repairType === RepairTaskConstants::SYSTEM_COMPONENTS_ONLY) {
293
            $percentage += random_int(RepairTaskConstants::SYSTEM_COMPONENTS_ONLY_MIN, RepairTaskConstants::SYSTEM_COMPONENTS_ONLY_MAX);
294
        } elseif ($repairType === RepairTaskConstants::BOTH) {
295
            $percentage += random_int(RepairTaskConstants::BOTH_MIN, RepairTaskConstants::BOTH_MAX);
296
        }
297
298
        return $percentage;
299
    }
300
301
    #[Override]
302
    public function instantSelfRepair(SpacecraftInterface $spacecraft, SpacecraftSystemTypeEnum $systemType, int $healingPercentage): bool
303
    {
304
        return $this->internalSelfRepair(
305
            $spacecraft,
306
            $systemType,
307
            $healingPercentage
308
        );
309
    }
310
311
    #[Override]
312
    public function selfRepair(SpacecraftInterface $spacecraft, RepairTaskInterface $repairTask): bool
313
    {
314
        $systemType = $repairTask->getSystemType();
315
        $percentage = $repairTask->getHealingPercentage();
316
317
        $this->repairTaskRepository->delete($repairTask);
318
319
        return $this->internalSelfRepair($spacecraft, $systemType, $percentage);
320
    }
321
322
    private function internalSelfRepair(SpacecraftInterface $spacecraft, SpacecraftSystemTypeEnum $systemType, int $percentage): bool
323
    {
324
        $result = true;
325
326
        if ($systemType === SpacecraftSystemTypeEnum::HULL) {
327
            $hullPercentage = (int) ($spacecraft->getCondition()->getHull() * 100 / $spacecraft->getMaxHull());
328
329
            if ($hullPercentage > $percentage) {
330
                $result = false;
331
            } else {
332
                $spacecraft->getCondition()->setHull((int)($spacecraft->getMaxHull() * $percentage / 100));
333
            }
334
        } else {
335
            $system = $spacecraft->getSpacecraftSystem($systemType);
336
337
            if ($system->getStatus() > $percentage) {
338
                $result = false;
339
            } else {
340
                $system->setStatus($percentage);
341
                $this->shipSystemRepository->save($system);
342
            }
343
        }
344
345
        $spacecraft->getCondition()->setState(SpacecraftStateEnum::NONE);
346
347
        return $result;
348
    }
349
350
    #[Override]
351
    public function isRepairStationBonus(SpacecraftWrapperInterface $wrapper): bool
352
    {
353
        $ship = $wrapper->get();
354
355
        $colony = $ship->isOverColony();
356
        if ($colony === null) {
357
            return false;
358
        }
359
360
        return $this->colonyFunctionManager->hasActiveFunction($colony, BuildingFunctionEnum::REPAIR_SHIPYARD);
361
    }
362
363 6
    #[Override]
364
    public function getRepairDuration(SpacecraftWrapperInterface $wrapper): int
365
    {
366 6
        $ship = $wrapper->get();
367 6
        $ticks = $this->getRepairTicks($wrapper);
368
369
        //check if repair station is active
370 6
        $colonyRepair = $this->colonyShipRepairRepository->getByShip($ship->getId());
371 6
        if ($colonyRepair !== null) {
372 2
            $isRepairStationBonus = $this->colonyFunctionManager->hasActiveFunction($colonyRepair->getColony(), BuildingFunctionEnum::REPAIR_SHIPYARD);
373 2
            if ($isRepairStationBonus) {
374 1
                $ticks = (int)ceil($ticks / 2);
375
            }
376
        }
377
378 6
        return $ticks;
379
    }
380
381 3
    #[Override]
382
    public function getRepairDurationPreview(SpacecraftWrapperInterface $wrapper): int
383
    {
384 3
        $ship = $wrapper->get();
385 3
        $ticks = $this->getRepairTicks($wrapper);
386
387 3
        $colony = $ship->isOverColony();
388 3
        if ($colony !== null) {
389 2
            $isRepairStationBonus = $this->colonyFunctionManager->hasActiveFunction($colony, BuildingFunctionEnum::REPAIR_SHIPYARD);
390 2
            if ($isRepairStationBonus) {
391 1
                $ticks = (int)ceil($ticks / 2);
392
            }
393
        }
394
395 3
        return $ticks;
396
    }
397
398 9
    private function getRepairTicks(SpacecraftWrapperInterface $wrapper): int
399
    {
400 9
        $ship = $wrapper->get();
401 9
        $ticks = (int) ceil(($ship->getMaxHull() - $ship->getCondition()->getHull()) / self::REPAIR_RATE_PER_TICK);
402
403 9
        return max($ticks, (int) ceil(count($wrapper->getDamagedSystems()) / 2));
404
    }
405
}
406