Skip to content

Commit 8f14a34

Browse files
committed
Implement panic bunker logic
1 parent 4927645 commit 8f14a34

File tree

3 files changed

+77
-40
lines changed

3 files changed

+77
-40
lines changed

src/Civ13/Gameserver.php

Lines changed: 73 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@
3030
use Monolog\Logger;
3131
use React\EventLoop\StreamSelectLoop;
3232
use React\EventLoop\TimerInterface;
33-
use React\Promise\Promise;
3433
use React\Promise\PromiseInterface;
3534

3635
use function React\Promise\reject;
@@ -261,21 +260,7 @@ public function localServerPlayerCount(array $players = []): int
261260
$this->logger->warning("Unable to open `{$this->serverdata}`");
262261
return 0;
263262
}
264-
$data = explode(';', str_replace(['<b>Address</b>: ', '<b>Map</b>: ', '<b>Gamemode</b>: ', '<b>Players</b>: ', 'round_timer=', 'map=', 'epoch=', 'season=', 'ckey_list=', '</b>', '<b>'], '', $data));
265-
/*
266-
0 => <b>Server Status</b> {Online/Offline}
267-
1 => <b>Address</b> byond://{ip_address}
268-
2 => <b>Map</b>: {map}
269-
3 => <b>Gamemode</b>: {gamemode}
270-
4 => <b>Players</b>: {playercount}
271-
5 => realtime={realtime}
272-
6 => world.address={ip}
273-
7 => round_timer={00:00}
274-
8 => map={map}
275-
9 => epoch={epoch}
276-
10 => season={season}
277-
11 => ckey_list={ckey&ckey}
278-
*/
263+
$data = self::explodeServerdata($data);
279264
if (isset($data[11])) $players = array_filter(array_map(fn($player) => Civ13::sanitizeInput($player), array_filter(explode('&', $data[11]), fn($player) => $player)));
280265
if (isset($data[4])) $playercount = $data[4]; // Player count
281266
$this->players = $players;
@@ -481,7 +466,7 @@ public function createCurrentRoundEmbedMessageBuilder(): ?MessageBuilder
481466
if (! $round = $this->getRound($this->current_round)) return null;
482467
$round_embed_builder = function () use ($round): MessageBuilder
483468
{
484-
if (file_exists($this->serverdata) && $data = @file_get_contents($this->serverdata)) $data = explode(';', str_replace(['<b>Address</b>: ', '<b>Map</b>: ', '<b>Gamemode</b>: ', '<b>Players</b>: ', 'round_timer=', 'map=', 'epoch=', 'season=', 'ckey_list=', '</b>', '<b>'], '', $data));
469+
if (file_exists($this->serverdata) && $data = @file_get_contents($this->serverdata)) $data = explode(';', str_replace(['<b>Address</b>: ', '<b>Map</b>: ', '<b>Gamemode</b>: ', '<b>Players</b>: ', 'round_timer=', 'map=', 'epoch=', 'season=', 'ckey_list=', 'allow_vote_restart=', '</b>', '<b>'], '', $data));
485470
$embed = $this->civ13->createEmbed()
486471
->setTitle($this->name)
487472
//->addFieldValues('Game ID', $game_id);
@@ -937,6 +922,34 @@ public function merge_banlist(array $banlists): array
937922
: $banlists;
938923
}
939924

