Passed
Push — master ( f4068b...77f637 )
by Nico
40:27 queued 14:09
created

TroopTransfer   D

Complexity

Total Complexity 59

Size/Duplication

Total Lines 379
Duplicated Lines 0 %

Test Coverage

Coverage 0%

Importance

Changes 0
Metric Value
eloc 209
dl 0
loc 379
ccs 0
cts 201
cp 0
rs 4.08
c 0
b 0
f 0
wmc 59

8 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 26 1
F handle() 0 130 24
A sendUplinkMessage() 0 19 3
A performSessionCheck() 0 3 1
A transferFromColony() 0 28 5
B transferToShip() 0 44 9
A transferToColony() 0 20 2
C transferFromShip() 0 65 14

How to fix   Complexity   

Complex Class

Complex classes like TroopTransfer often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use TroopTransfer, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
declare(strict_types=1);
4
5
namespace Stu\Module\Ship\Action\TroopTransfer;
6
7
use request;
8
use Stu\Component\Ship\System\Exception\ShipSystemException;
9
use Stu\Component\Ship\System\Exception\SystemNotActivatableException;
10
use Stu\Component\Ship\System\Exception\SystemNotFoundException;
11
use Stu\Component\Ship\System\ShipSystemManagerInterface;
12
use Stu\Component\Ship\System\ShipSystemModeEnum;
13
use Stu\Component\Ship\System\ShipSystemTypeEnum;
14
use Stu\Component\Ship\System\Type\UplinkShipSystem;
15
use Stu\Module\Colony\Lib\ColonyLibFactoryInterface;
16
use Stu\Module\Control\ActionControllerInterface;
17
use Stu\Module\Control\GameControllerInterface;
18
use Stu\Module\Logging\LoggerUtilFactoryInterface;
19
use Stu\Module\Logging\LoggerUtilInterface;
20
use Stu\Module\Message\Lib\PrivateMessageFolderSpecialEnum;
21
use Stu\Module\Message\Lib\PrivateMessageSenderInterface;
22
use Stu\Module\Ship\Lib\ActivatorDeactivatorHelperInterface;
23
use Stu\Module\Ship\Lib\Auxiliary\ShipShutdownInterface;
24
use Stu\Module\Ship\Lib\Interaction\DockPrivilegeUtilityInterface;
25
use Stu\Module\Ship\Lib\Interaction\InteractionChecker;
26
use Stu\Module\Ship\Lib\ShipLoaderInterface;
27
use Stu\Module\Ship\Lib\ShipWrapperFactoryInterface;
28
use Stu\Module\Ship\Lib\Crew\TroopTransferUtilityInterface;
29
use Stu\Module\Ship\Lib\ShipWrapperInterface;
30
use Stu\Module\Ship\View\ShowShip\ShowShip;
31
use Stu\Orm\Entity\ColonyInterface;
32
use Stu\Orm\Entity\ShipCrewInterface;
33
use Stu\Orm\Entity\ShipInterface;
34
use Stu\Orm\Repository\ColonyRepositoryInterface;
35
use Stu\Orm\Repository\ShipRepositoryInterface;
36
37
final class TroopTransfer implements ActionControllerInterface
38
{
39
    public const ACTION_IDENTIFIER = 'B_TROOP_TRANSFER';
40
41
    private ShipLoaderInterface $shipLoader;
42
43
    private ShipRepositoryInterface $shipRepository;
44
45
    private ColonyRepositoryInterface $colonyRepository;
46
47
    private TroopTransferUtilityInterface $transferUtility;
48
49
    private ActivatorDeactivatorHelperInterface $helper;
50
51
    private ShipSystemManagerInterface $shipSystemManager;
52
53
    private DockPrivilegeUtilityInterface $dockPrivilegeUtility;
54
55
    private ShipWrapperFactoryInterface $shipWrapperFactory;
56
57
    private PrivateMessageSenderInterface $privateMessageSender;
58
59
    private ColonyLibFactoryInterface $colonyLibFactory;
60
61
    private ShipShutdownInterface $shipShutdown;
62
63
    private LoggerUtilInterface $loggerUtil;
64
65
    public function __construct(
66
        ShipLoaderInterface $shipLoader,
67
        ShipRepositoryInterface $shipRepository,
68
        ColonyRepositoryInterface $colonyRepository,
69
        TroopTransferUtilityInterface $transferUtility,
70
        ActivatorDeactivatorHelperInterface $helper,
71
        ShipSystemManagerInterface $shipSystemManager,
72
        DockPrivilegeUtilityInterface $dockPrivilegeUtility,
73
        ShipWrapperFactoryInterface $shipWrapperFactory,
74
        PrivateMessageSenderInterface $privateMessageSender,
75
        ColonyLibFactoryInterface $colonyLibFactory,
76
        ShipShutdownInterface $shipShutdown,
77
        LoggerUtilFactoryInterface $loggerUtilFactory
78
    ) {
79
        $this->shipLoader = $shipLoader;
80
        $this->shipRepository = $shipRepository;
81
        $this->colonyRepository = $colonyRepository;
82
        $this->transferUtility = $transferUtility;
83
        $this->helper = $helper;
84
        $this->shipSystemManager = $shipSystemManager;
85
        $this->dockPrivilegeUtility = $dockPrivilegeUtility;
86
        $this->shipWrapperFactory = $shipWrapperFactory;
87
        $this->privateMessageSender = $privateMessageSender;
88
        $this->colonyLibFactory = $colonyLibFactory;
89
        $this->shipShutdown = $shipShutdown;
90
        $this->loggerUtil = $loggerUtilFactory->getLoggerUtil();
91
    }
92
93
    public function handle(GameControllerInterface $game): void
94
    {
95
        //$this->loggerUtil->init('stu', LoggerEnum::LEVEL_ERROR);
96
        $game->setView(ShowShip::VIEW_IDENTIFIER);
97
98
        $user = $game->getUser();
99
        $userId = $user->getId();
100
101
        $wrapper = $this->shipLoader->getWrapperByIdAndUser(
102
            request::indInt('id'),
103
            $userId
104
        );
105
        $ship = $wrapper->get();
106
107
        if (!$ship->hasEnoughCrew($game)) {
108
            return;
109
        }
110
111
        $isColony = request::has('isColony');
112
        if ($isColony) {
113
            $target = $this->colonyRepository->find(request::postIntFatal('target'));
114
        } else {
115
            $target = $this->shipRepository->find(request::postIntFatal('target'));
116
        }
117
        if ($target === null) {
118
            return;
119
        }
120
        if (!InteractionChecker::canInteractWith($ship, $target, $game, !$isColony)) {
121
            return;
122
        }
123
124
        if (!$ship->isSystemHealthy(ShipSystemTypeEnum::SYSTEM_TROOP_QUARTERS)) {
125
            $game->addInformation(_("Die Truppenquartiere sind zerstört"));
126
            return;
127
        }
128
129
        $epsSystem = $wrapper->getEpsSystemData();
130
        if ($epsSystem->getEps() == 0) {
131
            $game->addInformation(_("Keine Energie vorhanden"));
132
            return;
133
        }
134
        if ($ship->getCloakState()) {
135
            $game->addInformation(_("Die Tarnung ist aktiviert"));
136
            return;
137
        }
138
        if ($ship->getWarpState()) {
139
            $game->addInformation(_("Der Warpantrieb ist aktiviert"));
140
            return;
141
        }
142
        if ($ship->getShieldState()) {
143
            $game->addInformation(_("Die Schilde sind aktiviert"));
144
            return;
145
        }
146
147
        $isUnload = request::has('isUnload');
148
149
150
        if (!$isColony && $target->getWarpState()) {
151
            $game->addInformation(sprintf(_('Die %s befindet sich im Warp'), $target->getName()));
152
            return;
153
        }
154
        $requestedTransferCount = request::postInt('tcount');
155
156
        $amount = 0;
157
158
        try {
159
            if ($isColony) {
160
                if ($isUnload) {
161
                    $amount = $this->transferToColony($requestedTransferCount, $ship, $target);
162
                } else {
163
                    $amount = $this->transferFromColony($requestedTransferCount, $wrapper, $target, $game);
164
                }
165
            } else {
166
                $this->loggerUtil->log('A');
167
                $isUplinkSituation = false;
168
                $ownCrewOnTarget = $this->transferUtility->ownCrewOnTarget($user, $target);
169
170
                if ($target->getUser() !== $user) {
171
                    $this->loggerUtil->log('B');
172
                    if ($target->hasUplink()) {
173
                        $this->loggerUtil->log('C');
174
                        $isUplinkSituation = true;
175
                    } else {
176
                        return;
177
                    }
178
                }
179
180
                if ($isUnload) {
181
                    $this->loggerUtil->log('D');
182
                    if ($isUplinkSituation) {
183
                        $this->loggerUtil->log('E');
184
                        if (!$this->dockPrivilegeUtility->checkPrivilegeFor($target->getId(), $user)) {
185
                            $game->addInformation(_("Benötigte Andockerlaubnis wurde verweigert"));
186
                            return;
187
                        }
188
                        $this->loggerUtil->log('F');
189
                        if (!$target->isSystemHealthy(ShipSystemTypeEnum::SYSTEM_UPLINK)) {
190
                            $this->loggerUtil->log('G');
191
                            $game->addInformation(_("Das Ziel verfügt über keinen intakten Uplink"));
192
                            return;
193
                        }
194
195
                        if ($this->transferUtility->foreignerCount($target) >= UplinkShipSystem::MAX_FOREIGNERS) {
196
                            $game->addInformation(_("Maximale Anzahl an fremden Crewman ist bereits erreicht"));
197
                        }
198
                    }
199
200
                    $amount = $this->transferToShip($requestedTransferCount, $ship, $target, $isUplinkSituation, $ownCrewOnTarget, $game);
201
                } else {
202
                    $amount = $this->transferFromShip($requestedTransferCount, $wrapper, $target, $isUplinkSituation, $ownCrewOnTarget, $game);
203
                }
204
            }
205
        } catch (ShipSystemException $e) {
206
            return;
207
        }
208
209
        $this->shipLoader->save($ship);
210
211
        $game->addInformation(
212
            sprintf(
213
                _('Die %s hat %d Crewman %s der %s transferiert'),
214
                $ship->getName(),
215
                $amount,
216
                $isUnload ? 'zu' : 'von',
217
                $target->getName()
218
            )
219
        );
220
221
        if ($ship->getCrewCount() <= $ship->getBuildplan()->getCrew()) {
222
            $this->helper->deactivate($wrapper, ShipSystemTypeEnum::SYSTEM_TROOP_QUARTERS, $game);
223
        }
224
    }
225
226
    private function transferToColony(int $requestedTransferCount, ShipInterface $ship, ColonyInterface $colony): int
227
    {
228
        $freeAssignmentCount = $this->colonyLibFactory->createColonyPopulationCalculator(
229
            $colony
230
        )->getFreeAssignmentCount();
231
232
        $amount = min(
233
            $requestedTransferCount,
234
            $this->transferUtility->getBeamableTroopCount($ship),
235
            $freeAssignmentCount
236
        );
237
238
        $assignments = $ship->getCrewAssignments()->getValues();
239
240
        for ($i = 0; $i < $amount; $i++) {
241
            //assign crew to colony
242
            $this->transferUtility->assignCrew($assignments[$i], $colony);
243
        }
244
245
        return $amount;
246
    }
247
248
    private function transferFromColony(int $requestedTransferCount, ShipWrapperInterface $wrapper, ColonyInterface $colony, GameControllerInterface $game): int
249
    {
250
        $ship = $wrapper->get();
251
252
        $amount = min(
253
            $requestedTransferCount,
254
            $colony->getCrewAssignmentAmount(),
255
            $this->transferUtility->getFreeQuarters($ship)
256
        );
257
258
        if (
259
            $amount > 0
260
            && $ship->getShipSystem(ShipSystemTypeEnum::SYSTEM_TROOP_QUARTERS)->getMode() === ShipSystemModeEnum::MODE_OFF
261
            && !$this->helper->activate($wrapper, ShipSystemTypeEnum::SYSTEM_TROOP_QUARTERS, $game)
262
        ) {
263
            throw new SystemNotActivatableException();
264
        }
265
266
        $crewAssignments = $colony->getCrewAssignments();
267
268
        for ($i = 0; $i < $amount; $i++) {
269
            /** @var ShipCrewInterface $crewAssignment */
270
            $crewAssignment = $crewAssignments->get(array_rand($crewAssignments->toArray()));
0 ignored issues
show
Bug introduced by
It seems like array_rand($crewAssignments->toArray()) can also be of type array; however, parameter $key of Doctrine\Common\Collecti...adableCollection::get() does only seem to accept integer|string, 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

270
            $crewAssignment = $crewAssignments->get(/** @scrutinizer ignore-type */ array_rand($crewAssignments->toArray()));
Loading history...
271
272
            $this->transferUtility->assignCrew($crewAssignment, $ship);
273
        }
274
275
        return $amount;
276
    }
277
278
    private function transferToShip(
279
        int $requestedTransferCount,
280
        ShipInterface $ship,
281
        ShipInterface $target,
282
        bool $isUplinkSituation,
283
        int $ownCrewOnTarget,
284
        GameControllerInterface $game
285
    ): int {
286
        if (!$target->hasShipSystem(ShipSystemTypeEnum::SYSTEM_LIFE_SUPPORT)) {
287
            $game->addInformation(sprintf(_('Die %s hat keine Lebenserhaltungssysteme'), $target->getName()));
288
289
            throw new SystemNotFoundException();
290
        }
291
292
        $this->loggerUtil->log(sprintf('ownCrewOnTarget: %d', $ownCrewOnTarget));
293
294
        $amount = min(
295
            $requestedTransferCount,
296
            $this->transferUtility->getBeamableTroopCount($ship),
297
            $this->transferUtility->getFreeQuarters($target),
298
            $isUplinkSituation ? ($ownCrewOnTarget === 0 ? 1 : 0) : PHP_INT_MAX
299
        );
300
301
        $assignments = $ship->getCrewAssignments()->getValues();
302
303
        for ($i = 0; $i < $amount; $i++) {
304
            $this->transferUtility->assignCrew($assignments[$i], $target);
305
        }
306
307
        if ($amount > 0) {
308
            if (
309
                $target->isSystemHealthy(ShipSystemTypeEnum::SYSTEM_LIFE_SUPPORT)
310
                && $target->getShipSystem(ShipSystemTypeEnum::SYSTEM_LIFE_SUPPORT)->getMode() == ShipSystemModeEnum::MODE_OFF
311
            ) {
312
                $this->shipSystemManager->activate($this->shipWrapperFactory->wrapShip($target), ShipSystemTypeEnum::SYSTEM_LIFE_SUPPORT, true);
313
            }
314
315
            if ($isUplinkSituation) {
316
                $target->getShipSystem(ShipSystemTypeEnum::SYSTEM_UPLINK)->setMode(ShipSystemModeEnum::MODE_ON);
317
                $this->sendUplinkMessage(true, true, $ship, $target);
318
            }
319
        }
320
321
        return $amount;
322
    }
323
324
    private function transferFromShip(
325
        int $requestedTransferCount,
326
        ShipWrapperInterface $wrapper,
327
        ShipInterface $target,
328
        bool $isUplinkSituation,
329
        int $ownCrewOnTarget,
330
        GameControllerInterface $game
331
    ): int {
332
        $ship = $wrapper->get();
333
334
        $amount = min(
335
            $requestedTransferCount,
336
            $this->transferUtility->getFreeQuarters($ship),
337
            $ownCrewOnTarget
338
        );
339
340
        if (
341
            $amount > 0
342
            && $ship->getShipSystem(ShipSystemTypeEnum::SYSTEM_TROOP_QUARTERS)->getMode() === ShipSystemModeEnum::MODE_OFF
343
            && !$this->helper->activate($wrapper, ShipSystemTypeEnum::SYSTEM_TROOP_QUARTERS, $game)
344
        ) {
345
            throw new SystemNotActivatableException();
346
        }
347
348
        $array = $target->getCrewAssignments()->getValues();
349
        $targetCrewCount = $target->getCrewCount();
350
351
        $i = 0;
352
        foreach ($array as $crewAssignment) {
353
            if ($crewAssignment->getCrew()->getUser() !== $ship->getUser()) {
354
                continue;
355
            }
356
357
            $this->transferUtility->assignCrew($crewAssignment, $ship);
358
            $i++;
359
360
            if ($i === $amount) {
361
                break;
362
            }
363
        }
364
365
        if ($amount > 0 && $isUplinkSituation) {
366
            //no foreigners left, shut down uplink
367
            if ($this->transferUtility->foreignerCount($target) === 0) {
368
                $target->getShipSystem(ShipSystemTypeEnum::SYSTEM_UPLINK)->setMode(ShipSystemModeEnum::MODE_OFF);
369
                $this->sendUplinkMessage(false, false, $ship, $target);
370
            } else {
371
                $this->sendUplinkMessage(false, true, $ship, $target);
372
            }
373
        }
374
375
        $targetWrapper = $this->shipWrapperFactory->wrapShip($target);
376
377
        // no crew left
378
        if ($amount === $targetCrewCount) {
379
            $this->shipShutdown->shutdown($targetWrapper);
380
        } elseif (
381
            $target->hasShipSystem(ShipSystemTypeEnum::SYSTEM_TROOP_QUARTERS)
382
            && $target->getSystemState(ShipSystemTypeEnum::SYSTEM_TROOP_QUARTERS)
383
            && $target->getCrewCount() <= $target->getBuildplan()->getCrew()
384
        ) {
385
            $this->helper->deactivate($targetWrapper, ShipSystemTypeEnum::SYSTEM_TROOP_QUARTERS, $game);
386
        }
387
388
        return $amount;
389
    }
390
391
    private function sendUplinkMessage(bool $isUnload, bool $isOn, ShipInterface $ship, ShipInterface $target): void
392
    {
393
        $href = sprintf('ship.php?%s=1&id=%d', ShowShip::VIEW_IDENTIFIER, $target->getId());
394
395
        $msg = sprintf(
396
            _('Die %s von Spieler %s hat 1 Crewman %s deiner Station %s gebeamt. Der Uplink ist %s'),
397
            $ship->getName(),
398
            $ship->getUser()->getName(),
399
            $isUnload ? 'zu' : 'von',
400
            $target->getName(),
401
            $isOn ? 'aktiviert' : 'deaktiviert'
402
        );
403
404
        $this->privateMessageSender->send(
405
            $ship->getUser()->getId(),
406
            $target->getUser()->getId(),
407
            $msg,
408
            PrivateMessageFolderSpecialEnum::PM_SPECIAL_STATION,
409
            $href
410
        );
411
    }
412
413
    public function performSessionCheck(): bool
414
    {
415
        return true;
416
    }
417
}
418