Passed
Push — master ( c539b9...a2853f )
by Nico
42:04 queued 28:25
created

ColonyTick::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 14
Code Lines 0

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

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

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\Lib\Information\InformationFactoryInterface;
15
use Stu\Lib\Information\InformationWrapper;
16
use Stu\Module\Colony\Lib\ColonyLibFactoryInterface;
17
use Stu\Module\Commodity\Lib\CommodityCacheInterface;
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 InformationWrapper $information;
34
35
    /** @param array<ColonyTickComponentInterface> $components */
36 1
    public function __construct(
37
        private readonly ModuleQueueRepositoryInterface $moduleQueueRepository,
38
        private readonly PlanetFieldRepositoryInterface $planetFieldRepository,
39
        private readonly ColonyRepositoryInterface $colonyRepository,
40
        private readonly ColonyDepositMiningRepositoryInterface $colonyDepositMiningRepository,
41
        private readonly PrivateMessageSenderInterface $privateMessageSender,
42
        private readonly StorageManagerInterface $storageManager,
43
        private readonly BuildingManagerInterface $buildingManager,
44
        private readonly ColonyLibFactoryInterface $colonyLibFactory,
45
        private readonly ColonyFunctionManagerInterface $colonyFunctionManager,
46
        private readonly CommodityCacheInterface $commodityCache,
47
        private readonly InformationFactoryInterface $informationFactory,
48
        private readonly array $components
49 1
    ) {}
50
51
    #[Override]
52
    public function work(ColonyInterface $colony): void
53
    {
54
        $this->information = $this->informationFactory->createInformationWrapper();
55
56
        $deactivatedFields = $this->mainLoop($colony);
57
58
        $this->colonyRepository->save($colony);
59
60
        $this->proceedModules($colony, $deactivatedFields);
61
        $this->sendMessages($colony);
62
    }
63
64
    /**
65
     * @return array<int>
66
     */
67
    private function mainLoop(ColonyInterface $colony): array
68
    {
69
        $i = 1;
70
        $production = $this->colonyLibFactory->createColonyCommodityProduction($colony)->getProduction();
71
72
        $deactivatedFields = [-1];
73
74
        while (true) {
75
76
            $rewind = $this->checkStorage($colony, $production, $deactivatedFields);
77
            $rewind |= $this->checkLivingSpace($colony, $production, $deactivatedFields);
78
            $rewind |= $this->checkEnergyProduction($colony, $production, $deactivatedFields);
79
80
            if ($rewind !== 0) {
81
                $i++;
82
                if ($i == 100) {
83
                    // SECURITY
84
                    //echo "HIT SECURITY BREAK\n";
85
                    break;
86
                }
87
                continue;
88
            }
89
            break;
90
        }
91
        $colony->setEps(
92
            min(
93
                $colony->getMaxEps(),
94
                $colony->getEps() + $this->planetFieldRepository->getEnergyProductionByHost($colony, $deactivatedFields)
95
            )
96
        );
97
98
        foreach ($this->components as $component) {
99
            $component->work($colony, $production, $this->information);
100
        }
101
102
        return $deactivatedFields;
103
    }
104
105
    /**
106
     * @param array<int, ColonyProduction> $production
107
     * @param array<int> $deactivatedFields
108
     */
