Passed
Pull Request — master (#1658)
by Nico
08:36
created

ShipCreator   A

Complexity

Total Complexity 42

Size/Duplication

Total Lines 255
Duplicated Lines 0 %

Test Coverage

Coverage 0%

Importance

Changes 2
Bugs 2 Features 0
Metric Value
eloc 155
c 2
b 2
f 0
dl 0
loc 255
ccs 0
cts 151
cp 0
rs 9.0399
wmc 42

4 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 22 1
C createBy() 0 88 12
C addSpecialSystems() 0 42 14
F createShipSystemsByModuleList() 0 68 15

How to fix   Complexity   

Complex Class

Complex classes like ShipCreator 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 ShipCreator, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
declare(strict_types=1);
4
5
namespace Stu\Module\Ship\Lib;
6
7
use RuntimeException;
8
use Stu\Component\Ship\ShipModuleTypeEnum;
9
use Stu\Component\Ship\ShipRumpEnum;
10
use Stu\Component\Ship\ShipStateEnum;
11
use Stu\Component\Ship\System\ShipSystemModeEnum;
12
use Stu\Component\Ship\System\ShipSystemTypeEnum;
13
use Stu\Lib\ModuleRumpWrapper\ModuleRumpWrapperComputer;
14
use Stu\Lib\ModuleRumpWrapper\ModuleRumpWrapperEnergyWeapon;
15
use Stu\Lib\ModuleRumpWrapper\ModuleRumpWrapperEps;
16
use Stu\Lib\ModuleRumpWrapper\ModuleRumpWrapperHull;
17
use Stu\Lib\ModuleRumpWrapper\ModuleRumpWrapperImpulseDrive;
18
use Stu\Lib\ModuleRumpWrapper\ModuleRumpWrapperInterface;
19
use Stu\Lib\ModuleRumpWrapper\ModuleRumpWrapperProjectileWeapon;
20
use Stu\Lib\ModuleRumpWrapper\ModuleRumpWrapperReactor;
21
use Stu\Lib\ModuleRumpWrapper\ModuleRumpWrapperShield;
22
use Stu\Lib\ModuleRumpWrapper\ModuleRumpWrapperSpecial;
23
use Stu\Lib\ModuleRumpWrapper\ModuleRumpWrapperWarpDrive;
24
use Stu\Lib\ModuleRumpWrapper\ModuleRumpWrapperSensor;
25
use Stu\Module\Logging\LoggerUtilFactoryInterface;
26
use Stu\Module\Logging\LoggerUtilInterface;
27
use Stu\Module\ShipModule\ModuleSpecialAbilityEnum;
28
use Stu\Orm\Entity\BuildplanModuleInterface;
29
use Stu\Orm\Entity\ColonyInterface;
30
use Stu\Orm\Entity\ConstructionProgressInterface;
31
use Stu\Orm\Entity\ModuleInterface;
32
use Stu\Orm\Entity\ShipBuildplanInterface;
33
use Stu\Orm\Entity\ShipInterface;
34
use Stu\Orm\Repository\BuildplanModuleRepositoryInterface;
35
use Stu\Orm\Repository\ModuleSpecialRepositoryInterface;
36
use Stu\Orm\Repository\ShipBuildplanRepositoryInterface;
37
use Stu\Orm\Repository\ShipRepositoryInterface;
38
use Stu\Orm\Repository\ShipRumpRepositoryInterface;
39
use Stu\Orm\Repository\ShipSystemRepositoryInterface;
40
use Stu\Orm\Repository\StarSystemMapRepositoryInterface;
41
use Stu\Orm\Repository\UserRepositoryInterface;
42
43
final class ShipCreator implements ShipCreatorInterface
44
{
45
    private BuildplanModuleRepositoryInterface $buildplanModuleRepository;
46
47
    private ShipSystemRepositoryInterface $shipSystemRepository;
48
49
    private ShipRepositoryInterface $shipRepository;
50
51
    private UserRepositoryInterface $userRepository;
52
53
    private ShipRumpRepositoryInterface $shipRumpRepository;
54
55
    private ShipBuildplanRepositoryInterface $shipBuildplanRepository;
56
57
    private ModuleSpecialRepositoryInterface $moduleSpecialRepository;
58
59
    private StarSystemMapRepositoryInterface $starSystemMapRepository;
60
61
    private ShipWrapperFactoryInterface $shipWrapperFactory;
62
63
    private LoggerUtilInterface $loggerUtil;
64
65
    public function __construct(
66
        BuildplanModuleRepositoryInterface $buildplanModuleRepository,
67
        ShipSystemRepositoryInterface $shipSystemRepository,
68
        ShipRepositoryInterface $shipRepository,
69
        UserRepositoryInterface $userRepository,
70
        ShipRumpRepositoryInterface $shipRumpRepository,
71
        ShipBuildplanRepositoryInterface $shipBuildplanRepository,
72
        ModuleSpecialRepositoryInterface $moduleSpecialRepository,
73
        StarSystemMapRepositoryInterface $starSystemMapRepository,
74
        ShipWrapperFactoryInterface $shipWrapperFactory,
75
        LoggerUtilFactoryInterface $loggerUtilFactory
76
    ) {
77
        $this->buildplanModuleRepository = $buildplanModuleRepository;
78
        $this->shipSystemRepository = $shipSystemRepository;
79
        $this->shipRepository = $shipRepository;
80
        $this->userRepository = $userRepository;
81
        $this->shipRumpRepository = $shipRumpRepository;
82
        $this->shipBuildplanRepository = $shipBuildplanRepository;
83
        $this->moduleSpecialRepository = $moduleSpecialRepository;
84
        $this->starSystemMapRepository = $starSystemMapRepository;
85
        $this->shipWrapperFactory = $shipWrapperFactory;
86
        $this->loggerUtil = $loggerUtilFactory->getLoggerUtil();
87
    }
88
89
    public function createBy(
90
        int $userId,
91
        int $shipRumpId,
92
        int $shipBuildplanId,
93
        ?ColonyInterface $colony = null,
94
        ?ConstructionProgressInterface $progress = null
95
    ): ShipWrapperInterface {
96
        $user = $this->userRepository->find($userId);
97
        if ($user === null) {
98
            throw new RuntimeException('user not existent');
99
        }
100
101
        $rump = $this->shipRumpRepository->find($shipRumpId);
102
        if ($rump === null) {
103
            throw new RuntimeException('rump not existent');
104
        }
105
106
        $buildplan = $this->shipBuildplanRepository->find($shipBuildplanId);
107
        if ($buildplan === null) {
108
            throw new RuntimeException('buildplan not existent');
109
        }
110
111
        $ship = $progress !== null ? $progress->getShip() : $this->shipRepository->prototype();
112
        $ship->setUser($user);
113
        $ship->setBuildplan($buildplan);
114
        $ship->setRump($rump);
115
        $ship->setState(ShipStateEnum::SHIP_STATE_NONE);
116
117
        //create ship systems
118
        $this->createShipSystemsByModuleList(
119
            $ship,
120
            $this->buildplanModuleRepository->getByBuildplan(
121
                $buildplan->getId()
122
            ),
123
            $progress
124
        );
125
126
        $moduleTypeList = [
127
            ShipModuleTypeEnum::MODULE_TYPE_HULL => fn (ShipBuildplanInterface $buildplan, ShipWrapperInterface $wrapper): ModuleRumpWrapperInterface => new ModuleRumpWrapperHull($wrapper, $buildplan->getModulesByType(ShipModuleTypeEnum::MODULE_TYPE_HULL)),
128
            ShipModuleTypeEnum::MODULE_TYPE_SHIELDS => fn (ShipBuildplanInterface $buildplan, ShipWrapperInterface $wrapper): ModuleRumpWrapperInterface => new ModuleRumpWrapperShield($wrapper, $buildplan->getModulesByType(ShipModuleTypeEnum::MODULE_TYPE_SHIELDS)),
129
            ShipModuleTypeEnum::MODULE_TYPE_EPS => fn (ShipBuildplanInterface $buildplan, ShipWrapperInterface $wrapper): ModuleRumpWrapperInterface => new ModuleRumpWrapperEps($wrapper, $buildplan->getModulesByType(ShipModuleTypeEnum::MODULE_TYPE_EPS)),
130
            ShipModuleTypeEnum::MODULE_TYPE_IMPULSEDRIVE => fn (ShipBuildplanInterface $buildplan, ShipWrapperInterface $wrapper): ModuleRumpWrapperInterface => new ModuleRumpWrapperImpulseDrive($wrapper, $buildplan->getModulesByType(ShipModuleTypeEnum::MODULE_TYPE_IMPULSEDRIVE)),
131
            ShipModuleTypeEnum::MODULE_TYPE_REACTOR => fn (ShipBuildplanInterface $buildplan, ShipWrapperInterface $wrapper): ModuleRumpWrapperInterface => new ModuleRumpWrapperReactor($wrapper, $buildplan->getModulesByType(ShipModuleTypeEnum::MODULE_TYPE_REACTOR)),
132
            ShipModuleTypeEnum::MODULE_TYPE_COMPUTER => fn (ShipBuildplanInterface $buildplan, ShipWrapperInterface $wrapper): ModuleRumpWrapperInterface => new ModuleRumpWrapperComputer($wrapper, $buildplan->getModulesByType(ShipModuleTypeEnum::MODULE_TYPE_COMPUTER)),
133
            ShipModuleTypeEnum::MODULE_TYPE_PHASER => fn (ShipBuildplanInterface $buildplan, ShipWrapperInterface $wrapper): ModuleRumpWrapperInterface => new ModuleRumpWrapperEnergyWeapon($wrapper, $buildplan->getModulesByType(ShipModuleTypeEnum::MODULE_TYPE_PHASER)),
134
            ShipModuleTypeEnum::MODULE_TYPE_TORPEDO => fn (ShipBuildplanInterface $buildplan, ShipWrapperInterface $wrapper): ModuleRumpWrapperInterface => new ModuleRumpWrapperProjectileWeapon($wrapper, $buildplan->getModulesByType(ShipModuleTypeEnum::MODULE_TYPE_TORPEDO)),
135
            ShipModuleTypeEnum::MODULE_TYPE_SENSOR => fn (ShipBuildplanInterface $buildplan, ShipWrapperInterface $wrapper): ModuleRumpWrapperInterface => new ModuleRumpWrapperSensor($wrapper, $buildplan->getModulesByType(ShipModuleTypeEnum::MODULE_TYPE_SENSOR)),
136
            ShipModuleTypeEnum::MODULE_TYPE_WARPDRIVE => fn (ShipBuildplanInterface $buildplan, ShipWrapperInterface $wrapper): ModuleRumpWrapperInterface => new ModuleRumpWrapperWarpDrive($wrapper, $buildplan->getModulesByType(ShipModuleTypeEnum::MODULE_TYPE_WARPDRIVE)),
137
            ShipModuleTypeEnum::MODULE_TYPE_SPECIAL => function (ShipBuildplanInterface $buildplan, ShipWrapperInterface $wrapper): ModuleRumpWrapperInterface {
138
                $specialMods = $buildplan->getModulesByType(ShipModuleTypeEnum::MODULE_TYPE_SPECIAL);
139
                return new ModuleRumpWrapperSpecial($wrapper, $specialMods);
140
            },
141
        ];
142
143
        $wrapper = $this->shipWrapperFactory->wrapShip($ship);
144
145
        foreach ($moduleTypeList as $moduleTypeId => $wrapperCallable) {
146
            if ($this->loggerUtil->doLog()) {
147
                $this->loggerUtil->log(sprintf("moduleTypeId: %d", $moduleTypeId));
148
            }
149
            $buildplanModules = $buildplan->getModulesByType($moduleTypeId);
150
            if ($buildplanModules !== []) {
151
                if ($this->loggerUtil->doLog()) {
152
                    $this->loggerUtil->log("wrapperCallable!");
153
                }
154
                $moduleRumpWrapper = $wrapperCallable($buildplan, $wrapper);
155
                $moduleRumpWrapper->apply($ship);
156
            }
157
        }
158
159
        if ($ship->getName() == '' || $ship->getName() === sprintf('%s in Bau', $ship->getRump()->getName())) {
160
            $ship->setName($ship->getRump()->getName());
161
        }
162
        $ship->setSensorRange($ship->getRump()->getBaseSensorRange());
163
164
        $ship->setAlertStateGreen();
165
166
        $this->shipRepository->save($ship);
167
        if ($colony !== null) {
168
            $starsystemMap = $this->starSystemMapRepository->getByCoordinates($colony->getSystem()->getId(), $colony->getSx(), $colony->getSy());
169
170
            $ship->setCx($colony->getSystem()->getCx());
171
            $ship->setCy($colony->getSystem()->getCy());
172
            $ship->setStarsystemMap($starsystemMap);
173
            $this->shipRepository->save($ship);
174
        }
175
176
        return $wrapper;
177
    }
178
179
    /**
180
     * @param array<BuildplanModuleInterface> $modules
181
     */
182
    private function createShipSystemsByModuleList(
183
        ShipInterface $ship,
184
        array $modules,
185
        ?ConstructionProgressInterface $progress
186
    ): void {
187
        $systems = [];
188
189
        //default systems, that almost every ship should have
190
        if ($ship->getRump()->getCategoryId() !== ShipRumpEnum::SHIP_CATEGORY_SHUTTLE) {
191
            $systems[ShipSystemTypeEnum::SYSTEM_DEFLECTOR] = 0;
192
            $systems[ShipSystemTypeEnum::SYSTEM_TRACTOR_BEAM] = 0;
193
        }
194
        $systems[ShipSystemTypeEnum::SYSTEM_LIFE_SUPPORT] = 0;
195
        //TODO transporter
196
197
        if ($ship->getRump()->getCategoryId() === ShipRumpEnum::SHIP_CATEGORY_STATION) {
198
            $systems[ShipSystemTypeEnum::SYSTEM_BEAM_BLOCKER] = 0;
199
        }
200
201
        if ($ship->getRump()->isShipyard()) {
202
            $systems[ShipSystemTypeEnum::SYSTEM_CONSTRUCTION_HUB] = 0;
203
        }
204
205
        if ($ship->getRump()->getRoleId() === ShipRumpEnum::SHIP_ROLE_SENSOR) {
206
            $systems[ShipSystemTypeEnum::SYSTEM_UPLINK] = 0;
207
        }
208
209
        foreach ($modules as $buildplanmodule) {
210
            $module = $buildplanmodule->getModule();
211
212
            $systemType = $module->getSystemType();
213
            if (
214
                $systemType === null
215
                && array_key_exists($module->getType(), ShipModuleTypeEnum::MODULE_TYPE_TO_SYSTEM_TYPE)
216
            ) {
217
                $systemType = ShipModuleTypeEnum::MODULE_TYPE_TO_SYSTEM_TYPE[$module->getType()];
218
            }
219
220
            if ($systemType !== null) {
221
                $systems[$systemType] = $module;
222
            }
223
224
            switch ($module->getType()) {
225
                case ShipModuleTypeEnum::MODULE_TYPE_SENSOR:
226
                    $systems[ShipSystemTypeEnum::SYSTEM_NBS] = 0;
227
                    break;
228
                case ShipModuleTypeEnum::MODULE_TYPE_SPECIAL:
229
                    $this->addSpecialSystems($module, $systems);
230
                    break;
231
            }
232
        }
233
        if ($progress !== null) {
234
            foreach ($progress->getSpecialModules() as $mod) {
235
                $this->addSpecialSystems($mod->getModule(), $systems);
236
            }
237
        }
238
        foreach ($systems as $systemType => $module) {
239
            $obj = $this->shipSystemRepository->prototype();
240
            $obj->setShip($ship);
241
            $ship->getSystems()->set($systemType, $obj);
242
            $obj->setSystemType($systemType);
243
            if ($module !== 0) {
244
                $obj->setModule($module);
245
            }
246
            $obj->setStatus(100);
247
            $obj->setMode(ShipSystemModeEnum::MODE_OFF);
248
249
            $this->shipSystemRepository->save($obj);
250
        }
251
    }
252
253
    /**
254
     * @param array<int, ModuleInterface> $systems
255
     */
256
    private function addSpecialSystems(ModuleInterface $module, &$systems): void
257
    {
258
        $moduleSpecials = $this->moduleSpecialRepository->getByModule($module->getId());
259
260
        foreach ($moduleSpecials as $special) {
261
            switch ($special->getSpecialId()) {
262
                case ModuleSpecialAbilityEnum::MODULE_SPECIAL_CLOAK:
263
                    $systems[ShipSystemTypeEnum::SYSTEM_CLOAK] = $module;
264
                    break;
265
                case ModuleSpecialAbilityEnum::MODULE_SPECIAL_TACHYON_SCANNER:
266
                    $systems[ShipSystemTypeEnum::SYSTEM_TACHYON_SCANNER] = $module;
267
                    break;
268
                case ModuleSpecialAbilityEnum::MODULE_SPECIAL_TROOP_QUARTERS:
269
                    $systems[ShipSystemTypeEnum::SYSTEM_TROOP_QUARTERS] = $module;
270
                    break;
271
                case ModuleSpecialAbilityEnum::MODULE_SPECIAL_ASTRO_LABORATORY:
272
                    $systems[ShipSystemTypeEnum::SYSTEM_ASTRO_LABORATORY] = $module;
273
                    break;
274
                case ModuleSpecialAbilityEnum::MODULE_SPECIAL_SUBSPACE_FIELD_SENSOR:
275
                    $systems[ShipSystemTypeEnum::SYSTEM_SUBSPACE_SCANNER] = $module;
276
                    break;
277
                case ModuleSpecialAbilityEnum::MODULE_SPECIAL_MATRIX_SENSOR:
278
                    $systems[ShipSystemTypeEnum::SYSTEM_MATRIX_SCANNER] = $module;
279
                    break;
280
                case ModuleSpecialAbilityEnum::MODULE_SPECIAL_TORPEDO_STORAGE:
281
                    $systems[ShipSystemTypeEnum::SYSTEM_TORPEDO_STORAGE] = $module;
282
                    break;
283
                case ModuleSpecialAbilityEnum::MODULE_SPECIAL_SHUTTLE_RAMP:
284
                    $systems[ShipSystemTypeEnum::SYSTEM_SHUTTLE_RAMP] = $module;
285
                    break;
286
                case ModuleSpecialAbilityEnum::MODULE_SPECIAL_TRANSWARP_COIL:
287
                    $systems[ShipSystemTypeEnum::SYSTEM_TRANSWARP_COIL] = $module;
288
                    break;
289
                case ModuleSpecialAbilityEnum::MODULE_SPECIAL_HIROGEN_TRACKER:
290
                    $systems[ShipSystemTypeEnum::SYSTEM_TRACKER] = $module;
291
                    break;
292
                case ModuleSpecialAbilityEnum::MODULE_SPECIAL_THOLIAN_WEB:
293
                    $systems[ShipSystemTypeEnum::SYSTEM_THOLIAN_WEB] = $module;
294
                    break;
295
                case ModuleSpecialAbilityEnum::MODULE_SPECIAL_RPG:
296
                    $systems[ShipSystemTypeEnum::SYSTEM_RPG_MODULE] = 0;
297
                    break;
298
            }
299
        }
300
    }
301
}
302