Passed
Push — dev ( 0aa780...31f66c )
by Janko
11:20
created

isTargetOutsideFinishedTholianWeb()   A

Complexity

Conditions 5
Paths 4

Size

Total Lines 13
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 5.0729

Importance

Changes 0
Metric Value
cc 5
eloc 7
nc 4
nop 2
dl 0
loc 13
ccs 6
cts 7
cp 0.8571
crap 5.0729
rs 9.6111
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Stu\Module\Ship\Lib;
6
7
use Doctrine\ORM\EntityManagerInterface;
8
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...
9
use RuntimeException;
10
use Stu\Component\Game\TimeConstants;
0 ignored issues
show
Bug introduced by
The type Stu\Component\Game\TimeConstants 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...
11
use Stu\Component\Spacecraft\SpacecraftStateEnum;
12
use Stu\Component\Spacecraft\System\Data\WebEmitterSystemData;
13
use Stu\Component\Spacecraft\System\SpacecraftSystemTypeEnum;
14
use Stu\Lib\Interaction\EntityWithInteractionCheckInterface;
15
use Stu\Module\Control\StuTime;
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\Spacecraft\Lib\SpacecraftWrapperFactoryInterface;
22
use Stu\Module\Ship\Lib\ShipWrapperInterface;
23
use Stu\Module\Spacecraft\Lib\SpacecraftWrapperInterface;
24
use Stu\Orm\Entity\SpacecraftInterface;
25
use Stu\Orm\Entity\SpacecraftSystemInterface;
26
use Stu\Orm\Entity\TholianWebInterface;
27
use Stu\Orm\Repository\SpacecraftRepositoryInterface;
28
use Stu\Orm\Repository\SpacecraftSystemRepositoryInterface;
29
use Stu\Orm\Repository\TholianWebRepositoryInterface;
30
31
final class TholianWebUtil implements TholianWebUtilInterface
32
{
33
    private LoggerUtilInterface $loggerUtil;
34
35 6
    public function __construct(
36
        private SpacecraftRepositoryInterface $spacecraftRepository,
37
        private TholianWebRepositoryInterface $tholianWebRepository,
38
        private SpacecraftSystemRepositoryInterface $shipSystemRepository,
39
        private StuTime $stuTime,
40
        private PrivateMessageSenderInterface $privateMessageSender,
41
        private EntityManagerInterface $entityManager,
42
        LoggerUtilFactoryInterface $loggerUtilFactory
43
    ) {
44 6
        $this->loggerUtil = $loggerUtilFactory->getLoggerUtil();
45
    }
46
47
    #[Override]
48
    public function releaseSpacecraftFromWeb(SpacecraftWrapperInterface $wrapper): void
49
    {
50
        $this->loggerUtil->log(sprintf('releaseSpacecraftFromWeb, shipId: %d', $wrapper->get()->getId()));
51
52
        $spacecraft = $wrapper->get();
53
        $web = $spacecraft->getHoldingWeb();
54
        if ($web === null) {
55
            return;
56
        }
57
58
        $web->getCapturedSpacecrafts()->removeElement($spacecraft);
59
60
        if ($web->getCapturedSpacecrafts()->isEmpty()) {
61
            $this->resetWebHelpers($web, $wrapper->getSpacecraftWrapperFactory());
62
            $this->removeWeb($web);
63
        }
64
65
        $spacecraft->setHoldingWeb(null);
66
        $this->spacecraftRepository->save($spacecraft);
67
    }
68
69
    #[Override]
70
    public function releaseAllShips(TholianWebInterface $web, SpacecraftWrapperFactoryInterface $spacecraftWrapperFactory): void
71
    {
72
        foreach ($web->getCapturedSpacecrafts() as $target) {
73
            $this->releaseSpacecraftFromWeb($spacecraftWrapperFactory->wrapSpacecraft($target));
74
75
            //notify target owner
76
            $this->privateMessageSender->send(
77
                $web->getUser()->getId(),
78
                $target->getUser()->getId(),
79
                sprintf(
80
                    'Das Energienetz um die %s in Sektor %s wurde aufgelöst',
81
                    $target->getName(),
82
                    $target->getSectorString()
83
                ),
84
                $target->getType()->getMessageFolderType()
85
            );
86
        }
87
    }
88
89
    #[Override]
90
    public function removeWeb(TholianWebInterface $web): void
91
    {
92
        $this->loggerUtil->log(sprintf('removeWeb, webId: %d', $web->getId()));
93
94
        $this->tholianWebRepository->delete($web);
95
    }
96
97
    #[Override]
98
    public function releaseWebHelper(ShipWrapperInterface $wrapper): void
99
    {
100
        $this->loggerUtil->log(sprintf('releaseWebHelper, shipId: %d', $wrapper->get()->getId()));
101
102
        $emitter = $this->getMandatoryEmitter($wrapper);
103
        $web = $this->getMandatoryWebUnderConstruction($emitter);
104
105
        $finishedTime = $this->releaseWebHelperIntern($wrapper);
106
        if ($finishedTime === null) {
107
            return;
108
        }
109
110
        $currentSpinnerSystems = $this->shipSystemRepository->getWebConstructingShipSystems($web->getId());
111
112
        //remove web if lost
113
        if ($currentSpinnerSystems === []) {
114
            $this->releaseAllShips($web, $wrapper->getSpacecraftWrapperFactory());
115
            $this->removeWeb($web);
116
        } else {
117
            $ship = $wrapper->get();
118
119
            //notify other web spinners
120
            foreach ($currentSpinnerSystems as $shipSystem) {
121
                $this->privateMessageSender->send(
122
                    $ship->getUser()->getId(),
123
                    $shipSystem->getSpacecraft()->getUser()->getId(),
124
                    sprintf(
125
                        'Die %s hat den Netzaufbau in Sektor %s verlassen, Fertigstellung: %s',
126
                        $ship->getName(),
127
                        $ship->getSectorString(),
128
                        $this->stuTime->transformToStuDateTime($finishedTime)
129
                    ),
130
                    PrivateMessageFolderTypeEnum::SPECIAL_SHIP
131
                );
132
            }
133
        }
134
    }
135
136
    #[Override]
137
    public function resetWebHelpers(
138
        TholianWebInterface $web,
139
        SpacecraftWrapperFactoryInterface $spacecraftWrapperFactory,
140
        bool $isFinished = false
141
    ): void {
142
        $this->loggerUtil->log(sprintf('resetWebHelpers, webId: %d', $web->getId()));
143
144
        $systems = $this->shipSystemRepository->getWebConstructingShipSystems($web->getId());
145
        foreach ($systems as $system) {
146
            /** @var ShipWrapperInterface */
147
            $wrapper = $spacecraftWrapperFactory->wrapSpacecraft($system->getSpacecraft());
148
            $this->releaseWebHelperIntern($wrapper);
149
150
            //notify helpers when finished
151
            if ($isFinished) {
152
                $ship = $system->getSpacecraft();
153
154
                $this->privateMessageSender->send(
155
                    UserEnum::USER_NOONE,
156
                    $ship->getUser()->getId(),
157
                    sprintf(
158
                        'Das Energienetz in Sektor %s wurde fertiggestellt',
159
                        $ship->getSectorString()
160
                    ),
161
                    PrivateMessageFolderTypeEnum::SPECIAL_SHIP
162
                );
163
            }
164
        }
165
    }
166
167
    private function releaseWebHelperIntern(ShipWrapperInterface $wrapper): ?int
168
    {
169
        $emitter = $this->getMandatoryEmitter($wrapper);
170
        $web = $this->getMandatoryWebUnderConstruction($emitter);
171
172
        if ($emitter->ownedWebId === $emitter->webUnderConstructionId && !$web->isFinished()) {
173
            $emitter->setOwnedWebId(null);
174
        }
175
        $emitter->setWebUnderConstructionId(null)->update();
176
        $wrapper->getSpacecraftSystemManager()->deactivate($wrapper, SpacecraftSystemTypeEnum::THOLIAN_WEB, true);
177
178
        $ship = $wrapper->get();
179
        $ship->setState(SpacecraftStateEnum::SHIP_STATE_NONE);
180
        $this->spacecraftRepository->save($ship);
181
182
        //update finish time last
183
        return $this->updateWebFinishTime($web, -1);
184
    }
185
186
    #[Override]
187
    public function updateWebFinishTime(TholianWebInterface $web, ?int $helperModifier = null): ?int
188
    {
189
        $this->loggerUtil->log(sprintf('updateWebFinishTime, webId: %d', $web->getId()));
190
191
        //flush to read persistent webIds from system data
192
        $this->entityManager->flush();
193
194
        if ($web->isFinished()) {
195
            return null;
196
        }
197
198
        $currentSpinnerSystems = $this->shipSystemRepository->getWebConstructingShipSystems($web->getId());
199
        $time = $this->stuTime->time();
200
201
        //adjust by modified web spinner count
202
        if ($helperModifier !== null) {
203
            $secondsLeft = $web->getFinishedTime() - $time;
204
            $currentSpinnerCount = count($currentSpinnerSystems);
205
            $oldSpinnerCount =  $currentSpinnerCount - $helperModifier;
206
207
            if ($currentSpinnerCount !== 0) {
208
                $web->setFinishedTime($time + (int)ceil($secondsLeft * $oldSpinnerCount / $currentSpinnerCount));
209
            }
210
            $this->tholianWebRepository->save($web);
211
212
            return $web->getFinishedTime();
213
        }
214
215
        //initialize by weight of targets and spinners
216
        $targetWeightSum = array_reduce(
217
            $web->getCapturedSpacecrafts()->toArray(),
218
            fn(int $sum, SpacecraftInterface $spacecraft): int => $sum + $spacecraft->getRump()->getTractorMass(),
219
            0
220
        );
221
        $webSpinnerWeightSum = array_reduce(
222
            $this->shipSystemRepository->getWebConstructingShipSystems($web->getId()),
223
            fn(int $sum, SpacecraftSystemInterface $shipSystem): int => $sum + $shipSystem->getSpacecraft()->getRump()->getTractorMass(),
224
            0
225
        );
226
227
        $this->loggerUtil->log(sprintf('targetWeightSum: %d, webSpinnerWeightSum: %d', $targetWeightSum, $webSpinnerWeightSum));
228
229
        //only update if web spinners left
230
        if ($webSpinnerWeightSum !== 0) {
231
            $web->setFinishedTime($time + ((int)ceil($targetWeightSum / $webSpinnerWeightSum)) * TimeConstants::ONE_HOUR_IN_SECONDS);
232
            $this->tholianWebRepository->save($web);
233
        }
234
235
        return $web->getFinishedTime();
236
    }
237
238
    private function getMandatoryEmitter(ShipWrapperInterface $wrapper): WebEmitterSystemData
239
    {
240
        $emitter = $wrapper->getWebEmitterSystemData();
241
        if ($emitter === null) {
242
            throw new RuntimeException('no emitter');
243
        }
244
245
        return $emitter;
246
    }
247
    private function getMandatoryWebUnderConstruction(WebEmitterSystemData $emitter): TholianWebInterface
248
    {
249
        $web = $emitter->getWebUnderConstruction();
250
        if ($web === null) {
251
            throw new RuntimeException('no web under construction');
252
        }
253
254
        return $web;
255
    }
256
257 4
    #[Override]
258
    public function isTargetOutsideFinishedTholianWeb(EntityWithInteractionCheckInterface $source, EntityWithInteractionCheckInterface $target): bool
259
    {
260 4
        if (!$source instanceof SpacecraftInterface) {
261
            return false;
262
        }
263
264 4
        $web = $source->getHoldingWeb();
265 4
        if ($web === null || !$web->isFinished()) {
266 2
            return false;
267
        }
268
269 2
        return !$target instanceof SpacecraftInterface || $target->getHoldingWeb() !== $web;
270
    }
271
272
    #[Override]
273
    public function isTargetInsideFinishedTholianWeb(EntityWithInteractionCheckInterface $source, EntityWithInteractionCheckInterface $target): bool
274
    {
275
        if (!$target instanceof SpacecraftInterface) {
276
            return false;
277
        }
278
279
        $web = $target->getHoldingWeb();
280
        if ($web === null || !$web->isFinished()) {
281
            return false;
282
        }
283
284
        return !$source instanceof SpacecraftInterface || $source->getHoldingWeb() !== $web;
285
    }
286
}
287