925+
public function panicCheck(string $ckey): void
926+
{
927+
if (! $ban_reason = $this->__panicCheck($ckey)) return;
928+
if (! isset($this->civ13->channel_ids['staff_bot']) || ! $channel = $this->discord->getChannel($this->civ13->channel_ids['staff_bot'])) return;
929+
$this->civ13->sendMessage($channel, $ban_reason);
930+
}
931+
private function __panicCheck(string $ckey): string|false
932+
{
933+
if (! $this->panic_bunker) return false;
934+
if (! isset($this->civ13->verifier)) return false;
935+
if ($this->civ13->verifier->getVerifiedItem($ckey)) return false; // Whether the ckey is verified
936+
if (! @file_exists($this->serverdata) || ! $data = @file_get_contents($this->serverdata)) {
937+
$this->logger->warning("Unable to open `{$this->serverdata}`");
938+
return false;
939+
}
940+
if (self::explodeServerdata($data)[12] ?? true) return false; // Whether restart vote is allowed
941+
if (! $guild = $this->discord->guilds->get('id', $this->civ13->civ13_guild_id)) return false;
942+
if (! $admins = $guild->members->filter(fn(Member $member) => $member->roles->has($this->civ13->role_ids['Admin']))) return false; // Get a list of admins from the Discord server
943+
if (array_reduce($admins->toArray(), function ($carry, $member) { // Check if any of the admins are online
944+
/** @var bool $carry */
945+
if ($carry) return $carry;
946+
/** @var Member $member */
947+
if (! $item = $this->civ13->verifier->get('discord', $member->id)) return $carry;
948+
return in_array($item['ss13'], $this->players);
949+
}, false)) return false;
950+
return $this->ban(['ckey' => $ckey, 'duration' => '999 years', 'reason' => "Byond account `$ckey` must register and be approved to play. Verify at {$this->civ13->discord_formatted}"]);
951+
}
952+
940953
/*
941954
* These functions determine which of the above methods should be used to process a ban or unban
942955
* Ban functions will return a string containing the results of the ban
@@ -1085,9 +1098,9 @@ public function logPlayerLogin(string $ckey, string $time, string $ip = '', stri
10851098
'Proxy' => isset($ip_data['proxy']) && $ip_data['proxy'],
10861099
'Hosting' => isset($ip_data['hosting']) && $ip_data['hosting'],
10871100
];
1088-
$banReason = array_reduce(array_keys($conditions), fn($carry, $key) => $carry ?: ($conditions[$key] ? $key : null), null);
1089-
if ($banReason && isset($this->civ13->channel_ids['staff_bot']) && $channel = $this->discord->getChannel($this->civ13->channel_ids['staff_bot'])) {
1090-
return $this->civ13->sendMessage($channel, $this->civ13->ban(['ckey' => $ckey, 'duration' => '999 years', 'reason' => "Account under investigation. Appeal at {$this->civ13->discord_formatted}"], null, null, true) . " ($banReason)");
1101+
$ban_reason = array_reduce(array_keys($conditions), fn($carry, $key) => $carry ?: ($conditions[$key] ? $key : null), null);
1102+
if ($ban_reason && isset($this->civ13->channel_ids['staff_bot']) && $channel = $this->discord->getChannel($this->civ13->channel_ids['staff_bot'])) {
1103+
return $this->civ13->sendMessage($channel, $this->civ13->ban(['ckey' => $ckey, 'duration' => '999 years', 'reason' => "Account under investigation. Appeal at {$this->civ13->discord_formatted}"], null, null, true) . " ($ban_reason)");
10911104
}
10921105
}
10931106
return resolve(null);
@@ -1396,21 +1409,7 @@ public function generateServerstatusEmbed(): ?Embed
13961409
$embed = $this->civ13->createEmbed();
13971410
if (! is_resource($socket = @fsockopen('localhost', intval($this->port), $errno, $errstr, 1))) return $embed->addFieldValues($this->name, 'Offline');
13981411
fclose($socket);
1399-
$data = explode(';', str_replace(['<b>Address</b>: ', '<b>Map</b>: ', '<b>Gamemode</b>: ', '<b>Players</b>: ', 'round_timer=', 'map=', 'epoch=', 'season=', 'ckey_list=', '</b>', '<b>'], '', $data));
1400-
/*
1401-
0 => <b>Server Status</b> {Online/Offline}
1402-
1 => <b>Address</b> byond://{ip_address}
1403-
2 => <b>Map</b>: {map}
1404-
3 => <b>Gamemode</b>: {gamemode}
1405-
4 => <b>Players</b>: {playercount}
1406-
5 => realtime={realtime}
1407-
6 => world.address={ip}
1408-
7 => round_timer={00:00}
1409-
8 => map={map}
1410-
9 => epoch={epoch}
1411-
10 => season={season}
1412-
11 => ckey_list={ckey&ckey}
1413-
*/
1412+
$data = self::explodeServerdata($data);
14141413
if (isset($data[1])) $embed->addFieldValues($this->name, '<'.$data[1].'>');
14151414
$embed->addFieldValues('Host', $this->host, true);
14161415
if (isset($data[7])) $embed->addFieldValues('Round Time', $this->parseRoundTime($data[7]), true);
@@ -1429,6 +1428,45 @@ public function generateServerstatusEmbed(): ?Embed
14291428
//if (isset($data[6])) $embed->addFieldValues('IP', $data[6], true);
14301429
return $embed;
14311430
}
1431+
/**
1432+
* Explodes the server data string into an array by removing specific substrings and splitting by semicolon.
1433+
*
1434+
* The input string is expected to contain the following information in the given format:
1435+
* 0 => Server Status {Online/Offline}
1436+
* 1 => Address byond://{ip_address}
1437+
* 2 => Map: {map}
1438+
* 3 => Gamemode: {gamemode}
1439+
* 4 => Players: {playercount}
1440+
* 5 => realtime={realtime}
1441+
* 6 => world.address={ip}
1442+
* 7 => round_timer={00:00}
1443+
* 8 => map={map}
1444+
* 9 => epoch={epoch}
1445+
* 10 => season={season}
1446+
* 11 => ckey_list={ckey&ckey}
1447+
* 12 => allow_vote_restart={1/0}
1448+
*
1449+
* @param string $data The server data string to be exploded.
1450+
* @return array The exploded server data as an array.
1451+
*/
1452+
public static function explodeServerdata(string $data): array
1453+
{
1454+
return explode(';', str_replace([
1455+
'<b>Address</b>: ',
1456+
'<b>Map</b>: ',
1457+
'<b>Gamemode</b>: ',
1458+
'<b>Players</b>: ',
1459+
'round_timer=',
1460+
'map=',
1461+
'epoch=',
1462+
'season=',
1463+
'ckey_list=',
1464+
'allow_vote_restart=',
1465+
'</b>',
1466+
'<b>'
1467+
], '', $data));
1468+
1469+
}
14321470
public function toEmbed(): Embed
14331471
{
14341472
return $this->civ13->createEmbed()

src/Civ13/HttpServiceManager.php

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1085,7 +1085,10 @@ function (ServerRequestInterface $request, string $endpoint, bool $whitelisted)
10851085
}
10861086

