Scrutinizer GitHub App not installed

We could not synchronize checks via GitHub's checks API since Scrutinizer's GitHub App is not installed for this repository.

Install GitHub App

Failed Conditions
Pull Request — main (#1494)
by Dan
08:06 queued 03:15
created

EditGalaxiesProcessor   A

Complexity

Total Complexity 39

Size/Duplication

Total Lines 208
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 109
dl 0
loc 208
rs 9.28
c 1
b 0
f 0
wmc 39

2 Methods

Rating   Name   Duplication   Size   Complexity  
F build() 0 201 38
A __construct() 0 4 1
1
<?php declare(strict_types=1);
2
3
namespace Smr\Pages\Admin\UniGen;
4
5
use Smr\Database;
6
use Smr\Page\AccountPageProcessor;
7
use Smr\Request;
8
use SmrAccount;
9
use SmrGalaxy;
10
use SmrGame;
11
use SmrLocation;
12
use SmrPlanet;
13
use SmrPort;
14
use SmrSector;
15
16
class EditGalaxiesProcessor extends AccountPageProcessor {
17
18
	public function __construct(
19
		private readonly int $gameID,
20
		private readonly int $galaxyID
21
	) {}
22
23
	public function build(SmrAccount $account): never {
24
		$db = Database::getInstance();
25
26
		$gameID = $this->gameID;
27
		$game = SmrGame::getGame($gameID);
28
		$galaxies = $game->getGalaxies();
29
30
		// Save the original sizes for later processing
31
		$origGals = [];
32
		foreach ($galaxies as $i => $galaxy) {
33
			$origGals[$i] = [
34
				'Width' => $galaxy->getWidth(),
35
				'Height' => $galaxy->getHeight(),
36
			];
37
		}
38
39
		// Modify the galaxy properties
40
		foreach ($galaxies as $i => $galaxy) {
41
			$galaxy->setName(Request::get('gal' . $i));
42
			$galaxy->setGalaxyType(Request::get('type' . $i));
43
			$galaxy->setMaxForceTime(IFloor(Request::getFloat('forces' . $i) * 3600));
0 ignored issues
show
Bug introduced by
The function IFloor was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

43
			$galaxy->setMaxForceTime(/** @scrutinizer ignore-call */ IFloor(Request::getFloat('forces' . $i) * 3600));
Loading history...
44
			if (!$game->isEnabled()) {
45
				$galaxy->setWidth(Request::getInt('width' . $i));
46
				$galaxy->setHeight(Request::getInt('height' . $i));
47
			}
48
		}
49
50
		// Early return if no galaxy dimensions are modified
51
		$galaxySizesUnchanged = true;
52
		foreach ($galaxies as $i => $galaxy) {
53
			if ($galaxy->getWidth() != $origGals[$i]['Width'] || $galaxy->getHeight() != $origGals[$i]['Height']) {
54
				$galaxySizesUnchanged = false;
55
				break;
56
			}
57
		}
58
		if ($galaxySizesUnchanged) {
59
			SmrGalaxy::saveGalaxies();
60
			$message = '<span class="green">SUCCESS: </span>Edited galaxies (sizes unchanged).';
61
			$container = new EditGalaxy($this->gameID, $this->galaxyID, $message);
62
			$container->go();
63
		}
64
65
		// *** BEGIN GALAXY DIMENSION MODIFICATION! ***
66
		// Warning: This changes primary keys for several tables, which needs to be
67
		// done carefully. It also interacts with the caches in unexpected ways.
68
		// *** BEGIN GALAXY DIMENSION MODIFICATION! ***
69
70
		// Efficiently construct the caches before proceeding
71
		// NOTE: these will be associated with the old sector IDs, so the caches
72
		// will need to be cleared afterwards.
73
		foreach ($galaxies as $galaxy) {
74
			$galaxy->getSectors();
75
			$galaxy->getPorts();
76
			$galaxy->getLocations();
77
			$galaxy->getPlanets();
78
		}
79
80
		// Determine the mapping from old to new sector IDs
81
		$newID = 0;
82
		$oldID = 0;
83
		$sectorMap = [];
84
		foreach ($galaxies as $i => $galaxy) {
85
			$maxRows = max($galaxy->getHeight(), $origGals[$i]['Height']);
86
			$maxCols = max($galaxy->getWidth(), $origGals[$i]['Width']);
87
			for ($row = 0; $row < $maxRows; $row++) {
88
				for ($col = 0; $col < $maxCols; $col++) {
89
					$oldExists = ($row < $origGals[$i]['Height'] && $col < $origGals[$i]['Width']);
90
					$newExists = ($row < $galaxy->getHeight() && $col < $galaxy->getWidth());
91
92
					if ($oldExists && $newExists) {
93
						$oldID++;
94
						$newID++;
95
						$sectorMap[$newID] = $oldID;
96
					} elseif ($newExists) {
97
						$newID++;
98
						$sectorMap[$newID] = false;
99
					} elseif ($oldExists) {
100
						$oldID++;
101
						// Remove this sector and everything in it
102
						$delSector = SmrSector::getSector($gameID, $oldID);
103
						$delSector->removeAllFixtures();
104
						$db->write('DELETE FROM sector WHERE ' . $delSector->getSQL());
105
					}
106
				}
107
			}
108
		}
109
110
		// Save remaining old warps to re-add later, then clear all warp data.
111
		// This is necessary because we will be manually modifying sector IDs.
112
		$oldWarps = [];
113
		foreach ($galaxies as $galaxy) {
114
			foreach ($galaxy->getSectors() as $galSector) {
115
				if ($galSector->hasWarp()) {
116
					$oldWarps[$galSector->getSectorID()] = $galSector->getWarp();
117
				}
118
			}
119
		}
120
		$db->write('UPDATE sector SET warp = 0 WHERE game_id = ' . $db->escapeNumber($gameID));
121
122
		// Many sectors will have their IDs shifted up or down, so we need to modify
123
		// the primary keys for the sector table as well as planets, ports, etc.
124
		// We have to do this in a loop to ensure that the new sector ID will not
125
		// collide with an old sector ID that hasn't been shifted yet (because we
126
		// may be both adding and removing sectors).
127
		//
128
		// NOTE: We have already accounted for collisions from removing sectors by
129
		// deleting all fixtures from sectors that will no longer exist.
130
		$needsUpdate = $sectorMap;
131
		while ($needsUpdate) {
132
			foreach ($needsUpdate as $newID => $oldID) {
133
				// If sector is new or has the same ID, then no shifting is necessary
134
				if ($oldID === false || $oldID == $newID) {
135
					unset($needsUpdate[$newID]);
136
					continue;
137
				}
138
139
				// If the oldID still exists, then we have to defer shifting until
140
				// this destination has been vacated.
141
				if (array_search($newID, $needsUpdate)) {
142
					continue;
143
				}
144
145
				// Else we are ready to shift from oldID to newID
146
				$oldSector = SmrSector::getSector($gameID, $oldID);
147
				$SQL = 'SET sector_id = ' . $db->escapeNumber($newID) . ' WHERE ' . $oldSector->getSQL();
148
149
				if ($oldSector->hasPlanet()) {
150
					$db->write('UPDATE planet ' . $SQL);
151
					$db->write('UPDATE planet_has_building ' . $SQL);
152
					$db->write('UPDATE planet_has_cargo ' . $SQL);
153
					$db->write('UPDATE planet_has_weapon ' . $SQL);
154
				}
155
156
				if ($oldSector->hasPort()) {
157
					$db->write('UPDATE port ' . $SQL);
158
					$db->write('UPDATE port_has_goods ' . $SQL);
159
				}
160
161
				if ($oldSector->hasLocation()) {
162
					$db->write('UPDATE location ' . $SQL);
163
				}
164
165
				$db->write('UPDATE sector ' . $SQL);
166
				unset($needsUpdate[$newID]);
167
			}
168
		}
169
170
		// Clear all the caches, since they are associated with the old IDs.
171
		// NOTE: We can't re-initialize the cache here because the sectors
172
		// still have the wrong galaxy ID at this point.
173
		SmrSector::clearCache();
174
		SmrPort::clearCache();
175
		SmrPlanet::clearCache();
176
		SmrLocation::clearCache();
177
178
		// Create any new sectors that need to be made
179
		foreach ($sectorMap as $newID => $oldID) {
180
			if ($oldID === false) {
181
				SmrSector::createSector($gameID, $newID);
182
			}
183
		}
184
185
		// Finally, modify sector properties (galaxy ID, links, and warps)
186
		foreach ($sectorMap as $newID => $oldID) {
187
			$newSector = SmrSector::getSector($gameID, $newID);
188
189
			// Update the galaxy ID
190
			// NOTE: this must be done before SmrGalaxy::getSectors is called
191
			foreach ($galaxies as $galaxy) {
192
				if ($galaxy->contains($newID)) {
193
					$newSector->setGalaxyID($galaxy->getGalaxyID());
194
				}
195
			}
196
197
			// Update the sector connections
198
			foreach (['Up', 'Down', 'Left', 'Right'] as $dir) {
199
				if ($oldID === false) {
200
					// No sector walls for newly added sectors
201
					$newSector->enableLink($dir);
202
				} else {
203
					// Toggle links twice to reset them (since this internally handles
204
					// the calculation of the neighboring sector IDs).
205
					$newSector->toggleLink($dir);
206
					$newSector->toggleLink($dir);
207
				}
208
			}
209
210
			// Update the warp
211
			if ($oldID !== false && isset($oldWarps[$oldID])) {
212
				$oldWarpID = $oldWarps[$oldID];
213
				$newWarpID = array_search($oldWarpID, $sectorMap);
214
				$newSector->setWarp(SmrSector::getSector($gameID, $newWarpID));
0 ignored issues
show
Bug introduced by
It seems like $newWarpID can also be of type string; however, parameter $sectorID of SmrSector::getSector() 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

214
				$newSector->setWarp(SmrSector::getSector($gameID, /** @scrutinizer ignore-type */ $newWarpID));
Loading history...
215
			}
216
		}
217
218
		SmrGalaxy::saveGalaxies();
219
		SmrSector::saveSectors();
220
221
		$message = '<span class="green">SUCCESS: </span>Edited galaxies (sizes have changed).';
222
		$container = new EditGalaxy($this->gameID, $this->galaxyID, $message);
223
		$container->go();
224
	}
225
226
}
227