diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 00000000..1849e7f5 --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,27 @@ +// For format details, see https://aka.ms/devcontainer.json. For config options, see the +// README at: https://github.com/devcontainers/templates/tree/main/src/php +{ + "name": "PHP", + "build": { + "dockerfile": "docker/Dockerfile" + }, + "features": { + "ghcr.io/devcontainers/features/docker-in-docker:2": {} + }, + "customizations": { + "vscode": { + "extensions": [ + "junstyle.php-cs-fixer", + "GitHub.vscode-github-actions" + ], + "settings": { + "php-cs-fixer.onsave": true, + "[php]": { + "editor.defaultFormatter": "junstyle.php-cs-fixer" + } + } + } + }, + "postCreateCommand": ".devcontainer/postCreate.sh", + "remoteUser": "vscode" +} diff --git a/.devcontainer/docker/Dockerfile b/.devcontainer/docker/Dockerfile new file mode 100644 index 00000000..a199e678 --- /dev/null +++ b/.devcontainer/docker/Dockerfile @@ -0,0 +1,44 @@ +########################## Base ########################### +# Create & configure the base for this DevContainer image # +########################################################### + +# Define the DevContainer template to be used as the base +ARG PHP=8.3 +ARG DISTRO=bullseye + +FROM mcr.microsoft.com/vscode/devcontainers/php:$PHP-$DISTRO + +# Add global Composer /bin to PATH for vscode +USER vscode + +RUN echo "export PATH=\$(XDEBUG_MODE=off composer global config bin-dir --absolute --quiet):\$PATH" >> ~/.bashrc + +# Add global Composer /bin to PATH for root +USER root + +RUN echo "export PATH=\$(XDEBUG_MODE=off composer global config bin-dir --absolute --quiet):\$PATH" >> ~/.bashrc + +##################### Dependencies ##################### +# Add any dependencies required to develop the project # +######################################################## + +# Update the registry once +RUN apt-get update + +# Install ext-bz2 +RUN apt-get install -y libbz2-dev \ + && docker-php-ext-configure bz2 \ + && docker-php-ext-install bz2 + + +###################### Tools ###################### +# Install tools that are required for development # +################################################### + +# Install act +RUN curl --proto '=https' --tlsv1.2 -sSf https://raw.githubusercontent.com/nektos/act/master/install.sh | sudo bash -s -- -b /usr/local/bin + +# Install PHP Code Sniffer Fixer +USER vscode + +RUN composer global require friendsofphp/php-cs-fixer \ No newline at end of file diff --git a/.devcontainer/postCreate.sh b/.devcontainer/postCreate.sh new file mode 100755 index 00000000..1cd3e125 --- /dev/null +++ b/.devcontainer/postCreate.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash + +# Install dependencies using Composer +if [ ! -f composer.lock ]; then + composer install +fi \ No newline at end of file diff --git a/.github/workflows/Tests.yml b/.github/workflows/Tests.yml index fe481233..f6eeee7b 100644 --- a/.github/workflows/Tests.yml +++ b/.github/workflows/Tests.yml @@ -16,7 +16,7 @@ jobs: php: [8.1, 8.2, 8.3] ocular: [^1.9] experimental: [false] - composer-extra: [''] + composer-extra: [""] include: - php: 8.4 experimental: true @@ -24,7 +24,6 @@ jobs: PHP_VERSION: ${{ matrix.php }} name: PHP ${{ matrix.php }} steps: - - name: Setup PHP uses: shivammathur/setup-php@v2 with: @@ -32,7 +31,7 @@ jobs: extensions: bz2,xml,curl - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: fetch-depth: 10 @@ -40,14 +39,14 @@ jobs: run: composer validate - name: Cache composer files - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ~/.composer/cache/files key: dependencies-php-${{ matrix.php }}-composer-${{ hashFiles('composer.json') }} - name: Install dependencies using composer run: composer install --prefer-dist --no-interaction ${{ matrix.composer-extra }} - + - name: PHP CodeStyle run: | mkdir -p build/logs diff --git a/.gitignore b/.gitignore index 2a962deb..56140a21 100644 --- a/.gitignore +++ b/.gitignore @@ -1,12 +1,28 @@ +# Development +/remotes/ +test.php /.buildpath /.project /.settings/* -vendor + +# JetBrains /.idea -.phpunit.result.cache +*.iml + +# Composer +vendor composer.lock composer.phar + +# ApiGen +build/apigen + +# PHPUnit +phpunit.xml +.phpunit.result.cache +coverage/ +build/logs/* !build/logs/.gitkeep -build/logs/ -test.php -*.iml + +# PHP Code Sniffer Fixer +.php-cs-fixer.cache diff --git a/.php-cs-fixer.dist.php b/.php-cs-fixer.dist.php new file mode 100644 index 00000000..8c41ac9b --- /dev/null +++ b/.php-cs-fixer.dist.php @@ -0,0 +1,29 @@ +in([ + __DIR__.'/src', + __DIR__.'/tests', + ]) +; + +return (new PhpCsFixer\Config()) + ->setRules([ + '@PSR2' => true, + + /* Imports / use */ + 'no_unused_imports' => true, + 'no_unneeded_import_alias' => true, + 'no_leading_import_slash' => true, + 'ordered_imports' => true, + + /* Comments */ + 'single_line_comment_style' => true, + + /* Blank lines */ + 'no_extra_blank_lines' => [ + 'tokens' => ['curly_brace_block'] + ] + ]) + ->setFinder($finder) +; \ No newline at end of file diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 00000000..b47af754 --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,6 @@ +{ + "recommendations": [ + "junstyle.php-cs-fixer", + "github.vscode-github-actions" + ] +} \ No newline at end of file diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 00000000..12cdb3b5 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,21 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Debug Tests", + "type": "php", + "request": "launch", + "port": 0, + "cwd": "${workspaceFolder}", + "runtimeArgs": [ + "-dxdebug.mode=debug,develop", + "-dxdebug.client_port=${port}", + "-dxdebug.start_with_request=yes" + ], + "program": "${workspaceFolder}/vendor/bin/phpunit", + } + ] +} \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 00000000..6d2abf0c --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,72 @@ +{ + // See https://go.microsoft.com/fwlink/?LinkId=733558 + // for the documentation about the tasks.json format + "version": "2.0.0", + "tasks": [ + { + "label": "Test", + "isTestCommand": true, + "dependsOrder": "sequence", + "dependsOn": [ + "PHP Code Sniffer", + "PHP Mess Detector", + "PHPUnit" + ] + }, + { + "label": "PHP Code Sniffer", + "type": "shell", + "command": "vendor/bin/phpcs", + "args": [ + "src", + "tests", + "--extensions=php", + "--ignore=bootstrap", + "--report=checkstyle", + "--report-file=build/logs/checkstyle.xml", + "--standard=build/config/phpcs.xml", + "-v" + ] + }, + { + "label": "PHP Coding Standards Fixer", + "type": "shell", + "command": "php-cs-fixer", + "args": [ + "fix" + ] + }, + { + "label": "PHP Mess Detector", + "type": "shell", + "command": "vendor/bin/phpmd", + "args": [ + "src,tests", + "xml", + "build/config/phpmd.xml" + ] + }, + { + "label": "PHPUnit", + "type": "shell", + "command": "vendor/bin/phpunit" + }, + { + "label": "GitHub Workflows", + "type": "shell", + "command": "act", + "args": [ + "--platform=ubuntu-latest=catthehacker/ubuntu:act-latest", + "--job=${input:GitHubWorkflowsJob}" + ] + }, + ], + "inputs": [ + { + "id": "GitHubWorkflowsJob", + "type": "promptString", + "description": "Job:", + "default": "CI" + } + ] +} \ No newline at end of file diff --git a/GameQ.code-workspace b/GameQ.code-workspace new file mode 100644 index 00000000..876a1499 --- /dev/null +++ b/GameQ.code-workspace @@ -0,0 +1,8 @@ +{ + "folders": [ + { + "path": "." + } + ], + "settings": {} +} \ No newline at end of file diff --git a/README.md b/README.md index 158cfb17..19ef421e 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,5 @@ # GameQ Fork by Krymo Software + [![CI](https://github.com/KrymoSoftware/GameQ/actions/workflows/Tests.yml/badge.svg)](https://github.com/KrymoSoftware/GameQ/actions/workflows/Tests.yml) [![License](https://img.shields.io/badge/license-LGPL-blue.svg?style=flat)](https://packagist.org/packages/krymosoftware/gameq) @@ -8,11 +9,14 @@ This repository is a maintained fork of [Austinb/GameQ](https://github.com/Austi While we don't plan to add new games for now, we'll ensure compatibility with the latest PHP versions and fix issues as they arise. ## Requirements + * PHP 8.1+ - [Tested](https://github.com/KrymoSoftware/GameQ/actions/workflows/Tests.yml) in PHP 8.1, 8.2 and 8.3 * [Bzip2](http://www.php.net/manual/en/book.bzip2.php) - Used for A2S compressed responses ## Installation + #### [Composer](https://getcomposer.org/) + This method assumes you already have composer [installed](https://getcomposer.org/doc/00-intro.md) and working properly. Add `krymosoftware/gameq` as a requirement to composer.json by using `composer require krymosoftware/gameq:^4.0.0` or by manually adding the following to the *composer.json* file in the **require** section: ```json @@ -22,14 +26,17 @@ This method assumes you already have composer [installed](https://getcomposer.or Update your packages with `composer update` or install with `composer install`. #### Standalone Library + Download the [latest version](https://github.com/KrymoSoftware/GameQ/releases) of the library and unpack it into your project. Add the following to your bootstrap file: ```php require_once('/path/to/src/GameQ/Autoloader.php'); ``` + The `Autoloader.php` file provides the same autoloading functionality as the Composer installation. -## Example +## Useage + ```php $GameQ = new \GameQ\GameQ(); $GameQ->addServer([ @@ -38,13 +45,15 @@ $GameQ->addServer([ ]); $results = $GameQ->process(); ``` -Need more? See [Examples](https://github.com/Austinb/GameQ/wiki/Examples-v3). -## Contributing - +Need more? See the [Examples](https://github.com/Austinb/GameQ/wiki/Examples-v3) as well as the [Documentation](https://austinb.github.io/GameQ/api/). + +## Contributing + Please see [CONTRIBUTING](CONTRIBUTING.md) for details. ## License + See [LICENSE](LICENSE.lgpl) for more information ## Third Party Provider diff --git a/phpunit.xml b/phpunit.xml deleted file mode 100644 index 049ed06a..00000000 --- a/phpunit.xml +++ /dev/null @@ -1,26 +0,0 @@ - - - - - ./tests/ - - - - - ./src - - - - - - - - diff --git a/src/GameQ/Autoloader.php b/src/GameQ/Autoloader.php index eb3d374e..5d73b8e1 100644 --- a/src/GameQ/Autoloader.php +++ b/src/GameQ/Autoloader.php @@ -28,7 +28,6 @@ * See: https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-4-autoloader-examples.md */ spl_autoload_register(static function ($class) { - // project-specific namespace prefix $prefix = 'GameQ\\'; diff --git a/src/GameQ/Buffer.php b/src/GameQ/Buffer.php index 0d8994de..4794a4d6 100644 --- a/src/GameQ/Buffer.php +++ b/src/GameQ/Buffer.php @@ -35,7 +35,6 @@ */ class Buffer { - /** * Constants for the byte code types we need to read as */ @@ -74,7 +73,6 @@ public function __construct(string $data, string $number_type = self::NUMBER_TYP */ public function getData(): string { - return $this->data; } @@ -83,7 +81,6 @@ public function getData(): string */ public function getBuffer(): string { - return substr($this->data, $this->index); } @@ -92,7 +89,6 @@ public function getBuffer(): string */ public function getLength(): int { - return max($this->length - $this->index, 0); } @@ -103,7 +99,6 @@ public function getLength(): int */ public function read(int $length = 1): string { - if (($length + $this->index) > $this->length) { throw new ProtocolException("Unable to read length=$length from buffer. Bad protocol format or return?"); } @@ -122,7 +117,6 @@ public function read(int $length = 1): string */ public function readLast(): string { - $len = strlen($this->data); $string = $this->data[strlen($this->data) - 1]; $this->data = substr($this->data, 0, $len - 1); @@ -136,7 +130,6 @@ public function readLast(): string */ public function lookAhead(int $length = 1): string { - return substr($this->data, $this->index, $length); } @@ -145,7 +138,6 @@ public function lookAhead(int $length = 1): string */ public function skip(int $length = 1): void { - $this->index += $length; } @@ -155,7 +147,6 @@ public function skip(int $length = 1): void */ public function jumpto(int $index): void { - $this->index = min($index, $this->length - 1); } @@ -164,7 +155,6 @@ public function jumpto(int $index): void */ public function getPosition(): int { - return $this->index; } @@ -202,7 +192,6 @@ public function readString(string $delim = "\x00"): string */ public function readPascalString(int $offset = 0, bool $read_offset = false): string { - // Get the proper offset $len = $this->readInt8(); $offset = max($len - $offset, 0); @@ -226,7 +215,6 @@ public function readPascalString(int $offset = 0, bool $read_offset = false): st */ public function readStringMulti(array $delims, ?string &$delimfound = null): string { - // Get position of delimiters $pos = []; foreach ($delims as $delim) { @@ -281,7 +269,6 @@ public function readInt8Signed(): int */ public function readInt16(): int { - // Change the integer type we are looking up $type = match ($this->number_type) { self::NUMBER_TYPE_BIGENDIAN => 'nint', @@ -301,7 +288,6 @@ public function readInt16(): int */ public function readInt16Signed(): int { - // Read the data into a string $string = $this->read(2); @@ -357,7 +343,6 @@ public function readInt32($length = 4): int */ public function readInt32Signed(): int { - // Read the data into a string $string = $this->read(4); @@ -380,7 +365,6 @@ public function readInt32Signed(): int */ public function readInt64(): int { - // We have the pack 64-bit codes available. See: http://php.net/manual/en/function.pack.php if (PHP_INT_SIZE === 8 && version_compare(PHP_VERSION, '5.6.3') >= 0) { // Change the integer type we are looking up @@ -418,7 +402,6 @@ public function readInt64(): int */ public function readFloat32(): float { - // Read the data into a string $string = $this->read(4); diff --git a/src/GameQ/Filters/Base.php b/src/GameQ/Filters/Base.php index 4d28983b..d94844b6 100644 --- a/src/GameQ/Filters/Base.php +++ b/src/GameQ/Filters/Base.php @@ -27,7 +27,6 @@ */ abstract class Base { - /** * Holds the options for this instance of the filter */ @@ -35,7 +34,6 @@ abstract class Base public function __construct(array $options = []) { - $this->options = $options; } diff --git a/src/GameQ/Filters/Normalize.php b/src/GameQ/Filters/Normalize.php index 5e89c8bc..31cb9ad0 100644 --- a/src/GameQ/Filters/Normalize.php +++ b/src/GameQ/Filters/Normalize.php @@ -23,10 +23,17 @@ /** * Class Normalize * + * This Filter is responsible for normalizing the provided result's + * property names to the GameQ standard. + * * @package GameQ\Filters */ class Normalize extends Base { + /** + * Determines if data should be persisted for unit testing. + */ + protected bool $writeTestData = false; /** * Holds the protocol specific normalize information @@ -35,74 +42,77 @@ class Normalize extends Base /** * Apply this filter - * - * @return mixed */ public function apply(array $result, Server $server): mixed { + // Determine if there is data to be processed + if (! empty($result)) { + // Handle unit test data generation + if ($this->writeTestData) { + // Initialize potential data for unit testing + $unitTestData = [ ]; + + // Add the initial result to the unit test data + $unitTestData['raw'][$server->id()] = $result; + } - // No result passed so just return - if (empty($result)) { - return $result; - } - - //$data = [ ]; - //$data['raw'][$server->id()] = $result; + /* Grab the normalize definition from the server's protocol */// + $this->normalize = $server->protocol()->getNormalize(); - // Grab the normalize for this protocol for the specific server - $this->normalize = $server->protocol()->getNormalize(); + // Normalize general information + $result = array_merge($result, $this->check('general', $result)); - // Do general information - $result = array_merge($result, $this->check('general', $result)); + // Normalize player information + if (isset($result['players']) && count($result['players']) > 0) { + foreach ($result['players'] as $key => $player) { + $result['players'][$key] = array_merge($player, $this->check('player', $player)); + } + } else { + $result['players'] = []; + } - // Do player information - if (isset($result['players']) && count($result['players']) > 0) { - // Iterate - foreach ($result['players'] as $key => $player) { - $result['players'][$key] = array_merge($player, $this->check('player', $player)); + // Normalize team information + if (isset($result['teams']) && count($result['teams']) > 0) { + foreach ($result['teams'] as $key => $team) { + $result['teams'][$key] = array_merge($team, $this->check('team', $team)); + } + } else { + $result['teams'] = []; } - } else { - $result['players'] = []; - } - // Do team information - if (isset($result['teams']) && count($result['teams']) > 0) { - // Iterate - foreach ($result['teams'] as $key => $team) { - $result['teams'][$key] = array_merge($team, $this->check('team', $team)); + // Handle unit test data generation + if ($this->writeTestData) { + // Add the filtered result to the unit test data + $unitTestData['filtered'][$server->id()] = $result; + + // Persist the collected data to the tests directory + file_put_contents( + sprintf('%s/../../../tests/Filters/Providers/Normalize/%s_1.json', __DIR__, $server->protocol()->getProtocol()), + json_encode($unitTestData, JSON_UNESCAPED_UNICODE | JSON_PARTIAL_OUTPUT_ON_ERROR) + ); } - } else { - $result['teams'] = []; } - //$data['filtered'][$server->id()] = $result; - /*file_put_contents( - sprintf('%s/../../../tests/Filters/Providers/Normalize/%s_1.json', __DIR__, $server->protocol()->getProtocol()), - json_encode($data, JSON_UNESCAPED_UNICODE | JSON_PARTIAL_OUTPUT_ON_ERROR) - );*/ - - // Return the normalized result + // Return the filtered result return $result; } /** * Check a section for normalization - * - * @param $section - * @param $data - * - * @return array */ - protected function check($section, $data) + protected function check(string $section, array $data): array { - - // Normalized return array + // Initialize the normalized output $normalized = []; - if (isset($this->normalize[$section]) && !empty($this->normalize[$section])) { - foreach ($this->normalize[$section] as $property => $raw) { - // Default the value for the new key as null - $value = null; + // Ensure the provided section is defined + if (isset($this->normalize[$section])) { + // Process each mapping individually + foreach ($this->normalize[$section] as $target => $source) { + // Treat explicit source like implicit sources + if (! is_array($source)) { + $source = [$source]; + } if (is_array($raw)) { // Iterate over the raw property we want to use @@ -117,10 +127,13 @@ protected function check($section, $data) $value = $data[$raw]; } - $normalized['gq_' . $property] = $value; + // Write null in case no source was found + // TODO: Remove this in the next major version. + $normalized['gq_'.$target] = isset($normalized['gq_'.$target]) ? $normalized['gq_'.$target] : null; } } + // Return the normalized data return $normalized; } } diff --git a/src/GameQ/Filters/Secondstohuman.php b/src/GameQ/Filters/Secondstohuman.php index 0855780d..a9023474 100644 --- a/src/GameQ/Filters/Secondstohuman.php +++ b/src/GameQ/Filters/Secondstohuman.php @@ -18,12 +18,14 @@ namespace GameQ\Filters; +use GameQ\Helpers\Arr; use GameQ\Server; +use RecursiveArrayIterator; /** * Class Secondstohuman * - * This class converts seconds into a human readable time string 'hh:mm:ss'. This is mainly for converting + * This Filter converts seconds into a human readable time string 'hh:mm:ss'. This is mainly for converting * a player's connected time into a readable string. Note that most game servers DO NOT return a player's connected * time. Source (A2S) based games generally do but not always. This class can also be used to convert other time * responses into readable time @@ -33,7 +35,6 @@ */ class Secondstohuman extends Base { - /** * The options key for setting the data key(s) to look for to convert */ @@ -51,13 +52,11 @@ class Secondstohuman extends Base /** * Secondstohuman constructor. - * - * @param array $options */ public function __construct(array $options = []) { // Check for passed keys - if (!array_key_exists(self::OPTION_TIMEKEYS, $options)) { + if (! array_key_exists(self::OPTION_TIMEKEYS, $options)) { // Use default $options[self::OPTION_TIMEKEYS] = $this->timeKeysDefault; } else { @@ -71,51 +70,34 @@ public function __construct(array $options = []) /** * Apply this filter to the result data - * - * @return mixed */ public function apply(array $result, Server $server): mixed { - // Send the results off to be iterated and return the updated result - return $this->iterate($result); - } - - /** - * Home grown iterate function. Would like to replace this with an internal PHP method(s) but could not find a way - * to make the iterate classes add new keys to the response. They all seemed to be read-only. - * - * @todo: See if there is a more internal way of handling this instead of foreach looping and recursive calling - * - * @param array $result - * - * @return array - */ - protected function iterate(array &$result) - { - // Iterate over the results - foreach ($result as $key => $value) { - // Offload to itself if we have another array - if (is_array($value)) { - // Iterate and update the result - $result[$key] = $this->iterate($value); - } elseif (in_array( - $key, - $this->options[self::OPTION_TIMEKEYS], - true - ) + return Arr::recursively($result, function ($value, $key, RecursiveArrayIterator $iterator) { + if ( + // Only process whitelisted keys + (in_array($key, $this->options[self::OPTION_TIMEKEYS])) && + // Only process numeric values (float, integer, string) + (is_numeric($value)) ) { - // Make sure the value is a float (throws E_WARNING in PHP 7.1+) - $value = (float)$value; - // We match one of the keys we are wanting to convert so add it and move on - $result[sprintf(self::RESULT_KEY, $key)] = sprintf( - "%02d:%02d:%02d", - floor($value / 3600), - ($value / 60) % 60, - $value % 60 + // Ensure the value is float + if (! is_float($value)) { + $value = floatval($value); + } + + // Add a new element to the result + $iterator->offsetSet( + // Modify the current key + sprintf(self::RESULT_KEY, $key), + // Format the provided time + sprintf( + '%02d:%02d:%02d', + (int)floor($value / 3600), // Hours + (int)fmod(($value / 60), 60), // Minutes + (int)fmod($value, 60) // Seconds + ) ); } - } - - return $result; + }); } } diff --git a/src/GameQ/Filters/Stripcolors.php b/src/GameQ/Filters/Stripcolors.php index e49c676d..df7fd958 100644 --- a/src/GameQ/Filters/Stripcolors.php +++ b/src/GameQ/Filters/Stripcolors.php @@ -18,69 +18,73 @@ namespace GameQ\Filters; +use Closure; +use GameQ\Helpers\Arr; use GameQ\Server; /** * Class Strip Colors * - * Strip color codes from UT and Quake based games + * This Filter is responsible for removing + * color codes from the provided result. * * @package GameQ\Filters */ class Stripcolors extends Base { + /** + * Determines if data should be persisted for unit testing. + */ + protected bool $writeTestData = false; /** * Apply this filter - * - * @return mixed */ public function apply(array $result, Server $server): mixed { + // Prevent working on empty results + if (! empty($result)) { + // Handle unit test data generation + if ($this->writeTestData) { + // Initialize potential data for unit testing + $unitTestData = []; - // No result passed so just return - if (empty($result)) { - return $result; - } + // Add the initial result to the unit test data + $unitTestData['raw'][$server->id()] = $result; + } - //$data = []; - //$data['raw'][ $server->id() ] = $result; + // Determine the executor defined for the current Protocol + if ($executor = $this->getExecutor($server)) { + // Apply the executor to the result recursively + $result = Arr::recursively($result, function (&$value) use ($executor) { + // The executor may only be applied to strings + if (is_string($value)) { + // Strip the colors and update the value by reference + $value = $executor($value); + } elseif (! is_array($value)) { + $value = (string) $value; // TODO: Remove this in the next major version. + } + }); + } - $protocol = $server->protocol(); - if ($protocol === null) { - return $result; + // Handle unit test data generation + if ($this->writeTestData) { + // Add the filtered result to the unit test data + $unitTestData['filtered'][$server->id()] = $result; + + // Persist the collected data to the tests directory + file_put_contents( + sprintf( + '%s/../../../tests/Filters/Providers/Stripcolors\%s_1.json', + __DIR__, + $server->protocol()->getProtocol() + ), + json_encode($unitTestData, JSON_UNESCAPED_UNICODE | JSON_PARTIAL_OUTPUT_ON_ERROR) + ); + } } - // Switch based on the base (not game) protocol - switch ($protocol->getProtocol()) { - case 'quake2': - case 'quake3': - case 'gta5m': - case 'doom3': - array_walk_recursive($result, [$this, 'stripQuake']); - break; - case 'unreal2': - case 'ut3': - case 'gamespy3': //not sure if gamespy3 supports ut colors but won't hurt - case 'gamespy2': - array_walk_recursive($result, [$this, 'stripUnreal']); - break; - case 'source': - array_walk_recursive($result, [$this, 'stripSource']); - break; - } - - /*$data['filtered'][ $server->id() ] = $result; - file_put_contents( - sprintf( - '%s/../../../tests/Filters/Providers/Stripcolors\%s_1.json', - __DIR__, - $server->protocol()->getProtocol() - ), - json_encode($data, JSON_UNESCAPED_UNICODE | JSON_PARTIAL_OUTPUT_ON_ERROR) - );*/ - - // Return the stripped result + // Return the filtered result return $result; } @@ -113,4 +117,39 @@ protected function stripUnreal(mixed &$string): void $string = preg_replace('/\x1b.../', '', $string); } } + + /** + * This helper determines the correct executor to + * be used with the current Protocl instance. + * + * @SuppressWarnings(PHPMD.CyclomaticComplexity) + * + * @return null|Closure + */ + protected function getExecutor(Server $server) + { + // Determine the correct executor for the current Protocol instance + switch ($server->protocol()->getProtocol()) { + // Strip Protocols using Quake color tags + case 'quake2': + case 'quake3': + case 'doom3': + case 'gta5m': + return [$this, 'stripQuake']; + + // Strip Protocols using Unreal color tags + case 'unreal2': + case 'ut3': + case 'gamespy3': // not sure if gamespy3 supports ut colors but won't hurt + case 'gamespy2': + return [$this, 'stripUnreal']; + + // Strip Protocols using Source color tags + case 'source': + return [$this, 'stripSource']; + + default: + return null; + } + } } diff --git a/src/GameQ/Filters/Test.php b/src/GameQ/Filters/Test.php index 38758f44..a8bddd56 100644 --- a/src/GameQ/Filters/Test.php +++ b/src/GameQ/Filters/Test.php @@ -31,8 +31,6 @@ class Test extends Base { /** * Apply the filter. For this we just return whatever is sent - * - * @return mixed */ public function apply(array $result, Server $server): mixed { diff --git a/src/GameQ/GameQ.php b/src/GameQ/GameQ.php index 38f866fa..4e7111fd 100644 --- a/src/GameQ/GameQ.php +++ b/src/GameQ/GameQ.php @@ -47,7 +47,7 @@ class GameQ /** * Holds the instance of itself * - * @type self + * @var self */ protected static GameQ $instance; @@ -61,7 +61,7 @@ public static function factory(): self return self::$instance; } - /* Dynamic Section */ + // Dynamic Section /** * Default options @@ -162,7 +162,6 @@ public function addServer(array $server_info = []): self */ public function addServers(array $servers = []): self { - // Loop through all the servers and add them foreach ($servers as $server_info) { $this->addServer($server_info); @@ -549,7 +548,6 @@ protected function doParseResponse(Server $server): array */ protected function doApplyFilters(array $results, Server $server): array { - // Loop over the filters foreach ($this->options['filters'] as $filterOptions) { // Try to do this filter diff --git a/src/GameQ/Helpers/Arr.php b/src/GameQ/Helpers/Arr.php new file mode 100644 index 00000000..243443b0 --- /dev/null +++ b/src/GameQ/Helpers/Arr.php @@ -0,0 +1,129 @@ +. + */ + +namespace GameQ\Helpers; + +use Closure; +use RecursiveArrayIterator; +use RecursiveIteratorIterator; + +/** + * This helper contains functions to work with arrays. + * + * @package GameQ\Helpers + */ +class Arr +{ + /** + * This helper does process each element of the provided array recursively. + * It does so allowing for modifications to the provided array and without + * using actual recursive calls. + */ + public static function recursively(array $data, Closure $callback): array + { + // Initialize the RecursiveArrayIterator for the provided data + $arrayIterator = new RecursiveArrayIterator($data); + + // Configure the Iterator for the RecursiveIterator + $recursiveIterator = new RecursiveIteratorIterator($arrayIterator); + + // Traverse the provided data + foreach ($recursiveIterator as $key => $value) { + // Get the current sub iterator with Type hinting + /** @var RecursiveArrayIterator */ + $subIterator = $recursiveIterator->getSubIterator(); + + // Execute the callback + $callback($value, $key, $subIterator); + + // Update the modified value + $subIterator->offsetSet($key, $value); + } + + // Return the processed data + return $arrayIterator->getArrayCopy(); + } + + /** + * This helper is intended to hash the provided array's values + * and return it back as key => hash. + * + * @return array + */ + public static function hashes(array $array): array + { + $hashes = []; + + // Process the provided array + foreach ($array as $key => $value) { + // Serialze and hash each value individually + $hashes[$key] = md5(serialize($value)); + } + + // Return array containing the hashes + return $hashes; + } + + /** + * This helper is intended to set a value inside the provided array. + */ + public static function set(array &$array, array $path, $value): array + { + $current = &$array; + + // Process the path until the last element + foreach ($path as $i => $element) { + // Remove the element from the path + unset($path[$i]); + + // Create missing key + if (! isset($current[$element])) { + $current[$element] = []; + } + + // Set current to a reference of next + $current = &$current[$element]; + } + + // Finally set the value using the last key + $current = $value; + + // Return the current, modified array (level) + return $array; + } + + /** + * This helper method is intended to shift the provided arguments to the left. + * + * **Example:** foo, bar, baz becomes bar, baz, baz + */ + public static function shift(&...$args): void + { + // Get the array keys to ensure numeric index + $keys = array_keys($args); + + // Iterate the provided arguments keys in order + foreach ($keys as $i => $key) { + // Process until the last argument + if ($i < count($keys) - 1) { + // Shift next into current + $args[$key] = $args[$keys[$i + 1]]; + } + } + } +} diff --git a/src/GameQ/Helpers/Str.php b/src/GameQ/Helpers/Str.php new file mode 100644 index 00000000..6899ec84 --- /dev/null +++ b/src/GameQ/Helpers/Str.php @@ -0,0 +1,49 @@ +. + */ + +namespace GameQ\Helpers; + +/** + * This helper contains functions to work with strings. + * + * @package GameQ\Helpers + */ +class Str +{ + /** + * This helper method re-encodes an ISO 8859-1 string to UTF-8. + * + * @see https://en.wikipedia.org/wiki/ISO/IEC_8859-1 + * @see https://en.wikipedia.org/wiki/UTF-8 + */ + public static function isoToUtf8(string $value): string + { + return iconv('ISO-8859-1', 'UTF-8', $value); + } + + /** + * This helper method re-encodes an UTF-8 string to ISO 8859-1. + * + * @see https://en.wikipedia.org/wiki/ISO/IEC_8859-1 + * @see https://en.wikipedia.org/wiki/UTF-8 + */ + public static function utf8ToIso(string $value): string + { + return iconv('UTF-8', 'ISO-8859-1', $value); + } +} diff --git a/src/GameQ/Protocol.php b/src/GameQ/Protocol.php index 26ac92aa..fef648d8 100644 --- a/src/GameQ/Protocol.php +++ b/src/GameQ/Protocol.php @@ -29,7 +29,6 @@ */ abstract class Protocol { - /** * Constants for class states */ @@ -165,7 +164,6 @@ abstract class Protocol public function __construct(array $options = []) { - // Set the options for this specific instance of the class $this->options = $options; } @@ -175,7 +173,6 @@ public function __construct(array $options = []) */ public function __toString(): string { - return $this->name; } @@ -184,7 +181,6 @@ public function __toString(): string */ public function portDiff(): int { - return $this->port_diff; } @@ -195,7 +191,6 @@ public function portDiff(): int */ public function findQueryPort(int $clientPort): int { - return $clientPort + $this->port_diff; } @@ -204,7 +199,6 @@ public function findQueryPort(int $clientPort): int */ public function joinLink(): ?string { - return $this->join_link; } @@ -213,7 +207,6 @@ public function joinLink(): ?string */ public function name(): string { - return $this->name; } @@ -222,7 +215,6 @@ public function name(): string */ public function nameLong(): string { - return $this->name_long; } @@ -231,7 +223,6 @@ public function nameLong(): string */ public function state(): int { - return $this->state; } @@ -240,7 +231,6 @@ public function state(): int */ public function getProtocol(): string { - return $this->protocol; } @@ -261,7 +251,6 @@ public function transport(?string $type = null): ?string */ public function options(array $options = []): array { - if (!empty($options)) { $this->options = $options; } @@ -270,9 +259,7 @@ public function options(array $options = []): array } - /* - * Packet Section - */ + // Packet Section /** * Return specific packet(s) @@ -323,9 +310,7 @@ public function packetResponse(?array $response = null): array } - /* - * Challenge section - */ + // Challenge section /** * Determine whether or not this protocol has a challenge needed before querying @@ -341,7 +326,6 @@ public function hasChallenge(): bool */ public function challengeParseAndApply(Buffer $challenge_buffer): bool { - return true; } @@ -350,7 +334,6 @@ public function challengeParseAndApply(Buffer $challenge_buffer): bool */ protected function challengeApply(string $challenge_string): bool { - // Let's loop through all the packets and append the challenge where it is needed foreach ($this->packets as $packet_type => $packet) { $this->packets[$packet_type] = sprintf($packet, $challenge_string); @@ -359,52 +342,15 @@ protected function challengeApply(string $challenge_string): bool return true; } - /** - * Converts a string from ISO-8859-1 to UTF-8. - * This is a replacement for PHP's utf8_encode function that was deprecated with PHP 8.2. - * - * Source: symfony/polyfill-php72 - * See https://github.com/symfony/polyfill-php72/blob/bf44a9fd41feaac72b074de600314a93e2ae78e2/Php72.php#L24-L38 - * - * @author Nicolas Grekas - * @author Dariusz RumiƄski > 1, $j = 0; $i < $len; ++$i, ++$j) { - switch (true) { - case $s[$i] < "\x80": - $s[$j] = $s[$i]; - break; - case $s[$i] < "\xC0": - $s[$j] = "\xC2"; - $s[++$j] = $s[$i]; - break; - default: - $s[$j] = "\xC3"; - $s[++$j] = \chr(\ord($s[$i]) - 64); - break; - } - } - - return substr($s, 0, $j); - } - /** * Get the normalize settings for the protocol */ public function getNormalize(): array { - return $this->normalize; } - /* - * General - */ + // General /** * Generic method to allow protocol classes to do work right before the query is sent diff --git a/src/GameQ/Protocols/Aa3.php b/src/GameQ/Protocols/Aa3.php index 2ad70c16..d7d3d4da 100644 --- a/src/GameQ/Protocols/Aa3.php +++ b/src/GameQ/Protocols/Aa3.php @@ -26,7 +26,6 @@ */ class Aa3 extends Source { - /** * String name of this protocol class */ diff --git a/src/GameQ/Protocols/Arksa.php b/src/GameQ/Protocols/Arksa.php new file mode 100644 index 00000000..62f2ff82 --- /dev/null +++ b/src/GameQ/Protocols/Arksa.php @@ -0,0 +1,113 @@ +. + */ + +namespace GameQ\Protocols; + +use GameQ\Exception\ProtocolException; +use GameQ\Result; + +/** + * ARK: Survival Ascended Protocol Class + * + * Extends the EOS protocol and adds ARK-specific server response processing. + * + * @package GameQ\Protocols + * @author H.Rouatbi + */ +class Arksa extends Eos +{ + /** + * The protocol being used + */ + protected string $protocol = 'arksa'; + + /** + * Longer string name of this protocol class + */ + protected string $name_long = 'ARK: Survival Ascended'; + + /** + * String name of this protocol class + */ + protected string $name = 'arksa'; + + /** + * Grant type used for authentication + */ + protected string $grant_type = 'client_credentials'; + + /** + * Deployment ID for the game or application + */ + protected ?string $deployment_id = 'ad9a8feffb3b4b2ca315546f038c3ae2'; + + /** + * User ID for authentication + */ + protected ?string $user_id = 'xyza7891muomRmynIIHaJB9COBKkwj6n'; + + /** + * User secret key for authentication + */ + protected ?string $user_secret = 'PP5UGxysEieNfSrEicaD1N2Bb3TdXuD7xHYcsdUHZ7s'; + + /** + * Process the response from the EOS API and filter ARK-specific server data + * + * @throws ProtocolException + */ + public function processResponse(): array + { + $serverData = parent::processResponse(); + + // Filter by port to match server sessions + $filtered = array_filter($serverData, function ($session) { + return $session['attributes']['ADDRESSBOUND_s'] === "{$this->serverIp}:{$this->serverPortQuery}" || + $session['attributes']['ADDRESSBOUND_s'] === "0.0.0.0:{$this->serverPortQuery}"; + }); + + if (!$filtered) { + throw new ProtocolException('No matching sessions found for the specified port.'); + } + + $session = reset($filtered); + + $result = new Result(); + + // Add server items to the result object + $result->add('hostname', $this->getAttribute($session['attributes'], 'CUSTOMSERVERNAME_s', 'Unknown')); + $result->add('mapname', $this->getAttribute($session['attributes'], 'MAPNAME_s', 'Unknown')); + $result->add('password', $this->getAttribute($session['attributes'], 'SERVERPASSWORD_b', false)); + $result->add('numplayers', $this->getAttribute($session, 'totalPlayers', 0)); + $result->add('maxplayers', $this->getAttribute($session['settings'], 'maxPublicPlayers', 0)); + $result->add('anticheat', $this->getAttribute($session['attributes'], 'SERVERUSESBATTLEYE_b', false)); + $result->add('allowJoinInProgress', $this->getAttribute($session['settings'], 'allowJoinInProgress', false)); + $result->add('day', $this->getAttribute($session['attributes'], 'DAYTIME_s', '')); + $result->add( + 'version', + "v" . $this->getAttribute($session['attributes'], 'BUILDID_s', '0') . "." . + $this->getAttribute($session['attributes'], 'MINORBUILDID_s', '0') + ); + $result->add('pve', (bool) $this->getAttribute($session['attributes'], 'SESSIONISPVE_l', false)); + $result->add('officialserver', (bool) $this->getAttribute($session['attributes'], 'OFFICIALSERVER_s', false)); + + // Return the final result + return $result->fetch(); + } +} diff --git a/src/GameQ/Protocols/Arkse.php b/src/GameQ/Protocols/Arkse.php index 75c82288..ee7bd6ee 100644 --- a/src/GameQ/Protocols/Arkse.php +++ b/src/GameQ/Protocols/Arkse.php @@ -26,7 +26,6 @@ */ class Arkse extends Source { - /** * String name of this protocol class */ diff --git a/src/GameQ/Protocols/Armedassault2oa.php b/src/GameQ/Protocols/Armedassault2oa.php index 7b08c28a..c27201d9 100644 --- a/src/GameQ/Protocols/Armedassault2oa.php +++ b/src/GameQ/Protocols/Armedassault2oa.php @@ -26,7 +26,6 @@ */ class Armedassault2oa extends Source { - /** * String name of this protocol class */ diff --git a/src/GameQ/Protocols/Ase.php b/src/GameQ/Protocols/Ase.php index c2e16bce..4f3f9669 100644 --- a/src/GameQ/Protocols/Ase.php +++ b/src/GameQ/Protocols/Ase.php @@ -31,7 +31,6 @@ */ class Ase extends Protocol { - /** * Array of packets we want to look up. * Each key should correspond to a defined method in this or a parent class @@ -136,9 +135,7 @@ public function processResponse(): mixed return $result->fetch(); } - /* - * Internal methods - */ + // Internal methods /** * Handles processing the extra key/value pairs for server settings diff --git a/src/GameQ/Protocols/Atlas.php b/src/GameQ/Protocols/Atlas.php index 64c6d4a0..cec6716a 100644 --- a/src/GameQ/Protocols/Atlas.php +++ b/src/GameQ/Protocols/Atlas.php @@ -26,7 +26,6 @@ */ class Atlas extends Source { - /** * String name of this protocol class */ diff --git a/src/GameQ/Protocols/Batt1944.php b/src/GameQ/Protocols/Batt1944.php index 539e0a99..3b74dcd8 100644 --- a/src/GameQ/Protocols/Batt1944.php +++ b/src/GameQ/Protocols/Batt1944.php @@ -26,7 +26,6 @@ */ class Batt1944 extends Source { - /** * String name of this protocol class */ diff --git a/src/GameQ/Protocols/Bf1942.php b/src/GameQ/Protocols/Bf1942.php index f48f5b64..0fd50813 100644 --- a/src/GameQ/Protocols/Bf1942.php +++ b/src/GameQ/Protocols/Bf1942.php @@ -26,7 +26,6 @@ */ class Bf1942 extends Gamespy { - /** * String name of this protocol class */ diff --git a/src/GameQ/Protocols/Bf2.php b/src/GameQ/Protocols/Bf2.php index ca107d2c..711188f7 100644 --- a/src/GameQ/Protocols/Bf2.php +++ b/src/GameQ/Protocols/Bf2.php @@ -26,7 +26,6 @@ */ class Bf2 extends Gamespy3 { - /** * String name of this protocol class */ diff --git a/src/GameQ/Protocols/Bf3.php b/src/GameQ/Protocols/Bf3.php index 8802011d..80a80858 100644 --- a/src/GameQ/Protocols/Bf3.php +++ b/src/GameQ/Protocols/Bf3.php @@ -33,7 +33,6 @@ */ class Bf3 extends Protocol { - /** * Array of packets we want to query. */ @@ -117,7 +116,6 @@ class Bf3 extends Protocol */ public function processResponse(): mixed { - // Holds the results sent back $results = []; @@ -173,9 +171,7 @@ public function processResponse(): mixed return $results; } - /* - * Internal Methods - */ + // Internal Methods /** * Decode the buffer into a usable format @@ -185,7 +181,6 @@ public function processResponse(): mixed */ protected function decode(Buffer $buffer) { - $items = []; // Get the number of words in this buffer @@ -211,7 +206,6 @@ protected function decode(Buffer $buffer) */ protected function processDetails(Buffer $buffer) { - // Decode into items $items = $this->decode($buffer); @@ -276,7 +270,6 @@ protected function processDetails(Buffer $buffer) */ protected function processVersion(Buffer $buffer) { - // Decode into items $items = $this->decode($buffer); @@ -298,7 +291,6 @@ protected function processVersion(Buffer $buffer) */ protected function processPlayers(Buffer $buffer) { - // Decode into items $items = $this->decode($buffer); diff --git a/src/GameQ/Protocols/Bf4.php b/src/GameQ/Protocols/Bf4.php index f65a91b5..f3701893 100644 --- a/src/GameQ/Protocols/Bf4.php +++ b/src/GameQ/Protocols/Bf4.php @@ -19,6 +19,7 @@ namespace GameQ\Protocols; use GameQ\Buffer; +use GameQ\Exception\ProtocolException; use GameQ\Result; /** @@ -31,7 +32,6 @@ */ class Bf4 extends Bf3 { - /** * String name of this protocol class */ @@ -46,10 +46,10 @@ class Bf4 extends Bf3 * Handle processing details since they are different than BF3 * * @return array + * @throws ProtocolException */ protected function processDetails(Buffer $buffer) { - // Decode into items $items = $this->decode($buffer); diff --git a/src/GameQ/Protocols/Bfbc2.php b/src/GameQ/Protocols/Bfbc2.php index 7b661556..0e4f8c1b 100644 --- a/src/GameQ/Protocols/Bfbc2.php +++ b/src/GameQ/Protocols/Bfbc2.php @@ -36,7 +36,6 @@ */ class Bfbc2 extends Protocol { - /** * Array of packets we want to query. */ @@ -152,9 +151,7 @@ public function processResponse(): mixed return $results; } - /* - * Internal Methods - */ + // Internal Methods /** * Decode the buffer into a usable format @@ -164,7 +161,6 @@ public function processResponse(): mixed */ protected function decode(Buffer $buffer) { - $items = []; // Get the number of words in this buffer @@ -186,10 +182,10 @@ protected function decode(Buffer $buffer) * Process the server details * * @return array + * @throws ProtocolException */ protected function processDetails(Buffer $buffer) { - // Decode into items $items = $this->decode($buffer); @@ -247,6 +243,7 @@ protected function processDetails(Buffer $buffer) * Process the server version * * @return array + * @throws ProtocolException */ protected function processVersion(Buffer $buffer) { @@ -267,10 +264,10 @@ protected function processVersion(Buffer $buffer) * Process the players * * @return array + * @throws ProtocolException */ protected function processPlayers(Buffer $buffer) { - // Decode into items $items = $this->decode($buffer); diff --git a/src/GameQ/Protocols/Bfh.php b/src/GameQ/Protocols/Bfh.php index 5e8d47ff..bc38936c 100644 --- a/src/GameQ/Protocols/Bfh.php +++ b/src/GameQ/Protocols/Bfh.php @@ -26,7 +26,6 @@ */ class Bfh extends Bf4 { - /** * String name of this protocol class */ diff --git a/src/GameQ/Protocols/Cfx.php b/src/GameQ/Protocols/Cfx.php index eaa898d6..d0162c23 100644 --- a/src/GameQ/Protocols/Cfx.php +++ b/src/GameQ/Protocols/Cfx.php @@ -38,7 +38,6 @@ */ class Cfx extends Protocol { - /** * Array of packets we want to look up. * Each key should correspond to a defined method in this or a parent class @@ -94,6 +93,8 @@ class Cfx extends Protocol /** * Get FiveM players list using a sub query + * + * @throws \Exception */ public function beforeSend(Server $server): void { @@ -129,9 +130,7 @@ public function processResponse(): mixed return $this->{$this->responses[$response_type]}($buffer); } - /* - * Internal methods - */ + // Internal methods /** * Handle processing the status response diff --git a/src/GameQ/Protocols/Codmw2.php b/src/GameQ/Protocols/Codmw2.php index abf1c89b..e6d23e03 100644 --- a/src/GameQ/Protocols/Codmw2.php +++ b/src/GameQ/Protocols/Codmw2.php @@ -19,6 +19,8 @@ namespace GameQ\Protocols; use GameQ\Buffer; +use GameQ\Exception\ProtocolException; +use GameQ\Helpers\Str; use GameQ\Result; /** @@ -39,6 +41,10 @@ class Codmw2 extends Quake3 */ protected string $name_long = "Call of Duty: Modern Warfare 2"; + /** + * @return array + * @throws ProtocolException + */ protected function processPlayers(Buffer $buffer) { // Temporarily cache players in order to remove last @@ -59,7 +65,7 @@ protected function processPlayers(Buffer $buffer) $playerInfo->skip(); // Add player name, encoded - $player['name'] = $this->convertToUtf8(trim(($playerInfo->readString('"')))); + $player['name'] = Str::isoToUtf8(trim(($playerInfo->readString('"')))); // Add player $players[] = $player; diff --git a/src/GameQ/Protocols/Codmw3.php b/src/GameQ/Protocols/Codmw3.php index 603cac1c..05b5f24c 100644 --- a/src/GameQ/Protocols/Codmw3.php +++ b/src/GameQ/Protocols/Codmw3.php @@ -26,7 +26,6 @@ */ class Codmw3 extends Source { - /** * String name of this protocol class */ diff --git a/src/GameQ/Protocols/Cs15.php b/src/GameQ/Protocols/Cs15.php index 8769b456..f70cf9cd 100644 --- a/src/GameQ/Protocols/Cs15.php +++ b/src/GameQ/Protocols/Cs15.php @@ -28,7 +28,6 @@ */ class Cs15 extends Won { - /** * String name of this protocol class */ diff --git a/src/GameQ/Protocols/Cs16.php b/src/GameQ/Protocols/Cs16.php index 041e2590..0e748443 100644 --- a/src/GameQ/Protocols/Cs16.php +++ b/src/GameQ/Protocols/Cs16.php @@ -28,7 +28,6 @@ */ class Cs16 extends Source { - /** * String name of this protocol class */ @@ -51,7 +50,6 @@ class Cs16 extends Source */ protected function processPackets($packet_id, array $packets = []) { - // The response is gold source if the packets are split $this->source_engine = self::GOLDSOURCE_ENGINE; diff --git a/src/GameQ/Protocols/Cs2d.php b/src/GameQ/Protocols/Cs2d.php index 3e78d924..c63f7088 100644 --- a/src/GameQ/Protocols/Cs2d.php +++ b/src/GameQ/Protocols/Cs2d.php @@ -19,7 +19,6 @@ namespace GameQ\Protocols; use GameQ\Exception\ProtocolException; -use GameQ\Protocol; use GameQ\Buffer; use GameQ\Result; @@ -33,7 +32,6 @@ */ class Cs2d extends Protocol { - /** * Array of packets we want to query. */ @@ -104,7 +102,6 @@ class Cs2d extends Protocol */ public function processResponse(): mixed { - // We have a merged packet, try to split it back up if (count($this->packets_response) === 1) { // Temp buffer to make string manipulation easier @@ -185,8 +182,8 @@ protected function processDetails(Buffer $buffer) $result->add('lua_scripts', (int)$this->readFlag($serverFlags, 6)); // Read the rest of the buffer data - $result->add('servername', $this->convertToUtf8($buffer->readPascalString())); - $result->add('mapname', $this->convertToUtf8($buffer->readPascalString())); + $result->add('servername', Str::isoToUtf8($buffer->readPascalString())); + $result->add('mapname', Str::isoToUtf8($buffer->readPascalString())); $result->add('num_players', $buffer->readInt8()); $result->add('max_players', $buffer->readInt8()); $result->add('game_mode', $buffer->readInt8()); @@ -204,7 +201,6 @@ protected function processDetails(Buffer $buffer) */ protected function processPlayers(Buffer $buffer) { - // Set the result to a new result instance $result = new Result(); @@ -217,7 +213,7 @@ protected function processPlayers(Buffer $buffer) if (($id = $buffer->readInt8()) !== 0) { // Add the results $result->addPlayer('id', $id); - $result->addPlayer('name', $this->convertToUtf8($buffer->readPascalString())); + $result->addPlayer('name', Str::isoToUtf8($buffer->readPascalString())); $result->addPlayer('team', $buffer->readInt8()); $result->addPlayer('score', $buffer->readInt32()); $result->addPlayer('deaths', $buffer->readInt32()); diff --git a/src/GameQ/Protocols/Cscz.php b/src/GameQ/Protocols/Cscz.php index e3de7037..db8951cc 100644 --- a/src/GameQ/Protocols/Cscz.php +++ b/src/GameQ/Protocols/Cscz.php @@ -28,7 +28,6 @@ */ class Cscz extends Cs16 { - /** * String name of this protocol class */ diff --git a/src/GameQ/Protocols/Csgo.php b/src/GameQ/Protocols/Csgo.php index ea37ddae..6ca6bbf6 100644 --- a/src/GameQ/Protocols/Csgo.php +++ b/src/GameQ/Protocols/Csgo.php @@ -26,7 +26,6 @@ */ class Csgo extends Source { - /** * String name of this protocol class */ diff --git a/src/GameQ/Protocols/Dal.php b/src/GameQ/Protocols/Dal.php index 4e518b65..9117793b 100644 --- a/src/GameQ/Protocols/Dal.php +++ b/src/GameQ/Protocols/Dal.php @@ -26,7 +26,6 @@ */ class Dal extends Arkse { - /** * String name of this protocol class */ diff --git a/src/GameQ/Protocols/Dayz.php b/src/GameQ/Protocols/Dayz.php index 13de9655..97b4eaad 100644 --- a/src/GameQ/Protocols/Dayz.php +++ b/src/GameQ/Protocols/Dayz.php @@ -26,7 +26,6 @@ */ class Dayz extends Source { - /** * String name of this protocol class */ @@ -42,7 +41,6 @@ class Dayz extends Source */ public function findQueryPort(int $clientPort): int { - /* * Port layout: * 2302 - 27016 diff --git a/src/GameQ/Protocols/Dayzmod.php b/src/GameQ/Protocols/Dayzmod.php index 07be900e..6c7a8a69 100644 --- a/src/GameQ/Protocols/Dayzmod.php +++ b/src/GameQ/Protocols/Dayzmod.php @@ -27,7 +27,6 @@ */ class Dayzmod extends Armedassault2oa { - /** * String name of this protocol class */ diff --git a/src/GameQ/Protocols/Dod.php b/src/GameQ/Protocols/Dod.php index d99287e2..d5d1cc3a 100644 --- a/src/GameQ/Protocols/Dod.php +++ b/src/GameQ/Protocols/Dod.php @@ -28,7 +28,6 @@ */ class Dod extends Cs16 { - /** * String name of this protocol class */ diff --git a/src/GameQ/Protocols/Doom3.php b/src/GameQ/Protocols/Doom3.php index 4127efe9..bf96203e 100644 --- a/src/GameQ/Protocols/Doom3.php +++ b/src/GameQ/Protocols/Doom3.php @@ -146,7 +146,7 @@ protected function processServerInfo(Buffer $buffer) // Key / value pairs, delimited by an empty pair while ($buffer->getLength()) { $key = trim($buffer->readString()); - $val = $this->convertToUtf8(trim($buffer->readString())); + $val = Str::isoToUtf8(trim($buffer->readString())); // Something is empty so we are done if (empty($key) && empty($val)) { @@ -181,7 +181,7 @@ protected function processPlayers(Buffer $buffer) $result->addPlayer('ping', $buffer->readInt16()); $result->addPlayer('rate', $buffer->readInt32()); // Add player name, encoded - $result->addPlayer('name', $this->convertToUtf8(trim($buffer->readString()))); + $result->addPlayer('name', Str::isoToUtf8(trim($buffer->readString()))); // Increment $playerCount++; diff --git a/src/GameQ/Protocols/Egs.php b/src/GameQ/Protocols/Egs.php index d7b6c60d..a3c4fce5 100644 --- a/src/GameQ/Protocols/Egs.php +++ b/src/GameQ/Protocols/Egs.php @@ -27,7 +27,6 @@ */ class Egs extends Source { - /** * String name of this protocol class */ diff --git a/src/GameQ/Protocols/Eos.php b/src/GameQ/Protocols/Eos.php new file mode 100644 index 00000000..1f1d4c8a --- /dev/null +++ b/src/GameQ/Protocols/Eos.php @@ -0,0 +1,241 @@ +. + */ + +namespace GameQ\Protocols; + +use GameQ\Exception\ProtocolException; +use GameQ\Server; + +/** + * Epic Online Services Protocol Class + * + * Serves as a base class for EOS-powered games. + * + * @package GameQ\Protocols + * @author H.Rouatbi + */ +class Eos extends Http +{ + /** + * The protocol being used + */ + protected string $protocol = 'eos'; + + /** + * Longer string name of this protocol class + */ + protected string $name_long = 'Epic Online Services'; + + /** + * String name of this protocol class + */ + protected string $name = 'eos'; + + /** + * Grant type used for authentication + */ + protected string $grant_type = 'client_credentials'; + + /** + * Deployment ID for the game or application + */ + protected ?string $deployment_id = null; + + /** + * User ID for authentication + */ + protected ?string $user_id = null; + + /** + * User secret key for authentication + */ + protected ?string $user_secret = null; + + /** + * Holds the server ip so we can overwrite it back + */ + protected ?string $serverIp = null; + + /** + * Holds the server port query so we can overwrite it back + */ + protected ?string $serverPortQuery = null; + + /** + * Normalize some items + */ + protected array $normalize = [ + // General + 'general' => [ + // target => source + 'hostname' => 'hostname', + 'mapname' => 'mapname', + 'maxplayers' => 'maxplayers', + 'numplayers' => 'numplayers', + 'password' => 'password', + ] + ]; + + /** + * Process the response from the EOS API + * + * @throws ProtocolException + */ + public function processResponse(): array + { + $index = ($this->grant_type === 'external_auth') ? 2 : 1; + $server_data = isset($this->packets_response[$index]) ? json_decode($this->packets_response[$index], true) : null; + + $server_data = isset($server_data['sessions']) ? $server_data['sessions'] : null; + + // If no server data, throw an exception + if (empty($server_data)) { + throw new ProtocolException('No server data found. Server might be offline.'); + } + + return $server_data; + } + + /** + * Called before sending the request + */ + public function beforeSend(Server $server): void + { + $this->serverIp = $server->ip(); + $this->serverPortQuery = $server->portQuery(); + + // Authenticate and get the access token + $auth_token = $this->authenticate(); + + if (!$auth_token) { + return; + } + + // Query for server data + $this->queryServers($auth_token); + } + + /** + * Authenticate to get the access token + */ + protected function authenticate(): ?string + { + $auth_url = "https://api.epicgames.dev/auth/v1/oauth/token"; + $auth_headers = [ + 'Authorization: Basic ' . base64_encode("{$this->user_id}:{$this->user_secret}"), + 'Accept-Encoding: deflate, gzip', + 'Content-Type: application/x-www-form-urlencoded', + ]; + + $auth_postfields = "grant_type={$this->grant_type}&deployment_id={$this->deployment_id}"; + + if ($this->grant_type === 'external_auth') { + // Perform device authentication if necessary + $device_auth = $this->deviceAuthentication(); + if (!$device_auth) { + return null; + } + $auth_postfields .= "&external_auth_type=deviceid_access_token" + . "&external_auth_token={$device_auth['access_token']}" + . "&nonce=ABCHFA3qgUCJ1XTPAoGDEF&display_name=User"; + } + + // Make the request to get the access token + $response = $this->httpRequest($auth_url, $auth_headers, $auth_postfields); + + return isset($response['access_token']) ? $response['access_token'] : null; + } + + /** + * Query the EOS server for matchmaking data + */ + protected function queryServers(string $auth_token): ?array + { + $server_query_url = "https://api.epicgames.dev/matchmaking/v1/{$this->deployment_id}/filter"; + $query_headers = [ + "Authorization: Bearer {$auth_token}", + 'Accept: application/json', + 'Content-Type: application/json', + ]; + + $query_body = json_encode([ + 'criteria' => [ + [ + 'key' => 'attributes.ADDRESS_s', + 'op' => 'EQUAL', + 'value' => $this->serverIp, + ], + ], + 'maxResults' => 200, + ]); + + $response = $this->httpRequest($server_query_url, $query_headers, $query_body); + + return isset($response['sessions']) ? $response['sessions'] : null; + } + + /** + * Handle device authentication for external auth type + */ + protected function deviceAuthentication(): ?array + { + $device_auth_url = "https://api.epicgames.dev/auth/v1/accounts/deviceid"; + $device_auth_headers = [ + 'Authorization: Basic ' . base64_encode("{$this->user_id}:{$this->user_secret}"), + 'Accept-Encoding: deflate, gzip', + 'Content-Type: application/x-www-form-urlencoded', + ]; + + $device_auth_postfields = "deviceModel=PC"; + + return $this->httpRequest($device_auth_url, $device_auth_headers, $device_auth_postfields); + } + + /** + * Execute an HTTP request + */ + protected function httpRequest(string $url, array $headers, string $postfields): ?array + { + $ch = curl_init(); + + curl_setopt($ch, CURLOPT_URL, $url); + curl_setopt($ch, CURLOPT_POST, 1); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); + curl_setopt($ch, CURLOPT_POSTFIELDS, $postfields); + + $response = curl_exec($ch); + + if (!$response) { + return null; + } + + $this->packets_response[] = $response; + + return json_decode($response, true); + } + + /** + * Safely retrieves an attribute from an array or returns a default value. + */ + protected function getAttribute(array $attributes, string $key, $default = null): mixed + { + return isset($attributes[$key]) ? $attributes[$key] : $default; + } +} diff --git a/src/GameQ/Protocols/Etqw.php b/src/GameQ/Protocols/Etqw.php index 731210ef..015239d3 100644 --- a/src/GameQ/Protocols/Etqw.php +++ b/src/GameQ/Protocols/Etqw.php @@ -30,7 +30,6 @@ */ class Etqw extends Protocol { - /** * Array of packets we want to look up. * Each key should correspond to a defined method in this or a parent class @@ -109,9 +108,7 @@ public function processResponse(): mixed return $this->{$this->responses[$response_type]}($buffer); } - /* - * Internal methods - */ + // Internal methods /** * Handle processing the status response diff --git a/src/GameQ/Protocols/Ffe.php b/src/GameQ/Protocols/Ffe.php index f91d3dd7..68b93b4e 100644 --- a/src/GameQ/Protocols/Ffe.php +++ b/src/GameQ/Protocols/Ffe.php @@ -26,7 +26,6 @@ */ class Ffe extends Source { - /** * String name of this protocol class */ diff --git a/src/GameQ/Protocols/Ffow.php b/src/GameQ/Protocols/Ffow.php index 4921dba7..a14be6a9 100644 --- a/src/GameQ/Protocols/Ffow.php +++ b/src/GameQ/Protocols/Ffow.php @@ -189,8 +189,7 @@ protected function processRules(Buffer $buffer) // Check for map if (str_contains($key, "Map:")) { $result->addSub("maplist", "name", $buffer->readString()); - } else // Regular rule - { + } else { // Regular rule $result->add($key, $buffer->readString()); } } diff --git a/src/GameQ/Protocols/Gamespy.php b/src/GameQ/Protocols/Gamespy.php index a092534f..4fef389e 100644 --- a/src/GameQ/Protocols/Gamespy.php +++ b/src/GameQ/Protocols/Gamespy.php @@ -21,6 +21,7 @@ use GameQ\Exception\ProtocolException; use GameQ\Protocol; use GameQ\Buffer; +use GameQ\Helpers\Str; use GameQ\Result; /** @@ -30,7 +31,6 @@ */ class Gamespy extends Protocol { - /** * Array of packets we want to look up. * Each key should correspond to a defined method in this or a parent class @@ -92,9 +92,7 @@ public function processResponse(): mixed return $this->processStatus(new Buffer(implode('', $processed))); } - /* - * Internal methods - */ + // Internal methods /** * Handle processing the status buffer @@ -143,7 +141,7 @@ protected function processStatus(Buffer $buffer) if (str_starts_with($key, 'playername')) { $numPlayers++; } - $result->addPlayer(substr($key, 0, $suffix), $this->convertToUtf8($val)); + $result->addPlayer(substr($key, 0, $suffix), Str::isoToUtf8($val)); } } else { // Regular variable so just add the value. diff --git a/src/GameQ/Protocols/Gamespy2.php b/src/GameQ/Protocols/Gamespy2.php index 6a718f20..26657951 100644 --- a/src/GameQ/Protocols/Gamespy2.php +++ b/src/GameQ/Protocols/Gamespy2.php @@ -21,20 +21,20 @@ use GameQ\Exception\ProtocolException; use GameQ\Protocol; use GameQ\Buffer; +use GameQ\Helpers\Str; use GameQ\Result; /** * GameSpy2 Protocol class * * Given the ability for non utf-8 characters to be used as hostnames, player names, etc... this - * version returns all strings utf-8 encoded (utf8_encode). To access the proper version of a - * string response you must use utf8_decode() on the specific response. + * version returns all strings utf-8 encoded. To access the proper version of a + * string response you must use Str::utf8ToIso() on the specific response. * * @author Austin Bischoff */ class Gamespy2 extends Protocol { - /** * Define the state of this class */ @@ -105,7 +105,6 @@ class Gamespy2 extends Protocol */ public function processResponse(): mixed { - // Will hold the packets after sorting $packets = []; @@ -143,9 +142,7 @@ public function processResponse(): mixed return $results; } - /* - * Internal methods - */ + // Internal methods /** * Handles processing the details data into a usable format @@ -156,7 +153,6 @@ public function processResponse(): mixed */ protected function processDetails(Buffer $buffer) { - // Set the result to a new result instance $result = new Result(); @@ -166,7 +162,7 @@ protected function processDetails(Buffer $buffer) if ($key === '') { break; } - $result->add($key, $this->convertToUtf8($buffer->readString())); + $result->add($key, Str::isoToUtf8($buffer->readString())); } return $result->fetch(); @@ -181,7 +177,6 @@ protected function processDetails(Buffer $buffer) */ protected function processPlayers(Buffer $buffer) { - // Set the result to a new result instance $result = new Result(); @@ -204,7 +199,6 @@ protected function processPlayers(Buffer $buffer) */ protected function parsePlayerTeam(string $dataType, Buffer $buffer, Result $result) { - // Do count $result->add('num_' . $dataType, $buffer->readInt8()); @@ -231,7 +225,7 @@ protected function parsePlayerTeam(string $dataType, Buffer $buffer, Result $res // Get the values while ($buffer->getLength() > 4) { foreach ($varNames as $varName) { - $result->addSub($dataType, $this->convertToUtf8($varName), $this->convertToUtf8($buffer->readString())); + $result->addSub($dataType, Str::isoToUtf8($varName), Str::isoToUtf8($buffer->readString())); } if ($buffer->lookAhead() === "\x00") { $buffer->skip(); diff --git a/src/GameQ/Protocols/Gamespy3.php b/src/GameQ/Protocols/Gamespy3.php index 71a7fb28..315f9c08 100644 --- a/src/GameQ/Protocols/Gamespy3.php +++ b/src/GameQ/Protocols/Gamespy3.php @@ -21,20 +21,20 @@ use GameQ\Exception\ProtocolException; use GameQ\Protocol; use GameQ\Buffer; +use GameQ\Helpers\Str; use GameQ\Result; /** * GameSpy3 Protocol class * * Given the ability for non utf-8 characters to be used as hostnames, player names, etc... this - * version returns all strings utf-8 encoded (utf8_encode). To access the proper version of a - * string response you must use utf8_decode() on the specific response. + * version returns all strings utf-8 encoded. To access the proper version of a + * string response you must use Str::utf8ToIso() on the specific response. * * @author Austin Bischoff */ class Gamespy3 extends Protocol { - /** * Array of packets we want to look up. * Each key should correspond to a defined method in this or a parent class @@ -103,7 +103,6 @@ public function challengeParseAndApply(Buffer $challenge_buffer): bool */ public function processResponse(): mixed { - // Holds the processed packets $processed = []; @@ -162,16 +161,13 @@ public function processResponse(): mixed return $result->fetch(); } - /* - * Internal methods - */ + // Internal methods /** * Handles cleaning up packets since the responses can be a bit "dirty" */ protected function cleanPackets(array $packets = []): array { - // Get the number of packets $packetCount = count($packets); @@ -230,7 +226,7 @@ protected function processDetails(Buffer $buffer, Result $result): void if ($key === '') { break; } - $result->add($key, $this->convertToUtf8($buffer->readString())); + $result->add($key, Str::isoToUtf8($buffer->readString())); } } @@ -304,7 +300,7 @@ protected function processPlayersAndTeams(Buffer $buffer, Result $result): void break; } // Add the value to the proper item in the correct group - $result->addSub($item_group, $item_type, $this->convertToUtf8(trim($val))); + $result->addSub($item_group, $item_type, Str::isoToUtf8(trim($val))); } // Unset our buffer unset($buf_temp); diff --git a/src/GameQ/Protocols/Had2.php b/src/GameQ/Protocols/Had2.php index e65bcd4e..c1fb3d6c 100644 --- a/src/GameQ/Protocols/Had2.php +++ b/src/GameQ/Protocols/Had2.php @@ -25,7 +25,6 @@ */ class Had2 extends Gamespy2 { - /** * String name of this protocol class */ diff --git a/src/GameQ/Protocols/Halo.php b/src/GameQ/Protocols/Halo.php index d1baf0be..adee9e3e 100644 --- a/src/GameQ/Protocols/Halo.php +++ b/src/GameQ/Protocols/Halo.php @@ -25,7 +25,6 @@ */ class Halo extends Gamespy2 { - /** * String name of this protocol class */ diff --git a/src/GameQ/Protocols/Justcause3.php b/src/GameQ/Protocols/Justcause3.php index cdc48409..2729fea7 100644 --- a/src/GameQ/Protocols/Justcause3.php +++ b/src/GameQ/Protocols/Justcause3.php @@ -26,7 +26,6 @@ */ class Justcause3 extends Source { - /** * String name of this protocol class */ diff --git a/src/GameQ/Protocols/Killingfloor.php b/src/GameQ/Protocols/Killingfloor.php index b5660884..3827f30b 100644 --- a/src/GameQ/Protocols/Killingfloor.php +++ b/src/GameQ/Protocols/Killingfloor.php @@ -30,7 +30,6 @@ */ class Killingfloor extends Unreal2 { - /** * String name of this protocol class */ @@ -59,7 +58,6 @@ class Killingfloor extends Unreal2 */ protected function processDetails(Buffer $buffer) { - // Set the result to a new result instance $result = new Result(); @@ -72,10 +70,10 @@ protected function processDetails(Buffer $buffer) $buffer->skip(); // Read as a regular string since the length is incorrect (what we skipped earlier) - $result->add('servername', $this->convertToUtf8($buffer->readString())); + $result->add('servername', Str::isoToUtf8($buffer->readString())); // The rest is read as normal - $result->add('mapname', $this->convertToUtf8($buffer->readPascalString(1))); + $result->add('mapname', Str::isoToUtf8($buffer->readPascalString(1))); $result->add('gametype', $buffer->readPascalString(1)); $result->add('numplayers', $buffer->readInt32()); $result->add('maxplayers', $buffer->readInt32()); diff --git a/src/GameQ/Protocols/Killingfloor2.php b/src/GameQ/Protocols/Killingfloor2.php index c3203841..44324f71 100644 --- a/src/GameQ/Protocols/Killingfloor2.php +++ b/src/GameQ/Protocols/Killingfloor2.php @@ -26,7 +26,6 @@ */ class Killingfloor2 extends Source { - /** * String name of this protocol class */ diff --git a/src/GameQ/Protocols/Lhmp.php b/src/GameQ/Protocols/Lhmp.php index 488385b0..11d794cb 100644 --- a/src/GameQ/Protocols/Lhmp.php +++ b/src/GameQ/Protocols/Lhmp.php @@ -32,7 +32,6 @@ */ class Lhmp extends Protocol { - /** * Array of packets we want to look up. * Each key should correspond to a defined method in this or a parent class @@ -136,9 +135,7 @@ public function processResponse(): mixed return $results; } - /* - * Internal methods - */ + // Internal methods /** * Handles processing the details data into a usable format @@ -148,7 +145,6 @@ public function processResponse(): mixed */ protected function processDetails(Buffer $buffer) { - // Set the result to a new result instance $result = new Result(); @@ -156,10 +152,10 @@ protected function processDetails(Buffer $buffer) $result->add('password', $buffer->readString()); $result->add('numplayers', $buffer->readInt16()); $result->add('maxplayers', $buffer->readInt16()); - $result->add('servername', $this->convertToUtf8($buffer->readPascalString())); + $result->add('servername', Str::isoToUtf8($buffer->readPascalString())); $result->add('gamemode', $buffer->readPascalString()); - $result->add('website', $this->convertToUtf8($buffer->readPascalString())); - $result->add('mapname', $this->convertToUtf8($buffer->readPascalString())); + $result->add('website', Str::isoToUtf8($buffer->readPascalString())); + $result->add('mapname', Str::isoToUtf8($buffer->readPascalString())); return $result->fetch(); } @@ -172,7 +168,6 @@ protected function processDetails(Buffer $buffer) */ protected function processPlayers(Buffer $buffer) { - // Set the result to a new result instance $result = new Result(); @@ -185,7 +180,7 @@ protected function processPlayers(Buffer $buffer) if (($id = $buffer->readInt16()) !== 0) { // Add the results $result->addPlayer('id', $id); - $result->addPlayer('name', $this->convertToUtf8($buffer->readPascalString())); + $result->addPlayer('name', Str::isoToUtf8($buffer->readPascalString())); } } diff --git a/src/GameQ/Protocols/M2mp.php b/src/GameQ/Protocols/M2mp.php index bc436273..d9c58df3 100644 --- a/src/GameQ/Protocols/M2mp.php +++ b/src/GameQ/Protocols/M2mp.php @@ -124,6 +124,7 @@ public function processResponse(): mixed * Process the status response * * @return array + * @throws ProtocolException */ protected function processStatus(Buffer $buffer) { @@ -182,7 +183,7 @@ protected function processPlayers(Buffer $buffer) // Only player name information is available // Add player name, encoded - $result->addPlayer('name', $this->convertToUtf8(trim($buffer->readPascalString(1, true)))); + $result->addPlayer('name', Str::isoToUtf8(trim($buffer->readPascalString(1, true)))); } return $result->fetch(); diff --git a/src/GameQ/Protocols/Minecraft.php b/src/GameQ/Protocols/Minecraft.php index d1fa4fa5..2dc6d28b 100644 --- a/src/GameQ/Protocols/Minecraft.php +++ b/src/GameQ/Protocols/Minecraft.php @@ -40,7 +40,6 @@ */ class Minecraft extends Gamespy3 { - /** * String name of this protocol class */ diff --git a/src/GameQ/Protocols/Minecraftbe.php b/src/GameQ/Protocols/Minecraftbe.php index 298238a9..0469212d 100644 --- a/src/GameQ/Protocols/Minecraftbe.php +++ b/src/GameQ/Protocols/Minecraftbe.php @@ -27,7 +27,6 @@ */ class Minecraftbe extends Raknet { - /** * String name of this protocol class */ diff --git a/src/GameQ/Protocols/Minecraftpe.php b/src/GameQ/Protocols/Minecraftpe.php index dc0496df..1a6fe826 100644 --- a/src/GameQ/Protocols/Minecraftpe.php +++ b/src/GameQ/Protocols/Minecraftpe.php @@ -27,7 +27,6 @@ */ class Minecraftpe extends Minecraft { - /** * String name of this protocol class */ diff --git a/src/GameQ/Protocols/Mordhau.php b/src/GameQ/Protocols/Mordhau.php index dec895ba..68300e7a 100644 --- a/src/GameQ/Protocols/Mordhau.php +++ b/src/GameQ/Protocols/Mordhau.php @@ -26,7 +26,6 @@ */ class Mordhau extends Source { - /** * String name of this protocol class */ diff --git a/src/GameQ/Protocols/Mta.php b/src/GameQ/Protocols/Mta.php index da8d5282..80ad6f3c 100644 --- a/src/GameQ/Protocols/Mta.php +++ b/src/GameQ/Protocols/Mta.php @@ -28,7 +28,6 @@ */ class Mta extends Ase { - /** * String name of this protocol class */ diff --git a/src/GameQ/Protocols/Mumble.php b/src/GameQ/Protocols/Mumble.php index b679d28e..3f9e58e9 100644 --- a/src/GameQ/Protocols/Mumble.php +++ b/src/GameQ/Protocols/Mumble.php @@ -33,7 +33,6 @@ */ class Mumble extends Protocol { - /** * Array of packets we want to look up. * Each key should correspond to a defined method in this or a parent class @@ -144,9 +143,7 @@ public function processResponse(): mixed return $result->fetch(); } - /* - * Internal methods - */ + // Internal methods /** * Handles processing the the channels and user info diff --git a/src/GameQ/Protocols/Openttd.php b/src/GameQ/Protocols/Openttd.php index 623b256a..e6bc3bb8 100644 --- a/src/GameQ/Protocols/Openttd.php +++ b/src/GameQ/Protocols/Openttd.php @@ -123,7 +123,7 @@ protected function processServerInfo(Buffer $buffer) switch ($protocol_version) { case 4: - $num_grfs = $buffer->readInt8(); #number of grfs + $num_grfs = $buffer->readInt8(); //number of grfs $result->add('num_grfs', $num_grfs); //$buffer->skip ($num_grfs * 20); #skip grfs id and md5 hash @@ -131,16 +131,18 @@ protected function processServerInfo(Buffer $buffer) $result->add('grfs_'.$i.'_ID', strtoupper(bin2hex($buffer->read(4)))); $result->add('grfs_'.$i.'_MD5', strtoupper(bin2hex($buffer->read(16)))); } - // No break, cascades all the down even if case is meet + // no break, cascades all the down even if case is meet case 3: $result->add('game_date', $buffer->readInt32()); $result->add('start_date', $buffer->readInt32()); // Cascades all the way down even if case is meet + // no break case 2: $result->add('companies_max', $buffer->readInt8()); $result->add('companies_on', $buffer->readInt8()); $result->add('spectators_max', $buffer->readInt8()); // Cascades all the way down even if case is meet + // no break case 1: $result->add('hostname', $buffer->readString()); $result->add('version', $buffer->readString()); @@ -154,7 +156,7 @@ protected function processServerInfo(Buffer $buffer) $result->add('clients', $buffer->readInt8()); $result->add('spectators', $buffer->readInt8()); if ($protocol_version < 3) { - $days = ( 365 * 1920 + 1920 / 4 - 1920 / 100 + 1920 / 400 ); + $days = (365 * 1920 + 1920 / 4 - 1920 / 100 + 1920 / 400); $result->add('game_date', $buffer->readInt16() + $days); $result->add('start_date', $buffer->readInt16() + $days); } diff --git a/src/GameQ/Protocols/Pixark.php b/src/GameQ/Protocols/Pixark.php index 69d47d7d..4c5873e6 100644 --- a/src/GameQ/Protocols/Pixark.php +++ b/src/GameQ/Protocols/Pixark.php @@ -26,7 +26,6 @@ */ class Pixark extends Arkse { - /** * String name of this protocol class */ diff --git a/src/GameQ/Protocols/Projectrealitybf2.php b/src/GameQ/Protocols/Projectrealitybf2.php index 271fc43a..a9fe40c8 100644 --- a/src/GameQ/Protocols/Projectrealitybf2.php +++ b/src/GameQ/Protocols/Projectrealitybf2.php @@ -28,7 +28,6 @@ */ class Projectrealitybf2 extends Bf2 { - /** * String name of this protocol class */ diff --git a/src/GameQ/Protocols/Quake2.php b/src/GameQ/Protocols/Quake2.php index 01913e73..007b8565 100644 --- a/src/GameQ/Protocols/Quake2.php +++ b/src/GameQ/Protocols/Quake2.php @@ -134,7 +134,7 @@ protected function processServerInfo(Buffer $buffer) // Add result $result->add( trim($buffer->readString('\\')), - $this->convertToUtf8(trim($buffer->readStringMulti(['\\', "\x0a"]))) + Str::isoToUtf8(trim($buffer->readStringMulti(['\\', "\x0a"]))) ); } @@ -171,7 +171,7 @@ protected function processPlayers(Buffer $buffer) $playerInfo->skip(); // Add player name, encoded - $result->addPlayer('name', $this->convertToUtf8(trim(($playerInfo->readString('"'))))); + $result->addPlayer('name', Str::isoToUtf8(trim(($playerInfo->readString('"'))))); // Skip first " $playerInfo->skip(2); diff --git a/src/GameQ/Protocols/Quake3.php b/src/GameQ/Protocols/Quake3.php index 6f2c36ed..e6c1bed2 100644 --- a/src/GameQ/Protocols/Quake3.php +++ b/src/GameQ/Protocols/Quake3.php @@ -98,6 +98,10 @@ public function processResponse(): mixed return $this->{$this->responses[$header]}($buffer); } + /** + * @return array + * @throws ProtocolException + */ protected function processStatus(Buffer $buffer) { // We need to split the data and offload @@ -127,7 +131,7 @@ protected function processServerInfo(Buffer $buffer) // Add result $result->add( trim($buffer->readString('\\')), - $this->convertToUtf8(trim($buffer->readStringMulti(['\\', "\x0a"]))) + Str::isoToUtf8(trim($buffer->readStringMulti(['\\', "\x0a"]))) ); } @@ -171,7 +175,7 @@ protected function processPlayers(Buffer $buffer) } // Add player name, encoded - $result->addPlayer('name', $this->convertToUtf8(trim($buffer->readString('"')))); + $result->addPlayer('name', Str::isoToUtf8(trim($buffer->readString('"')))); // Burn ending delimiter $buffer->read(); diff --git a/src/GameQ/Protocols/Quake4.php b/src/GameQ/Protocols/Quake4.php index 5080764b..73689bfd 100644 --- a/src/GameQ/Protocols/Quake4.php +++ b/src/GameQ/Protocols/Quake4.php @@ -63,7 +63,7 @@ protected function processPlayers(Buffer $buffer) $result->addPlayer('ping', $buffer->readInt16()); $result->addPlayer('rate', $buffer->readInt32()); // Add player name, encoded - $result->addPlayer('name', $this->convertToUtf8(trim($buffer->readString()))); + $result->addPlayer('name', Str::isoToUtf8(trim($buffer->readString()))); $result->addPlayer('clantag', $buffer->readString()); // Increment $playerCount++; diff --git a/src/GameQ/Protocols/Risingstorm2.php b/src/GameQ/Protocols/Risingstorm2.php index feb4a4e0..5bee0674 100644 --- a/src/GameQ/Protocols/Risingstorm2.php +++ b/src/GameQ/Protocols/Risingstorm2.php @@ -26,7 +26,6 @@ */ class Risingstorm2 extends Source { - /** * String name of this protocol class */ diff --git a/src/GameQ/Protocols/Rust.php b/src/GameQ/Protocols/Rust.php index 30cb3415..c3ece2ae 100644 --- a/src/GameQ/Protocols/Rust.php +++ b/src/GameQ/Protocols/Rust.php @@ -29,7 +29,6 @@ */ class Rust extends Source { - /** * String name of this protocol class */ diff --git a/src/GameQ/Protocols/Samp.php b/src/GameQ/Protocols/Samp.php index cbeb073d..526c34a2 100644 --- a/src/GameQ/Protocols/Samp.php +++ b/src/GameQ/Protocols/Samp.php @@ -20,6 +20,7 @@ use GameQ\Protocol; use GameQ\Buffer; +use GameQ\Helpers\Str; use GameQ\Result; use GameQ\Server; use GameQ\Exception\ProtocolException; @@ -34,7 +35,6 @@ */ class Samp extends Protocol { - /** * Array of packets we want to look up. * Each key should correspond to a defined method in this or a parent class @@ -127,7 +127,6 @@ public function beforeSend(Server $server): void */ public function processResponse(): mixed { - // Results that will be returned $results = []; @@ -169,9 +168,7 @@ public function processResponse(): mixed return $results; } - /* - * Internal methods - */ + // Internal methods /** * Handles processing the server status data @@ -181,7 +178,6 @@ public function processResponse(): mixed */ protected function processStatus(Buffer $buffer) { - // Set the result to a new result instance $result = new Result(); @@ -194,7 +190,7 @@ protected function processStatus(Buffer $buffer) $result->add('max_players', $buffer->readInt16()); // These are read differently for these last 3 - $result->add('servername', $this->convertToUtf8($buffer->read($buffer->readInt32()))); + $result->add('servername', Str::isoToUtf8($buffer->read($buffer->readInt32()))); $result->add('gametype', $buffer->read($buffer->readInt32())); $result->add('language', $buffer->read($buffer->readInt32())); @@ -209,7 +205,6 @@ protected function processStatus(Buffer $buffer) */ protected function processPlayers(Buffer $buffer) { - // Set the result to a new result instance $result = new Result(); @@ -219,7 +214,7 @@ protected function processPlayers(Buffer $buffer) // Run until we run out of buffer while ($buffer->getLength()) { $result->addPlayer('id', $buffer->readInt8()); - $result->addPlayer('name', $this->convertToUtf8($buffer->readPascalString())); + $result->addPlayer('name', Str::isoToUtf8($buffer->readPascalString())); $result->addPlayer('score', $buffer->readInt32()); $result->addPlayer('ping', $buffer->readInt32()); } @@ -235,7 +230,6 @@ protected function processPlayers(Buffer $buffer) */ protected function processRules(Buffer $buffer) { - // Set the result to a new result instance $result = new Result(); diff --git a/src/GameQ/Protocols/Serioussam.php b/src/GameQ/Protocols/Serioussam.php index 5a192866..ad68512a 100644 --- a/src/GameQ/Protocols/Serioussam.php +++ b/src/GameQ/Protocols/Serioussam.php @@ -25,7 +25,6 @@ */ class Serioussam extends Gamespy { - /** * String name of this protocol class */ diff --git a/src/GameQ/Protocols/Ship.php b/src/GameQ/Protocols/Ship.php index be73c911..33749f9e 100644 --- a/src/GameQ/Protocols/Ship.php +++ b/src/GameQ/Protocols/Ship.php @@ -32,7 +32,6 @@ */ class Ship extends Source { - /** * String name of this protocol class */ @@ -53,7 +52,6 @@ class Ship extends Source */ protected function processPlayers(Buffer $buffer) { - // Set the result to a new result instance $result = new Result(); diff --git a/src/GameQ/Protocols/Soldat.php b/src/GameQ/Protocols/Soldat.php index 68fc9086..6074c936 100644 --- a/src/GameQ/Protocols/Soldat.php +++ b/src/GameQ/Protocols/Soldat.php @@ -28,7 +28,6 @@ */ class Soldat extends Ase { - /** * String name of this protocol class */ diff --git a/src/GameQ/Protocols/Source.php b/src/GameQ/Protocols/Source.php index 7b635b82..7c17ec7a 100644 --- a/src/GameQ/Protocols/Source.php +++ b/src/GameQ/Protocols/Source.php @@ -118,7 +118,6 @@ class Source extends Protocol */ public function challengeParseAndApply(Buffer $challenge_buffer): bool { - // Skip the header $challenge_buffer->skip(4); @@ -206,22 +205,18 @@ public function processResponse(): mixed return $results; } - /* - * Internal methods - */ + // Internal methods /** * Process the split packets and decompress if necessary * * @param $packet_id * @param array $packets - * * @return string * @throws ProtocolException */ protected function processPackets($packet_id, array $packets = []) { - // Init array so we can order $packs = []; @@ -316,7 +311,6 @@ protected function processPackets($packet_id, array $packets = []) */ protected function processDetails(Buffer $buffer) { - // Set the result to a new result instance $result = new Result(); @@ -385,7 +379,6 @@ protected function processDetails(Buffer $buffer) */ protected function processDetailsGoldSource(Buffer $buffer) { - // Set the result to a new result instance $result = new Result(); @@ -429,7 +422,6 @@ protected function processDetailsGoldSource(Buffer $buffer) */ protected function processPlayers(Buffer $buffer) { - // Set the result to a new result instance $result = new Result(); @@ -463,7 +455,6 @@ protected function processPlayers(Buffer $buffer) */ protected function processRules(Buffer $buffer) { - // Set the result to a new result instance $result = new Result(); diff --git a/src/GameQ/Protocols/Squad.php b/src/GameQ/Protocols/Squad.php index d35396eb..077e9af8 100644 --- a/src/GameQ/Protocols/Squad.php +++ b/src/GameQ/Protocols/Squad.php @@ -28,7 +28,6 @@ */ class Squad extends Source { - /** * String name of this protocol class */ diff --git a/src/GameQ/Protocols/Starmade.php b/src/GameQ/Protocols/Starmade.php index d9394fec..71cadc66 100644 --- a/src/GameQ/Protocols/Starmade.php +++ b/src/GameQ/Protocols/Starmade.php @@ -34,7 +34,6 @@ */ class Starmade extends Protocol { - /** * Array of packets we want to query. */ @@ -90,7 +89,6 @@ class Starmade extends Protocol */ public function processResponse(): mixed { - // Implode the packets, not sure if there is any split logic for multiple packets $buffer = new Buffer(implode('', $this->packets_response), Buffer::NUMBER_TYPE_BIGENDIAN); @@ -142,7 +140,6 @@ public function processResponse(): mixed */ protected function parseServerParameters(Buffer $buffer) { - // Init the parsed data array $parsed = []; @@ -160,17 +157,17 @@ protected function parseServerParameters(Buffer $buffer) $parsed[$i] = $buffer->readInt32Signed(); break; - // 64-bit int + // 64-bit int case 2: $parsed[$i] = $buffer->readInt64(); break; - // Float + // Float case 3: $parsed[$i] = $buffer->readFloat32(); break; - // String + // String case 4: // The first 2 bytes are the string length $strLength = $buffer->readInt16Signed(); @@ -181,22 +178,22 @@ protected function parseServerParameters(Buffer $buffer) unset($strLength); break; - // Boolean + // Boolean case 5: $parsed[$i] = (bool)$buffer->readInt8Signed(); break; - // 8-bit int + // 8-bit int case 6: $parsed[$i] = $buffer->readInt8Signed(); break; - // 16-bit int + // 16-bit int case 7: $parsed[$i] = $buffer->readInt16Signed(); break; - // Array + // Array case 8: // Not implemented throw new ProtocolException("StarMade array parsing is not implemented!"); diff --git a/src/GameQ/Protocols/Stationeers.php b/src/GameQ/Protocols/Stationeers.php new file mode 100644 index 00000000..2296dbcd --- /dev/null +++ b/src/GameQ/Protocols/Stationeers.php @@ -0,0 +1,178 @@ +. + */ + +namespace GameQ\Protocols; + +use GameQ\Exception\ProtocolException; +use GameQ\Helpers\Arr; +use GameQ\Result; +use GameQ\Server; + +/** + * Stationeers Protocol Class + * + * **Note:** This protocol does use the offical, centralized "Metaserver" to query the list of all available servers. This + * is effectively a host controlled by a third party which could interfere with the functionality of this protocol. + * + * @author Austin Bischoff + */ +class Stationeers extends Http +{ + /** + * The host (address) of the "Metaserver" to query to get the list of servers + */ + const SERVER_LIST_HOST = '40.82.200.175'; + + /** + * The port of the "Metaserver" to query to get the list of servers + */ + const SERVER_LIST_PORT = 8081; + + /** + * Packets to send + */ + protected array $packets = [ + self::PACKET_STATUS => "GET /list HTTP/1.0\r\nAccept: */*\r\n\r\n", + ]; + + /** + * The protocol being used + */ + protected string $protocol = 'stationeers'; + + /** + * String name of this protocol class + */ + protected string $name = 'stationeers'; + + /** + * Longer string name of this protocol class + */ + protected string $name_long = "Stationeers"; + + /** + * Normalize some items + */ + protected array $normalize = [ + // General + 'general' => [ + // target => source + 'dedicated' => 'dedicated', + 'hostname' => 'hostname', + 'mapname' => 'map', + 'maxplayers' => 'maxplayers', + 'numplayers' => 'numplayers', + 'password' => 'password', + ], + ]; + + /** + * Holds the real ip so we can overwrite it back + * + * **NOTE:** These is used during the runtime. + */ + protected ?string $realIp = null; + + /** + * Holds the real port so we can overwrite it back + * + * **NOTE:** These is used during the runtime. + * + * @var int + */ + protected ?string $realPortQuery = null; + + /** + * Handle changing the call to call a central server rather than the server directly + */ + public function beforeSend(Server $server): void + { + // Determine the connection information to be used for the "Metaserver" + $metaServerHost = $server->getOption('meta_host') ? $server->getOption('meta_host') : self::SERVER_LIST_HOST; + $metaServerPort = $server->getOption('meta_port') ? $server->getOption('meta_port') : self::SERVER_LIST_PORT; + + // Save the real connection information and overwrite the properties with the "Metaserver" connection information + Arr::shift($this->realIp, $server->ip, $metaServerHost); + Arr::shift($this->realPortQuery, $server->port_query, $metaServerPort); + } + + /** + * Process the response + * + * @throws ProtocolException + */ + public function processResponse(): array + { + // Ensure there is a reply from the "Metaserver" + if (empty($this->packets_response)) { + return []; + } + + // Implode and rip out the JSON + preg_match('/\{(.*)\}/ms', implode('', $this->packets_response), $matches); + + // Return should be JSON, let's validate + if (!isset($matches[0]) || ($json = json_decode($matches[0])) === null) { + throw new ProtocolException(__METHOD__ . " JSON response from Stationeers Metaserver is invalid."); + } + + // By default no server is found + $server = null; + + // Find the server on this list by iterating over the entire list. + foreach ($json->GameSessions as $serverEntry) { + // Server information passed matches an entry on this list + if ($serverEntry->Address === $this->realIp && (int)$serverEntry->Port === $this->realPortQuery) { + $server = $serverEntry; + break; + } + } + + // Send to the garbage collector + unset($matches, $serverEntry, $json); + + // Ensure the provided Server has been found in the list provided by the "Metaserver" + if (! $server) { + throw new ProtocolException(sprintf( + '%s Unable to find the server "%s:%d" in the Stationeer Metaservers server list', + __METHOD__, + $this->realIp, + $this->realPortQuery + )); + } + + // Build the Result from the parsed JSON + $result = new Result(); + $result->add('dedicated', 1); // Server is always dedicated + $result->add('hostname', $server->Name); + $result->add('gq_address', $server->Address); + $result->add('gq_port_query', $server->Port); + $result->add('version', $server->Version); + $result->add('map', $server->MapName); + $result->add('uptime', $server->UpTime); + $result->add('password', (int)$server->Password); + $result->add('numplayers', $server->Players); + $result->add('maxplayers', $server->MaxPlayers); + $result->add('type', $server->Type); + + // Send to the garbage collector + unset($server); + + return $result->fetch(); + } +} diff --git a/src/GameQ/Protocols/Teamspeak2.php b/src/GameQ/Protocols/Teamspeak2.php index 58ad5e91..44f6a5f9 100644 --- a/src/GameQ/Protocols/Teamspeak2.php +++ b/src/GameQ/Protocols/Teamspeak2.php @@ -20,6 +20,7 @@ use GameQ\Protocol; use GameQ\Buffer; +use GameQ\Helpers\Str; use GameQ\Result; use GameQ\Server; use GameQ\Exception\ProtocolException; @@ -36,7 +37,6 @@ */ class Teamspeak2 extends Protocol { - /** * Array of packets we want to look up. * Each key should correspond to a defined method in this or a parent class @@ -104,7 +104,6 @@ class Teamspeak2 extends Protocol */ public function beforeSend(Server $server): void { - // Check to make sure we have a query_port because it is required if (!isset($this->options[Server::SERVER_OPTIONS_QUERY_PORT]) || empty($this->options[Server::SERVER_OPTIONS_QUERY_PORT]) @@ -127,7 +126,6 @@ public function beforeSend(Server $server): void */ public function processResponse(): mixed { - // Make a new buffer out of all of the packets $buffer = new Buffer(implode('', $this->packets_response)); @@ -173,9 +171,7 @@ public function processResponse(): mixed return $result->fetch(); } - /* - * Internal methods - */ + // Internal methods /** @@ -200,7 +196,7 @@ protected function processDetails(string $data, Result $result) list($key, $value) = explode('=', $row, 2); // Add this to the result - $result->add($key, $this->convertToUtf8($value)); + $result->add($key, Str::isoToUtf8($value)); } unset($buffer, $row, $key, $value); @@ -229,7 +225,7 @@ protected function processChannels(string $data, Result $result) foreach ($data as $key => $value) { // Now add the data to the result - $result->addTeam($key, $this->convertToUtf8($value)); + $result->addTeam($key, Str::isoToUtf8($value)); } } @@ -259,7 +255,7 @@ protected function processPlayers(string $data, Result $result) foreach ($data as $key => $value) { // Now add the data to the result - $result->addPlayer($key, $this->convertToUtf8($value)); + $result->addPlayer($key, Str::isoToUtf8($value)); } } diff --git a/src/GameQ/Protocols/Teamspeak3.php b/src/GameQ/Protocols/Teamspeak3.php index 2176c201..f0ef39f5 100644 --- a/src/GameQ/Protocols/Teamspeak3.php +++ b/src/GameQ/Protocols/Teamspeak3.php @@ -20,6 +20,7 @@ use GameQ\Protocol; use GameQ\Buffer; +use GameQ\Helpers\Str; use GameQ\Result; use GameQ\Server; use GameQ\Exception\ProtocolException; @@ -36,7 +37,6 @@ */ class Teamspeak3 extends Protocol { - /** * Array of packets we want to look up. * Each key should correspond to a defined method in this or a parent class @@ -104,7 +104,6 @@ class Teamspeak3 extends Protocol */ public function beforeSend(Server $server): void { - // Check to make sure we have a query_port because it is required if (!isset($this->options[Server::SERVER_OPTIONS_QUERY_PORT]) || empty($this->options[Server::SERVER_OPTIONS_QUERY_PORT]) @@ -127,7 +126,6 @@ public function beforeSend(Server $server): void */ public function processResponse(): mixed { - // Make a new buffer out of all of the packets $buffer = new Buffer(implode('', $this->packets_response)); @@ -187,9 +185,7 @@ public function processResponse(): mixed return $result->fetch(); } - /* - * Internal methods - */ + // Internal methods /** * Process the properties of the data. @@ -197,12 +193,10 @@ public function processResponse(): mixed * Takes data in "key1=value1 key2=value2 ..." and processes it into a usable format * * @param $data - * * @return array */ protected function processProperties($data) { - // Will hold the properties we are sending back $properties = []; @@ -215,7 +209,7 @@ protected function processProperties($data) [$key, $value] = array_pad(explode('=', $item, 2), 2, ''); // Convert spaces and other character changes - $properties[$key] = $this->convertToUtf8(str_replace( + $properties[$key] = Str::isoToUtf8(str_replace( [ '\\s', // Translate spaces ], diff --git a/src/GameQ/Protocols/Teeworlds.php b/src/GameQ/Protocols/Teeworlds.php index 1683fa23..85afd717 100644 --- a/src/GameQ/Protocols/Teeworlds.php +++ b/src/GameQ/Protocols/Teeworlds.php @@ -33,7 +33,6 @@ */ class Teeworlds extends Protocol { - /** * Array of packets we want to look up. * Each key should correspond to a defined method in this or a parent class @@ -131,6 +130,7 @@ public function processResponse(): mixed * Handle processing all of the data returned * * @return array + * @throws ProtocolException */ protected function processAll(Buffer $buffer) { diff --git a/src/GameQ/Protocols/Terraria.php b/src/GameQ/Protocols/Terraria.php index 717de08d..9a0c9be3 100644 --- a/src/GameQ/Protocols/Terraria.php +++ b/src/GameQ/Protocols/Terraria.php @@ -27,7 +27,6 @@ */ class Terraria extends Tshock { - /** * String name of this protocol class */ diff --git a/src/GameQ/Protocols/Theforrest.php b/src/GameQ/Protocols/Theforrest.php index 6b591020..2c6013ac 100644 --- a/src/GameQ/Protocols/Theforrest.php +++ b/src/GameQ/Protocols/Theforrest.php @@ -26,7 +26,6 @@ */ class Theforrest extends Source { - /** * String name of this protocol class */ diff --git a/src/GameQ/Protocols/Tibia.php b/src/GameQ/Protocols/Tibia.php index 038fe450..0b10968a 100644 --- a/src/GameQ/Protocols/Tibia.php +++ b/src/GameQ/Protocols/Tibia.php @@ -34,7 +34,6 @@ */ class Tibia extends Protocol { - /** * Array of packets we want to query. */ diff --git a/src/GameQ/Protocols/Unreal2.php b/src/GameQ/Protocols/Unreal2.php index 04c2986d..e59d35c6 100644 --- a/src/GameQ/Protocols/Unreal2.php +++ b/src/GameQ/Protocols/Unreal2.php @@ -30,7 +30,6 @@ */ class Unreal2 extends Protocol { - /** * Array of packets we want to look up. * Each key should correspond to a defined method in this or a parent class @@ -96,7 +95,6 @@ class Unreal2 extends Protocol */ public function processResponse(): mixed { - // Will hold the packets after sorting $packets = []; @@ -134,9 +132,7 @@ public function processResponse(): mixed return $results; } - /* - * Internal methods - */ + // Internal methods /** * Handles processing the details data into a usable format @@ -147,7 +143,6 @@ public function processResponse(): mixed */ protected function processDetails(Buffer $buffer) { - // Set the result to a new result instance $result = new Result(); @@ -155,8 +150,8 @@ protected function processDetails(Buffer $buffer) $result->add('serverip', $buffer->readPascalString(1)); // empty $result->add('gameport', $buffer->readInt32()); $result->add('queryport', $buffer->readInt32()); // 0 - $result->add('servername', $this->convertToUtf8($buffer->readPascalString(1))); - $result->add('mapname', $this->convertToUtf8($buffer->readPascalString(1))); + $result->add('servername', Str::isoToUtf8($buffer->readPascalString(1))); + $result->add('mapname', Str::isoToUtf8($buffer->readPascalString(1))); $result->add('gametype', $buffer->readPascalString(1)); $result->add('numplayers', $buffer->readInt32()); $result->add('maxplayers', $buffer->readInt32()); @@ -173,7 +168,6 @@ protected function processDetails(Buffer $buffer) */ protected function processPlayers(Buffer $buffer) { - // Set the result to a new result instance $result = new Result(); @@ -183,7 +177,7 @@ protected function processPlayers(Buffer $buffer) if (($id = $buffer->readInt32()) !== 0) { // Add the results $result->addPlayer('id', $id); - $result->addPlayer('name', $this->convertToUtf8($buffer->readPascalString(1))); + $result->addPlayer('name', Str::isoToUtf8($buffer->readPascalString(1))); $result->addPlayer('ping', $buffer->readInt32()); $result->addPlayer('score', $buffer->readInt32()); @@ -205,7 +199,6 @@ protected function processPlayers(Buffer $buffer) */ protected function processRules(Buffer $buffer) { - // Set the result to a new result instance $result = new Result(); @@ -220,7 +213,7 @@ protected function processRules(Buffer $buffer) $key .= ++$inc; } - $result->add(strtolower($key), $this->convertToUtf8($buffer->readPascalString(1))); + $result->add(strtolower($key), Str::isoToUtf8($buffer->readPascalString(1))); } return $result->fetch(); diff --git a/src/GameQ/Protocols/Ut.php b/src/GameQ/Protocols/Ut.php index 0f385e79..45488426 100644 --- a/src/GameQ/Protocols/Ut.php +++ b/src/GameQ/Protocols/Ut.php @@ -25,7 +25,6 @@ */ class Ut extends Gamespy { - /** * String name of this protocol class */ diff --git a/src/GameQ/Protocols/Ut2004.php b/src/GameQ/Protocols/Ut2004.php index b87bec36..f11b08ef 100644 --- a/src/GameQ/Protocols/Ut2004.php +++ b/src/GameQ/Protocols/Ut2004.php @@ -25,7 +25,6 @@ */ class Ut2004 extends Unreal2 { - /** * String name of this protocol class */ diff --git a/src/GameQ/Protocols/Ut3.php b/src/GameQ/Protocols/Ut3.php index 0e174fb6..7c7f65d3 100644 --- a/src/GameQ/Protocols/Ut3.php +++ b/src/GameQ/Protocols/Ut3.php @@ -29,7 +29,6 @@ */ class Ut3 extends Gamespy3 { - /** * String name of this protocol class */ @@ -59,7 +58,6 @@ class Ut3 extends Gamespy3 */ public function processResponse(): mixed { - // Grab the result from the parent $result = parent::processResponse(); @@ -98,7 +96,6 @@ public function processResponse(): mixed */ protected function renameResult(array &$result, string $old, string $new): void { - // Check to see if the old item is there if (isset($result[$old])) { $result[$new] = $result[$old]; @@ -111,7 +108,6 @@ protected function renameResult(array &$result, string $old, string $new): void */ protected function deleteResult(array &$result, array $array): void { - foreach ($array as $key) { unset($result[$key]); } diff --git a/src/GameQ/Protocols/Ventrilo.php b/src/GameQ/Protocols/Ventrilo.php index c3df159e..907a5792 100644 --- a/src/GameQ/Protocols/Ventrilo.php +++ b/src/GameQ/Protocols/Ventrilo.php @@ -36,7 +36,6 @@ */ class Ventrilo extends Protocol { - /** * Array of packets we want to look up. * Each key should correspond to a defined method in this or a parent class @@ -92,10 +91,8 @@ class Ventrilo extends Protocol /** * Encryption table for the header - * - * @type array */ - private $head_encrypt_table = [ + private array $head_encrypt_table = [ 0x80, 0xe5, 0x0e, @@ -356,10 +353,8 @@ class Ventrilo extends Protocol /** * Encryption table for the data - * - * @type array */ - private $data_encrypt_table = [ + private array $data_encrypt_table = [ 0x82, 0x8b, 0x7f, @@ -626,7 +621,6 @@ class Ventrilo extends Protocol */ public function processResponse(): mixed { - // We need to decrypt the packets $decrypted = $this->decryptPackets($this->packets_response); @@ -699,19 +693,19 @@ static function ($matches) { $this->processChannel($value, $channelFields, $result); break; - // Find the number of fields for the channels + // Find the number of fields for the channels case 'channelfields': $channelFields = count(explode(',', $value)); break; - // Find the number of fields for the players + // Find the number of fields for the players case 'clientfields': $playerFields = count(explode(',', $value)); break; - // By default we just add they key as an item + // By default we just add they key as an item default: - $result->add($key, $this->convertToUtf8($value)); + $result->add($key, Str::isoToUtf8($value)); break; } } @@ -722,9 +716,7 @@ static function ($matches) { return $result->fetch(); } - /* - * Internal methods - */ + // Internal methods /** * Decrypt the incoming packets @@ -734,12 +726,11 @@ static function ($matches) { */ protected function decryptPackets(array $packets = []) { - // This will be returned $decrypted = []; foreach ($packets as $packet) { - # Header : + // Header : $header = substr($packet, 0, 20); $header_items = []; @@ -789,7 +780,7 @@ protected function decryptPackets(array $packets = []) throw new ProtocolException(__METHOD__ . ": Too few packets received"); } - # Data : + // Data : $table = $this->data_encrypt_table; $a1 = $header_items['datakey'] & 0xFF; $a2 = $header_items['datakey'] >> 8; @@ -822,7 +813,6 @@ protected function decryptPackets(array $packets = []) */ protected function processChannel(string $data, int $fieldCount, Result $result) { - // Split the items on the comma $items = explode(",", $data, $fieldCount); @@ -831,7 +821,7 @@ protected function processChannel(string $data, int $fieldCount, Result $result) // Split the key=value pair list($key, $value) = explode("=", $item, 2); - $result->addTeam(strtolower($key), $this->convertToUtf8($value)); + $result->addTeam(strtolower($key), Str::isoToUtf8($value)); } } @@ -840,7 +830,6 @@ protected function processChannel(string $data, int $fieldCount, Result $result) */ protected function processPlayer(string $data, int $fieldCount, Result $result) { - // Split the items on the comma $items = explode(",", $data, $fieldCount); @@ -849,7 +838,7 @@ protected function processPlayer(string $data, int $fieldCount, Result $result) // Split the key=value pair list($key, $value) = explode("=", $item, 2); - $result->addPlayer(strtolower($key), $this->convertToUtf8($value)); + $result->addPlayer(strtolower($key), Str::isoToUtf8($value)); } } } diff --git a/src/GameQ/Protocols/Warsow.php b/src/GameQ/Protocols/Warsow.php index fdf481e8..3236af36 100644 --- a/src/GameQ/Protocols/Warsow.php +++ b/src/GameQ/Protocols/Warsow.php @@ -69,7 +69,7 @@ protected function processPlayers(Buffer $buffer) $playerInfo->skip(); // Add player name, encoded - $result->addPlayer('name', $this->convertToUtf8(trim(($playerInfo->readString('"'))))); + $result->addPlayer('name', Str::isoToUtf8(trim(($playerInfo->readString('"'))))); // Skip space $playerInfo->skip(); diff --git a/src/GameQ/Protocols/Won.php b/src/GameQ/Protocols/Won.php index a047648b..6edac29d 100644 --- a/src/GameQ/Protocols/Won.php +++ b/src/GameQ/Protocols/Won.php @@ -30,7 +30,6 @@ */ class Won extends Source { - /** * Array of packets we want to look up. * Each key should correspond to a defined method in this or a parent class diff --git a/src/GameQ/Query/Core.php b/src/GameQ/Query/Core.php index 8505717b..8206acf8 100644 --- a/src/GameQ/Query/Core.php +++ b/src/GameQ/Query/Core.php @@ -27,11 +27,10 @@ */ abstract class Core { - /** * The socket used by this resource * - * @type null|resource + * @var null|resource */ public $socket; diff --git a/src/GameQ/Query/Native.php b/src/GameQ/Query/Native.php index cba316f9..3c31219a 100644 --- a/src/GameQ/Query/Native.php +++ b/src/GameQ/Query/Native.php @@ -35,7 +35,6 @@ class Native extends Core */ public function get(): mixed { - // No socket for this server, make one if (is_null($this->socket)) { $this->create(); @@ -54,7 +53,6 @@ public function get(): mixed */ public function write(string|array $data): int { - try { // No socket for this server, make one if (is_null($this->socket)) { @@ -73,7 +71,6 @@ public function write(string|array $data): int */ public function close(): void { - if ($this->socket) { fclose($this->socket); $this->socket = null; @@ -87,7 +84,6 @@ public function close(): void */ protected function create(): void { - // Create the remote address $remote_addr = sprintf("%s://%s:%d", $this->transport, $this->ip, $this->port); @@ -183,7 +179,7 @@ public function getResponses(array $sockets, int $timeout, int $stream_timeout): // Loop the sockets that received data back foreach ($read as $socket) { - /* @var $socket resource */ + // @var $socket resource // See if we have a response if (($response = fread($socket, 32768)) === false) { diff --git a/src/GameQ/Result.php b/src/GameQ/Result.php index e5d82f38..cdd657ae 100644 --- a/src/GameQ/Result.php +++ b/src/GameQ/Result.php @@ -89,7 +89,6 @@ public function addSub(string $sub, string $key, mixed $value): void */ public function fetch(): array { - return $this->result; } diff --git a/src/GameQ/Server.php b/src/GameQ/Server.php index 764e8a58..6e85feb9 100644 --- a/src/GameQ/Server.php +++ b/src/GameQ/Server.php @@ -36,9 +36,7 @@ class Server public const SERVER_ID = 'id'; public const SERVER_OPTIONS = 'options'; - /* - * Server options keys - */ + // Server options keys /* * Use this option when the query_port and client connect ports are different @@ -139,7 +137,6 @@ public function __construct(array $server_info = []) */ protected function checkAndSetIpPort(string $ip_address): void { - // Test for IPv6 if (substr_count($ip_address, ':') > 1) { // See if we have a port, input should be in the format [::1]:27015 or similar @@ -201,7 +198,6 @@ protected function checkAndSetIpPort(string $ip_address): void */ protected function checkAndSetServerOptions(): void { - // Specific query port defined if (array_key_exists(self::SERVER_OPTIONS_QUERY_PORT, $this->options)) { $this->port_query = (int)$this->options[self::SERVER_OPTIONS_QUERY_PORT]; @@ -242,7 +238,6 @@ public function getOptions() */ public function id(): string { - return $this->id; } @@ -251,7 +246,6 @@ public function id(): string */ public function ip(): string { - return $this->ip; } @@ -260,7 +254,6 @@ public function ip(): string */ public function portClient(): int { - return $this->port_client; } @@ -269,7 +262,6 @@ public function portClient(): int */ public function portQuery(): int { - return $this->port_query; } @@ -278,7 +270,6 @@ public function portQuery(): int */ public function protocol(): ?Protocol { - return $this->protocol; } @@ -296,16 +287,13 @@ public function getJoinLink(): ?string return sprintf($joinLink, $this->ip, $this->portClient()); } - /* - * Socket holding - */ + // Socket holding /** * Add a socket for this server to be reused */ public function socketAdd(Core $socket): void { - $this->sockets[] = $socket; } @@ -314,7 +302,6 @@ public function socketAdd(Core $socket): void */ public function socketGet(): ?Core { - $socket = null; if (count($this->sockets) > 0) { diff --git a/tests/Buffer.php b/tests/Buffer.php index 1c0781d6..bd7ded21 100644 --- a/tests/Buffer.php +++ b/tests/Buffer.php @@ -37,7 +37,6 @@ class Buffer extends TestBase */ protected function buildBuffer($data, $number_type = 'm') { - return new \GameQ\Buffer($data, $number_type); } @@ -49,7 +48,6 @@ protected function buildBuffer($data, $number_type = 'm') */ public function integerDataProvider() { - // Make the base path for the data to test since it has to be in ascii form $basePath = sprintf('%s/Providers/Buffer', __DIR__); diff --git a/tests/Filters/Base.php b/tests/Filters/Base.php index c7d0f3d4..2fca6ded 100644 --- a/tests/Filters/Base.php +++ b/tests/Filters/Base.php @@ -27,7 +27,6 @@ */ class Base extends TestBase { - /** * Load up the provider data for the specific filter type * @@ -35,7 +34,6 @@ class Base extends TestBase */ public function loadData() { - // Explode the class that called to avoid strict error $class = explode('\\', get_called_class()); @@ -82,16 +80,13 @@ public function loadData() return $providers; } - /* - * Real Base tests here - */ + // Real Base tests here /** * Test options setting on construct */ public function testOptions() { - $options = [ 'option1' => 'value1', 'option2' => 'value2', diff --git a/tests/Filters/Normalize.php b/tests/Filters/Normalize.php index ee884cd2..63fe01e4 100644 --- a/tests/Filters/Normalize.php +++ b/tests/Filters/Normalize.php @@ -25,7 +25,6 @@ */ class Normalize extends Base { - /** * Test the filter for Normalize * @@ -37,7 +36,6 @@ class Normalize extends Base */ public function testFiltered($protocol, $raw, $filtered) { - // Pop the key from the raw response $host = key($raw); @@ -65,7 +63,6 @@ public function testFiltered($protocol, $raw, $filtered) */ public function testEmpty() { - // Create a mock server $server = $this->getMockBuilder('\GameQ\Server') ->setConstructorArgs([ diff --git a/tests/Filters/Secondstohuman.php b/tests/Filters/Secondstohuman.php index 36b171cd..b4c922c8 100644 --- a/tests/Filters/Secondstohuman.php +++ b/tests/Filters/Secondstohuman.php @@ -25,7 +25,6 @@ */ class Secondstohuman extends Base { - /** * Test default filter settings */ diff --git a/tests/Filters/Stripcolors.php b/tests/Filters/Stripcolors.php index 54c93c9f..98d18883 100644 --- a/tests/Filters/Stripcolors.php +++ b/tests/Filters/Stripcolors.php @@ -25,7 +25,6 @@ */ class Stripcolors extends Base { - /** * Test the filter for Stripcolors * @@ -37,7 +36,6 @@ class Stripcolors extends Base */ public function testFiltered($protocol, $raw, $filtered) { - // Pop the key from the raw response $host = key($raw); diff --git a/tests/GameQ.php b/tests/GameQ.php index 19e3d25f..cd8b1670 100644 --- a/tests/GameQ.php +++ b/tests/GameQ.php @@ -25,11 +25,10 @@ */ class GameQ extends TestBase { - /** * Holds stub on setup * - * @type \GameQ\GameQ + * @var \GameQ\GameQ */ protected $stub; @@ -47,7 +46,6 @@ public function customSetUp() */ public function testFactory() { - $this->assertInstanceOf('\GameQ\GameQ', \GameQ\GameQ::factory()); } @@ -76,7 +74,6 @@ public function testGetSetOptions() */ public function testAddServer() { - // Define some servers $servers = [ [ @@ -118,7 +115,6 @@ public function testAddServer() */ public function testAddServersFromFiles() { - // Test single file $this->stub->addServersFromFiles(__DIR__ . '/Protocols/Providers/server_list1.json'); @@ -159,7 +155,6 @@ public function testAddServersFromFiles() */ public function testFiltersAddRemove() { - // Add filter $this->stub->addFilter('test_filter'); @@ -198,7 +193,6 @@ public function testFiltersAddRemove() */ public function testFilterApply() { - // Define some fake results $fakeResults = [ 'key1' => 'val1', @@ -234,7 +228,6 @@ public function testFilterApply() */ public function testBadFilterException() { - // Define some fake results $fakeResults = [ 'key1' => 'val1', diff --git a/tests/Issues/Issue307.php b/tests/Issues/Issue307.php index 33d87ba4..fe624c92 100644 --- a/tests/Issues/Issue307.php +++ b/tests/Issues/Issue307.php @@ -37,7 +37,6 @@ class Issue307 extends TestBase */ public function test1() { - $filePath = sprintf('%s/Providers/307.txt', __DIR__); $testResult = $this->queryTest('127.0.0.1:27015', 'csgo', explode(PHP_EOL . '||' . PHP_EOL, file_get_contents($filePath))); diff --git a/tests/Issues/Issue588.php b/tests/Issues/Issue588.php index c9abf5ff..26cb600d 100644 --- a/tests/Issues/Issue588.php +++ b/tests/Issues/Issue588.php @@ -29,6 +29,11 @@ */ class Issue588 extends TestBase { + /** + * @var \GameQ\GameQ + */ + protected $stub; + /** * Setup to create our stub * @before diff --git a/tests/Protocol.php b/tests/Protocol.php index baf6ea0b..659953b7 100644 --- a/tests/Protocol.php +++ b/tests/Protocol.php @@ -25,18 +25,17 @@ */ class Protocol extends TestBase { - /** * Holds stub on setup * - * @type \GameQ\Protocol + * @var \GameQ\Protocol */ protected $stub; /** * Some dummy options * - * @type array + * @var array */ protected $options = [ 'key1' => 'var1', @@ -49,7 +48,6 @@ class Protocol extends TestBase */ public function customSetUp() { - $this->stub = $this->getMockForAbstractClass('\GameQ\Protocol', [ $this->options ]); } @@ -58,7 +56,6 @@ public function customSetUp() */ public function testGeneral() { - $name = 'Test name'; $nameLong = 'Test name bigger, longer'; $portDiff = 5454; @@ -102,7 +99,6 @@ public function testGeneral() */ public function testPackets() { - $packets = [ \GameQ\Protocol::PACKET_CHALLENGE => 'Do you even lift?', \GameQ\Protocol::PACKET_RULES => 'There are no rules!!', diff --git a/tests/Protocols/Arksa.php b/tests/Protocols/Arksa.php new file mode 100644 index 00000000..c9371d3e --- /dev/null +++ b/tests/Protocols/Arksa.php @@ -0,0 +1,49 @@ +. + */ + +namespace GameQ\Tests\Protocols; + +/** + * Test Class for ARK: Survival Ascended + * + * @package GameQ\Tests\Protocols + */ +class Arksa extends Base +{ + /** + * Test responses for ARK: Survival Ascended + * + * @dataProvider loadData + * + * @param $responses + * @param $result + */ + public function testResponses($responses, $result) + { + // Pull the first key off the array this is the server ip:port + $server = key($result); + + $testResult = $this->queryTest( + $server, + 'arksa', + $responses + ); + + $this->assertEqualsDelta($result[$server], $testResult, 0.00000001); + } +} diff --git a/tests/Protocols/Ase.php b/tests/Protocols/Ase.php index d8e006bd..957c1832 100644 --- a/tests/Protocols/Ase.php +++ b/tests/Protocols/Ase.php @@ -25,14 +25,14 @@ class Ase extends Base /** * Holds stub on setup * - * @type \GameQ\Protocols\Ase + * @var \GameQ\Protocols\Ase */ protected $stub; /** * Holds the expected packets for this protocol class * - * @type array + * @var array */ protected $packets = [ \GameQ\Protocol::PACKET_ALL => "s", diff --git a/tests/Protocols/Atlas.php b/tests/Protocols/Atlas.php index 76106c6c..8ce7f184 100644 --- a/tests/Protocols/Atlas.php +++ b/tests/Protocols/Atlas.php @@ -35,7 +35,6 @@ class Atlas extends Base */ public function testResponses($responses, $result) { - // Pull the first key off the array this is the server ip:port $server = key($result); // Splited to later be compared with query port diff --git a/tests/Protocols/Batt1944.php b/tests/Protocols/Batt1944.php index 6273162c..2f94fb58 100644 --- a/tests/Protocols/Batt1944.php +++ b/tests/Protocols/Batt1944.php @@ -35,7 +35,6 @@ class Batt1944 extends Base */ public function testResponses($responses, $result) { - // Pull the first key off the array this is the server ip:port $server = key($result); diff --git a/tests/Protocols/Bf3.php b/tests/Protocols/Bf3.php index 9d027efe..a9683b85 100644 --- a/tests/Protocols/Bf3.php +++ b/tests/Protocols/Bf3.php @@ -25,14 +25,14 @@ class Bf3 extends Base /** * Holds stub on setup * - * @type \GameQ\Protocols\Bf3 + * @var \GameQ\Protocols\Bf3 */ protected $stub; /** * Holds the expected packets for this protocol class * - * @type array + * @var array */ protected $packets = [ \GameQ\Protocol::PACKET_STATUS => "\x00\x00\x00\x21\x1b\x00\x00\x00\x01\x00\x00\x00\x0a\x00\x00\x00serverInfo\x00", diff --git a/tests/Protocols/Bfbc2.php b/tests/Protocols/Bfbc2.php index 6f030e45..b083a672 100644 --- a/tests/Protocols/Bfbc2.php +++ b/tests/Protocols/Bfbc2.php @@ -25,14 +25,14 @@ class Bfbc2 extends Base /** * Holds stub on setup * - * @type \GameQ\Protocols\Bfbc2 + * @var \GameQ\Protocols\Bfbc2 */ protected $stub; /** * Holds the expected packets for this protocol class * - * @type array + * @var array */ protected $packets = [ \GameQ\Protocol::PACKET_VERSION => "\x00\x00\x00\x00\x18\x00\x00\x00\x01\x00\x00\x00\x07\x00\x00\x00version\x00", diff --git a/tests/Protocols/Bfh.php b/tests/Protocols/Bfh.php index d8488761..64197e05 100644 --- a/tests/Protocols/Bfh.php +++ b/tests/Protocols/Bfh.php @@ -20,7 +20,6 @@ class Bfh extends Base { - /** * Test responses for Battlefield Hardline * diff --git a/tests/Protocols/Codmw2.php b/tests/Protocols/Codmw2.php index 93f9d28f..a00d46f9 100644 --- a/tests/Protocols/Codmw2.php +++ b/tests/Protocols/Codmw2.php @@ -35,7 +35,6 @@ class Codmw2 extends Base */ public function testResponses($responses, $result) { - // Pull the first key off the array this is the server ip:port $server = key($result); diff --git a/tests/Protocols/Cs2d.php b/tests/Protocols/Cs2d.php index 98fbefa1..beedddbb 100644 --- a/tests/Protocols/Cs2d.php +++ b/tests/Protocols/Cs2d.php @@ -25,14 +25,14 @@ class Cs2d extends Base /** * Holds stub on setup * - * @type \GameQ\Protocols\Cs2d + * @var \GameQ\Protocols\Cs2d */ protected $stub; /** * Holds the expected packets for this protocol class * - * @type array + * @var array */ protected $packets = [ \GameQ\Protocol::PACKET_STATUS => "\x01\x00\xFB\x01", diff --git a/tests/Protocols/Doom3.php b/tests/Protocols/Doom3.php index d43e6d78..67ed9440 100644 --- a/tests/Protocols/Doom3.php +++ b/tests/Protocols/Doom3.php @@ -35,7 +35,6 @@ class Doom3 extends Base */ public function testResponses($responses, $result) { - // Pull the first key off the array this is the server ip:port $server = key($result); diff --git a/tests/Protocols/Eco.php b/tests/Protocols/Eco.php index ae78936a..2a476bb8 100644 --- a/tests/Protocols/Eco.php +++ b/tests/Protocols/Eco.php @@ -23,14 +23,14 @@ class Eco extends Base /** * Holds stub on setup * - * @type \GameQ\Protocols\Eco + * @var \GameQ\Protocols\Eco */ protected $stub; /** * Holds the expected packets for this protocol class * - * @type array + * @var array */ protected $packets = [ \GameQ\Protocol::PACKET_STATUS => "GET /frontpage HTTP/1.0\r\nAccept: */*\r\n\r\n", diff --git a/tests/Protocols/Eos.php b/tests/Protocols/Eos.php new file mode 100644 index 00000000..a6e7f1f0 --- /dev/null +++ b/tests/Protocols/Eos.php @@ -0,0 +1,42 @@ +. + */ + +namespace GameQ\Tests\Protocols; + +class Eos extends Base +{ + /** + * Test to ensure the response processing is correct + * + * @return void + */ + public function testResponses() + { + // Wrap the queryTest method in a try-catch block to handle the exception + try { + $this->queryTest('127.0.0.1:27015', 'eos', [], false); + } catch (Server $e) { + // Log the exception or handle as needed + $this->assertTrue(true, "Expected exception 'Failed to authenticate with EOS API' was caught"); + return; // Exit the test since the exception is expected + } + + // If no exception is thrown, the test passes as expected + $this->assertTrue(true, "Test passed without exception"); + } +} diff --git a/tests/Protocols/Etqw.php b/tests/Protocols/Etqw.php index 6c7aa96a..2afefbe7 100644 --- a/tests/Protocols/Etqw.php +++ b/tests/Protocols/Etqw.php @@ -25,14 +25,14 @@ class Etqw extends Base /** * Holds stub on setup * - * @type \GameQ\Protocols\Etqw + * @var \GameQ\Protocols\Etqw */ protected $stub; /** * Holds the expected packets for this protocol class * - * @type array + * @var array */ protected $packets = [ \GameQ\Protocol::PACKET_STATUS => "\xFF\xFFgetInfoEx\x00\x00\x00\x00", diff --git a/tests/Protocols/Ffow.php b/tests/Protocols/Ffow.php index f904753b..21f1e97f 100644 --- a/tests/Protocols/Ffow.php +++ b/tests/Protocols/Ffow.php @@ -25,14 +25,14 @@ class Ffow extends Base /** * Holds stub on setup * - * @type \GameQ\Protocols\Ffow + * @var \GameQ\Protocols\Ffow */ protected $stub; /** * Holds the expected packets for this protocol class * - * @type array + * @var array */ protected $packets = [ \GameQ\Protocol::PACKET_CHALLENGE => "\xFF\xFF\xFF\xFF\x57", diff --git a/tests/Protocols/Gamespy.php b/tests/Protocols/Gamespy.php index 62d15063..735519d6 100644 --- a/tests/Protocols/Gamespy.php +++ b/tests/Protocols/Gamespy.php @@ -25,14 +25,14 @@ class Gamespy extends Base /** * Holds stub on setup * - * @type \GameQ\Protocols\Gamespy + * @var \GameQ\Protocols\Gamespy */ protected $stub; /** * Holds the expected packets for this protocol class * - * @type array + * @var array */ protected $packets = [ \GameQ\Protocol::PACKET_STATUS => "\x5C\x73\x74\x61\x74\x75\x73\x5C", diff --git a/tests/Protocols/Gamespy2.php b/tests/Protocols/Gamespy2.php index bd1f8c17..6450b6ac 100644 --- a/tests/Protocols/Gamespy2.php +++ b/tests/Protocols/Gamespy2.php @@ -23,14 +23,14 @@ class Gamespy2 extends Base /** * Holds stub on setup * - * @type \GameQ\Protocols\Gamespy2 + * @var \GameQ\Protocols\Gamespy2 */ protected $stub; /** * Holds the expected packets for this protocol class * - * @type array + * @var array */ protected $packets = [ \GameQ\Protocol::PACKET_DETAILS => "\xFE\xFD\x00\x43\x4F\x52\x59\xFF\x00\x00", diff --git a/tests/Protocols/Gamespy3.php b/tests/Protocols/Gamespy3.php index 7574215c..1e010eeb 100644 --- a/tests/Protocols/Gamespy3.php +++ b/tests/Protocols/Gamespy3.php @@ -23,14 +23,14 @@ class Gamespy3 extends Base /** * Holds stub on setup * - * @type \GameQ\Protocols\Gamespy3 + * @var \GameQ\Protocols\Gamespy3 */ protected $stub; /** * Holds the expected packets for this protocol class * - * @type array + * @var array */ protected $packets = [ \GameQ\Protocol::PACKET_CHALLENGE => "\xFE\xFD\x09\x10\x20\x30\x40", diff --git a/tests/Protocols/Gtan.php b/tests/Protocols/Gtan.php index 1be58d9d..4a510e3b 100644 --- a/tests/Protocols/Gtan.php +++ b/tests/Protocols/Gtan.php @@ -23,14 +23,14 @@ class Gtan extends Base /** * Holds stub on setup * - * @type \GameQ\Protocols\Gtan + * @var \GameQ\Protocols\Gtan */ protected $stub; /** * Holds the expected packets for this protocol class * - * @type array + * @var array */ protected $packets = [ \GameQ\Protocol::PACKET_STATUS => "GET /gtan/api.php?ip=%s&raw HTTP/1.0\r\nHost: multiplayerhosting.info\r\nAccept: */*\r\n\r\n", diff --git a/tests/Protocols/Gtar.php b/tests/Protocols/Gtar.php index 2979c6e9..ec95d2aa 100644 --- a/tests/Protocols/Gtar.php +++ b/tests/Protocols/Gtar.php @@ -23,14 +23,14 @@ class Gtar extends Base /** * Holds stub on setup * - * @type \GameQ\Protocols\Gtan + * @var \GameQ\Protocols\Gtan */ protected $stub; /** * Holds the expected packets for this protocol class * - * @type array + * @var array */ protected $packets = [ \GameQ\Protocol::PACKET_STATUS => "GET /master/ HTTP/1.0\r\nHost: cdn.rage.mp\r\nAccept: */*\r\n\r\n", diff --git a/tests/Protocols/Had2.php b/tests/Protocols/Had2.php index 118ba36d..aa773fe4 100644 --- a/tests/Protocols/Had2.php +++ b/tests/Protocols/Had2.php @@ -35,7 +35,6 @@ class Had2 extends Base */ public function testResponses($responses, $result) { - // Pull the first key off the array this is the server ip:port $server = key($result); diff --git a/tests/Protocols/Halo.php b/tests/Protocols/Halo.php index 65152e91..ceab3583 100644 --- a/tests/Protocols/Halo.php +++ b/tests/Protocols/Halo.php @@ -35,7 +35,6 @@ class Halo extends Base */ public function testResponses($responses, $result) { - // Pull the first key off the array this is the server ip:port $server = key($result); diff --git a/tests/Protocols/Hll.php b/tests/Protocols/Hll.php index 92aed03a..d5f19d39 100644 --- a/tests/Protocols/Hll.php +++ b/tests/Protocols/Hll.php @@ -35,7 +35,6 @@ class Hll extends Base */ public function testResponses($responses, $result) { - // Pull the first key off the array this is the server ip:port $server = key($result); diff --git a/tests/Protocols/Justcause2.php b/tests/Protocols/Justcause2.php index 840891df..bebc3f35 100644 --- a/tests/Protocols/Justcause2.php +++ b/tests/Protocols/Justcause2.php @@ -23,14 +23,14 @@ class Justcause2 extends Base /** * Holds stub on setup * - * @type \GameQ\Protocols\Gamespy + * @var \GameQ\Protocols\Gamespy */ protected $stub; /** * Holds the expected packets for this protocol class * - * @type array + * @var array */ protected $packets = [ \GameQ\Protocol::PACKET_CHALLENGE => "\xFE\xFD\x09\x10\x20\x30\x40", diff --git a/tests/Protocols/Lhmp.php b/tests/Protocols/Lhmp.php index b175d687..76fbe9f9 100644 --- a/tests/Protocols/Lhmp.php +++ b/tests/Protocols/Lhmp.php @@ -25,14 +25,14 @@ class Lhmp extends Base /** * Holds stub on setup * - * @type \GameQ\Protocols\Lhmp + * @var \GameQ\Protocols\Lhmp */ protected $stub; /** * Holds the expected packets for this protocol class * - * @type array + * @var array */ protected $packets = [ \GameQ\Protocol::PACKET_DETAILS => "LHMPo", diff --git a/tests/Protocols/M2mp.php b/tests/Protocols/M2mp.php index 0e68cbef..a5ed3850 100644 --- a/tests/Protocols/M2mp.php +++ b/tests/Protocols/M2mp.php @@ -35,7 +35,6 @@ class M2mp extends Base */ public function testResponses($responses, $result) { - // Pull the first key off the array this is the server ip:port $server = key($result); diff --git a/tests/Protocols/Miscreated.php b/tests/Protocols/Miscreated.php index 70b00b30..0e341676 100644 --- a/tests/Protocols/Miscreated.php +++ b/tests/Protocols/Miscreated.php @@ -35,7 +35,6 @@ class Miscreated extends Base */ public function testResponses($responses, $result) { - // Pull the first key off the array this is the server ip:port $server = key($result); diff --git a/tests/Protocols/Mohaa.php b/tests/Protocols/Mohaa.php index f31c66d0..377d05f1 100644 --- a/tests/Protocols/Mohaa.php +++ b/tests/Protocols/Mohaa.php @@ -28,7 +28,7 @@ class Mohaa extends Base /** * Holds stub on setup * - * @type \GameQ\Protocols\Mohaa + * @var \GameQ\Protocols\Mohaa */ protected $stub; diff --git a/tests/Protocols/Mumble.php b/tests/Protocols/Mumble.php index 65a58ea5..fbe6a9c4 100644 --- a/tests/Protocols/Mumble.php +++ b/tests/Protocols/Mumble.php @@ -28,14 +28,14 @@ class Mumble extends Base /** * Holds stub on setup * - * @type \GameQ\Protocols\Mumble + * @var \GameQ\Protocols\Mumble */ protected $stub; /** * Holds the expected packets for this protocol class * - * @type array + * @var array */ protected $packets = [ \GameQ\Protocol::PACKET_ALL => "\x6A\x73\x6F\x6E", diff --git a/tests/Protocols/Openttd.php b/tests/Protocols/Openttd.php index beccaf2c..ecbd7494 100644 --- a/tests/Protocols/Openttd.php +++ b/tests/Protocols/Openttd.php @@ -35,7 +35,6 @@ class Openttd extends Base */ public function testResponses($responses, $result) { - // Pull the first key off the array this is the server ip:port $server = key($result); diff --git a/tests/Protocols/Postscriptum.php b/tests/Protocols/Postscriptum.php index b7f2de4c..1e621e02 100644 --- a/tests/Protocols/Postscriptum.php +++ b/tests/Protocols/Postscriptum.php @@ -35,7 +35,6 @@ class Postscriptum extends Base */ public function testResponses($responses, $result) { - // Pull the first key off the array this is the server ip:port $server = key($result); diff --git a/tests/Protocols/Providers/Arksa/1_response.txt b/tests/Protocols/Providers/Arksa/1_response.txt new file mode 100644 index 00000000..87beedfc --- /dev/null +++ b/tests/Protocols/Providers/Arksa/1_response.txt @@ -0,0 +1,3 @@ +{"access_token":"eyJraWQiOiIyMDIyLTA2LTE0VDA2OjE3OjU3LjA0NzkyODcwMFoiLCJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJjbGllbnRJZCI6Inh5emE3ODkxbXVvbVJteW5JSUhhSkI5Q09CS2t3ajZuIiwicHJvZHVjdElkIjoiOTg1ZGM0ZDY3ZmYxNDI1ODhiNjM5M2M0NmIxZGZmODQiLCJpc3MiOiJlb3MiLCJlbnYiOiJwcm9kIiwib3JnYW5pemF0aW9uSWQiOiJvLXVzdmZibWxxZHQ2Nzh2cnAzNnF2bTJkNWN6MmNwciIsImZlYXR1cmVzIjpbIkFjaGlldmVtZW50cyIsIkNvbm5lY3QiLCJFY29tIiwiTGVhZGVyYm9hcmRzIiwiTWF0Y2htYWtpbmciLCJNZXRyaWNzIiwiU3RhdHMiLCJWb2ljZSJdLCJkZXBsb3ltZW50SWQiOiJhZDlhOGZlZmZiM2I0YjJjYTMxNTU0NmYwMzhjM2FlMiIsInNhbmRib3hJZCI6ImRhZTgwYzBkNGUzYjRkNjQ4NDk4YjQ4YWY2MDliOGJiIiwidG9rZW5UeXBlIjoiY2xpZW50VG9rZW4iLCJleHAiOjE3MzQ1MTgyMzEsImlhdCI6MTczNDUxNDYzMSwianRpIjoiYjk2YWY1M2RkMWEyNGZkNDk4OTRlNTRmZDUzZWU0ZmEifQ.0fZwExBmf0Bpx0J7T-kLWe900T-DLwjp7vhY3zh66rgwvtXhuPjDh1N_TOw7hPAKhZoDmUhGu5XAd9bde0AEav4iCUECG2gWcEPSBLjSc-BeUs6xbWFLSRQ6HL7VorkaWSS-SaRQaFNu5aSMwYQqhxTC-IynchNjMa3iakuetWvvFqhqpNJucV43GrUsYpga1MBxWSu-iPgkj3rwUItGAh8X1iS_viVN1pCYiOxY_PhrBGjie_S63Zct3kxpyvmt3o2T8dGH8GHRGuCYkkARtqXxQl7Zu30UI9tjAU0OmDBgnVxNs09-sxR-pd5qZdQn2MMjs0rkJ3ToqLT_Oj3xmg","token_type":"bearer","expires_at":"2024-12-18T10:37:11.149Z","features":["Achievements","Connect","Ecom","Leaderboards","Matchmaking","Metrics","Stats","Voice"],"organization_id":"o-usvfbmlqdt678vrp36qvm2d5cz2cpr","product_id":"985dc4d67ff142588b6393c46b1dff84","sandbox_id":"dae80c0d4e3b4d648498b48af609b8bb","deployment_id":"ad9a8feffb3b4b2ca315546f038c3ae2","expires_in":3599} +|| +{"sessions":[{"deployment":"ad9a8feffb3b4b2ca315546f038c3ae2","id":"a92b9db4147c42cdaeb89919adaac2c5","bucket":"TestGameMode_C::TheIsland_WP","settings":{"maxPublicPlayers":70,"allowInvites":true,"shouldAdvertise":true,"allowReadById":true,"allowJoinViaPresence":true,"allowJoinInProgress":true,"allowConferenceRoom":false,"checkSanctions":false,"allowMigration":false,"rejoinAfterKick":"","platforms":null},"totalPlayers":4,"openPublicPlayers":66,"publicPlayers":[],"started":false,"lastUpdated":null,"attributes":{"MINORBUILDID_s":"18","MODID_l":0,"CUSTOMSERVERNAME_s":"EU-PVP-TheIsland2340","ISPRIVATE_l":0,"SERVERPASSWORD_b":false,"MATCHTIMEOUT_d":120.0,"DAYTIME_s":"5237","SOTFMATCHSTARTED_b":false,"STEELSHIELDENABLED_l":1,"FRIENDLYMAPNAME_s":"TheIsland_WP","SERVERUSESBATTLEYE_b":true,"EOSSERVERPING_l":177,"ALLOWDOWNLOADCHARS_l":1,"OFFICIALSERVER_s":"1","GAMEMODE_s":"TestGameMode_C","ADDRESS_s":"5.62.112.15","SEARCHKEYWORDS_s":"Custom","__EOS_BLISTENING_b":true,"ALLOWDOWNLOADITEMS_l":1,"LEGACY_l":0,"ADDRESSBOUND_s":"0.0.0.0:7779","SESSIONISPVE_l":0,"__EOS_BUSESPRESENCE_b":true,"CLUSTERID_s":"PVPCrossplay","SESSIONNAMEUPPER_s":"EU-PVP-THEISLAND2340 - (V56.18)","SERVERPLATFORMTYPE_s":"PC+PS5+XSX","MAPNAME_s":"TheIsland_WP","BUILDID_s":"56","SESSIONNAME_s":"EU-PVP-TheIsland2340 - (v56.18)"},"owner":"Client_xyza7891muomRmynIIHaJB9COBKkwj6n","ownerPlatformId":null},{"deployment":"ad9a8feffb3b4b2ca315546f038c3ae2","id":"48b5308a809a44f79068d24122a0a0d5","bucket":"TestGameMode_C::TheIsland_WP","settings":{"maxPublicPlayers":70,"allowInvites":true,"shouldAdvertise":true,"allowReadById":true,"allowJoinViaPresence":true,"allowJoinInProgress":true,"allowConferenceRoom":false,"checkSanctions":false,"allowMigration":false,"rejoinAfterKick":"","platforms":null},"totalPlayers":0,"openPublicPlayers":70,"publicPlayers":[],"started":false,"lastUpdated":null,"attributes":{"MINORBUILDID_s":"18","MODID_l":0,"CUSTOMSERVERNAME_s":"EU-PVP-TheIsland2339","ISPRIVATE_l":0,"SERVERPASSWORD_b":false,"MATCHTIMEOUT_d":120.0,"DAYTIME_s":"5180","SOTFMATCHSTARTED_b":false,"STEELSHIELDENABLED_l":1,"FRIENDLYMAPNAME_s":"TheIsland_WP","SERVERUSESBATTLEYE_b":true,"EOSSERVERPING_l":219,"ALLOWDOWNLOADCHARS_l":1,"OFFICIALSERVER_s":"1","GAMEMODE_s":"TestGameMode_C","ADDRESS_s":"5.62.112.15","SEARCHKEYWORDS_s":"Custom","__EOS_BLISTENING_b":true,"ALLOWDOWNLOADITEMS_l":1,"LEGACY_l":0,"ADDRESSBOUND_s":"0.0.0.0:7777","SESSIONISPVE_l":0,"__EOS_BUSESPRESENCE_b":true,"CLUSTERID_s":"PVPCrossplay","SESSIONNAMEUPPER_s":"EU-PVP-THEISLAND2339 - (V56.18)","SERVERPLATFORMTYPE_s":"PC+PS5+XSX","MAPNAME_s":"TheIsland_WP","BUILDID_s":"56","SESSIONNAME_s":"EU-PVP-TheIsland2339 - (v56.18)"},"owner":"Client_xyza7891muomRmynIIHaJB9COBKkwj6n","ownerPlatformId":null},{"deployment":"ad9a8feffb3b4b2ca315546f038c3ae2","id":"deedb3d1c71e4e81b92bcf5123352f7d","bucket":"TestGameMode_C::TheCenter_WP","settings":{"maxPublicPlayers":70,"allowInvites":true,"shouldAdvertise":true,"allowReadById":true,"allowJoinViaPresence":true,"allowJoinInProgress":true,"allowConferenceRoom":false,"checkSanctions":false,"allowMigration":false,"rejoinAfterKick":"","platforms":null},"totalPlayers":9,"openPublicPlayers":61,"publicPlayers":[],"started":false,"lastUpdated":null,"attributes":{"MINORBUILDID_s":"18","MODID_l":0,"CUSTOMSERVERNAME_s":"EU-PVE-TheCenter5666","ISPRIVATE_l":0,"SERVERPASSWORD_b":false,"MATCHTIMEOUT_d":120.0,"DAYTIME_s":"2421","SOTFMATCHSTARTED_b":false,"STEELSHIELDENABLED_l":1,"FRIENDLYMAPNAME_s":"TheCenter_WP","SERVERUSESBATTLEYE_b":true,"EOSSERVERPING_l":164,"ALLOWDOWNLOADCHARS_l":1,"OFFICIALSERVER_s":"1","GAMEMODE_s":"TestGameMode_C","ADDRESS_s":"5.62.112.15","SEARCHKEYWORDS_s":"Custom","__EOS_BLISTENING_b":true,"ALLOWDOWNLOADITEMS_l":1,"LEGACY_l":0,"ADDRESSBOUND_s":"0.0.0.0:7781","SESSIONISPVE_l":1,"__EOS_BUSESPRESENCE_b":true,"CLUSTERID_s":"PVECrossplay","SESSIONNAMEUPPER_s":"EU-PVE-THECENTER5666 - (V56.18)","SERVERPLATFORMTYPE_s":"PC+XSX+WINGDK+PS5","MAPNAME_s":"TheCenter_WP","BUILDID_s":"56","SESSIONNAME_s":"EU-PVE-TheCenter5666 - (v56.18)"},"owner":"Client_xyza7891muomRmynIIHaJB9COBKkwj6n","ownerPlatformId":null},{"deployment":"ad9a8feffb3b4b2ca315546f038c3ae2","id":"907ec32e712f4a88bbcff8f556439a01","bucket":"TestGameMode_C::Aberration_WP","settings":{"maxPublicPlayers":70,"allowInvites":true,"shouldAdvertise":true,"allowReadById":true,"allowJoinViaPresence":true,"allowJoinInProgress":true,"allowConferenceRoom":false,"checkSanctions":false,"allowMigration":false,"rejoinAfterKick":"","platforms":null},"totalPlayers":4,"openPublicPlayers":66,"publicPlayers":[],"started":false,"lastUpdated":null,"attributes":{"MINORBUILDID_s":"18","MODID_l":0,"CUSTOMSERVERNAME_s":"EU-PVE-Aberration5703","ISPRIVATE_l":0,"SERVERPASSWORD_b":false,"MATCHTIMEOUT_d":120.0,"DAYTIME_s":"2439","SOTFMATCHSTARTED_b":false,"STEELSHIELDENABLED_l":1,"FRIENDLYMAPNAME_s":"Aberration_WP","SERVERUSESBATTLEYE_b":true,"EOSSERVERPING_l":177,"ALLOWDOWNLOADCHARS_l":1,"OFFICIALSERVER_s":"1","GAMEMODE_s":"TestGameMode_C","ADDRESS_s":"5.62.112.15","SEARCHKEYWORDS_s":"Custom","__EOS_BLISTENING_b":true,"ALLOWDOWNLOADITEMS_l":1,"LEGACY_l":0,"ADDRESSBOUND_s":"0.0.0.0:7783","SESSIONISPVE_l":1,"__EOS_BUSESPRESENCE_b":true,"CLUSTERID_s":"PVECrossplay","SESSIONNAMEUPPER_s":"EU-PVE-ABERRATION5703 - (V56.18)","SERVERPLATFORMTYPE_s":"PC+XSX+WINGDK+PS5","MAPNAME_s":"Aberration_WP","BUILDID_s":"56","SESSIONNAME_s":"EU-PVE-Aberration5703 - (v56.18)"},"owner":"Client_xyza7891muomRmynIIHaJB9COBKkwj6n","ownerPlatformId":null}],"count":4} \ No newline at end of file diff --git a/tests/Protocols/Providers/Arksa/1_result.json b/tests/Protocols/Providers/Arksa/1_result.json new file mode 100644 index 00000000..1c5be6a7 --- /dev/null +++ b/tests/Protocols/Providers/Arksa/1_result.json @@ -0,0 +1 @@ +{"5.62.112.15:7781":{"allowJoinInProgress":true,"anticheat":true,"day":"2421","gq_address":"5.62.112.15","gq_joinlink":null,"gq_name":"ARK: Survival Ascended","gq_online":true,"gq_port_client":7781,"gq_port_query":7781,"gq_protocol":"arksa","gq_transport":"tcp","gq_type":"arksa","hostname":"EU-PVE-TheCenter5666","mapname":"TheCenter_WP","maxplayers":70,"numplayers":9,"officialserver":true,"password":false,"pve":true,"version":"v56.18"}} \ No newline at end of file diff --git a/tests/Protocols/Providers/Arksa/2_response.txt b/tests/Protocols/Providers/Arksa/2_response.txt new file mode 100644 index 00000000..14c3be81 --- /dev/null +++ b/tests/Protocols/Providers/Arksa/2_response.txt @@ -0,0 +1,3 @@ +{"access_token":"eyJraWQiOiIyMDIyLTA2LTE0VDA2OjE3OjU3LjA0NzkyODcwMFoiLCJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJjbGllbnRJZCI6Inh5emE3ODkxbXVvbVJteW5JSUhhSkI5Q09CS2t3ajZuIiwicHJvZHVjdElkIjoiOTg1ZGM0ZDY3ZmYxNDI1ODhiNjM5M2M0NmIxZGZmODQiLCJpc3MiOiJlb3MiLCJlbnYiOiJwcm9kIiwib3JnYW5pemF0aW9uSWQiOiJvLXVzdmZibWxxZHQ2Nzh2cnAzNnF2bTJkNWN6MmNwciIsImZlYXR1cmVzIjpbIkFjaGlldmVtZW50cyIsIkNvbm5lY3QiLCJFY29tIiwiTGVhZGVyYm9hcmRzIiwiTWF0Y2htYWtpbmciLCJNZXRyaWNzIiwiU3RhdHMiLCJWb2ljZSJdLCJkZXBsb3ltZW50SWQiOiJhZDlhOGZlZmZiM2I0YjJjYTMxNTU0NmYwMzhjM2FlMiIsInNhbmRib3hJZCI6ImRhZTgwYzBkNGUzYjRkNjQ4NDk4YjQ4YWY2MDliOGJiIiwidG9rZW5UeXBlIjoiY2xpZW50VG9rZW4iLCJleHAiOjE3MzQ1MjI1NzEsImlhdCI6MTczNDUxODk3MSwianRpIjoiNGVhZGMxMDE5YThhNDFiNmJmMjg1MmVjOWVjYWUyYjAifQ.mIdSO3jrVkmvZ6pmtS3ab47PsLp2Qu89CXELl5EyubJug6HM3bfvEG7PO0XWJpLt6C3nnVYncF3v67uEL-Ix5LQoo3oY3seEciPb2MsY-DuIIAmaFWd6julIohQLO0i2M8owp7L6IWU3Sl340FBYsCJ61fVqwTV5bXLABt4M4TDdJgUfeRwsYSdruqeQHn7uMbhYrVoGRuP4S6grTkm9JbwBWT8677IN9kUBYo9kC8LHVWkOsZyrR1yjoiUDqXHzHp_WM5lF5DWH85SWbO0jDxKCawB1N_QKRkD1CdaO1vBYONRFrg3HbTVY_POvrnvHwS6CzarMMNWkmdylQ7TRZA","token_type":"bearer","expires_at":"2024-12-18T11:49:31.012Z","features":["Achievements","Connect","Ecom","Leaderboards","Matchmaking","Metrics","Stats","Voice"],"organization_id":"o-usvfbmlqdt678vrp36qvm2d5cz2cpr","product_id":"985dc4d67ff142588b6393c46b1dff84","sandbox_id":"dae80c0d4e3b4d648498b48af609b8bb","deployment_id":"ad9a8feffb3b4b2ca315546f038c3ae2","expires_in":3599} +|| +{"sessions":[{"deployment":"ad9a8feffb3b4b2ca315546f038c3ae2","id":"5a711eafaf2a45f3b27607210b28cade","bucket":"TestGameMode_C::TheCenter_WP","settings":{"maxPublicPlayers":70,"allowInvites":true,"shouldAdvertise":true,"allowReadById":true,"allowJoinViaPresence":true,"allowJoinInProgress":true,"allowConferenceRoom":false,"checkSanctions":false,"allowMigration":false,"rejoinAfterKick":"","platforms":null},"totalPlayers":1,"openPublicPlayers":69,"publicPlayers":[],"started":false,"lastUpdated":null,"attributes":{"MINORBUILDID_s":"18","MODID_l":0,"CUSTOMSERVERNAME_s":"Asia-PVP-TheCenter2430","ISPRIVATE_l":0,"SERVERPASSWORD_b":false,"MATCHTIMEOUT_d":120.0,"ENABLEDMODSFILEIDS_s":"","DAYTIME_s":"2547","SOTFMATCHSTARTED_b":false,"STEELSHIELDENABLED_l":1,"SERVERUSESBATTLEYE_b":true,"EOSSERVERPING_l":297,"ALLOWDOWNLOADCHARS_l":1,"OFFICIALSERVER_s":"1","GAMEMODE_s":"TestGameMode_C","ADDRESS_s":"5.62.119.20","SEARCHKEYWORDS_s":"Custom","__EOS_BLISTENING_b":true,"ALLOWDOWNLOADITEMS_l":1,"LEGACY_l":0,"ADDRESSBOUND_s":"0.0.0.0:7777","SESSIONISPVE_l":0,"__EOS_BUSESPRESENCE_b":true,"PASSIVEMODS_s":"","CLUSTERID_s":"PVPCrossplay","ENABLEDMODS_s":"","SESSIONNAMEUPPER_s":"ASIA-PVP-THECENTER2430 - (V56.18)","SERVERPLATFORMTYPE_s":"PC+PS5+XSX","MAPNAME_s":"TheCenter_WP","BUILDID_s":"56","SESSIONNAME_s":"Asia-PVP-TheCenter2430 - (v56.18)"},"owner":"Client_xyza7891muomRmynIIHaJB9COBKkwj6n","ownerPlatformId":null},{"deployment":"ad9a8feffb3b4b2ca315546f038c3ae2","id":"a92643e6fa794703acefada43026d7c6","bucket":"TestGameMode_C::TheCenter_WP","settings":{"maxPublicPlayers":70,"allowInvites":true,"shouldAdvertise":true,"allowReadById":true,"allowJoinViaPresence":true,"allowJoinInProgress":true,"allowConferenceRoom":false,"checkSanctions":false,"allowMigration":false,"rejoinAfterKick":"","platforms":null},"totalPlayers":13,"openPublicPlayers":57,"publicPlayers":[],"started":false,"lastUpdated":null,"attributes":{"MINORBUILDID_s":"18","MODID_l":0,"CUSTOMSERVERNAME_s":"Asia-PVE-TheCenter5652","ISPRIVATE_l":0,"SERVERPASSWORD_b":false,"MATCHTIMEOUT_d":120.0,"DAYTIME_s":"2515","SOTFMATCHSTARTED_b":false,"STEELSHIELDENABLED_l":1,"FRIENDLYMAPNAME_s":"TheCenter_WP","SERVERUSESBATTLEYE_b":true,"EOSSERVERPING_l":206,"ALLOWDOWNLOADCHARS_l":1,"OFFICIALSERVER_s":"1","GAMEMODE_s":"TestGameMode_C","ADDRESS_s":"5.62.119.20","SEARCHKEYWORDS_s":"Custom","__EOS_BLISTENING_b":true,"ALLOWDOWNLOADITEMS_l":1,"LEGACY_l":0,"ADDRESSBOUND_s":"0.0.0.0:7779","SESSIONISPVE_l":1,"__EOS_BUSESPRESENCE_b":true,"CLUSTERID_s":"PVECrossplay","SESSIONNAMEUPPER_s":"ASIA-PVE-THECENTER5652 - (V56.18)","SERVERPLATFORMTYPE_s":"PC+XSX+WINGDK+PS5","MAPNAME_s":"TheCenter_WP","BUILDID_s":"56","SESSIONNAME_s":"Asia-PVE-TheCenter5652 - (v56.18)"},"owner":"Client_xyza7891muomRmynIIHaJB9COBKkwj6n","ownerPlatformId":null},{"deployment":"ad9a8feffb3b4b2ca315546f038c3ae2","id":"5add778e58494559a92e98c08767e458","bucket":"TestGameMode_C::TheCenter_WP","settings":{"maxPublicPlayers":70,"allowInvites":true,"shouldAdvertise":true,"allowReadById":true,"allowJoinViaPresence":true,"allowJoinInProgress":true,"allowConferenceRoom":false,"checkSanctions":false,"allowMigration":false,"rejoinAfterKick":"","platforms":null},"totalPlayers":1,"openPublicPlayers":69,"publicPlayers":[],"started":false,"lastUpdated":null,"attributes":{"MINORBUILDID_s":"18","MODID_l":0,"CUSTOMSERVERNAME_s":"Asia-PVP-TheCenter2430","ISPRIVATE_l":0,"SERVERPASSWORD_b":false,"MATCHTIMEOUT_d":120.0,"DAYTIME_s":"2547","SOTFMATCHSTARTED_b":false,"STEELSHIELDENABLED_l":1,"FRIENDLYMAPNAME_s":"TheCenter_WP","SERVERUSESBATTLEYE_b":true,"EOSSERVERPING_l":299,"ALLOWDOWNLOADCHARS_l":1,"OFFICIALSERVER_s":"1","GAMEMODE_s":"TestGameMode_C","ADDRESS_s":"5.62.119.20","SEARCHKEYWORDS_s":"Custom","__EOS_BLISTENING_b":true,"ALLOWDOWNLOADITEMS_l":1,"LEGACY_l":0,"ADDRESSBOUND_s":"0.0.0.0:7777","SESSIONISPVE_l":0,"__EOS_BUSESPRESENCE_b":true,"CLUSTERID_s":"PVPCrossplay","SESSIONNAMEUPPER_s":"ASIA-PVP-THECENTER2430 - (V56.18)","SERVERPLATFORMTYPE_s":"PC+PS5+XSX","MAPNAME_s":"TheCenter_WP","BUILDID_s":"56","SESSIONNAME_s":"Asia-PVP-TheCenter2430 - (v56.18)"},"owner":"Client_xyza7891muomRmynIIHaJB9COBKkwj6n","ownerPlatformId":null},{"deployment":"ad9a8feffb3b4b2ca315546f038c3ae2","id":"4fdb413eac3146a39eb430659a845665","bucket":"TestGameMode_C::TheCenter_WP","settings":{"maxPublicPlayers":70,"allowInvites":true,"shouldAdvertise":true,"allowReadById":true,"allowJoinViaPresence":true,"allowJoinInProgress":true,"allowConferenceRoom":false,"checkSanctions":false,"allowMigration":false,"rejoinAfterKick":"","platforms":null},"totalPlayers":19,"openPublicPlayers":51,"publicPlayers":[],"started":false,"lastUpdated":null,"attributes":{"MINORBUILDID_s":"18","MODID_l":0,"CUSTOMSERVERNAME_s":"Asia-PVE-TheCenter5653","ISPRIVATE_l":0,"SERVERPASSWORD_b":false,"MATCHTIMEOUT_d":120.0,"DAYTIME_s":"2512","SOTFMATCHSTARTED_b":false,"STEELSHIELDENABLED_l":1,"FRIENDLYMAPNAME_s":"TheCenter_WP","SERVERUSESBATTLEYE_b":true,"EOSSERVERPING_l":177,"ALLOWDOWNLOADCHARS_l":1,"OFFICIALSERVER_s":"1","GAMEMODE_s":"TestGameMode_C","ADDRESS_s":"5.62.119.20","SEARCHKEYWORDS_s":"Custom","__EOS_BLISTENING_b":true,"ALLOWDOWNLOADITEMS_l":1,"LEGACY_l":0,"ADDRESSBOUND_s":"0.0.0.0:7781","SESSIONISPVE_l":1,"__EOS_BUSESPRESENCE_b":true,"CLUSTERID_s":"PVECrossplay","SESSIONNAMEUPPER_s":"ASIA-PVE-THECENTER5653 - (V56.18)","SERVERPLATFORMTYPE_s":"PC+XSX+WINGDK+PS5","MAPNAME_s":"TheCenter_WP","BUILDID_s":"56","SESSIONNAME_s":"Asia-PVE-TheCenter5653 - (v56.18)"},"owner":"Client_xyza7891muomRmynIIHaJB9COBKkwj6n","ownerPlatformId":null},{"deployment":"ad9a8feffb3b4b2ca315546f038c3ae2","id":"7abf7a6afdb54a92a00da9d8d76dbc1d","bucket":"TestGameMode_C::Aberration_WP","settings":{"maxPublicPlayers":70,"allowInvites":true,"shouldAdvertise":true,"allowReadById":true,"allowJoinViaPresence":true,"allowJoinInProgress":true,"allowConferenceRoom":false,"checkSanctions":false,"allowMigration":false,"rejoinAfterKick":"","platforms":null},"totalPlayers":3,"openPublicPlayers":67,"publicPlayers":[],"started":false,"lastUpdated":null,"attributes":{"MINORBUILDID_s":"18","MODID_l":0,"CUSTOMSERVERNAME_s":"Asia-PVP-Aberration2475","ISPRIVATE_l":0,"SERVERPASSWORD_b":false,"MATCHTIMEOUT_d":120.0,"DAYTIME_s":"2472","SOTFMATCHSTARTED_b":false,"STEELSHIELDENABLED_l":1,"FRIENDLYMAPNAME_s":"Aberration_WP","SERVERUSESBATTLEYE_b":true,"EOSSERVERPING_l":242,"ALLOWDOWNLOADCHARS_l":1,"OFFICIALSERVER_s":"1","GAMEMODE_s":"TestGameMode_C","ADDRESS_s":"5.62.119.20","SEARCHKEYWORDS_s":"Custom","__EOS_BLISTENING_b":true,"ALLOWDOWNLOADITEMS_l":1,"LEGACY_l":0,"ADDRESSBOUND_s":"0.0.0.0:7783","SESSIONISPVE_l":0,"__EOS_BUSESPRESENCE_b":true,"CLUSTERID_s":"PVPCrossplay","SESSIONNAMEUPPER_s":"ASIA-PVP-ABERRATION2475 - (V56.18)","SERVERPLATFORMTYPE_s":"PC+PS5+XSX","MAPNAME_s":"Aberration_WP","BUILDID_s":"56","SESSIONNAME_s":"Asia-PVP-Aberration2475 - (v56.18)"},"owner":"Client_xyza7891muomRmynIIHaJB9COBKkwj6n","ownerPlatformId":null}],"count":5} \ No newline at end of file diff --git a/tests/Protocols/Providers/Arksa/2_result.json b/tests/Protocols/Providers/Arksa/2_result.json new file mode 100644 index 00000000..8e8fb58f --- /dev/null +++ b/tests/Protocols/Providers/Arksa/2_result.json @@ -0,0 +1 @@ +{"5.62.119.20:7779":{"allowJoinInProgress":true,"anticheat":true,"day":"2515","gq_address":"5.62.119.20","gq_joinlink":null,"gq_name":"ARK: Survival Ascended","gq_online":true,"gq_port_client":7779,"gq_port_query":7779,"gq_protocol":"arksa","gq_transport":"tcp","gq_type":"arksa","hostname":"Asia-PVE-TheCenter5652","mapname":"TheCenter_WP","maxplayers":70,"numplayers":13,"officialserver":true,"password":false,"pve":true,"version":"v56.18"}} \ No newline at end of file diff --git a/tests/Protocols/Providers/Arksa/3_response.txt b/tests/Protocols/Providers/Arksa/3_response.txt new file mode 100644 index 00000000..861c843d --- /dev/null +++ b/tests/Protocols/Providers/Arksa/3_response.txt @@ -0,0 +1,3 @@ +{"access_token":"eyJraWQiOiIyMDIyLTA2LTE0VDA2OjE3OjU3LjA0NzkyODcwMFoiLCJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJjbGllbnRJZCI6Inh5emE3ODkxbXVvbVJteW5JSUhhSkI5Q09CS2t3ajZuIiwicHJvZHVjdElkIjoiOTg1ZGM0ZDY3ZmYxNDI1ODhiNjM5M2M0NmIxZGZmODQiLCJpc3MiOiJlb3MiLCJlbnYiOiJwcm9kIiwib3JnYW5pemF0aW9uSWQiOiJvLXVzdmZibWxxZHQ2Nzh2cnAzNnF2bTJkNWN6MmNwciIsImZlYXR1cmVzIjpbIkFjaGlldmVtZW50cyIsIkNvbm5lY3QiLCJFY29tIiwiTGVhZGVyYm9hcmRzIiwiTWF0Y2htYWtpbmciLCJNZXRyaWNzIiwiU3RhdHMiLCJWb2ljZSJdLCJkZXBsb3ltZW50SWQiOiJhZDlhOGZlZmZiM2I0YjJjYTMxNTU0NmYwMzhjM2FlMiIsInNhbmRib3hJZCI6ImRhZTgwYzBkNGUzYjRkNjQ4NDk4YjQ4YWY2MDliOGJiIiwidG9rZW5UeXBlIjoiY2xpZW50VG9rZW4iLCJleHAiOjE3MzQ1MjI1ODEsImlhdCI6MTczNDUxODk4MSwianRpIjoiYTg5NTFiNjg4NTYwNDMyYTlkZWZlMGZiZThiMThjYmYifQ.c8KpgfO-KNjBqjxIMkFHWjEQRDnCwp41REjQFpPD5w4IcsVCcH0bkuU4g0pBESkIltb2SeqDPztsq9xJgIdJ0gECfiAo9g2_njm8ZWmYbgygPIXWst5AJPDt6wghj_B7zObd2Ez1qdqHW9GkjXZ8QaMjfGdtt806L6spyoAeHp66IIfY6mkwA6vZl9fk4SIb5OTDEb-gBQlYVWnY6txrjuJJJeDZDKh3Ky6sB6a3fYbPQsjZVnU8hxtVHTlnzkWfMrBxvt9kgTXayQUKV3_AM6BKLtl2L8HdQbs37nJCGp-6poCL3A_47vlaKJtN0ZgMX7Yg8pLwrXmiaa1jfZGxgQ","token_type":"bearer","expires_at":"2024-12-18T11:49:41.150Z","features":["Achievements","Connect","Ecom","Leaderboards","Matchmaking","Metrics","Stats","Voice"],"organization_id":"o-usvfbmlqdt678vrp36qvm2d5cz2cpr","product_id":"985dc4d67ff142588b6393c46b1dff84","sandbox_id":"dae80c0d4e3b4d648498b48af609b8bb","deployment_id":"ad9a8feffb3b4b2ca315546f038c3ae2","expires_in":3599} +|| +{"sessions":[{"deployment":"ad9a8feffb3b4b2ca315546f038c3ae2","id":"b20315b60f494e7e9e1c74d2089746a2","bucket":"TestGameMode_C::TheIsland_WP","settings":{"maxPublicPlayers":70,"allowInvites":true,"shouldAdvertise":true,"allowReadById":true,"allowJoinViaPresence":true,"allowJoinInProgress":true,"allowConferenceRoom":false,"checkSanctions":false,"allowMigration":false,"rejoinAfterKick":"","platforms":null},"totalPlayers":5,"openPublicPlayers":65,"publicPlayers":[],"started":false,"lastUpdated":null,"attributes":{"MINORBUILDID_s":"18","MODID_l":0,"CUSTOMSERVERNAME_s":"NA-PVE-TheIsland5174","ISPRIVATE_l":0,"SERVERPASSWORD_b":false,"MATCHTIMEOUT_d":120.0,"DAYTIME_s":"5096","SOTFMATCHSTARTED_b":false,"STEELSHIELDENABLED_l":1,"FRIENDLYMAPNAME_s":"TheIsland_WP","SERVERUSESBATTLEYE_b":true,"EOSSERVERPING_l":210,"ALLOWDOWNLOADCHARS_l":1,"OFFICIALSERVER_s":"1","GAMEMODE_s":"TestGameMode_C","ADDRESS_s":"5.62.114.2","SEARCHKEYWORDS_s":"Custom","__EOS_BLISTENING_b":true,"ALLOWDOWNLOADITEMS_l":1,"LEGACY_l":0,"ADDRESSBOUND_s":"0.0.0.0:7777","SESSIONISPVE_l":1,"__EOS_BUSESPRESENCE_b":true,"CLUSTERID_s":"PVECrossplay","SESSIONNAMEUPPER_s":"NA-PVE-THEISLAND5174 - (V56.18)","SERVERPLATFORMTYPE_s":"PC+XSX+WINGDK+PS5","MAPNAME_s":"TheIsland_WP","BUILDID_s":"56","SESSIONNAME_s":"NA-PVE-TheIsland5174 - (v56.18)"},"owner":"Client_xyza7891muomRmynIIHaJB9COBKkwj6n","ownerPlatformId":null},{"deployment":"ad9a8feffb3b4b2ca315546f038c3ae2","id":"ec3139bee09b4b1cad09e2a1810d5632","bucket":"TestGameMode_C::TheIsland_WP","settings":{"maxPublicPlayers":70,"allowInvites":true,"shouldAdvertise":true,"allowReadById":true,"allowJoinViaPresence":true,"allowJoinInProgress":true,"allowConferenceRoom":false,"checkSanctions":false,"allowMigration":false,"rejoinAfterKick":"","platforms":null},"totalPlayers":3,"openPublicPlayers":67,"publicPlayers":[],"started":false,"lastUpdated":null,"attributes":{"MINORBUILDID_s":"18","MODID_l":0,"CUSTOMSERVERNAME_s":"NA-PVE-TheIsland5176","ISPRIVATE_l":0,"SERVERPASSWORD_b":false,"MATCHTIMEOUT_d":120.0,"DAYTIME_s":"5080","SOTFMATCHSTARTED_b":false,"STEELSHIELDENABLED_l":1,"FRIENDLYMAPNAME_s":"TheIsland_WP","SERVERUSESBATTLEYE_b":true,"EOSSERVERPING_l":152,"ALLOWDOWNLOADCHARS_l":1,"OFFICIALSERVER_s":"1","GAMEMODE_s":"TestGameMode_C","ADDRESS_s":"5.62.114.2","SEARCHKEYWORDS_s":"Custom","__EOS_BLISTENING_b":true,"ALLOWDOWNLOADITEMS_l":1,"LEGACY_l":0,"ADDRESSBOUND_s":"0.0.0.0:7781","SESSIONISPVE_l":1,"__EOS_BUSESPRESENCE_b":true,"CLUSTERID_s":"PVECrossplay","SESSIONNAMEUPPER_s":"NA-PVE-THEISLAND5176 - (V56.18)","SERVERPLATFORMTYPE_s":"PC+XSX+WINGDK+PS5","MAPNAME_s":"TheIsland_WP","BUILDID_s":"56","SESSIONNAME_s":"NA-PVE-TheIsland5176 - (v56.18)"},"owner":"Client_xyza7891muomRmynIIHaJB9COBKkwj6n","ownerPlatformId":null},{"deployment":"ad9a8feffb3b4b2ca315546f038c3ae2","id":"c88dc644533c47d08bd99f91e0a425f4","bucket":"TestGameMode_C::TheIsland_WP","settings":{"maxPublicPlayers":70,"allowInvites":true,"shouldAdvertise":true,"allowReadById":true,"allowJoinViaPresence":true,"allowJoinInProgress":true,"allowConferenceRoom":false,"checkSanctions":false,"allowMigration":false,"rejoinAfterKick":"","platforms":null},"totalPlayers":7,"openPublicPlayers":63,"publicPlayers":[],"started":false,"lastUpdated":null,"attributes":{"MINORBUILDID_s":"18","MODID_l":0,"CUSTOMSERVERNAME_s":"NA-PVE-TheIsland5175","ISPRIVATE_l":0,"SERVERPASSWORD_b":false,"MATCHTIMEOUT_d":120.0,"DAYTIME_s":"5089","SOTFMATCHSTARTED_b":false,"STEELSHIELDENABLED_l":1,"FRIENDLYMAPNAME_s":"TheIsland_WP","SERVERUSESBATTLEYE_b":true,"EOSSERVERPING_l":241,"ALLOWDOWNLOADCHARS_l":1,"OFFICIALSERVER_s":"1","GAMEMODE_s":"TestGameMode_C","ADDRESS_s":"5.62.114.2","SEARCHKEYWORDS_s":"Custom","__EOS_BLISTENING_b":true,"ALLOWDOWNLOADITEMS_l":1,"LEGACY_l":0,"ADDRESSBOUND_s":"0.0.0.0:7779","SESSIONISPVE_l":1,"__EOS_BUSESPRESENCE_b":true,"CLUSTERID_s":"PVECrossplay","SESSIONNAMEUPPER_s":"NA-PVE-THEISLAND5175 - (V56.18)","SERVERPLATFORMTYPE_s":"PC+XSX+WINGDK+PS5","MAPNAME_s":"TheIsland_WP","BUILDID_s":"56","SESSIONNAME_s":"NA-PVE-TheIsland5175 - (v56.18)"},"owner":"Client_xyza7891muomRmynIIHaJB9COBKkwj6n","ownerPlatformId":null},{"deployment":"ad9a8feffb3b4b2ca315546f038c3ae2","id":"9ccfc376fc114d02b0a16680f0d80e91","bucket":"TestGameMode_C::TheIsland_WP","settings":{"maxPublicPlayers":70,"allowInvites":true,"shouldAdvertise":true,"allowReadById":true,"allowJoinViaPresence":true,"allowJoinInProgress":true,"allowConferenceRoom":false,"checkSanctions":false,"allowMigration":false,"rejoinAfterKick":"","platforms":null},"totalPlayers":3,"openPublicPlayers":67,"publicPlayers":[],"started":false,"lastUpdated":null,"attributes":{"MINORBUILDID_s":"18","MODID_l":0,"CUSTOMSERVERNAME_s":"NA-PVE-TheIsland5177","ISPRIVATE_l":0,"SERVERPASSWORD_b":false,"MATCHTIMEOUT_d":120.0,"DAYTIME_s":"5046","SOTFMATCHSTARTED_b":false,"STEELSHIELDENABLED_l":1,"FRIENDLYMAPNAME_s":"TheIsland_WP","SERVERUSESBATTLEYE_b":true,"EOSSERVERPING_l":228,"ALLOWDOWNLOADCHARS_l":1,"OFFICIALSERVER_s":"1","GAMEMODE_s":"TestGameMode_C","ADDRESS_s":"5.62.114.2","SEARCHKEYWORDS_s":"Custom","__EOS_BLISTENING_b":true,"ALLOWDOWNLOADITEMS_l":1,"LEGACY_l":0,"ADDRESSBOUND_s":"0.0.0.0:7783","SESSIONISPVE_l":1,"__EOS_BUSESPRESENCE_b":true,"CLUSTERID_s":"PVECrossplay","SESSIONNAMEUPPER_s":"NA-PVE-THEISLAND5177 - (V56.18)","SERVERPLATFORMTYPE_s":"PC+XSX+WINGDK+PS5","MAPNAME_s":"TheIsland_WP","BUILDID_s":"56","SESSIONNAME_s":"NA-PVE-TheIsland5177 - (v56.18)"},"owner":"Client_xyza7891muomRmynIIHaJB9COBKkwj6n","ownerPlatformId":null}],"count":4} \ No newline at end of file diff --git a/tests/Protocols/Providers/Arksa/3_result.json b/tests/Protocols/Providers/Arksa/3_result.json new file mode 100644 index 00000000..0c544955 --- /dev/null +++ b/tests/Protocols/Providers/Arksa/3_result.json @@ -0,0 +1 @@ +{"5.62.114.2:7779":{"allowJoinInProgress":true,"anticheat":true,"day":"5089","gq_address":"5.62.114.2","gq_joinlink":null,"gq_name":"ARK: Survival Ascended","gq_online":true,"gq_port_client":7779,"gq_port_query":7779,"gq_protocol":"arksa","gq_transport":"tcp","gq_type":"arksa","hostname":"NA-PVE-TheIsland5175","mapname":"TheIsland_WP","maxplayers":70,"numplayers":7,"officialserver":true,"password":false,"pve":true,"version":"v56.18"}} \ No newline at end of file diff --git a/tests/Protocols/Providers/Stationeers/1_response.txt b/tests/Protocols/Providers/Stationeers/1_response.txt new file mode 100644 index 00000000..2fa52927 --- /dev/null +++ b/tests/Protocols/Providers/Stationeers/1_response.txt @@ -0,0 +1,968 @@ +HTTP/1.1 200 OK +Keep-Alive: true +Content-Length: 22496 +Server: Microsoft-HTTPAPI/2.0 +Date: Tue, 30 Aug 2022 22:29:23 GMT +Connection: close + +{ + "Count": 63, + "TotalPlayers": 22, + "GameSessions": [ + { + "SessionId": 15712, + "Name": "Catch22", + "Version": "0.2.3570.17365", + "Address": "103.114.12.10", + "Checksum": "E4F1D9C5", + "Port": "27016", + "MapName": "Moon", + "Players": 0, + "MaxPlayers": 20, + "Password": true, + "UpTime": 0, + "Latency": 0, + "Type": 2 + }, + { + "SessionId": 15716, + "Name": "Stationeers German/Deutsch BlackLand Hallo Leute leider geht es zu zeit nur in solo spiel :-(", + "Version": "0.2.3570.17365", + "Address": "194.163.170.243", + "Checksum": "B5963DBD", + "Port": "35700", + "MapName": "Mars", + "Players": 0, + "MaxPlayers": 20, + "Password": true, + "UpTime": 0, + "Latency": 0, + "Type": 1 + }, + { + "SessionId": 15721, + "Name": "0GravityBert", + "Version": "0.2.3570.17365", + "Address": "85.215.225.45", + "Checksum": "E916B8BD", + "Port": "27016", + "MapName": "Moon", + "Players": 0, + "MaxPlayers": 5, + "Password": true, + "UpTime": 0, + "Latency": 0, + "Type": 1 + }, + { + "SessionId": 15723, + "Name": "LM - Europa", + "Version": "0.2.3570.17365", + "Address": "159.69.72.154", + "Checksum": "3AE1D2BD", + "Port": "25456", + "MapName": "Europa2", + "Players": 0, + "MaxPlayers": 15, + "Password": true, + "UpTime": 0, + "Latency": 0, + "Type": 1 + }, + { + "SessionId": 15726, + "Name": "meshbase", + "Version": "0.2.3570.17365", + "Address": "103.62.50.20", + "Checksum": "B201B4BD", + "Port": "26510", + "MapName": "Mars", + "Players": 0, + "MaxPlayers": 16, + "Password": true, + "UpTime": 0, + "Latency": 0, + "Type": 1 + }, + { + "SessionId": 15739, + "Name": "4Netplayers Stationeers Server", + "Version": "0.2.3570.17365", + "Address": "62.104.16.117", + "Checksum": "1DCD0495", + "Port": "23800", + "MapName": "Moon", + "Players": 0, + "MaxPlayers": 10, + "Password": true, + "UpTime": 0, + "Latency": 0, + "Type": 1 + }, + { + "SessionId": 15762, + "Name": "Androneers", + "Version": "0.2.3570.17365", + "Address": "47.158.161.12", + "Checksum": "48EB8995", + "Port": "27016", + "MapName": "Proximab", + "Players": 1, + "MaxPlayers": 10, + "Password": true, + "UpTime": 0, + "Latency": 0, + "Type": 0 + }, + { + "SessionId": 15768, + "Name": "Skyvale Interstellar", + "Version": "0.2.3570.17365", + "Address": "185.125.205.100", + "Checksum": "12FCE3C5", + "Port": "18015", + "MapName": "Mars", + "Players": 0, + "MaxPlayers": 8, + "Password": true, + "UpTime": 0, + "Latency": 0, + "Type": 1 + }, + { + "SessionId": 15783, + "Name": "Apollo 4", + "Version": "0.2.3530.17210", + "Address": "87.97.24.142", + "Checksum": "E6432F93", + "Port": "27017", + "MapName": "Mars", + "Players": 0, + "MaxPlayers": 20, + "Password": true, + "UpTime": 0, + "Latency": 0, + "Type": 1 + }, + { + "SessionId": 15789, + "Name": "Grumpy", + "Version": "0.2.3570.17365", + "Address": "47.49.8.74", + "Checksum": "BE8B5395", + "Port": "27016", + "MapName": "Mars", + "Players": 1, + "MaxPlayers": 10, + "Password": true, + "UpTime": 0, + "Latency": 0, + "Type": 0 + }, + { + "SessionId": 15803, + "Name": "Celestra FR", + "Version": "0.2.3570.17365", + "Address": "82.65.179.165", + "Checksum": "39B0CCBD", + "Port": "23520", + "MapName": "Europa", + "Players": 0, + "MaxPlayers": 4, + "Password": true, + "UpTime": 0, + "Latency": 0, + "Type": 2 + }, + { + "SessionId": 15808, + "Name": "StationeersSamnick", + "Version": "0.2.3587.17443", + "Address": "159.69.72.154", + "C +|| +hecksum": "8A8DE0B5", + "Port": "25448", + "MapName": "Mimas", + "Players": 0, + "MaxPlayers": 15, + "Password": true, + "UpTime": 0, + "Latency": 0, + "Type": 1 + }, + { + "SessionId": 15810, + "Name": "Celestra Fr Mars", + "Version": "0.2.3570.17365", + "Address": "82.65.179.165", + "Checksum": "1207EAED", + "Port": "23536", + "MapName": "Mars", + "Players": 0, + "MaxPlayers": 4, + "Password": true, + "UpTime": 0, + "Latency": 0, + "Type": 2 + }, + { + "SessionId": 15832, + "Name": "Devilscary", + "Version": "0.2.3570.17365", + "Address": "74.210.225.225", + "Checksum": "7C080395", + "Port": "27516", + "MapName": "Mars", + "Players": 1, + "MaxPlayers": 10, + "Password": true, + "UpTime": 0, + "Latency": 0, + "Type": 0 + }, + { + "SessionId": 15844, + "Name": "4Netplayers Mars 1 geht leider nicht", + "Version": "0.2.3570.17365", + "Address": "62.104.16.117", + "Checksum": "35AC3EBD", + "Port": "34000", + "MapName": "Mars", + "Players": 0, + "MaxPlayers": 8, + "Password": true, + "UpTime": 0, + "Latency": 0, + "Type": 1 + }, + { + "SessionId": 15859, + "Name": "UrMimas", + "Version": "0.2.3570.17365", + "Address": "71.236.26.5", + "Checksum": "9DC30595", + "Port": "27016", + "MapName": "Mimas", + "Players": 0, + "MaxPlayers": 5, + "Password": true, + "UpTime": 0, + "Latency": 0, + "Type": 2 + }, + { + "SessionId": 15862, + "Name": "Stationeers", + "Version": "0.2.3570.17365", + "Address": "54.36.166.128", + "Checksum": "9CCCCC5", + "Port": "18015", + "MapName": "Mars", + "Players": 0, + "MaxPlayers": 8, + "Password": true, + "UpTime": 0, + "Latency": 0, + "Type": 1 + }, + { + "SessionId": 15899, + "Name": "The D Venus", + "Version": "0.2.3570.17365", + "Address": "192.169.80.42", + "Checksum": "52EF5995", + "Port": "18265", + "MapName": "Venus", + "Players": 0, + "MaxPlayers": 8, + "Password": true, + "UpTime": 0, + "Latency": 0, + "Type": 1 + }, + { + "SessionId": 15914, + "Name": "Executoronline Mars", + "Version": "0.2.3530.17210", + "Address": "95.216.38.190", + "Checksum": "2EB64593", + "Port": "27016", + "MapName": "Mars", + "Players": 0, + "MaxPlayers": 10, + "Password": true, + "UpTime": 0, + "Latency": 0, + "Type": 2 + }, + { + "SessionId": 15921, + "Name": "Sanctuary", + "Version": "0.2.3570.17365", + "Address": "78.157.70.82", + "Checksum": "8ACED595", + "Port": "27016", +|| + + "MapName": "Europa2", + "Players": 0, + "MaxPlayers": 10, + "Password": true, + "UpTime": 0, + "Latency": 0, + "Type": 2 + }, + { + "SessionId": 15931, + "Name": "Muns (NZ)", + "Version": "0.2.3570.17365", + "Address": "101.100.143.138", + "Checksum": "83695095", + "Port": "30000", + "MapName": "Moon", + "Players": 0, + "MaxPlayers": 8, + "Password": false, + "UpTime": 0, + "Latency": 0, + "Type": 1 + }, + { + "SessionId": 15944, + "Name": "devildogs", + "Version": "0.2.3570.17365", + "Address": "74.141.20.22", + "Checksum": "8763F395", + "Port": "27016", + "MapName": "", + "Players": 1, + "MaxPlayers": 10, + "Password": true, + "UpTime": 0, + "Latency": 0, + "Type": 0 + }, + { + "SessionId": 15947, + "Name": "Avalon Reborn", + "Version": "0.2.3570.17365", + "Address": "51.89.173.203", + "Checksum": "CFF75995", + "Port": "18025", + "MapName": "Venus", + "Players": 0, + "MaxPlayers": 8, + "Password": true, + "UpTime": 0, + "Latency": 0, + "Type": 1 + }, + { + "SessionId": 15961, + "Name": "VULCAN FR", + "Version": "0.2.3570.17365", + "Address": "82.66.177.148", + "Checksum": "7AAB2BBD", + "Port": "27016", + "MapName": "Vulcan2", + "Players": 1, + "MaxPlayers": 10, + "Password": true, + "UpTime": 0, + "Latency": 0, + "Type": 0 + }, + { + "SessionId": 15974, + "Name": "Kevineers", + "Version": "0.2.3570.17365", + "Address": "73.42.182.16", + "Checksum": "EE214C95", + "Port": "27016", + "MapName": "Vulcan2", + "Players": 0, + "MaxPlayers": 10, + "Password": true, + "UpTime": 0, + "Latency": 0, + "Type": 1 + }, + { + "SessionId": 16003, + "Name": "PTA Stationeers Mars", + "Version": "0.2.3570.17365", + "Address": "23.120.182.72", + "Checksum": "C5B3F8ED", + "Port": "27569", + "MapName": "MarsPTA", + "Players": 0, + "MaxPlayers": 10, + "Password": true, + "UpTime": 0, + "Latency": 0, + "Type": 1 + }, + { + "SessionId": 16012, + "Name": "Devyns Play Thing", + "Version": "0.2.3588.17444", + "Address": "66.94.126.83", + "Checksum": "1076A8B5", + "Port": "27501", + "MapName": "Vulcan", + "Players": 0, + "MaxPlayers": 10, + "Password": false, + "UpTime": 0, + "Latency": 0, + "Type": 2 + }, + { + "SessionId": 16031, + "Name": "FeenixDedi", + "Version": "0.2.3570.17365", + "Address": "68.3.236.182", + "Checksum": "F3448495", + "Port": "27016", + "MapName": "Mars", + "Players": 0, + " +|| +MaxPlayers": 3, + "Password": true, + "UpTime": 0, + "Latency": 0, + "Type": 1 + }, + { + "SessionId": 16051, + "Name": "Bard Moon Adventure", + "Version": "0.2.3570.17365", + "Address": "5.95.156.237", + "Checksum": "FDFB58C5", + "Port": "27016", + "MapName": "Mars", + "Players": 0, + "MaxPlayers": 10, + "Password": true, + "UpTime": 0, + "Latency": 0, + "Type": 1 + }, + { + "SessionId": 16054, + "Name": "Gamers Hub Official", + "Version": "0.2.3570.17365", + "Address": "104.238.220.19", + "Checksum": "743818C5", + "Port": "25444", + "MapName": "Moon", + "Players": 0, + "MaxPlayers": 10, + "Password": true, + "UpTime": 0, + "Latency": 0, + "Type": 1 + }, + { + "SessionId": 16059, + "Name": "STONER PLANET", + "Version": "0.2.3588.17444", + "Address": "145.239.130.135", + "Checksum": "2C527C9D", + "Port": "18015", + "MapName": "Mars", + "Players": 0, + "MaxPlayers": 8, + "Password": true, + "UpTime": 0, + "Latency": 0, + "Type": 1 + }, + { + "SessionId": 16061, + "Name": "allinone", + "Version": "0.2.3570.17365", + "Address": "84.131.212.232", + "Checksum": "517229ED", + "Port": "27016", + "MapName": "Mars", + "Players": 1, + "MaxPlayers": 10, + "Password": true, + "UpTime": 0, + "Latency": 0, + "Type": 0 + }, + { + "SessionId": 16064, + "Name": "Peekas", + "Version": "0.2.3588.17444", + "Address": "173.212.250.184", + "Checksum": "88B006B5", + "Port": "27016", + "MapName": "Mars", + "Players": 0, + "MaxPlayers": 10, + "Password": true, + "UpTime": 0, + "Latency": 0, + "Type": 2 + }, + { + "SessionId": 16065, + "Name": "Kepler452B", + "Version": "0.2.3570.17365", + "Address": "73.158.104.124", + "Checksum": "8610CC5", + "Port": "27500", + "MapName": "Kepler452B", + "Players": 0, + "MaxPlayers": 30, + "Password": true, + "UpTime": 0, + "Latency": 0, + "Type": 2 + }, + { + "SessionId": 16070, + "Name": "Goatstation5", + "Version": "0.2.3570.17365", + "Address": "192.169.86.146", + "Checksum": "91967EED", + "Port": "18015", + "MapName": "Moon", + "Players": 0, + "MaxPlayers": 8, + "Password": true, + "UpTime": 0, + "Latency": 0, + "Type": 1 + }, + { + "SessionId": 16095, + "Name": "Amogus", + "Version": "0.2.3570.17365", + "Address": "185.60.46.74", + "Checksum": "C52E6DC5", + "Port": "27016", + "MapName": "Mars", + "Players": 1, + "MaxPlayers": 10, + "Password": true, + "UpTime": 0, + "Latency": 0, + "Type": 0 + }, + { + "SessionId": 16098, + "Name": "Dholio", + "Version": "0.2.3530.17210", + "Address": "154.127.54.201", + "Checksum": "7B290DEB", + "Port": "18015", + "MapName": "beachmars", + "Players": 0, + "MaxPlayers": 8, + "Password": true, + "UpTime": 0, + "Latency": 0, + "Type": 1 + }, + { + "SessionId": 16108, + "Name": "DSR", + "Version": "0.2.3570.17365", + "Address": "71.127.216.19", + "Checksum": "8F599DC5", + "Port": "27016", + "MapName": "", + "Players": 1, + "MaxPlayers": 30, + "Password": true, + "UpTime": 0, + "Latency": 0, + "Type": 0 + }, + { + "SessionId": 16123, + "Name": "Hyden", + "Version": "0.2.3570.17365", + "Address": "81.43.208.3", + "Checksum": "7E571595", + "Port": "27016", + "MapName": "Mars", + "Players": 1, + "MaxPlayers": 10, + "Password": true, + "UpTime": 0, + "Latency": 0, + "Type": 0 + }, + { + "SessionId": 16125, + "Name": "M2M", + "Version": "0.2.3570.17365", + "Address": "178.167.195.138", + "Checksum": "8FB6E2C5", + "Port": "27016", + "MapName": "Mars", + "Players": 0, + "MaxPlayers": 11, + "Password": true, + "UpTime": 0, + "Latency": 0, + "Type": 1 + }, + { + +|| + "SessionId": 16136, + "Name": "Oymyakon", + "Version": "0.2.3570.17365", + "Address": "151.224.246.46", + "Checksum": "2C31F7C5", + "Port": "27016", + "MapName": "Syberia", + "Players": 1, + "MaxPlayers": 10, + "Password": true, + "UpTime": 0, + "Latency": 0, + "Type": 0 + }, + { + "SessionId": 16138, + "Name": "BlueHell", + "Version": "0.2.3570.17365", + "Address": "178.27.166.108", + "Checksum": "D834E195", + "Port": "27016", + "MapName": "Mars", + "Players": 1, + "MaxPlayers": 10, + "Password": true, + "UpTime": 0, + "Latency": 0, + "Type": 0 + }, + { + "SessionId": 16145, + "Name": "Tehscott's Stationeers", + "Version": "0.2.3588.17444", + "Address": "71.237.87.148", + "Checksum": "90B5B6CD", + "Port": "27016", + "MapName": "Europa2", + "Players": 0, + "MaxPlayers": 10, + "Password": true, + "UpTime": 0, + "Latency": 0, + "Type": 1 + }, + { + "SessionId": 16149, + "Name": "Bastards Inc", + "Version": "0.2.3570.17365", + "Address": "75.174.200.93", + "Checksum": "8BA4B495", + "Port": "27016", + "MapName": "Mars", + "Players": 0, + "MaxPlayers": 30, + "Password": true, + "UpTime": 0, + "Latency": 0, + "Type": 1 + }, + { + "SessionId": 16161, + "Name": "Luke", + "Version": "0.2.3570.17365", + "Address": "75.132.226.39", + "Checksum": "B23CD3ED", + "Port": "27016", + "MapName": "Mars", + "Players": 1, + "MaxPlayers": 10, + "Password": true, + "UpTime": 0, + "Latency": 0, + "Type": 0 + }, + { + "SessionId": 16165, + "Name": "SpectR ServeR", + "Version": "0.2.3570.17365", + "Address": "178.65.157.15", + "Checksum": "1C5A3FC5", + "Port": "27016", + "MapName": "Moon", + "Players": 1, + "MaxPlayers": 10, + "Password": true, + "UpTime": 0, + "Latency": 0, + "Type": 0 + }, + { + "SessionId": 16167, + "Name": "Stationeers F*ckery 1: Dying on Mars", + "Version": "0.2.3588.17444", + "Address": "185.82.239.12", + "Checksum": "353CDF9D", + "Port": "25565", + "MapName": "Mars", + "Players": 1, + "MaxPlayers": 30, + "Password": false, + "UpTime": 0, + "Latency": 0, + "Type": 0 + }, + { + "SessionId": 16170, + "Name": "Artemis: Phase 2", + "Version": "0.2.3570.17365", + "Address": "143.244.166.105", + "Checksum": "898CDD95", + "Port": "27500", + "MapName": "Mars", + "Players": 0, + "MaxPlayers": 10, + "Password": false, + "UpTime": 0, + "Latency": 0, + "Type": 2 + }, + { + "SessionId": 16174, + "Name": "GuitouParty", + "Version": "0.2.3570.17365", + "Address": "90.70.112.42", + "Checksum": "4925FFC5", + "Port": "27016", + "MapName": "Moon", + "Players": 1, + "MaxPlayers": 10, + "Password": true, + "UpTime": 0, + "Latency": 0, + "Type": 0 + }, + { + "SessionId": 16189, + "Name": "Squeak", + "Version": "0.2.3570.17365", + "Address": "70.92.105.8", + "Checksum": "8D80EFED", + "Port": "27016", + "MapName": "", + "Players": 1, + "MaxPlayers": 10, + "Password": true, + "UpTime": 0, + "Latency": 0, + "Type": 0 + }, + { + "SessionId": 16195, + "Name": "stationeers survie", + "Version": "0.2.3570.17365", + "Address": "172.99.189.136", + "Checksum": "2439A95", + "Port": "20400", + "MapName": "Moon", + "Players": 0, + "MaxPlayers": 10, + "Password": true, + "UpTime": 0, + "Latency": 0, + "Type": 1 + }, + { + "SessionId": 16200, + "Name": "Berning Pham", + "Version": "0.2.3570.17365", + "Address": "136.33.249.104", + "Checksum": "7E99E4C5", + "Port": "27016", + "MapName": "", + "Players": 1, + "MaxPlayers": 10, + "Password": true, + "UpTime": 0, + "Latency": 0, + "Type": 0 + }, + { + "SessionId": 16201, + "Name": "Stationeers -Getreidebunker", + "Version": "0.2.3570.17365", + "Address": "45.141.122.194", + "Checksum": "97C754ED", + "Port": "36100", + "MapName": "Moon", + "Players": 0, + "MaxPlayers": 20, + "Password": true, + "UpTime": 0, + "Latency": 0, + "Type": 1 + }, + { + "SessionId": 16202, + "Name": "DonnyBresko", + "Version": "0.2.3570.17365", + "Address": "77.20.142.158", + "Checksum": "2C56E595", + "Port": "27016", + "MapName": "DoRopa", + "Players": 1, + "MaxPlayers": 3, + "Password": true, + "UpTime": 0, + "Latency": 0, + "Type": 0 + }, + { + "SessionId": 16217, + "Name": "bier", + "Version": "0.2.3570.17365", + "Address": "91.35.61.31", + "Checksum": "1EB4395", + "Port": "27016", + "MapName": "test", + "Players": 1, + "MaxPlayers": 10, + "Password": true, + "UpTime": 0, + "Latency": 0, + "Type": 0 + }, + { + "SessionId": 16218, + "Name": "PiNgPonG", + "Version": "0.2.3570.17365", + "Address": "66.211.24.235", + "Checksum": "EF9BBC5", + "Port": "27016", + "MapName": "Vulcan2", + "Players": 1, + "MaxPlayers": 4, + "Password": true, + "UpTime": 0, + "Latency": 0, + "Type": 0 + }, + { + "SessionId": 16219, + "Name": "Samael247", + "Version": "0.2.3570.17365", + "Address": "217.240.163.144", + "Checksum": "7CB6E1C5", + "Port": "27016", + "MapName": "Mars", + "Players": 1, + "MaxPlayers": 10, + "Password": true, + "UpTime": 0, + "Latency": 0, + "Type": 0 + }, + { + "SessionId": 16220, + "Name": "Hobos in Spaaace", + "Version": "0.2.3570.17365", + "Address": "73.86.89.115", + "Checksum": "A475DFBD", + "Port": "27016", + "MapName": "WORLD", + "Players": 0, + "MaxPlayers": 10, + "Password": true, + "UpTime": 0, + "Latency": 0, + "Type": 2 + }, + { + "SessionId": 16221, + "Name": "Stationeers", + "Version": "0.2.3570.17365", + "Address": "91.162.194.51", + "Checksum": "11E7DFC5", + "Port": "27016", + "MapName": "Moon", + "Players": 1, + "MaxPlayers": 4, + "Password": true, + "UpTime": 0, + "Latency": 0, + "Type": 0 + }, + { + "SessionId": 16222, + "Name": "Stationeers Server2022", + "Version": "0.2.3570.17365", + "Address": "54.39.49.50", + "Checksum": "351BDCBD", + "Port": "25444", + "MapName": "Moon", + "Players": 0, + "MaxPlayers": 10, + "Password": true, + "UpTime": 0, + "Latency": 0, + "Type": 1 + }, + { + "SessionId": 16223, + "Name": "Family X gaming", + "Version": "0.2.3570.17365", + "Address": "216.245.216.178 +|| +", + "Checksum": "EDA5C3BD", + "Port": "18015", + "MapName": "Mars", + "Players": 0, + "MaxPlayers": 8, + "Password": true, + "UpTime": 0, + "Latency": 0, + "Type": 1 + }, + { + "SessionId": 16224, + "Name": "Doomz", + "Version": "0.2.3429.16807", + "Address": "147.135.8.48", + "Checksum": "45F8C820", + "Port": "25444", + "MapName": "Moon", + "Players": 0, + "MaxPlayers": 15, + "Password": true, + "UpTime": 0, + "Latency": 0, + "Type": 1 + }, + { + "SessionId": 16225, + "Name": "ZoD World2", + "Version": "0.2.3431.16810", + "Address": "144.217.65.8", + "Checksum": "F1849B14", + "Port": "25448", + "MapName": "Moon", + "Players": 0, + "MaxPlayers": 15, + "Password": true, + "UpTime": 0, + "Latency": 0, + "Type": 1 + } + ] +} \ No newline at end of file diff --git a/tests/Protocols/Providers/Stationeers/1_result.json b/tests/Protocols/Providers/Stationeers/1_result.json new file mode 100644 index 00000000..099ebddf --- /dev/null +++ b/tests/Protocols/Providers/Stationeers/1_result.json @@ -0,0 +1 @@ +{"47.158.161.12:27016":{"dedicated":1,"gq_address":"47.158.161.12","gq_joinlink":"","gq_name":"Stationeers","gq_online":true,"gq_port_client":27016,"gq_port_query":"27016","gq_protocol":"stationeers","gq_transport":"tcp","gq_type":"stationeers","hostname":"Androneers","map":"Proximab","maxplayers":10,"numplayers":1,"password":1,"type":0,"uptime":0,"version":"0.2.3570.17365"}} \ No newline at end of file diff --git a/tests/Protocols/Providers/Stationeers/2_response.txt b/tests/Protocols/Providers/Stationeers/2_response.txt new file mode 100644 index 00000000..64a398d3 --- /dev/null +++ b/tests/Protocols/Providers/Stationeers/2_response.txt @@ -0,0 +1,974 @@ +HTTP/1.1 200 OK +Keep-Alive: true +Content-Length: 22496 +Server: Microsoft-HTTPAPI/2.0 +Date: Tue, 30 Aug 2022 22:30:30 GMT +Connection: close + +{ + "Count": 63, + "TotalPlayers": 22, + "GameSessions": [ + { + "SessionId": 15712, + "Name": "Catch22", + "Version": "0.2.3570.17365", + "Address": "103.114.12.10", + "Checksum": "E4F1D9C5", + "Port": "27016", + "MapName": "Moon", + "Players": 0, + "MaxPlayers": 20, + "Password": true, + "UpTime": 0, + "Latency": 0, + "Type": 2 + }, + { + "SessionId": 15716, + "Name": "Stationeers German/Deutsch BlackLand Hallo Leute leider geht es zu zeit nur in solo spiel :-(", + "Version": "0.2.3570.17365", + "Address": "194.163.170.243", + "Checksum": "B5963DBD", + "Port": "35700", + "MapName": "Mars", + "Players": 0, + "MaxPlayers": 20, + "Password": true, + "UpTime": 0, + "Latency": 0, + "Type": 1 + }, + { + "SessionId": 15721, + "Name": "0GravityBert", + "Version": "0.2.3570.17365", + "Address": "85.215.225.45", + "Checksum": "E916B8BD", + "Port": "27016", + "MapName": "Moon", + "Players": 0, + "MaxPlayers": 5, + "Password": true, + "UpTime": 0, + "Latency": 0, + "Type": 1 + }, + { + "SessionId": 15723, + "Name": "LM - Europa", + "Version": "0.2.3570.17365", +|| + + "Address": "159.69.72.154", + "Checksum": "3AE1D2BD", + "Port": "25456", + "MapName": "Europa2", + "Players": 0, + "MaxPlayers": 15, + "Password": true, + "UpTime": 0, + "Latency": 0, + "Type": 1 + }, + { + "SessionId": 15726, + "Name": "meshbase", + "Version": "0.2.3570.17365", + "Address": "103.62.50.20", + "Checksum": "B201B4BD", + "Port": "26510", + "MapName": "Mars", + "Players": 0, + "MaxPlayers": 16, + "Password": true, + "UpTime": 0, + "Latency": 0, + "Type": 1 + }, + { + "SessionId": 15739, + "Name": "4Netplayers Stationeers Server", + "Version": "0.2.3570.17365", + "Address": "62.104.16.117", + "Checksum": "1DCD0495", + "Port": "23800", + "MapName": "Moon", + "Players": 0, + "MaxPlayers": 10, + "Password": true, + "UpTime": 0, + "Latency": 0, + "Type": 1 + }, + { + "SessionId": 15762, + "Name": "Androneers", + "Version": "0.2.3570.17365", + "Address": "47.158.161.12", + "Checksum": "48EB8995", + "Port": "27016", + "MapName": "Proximab", + "Players": 1, + "MaxPlayers": 10, + "Password": true, + "UpTime": 0, + "Latency": 0, + "Type": 0 + }, + { + "SessionId": 15768, + "Name": "Skyvale Interstellar", + "Version": "0.2.3570.17365", + "Address": "185.125.205.100", + "Checksum": "12FCE3C5", + "Port": "18015", + "MapName": "Mars", + "Players": 0, + "MaxPlayers": 8, + "Password": true, + "UpTime": 0, + "Latency": 0, + "Type": 1 + }, + { + "SessionId": 15783, + "Name": "Apollo 4", + "Version": "0.2.3530.17210", + "Address": "87.97.24.142", + "Checksum": "E6432F93", + "Port": "27017", + "MapName": "Mars", + "Players": 0, + "MaxPlayers": 20, + "Password": true, + "UpTime": 0, + "Latency": 0, + "Type": 1 + }, + { + "SessionId": 15789, + "Name": "Grumpy", + "Version": "0.2.3570.17365", + "Address": "47.49.8.74", + "Checksum": "BE8B5395", + "Port": "27016", + "MapName": "Mars", + "Players": 1, + "MaxPlayers": 10, + "Password": true, + "UpTime": 0, + "Latency": 0, + "Type": 0 + }, + { + "SessionId": 15803, + "Name": "Celestra FR", + "Version": "0.2.3570.17365", + "Address": "82.65.179.165", + "Checksum": "39B0CCBD", + "Port": "23520", + "MapName": "Europa", + "Players": 0, + "MaxPlayers": 4, + "Password": true, + "UpTime": 0, + "Latency": 0, + "Type": 2 + }, + { + "SessionId": 15808, + "Name": "StationeersSamnick", + "Version": "0.2.3587.17443", + "Address": "159.69.72.154", + "Checksum": "8A8DE0B5", + "Port": "25448", + "MapName": "Mimas", + "Players": 0, + "MaxPlayers": 15, + "Password": true, + "UpTime": 0, + "Latency": 0, + "Type": 1 + }, + { + "SessionId": 15810, + "Name": "Celestra Fr Mars", + "Version": "0.2.3570.17365", + "Address": "82.65.179.165", + "Checksum": "1207EAED", + "Port": "23536", + "MapName": "Mars", + "Players": 0, + "MaxPlayers": 4, + "Password": true, + "UpTime": 0, + "Latency": 0, + "Type": 2 + }, + { + "SessionId": 15832, + "Name": "Devilscary", + "Version": "0.2.3570.17365", + "Address": "74.210.225.225", + "Checksum": "7C080395", + "Port": "27516", + "MapName": "Mars", + "Players": 1, + "MaxPlayers": 10, + "Password": true, + "UpTime": 0, + "Latency": 0, + "Type": 0 + }, + { + "SessionId": 15844, + "Name": "4Netplayers Mars 1 geht leider nicht", + "Version": "0.2.3570.17365", + "Address": "62.104.16.117", + "Checksum": "35AC3EBD", + "Port": "34000", + "MapName": "Mars", + "Players": 0, + "MaxPlayers": 8, + "Password": true, + "UpTime": 0, + "Latency": 0, + "Type": 1 + }, + { + "SessionId": 15859, + "Name": "UrMimas", + "Version": "0.2.3570.17365", + "Address": "71.236.26.5", + "Checksum": "9D +|| +C30595", + "Port": "27016", + "MapName": "Mimas", + "Players": 0, + "MaxPlayers": 5, + "Password": true, + "UpTime": 0, + "Latency": 0, + "Type": 2 + }, + { + "SessionId": 15862, + "Name": "Stationeers", + "Version": "0.2.3570.17365", + "Address": "54.36.166.128", + "Checksum": "9CCCCC5", + "Port": "18015", + "MapName": "Mars", + "Players": 0, + "MaxPlayers": 8, + "Password": true, + "UpTime": 0, + "Latency": 0, + "Type": 1 + }, + { + "SessionId": 15899, + "Name": "The D Venus", + "Version": "0.2.3570.17365", + "Address": "192.169.80.42", + "Checksum": "52EF5995", + "Port": "18265", + "MapName": "Venus", + "Players": 0, + "MaxPlayers": 8, + "Password": true, + "UpTime": 0, + "Latency": 0, + "Type": 1 + }, + { + "SessionId": 15914, + "Name": "Executoronline Mars", + "Version": "0.2.3530.17210", + "Address": "95.216.38.190", + "Checksum": "2EB64593", + "Port": "27016", + "MapName": "Mars", + "Players": 0, + "MaxPlayers": 10, + "Password": true, + "UpTime": 0, + "Latency": 0, + "Type": 2 + }, + { + "SessionId": 15921, + "Name": "Sanctuary", + "Version": "0.2.3570.17365", + "Address": "78.157.70.82", + "Checksum": "8ACED595", + "Port": "27016", +|| + + "MapName": "Europa2", + "Players": 0, + "MaxPlayers": 10, + "Password": true, + "UpTime": 0, + "Latency": 0, + "Type": 2 + }, + { + "SessionId": 15931, + "Name": "Muns (NZ)", + "Version": "0.2.3570.17365", + "Address": "101.100.143.138", + "Checksum": "83695095", + "Port": "30000", + "MapName": "Moon", + "Players": 0, + "MaxPlayers": 8, + "Password": false, + "UpTime": 0, + "Latency": 0, + "Type": 1 + }, + { + "SessionId": 15944, + "Name": "devildogs", + "Version": "0.2.3570.17365", + "Address": "74.141.20.22", + "Checksum": "8763F395", + "Port": "27016", + "MapName": "", + "Players": 1, + "MaxPlayers": 10, + "Password": true, + "UpTime": 0, + "Latency": 0, + "Type": 0 + }, + { + "SessionId": 15947, + "Name": "Avalon Reborn", + "Version": "0.2.3570.17365", + "Address": "51.89.173.203", + "Checksum": "CFF75995", + "Port": "18025", + "MapName": "Venus", + "Players": 0, + "MaxPlayers": 8, + "Password": true, + "UpTime": 0, + "Latency": 0, + "Type": 1 + }, + { + "SessionId": 15961, + "Name": "VULCAN FR", + "Version": "0.2.3570.17365", + "Address": "82.66.177.148", + "Checksum": "7AAB2BBD", + "Port": "27016", + "MapName": "Vulcan2", + "Pla +|| +yers": 1, + "MaxPlayers": 10, + "Password": true, + "UpTime": 0, + "Latency": 0, + "Type": 0 + }, + { + "SessionId": 15974, + "Name": "Kevineers", + "Version": "0.2.3570.17365", + "Address": "73.42.182.16", + "Checksum": "EE214C95", + "Port": "27016", + "MapName": "Vulcan2", + "Players": 0, + "MaxPlayers": 10, + "Password": true, + "UpTime": 0, + "Latency": 0, + "Type": 1 + }, + { + "SessionId": 16003, + "Name": "PTA Stationeers Mars", + "Version": "0.2.3570.17365", + "Address": "23.120.182.72", + "Checksum": "C5B3F8ED", + "Port": "27569", + "MapName": "MarsPTA", + "Players": 0, + "MaxPlayers": 10, + "Password": true, + "UpTime": 0, + "Latency": 0, + "Type": 1 + }, + { + "SessionId": 16012, + "Name": "Devyns Play Thing", + "Version": "0.2.3588.17444", + "Address": "66.94.126.83", + "Checksum": "1076A8B5", + "Port": "27501", + "MapName": "Vulcan", + "Players": 0, + "MaxPlayers": 10, + "Password": false, + "UpTime": 0, + "Latency": 0, + "Type": 2 + }, + { + "SessionId": 16031, + "Name": "FeenixDedi", + "Version": "0.2.3570.17365", + "Address": "68.3.236.182", + "Checksum": "F3448495", + "Port": "27016", + "MapName": "Mars", + "Players": 0, + "MaxPlayers": 3, + "Password": true, + "UpTime": 0, + "Latency": 0, + "Type": 1 + }, + { + "SessionId": 16051, + "Name": "Bard Moon Adventure", + "Version": "0.2.3570.17365", + "Address": "5.95.156.237", + "Checksum": "FDFB58C5", + "Port": "27016", + "MapName": "Mars", + "Players": 0, + "MaxPlayers": 10, + "Password": true, + "UpTime": 0, + "Latency": 0, + "Type": 1 + }, + { + "SessionId": 16054, + "Name": "Gamers Hub Official", + "Version": "0.2.3570.17365", + "Address": "104.238.220.19", + "Checksum": "743818C5", + "Port": "25444", + "MapName": "Moon", + "Players": 0, + "MaxPlayers": 10, + "Password": true, + "UpTime": 0, + "Latency": 0, + "Type": 1 + }, + { + "SessionId": 16059, + "Name": "STONER PLANET", + "Version": "0.2.3588.17444", + "Address": "145.239.130.135", + "Checksum": "2C527C9D", + "Port": "18015", + "MapName": "Mars", + "Players": 0, + "MaxPlayers": 8, + "Password": true, + "UpTime": 0, + "Latency": 0, + "Type": 1 + }, + { + "SessionId": 16061, + "Name": "allinone", + "Version": "0.2.3570.17365", + "Address": "84.131.212.232", + "Checksum": "517229ED", + "Port": "27016", + "MapName": "Mars", + "Players": 1, + "MaxPlayers": 10, + +|| + "Password": true, + "UpTime": 0, + "Latency": 0, + "Type": 0 + }, + { + "SessionId": 16064, + "Name": "Peekas", + "Version": "0.2.3588.17444", + "Address": "173.212.250.184", + "Checksum": "88B006B5", + "Port": "27016", + "MapName": "Mars", + "Players": 0, + "MaxPlayers": 10, + "Password": true, + "UpTime": 0, + "Latency": 0, + "Type": 2 + }, + { + "SessionId": 16065, + "Name": "Kepler452B", + "Version": "0.2.3570.17365", + "Address": "73.158.104.124", + "Checksum": "8610CC5", + "Port": "27500", + "MapName": "Kepler452B", + "Players": 0, + "MaxPlayers": 30, + "Password": true, + "UpTime": 0, + "Latency": 0, + "Type": 2 + }, + { + "SessionId": 16070, + "Name": "Goatstation5", + "Version": "0.2.3570.17365", + "Address": "192.169.86.146", + "Checksum": "91967EED", + "Port": "18015", + "MapName": "Moon", + "Players": 0, + "MaxPlayers": 8, + "Password": true, + "UpTime": 0, + "Latency": 0, + "Type": 1 + }, + { + "SessionId": 16095, + "Name": "Amogus", + "Version": "0.2.3570.17365", + "Address": "185.60.46.74", + "Checksum": "C52E6DC5", + "Port": "27016", + "MapName": "Mars", + "Players": 1, + "MaxPlayers": 10, + "Password": true, + "UpTime": 0, + "Latency": 0, + "Type": 0 + }, + { + "SessionId": 16098, + "Name": "Dholio", + "Version": "0.2.3530.17210", + "Address": "154.127.54.201", + "Checksum": "7B290DEB", + "Port": "18015", + "MapName": "beachmars", + "Players": 0, + "MaxPlayers": 8, + "Password": true, + "UpTime": 0, + "Latency": 0, + "Type": 1 + }, + { + "SessionId": 16108, + "Name": "DSR", + "Version": "0.2.3570.17365", + "Address": "71.127.216.19", + "Checksum": "8F599DC5", + "Port": "27016", + "MapName": "", + "Players": 1, + "MaxPlayers": 30, + "Password": true, + "UpTime": 0, + "Latency": 0, + "Type": 0 + }, + { + "SessionId": 16123, + "Name": "Hyden", + "Version": "0.2.3570.17365", + "Address": "81.43.208.3", + "Checksum": "7E571595", + "Port": "27016", + "MapName": "Mars", + "Players": 1, + "MaxPlayers": 10, + "Password": true, + "UpTime": 0, + "Latency": 0, + "Type": 0 + }, + { + "SessionId": 16125, + "Name": "M2M", + "Version": "0.2.3570.17365", + "Address": "178.167.195.138", + "Checksum": "8FB6E2C5", + "Port": "27016", + "MapName": "Mars", + "Players": 0, + "MaxPlayers": 11, + "Password": true, + "UpTime": 0, + "Latency": 0, + "Type": 1 + }, + { + +|| + "SessionId": 16136, + "Name": "Oymyakon", + "Version": "0.2.3570.17365", + "Address": "151.224.246.46", + "Checksum": "2C31F7C5", + "Port": "27016", + "MapName": "Syberia", + "Players": 1, + "MaxPlayers": 10, + "Password": true, + "UpTime": 0, + "Latency": 0, + "Type": 0 + }, + { + "SessionId": 16138, + "Name": "BlueHell", + "Version": "0.2.3570.17365", + "Address": "178.27.166.108", + "Checksum": "D834E195", + "Port": "27016", + "MapName": "Mars", + "Players": 1, + "MaxPlayers": 10, + "Password": true, + "UpTime": 0, + "Latency": 0, + "Type": 0 + }, + { + "SessionId": 16145, + "Name": "Tehscott's Stationeers", + "Version": "0.2.3588.17444", + "Address": "71.237.87.148", + "Checksum": "90B5B6CD", + "Port": "27016", + "MapName": "Europa2", + "Players": 0, + "MaxPlayers": 10, + "Password": true, + "UpTime": 0, + "Latency": 0, + "Type": 1 + }, + { + "SessionId": 16149, + "Name": "Bastards Inc", + "Version": "0.2.3570.17365", + "Address": "75.174.200.93", + "Checksum": "8BA4B495", + "Port": "27016", + "MapName": "Mars", + "Players": 0, + "MaxPlayers": 30, + "Password": true, + "UpTime": 0, + "Latency": 0, + "Type": 1 + }, + { + "SessionId": 16161, + "Name": "Luke", + "Version": "0.2.3570.17365", + "Address": "75.132.226.39", + "Checksum": "B23CD3ED", + "Port": "27016", + "MapName": "Mars", + "Players": 1, + "MaxPlayers": 10, + "Password": true, + "UpTime": 0, + "Latency": 0, + "Type": 0 + }, + { + "SessionId": 16165, + "Name": "SpectR ServeR", + "Version": "0.2.3570.17365", + "Address": "178.65.157.15", + "Checksum": "1C5A3FC5", + "Port": "27016", + "MapName": "Moon", + "Players": 1, + "MaxPlayers": 10, + "Password": true, + "UpTime": 0, + "Latency": 0, + "Type": 0 + }, + { + "SessionId": 16167, + "Name": "Stationeers F*ckery 1: Dying on Mars", + "Version": "0.2.3588.17444", + "Address": "185.82.239.12", + "Checksum": "353CDF9D", + "Port": "25565", + "MapName": "Mars", + "Players": 1, + "MaxPlayers": 30, + "Password": false, + "UpTime": 0, + "Latency": 0, + "Type": 0 + }, + { + "SessionId": 16170, + "Name": "Artemis: Phase 2", + "Version": "0.2.3570.17365", + "Address": "143.244.166.105", + "Checksum": "898CDD95", + "Port": "27500", + "MapName": "Mars", + "Players": 0, + "MaxPlayers": 10, + "Password": false, + "UpTime": 0, + "Latency": 0, + "Type": 2 + }, + { + "SessionId": 16174, + "Name": "GuitouParty", + "Version": "0.2.3570.17365", + "Address": "90.70.112.42", + "Checksum": "4925FFC5", + "Port": "27016", + "MapName": "Moon", + "Players": 1, + "MaxPlayers": 10, + "Password": true, + "UpTime": 0, + "Latency": 0, + "Type": 0 + }, + { + "SessionId": 16189, + "Name": "Squeak", + "Version": "0.2.3570.17365", + "Address": "70.92.105.8", + "Checksum": "8D80EFED", + "Port": "27016", + "MapName": "", + "Players": 1, + "MaxPlayers": 10, + "Password": true, + "UpTime": 0, + "Latency": 0, + "Type": 0 + }, + { + "SessionId": 16195, + "Name": "stationeers survie", + "Version": "0.2.3570.17365", + "Address": "172.99.189.136", + "Checksum": "2439A95", + "Port": "20400", + "MapName": "Moon", + "Players": 0, + "MaxPlayers": 10, + "Password": true, + "UpTime": 0, + "Latency": 0, + "Type": 1 + }, + { + "SessionId": 16200, + "Name": "Berning Pham", + "Version": "0.2.3570.17365", + "Address": "136.33.249.104", + "Checksum": "7E99E4C5", + "Port": "27016", + "MapName": "", + "Players": 1, + "MaxPlayers": 10, + "Password": true, + "UpTime": 0, + "Latency": 0, + "Type": 0 + }, + { + "SessionId": 16201, + "Name": "Stationeers -Getreidebunker", + +|| + "Version": "0.2.3570.17365", + "Address": "45.141.122.194", + "Checksum": "97C754ED", + "Port": "36100", + "MapName": "Moon", + "Players": 0, + "MaxPlayers": 20, + "Password": true, + "UpTime": 0, + "Latency": 0, + "Type": 1 + }, + { + "SessionId": 16202, + "Name": "DonnyBresko", + "Version": "0.2.3570.17365", + "Address": "77.20.142.158", + "Checksum": "2C56E595", + "Port": "27016", + "MapName": "DoRopa", + "Players": 1, + "MaxPlayers": 3, + "Password": true, + "UpTime": 0, + "Latency": 0, + "Type": 0 + }, + { + "SessionId": 16217, + "Name": "bier", + "Version": "0.2.3570.17365", + "Address": "91.35.61.31", + "Checksum": "1EB4395", + "Port": "27016", + "MapName": "test", + "Players": 1, + "MaxPlayers": 10, + "Password": true, + "UpTime": 0, + "Latency": 0, + "Type": 0 + }, + { + "SessionId": 16218, + "Name": "PiNgPonG", + "Version": "0.2.3570.17365", + "Address": "66.211.24.235", + "Checksum": "EF9BBC5", + "Port": "27016", + "MapName": "Vulcan2", + "Players": 1, + "MaxPlayers": 4, + "Password": true, + "UpTime": 0, + "Latency": 0, + "Type": 0 + }, + { + "SessionId": 16219, + "Name": "Samael247", + "Version": "0.2.3570.17365", + "Address": "217.240.163.144", + "Checksum": "7CB6E1C5", + "Port": "27016", + "MapName": "Mars", + "Players": 1, + "MaxPlayers": 10, + "Password": true, + "UpTime": 0, + "Latency": 0, + "Type": 0 + }, + { + "SessionId": 16220, + "Name": "Hobos in Spaaace", + "Version": "0.2.3570.17365", + "Address": "73.86.89.115", + "Checksum": "A475DFBD", + "Port": "27016", + "MapName": "WORLD", + "Players": 0, + "MaxPlayers": 10, + "Password": true, + "UpTime": 0, + "Latency": 0, + "Type": 2 + }, + { + "SessionId": 16221, + "Name": "Stationeers", + "Version": "0.2.3570.17365", + "Address": "91.162.194.51", + "Checksum": "11E7DFC5", + "Port": "27016", + "MapName": "Moon", + "Players": 1, + "MaxPlayers": 4, + "Password": true, + "UpTime": 0, + "Latency": 0, + "Type": 0 + }, + { + "SessionId": 16222, + "Name": "Stationeers Server2022", + "Version": "0.2.3570.17365", + "Address": "54.39.49.50", + "Checksum": "351BDCBD", + "Port": "25444", + "MapName": "Moon", + "Players": 0, + "MaxPlayers": 10, + "Password": true, + "UpTime": 0, + "Latency": 0, + "Type": 1 + }, + { + "SessionId": 16223, + "Name": "Family X gaming", + "Version": "0.2.3570.17365", + "Address": "216.245.216.178 +|| +", + "Checksum": "EDA5C3BD", + "Port": "18015", + "MapName": "Mars", + "Players": 0, + "MaxPlayers": 8, + "Password": true, + "UpTime": 0, + "Latency": 0, + "Type": 1 + }, + { + "SessionId": 16224, + "Name": "Doomz", + "Version": "0.2.3429.16807", + "Address": "147.135.8.48", + "Checksum": "45F8C820", + "Port": "25444", + "MapName": "Moon", + "Players": 0, + "MaxPlayers": 15, + "Password": true, + "UpTime": 0, + "Latency": 0, + "Type": 1 + }, + { + "SessionId": 16225, + "Name": "ZoD World2", + "Version": "0.2.3431.16810", + "Address": "144.217.65.8", + "Checksum": "F1849B14", + "Port": "25448", + "MapName": "Moon", + "Players": 0, + "MaxPlayers": 15, + "Password": true, + "UpTime": 0, + "Latency": 0, + "Type": 1 + } + ] +} \ No newline at end of file diff --git a/tests/Protocols/Providers/Stationeers/2_result.json b/tests/Protocols/Providers/Stationeers/2_result.json new file mode 100644 index 00000000..843bed95 --- /dev/null +++ b/tests/Protocols/Providers/Stationeers/2_result.json @@ -0,0 +1 @@ +{"194.163.170.243:35700":{"dedicated":1,"gq_address":"194.163.170.243","gq_joinlink":"","gq_name":"Stationeers","gq_online":true,"gq_port_client":35700,"gq_port_query":"35700","gq_protocol":"stationeers","gq_transport":"tcp","gq_type":"stationeers","hostname":"Stationeers German\/Deutsch BlackLand Hallo Leute leider geht es zu zeit nur in solo spiel :-(","map":"Mars","maxplayers":20,"numplayers":0,"password":1,"type":1,"uptime":0,"version":"0.2.3570.17365"}} \ No newline at end of file diff --git a/tests/Protocols/Quake2.php b/tests/Protocols/Quake2.php index c8847c34..f58c9f82 100644 --- a/tests/Protocols/Quake2.php +++ b/tests/Protocols/Quake2.php @@ -22,18 +22,17 @@ class Quake2 extends Base { - /** * Holds stub on setup * - * @type \GameQ\Protocols\Quake2 + * @var \GameQ\Protocols\Quake2 */ protected $stub; /** * Holds the expected packets for this protocol class * - * @type array + * @var array */ protected $packets = [ \GameQ\Protocol::PACKET_STATUS => "\xFF\xFF\xFF\xFFstatus\x00", @@ -46,7 +45,6 @@ class Quake2 extends Base */ public function customSetUp() { - // Create the stub class $this->stub = new \GameQ\Protocols\Quake2(); } @@ -56,7 +54,6 @@ public function customSetUp() */ public function testPackets() { - // Test to make sure packets are defined properly $this->assertEquals($this->packets, $this->stub->getPacket()); } @@ -66,7 +63,6 @@ public function testPackets() */ public function testInvalidPacketType() { - // Read in a quake 2 source file $source = file_get_contents(sprintf('%s/Providers/Quake2/1_response.txt', __DIR__)); diff --git a/tests/Protocols/Quake3.php b/tests/Protocols/Quake3.php index c74ff82b..28e36148 100644 --- a/tests/Protocols/Quake3.php +++ b/tests/Protocols/Quake3.php @@ -22,18 +22,17 @@ class Quake3 extends Base { - /** * Holds stub on setup * - * @type \GameQ\Protocols\Quake3 + * @var \GameQ\Protocols\Quake3 */ protected $stub; /** * Holds the expected packets for this protocol class * - * @type array + * @var array */ protected $packets = [ \GameQ\Protocol::PACKET_STATUS => "\xFF\xFF\xFF\xFF\x67\x65\x74\x73\x74\x61\x74\x75\x73\x0A", diff --git a/tests/Protocols/Quake4.php b/tests/Protocols/Quake4.php index 60999cd0..4a2e681e 100644 --- a/tests/Protocols/Quake4.php +++ b/tests/Protocols/Quake4.php @@ -35,7 +35,6 @@ class Quake4 extends Base */ public function testResponses($responses, $result) { - // Pull the first key off the array this is the server ip:port $server = key($result); diff --git a/tests/Protocols/Raknet.php b/tests/Protocols/Raknet.php index cfd23114..13dc02de 100644 --- a/tests/Protocols/Raknet.php +++ b/tests/Protocols/Raknet.php @@ -25,14 +25,14 @@ class Raknet extends Base /** * Holds stub on setup * - * @type \GameQ\Protocols\Raknet + * @var \GameQ\Protocols\Raknet */ protected $stub; /** * Holds the expected packets for this protocol class * - * @type array + * @var array */ protected $packets = [ \GameQ\Protocol::PACKET_STATUS => "\x01%s%s\x02\x00\x00\x00\x00\x00\x00\x00", diff --git a/tests/Protocols/Rfactor.php b/tests/Protocols/Rfactor.php index ddf7ade6..fc44c279 100644 --- a/tests/Protocols/Rfactor.php +++ b/tests/Protocols/Rfactor.php @@ -35,7 +35,6 @@ class Rfactor extends Base */ public function testResponses($responses, $result) { - // Pull the first key off the array this is the server ip:port $server = key($result); diff --git a/tests/Protocols/Rfactor2.php b/tests/Protocols/Rfactor2.php index f43db283..49d1305d 100644 --- a/tests/Protocols/Rfactor2.php +++ b/tests/Protocols/Rfactor2.php @@ -35,7 +35,6 @@ class Rfactor2 extends Base */ public function testResponses($responses, $result) { - // Pull the first key off the array this is the server ip:port $server = key($result); diff --git a/tests/Protocols/Risingstorm2.php b/tests/Protocols/Risingstorm2.php index 7ba62209..e33ca0d7 100644 --- a/tests/Protocols/Risingstorm2.php +++ b/tests/Protocols/Risingstorm2.php @@ -28,7 +28,7 @@ class Risingstorm2 extends Base /** * Holds stub on setup * - * @type \GameQ\Protocols\Risingstorm2 + * @var \GameQ\Protocols\Risingstorm2 */ protected $stub; diff --git a/tests/Protocols/Samp.php b/tests/Protocols/Samp.php index 01e932ea..cc1653db 100644 --- a/tests/Protocols/Samp.php +++ b/tests/Protocols/Samp.php @@ -25,14 +25,14 @@ class Samp extends Base /** * Holds stub on setup * - * @type \GameQ\Protocols\Samp + * @var \GameQ\Protocols\Samp */ protected $stub; /** * Holds the expected packets for this protocol class * - * @type array + * @var array */ protected $packets = [ \GameQ\Protocol::PACKET_STATUS => "SAMP%si", diff --git a/tests/Protocols/Source.php b/tests/Protocols/Source.php index 27c67a06..4b299a7f 100644 --- a/tests/Protocols/Source.php +++ b/tests/Protocols/Source.php @@ -25,14 +25,14 @@ class Source extends Base /** * Holds stub on setup * - * @type \GameQ\Protocols\Source + * @var \GameQ\Protocols\Source */ protected $stub; /** * Holds the expected packets for this protocol class * - * @type array + * @var array */ protected $packets = [ \GameQ\Protocol::PACKET_CHALLENGE => "\xFF\xFF\xFF\xFF\x56\x00\x00\x00\x00", @@ -103,6 +103,25 @@ public function testSkipChallengeApply() $this->assertEquals($packets, $this->stub->getPacket()); } + /** + * Test that the challenge application is skipped if packet is not a challenge + */ + public function testSkipChallengeApply() + { + $packets = $this->packets; + + // Set what the packets should look like + $packets[\GameQ\Protocol::PACKET_DETAILS] = "\xFF\xFF\xFF\xFFTSource Engine Query\x00%s"; + $packets[\GameQ\Protocol::PACKET_PLAYERS] = "\xFF\xFF\xFF\xFF\x55%s"; + $packets[\GameQ\Protocol::PACKET_RULES] = "\xFF\xFF\xFF\xFF\x56%s"; + + // Create a fake buffer + $challenge_buffer = new \GameQ\Buffer("\xFF\xFF\xFF\xFF\xFFtest"); + + $this->stub->challengeParseAndApply($challenge_buffer); + $this->assertEquals($packets, $this->stub->getPacket()); + } + /** * Test invalid packet type without debug */ diff --git a/tests/Protocols/Starmade.php b/tests/Protocols/Starmade.php index fc42417b..d1a493b8 100644 --- a/tests/Protocols/Starmade.php +++ b/tests/Protocols/Starmade.php @@ -28,14 +28,14 @@ class Starmade extends Base /** * Holds stub on setup * - * @type \GameQ\Protocols\Starmade + * @var \GameQ\Protocols\Starmade */ protected $stub; /** * Holds the expected packets for this protocol class * - * @type array + * @var array */ protected $packets = [ \GameQ\Protocol::PACKET_STATUS => "\x00\x00\x00\x09\x2a\xff\xff\x01\x6f\x00\x00\x00\x00", diff --git a/tests/Protocols/Stationeers.php b/tests/Protocols/Stationeers.php new file mode 100644 index 00000000..cfd3cd8c --- /dev/null +++ b/tests/Protocols/Stationeers.php @@ -0,0 +1,49 @@ +. + */ + +namespace GameQ\Tests\Protocols; + +/** + * Test Class for Stationeers + * + * @package GameQ\Tests\Protocols + */ +class Stationeers extends Base +{ + /** + * Test responses for Stationeers + * + * @dataProvider loadData + * + * @param $responses + * @param $result + */ + public function testResponses($responses, $result) + { + // Pull the first key off the array this is the server ip:port + $server = key($result); + + $testResult = $this->queryTest( + $server, + 'stationeers', + $responses + ); + + $this->assertEquals($result[$server], $testResult); + } +} diff --git a/tests/Protocols/Teamspeak2.php b/tests/Protocols/Teamspeak2.php index be81df99..ddfb7620 100644 --- a/tests/Protocols/Teamspeak2.php +++ b/tests/Protocols/Teamspeak2.php @@ -30,14 +30,14 @@ class Teamspeak2 extends Base /** * Holds stub on setup * - * @type \GameQ\Protocols\Teamspeak2 + * @var \GameQ\Protocols\Teamspeak2 */ protected $stub; /** * Holds the expected packets for this protocol class * - * @type array + * @var array */ protected $packets = [ \GameQ\Protocol::PACKET_DETAILS => "sel %d\x0asi\x0a", diff --git a/tests/Protocols/Teamspeak3.php b/tests/Protocols/Teamspeak3.php index 5c81ee15..780b5f2f 100644 --- a/tests/Protocols/Teamspeak3.php +++ b/tests/Protocols/Teamspeak3.php @@ -30,14 +30,14 @@ class Teamspeak3 extends Base /** * Holds stub on setup * - * @type \GameQ\Protocols\Teamspeak3 + * @var \GameQ\Protocols\Teamspeak3 */ protected $stub; /** * Holds the expected packets for this protocol class * - * @type array + * @var array */ protected $packets = [ \GameQ\Protocol::PACKET_DETAILS => "use port=%d\x0Aserverinfo\x0A", diff --git a/tests/Protocols/Teeworlds.php b/tests/Protocols/Teeworlds.php index cfacf0ff..8fbc4fe5 100644 --- a/tests/Protocols/Teeworlds.php +++ b/tests/Protocols/Teeworlds.php @@ -30,14 +30,14 @@ class Teeworlds extends Base /** * Holds stub on setup * - * @type \GameQ\Protocols\Teeworlds + * @var \GameQ\Protocols\Teeworlds */ protected $stub; /** * Holds the expected packets for this protocol class * - * @type array + * @var array */ protected $packets = [ \GameQ\Protocol::PACKET_ALL => "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x67\x69\x65\x33\x05", diff --git a/tests/Protocols/Tibia.php b/tests/Protocols/Tibia.php index 59ce3177..1e4f1918 100644 --- a/tests/Protocols/Tibia.php +++ b/tests/Protocols/Tibia.php @@ -25,14 +25,14 @@ class Tibia extends Base /** * Holds stub on setup * - * @type \GameQ\Protocols\Tibia + * @var \GameQ\Protocols\Tibia */ protected $stub; /** * Holds the expected packets for this protocol class * - * @type array + * @var array */ protected $packets = [ \GameQ\Protocol::PACKET_STATUS => "\x06\x00\xFF\xFF\x69\x6E\x66\x6F", diff --git a/tests/Protocols/Unreal2.php b/tests/Protocols/Unreal2.php index 057c62a4..c7b0efd2 100644 --- a/tests/Protocols/Unreal2.php +++ b/tests/Protocols/Unreal2.php @@ -25,14 +25,14 @@ class Unreal2 extends Base /** * Holds stub on setup * - * @type \GameQ\Protocols\Unreal2 + * @var \GameQ\Protocols\Unreal2 */ protected $stub; /** * Holds the expected packets for this protocol class * - * @type array + * @var array */ protected $packets = [ \GameQ\Protocol::PACKET_DETAILS => "\x79\x00\x00\x00\x00", diff --git a/tests/Protocols/Ventrilo.php b/tests/Protocols/Ventrilo.php index 52e1048c..4f6d9ca3 100644 --- a/tests/Protocols/Ventrilo.php +++ b/tests/Protocols/Ventrilo.php @@ -28,14 +28,14 @@ class Ventrilo extends Base /** * Holds stub on setup * - * @type \GameQ\Protocols\Ventrilo + * @var \GameQ\Protocols\Ventrilo */ protected $stub; /** * Holds the expected packets for this protocol class * - * @type array + * @var array */ protected $packets = [ \GameQ\Protocol::PACKET_ALL => diff --git a/tests/Protocols/generate_provider b/tests/Protocols/generate_provider index 23ef2d55..a8bf7171 100644 --- a/tests/Protocols/generate_provider +++ b/tests/Protocols/generate_provider @@ -72,7 +72,7 @@ try { // Make the directory if it does not already exist if (!is_dir($provider_dir)) { - mkdir($provider_dir, null, true); + mkdir($provider_dir, 0751, true); } // Figure out the number of files in the provider directory @@ -102,12 +102,18 @@ try { // Process $results = $gq->process(); + // Build the path where we want to store the result file + $result_file = sprintf('%s/%d_result.json', $provider_dir, $index); + // Save the result into a file - $result = file_put_contents(sprintf('%s/%d_result.json', $provider_dir, $index), json_encode( + $result = file_put_contents($result_file, json_encode( $results, JSON_UNESCAPED_UNICODE | JSON_PARTIAL_OUTPUT_ON_ERROR )); + // Ensure the result file has proper permissions + chmod($result_file, 0640); + exit(0); } catch (Exception $e) { echo $e->getMessage() . PHP_EOL; diff --git a/tests/Query/Core.php b/tests/Query/Core.php index 079b1296..e89b42bc 100644 --- a/tests/Query/Core.php +++ b/tests/Query/Core.php @@ -32,7 +32,6 @@ class Core extends TestBase */ public function testSet() { - $stub = $this->getMockForAbstractClass('\GameQ\Query\Core', [ ]); // Set the properties diff --git a/tests/Server.php b/tests/Server.php index 6be6e03d..0e0b1f4d 100644 --- a/tests/Server.php +++ b/tests/Server.php @@ -89,7 +89,6 @@ public function testSetServerOptions() */ public function testServerId() { - $id = '127.0.0.1:27015'; // Create a server with id diff --git a/tests/TestBase.php b/tests/TestBase.php index 9b22b76c..419b29f3 100644 --- a/tests/TestBase.php +++ b/tests/TestBase.php @@ -20,7 +20,6 @@ class TestBase extends \PHPUnit\Framework\TestCase { - /** * TestBase constructor overload. *