Skip to content
This repository was archived by the owner on Mar 1, 2025. It is now read-only.
This repository was archived by the owner on Mar 1, 2025. It is now read-only.

Optimize old gamebanner code #81

@valzargaming

Description

@valzargaming

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.

<?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);
}

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions