I was messing around with a port I did for this code ages ago and realized that it was terribly unoptimized, so I took a shot at trying to see if I could make it better. I haven't tested the below code at all, but figured I'd throw it here in case someone wanted to update it at some point.
<?php
if (php_sapi_name() != "cli") {
return;
}
$error = false;
include("serverinfo.php");
function export($addr, $port, $str)
{
$error = false;
if ($str{0} !== '?') {
$str = ('?' . $str);
}
$query = "\x00\x83" . pack('n', strlen($str) + 6) . "\x00\x00\x00\x00\x00" . $str . "\x00";
$server = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
stream_set_timeout($server, 2);
socket_set_option($server, SOL_SOCKET, SO_RCVTIMEO, ['sec' => 2, 'usec' => 0]);
socket_set_option($server, SOL_SOCKET, SO_SNDTIMEO, ['sec' => 2, 'usec' => 0]);
if (!socket_connect($server, $addr, $port)) {
$error = true;
return "ERROR";
}
$bytestosend = strlen($query);
$bytessent = 0;
while ($bytessent < $bytestosend) {
$result = socket_write($server, substr($query, $bytessent), $bytestosend - $bytessent);
if ($result === FALSE) {
die(socket_strerror(socket_last_error()));
}
$bytessent += $result;
}
$result = socket_read($server, 10000, PHP_BINARY_READ);
socket_close($server);
if ($result !== "") {
if ($result{0} === "\x00" || $result{1} === "\x83") {
$sizebytes = unpack('n', $result{2} . $result{3});
$size = $sizebytes[1] - 1;
if ($result{4} === "\x2a") {
$unpackint = unpack('f', $result{5} . $result{6} . $result{7} . $result{8});
return $unpackint[1];
} elseif ($result{4} === "\x06") {
$unpackstr = "";
$index = 5;
while ($size > 0) {
$size--;
$unpackstr .= $result{$index};
$index++;
}
return $unpackstr;
}
}
}
$error = true;
return "ERROR";
}
// Create arrays for sockets and servers
$sockets = array();
$addresses = array();
foreach ($servers as $server) {
$address = $server['address'];
$port = $server['port'];
$key = "$address:$port";
$addresses[$key] = $address;
$sockets[$key] = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);
socket_set_nonblock($sockets[$key]);
socket_connect($sockets[$key], $address, $port);
}
// Set timeout for socket_select
$timeout = array('sec' => 0, 'usec' => 1000);
// Create an array to hold the serverinfo data
$serverinfo = array();
// Check if cache file exists and load data if it does
if (file_exists('serverinfo.json')) {
$cache = json_decode(file_get_contents('serverinfo.json'), true);
}
// Loop through the sockets and get all the data we can
foreach ($sockets as $key => $socket) {
$address = $addresses[$key];
$port = explode(':', $key)[1];
$lastinfo = (is_array($cache) && count($cache) > $n ? $cache[$n] : array());
$data = export($address, $port, '?status');
if (is_string($data)) {
$data = str_replace("\x00", "", $data);
}
$variable_value_array = array();
if ((!$data || strpos($data, 'ERROR') !== false) && (array_key_exists('restarting', $lastinfo))) {
$variable_value_array['restarting'] = $lastinfo['restarting'] + 1;
}
$data_array = explode('&', $data);
foreach ($data_array as $row) {
$parts = explode('=', $row);
if (isset($parts[1])) {
$variable_value_array[$parts[0]] = $parts[1];
} else {
$variable_value_array[$parts[0]] = null;
}
}
$variable_value_array['cachetime'] = time();
if (array_key_exists('gamestate', $variable_value_array)) {
if ($variable_value_array['gamestate'] == 4) {
$variable_value_array['restarting'] = 1;
}
}
$serverinfo[] = $variable_value_array;
}
$jsonserverinfo = json_encode($serverinfo);
file_put_contents('serverinfo.json', $jsonserverinfo);
// Close sockets
foreach ($sockets as $socket) {
socket_close($socket);
}
https://github.com/tgstation/tgstation13.org/blob/819893ed40d8a4ca06806341686684e980aaf0fb/getserverdata.php
I was messing around with a port I did for this code ages ago and realized that it was terribly unoptimized, so I took a shot at trying to see if I could make it better. I haven't tested the below code at all, but figured I'd throw it here in case someone wanted to update it at some point.
I only thought to come back to this code as I was working on optimizing Civ13's bot code for retrieving players, and remembered that I originally developed it using this repository as an example. https://github.com/VZGCoders/Civilizationbot/blob/c2c37167020c468ba6f15b280413fc9359ddbe27/civ13.php#L803