109
    private function checkStorage(
110
        ColonyInterface $colony,
111
        array &$production,
112
        array &$deactivatedFields
113
    ): bool {
114
115
        $result = false;
116
117
        foreach ($production as $pro) {
118
            if ($pro->getProduction() >= 0) {
119
                continue;
120
            }
121
122
            $commodityId = $pro->getCommodityId();
123
124
            $depositMining = $this->colonyDepositMiningRepository->getCurrentUserDepositMinings($colony)[$commodityId] ?? null;
125
            if ($depositMining !== null && $depositMining->isEnoughLeft(abs($pro->getProduction()))) {
0 ignored issues
show
Bug introduced by
It seems like abs($pro->getProduction()) can also be of type double; however, parameter $neededAmount of Stu\Orm\Entity\ColonyDep...terface::isEnoughLeft() 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

125
            if ($depositMining !== null && $depositMining->isEnoughLeft(/** @scrutinizer ignore-type */ abs($pro->getProduction()))) {
Loading history...
126
                continue;
127
            }
128
129
            $storage = $colony->getStorage();
130
            $storageItem = $storage[$commodityId] ?? null;
131
            if ($storageItem !== null && $storageItem->getAmount() + $pro->getProduction() >= 0) {
132
                continue;
133
            }
134
            //echo "coloId:" . $colony->getId() . ", production:" . $pro->getProduction() . ", commodityId:" . $commodityId . ", commodity:" . $this->commodityCache->get($commodityId)->getName() . "\n";
135
            $field = $this->getBuildingToDeactivateByCommodity($colony, $commodityId, $deactivatedFields);
136
            // echo $i." hit by commodity ".$field->getFieldId()." - produce ".$pro->getProduction()." MT ".microtime()."\n";
137
            $this->deactivateBuilding($field, $production, $this->commodityCache->get($commodityId));
138
            $deactivatedFields[] = $field->getFieldId();
139
140
            $result = true;
141
        }
142
143
        return $result;
144
    }
145
146
    /**
147
     * @param array<int, ColonyProduction> $production
148
     * @param array<int> $deactivatedFields
149
     */
150
    private function checkLivingSpace(
151
        ColonyInterface $colony,
152
        array &$production,
153
        array &$deactivatedFields
154
    ): bool {
155
        if ($colony->getWorkers() > $colony->getMaxBev()) {
156
            $field = $this->getBuildingToDeactivateByLivingSpace($colony, $deactivatedFields);
157
            if ($field !== null) {
158
                $this->deactivateBuilding($field, $production, 'Wohnraum');
159
                $deactivatedFields[] = $field->getFieldId();
160
161
                return true;
162
            }
163
        }
164
165
        return false;
166
    }
167
168
    /**
169
     * @param array<int, ColonyProduction> $production
170
     * @param array<int> $deactivatedFields
171
     */
172
    private function checkEnergyProduction(
173
        ColonyInterface $colony,
174
        array &$production,
175
        array &$deactivatedFields
176
    ): bool {
177
        $energyProduction = $this->planetFieldRepository->getEnergyProductionByHost($colony, $deactivatedFields);
178
179
        if ($energyProduction < 0 && $colony->getEps() + $energyProduction < 0) {
180
            $field = $this->getBuildingToDeactivateByEpsUsage($colony, $deactivatedFields);
181
            //echo $i . " hit by eps " . $field->getFieldId() . " - complete usage " . $colony->getEpsProduction() . " - usage " . $field->getBuilding()->getEpsProduction() . " MT " . microtime() . "\n";
182
            $this->deactivateBuilding($field, $production, 'Energie');
183
            $deactivatedFields[] = $field->getFieldId();
184
185
            return true;
186
        }
187
188
        return false;
189
    }
190
191
    /**
192
     * @param array<int, ColonyProduction> $production
193
     */
194
    private function deactivateBuilding(
195
        PlanetFieldInterface $field,
196
        array &$production,
197
        CommodityInterface|string $cause
198
    ): void {
199
        $ext = $cause instanceof CommodityInterface ? $cause->getName() : $cause;
200
        $building = $field->getBuilding();
201
202
        if ($building === null) {
203
            throw new InvalidArgumentException('can not deactivate field without building');
204
        }
205
206
        $this->buildingManager->deactivate($field);
207
208
        $this->mergeProduction($building->getCommodities(), $production);
209
210
        $this->information->addInformationf(
211
            "%s auf Feld %d deaktiviert (Mangel an %s)",
212
            $building->getName(),
213
            $field->getFieldId(),
214
            $ext
215
        );
216
    }
217
218
    /**
219
     * @param array<int> $deactivatedFields
220
     */
221
    private function getBuildingToDeactivateByCommodity(
222
        ColonyInterface $colony,
223
        int $commodityId,
224
        array $deactivatedFields
225
    ): PlanetFieldInterface {
226
        $fields = $this->planetFieldRepository->getCommodityConsumingByHostAndCommodity(
227
            $colony,
228
            $commodityId,
229
            [1],
230
            1,
231
            $deactivatedFields
232
        );
233
234
        $result = current($fields);
235
        if (!$result) {
236
            throw new RuntimeException('no building found');
237
        }
238
239
        return $result;
240
    }
241
242
    /**
243
     * @param array<int> $deactivatedFields
244
     */
245
    private function getBuildingToDeactivateByEpsUsage(
246
        ColonyInterface $colony,
247
        array $deactivatedFields
248
    ): PlanetFieldInterface {
249
        $fields = $this->planetFieldRepository->getEnergyConsumingByHost(
250
            $colony,
251
            [1],
252
            1,
253
            $deactivatedFields
254
        );
255
256
        $result = current($fields);
257
        if (!$result) {
258
            throw new RuntimeException('no building found');
259
        }
260
261
        return $result;
262
    }
263
264
    /**
265
     * @param array<int> $deactivatedFields
266
     */
267
    private function getBuildingToDeactivateByLivingSpace(
268
        ColonyInterface $colony,
269
        array $deactivatedFields
270
    ): ?PlanetFieldInterface {
271
        $fields = $this->planetFieldRepository->getWorkerConsumingByColonyAndState(
272
            $colony->getId(),
273
            [1],
274
            1,
275
            $deactivatedFields
276
        );
277
278
        return $fields === [] ? null : current($fields);
279
    }
280
281
    /**
282
     * @param array<int> $deactivatedFields
283
     */
284
    private function proceedModules(ColonyInterface $colony, array $deactivatedFields): void
285
    {
286
        foreach ($this->moduleQueueRepository->getByColony($colony->getId()) as $queue) {
287
            $buildingFunction = $queue->getBuildingFunction();
288
289
            //spare parts and system components are generated by spacecraft tick manager, to avoid dead locks
290
            if (
291
                $buildingFunction === BuildingFunctionEnum::FABRICATION_HALL ||
292
                $buildingFunction === BuildingFunctionEnum::TECH_CENTER
293
            ) {
294
                continue;
295
            }
296
297
            if ($this->colonyFunctionManager->hasActiveFunction($colony, $buildingFunction, false, $deactivatedFields)) {
298
                $this->storageManager->upperStorage(
299
                    $colony,
300
                    $queue->getModule()->getCommodity(),
301
                    $queue->getAmount()
302
                );
303
304
                $this->information->addInformationf(
305
                    _('Es wurden %d %s hergestellt'),
306
                    $queue->getAmount(),
307
                    $queue->getModule()->getName()
308
                );
309
                $this->moduleQueueRepository->delete($queue);
310
            }
311
        }
312
    }
313
314
    private function sendMessages(ColonyInterface $colony): void
315
    {
316
        if ($this->information->isEmpty()) {
317
            return;
318
        }
319
320
        $text = sprintf(
321
            "Tickreport der Kolonie %s\n%s",
322
            $colony->getName(),
323
            $this->information->getInformationsAsString()
324
        );
325
326
        $this->privateMessageSender->send(
327
            UserEnum::USER_NOONE,
328
            $colony->getUserId(),
329
            $text,
330
            PrivateMessageFolderTypeEnum::SPECIAL_COLONY,
331
            $colony
332
        );
333
334
        $this->information = $this->informationFactory->createInformationWrapper();
335
    }
336
337
    /**
338
     * @param Collection<int, BuildingCommodityInterface> $buildingProduction
339
     * @param array<int, ColonyProduction> $production
340
     */
341
    private function mergeProduction(
342
        Collection $buildingProduction,
343
        array &$production
344
    ): void {
345
        foreach ($buildingProduction as $obj) {
346
            $commodityId = $obj->getCommodityId();
347
            if (!array_key_exists($commodityId, $production)) {
348
                $data = $this->colonyLibFactory->createColonyProduction(
349
                    $obj->getCommodity(),
350
                    $obj->getAmount() * -1
351
                );
352
                $production[$commodityId] = $data;
353
            } elseif ($obj->getAmount() < 0) {
354
                $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

354
                $production[$commodityId]->upperProduction(/** @scrutinizer ignore-type */ abs($obj->getAmount()));
Loading history...
355
            } else {
356
                $production[$commodityId]->lowerProduction($obj->getAmount());
357
            }
358
        }
359
    }
360
}
361