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 (#1487)
by Dan
06:01
created

SmrGame::isEnabled()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 2
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 1
dl 0
loc 2
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 0
1
<?php declare(strict_types=1);
2
3
use Smr\Database;
4
use Smr\Epoch;
5
use Smr\Exceptions\GameNotFound;
6
use Smr\Race;
7
8
class SmrGame {
9
10
	/** @var array<int, self> */
11
	protected static array $CACHE_GAMES = [];
12
13
	protected Database $db;
14
15
	protected string $name;
16
	protected string $description;
17
	protected int $joinTime;
18
	protected int $startTime;
19
	protected int $endTime;
20
	protected int $maxPlayers;
21
	protected int $maxTurns;
22
	protected int $startTurnHours;
23
	protected int $gameTypeID;
24
	protected int $creditsNeeded;
25
	protected float $gameSpeed;
26
	protected bool $enabled;
27
	protected bool $ignoreStats;
28
	protected int $allianceMaxPlayers;
29
	protected int $allianceMaxVets;
30
	protected int $startingCredits;
31
32
	protected int $totalPlayers;
33
	/** @var array<int> */
34
	protected array $playableRaceIDs;
35
36
	protected bool $hasChanged = false;
37
	protected bool $isNew = false;
38
39
	public const GAME_TYPE_DEFAULT = 0;
40
	public const GAME_TYPE_HUNTER_WARS = 3;
41
	public const GAME_TYPE_SEMI_WARS = 4;
42
	public const GAME_TYPE_DRAFT = 5;
43
	public const GAME_TYPE_FFA = 6;
44
	public const GAME_TYPE_NEWBIE = 7;
45
	public const GAME_TYPES = [
46
		self::GAME_TYPE_DEFAULT => 'Default',
47
		self::GAME_TYPE_HUNTER_WARS => 'Hunter Wars',
48
		self::GAME_TYPE_SEMI_WARS => 'Semi Wars',
49
		self::GAME_TYPE_DRAFT => 'Draft',
50
		self::GAME_TYPE_FFA => 'FFA',
51
		self::GAME_TYPE_NEWBIE => 'Newbie',
52
	];
53
54
	/**
55
	 * Attempts to construct the game to determine if it exists.
56
	 */
57
	public static function gameExists(int $gameID): bool {
58
		try {
59
			self::getGame($gameID);
60
			return true;
61
		} catch (GameNotFound) {
62
			return false;
63
		}
64
	}
65
66
	public static function getGame(int $gameID, bool $forceUpdate = false): self {
67
		if ($forceUpdate || !isset(self::$CACHE_GAMES[$gameID])) {
68
			self::$CACHE_GAMES[$gameID] = new self($gameID);
69
		}
70
		return self::$CACHE_GAMES[$gameID];
71
	}
72
73
	public static function clearCache(): void {
74
		self::$CACHE_GAMES = [];
75
	}
76
77
	public static function saveGames(): void {
78
		foreach (self::$CACHE_GAMES as $game) {
79
			$game->save();
80
		}
81
	}
82
83
	public static function createGame(int $gameID): self {
84
		if (!isset(self::$CACHE_GAMES[$gameID])) {
85
			self::$CACHE_GAMES[$gameID] = new self($gameID, true);
86
		}
87
		return self::$CACHE_GAMES[$gameID];
88
	}
89
90
	protected function __construct(
91
		protected readonly int $gameID,
92
		bool $create = false
93
	) {
94
		$this->db = Database::getInstance();
95
96
		$dbResult = $this->db->read('SELECT * FROM game WHERE game_id = ' . $this->db->escapeNumber($gameID));
97
		if ($dbResult->hasRecord()) {
98
			$dbRecord = $dbResult->record();
99
			$this->name = $dbRecord->getString('game_name');
100
			$this->description = $dbRecord->getString('game_description');
101
			$this->joinTime = $dbRecord->getInt('join_time');
102
			$this->startTime = $dbRecord->getInt('start_time');
103
			$this->endTime = $dbRecord->getInt('end_time');
104
			$this->maxPlayers = $dbRecord->getInt('max_players');
105
			$this->maxTurns = $dbRecord->getInt('max_turns');
106
			$this->startTurnHours = $dbRecord->getInt('start_turns');
107
			$this->gameTypeID = $dbRecord->getInt('game_type');
108
			$this->creditsNeeded = $dbRecord->getInt('credits_needed');
109
			$this->gameSpeed = $dbRecord->getFloat('game_speed');
110
			$this->enabled = $dbRecord->getBoolean('enabled');
111
			$this->ignoreStats = $dbRecord->getBoolean('ignore_stats');
112
			$this->allianceMaxPlayers = $dbRecord->getInt('alliance_max_players');
113
			$this->allianceMaxVets = $dbRecord->getInt('alliance_max_vets');
114
			$this->startingCredits = $dbRecord->getInt('starting_credits');
115
		} elseif ($create === true) {
116
			$this->isNew = true;
117
		} else {
118
			throw new GameNotFound('No such game: ' . $gameID);
119
		}
120
	}
121
122
	public function save(): void {
123
		if ($this->isNew) {
124
			$this->db->insert('game', [
125
				'game_id' => $this->db->escapeNumber($this->getGameID()),
126
				'game_name' => $this->db->escapeString($this->getName()),
127
				'game_description' => $this->db->escapeString($this->getDescription()),
128
				'join_time' => $this->db->escapeNumber($this->getJoinTime()),
129
				'start_time' => $this->db->escapeNumber($this->getStartTime()),
130
				'end_time' => $this->db->escapeNumber($this->getEndTime()),
131
				'max_players' => $this->db->escapeNumber($this->getMaxPlayers()),
132
				'max_turns' => $this->db->escapeNumber($this->getMaxTurns()),
133
				'start_turns' => $this->db->escapeNumber($this->getStartTurnHours()),
134
				'game_type' => $this->db->escapeNumber($this->gameTypeID),
135
				'credits_needed' => $this->db->escapeNumber($this->getCreditsNeeded()),
136
				'game_speed' => $this->db->escapeNumber($this->getGameSpeed()),
137
				'enabled' => $this->db->escapeBoolean($this->isEnabled()),
138
				'ignore_stats' => $this->db->escapeBoolean($this->isIgnoreStats()),
139
				'alliance_max_players' => $this->db->escapeNumber($this->getAllianceMaxPlayers()),
140
				'alliance_max_vets' => $this->db->escapeNumber($this->getAllianceMaxVets()),
141
				'starting_credits' => $this->db->escapeNumber($this->getStartingCredits()),
142
			]);
143
		} elseif ($this->hasChanged) {
144
			$this->db->write('UPDATE game SET game_name = ' . $this->db->escapeString($this->getName()) .
145
										', game_description = ' . $this->db->escapeString($this->getDescription()) .
146
										', join_time = ' . $this->db->escapeNumber($this->getJoinTime()) .
147
										', start_time = ' . $this->db->escapeNumber($this->getStartTime()) .
148
										', end_time = ' . $this->db->escapeNumber($this->getEndTime()) .
149
										', max_players = ' . $this->db->escapeNumber($this->getMaxPlayers()) .
150
										', max_turns = ' . $this->db->escapeNumber($this->getMaxTurns()) .
151
										', start_turns = ' . $this->db->escapeNumber($this->getStartTurnHours()) .
152
										', game_type = ' . $this->db->escapeNumber($this->gameTypeID) .
153
										', credits_needed = ' . $this->db->escapeNumber($this->getCreditsNeeded()) .
154
										', game_speed = ' . $this->db->escapeNumber($this->getGameSpeed()) .
155
										', enabled = ' . $this->db->escapeBoolean($this->isEnabled()) .
156
										', ignore_stats = ' . $this->db->escapeBoolean($this->isIgnoreStats()) .
157
										', alliance_max_players = ' . $this->db->escapeNumber($this->getAllianceMaxPlayers()) .
158
										', alliance_max_vets = ' . $this->db->escapeNumber($this->getAllianceMaxVets()) .
159
										', starting_credits = ' . $this->db->escapeNumber($this->getStartingCredits()) .
160
									' WHERE game_id = ' . $this->db->escapeNumber($this->getGameID()));
161
		}
162
		$this->isNew = false;
163
		$this->hasChanged = false;
164
	}
165
166
	public function getGameID(): int {
167
		return $this->gameID;
168
	}
169
170
	public function getName(): string {
171
		return $this->name;
172
	}
173
174
	public function setName(string $name): void {
175
		if (!$this->isNew && $this->name === $name) {
176
			return;
177
		}
178
		$this->name = $name;
179
		$this->hasChanged = true;
180
	}
181
182
	public function getDescription(): string {
183
		return $this->description;
184
	}
185
186
	public function setDescription(string $description): void {
187
		if (!$this->isNew && $this->description === $description) {
188
			return;
189
		}
190
		$this->description = $description;
191
		$this->hasChanged = true;
192
	}
193
194
	public function hasStarted(): bool {
195
		return Epoch::time() >= $this->getStartTime();
196
	}
197
198
	/**
199
	 * Returns the epoch time when the game starts,
200
	 * i.e. when players can move, turns are gained, etc.
201
	 */
202
	public function getStartTime(): int {
203
		return $this->startTime;
204
	}
205
206
	public function setStartTime(int $startTime): void {
207
		if (!$this->isNew && $this->startTime === $startTime) {
208
			return;
209
		}
210
		$this->startTime = $startTime;
211
		$this->hasChanged = true;
212
	}
213
214
	/**
215
	 * Returns the epoch time when players can begin to join the game.
216
	 */
217
	public function getJoinTime(): int {
218
		return $this->joinTime;
219
	}
220
221
	public function setJoinTime(int $joinTime): void {
222
		if (!$this->isNew && $this->joinTime === $joinTime) {
223
			return;
224
		}
225
		$this->joinTime = $joinTime;
226
		$this->hasChanged = true;
227
	}
228
229
	public function hasEnded(): bool {
230
		return $this->getEndTime() < Epoch::time();
231
	}
232
233
	/**
234
	 * Returns the epoch time when the game ends.
235
	 */
236
	public function getEndTime(): int {
237
		return $this->endTime;
238
	}
239
240
	public function setEndTime(int $endTime): void {
241
		if (!$this->isNew && $this->endTime === $endTime) {
242
			return;
243
		}
244
		$this->endTime = $endTime;
245
		$this->hasChanged = true;
246
	}
247
248
	public function getMaxPlayers(): int {
249
		return $this->maxPlayers;
250
	}
251
252
	public function setMaxPlayers(int $maxPlayers): void {
253
		if (!$this->isNew && $this->maxPlayers === $maxPlayers) {
254
			return;
255
		}
256
		$this->maxPlayers = $maxPlayers;
257
		$this->hasChanged = true;
258
	}
259
260
	public function getMaxTurns(): int {
261
		return $this->maxTurns;
262
	}
263
264
	public function setMaxTurns(int $int): void {
265
		if (!$this->isNew && $this->maxTurns === $int) {
266
			return;
267
		}
268
		$this->maxTurns = $int;
269
		$this->hasChanged = true;
270
	}
271
272
	public function getStartTurnHours(): int {
273
		return $this->startTurnHours;
274
	}
275
276
	public function setStartTurnHours(int $int): void {
277
		if (!$this->isNew && $this->startTurnHours === $int) {
278
			return;
279
		}
280
		$this->startTurnHours = $int;
281
		$this->hasChanged = true;
282
	}
283
284
	public function isGameType(int $gameTypeID): bool {
285
		return $this->gameTypeID === $gameTypeID;
286
	}
287
288
	public function getGameType(): string {
289
		return self::GAME_TYPES[$this->gameTypeID];
290
	}
291
292
	public function setGameTypeID(int $gameTypeID): void {
293
		if (!$this->isNew && $this->gameTypeID === $gameTypeID) {
294
			return;
295
		}
296
		$this->gameTypeID = $gameTypeID;
297
		$this->hasChanged = true;
298
	}
299
300
	public function getCreditsNeeded(): int {
301
		return $this->creditsNeeded;
302
	}
303
304
	public function setCreditsNeeded(int $creditsNeeded): void {
305
		if (!$this->isNew && $this->creditsNeeded === $creditsNeeded) {
306
			return;
307
		}
308
		$this->creditsNeeded = $creditsNeeded;
309
		$this->hasChanged = true;
310
	}
311
312
	public function getGameSpeed(): float {
313
		return $this->gameSpeed;
314
	}
315
316
	public function setGameSpeed(float $gameSpeed): void {
317
		if (!$this->isNew && $this->gameSpeed === $gameSpeed) {
318
			return;
319
		}
320
		$this->gameSpeed = $gameSpeed;
321
		$this->hasChanged = true;
322
	}
323
324
	public function isEnabled(): bool {
325
		return $this->enabled;
326
	}
327
328
	public function setEnabled(bool $bool): void {
329
		if (!$this->isNew && $this->enabled === $bool) {
330
			return;
331
		}
332
		$this->enabled = $bool;
333
		$this->hasChanged = true;
334
	}
335
336
	public function isIgnoreStats(): bool {
337
		return $this->ignoreStats;
338
	}
339
340
	public function setIgnoreStats(bool $bool): void {
341
		if (!$this->isNew && $this->ignoreStats === $bool) {
342
			return;
343
		}
344
		$this->ignoreStats = $bool;
345
		$this->hasChanged = true;
346
	}
347
348
	public function getAllianceMaxPlayers(): int {
349
		return $this->allianceMaxPlayers;
350
	}
351
352
	public function setAllianceMaxPlayers(int $int): void {
353
		if (!$this->isNew && $this->allianceMaxPlayers === $int) {
354
			return;
355
		}
356
		$this->allianceMaxPlayers = $int;
357
		$this->hasChanged = true;
358
	}
359
360
	public function getAllianceMaxVets(): int {
361
		return $this->allianceMaxVets;
362
	}
363
364
	public function setAllianceMaxVets(int $int): void {
365
		if (!$this->isNew && $this->allianceMaxVets === $int) {
366
			return;
367
		}
368
		$this->allianceMaxVets = $int;
369
		$this->hasChanged = true;
370
	}
371
372
	public function getStartingCredits(): int {
373
		return $this->startingCredits;
374
	}
375
376
	public function setStartingCredits(int $int): void {
377
		if (!$this->isNew && $this->startingCredits === $int) {
378
			return;
379
		}
380
		$this->startingCredits = $int;
381
		$this->hasChanged = true;
382
	}
383
384
	public function getTotalPlayers(): int {
385
		if (!isset($this->totalPlayers)) {
386
			$dbResult = $this->db->read('SELECT count(*) FROM player WHERE game_id = ' . $this->db->escapeNumber($this->getGameID()));
387
			$this->totalPlayers = $dbResult->record()->getInt('count(*)');
388
		}
389
		return $this->totalPlayers;
390
	}
391
392
	/**
393
	 * @return array<int, \SmrGalaxy>
394
	 */
395
	public function getGalaxies(): array {
396
		return SmrGalaxy::getGameGalaxies($this->gameID);
397
	}
398
399
	public function getNumberOfGalaxies(): int {
400
		return count($this->getGalaxies());
401
	}
402
403
	public function equals(self $otherGame): bool {
404
		return $otherGame->getGameID() == $this->getGameID();
405
	}
406
407
	// Convenience function for printing the game name with id
408
	public function getDisplayName(): string {
409
		return $this->getName() . ' (' . $this->getGameID() . ')';
410
	}
411
412
	/**
413
	 * Set the starting political relations between races.
414
	 */
415
	public function setStartingRelations(int $relations): void {
416
		if ($relations < MIN_GLOBAL_RELATIONS || $relations > MAX_GLOBAL_RELATIONS) {
417
			throw new Exception('Invalid relations: ' . $relations);
418
		}
419
		foreach (Race::getAllIDs() as $raceID1) {
420
			foreach (Race::getAllIDs() as $raceID2) {
421
				if ($raceID1 == $raceID2) {
422
					// Max relations for a race with itself
423
					$amount = MAX_GLOBAL_RELATIONS;
424
				} elseif ($raceID1 == RACE_NEUTRAL || $raceID2 == RACE_NEUTRAL) {
425
					$amount = 0; //0 relations with neutral
426
				} else {
427
					$amount = $relations;
428
				}
429
				$this->db->replace('race_has_relation', [
430
					'game_id' => $this->db->escapeNumber($this->getGameID()),
431
					'race_id_1' => $this->db->escapeNumber($raceID1),
432
					'race_id_2' => $this->db->escapeNumber($raceID2),
433
					'relation' => $this->db->escapeNumber($amount),
434
				]);
435
			}
436
		}
437
	}
438
439
	/**
440
	 * Get the list of playable Race IDs based on which Racial HQ's
441
	 * are locations in this game.
442
	 *
443
	 * @return array<int>
444
	 */
445
	public function getPlayableRaceIDs(): array {
446
		if (!isset($this->playableRaceIDs)) {
447
			// Get a unique set of HQ's available in game
448
			$dbResult = $this->db->read('SELECT DISTINCT location_type_id
449
				FROM location
450
				WHERE location_type_id > ' . $this->db->escapeNumber(UNDERGROUND) . '
451
					AND location_type_id < ' . $this->db->escapeNumber(FED) . '
452
					AND game_id = ' . $this->db->escapeNumber($this->getGameID()) . '
453
				ORDER BY location_type_id');
454
			$this->playableRaceIDs = [];
455
			foreach ($dbResult->records() as $dbRecord) {
456
				$this->playableRaceIDs[] = $dbRecord->getInt('location_type_id') - GOVERNMENT;
457
			}
458
		}
459
		return $this->playableRaceIDs;
460
	}
461
462
	/**
463
	 * Returns the time (in seconds) until restricted ships are unlocked.
464
	 */
465
	public function timeUntilShipUnlock(): int {
466
		return $this->getStartTime() + TIME_FOR_RAIDER_UNLOCK - Epoch::time();
467
	}
468
469
}
470