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 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\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...
21
use Stu\Module\Tick\Colony\Component\ColonyTickComponentInterface;
22
use Stu\Orm\Entity\BuildingCommodity;
23
use Stu\Orm\Entity\Colony;
24
use Stu\Orm\Entity\Commodity;
25
use Stu\Orm\Entity\PlanetField;
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(Colony $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(Colony $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
        $changeable = $colony->getChangeable();
92
        $changeable->setEps(
93
            min(
94
                $colony->getMaxEps(),
95
                $changeable->getEps() + $this->planetFieldRepository->getEnergyProductionByHost($colony, $deactivatedFields)
96
            )
97
        );
98
99
        foreach ($this->components as $component) {
100
            $component->work($colony, $production, $this->information);
101
        }
102
103
        return $deactivatedFields;
104
    }
105
106
    /**
107
     * @param array<int, ColonyProduction> $production
108
     * @param array<int> $deactivatedFields
109
     */
110
    private function checkStorage(
111
        Colony $colony,
112
        array &$production,
113
        array &$deactivatedFields
114
    ): bool {
115
116
        $result = false;
117
118
        foreach ($production as $pro) {
119
            if ($pro->getProduction() >= 0) {
120
                continue;
121
            }
122
123
            $commodityId = $pro->getCommodityId();
124
125
            $depositMining = $this->colonyDepositMiningRepository->getCurrentUserDepositMinings($colony)[$commodityId] ?? null;
126
            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

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

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