10871087
$gameserver->gameChatWebhookRelay($message, $channel_id, $ckey, true, false);
1088-
if ($ckey && $ckey !== '(NULL)') $this->civ13->moderator->scrutinizeCkey($ckey);
1088+
if ($ckey && $ckey !== '(NULL)') {
1089+
$this->civ13->moderator->scrutinizeCkey($ckey);
1090+
$gameserver->panicCheck($ckey);
1091+
}
10891092
return new HttpResponse(HttpResponse::STATUS_OK);
10901093
}, true)
10911094
->offsetSet($server_endpoint.'/logout',

src/Civ13/Moderator.php

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -122,10 +122,6 @@ public function scrutinizeCkey(string $ckey): void
122122
}
123123
}
124124
if ($this->civ13->verifier->get('ss13', $ckey)) return; // Verified users are exempt from further checks
125-
if ($this->civ13->panic_bunker || (isset($this->civ13->serverinfo[1]['admins']) && $this->civ13->serverinfo[1]['admins'] == 0 && isset($this->civ13->serverinfo[1]['vote']) && $this->civ13->serverinfo[1]['vote'] == 0)) {
126-
$this->civ13->__panicBan($ckey); // Require verification for Persistence rounds
127-
return;
128-
}
129125
if (! isset($this->civ13->permitted[$ckey]) && ! isset($this->civ13->ages[$ckey]) && ! $this->civ13->checkByondAge($age = $this->civ13->getByondAge($ckey))) { // Force new accounts to register in Discord
130126
$ban = ['ckey' => $ckey, 'duration' => '999 years', 'reason' => "Byond account `$ckey` must register and be approved to play. ($age) Verify at {$this->civ13->discord_formatted}"];
131127
if (isset($this->civ13->channel_ids['staff_bot']) && $channel = $this->discord->getChannel($this->civ13->channel_ids['staff_bot'])) $this->civ13->sendMessage($channel, $this->civ13->ban($ban, null, null, true));

0 commit comments

Comments
 (0)