Passed
Push — master ( 91454b...2408fc )
by Nico
22:07 queued 10:43
created

ColonyTick::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 15
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 12
dl 0
loc 15
ccs 2
cts 2
cp 1
crap 1
rs 10
c 0
b 0
f 0

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
<?php
2
3
namespace Stu\Module\Tick\Colony;
4
5
use Doctrine\Common\Collections\Collection;
6
use InvalidArgumentException;
7
use Override;
0 ignored issues
show
Bug introduced by
The type Override was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
8
use RuntimeException;
9
use Stu\Component\Building\BuildingFunctionEnum;
10
use Stu\Component\Building\BuildingManagerInterface;
11
use Stu\Component\Colony\ColonyFunctionManagerInterface;
12
use Stu\Lib\Transfer\Storage\StorageManagerInterface;
13
use Stu\Lib\ColonyProduction\ColonyProduction;
14
use Stu\Module\Colony\Lib\ColonyLibFactoryInterface;
15
use Stu\Module\Commodity\Lib\CommodityCacheInterface;
16
use Stu\Module\Logging\LoggerUtilFactoryInterface;
17
use Stu\Module\Logging\LoggerUtilInterface;
18
use Stu\Module\Message\Lib\PrivateMessageFolderTypeEnum;
19
use Stu\Module\Message\Lib\PrivateMessageSenderInterface;
20
use Stu\Module\PlayerSetting\Lib\UserEnum;
0 ignored issues
show
Bug introduced by
The type Stu\Module\PlayerSetting\Lib\UserEnum was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
21
use Stu\Module\Tick\Colony\Component\ColonyTickComponentInterface;
22
use Stu\Orm\Entity\BuildingCommodityInterface;
23
use Stu\Orm\Entity\ColonyInterface;
24
use Stu\Orm\Entity\CommodityInterface;
25
use Stu\Orm\Entity\PlanetFieldInterface;
26
use Stu\Orm\Repository\ColonyDepositMiningRepositoryInterface;
27
use Stu\Orm\Repository\ColonyRepositoryInterface;
28
use Stu\Orm\Repository\ModuleQueueRepositoryInterface;
29
use Stu\Orm\Repository\PlanetFieldRepositoryInterface;
30
31
final class ColonyTick implements ColonyTickInterface
32
{
33
    private LoggerUtilInterface $loggerUtil;
34
35
    /**
36
     * @var array<string>
37
     */
38
    private array $msg = [];
39
40
    /** @param array<ColonyTickComponentInterface> $components */
41 1
    public function __construct(
42
        private ModuleQueueRepositoryInterface $moduleQueueRepository,
43
        private PlanetFieldRepositoryInterface $planetFieldRepository,
44
        private PrivateMessageSenderInterface $privateMessageSender,
45
        private StorageManagerInterface $storageManager,
46
        private ColonyRepositoryInterface $colonyRepository,
47
        private BuildingManagerInterface $buildingManager,
48
        private ColonyDepositMiningRepositoryInterface $colonyDepositMiningRepository,
49
        private ColonyLibFactoryInterface $colonyLibFactory,
50
        private ColonyFunctionManagerInterface $colonyFunctionManager,
51
        private CommodityCacheInterface $commodityCache,
52
        LoggerUtilFactoryInterface $loggerUtilFactory,
53
        private array $components
54
    ) {
55 1
        $this->loggerUtil = $loggerUtilFactory->getLoggerUtil();
56
    }
57
58
    #[Override]
59
    public function work(ColonyInterface $colony): void
60
    {
61
        $doLog = $this->loggerUtil->doLog();
62
        if ($doLog) {
63
            $startTime = microtime(true);
64
        }
65
66
        $this->mainLoop($colony);
67
68
        $this->colonyRepository->save($colony);
69
70
        $this->proceedModules($colony);
71
        $this->sendMessages($colony);
72
73
        if ($doLog) {
74
            $endTime = microtime(true);
75
            $this->loggerUtil->log(sprintf("Colony-Id: %6d, seconds: %F", $colony->getId(), $endTime - $startTime));
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $startTime does not seem to be defined for all execution paths leading up to this point.
Loading history...
76
        }
77
    }
78
79
    private function mainLoop(ColonyInterface $colony): void
80
    {
81
        $doLog = $this->loggerUtil->doLog();
82
83
        if ($doLog) {
84
            $startTime = microtime(true);
85
        }
86
87
        $i = 1;
88
        $production = $this->colonyLibFactory->createColonyCommodityProduction($colony)->getProduction();
89
90
        $deactivatedFields = [-1];
91
92
        while (true) {
93
94
            $rewind = $this->checkStorage($colony, $production, $deactivatedFields);
95
            $rewind |= $this->checkLivingSpace($colony, $production, $deactivatedFields);
96
            $rewind |= $this->checkEnergyProduction($colony, $production, $deactivatedFields);
97
98
            if ($rewind !== 0) {
99
                $i++;
100
                if ($i == 100) {
101
                    // SECURITY
102
                    //echo "HIT SECURITY BREAK\n";
103
                    break;
104
                }
105
                continue;
106
            }
107
            break;
108
        }
109
        $colony->setEps(
110
            min(
111
                $colony->getMaxEps(),
112
                $colony->getEps() + $this->planetFieldRepository->getEnergyProductionByHost($colony, $deactivatedFields)
113
            )
114
        );
115
116
        if ($doLog) {
117
            $endTime = microtime(true);
118
            $this->loggerUtil->log(sprintf("\tmainLoop, seconds: %F", $endTime - $startTime));
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $startTime does not seem to be defined for all execution paths leading up to this point.
Loading history...
119
        }
120
121
        foreach ($this->components as $component) {
122
            $component->work($colony, $production);
123
        }
124
125
        $this->proceedStorage($colony, $production);
126
    }
127
128
    /**
129
     * @param array<int, ColonyProduction> $production
130
     * @param array<int> $deactivatedFields
131
     */
132
    private function checkStorage(
133
        ColonyInterface $colony,
134
        array &$production,
135
        array &$deactivatedFields
136
    ): bool {
137
138
        $result = false;
139
140
        foreach ($production as $pro) {
141
            if ($pro->getProduction() >= 0) {
142
                continue;
143
            }
144
145
            $commodityId = $pro->getCommodityId();
146
147
            $depositMining = $colony->getUserDepositMinings()[$commodityId] ?? null;
148
            if ($depositMining !== null && $depositMining->isEnoughLeft((int) abs($pro->getProduction()))) {
149
                continue;
150
            }
151
152
            $storage = $colony->getStorage();
153
            $storageItem = $storage[$commodityId] ?? null;
154
            if ($storageItem !== null && $storageItem->getAmount() + $pro->getProduction() >= 0) {
155
                continue;
156
            }
157
            //echo "coloId:" . $colony->getId() . ", production:" . $pro->getProduction() . ", commodityId:" . $commodityId . ", commodity:" . $this->commodityCache->get($commodityId)->getName() . "\n";
158
            $field = $this->getBuildingToDeactivateByCommodity($colony, $commodityId, $deactivatedFields);
159
            // echo $i." hit by commodity ".$field->getFieldId()." - produce ".$pro->getProduction()." MT ".microtime()."\n";
160
            $this->deactivateBuilding($field, $production, $this->commodityCache->get($commodityId));
161
            $deactivatedFields[] = $field->getFieldId();
162
163
            $result = true;
164
        }
165
166
        return $result;
167
    }
168
169
    /**
170
     * @param array<int, ColonyProduction> $production
171
     * @param array<int> $deactivatedFields
172
     */
173
    private function checkLivingSpace(
174
        ColonyInterface $colony,
175
        array &$production,
176
        array &$deactivatedFields
177
    ): bool {
178
        if ($colony->getWorkers() > $colony->getMaxBev()) {
179
            $field = $this->getBuildingToDeactivateByLivingSpace($colony, $deactivatedFields);
180
            if ($field !== null) {
181
                $this->deactivateBuilding($field, $production, 'Wohnraum');
182
                $deactivatedFields[] = $field->getFieldId();
183
184
                return true;
185
            }
186
        }
187
188
        return false;
189
    }
190
191
    /**
192
     * @param array<int, ColonyProduction> $production
193
     * @param array<int> $deactivatedFields
194
     */
195
    private function checkEnergyProduction(
196
        ColonyInterface $colony,
197
        array &$production,
198
        array &$deactivatedFields
199
    ): bool {
200
        $energyProduction = $this->planetFieldRepository->getEnergyProductionByHost($colony, $deactivatedFields);
201
202
        if ($energyProduction < 0 && $colony->getEps() + $energyProduction < 0) {
203
            $field = $this->getBuildingToDeactivateByEpsUsage($colony, $deactivatedFields);
204
            //echo $i . " hit by eps " . $field->getFieldId() . " - complete usage " . $colony->getEpsProduction() . " - usage " . $field->getBuilding()->getEpsProduction() . " MT " . microtime() . "\n";
205
            $this->deactivateBuilding($field, $production, 'Energie');
206
            $deactivatedFields[] = $field->getFieldId();
207
208
            return true;
209
        }
210
211
        return false;
212
    }
213
214
    /**
215
     * @param array<int, ColonyProduction> $production
216
     */
217
    private function deactivateBuilding(
218
        PlanetFieldInterface $field,
219
        array &$production,
220
        CommodityInterface|string $cause
221
    ): void {
222
        $ext = $cause instanceof CommodityInterface ? $cause->getName() : $cause;
223
        $building = $field->getBuilding();
224
225
        if ($building === null) {
226
            throw new InvalidArgumentException('can not deactivate field without building');
227
        }
228
229
        $this->buildingManager->deactivate($field);
230
231
        $this->mergeProduction($building->getCommodities(), $production);
232
233
        $this->msg[] = $building->getName() . " auf Feld " . $field->getFieldId() . " deaktiviert (Mangel an " . $ext . ")";
234
    }
235
236
    /**
237
     * @param array<int> $deactivatedFields
238
     */
239
    private function getBuildingToDeactivateByCommodity(
240
        ColonyInterface $colony,
241
        int $commodityId,
242
        array $deactivatedFields
243
    ): PlanetFieldInterface {
244
        $fields = $this->planetFieldRepository->getCommodityConsumingByHostAndCommodity(
245
            $colony,
246
            $commodityId,
247
            [1],
248
            1,
249
            $deactivatedFields
250
        );
251
252
        $result = current($fields);
253
        if (!$result) {
254
            throw new RuntimeException('no building found');
255
        }
256
257
        return $result;
258
    }
259
260
    /**
261
     * @param array<int> $deactivatedFields
262
     */
263
    private function getBuildingToDeactivateByEpsUsage(
264
        ColonyInterface $colony,
265
        array $deactivatedFields
266
    ): PlanetFieldInterface {
267
        $fields = $this->planetFieldRepository->getEnergyConsumingByHost(
268
            $colony,
269
            [1],
270
            1,
271
            $deactivatedFields
272
        );
273
274
        $result = current($fields);
275
        if (!$result) {
276
            throw new RuntimeException('no building found');
277
        }
278
279
        return $result;
280
    }
281
282
    /**
283
     * @param array<int> $deactivatedFields
284
     */
285
    private function getBuildingToDeactivateByLivingSpace(
286
        ColonyInterface $colony,
287
        array $deactivatedFields
288
    ): ?PlanetFieldInterface {
289
        $fields = $this->planetFieldRepository->getWorkerConsumingByColonyAndState(
290
            $colony->getId(),
291
            [1],
292
            1,
293
            $deactivatedFields
294
        );
295
296
        return $fields === [] ? null : current($fields);
297
    }
298
299
    /**
300
     * @param array<ColonyProduction> $production
301
     */
302
    private function proceedStorage(
303
        ColonyInterface $colony,
304
        array $production
305
    ): void {
306
        $doLog = $this->loggerUtil->doLog();
307
        if ($doLog) {
308
            $startTime = microtime(true);
309
        }
310
311
        $sum = $colony->getStorageSum();
312
313
        if ($doLog) {
314
            $startTime = microtime(true);
315
        }
316
317
        //DECREASE
318
        foreach ($production as $commodityId => $obj) {
319
            $amount = $obj->getProduction();
320
            $commodity = $this->commodityCache->get($commodityId);
321
322
            if ($amount < 0) {
323
                $amount = abs($amount);
324
325
                if ($commodity->isSaveable()) {
326
                    // STANDARD
327
                    $this->storageManager->lowerStorage(
328
                        $colony,
329
                        $this->commodityCache->get($commodityId),
330
                        $amount
0 ignored issues
show
Bug introduced by
It seems like $amount can also be of type double; however, parameter $amount of Stu\Lib\Transfer\Storage...terface::lowerStorage() does only seem to accept integer, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

330
                        /** @scrutinizer ignore-type */ $amount
Loading history...
331
                    );
332
                    $sum -= $amount;
333
                } else {
334
                    // EFFECTS
335
                    $depositMining = $colony->getUserDepositMinings()[$commodityId];
336
337
                    $depositMining->setAmountLeft($depositMining->getAmountLeft() - $amount);
0 ignored issues
show
Bug introduced by
$depositMining->getAmountLeft() - $amount of type double is incompatible with the type integer expected by parameter $amountLeft of Stu\Orm\Entity\ColonyDep...erface::setAmountLeft(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

337
                    $depositMining->setAmountLeft(/** @scrutinizer ignore-type */ $depositMining->getAmountLeft() - $amount);
Loading history...
338
                    $this->colonyDepositMiningRepository->save($depositMining);
339
                }
340
            }
341
        }
342
        if ($doLog) {
343
            $endTime = microtime(true);
344
            $this->loggerUtil->log(sprintf("\tforeach1, seconds: %F", $endTime - $startTime));
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $startTime does not seem to be defined for all execution paths leading up to this point.
Loading history...
345
        }
346
347
        if ($doLog) {
348
            $startTime = microtime(true);
349
        }
350
        foreach ($production as $commodityId => $obj) {
351
            $startTimeC = microtime(true);
352
353
            $commodity = $this->commodityCache->get($commodityId);
354
            if ($obj->getProduction() <= 0 || !$commodity->isSaveable()) {
355
                continue;
356
            }
357
            if ($sum >= $colony->getMaxStorage()) {
358
                if ($colony->getUser()->isStorageNotification()) {
359
                    $this->msg[] = _('Das Lager der Kolonie ist voll');
360
                }
361
                break;
362
            }
363
            if ($sum + $obj->getProduction() > $colony->getMaxStorage()) {
364
                $this->storageManager->upperStorage(
365
                    $colony,
366
                    $commodity,
367
                    $colony->getMaxStorage() - $sum
368
                );
369
                if ($colony->getUser()->isStorageNotification()) {
370
                    $this->msg[] = _('Das Lager der Kolonie ist voll');
371
                }
372
                break;
373
            }
374
            $startTimeM = microtime(true);
375
            $this->storageManager->upperStorage(
376
                $colony,
377
                $commodity,
378
                $obj->getProduction()
379
            );
380
            if ($doLog) {
381
                $endTimeM = microtime(true);
382
                $this->loggerUtil->log(sprintf("\t\t\tupper, seconds: %F", $endTimeM - $startTimeM));
383
            }
384
            $sum += $obj->getProduction();
385
            if ($doLog) {
386
                $endTimeC = microtime(true);
387
                $this->loggerUtil->log(sprintf("\t\tcommodity: %s, seconds: %F", $commodity->getName(), $endTimeC - $startTimeC));
388
            }
389
        }
390
        if ($doLog) {
391
            $endTime = microtime(true);
392
            $this->loggerUtil->log(sprintf("\tforeach2, seconds: %F", $endTime - $startTime));
393
        }
394
395
        if ($doLog) {
396
            $startTime = microtime(true);
397
        }
398
399
        if ($doLog) {
400
            $endTime = microtime(true);
401
            $this->loggerUtil->log(sprintf("\tresearch, seconds: %F", $endTime - $startTime));
402
        }
403
404
        if ($colony->getPopulation() > $colony->getMaxBev()) {
405
            $this->proceedEmigration($colony);
406
            return;
407
        }
408
409
        if ($colony->getPopulationLimit() > 0 && $colony->getPopulation() > $colony->getPopulationLimit() && $colony->getWorkless()) {
410
            if (($free = ($colony->getPopulationLimit() - $colony->getWorkers())) > 0) {
411
                $this->msg[] = sprintf(
412
                    _('Es sind %d Arbeitslose ausgewandert'),
413
                    ($colony->getWorkless() - $free)
414
                );
415
                $colony->setWorkless($free);
416
            } else {
417
                $this->msg[] = _('Es sind alle Arbeitslosen ausgewandert');
418
                $colony->setWorkless(0);
419
            }
420
        }
421
        $this->proceedImmigration(
422
            $colony,
423
            $production
424
        );
425
426
        if ($doLog) {
427
            $endTime = microtime(true);
428
            $this->loggerUtil->log(sprintf("\tstorage, seconds: %F", $endTime - $startTime));
429
        }
430
    }
431
432
    private function proceedModules(ColonyInterface $colony): void
433
    {
434
        foreach ($this->moduleQueueRepository->getByColony($colony->getId()) as $queue) {
435
            $buildingFunction = $queue->getBuildingFunction();
436
437
            //spare parts and system components are generated by ship tick manager, to avoid dead locks
438
            if (
439
                $buildingFunction === BuildingFunctionEnum::FABRICATION_HALL ||
440
                $buildingFunction === BuildingFunctionEnum::TECH_CENTER
441
            ) {
442
                continue;
443
            }
444
445
            if ($this->colonyFunctionManager->hasActiveFunction($colony, $buildingFunction, false)) {
446
                $this->storageManager->upperStorage(
447
                    $colony,
448
                    $queue->getModule()->getCommodity(),
449
                    $queue->getAmount()
450
                );
451
452
                $this->msg[] = sprintf(
453
                    _('Es wurden %d %s hergestellt'),
454
                    $queue->getAmount(),
455
                    $queue->getModule()->getName()
456
                );
457
                $this->moduleQueueRepository->delete($queue);
458
            }
459
        }
460
    }
461
462
    /**
463
     * @param array<int, ColonyProduction> $production
464
     */
465
    private function proceedImmigration(
466
        ColonyInterface $colony,
467
        array $production
468
    ): void {
469
        // @todo
470
        $colony->setWorkless(
471
            $colony->getWorkless() +
472
                $this->colonyLibFactory->createColonyPopulationCalculator($colony, $production)->getGrowth()
473
        );
474
    }
475
476
    private function proceedEmigration(ColonyInterface $colony): void
477
    {
478
        if ($colony->getWorkless() !== 0) {
479
            $bev = random_int(1, $colony->getWorkless());
480
            $colony->setWorkless($colony->getWorkless() - $bev);
481
            $this->msg[] = $bev . " Einwohner sind ausgewandert";
482
        }
483
    }
484
485
    private function sendMessages(ColonyInterface $colony): void
486
    {
487
        if ($this->msg === []) {
488
            return;
489
        }
490
        $text = "Tickreport der Kolonie " . $colony->getName() . "\n";
491
        foreach ($this->msg as $msg) {
492
            $text .= $msg . "\n";
493
        }
494
495
        $this->privateMessageSender->send(
496
            UserEnum::USER_NOONE,
497
            $colony->getUserId(),
498
            $text,
499
            PrivateMessageFolderTypeEnum::SPECIAL_COLONY,
500
            $colony
501
        );
502
503
        $this->msg = [];
504
    }
505
506
    /**
507
     * @param Collection<int, BuildingCommodityInterface> $buildingProduction
508
     * @param array<int, ColonyProduction> $production
509
     */
510
    private function mergeProduction(
511
        Collection $buildingProduction,
512
        array &$production
513
    ): void {
514
        foreach ($buildingProduction as $obj) {
515
            $commodityId = $obj->getCommodityId();
516
            if (!array_key_exists($commodityId, $production)) {
517
                $data = $this->colonyLibFactory->createColonyProduction(
518
                    $obj->getCommodity(),
519
                    $obj->getAmount() * -1
520
                );
521
                $production[$commodityId] = $data;
522
            } elseif ($obj->getAmount() < 0) {
523
                $production[$commodityId]->upperProduction(abs($obj->getAmount()));
0 ignored issues
show
Bug introduced by
It seems like abs($obj->getAmount()) can also be of type double; however, parameter $value of Stu\Lib\ColonyProduction...tion::upperProduction() does only seem to accept integer, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

523
                $production[$commodityId]->upperProduction(/** @scrutinizer ignore-type */ abs($obj->getAmount()));
Loading history...
524
            } else {
525
                $production[$commodityId]->lowerProduction($obj->getAmount());
526
            }
527
        }
528
    }
529
}
530