ColonyTick::__construct()   A
last analyzed

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 RuntimeException;
8
use Stu\Component\Building\BuildingFunctionEnum;
9
use Stu\Component\Building\BuildingManagerInterface;
10
use Stu\Component\Colony\ColonyFunctionManagerInterface;
11
use Stu\Lib\Transfer\Storage\StorageManagerInterface;
12
use Stu\Lib\ColonyProduction\ColonyProduction;
13
use Stu\Lib\Information\InformationFactoryInterface;
14
use Stu\Lib\Information\InformationWrapper;
15
use Stu\Module\Colony\Lib\ColonyLibFactoryInterface;
16
use Stu\Module\Commodity\Lib\CommodityCacheInterface;
17
use Stu\Module\Message\Lib\PrivateMessageFolderTypeEnum;
18
use Stu\Module\Message\Lib\PrivateMessageSenderInterface;
19
use Stu\Module\PlayerSetting\Lib\UserConstants;
0 ignored issues
show
Bug introduced by
The type Stu\Module\PlayerSetting\Lib\UserConstants 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...
20
use Stu\Module\Tick\Colony\Component\ColonyTickComponentInterface;
21
use Stu\Orm\Entity\BuildingCommodity;
22
use Stu\Orm\Entity\Colony;
23
use Stu\Orm\Entity\Commodity;
24
use Stu\Orm\Entity\PlanetField;
25
use Stu\Orm\Repository\ColonyDepositMiningRepositoryInterface;
26
use Stu\Orm\Repository\ColonyRepositoryInterface;
27
use Stu\Orm\Repository\ModuleQueueRepositoryInterface;
28
use Stu\Orm\Repository\PlanetFieldRepositoryInterface;
29
30
final class ColonyTick implements ColonyTickInterface
31
{
32
    private InformationWrapper $information;
33
34
    /** @param array<ColonyTickComponentInterface> $components */
35 1
    public function __construct(
36
        private readonly ModuleQueueRepositoryInterface $moduleQueueRepository,
37
        private readonly PlanetFieldRepositoryInterface $planetFieldRepository,
38
        private readonly ColonyRepositoryInterface $colonyRepository,
39
        private readonly ColonyDepositMiningRepositoryInterface $colonyDepositMiningRepository,
40
        private readonly PrivateMessageSenderInterface $privateMessageSender,
41
        private readonly StorageManagerInterface $storageManager,
42
        private readonly BuildingManagerInterface $buildingManager,
43
        private readonly ColonyLibFactoryInterface $colonyLibFactory,
44
        private readonly ColonyFunctionManagerInterface $colonyFunctionManager,
45
        private readonly CommodityCacheInterface $commodityCache,
46
        private readonly InformationFactoryInterface $informationFactory,
47
        private readonly array $components
48 1
    ) {}
49
50 1
    #[\Override]
51
    public function work(Colony $colony): void
52
    {
53 1
        $this->information = $this->informationFactory->createInformationWrapper();
54
55 1
        $deactivatedFields = $this->mainLoop($colony);
56
57 1
        $this->colonyRepository->save($colony);
58
59 1
        $this->proceedModules($colony, $deactivatedFields);
60 1
        $this->sendMessages($colony);
61
    }
62
63
    /**
64
     * @return array<int>
65
     */
66 1
    private function mainLoop(Colony $colony): array
67
    {
68 1
        $i = 1;
69 1
        $production = $this->colonyLibFactory->createColonyCommodityProduction($colony)->getProduction();
70
71 1
        $deactivatedFields = [-1];
72
73 1
        while (true) {
74
75 1
            $rewind = $this->checkStorage($colony, $production, $deactivatedFields);
76 1
            $rewind |= $this->checkLivingSpace($colony, $production, $deactivatedFields);
77 1
            $rewind |= $this->checkEnergyProduction($colony, $production, $deactivatedFields);
78
79 1
            if ($rewind !== 0) {
80
                $i++;
81
                if ($i == 100) {
82
                    // SECURITY
83
                    //echo "HIT SECURITY BREAK\n";
84
                    break;
85
                }
86
                continue;
87
            }
88 1
            break;
89
        }
90 1
        $changeable = $colony->getChangeable();
91 1
        $changeable->setEps(
92 1
            min(
93 1
                $colony->getMaxEps(),
94 1
                $changeable->getEps() + $this->planetFieldRepository->getEnergyProductionByHost($colony, $deactivatedFields)
95 1
            )
96 1
        );
97
98 1
        foreach ($this->components as $component) {
99 1
            $component->work($colony, $production, $this->information);
100
        }
101
102 1
        return $deactivatedFields;
103
    }
104
105
    /**
106
     * @param array<int, ColonyProduction> $production
107
     * @param array<int> $deactivatedFields
108
     */
109 1
    private function checkStorage(
110
        Colony $colony,
111
        array &$production,
112
        array &$deactivatedFields
113
    ): bool {
114
115 1
        $result = false;
116
117 1
        foreach ($production as $pro) {
118 1
            if ($pro->getProduction() >= 0) {
119 1
                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\ColonyDepositMining::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 1
        return $result;
144
    }
145
146
    /**
147
     * @param array<int, ColonyProduction> $production
148
     * @param array<int> $deactivatedFields
149
     */
150 1
    private function checkLivingSpace(
151
        Colony $colony,
152
        array &$production,
153
        array &$deactivatedFields
154
    ): bool {
155 1
        if ($colony->getWorkers() > $colony->getChangeable()->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 1
        return false;
166
    }
167
168
    /**
169
     * @param array<int, ColonyProduction> $production
170
     * @param array<int> $deactivatedFields
171
     */
172 1
    private function checkEnergyProduction(
173
        Colony $colony,
174
        array &$production,
175
        array &$deactivatedFields
176
    ): bool {
177 1
        $energyProduction = $this->planetFieldRepository->getEnergyProductionByHost($colony, $deactivatedFields);
178
179 1
        if ($energyProduction < 0 && $colony->getChangeable()->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 1
        return false;
189
    }
190
191
    /**
192
     * @param array<int, ColonyProduction> $production
193
     */
194
    private function deactivateBuilding(
195
        PlanetField $field,
196
        array &$production,
197
        Commodity|string $cause
198
    ): void {
199
        $ext = $cause instanceof Commodity ? $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
        Colony $colony,
223
        int $commodityId,
224
        array $deactivatedFields
225
    ): PlanetField {
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
        Colony $colony,
247
        array $deactivatedFields
248
    ): PlanetField {
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
        Colony $colony,
269
        array $deactivatedFields
270
    ): ?PlanetField {
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 1
    private function proceedModules(Colony $colony, array $deactivatedFields): void
285
    {
286 1
        foreach ($this->moduleQueueRepository->getByColony($colony->getId()) as $queue) {
287 1
            $buildingFunction = $queue->getBuildingFunction();
288
289
            //spare parts and system components are generated by spacecraft tick manager, to avoid dead locks
290
            if (
291 1
                $buildingFunction === BuildingFunctionEnum::FABRICATION_HALL ||
292 1
                $buildingFunction === BuildingFunctionEnum::TECH_CENTER
293
            ) {
294
                continue;
295
            }
296
297 1
            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 1
    private function sendMessages(Colony $colony): void
315
    {
316 1
        if ($this->information->isEmpty()) {
317 1
            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
            UserConstants::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, BuildingCommodity> $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