first commit
This commit is contained in:
parent
b2f89bdb73
commit
47fd3bab62
276 changed files with 31622 additions and 2 deletions
12
GameQ/.github/FUNDING.yml
vendored
Normal file
12
GameQ/.github/FUNDING.yml
vendored
Normal file
|
@ -0,0 +1,12 @@
|
|||
# These are supported funding model platforms
|
||||
|
||||
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
|
||||
patreon: # Replace with a single Patreon username
|
||||
open_collective: # Replace with a single Open Collective username
|
||||
ko_fi: # Replace with a single Ko-fi username
|
||||
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
|
||||
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
|
||||
liberapay: # Replace with a single Liberapay username
|
||||
issuehunt: # Replace with a single IssueHunt username
|
||||
otechie: # Replace with a single Otechie username
|
||||
custom: ["https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=VAU2KADATP5PU"]
|
4
GameQ/.github/issue_label_bot.yaml
vendored
Normal file
4
GameQ/.github/issue_label_bot.yaml
vendored
Normal file
|
@ -0,0 +1,4 @@
|
|||
label-alias:
|
||||
bug: 'Bug'
|
||||
feature_request: 'Feature Request'
|
||||
question: 'Support'
|
19
GameQ/.github/stale.yml
vendored
Normal file
19
GameQ/.github/stale.yml
vendored
Normal file
|
@ -0,0 +1,19 @@
|
|||
# Number of days of inactivity before an issue becomes stale
|
||||
daysUntilStale: 28
|
||||
# Number of days of inactivity before a stale issue is closed
|
||||
daysUntilClose: 14
|
||||
# Issues with these labels will never be considered stale
|
||||
exemptLabels:
|
||||
- Bug
|
||||
- Feature Request
|
||||
- Support
|
||||
# Label to use when marking an issue as stale
|
||||
staleLabel: Stale
|
||||
# Comment to post when marking an issue as stale. Set to `false` to disable
|
||||
markComment: >
|
||||
This issue has been automatically marked as stale because it has not had
|
||||
recent activity. It will be closed if no further activity occurs. Thank you
|
||||
for your contributions.
|
||||
# Comment to post when closing a stale issue. Set to `false` to disable
|
||||
closeComment: false
|
||||
|
60
GameQ/Autoloader.php
Normal file
60
GameQ/Autoloader.php
Normal file
|
@ -0,0 +1,60 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is part of GameQ.
|
||||
*
|
||||
* GameQ is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GameQ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* A simple PSR-4 spec auto loader to allow GameQ to function the same as if it were loaded via Composer
|
||||
*
|
||||
* To use this just include this file in your script and the GameQ namespace will be made available
|
||||
*
|
||||
* i.e. require_once('/path/to/src/GameQ/Autoloader.php');
|
||||
*
|
||||
* See: https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-4-autoloader-examples.md
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
spl_autoload_register(function ($class) {
|
||||
|
||||
// project-specific namespace prefix
|
||||
$prefix = 'GameQ\\';
|
||||
|
||||
// base directory for the namespace prefix
|
||||
$base_dir = __DIR__ . DIRECTORY_SEPARATOR;
|
||||
|
||||
// does the class use the namespace prefix?
|
||||
$len = strlen($prefix);
|
||||
|
||||
if (strncmp($prefix, $class, $len) !== 0) {
|
||||
// no, move to the next registered autoloader
|
||||
return;
|
||||
}
|
||||
|
||||
// get the relative class name
|
||||
$relative_class = substr($class, $len);
|
||||
|
||||
// replace the namespace prefix with the base directory, replace namespace
|
||||
// separators with directory separators in the relative class name, append
|
||||
// with .php
|
||||
$file = $base_dir . str_replace('\\', '/', $relative_class) . '.php';
|
||||
|
||||
// if the file exists, require it
|
||||
if (file_exists($file)) {
|
||||
require $file;
|
||||
}
|
||||
});
|
501
GameQ/Buffer.php
Normal file
501
GameQ/Buffer.php
Normal file
|
@ -0,0 +1,501 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is part of GameQ.
|
||||
*
|
||||
* GameQ is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GameQ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
namespace GameQ;
|
||||
|
||||
use GameQ\Exception\Protocol as Exception;
|
||||
|
||||
/**
|
||||
* Class Buffer
|
||||
*
|
||||
* Read specific byte sequences from a provided string or Buffer
|
||||
*
|
||||
* @package GameQ
|
||||
*
|
||||
* @author Austin Bischoff <austin@codebeard.com>
|
||||
* @author Aidan Lister <aidan@php.net>
|
||||
* @author Tom Buskens <t.buskens@deviation.nl>
|
||||
*/
|
||||
class Buffer
|
||||
{
|
||||
|
||||
/**
|
||||
* Constants for the byte code types we need to read as
|
||||
*/
|
||||
const NUMBER_TYPE_BIGENDIAN = 'be',
|
||||
NUMBER_TYPE_LITTLEENDIAN = 'le',
|
||||
NUMBER_TYPE_MACHINE = 'm';
|
||||
|
||||
/**
|
||||
* The number type we use for reading integers. Defaults to little endian
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
private $number_type = self::NUMBER_TYPE_LITTLEENDIAN;
|
||||
|
||||
/**
|
||||
* The original data
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
private $data;
|
||||
|
||||
/**
|
||||
* The original data
|
||||
*
|
||||
* @type int
|
||||
*/
|
||||
private $length;
|
||||
|
||||
/**
|
||||
* Position of pointer
|
||||
*
|
||||
* @type int
|
||||
*/
|
||||
private $index = 0;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param string $data
|
||||
* @param string $number_type
|
||||
*/
|
||||
public function __construct($data, $number_type = self::NUMBER_TYPE_LITTLEENDIAN)
|
||||
{
|
||||
|
||||
$this->number_type = $number_type;
|
||||
$this->data = $data;
|
||||
$this->length = strlen($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all the data
|
||||
*
|
||||
* @return string The data
|
||||
*/
|
||||
public function getData()
|
||||
{
|
||||
|
||||
return $this->data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return data currently in the buffer
|
||||
*
|
||||
* @return string The data currently in the buffer
|
||||
*/
|
||||
public function getBuffer()
|
||||
{
|
||||
|
||||
return substr($this->data, $this->index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of bytes in the buffer
|
||||
*
|
||||
* @return int Length of the buffer
|
||||
*/
|
||||
public function getLength()
|
||||
{
|
||||
|
||||
return max($this->length - $this->index, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read from the buffer
|
||||
*
|
||||
* @param int $length
|
||||
*
|
||||
* @return string
|
||||
* @throws \GameQ\Exception\Protocol
|
||||
*/
|
||||
public function read($length = 1)
|
||||
{
|
||||
|
||||
if (($length + $this->index) > $this->length) {
|
||||
throw new Exception("Unable to read length={$length} from buffer. Bad protocol format or return?");
|
||||
}
|
||||
|
||||
$string = substr($this->data, $this->index, $length);
|
||||
$this->index += $length;
|
||||
|
||||
return $string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the last character from the buffer
|
||||
*
|
||||
* Unlike the other read functions, this function actually removes
|
||||
* the character from the buffer.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function readLast()
|
||||
{
|
||||
|
||||
$len = strlen($this->data);
|
||||
$string = $this->data[strlen($this->data) - 1];
|
||||
$this->data = substr($this->data, 0, $len - 1);
|
||||
$this->length -= 1;
|
||||
|
||||
return $string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Look at the buffer, but don't remove
|
||||
*
|
||||
* @param int $length
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function lookAhead($length = 1)
|
||||
{
|
||||
|
||||
return substr($this->data, $this->index, $length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Skip forward in the buffer
|
||||
*
|
||||
* @param int $length
|
||||
*/
|
||||
public function skip($length = 1)
|
||||
{
|
||||
|
||||
$this->index += $length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Jump to a specific position in the buffer,
|
||||
* will not jump past end of buffer
|
||||
*
|
||||
* @param $index
|
||||
*/
|
||||
public function jumpto($index)
|
||||
{
|
||||
|
||||
$this->index = min($index, $this->length - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current pointer position
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getPosition()
|
||||
{
|
||||
|
||||
return $this->index;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read from buffer until delimiter is reached
|
||||
*
|
||||
* If not found, return everything
|
||||
*
|
||||
* @param string $delim
|
||||
*
|
||||
* @return string
|
||||
* @throws \GameQ\Exception\Protocol
|
||||
*/
|
||||
public function readString($delim = "\x00")
|
||||
{
|
||||
|
||||
// Get position of delimiter
|
||||
$len = strpos($this->data, $delim, min($this->index, $this->length));
|
||||
|
||||
// If it is not found then return whole buffer
|
||||
if ($len === false) {
|
||||
return $this->read(strlen($this->data) - $this->index);
|
||||
}
|
||||
|
||||
// Read the string and remove the delimiter
|
||||
$string = $this->read($len - $this->index);
|
||||
++$this->index;
|
||||
|
||||
return $string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a pascal string from the buffer
|
||||
*
|
||||
* @param int $offset Number of bits to cut off the end
|
||||
* @param bool $read_offset True if the data after the offset is to be read
|
||||
*
|
||||
* @return string
|
||||
* @throws \GameQ\Exception\Protocol
|
||||
*/
|
||||
public function readPascalString($offset = 0, $read_offset = false)
|
||||
{
|
||||
|
||||
// Get the proper offset
|
||||
$len = $this->readInt8();
|
||||
$offset = max($len - $offset, 0);
|
||||
|
||||
// Read the data
|
||||
if ($read_offset) {
|
||||
return $this->read($offset);
|
||||
} else {
|
||||
return substr($this->read($len), 0, $offset);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read from buffer until any of the delimiters is reached
|
||||
*
|
||||
* If not found, return everything
|
||||
*
|
||||
* @param $delims
|
||||
* @param null $delimfound
|
||||
*
|
||||
* @return string
|
||||
* @throws \GameQ\Exception\Protocol
|
||||
*
|
||||
* @todo: Check to see if this is even used anymore
|
||||
*/
|
||||
public function readStringMulti($delims, &$delimfound = null)
|
||||
{
|
||||
|
||||
// Get position of delimiters
|
||||
$pos = [];
|
||||
foreach ($delims as $delim) {
|
||||
if ($p = strpos($this->data, $delim, min($this->index, $this->length))) {
|
||||
$pos[] = $p;
|
||||
}
|
||||
}
|
||||
|
||||
// If none are found then return whole buffer
|
||||
if (empty($pos)) {
|
||||
return $this->read(strlen($this->data) - $this->index);
|
||||
}
|
||||
|
||||
// Read the string and remove the delimiter
|
||||
sort($pos);
|
||||
$string = $this->read($pos[0] - $this->index);
|
||||
$delimfound = $this->read();
|
||||
|
||||
return $string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read an 8-bit unsigned integer
|
||||
*
|
||||
* @return int
|
||||
* @throws \GameQ\Exception\Protocol
|
||||
*/
|
||||
public function readInt8()
|
||||
{
|
||||
|
||||
$int = unpack('Cint', $this->read(1));
|
||||
|
||||
return $int['int'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Read and 8-bit signed integer
|
||||
*
|
||||
* @return int
|
||||
* @throws \GameQ\Exception\Protocol
|
||||
*/
|
||||
public function readInt8Signed()
|
||||
{
|
||||
|
||||
$int = unpack('cint', $this->read(1));
|
||||
|
||||
return $int['int'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a 16-bit unsigned integer
|
||||
*
|
||||
* @return int
|
||||
* @throws \GameQ\Exception\Protocol
|
||||
*/
|
||||
public function readInt16()
|
||||
{
|
||||
|
||||
// Change the integer type we are looking up
|
||||
switch ($this->number_type) {
|
||||
case self::NUMBER_TYPE_BIGENDIAN:
|
||||
$type = 'nint';
|
||||
break;
|
||||
|
||||
case self::NUMBER_TYPE_LITTLEENDIAN:
|
||||
$type = 'vint';
|
||||
break;
|
||||
|
||||
default:
|
||||
$type = 'Sint';
|
||||
}
|
||||
|
||||
$int = unpack($type, $this->read(2));
|
||||
|
||||
return $int['int'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a 16-bit signed integer
|
||||
*
|
||||
* @return int
|
||||
* @throws \GameQ\Exception\Protocol
|
||||
*/
|
||||
public function readInt16Signed()
|
||||
{
|
||||
|
||||
// Read the data into a string
|
||||
$string = $this->read(2);
|
||||
|
||||
// For big endian we need to reverse the bytes
|
||||
if ($this->number_type == self::NUMBER_TYPE_BIGENDIAN) {
|
||||
$string = strrev($string);
|
||||
}
|
||||
|
||||
$int = unpack('sint', $string);
|
||||
|
||||
unset($string);
|
||||
|
||||
return $int['int'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a 32-bit unsigned integer
|
||||
*
|
||||
* @return int
|
||||
* @throws \GameQ\Exception\Protocol
|
||||
*/
|
||||
public function readInt32()
|
||||
{
|
||||
|
||||
// Change the integer type we are looking up
|
||||
switch ($this->number_type) {
|
||||
case self::NUMBER_TYPE_BIGENDIAN:
|
||||
$type = 'Nint';
|
||||
break;
|
||||
|
||||
case self::NUMBER_TYPE_LITTLEENDIAN:
|
||||
$type = 'Vint';
|
||||
break;
|
||||
|
||||
default:
|
||||
$type = 'Lint';
|
||||
}
|
||||
|
||||
// Unpack the number
|
||||
$int = unpack($type, $this->read(4));
|
||||
|
||||
return $int['int'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a 32-bit signed integer
|
||||
*
|
||||
* @return int
|
||||
* @throws \GameQ\Exception\Protocol
|
||||
*/
|
||||
public function readInt32Signed()
|
||||
{
|
||||
|
||||
// Read the data into a string
|
||||
$string = $this->read(4);
|
||||
|
||||
// For big endian we need to reverse the bytes
|
||||
if ($this->number_type == self::NUMBER_TYPE_BIGENDIAN) {
|
||||
$string = strrev($string);
|
||||
}
|
||||
|
||||
$int = unpack('lint', $string);
|
||||
|
||||
unset($string);
|
||||
|
||||
return $int['int'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a 64-bit unsigned integer
|
||||
*
|
||||
* @return int
|
||||
* @throws \GameQ\Exception\Protocol
|
||||
*/
|
||||
public function readInt64()
|
||||
{
|
||||
|
||||
// We have the pack 64-bit codes available. See: http://php.net/manual/en/function.pack.php
|
||||
if (version_compare(PHP_VERSION, '5.6.3') >= 0 && PHP_INT_SIZE == 8) {
|
||||
// Change the integer type we are looking up
|
||||
switch ($this->number_type) {
|
||||
case self::NUMBER_TYPE_BIGENDIAN:
|
||||
$type = 'Jint';
|
||||
break;
|
||||
|
||||
case self::NUMBER_TYPE_LITTLEENDIAN:
|
||||
$type = 'Pint';
|
||||
break;
|
||||
|
||||
default:
|
||||
$type = 'Qint';
|
||||
}
|
||||
|
||||
$int64 = unpack($type, $this->read(8));
|
||||
|
||||
$int = $int64['int'];
|
||||
|
||||
unset($int64);
|
||||
} else {
|
||||
if ($this->number_type == self::NUMBER_TYPE_BIGENDIAN) {
|
||||
$high = $this->readInt32();
|
||||
$low = $this->readInt32();
|
||||
} else {
|
||||
$low = $this->readInt32();
|
||||
$high = $this->readInt32();
|
||||
}
|
||||
|
||||
// We have to determine the number via bitwise
|
||||
$int = ($high << 32) | $low;
|
||||
|
||||
unset($low, $high);
|
||||
}
|
||||
|
||||
return $int;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a 32-bit float
|
||||
*
|
||||
* @return float
|
||||
* @throws \GameQ\Exception\Protocol
|
||||
*/
|
||||
public function readFloat32()
|
||||
{
|
||||
|
||||
// Read the data into a string
|
||||
$string = $this->read(4);
|
||||
|
||||
// For big endian we need to reverse the bytes
|
||||
if ($this->number_type == self::NUMBER_TYPE_BIGENDIAN) {
|
||||
$string = strrev($string);
|
||||
}
|
||||
|
||||
$float = unpack('ffloat', $string);
|
||||
|
||||
unset($string);
|
||||
|
||||
return $float['float'];
|
||||
}
|
||||
}
|
39
GameQ/CONTRIBUTING.md
Normal file
39
GameQ/CONTRIBUTING.md
Normal file
|
@ -0,0 +1,39 @@
|
|||
# Contributing
|
||||
|
||||
Contributions are **welcome** and will be fully **credited**.
|
||||
|
||||
## Pull Requests
|
||||
|
||||
- **Document any change in behavior** - Make sure the `README.md` and any other relevant documentation are kept up-to-date.
|
||||
|
||||
- **Create feature branches** - Don't ask us to pull from your master branch.
|
||||
|
||||
- **One pull request per feature** - If you want to do more than one thing, send multiple pull requests.
|
||||
|
||||
## Coding Standard
|
||||
|
||||
- The **[PSR-2 Coding Standard](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md)** is to be used for all code.
|
||||
- **[PHPMD](http://phpmd.org/)** is used to help keep the code clean but exceptions can exist.
|
||||
|
||||
- Use the following commands to check your code before committing it:
|
||||
|
||||
```sh
|
||||
$ vendor/bin/phpcs src tests --extensions=php --ignore=bootstrap --report=checkstyle --report-file=build/logs/checkstyle.xml --standard=build/config/phpcs.xml -v
|
||||
$ vendor/bin/phpmd src,tests xml build/config/phpmd.xml
|
||||
```
|
||||
|
||||
|
||||
## Tests
|
||||
|
||||
- **Add tests!** - Your patch won't be accepted if it doesn't have tests.
|
||||
|
||||
- Run tests by calling `phpunit`
|
||||
```sh
|
||||
$ vendor/bin/phpunit
|
||||
```
|
||||
|
||||
The coding standard, mess detection and tests are validated by [Travis CI](.travis.yml).
|
||||
|
||||
# Can't Contribute?
|
||||
If you do not feel comfortable writing your own changes feel free open up a [new issue](https://github.com/Austinb/GameQ/issues/new) for
|
||||
to add a game or feature.
|
30
GameQ/Exception/Protocol.php
Normal file
30
GameQ/Exception/Protocol.php
Normal file
|
@ -0,0 +1,30 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is part of GameQ.
|
||||
*
|
||||
* GameQ is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GameQ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
namespace GameQ\Exception;
|
||||
|
||||
/**
|
||||
* Exception
|
||||
*
|
||||
* @author Austin Bischoff <austin@codebeard.com>
|
||||
*/
|
||||
class Protocol extends \Exception
|
||||
{
|
||||
}
|
30
GameQ/Exception/Query.php
Normal file
30
GameQ/Exception/Query.php
Normal file
|
@ -0,0 +1,30 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is part of GameQ.
|
||||
*
|
||||
* GameQ is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GameQ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
namespace GameQ\Exception;
|
||||
|
||||
/**
|
||||
* Exception
|
||||
*
|
||||
* @author Austin Bischoff <austin@codebeard.com>
|
||||
*/
|
||||
class Query extends \Exception
|
||||
{
|
||||
}
|
30
GameQ/Exception/Server.php
Normal file
30
GameQ/Exception/Server.php
Normal file
|
@ -0,0 +1,30 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is part of GameQ.
|
||||
*
|
||||
* GameQ is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GameQ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
namespace GameQ\Exception;
|
||||
|
||||
/**
|
||||
* Exception
|
||||
*
|
||||
* @author Austin Bischoff <austin@codebeard.com>
|
||||
*/
|
||||
class Server extends \Exception
|
||||
{
|
||||
}
|
58
GameQ/Filters/Base.php
Normal file
58
GameQ/Filters/Base.php
Normal file
|
@ -0,0 +1,58 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is part of GameQ.
|
||||
*
|
||||
* GameQ is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GameQ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace GameQ\Filters;
|
||||
|
||||
use GameQ\Server;
|
||||
|
||||
/**
|
||||
* Abstract base class which all filters must inherit
|
||||
*
|
||||
* @author Austin Bischoff <austin@codebeard.com>
|
||||
*/
|
||||
abstract class Base
|
||||
{
|
||||
|
||||
/**
|
||||
* Holds the options for this instance of the filter
|
||||
*
|
||||
* @type array
|
||||
*/
|
||||
protected $options = [];
|
||||
|
||||
/**
|
||||
* Construct
|
||||
*
|
||||
* @param array $options
|
||||
*/
|
||||
public function __construct(array $options = [])
|
||||
{
|
||||
|
||||
$this->options = $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply the filter to the data
|
||||
*
|
||||
* @param array $result
|
||||
* @param \GameQ\Server $server
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
abstract public function apply(array $result, Server $server);
|
||||
}
|
133
GameQ/Filters/Normalize.php
Normal file
133
GameQ/Filters/Normalize.php
Normal file
|
@ -0,0 +1,133 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is part of GameQ.
|
||||
*
|
||||
* GameQ is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GameQ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace GameQ\Filters;
|
||||
|
||||
use GameQ\Server;
|
||||
|
||||
/**
|
||||
* Class Normalize
|
||||
*
|
||||
* @package GameQ\Filters
|
||||
*/
|
||||
class Normalize extends Base
|
||||
{
|
||||
|
||||
/**
|
||||
* Holds the protocol specific normalize information
|
||||
*
|
||||
* @type array
|
||||
*/
|
||||
protected $normalize = [];
|
||||
|
||||
/**
|
||||
* Apply this filter
|
||||
*
|
||||
* @param array $result
|
||||
* @param \GameQ\Server $server
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function apply(array $result, Server $server)
|
||||
{
|
||||
|
||||
// No result passed so just return
|
||||
if (empty($result)) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
//$data = [ ];
|
||||
//$data['raw'][$server->id()] = $result;
|
||||
|
||||
// Grab the normalize for this protocol for the specific server
|
||||
$this->normalize = $server->protocol()->getNormalize();
|
||||
|
||||
// Do general information
|
||||
$result = array_merge($result, $this->check('general', $result));
|
||||
|
||||
// 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));
|
||||
}
|
||||
} 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));
|
||||
}
|
||||
} 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 $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check a section for normalization
|
||||
*
|
||||
* @param $section
|
||||
* @param $data
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function check($section, $data)
|
||||
{
|
||||
|
||||
// Normalized return array
|
||||
$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;
|
||||
|
||||
if (is_array($raw)) {
|
||||
// Iterate over the raw property we want to use
|
||||
foreach ($raw as $check) {
|
||||
if (array_key_exists($check, $data)) {
|
||||
$value = $data[$check];
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// String
|
||||
if (array_key_exists($raw, $data)) {
|
||||
$value = $data[$raw];
|
||||
}
|
||||
}
|
||||
|
||||
$normalized['gq_' . $property] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
return $normalized;
|
||||
}
|
||||
}
|
121
GameQ/Filters/Secondstohuman.php
Normal file
121
GameQ/Filters/Secondstohuman.php
Normal file
|
@ -0,0 +1,121 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is part of GameQ.
|
||||
*
|
||||
* GameQ is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GameQ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace GameQ\Filters;
|
||||
|
||||
use GameQ\Server;
|
||||
|
||||
/**
|
||||
* Class Secondstohuman
|
||||
*
|
||||
* This class 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
|
||||
*
|
||||
* @package GameQ\Filters
|
||||
* @author Austin Bischoff <austin@codebeard.com>
|
||||
*/
|
||||
class Secondstohuman extends Base
|
||||
{
|
||||
|
||||
/**
|
||||
* The options key for setting the data key(s) to look for to convert
|
||||
*/
|
||||
const OPTION_TIMEKEYS = 'timekeys';
|
||||
|
||||
/**
|
||||
* The result key added when applying this filter to a result
|
||||
*/
|
||||
const RESULT_KEY = 'gq_%s_human';
|
||||
|
||||
/**
|
||||
* Holds the default 'time' keys from the response array. This is key is usually 'time' from A2S responses
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $timeKeysDefault = ['time'];
|
||||
|
||||
/**
|
||||
* Secondstohuman constructor.
|
||||
*
|
||||
* @param array $options
|
||||
*/
|
||||
public function __construct(array $options = [])
|
||||
{
|
||||
// Check for passed keys
|
||||
if (!array_key_exists(self::OPTION_TIMEKEYS, $options)) {
|
||||
// Use default
|
||||
$options[self::OPTION_TIMEKEYS] = $this->timeKeysDefault;
|
||||
} else {
|
||||
// Used passed key(s) and make sure it is an array
|
||||
$options[self::OPTION_TIMEKEYS] = (!is_array($options[self::OPTION_TIMEKEYS])) ?
|
||||
[$options[self::OPTION_TIMEKEYS]] : $options[self::OPTION_TIMEKEYS];
|
||||
}
|
||||
|
||||
parent::__construct($options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply this filter to the result data
|
||||
*
|
||||
* @param array $result
|
||||
* @param Server $server
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function apply(array $result, Server $server)
|
||||
{
|
||||
// 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])) {
|
||||
// Make sure the value is a float (throws E_WARNING in PHP 7.1+)
|
||||
$value = floatval($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
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
115
GameQ/Filters/Stripcolors.php
Normal file
115
GameQ/Filters/Stripcolors.php
Normal file
|
@ -0,0 +1,115 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is part of GameQ.
|
||||
*
|
||||
* GameQ is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GameQ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace GameQ\Filters;
|
||||
|
||||
use GameQ\Server;
|
||||
|
||||
/**
|
||||
* Class Strip Colors
|
||||
*
|
||||
* Strip color codes from UT and Quake based games
|
||||
*
|
||||
* @package GameQ\Filters
|
||||
*/
|
||||
class Stripcolors extends Base
|
||||
{
|
||||
|
||||
/**
|
||||
* Apply this filter
|
||||
*
|
||||
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
|
||||
*
|
||||
* @param array $result
|
||||
* @param \GameQ\Server $server
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function apply(array $result, Server $server)
|
||||
{
|
||||
|
||||
// No result passed so just return
|
||||
if (empty($result)) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
//$data = [];
|
||||
//$data['raw'][ $server->id() ] = $result;
|
||||
|
||||
// Switch based on the base (not game) protocol
|
||||
switch ($server->protocol()->getProtocol()) {
|
||||
case 'quake2':
|
||||
case 'quake3':
|
||||
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 $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Strip color codes from quake based games
|
||||
*
|
||||
* @param string $string
|
||||
*/
|
||||
protected function stripQuake(&$string)
|
||||
{
|
||||
$string = preg_replace('#(\^.)#', '', $string);
|
||||
}
|
||||
|
||||
/**
|
||||
* Strip color codes from Unreal based games
|
||||
*
|
||||
* @param string $string
|
||||
*/
|
||||
protected function stripUnreal(&$string)
|
||||
{
|
||||
$string = preg_replace('/\x1b.../', '', $string);
|
||||
}
|
||||
|
||||
/**
|
||||
* Strip color codes from Source based games
|
||||
*
|
||||
* @param string $string
|
||||
*/
|
||||
protected function stripSource(&$string)
|
||||
{
|
||||
$string = strip_tags($string);
|
||||
}
|
||||
}
|
47
GameQ/Filters/Test.php
Normal file
47
GameQ/Filters/Test.php
Normal file
|
@ -0,0 +1,47 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is part of GameQ.
|
||||
*
|
||||
* GameQ is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GameQ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace GameQ\Filters;
|
||||
|
||||
use GameQ\Server;
|
||||
|
||||
/**
|
||||
* Class Test
|
||||
*
|
||||
* This is a test filter to be used for testing purposes only.
|
||||
*
|
||||
* @package GameQ\Filters
|
||||
*/
|
||||
class Test extends Base
|
||||
{
|
||||
/**
|
||||
* Apply the filter. For this we just return whatever is sent
|
||||
*
|
||||
* @SuppressWarnings(PHPMD)
|
||||
*
|
||||
* @param array $result
|
||||
* @param \GameQ\Server $server
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function apply(array $result, Server $server)
|
||||
{
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
649
GameQ/GameQ.php
Normal file
649
GameQ/GameQ.php
Normal file
|
@ -0,0 +1,649 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is part of GameQ.
|
||||
*
|
||||
* GameQ is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GameQ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace GameQ;
|
||||
|
||||
use GameQ\Exception\Protocol as ProtocolException;
|
||||
use GameQ\Exception\Query as QueryException;
|
||||
|
||||
/**
|
||||
* Base GameQ Class
|
||||
*
|
||||
* This class should be the only one that is included when you use GameQ to query
|
||||
* any games servers.
|
||||
*
|
||||
* Requirements: See wiki or README for more information on the requirements
|
||||
* - PHP 5.4.14+
|
||||
* * Bzip2 - http://www.php.net/manual/en/book.bzip2.php
|
||||
*
|
||||
* @author Austin Bischoff <austin@codebeard.com>
|
||||
*
|
||||
* @property bool $debug
|
||||
* @property string $capture_packets_file
|
||||
* @property int $stream_timeout
|
||||
* @property int $timeout
|
||||
* @property int $write_wait
|
||||
*/
|
||||
class GameQ
|
||||
{
|
||||
/*
|
||||
* Constants
|
||||
*/
|
||||
const PROTOCOLS_DIRECTORY = __DIR__ . '/Protocols';
|
||||
|
||||
/* Static Section */
|
||||
|
||||
/**
|
||||
* Holds the instance of itself
|
||||
*
|
||||
* @type self
|
||||
*/
|
||||
protected static $instance = null;
|
||||
|
||||
/**
|
||||
* Create a new instance of this class
|
||||
*
|
||||
* @return \GameQ\GameQ
|
||||
*/
|
||||
public static function factory()
|
||||
{
|
||||
|
||||
// Create a new instance
|
||||
self::$instance = new self();
|
||||
|
||||
// Return this new instance
|
||||
return self::$instance;
|
||||
}
|
||||
|
||||
/* Dynamic Section */
|
||||
|
||||
/**
|
||||
* Default options
|
||||
*
|
||||
* @type array
|
||||
*/
|
||||
protected $options = [
|
||||
'debug' => false,
|
||||
'timeout' => 3, // Seconds
|
||||
'filters' => [
|
||||
// Default normalize
|
||||
'normalize_d751713988987e9331980363e24189ce' => [
|
||||
'filter' => 'normalize',
|
||||
'options' => [],
|
||||
],
|
||||
],
|
||||
// Advanced settings
|
||||
'stream_timeout' => 200000, // See http://www.php.net/manual/en/function.stream-select.php for more info
|
||||
'write_wait' => 500,
|
||||
// How long (in micro-seconds) to pause between writing to server sockets, helps cpu usage
|
||||
|
||||
// Used for generating protocol test data
|
||||
'capture_packets_file' => null,
|
||||
];
|
||||
|
||||
/**
|
||||
* Array of servers being queried
|
||||
*
|
||||
* @type array
|
||||
*/
|
||||
protected $servers = [];
|
||||
|
||||
/**
|
||||
* The query library to use. Default is Native
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $queryLibrary = 'GameQ\\Query\\Native';
|
||||
|
||||
/**
|
||||
* Holds the instance of the queryLibrary
|
||||
*
|
||||
* @type \GameQ\Query\Core|null
|
||||
*/
|
||||
protected $query = null;
|
||||
|
||||
/**
|
||||
* GameQ constructor.
|
||||
*
|
||||
* Do some checks as needed so this will operate
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
// Check for missing utf8_encode function
|
||||
if (!function_exists('utf8_encode')) {
|
||||
throw new \Exception("PHP's utf8_encode() function is required - "
|
||||
. "http://php.net/manual/en/function.utf8-encode.php. Check your php installation.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an option's value
|
||||
*
|
||||
* @param mixed $option
|
||||
*
|
||||
* @return mixed|null
|
||||
*/
|
||||
public function __get($option)
|
||||
{
|
||||
|
||||
return isset($this->options[$option]) ? $this->options[$option] : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set an option's value
|
||||
*
|
||||
* @param mixed $option
|
||||
* @param mixed $value
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function __set($option, $value)
|
||||
{
|
||||
|
||||
$this->options[$option] = $value;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Chainable call to __set, uses set as the actual setter
|
||||
*
|
||||
* @param mixed $var
|
||||
* @param mixed $value
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setOption($var, $value)
|
||||
{
|
||||
|
||||
// Use magic
|
||||
$this->{$var} = $value;
|
||||
|
||||
return $this; // Make chainable
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a single server
|
||||
*
|
||||
* @param array $server_info
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function addServer(array $server_info = [])
|
||||
{
|
||||
|
||||
// Add and validate the server
|
||||
$this->servers[uniqid()] = new Server($server_info);
|
||||
|
||||
return $this; // Make calls chainable
|
||||
}
|
||||
|
||||
/**
|
||||
* Add multiple servers in a single call
|
||||
*
|
||||
* @param array $servers
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function addServers(array $servers = [])
|
||||
{
|
||||
|
||||
// Loop through all the servers and add them
|
||||
foreach ($servers as $server_info) {
|
||||
$this->addServer($server_info);
|
||||
}
|
||||
|
||||
return $this; // Make calls chainable
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a set of servers from a file or an array of files.
|
||||
* Supported formats:
|
||||
* JSON
|
||||
*
|
||||
* @param array $files
|
||||
*
|
||||
* @return $this
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function addServersFromFiles($files = [])
|
||||
{
|
||||
|
||||
// Since we expect an array let us turn a string (i.e. single file) into an array
|
||||
if (!is_array($files)) {
|
||||
$files = [$files];
|
||||
}
|
||||
|
||||
// Iterate over the file(s) and add them
|
||||
foreach ($files as $file) {
|
||||
// Check to make sure the file exists and we can read it
|
||||
if (!file_exists($file) || !is_readable($file)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// See if this file is JSON
|
||||
if (($servers = json_decode(file_get_contents($file), true)) === null
|
||||
&& json_last_error() !== JSON_ERROR_NONE
|
||||
) {
|
||||
// Type not supported
|
||||
continue;
|
||||
}
|
||||
|
||||
// Add this list of servers
|
||||
$this->addServers($servers);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear all of the defined servers
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function clearServers()
|
||||
{
|
||||
|
||||
// Reset all the servers
|
||||
$this->servers = [];
|
||||
|
||||
return $this; // Make Chainable
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a filter to the processing list
|
||||
*
|
||||
* @param string $filterName
|
||||
* @param array $options
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function addFilter($filterName, $options = [])
|
||||
{
|
||||
// Create the filter hash so we can run multiple versions of the same filter
|
||||
$filterHash = sprintf('%s_%s', strtolower($filterName), md5(json_encode($options)));
|
||||
|
||||
// Add the filter
|
||||
$this->options['filters'][$filterHash] = [
|
||||
'filter' => strtolower($filterName),
|
||||
'options' => $options,
|
||||
];
|
||||
|
||||
unset($filterHash);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove an added filter
|
||||
*
|
||||
* @param string $filterHash
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function removeFilter($filterHash)
|
||||
{
|
||||
// Make lower case
|
||||
$filterHash = strtolower($filterHash);
|
||||
|
||||
// Remove this filter if it has been defined
|
||||
if (array_key_exists($filterHash, $this->options['filters'])) {
|
||||
unset($this->options['filters'][$filterHash]);
|
||||
}
|
||||
|
||||
unset($filterHash);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the list of applied filters
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function listFilters()
|
||||
{
|
||||
return $this->options['filters'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Main method used to actually process all of the added servers and return the information
|
||||
*
|
||||
* @return array
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function process()
|
||||
{
|
||||
|
||||
// Initialize the query library we are using
|
||||
$class = new \ReflectionClass($this->queryLibrary);
|
||||
|
||||
// Set the query pointer to the new instance of the library
|
||||
$this->query = $class->newInstance();
|
||||
|
||||
unset($class);
|
||||
|
||||
// Define the return
|
||||
$results = [];
|
||||
|
||||
// @todo: Add break up into loop to split large arrays into smaller chunks
|
||||
|
||||
// Do server challenge(s) first, if any
|
||||
$this->doChallenges();
|
||||
|
||||
// Do packets for server(s) and get query responses
|
||||
$this->doQueries();
|
||||
|
||||
// Now we should have some information to process for each server
|
||||
foreach ($this->servers as $server) {
|
||||
/* @var $server \GameQ\Server */
|
||||
|
||||
// Parse the responses for this server
|
||||
$result = $this->doParseResponse($server);
|
||||
|
||||
// Apply the filters
|
||||
$result = array_merge($result, $this->doApplyFilters($result, $server));
|
||||
|
||||
// Sort the keys so they are alphabetical and nicer to look at
|
||||
ksort($result);
|
||||
|
||||
// Add the result to the results array
|
||||
$results[$server->id()] = $result;
|
||||
}
|
||||
|
||||
return $results;
|
||||
}
|
||||
|
||||
/**
|
||||
* Do server challenges, where required
|
||||
*/
|
||||
protected function doChallenges()
|
||||
{
|
||||
|
||||
// Initialize the sockets for reading
|
||||
$sockets = [];
|
||||
|
||||
// By default we don't have any challenges to process
|
||||
$server_challenge = false;
|
||||
|
||||
// Do challenge packets
|
||||
foreach ($this->servers as $server_id => $server) {
|
||||
/* @var $server \GameQ\Server */
|
||||
|
||||
// This protocol has a challenge packet that needs to be sent
|
||||
if ($server->protocol()->hasChallenge()) {
|
||||
// We have a challenge, set the flag
|
||||
$server_challenge = true;
|
||||
|
||||
// Let's make a clone of the query class
|
||||
$socket = clone $this->query;
|
||||
|
||||
// Set the information for this query socket
|
||||
$socket->set(
|
||||
$server->protocol()->transport(),
|
||||
$server->ip,
|
||||
$server->port_query,
|
||||
$this->timeout
|
||||
);
|
||||
|
||||
try {
|
||||
// Now write the challenge packet to the socket.
|
||||
$socket->write($server->protocol()->getPacket(Protocol::PACKET_CHALLENGE));
|
||||
|
||||
// Add the socket information so we can reference it easily
|
||||
$sockets[(int)$socket->get()] = [
|
||||
'server_id' => $server_id,
|
||||
'socket' => $socket,
|
||||
];
|
||||
} catch (QueryException $e) {
|
||||
// Check to see if we are in debug, if so bubble up the exception
|
||||
if ($this->debug) {
|
||||
throw new \Exception($e->getMessage(), $e->getCode(), $e);
|
||||
}
|
||||
}
|
||||
|
||||
unset($socket);
|
||||
|
||||
// Let's sleep shortly so we are not hammering out calls rapid fire style hogging cpu
|
||||
usleep($this->write_wait);
|
||||
}
|
||||
}
|
||||
|
||||
// We have at least one server with a challenge, we need to listen for responses
|
||||
if ($server_challenge) {
|
||||
// Now we need to listen for and grab challenge response(s)
|
||||
$responses = call_user_func_array(
|
||||
[$this->query, 'getResponses'],
|
||||
[$sockets, $this->timeout, $this->stream_timeout]
|
||||
);
|
||||
|
||||
// Iterate over the challenge responses
|
||||
foreach ($responses as $socket_id => $response) {
|
||||
// Back out the server_id we need to update the challenge response for
|
||||
$server_id = $sockets[$socket_id]['server_id'];
|
||||
|
||||
// Make this into a buffer so it is easier to manipulate
|
||||
$challenge = new Buffer(implode('', $response));
|
||||
|
||||
// Grab the server instance
|
||||
/* @var $server \GameQ\Server */
|
||||
$server = $this->servers[$server_id];
|
||||
|
||||
// Apply the challenge
|
||||
$server->protocol()->challengeParseAndApply($challenge);
|
||||
|
||||
// Add this socket to be reused, has to be reused in GameSpy3 for example
|
||||
$server->socketAdd($sockets[$socket_id]['socket']);
|
||||
|
||||
// Clear
|
||||
unset($server);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the actual queries and get the response(s)
|
||||
*/
|
||||
protected function doQueries()
|
||||
{
|
||||
|
||||
// Initialize the array of sockets
|
||||
$sockets = [];
|
||||
|
||||
// Iterate over the server list
|
||||
foreach ($this->servers as $server_id => $server) {
|
||||
/* @var $server \GameQ\Server */
|
||||
|
||||
// Invoke the beforeSend method
|
||||
$server->protocol()->beforeSend($server);
|
||||
|
||||
// Get all the non-challenge packets we need to send
|
||||
$packets = $server->protocol()->getPacket('!' . Protocol::PACKET_CHALLENGE);
|
||||
|
||||
if (count($packets) == 0) {
|
||||
// Skip nothing else to do for some reason.
|
||||
continue;
|
||||
}
|
||||
|
||||
// Try to use an existing socket
|
||||
if (($socket = $server->socketGet()) === null) {
|
||||
// Let's make a clone of the query class
|
||||
$socket = clone $this->query;
|
||||
|
||||
// Set the information for this query socket
|
||||
$socket->set(
|
||||
$server->protocol()->transport(),
|
||||
$server->ip,
|
||||
$server->port_query,
|
||||
$this->timeout
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
// Iterate over all the packets we need to send
|
||||
foreach ($packets as $packet_data) {
|
||||
// Now write the packet to the socket.
|
||||
$socket->write($packet_data);
|
||||
|
||||
// Let's sleep shortly so we are not hammering out calls rapid fire style
|
||||
usleep($this->write_wait);
|
||||
}
|
||||
|
||||
unset($packets);
|
||||
|
||||
// Add the socket information so we can reference it easily
|
||||
$sockets[(int)$socket->get()] = [
|
||||
'server_id' => $server_id,
|
||||
'socket' => $socket,
|
||||
];
|
||||
} catch (QueryException $e) {
|
||||
// Check to see if we are in debug, if so bubble up the exception
|
||||
if ($this->debug) {
|
||||
throw new \Exception($e->getMessage(), $e->getCode(), $e);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// Clean up the sockets, if any left over
|
||||
$server->socketCleanse();
|
||||
}
|
||||
|
||||
// Now we need to listen for and grab response(s)
|
||||
$responses = call_user_func_array(
|
||||
[$this->query, 'getResponses'],
|
||||
[$sockets, $this->timeout, $this->stream_timeout]
|
||||
);
|
||||
|
||||
// Iterate over the responses
|
||||
foreach ($responses as $socket_id => $response) {
|
||||
// Back out the server_id
|
||||
$server_id = $sockets[$socket_id]['server_id'];
|
||||
|
||||
// Grab the server instance
|
||||
/* @var $server \GameQ\Server */
|
||||
$server = $this->servers[$server_id];
|
||||
|
||||
// Save the response from this packet
|
||||
$server->protocol()->packetResponse($response);
|
||||
|
||||
unset($server);
|
||||
}
|
||||
|
||||
// Now we need to close all of the sockets
|
||||
foreach ($sockets as $socketInfo) {
|
||||
/* @var $socket \GameQ\Query\Core */
|
||||
$socket = $socketInfo['socket'];
|
||||
|
||||
// Close the socket
|
||||
$socket->close();
|
||||
|
||||
unset($socket);
|
||||
}
|
||||
|
||||
unset($sockets);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the response for a specific server
|
||||
*
|
||||
* @param \GameQ\Server $server
|
||||
*
|
||||
* @return array
|
||||
* @throws \Exception
|
||||
*/
|
||||
protected function doParseResponse(Server $server)
|
||||
{
|
||||
|
||||
try {
|
||||
// @codeCoverageIgnoreStart
|
||||
// We want to save this server's response to a file (useful for unit testing)
|
||||
if (!is_null($this->capture_packets_file)) {
|
||||
file_put_contents(
|
||||
$this->capture_packets_file,
|
||||
implode(PHP_EOL . '||' . PHP_EOL, $server->protocol()->packetResponse())
|
||||
);
|
||||
}
|
||||
// @codeCoverageIgnoreEnd
|
||||
|
||||
// Get the server response
|
||||
$results = $server->protocol()->processResponse();
|
||||
|
||||
// Check for online before we do anything else
|
||||
$results['gq_online'] = (count($results) > 0);
|
||||
} catch (ProtocolException $e) {
|
||||
// Check to see if we are in debug, if so bubble up the exception
|
||||
if ($this->debug) {
|
||||
throw new \Exception($e->getMessage(), $e->getCode(), $e);
|
||||
}
|
||||
|
||||
// We ignore this server
|
||||
$results = [
|
||||
'gq_online' => false,
|
||||
];
|
||||
}
|
||||
|
||||
// Now add some default stuff
|
||||
$results['gq_address'] = (isset($results['gq_address'])) ? $results['gq_address'] : $server->ip();
|
||||
$results['gq_port_client'] = $server->portClient();
|
||||
$results['gq_port_query'] = (isset($results['gq_port_query'])) ? $results['gq_port_query'] : $server->portQuery();
|
||||
$results['gq_protocol'] = $server->protocol()->getProtocol();
|
||||
$results['gq_type'] = (string)$server->protocol();
|
||||
$results['gq_name'] = $server->protocol()->nameLong();
|
||||
$results['gq_transport'] = $server->protocol()->transport();
|
||||
|
||||
// Process the join link
|
||||
if (!isset($results['gq_joinlink']) || empty($results['gq_joinlink'])) {
|
||||
$results['gq_joinlink'] = $server->getJoinLink();
|
||||
}
|
||||
|
||||
return $results;
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply any filters to the results
|
||||
*
|
||||
* @param array $results
|
||||
* @param \GameQ\Server $server
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function doApplyFilters(array $results, Server $server)
|
||||
{
|
||||
|
||||
// Loop over the filters
|
||||
foreach ($this->options['filters'] as $filterOptions) {
|
||||
// Try to do this filter
|
||||
try {
|
||||
// Make a new reflection class
|
||||
$class = new \ReflectionClass(sprintf('GameQ\\Filters\\%s', ucfirst($filterOptions['filter'])));
|
||||
|
||||
// Create a new instance of the filter class specified
|
||||
$filter = $class->newInstanceArgs([$filterOptions['options']]);
|
||||
|
||||
// Apply the filter to the data
|
||||
$results = $filter->apply($results, $server);
|
||||
} catch (\ReflectionException $e) {
|
||||
// Invalid, skip it
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
return $results;
|
||||
}
|
||||
}
|
165
GameQ/LICENSE.lgpl
Normal file
165
GameQ/LICENSE.lgpl
Normal file
|
@ -0,0 +1,165 @@
|
|||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
|
||||
This version of the GNU Lesser General Public License incorporates
|
||||
the terms and conditions of version 3 of the GNU General Public
|
||||
License, supplemented by the additional permissions listed below.
|
||||
|
||||
0. Additional Definitions.
|
||||
|
||||
As used herein, "this License" refers to version 3 of the GNU Lesser
|
||||
General Public License, and the "GNU GPL" refers to version 3 of the GNU
|
||||
General Public License.
|
||||
|
||||
"The Library" refers to a covered work governed by this License,
|
||||
other than an Application or a Combined Work as defined below.
|
||||
|
||||
An "Application" is any work that makes use of an interface provided
|
||||
by the Library, but which is not otherwise based on the Library.
|
||||
Defining a subclass of a class defined by the Library is deemed a mode
|
||||
of using an interface provided by the Library.
|
||||
|
||||
A "Combined Work" is a work produced by combining or linking an
|
||||
Application with the Library. The particular version of the Library
|
||||
with which the Combined Work was made is also called the "Linked
|
||||
Version".
|
||||
|
||||
The "Minimal Corresponding Source" for a Combined Work means the
|
||||
Corresponding Source for the Combined Work, excluding any source code
|
||||
for portions of the Combined Work that, considered in isolation, are
|
||||
based on the Application, and not on the Linked Version.
|
||||
|
||||
The "Corresponding Application Code" for a Combined Work means the
|
||||
object code and/or source code for the Application, including any data
|
||||
and utility programs needed for reproducing the Combined Work from the
|
||||
Application, but excluding the System Libraries of the Combined Work.
|
||||
|
||||
1. Exception to Section 3 of the GNU GPL.
|
||||
|
||||
You may convey a covered work under sections 3 and 4 of this License
|
||||
without being bound by section 3 of the GNU GPL.
|
||||
|
||||
2. Conveying Modified Versions.
|
||||
|
||||
If you modify a copy of the Library, and, in your modifications, a
|
||||
facility refers to a function or data to be supplied by an Application
|
||||
that uses the facility (other than as an argument passed when the
|
||||
facility is invoked), then you may convey a copy of the modified
|
||||
version:
|
||||
|
||||
a) under this License, provided that you make a good faith effort to
|
||||
ensure that, in the event an Application does not supply the
|
||||
function or data, the facility still operates, and performs
|
||||
whatever part of its purpose remains meaningful, or
|
||||
|
||||
b) under the GNU GPL, with none of the additional permissions of
|
||||
this License applicable to that copy.
|
||||
|
||||
3. Object Code Incorporating Material from Library Header Files.
|
||||
|
||||
The object code form of an Application may incorporate material from
|
||||
a header file that is part of the Library. You may convey such object
|
||||
code under terms of your choice, provided that, if the incorporated
|
||||
material is not limited to numerical parameters, data structure
|
||||
layouts and accessors, or small macros, inline functions and templates
|
||||
(ten or fewer lines in length), you do both of the following:
|
||||
|
||||
a) Give prominent notice with each copy of the object code that the
|
||||
Library is used in it and that the Library and its use are
|
||||
covered by this License.
|
||||
|
||||
b) Accompany the object code with a copy of the GNU GPL and this license
|
||||
document.
|
||||
|
||||
4. Combined Works.
|
||||
|
||||
You may convey a Combined Work under terms of your choice that,
|
||||
taken together, effectively do not restrict modification of the
|
||||
portions of the Library contained in the Combined Work and reverse
|
||||
engineering for debugging such modifications, if you also do each of
|
||||
the following:
|
||||
|
||||
a) Give prominent notice with each copy of the Combined Work that
|
||||
the Library is used in it and that the Library and its use are
|
||||
covered by this License.
|
||||
|
||||
b) Accompany the Combined Work with a copy of the GNU GPL and this license
|
||||
document.
|
||||
|
||||
c) For a Combined Work that displays copyright notices during
|
||||
execution, include the copyright notice for the Library among
|
||||
these notices, as well as a reference directing the user to the
|
||||
copies of the GNU GPL and this license document.
|
||||
|
||||
d) Do one of the following:
|
||||
|
||||
0) Convey the Minimal Corresponding Source under the terms of this
|
||||
License, and the Corresponding Application Code in a form
|
||||
suitable for, and under terms that permit, the user to
|
||||
recombine or relink the Application with a modified version of
|
||||
the Linked Version to produce a modified Combined Work, in the
|
||||
manner specified by section 6 of the GNU GPL for conveying
|
||||
Corresponding Source.
|
||||
|
||||
1) Use a suitable shared library mechanism for linking with the
|
||||
Library. A suitable mechanism is one that (a) uses at run time
|
||||
a copy of the Library already present on the user's computer
|
||||
system, and (b) will operate properly with a modified version
|
||||
of the Library that is interface-compatible with the Linked
|
||||
Version.
|
||||
|
||||
e) Provide Installation Information, but only if you would otherwise
|
||||
be required to provide such information under section 6 of the
|
||||
GNU GPL, and only to the extent that such information is
|
||||
necessary to install and execute a modified version of the
|
||||
Combined Work produced by recombining or relinking the
|
||||
Application with a modified version of the Linked Version. (If
|
||||
you use option 4d0, the Installation Information must accompany
|
||||
the Minimal Corresponding Source and Corresponding Application
|
||||
Code. If you use option 4d1, you must provide the Installation
|
||||
Information in the manner specified by section 6 of the GNU GPL
|
||||
for conveying Corresponding Source.)
|
||||
|
||||
5. Combined Libraries.
|
||||
|
||||
You may place library facilities that are a work based on the
|
||||
Library side by side in a single library together with other library
|
||||
facilities that are not Applications and are not covered by this
|
||||
License, and convey such a combined library under terms of your
|
||||
choice, if you do both of the following:
|
||||
|
||||
a) Accompany the combined library with a copy of the same work based
|
||||
on the Library, uncombined with any other library facilities,
|
||||
conveyed under the terms of this License.
|
||||
|
||||
b) Give prominent notice with the combined library that part of it
|
||||
is a work based on the Library, and explaining where to find the
|
||||
accompanying uncombined form of the same work.
|
||||
|
||||
6. Revised Versions of the GNU Lesser General Public License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions
|
||||
of the GNU Lesser General Public License from time to time. Such new
|
||||
versions will be similar in spirit to the present version, but may
|
||||
differ in detail to address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Library as you received it specifies that a certain numbered version
|
||||
of the GNU Lesser General Public License "or any later version"
|
||||
applies to it, you have the option of following the terms and
|
||||
conditions either of that published version or of any later version
|
||||
published by the Free Software Foundation. If the Library as you
|
||||
received it does not specify a version number of the GNU Lesser
|
||||
General Public License, you may choose any version of the GNU Lesser
|
||||
General Public License ever published by the Free Software Foundation.
|
||||
|
||||
If the Library as you received it specifies that a proxy can decide
|
||||
whether future versions of the GNU Lesser General Public License shall
|
||||
apply, that proxy's public statement of acceptance of any version is
|
||||
permanent authorization for you to choose that version for the
|
||||
Library.
|
500
GameQ/Protocol.php
Normal file
500
GameQ/Protocol.php
Normal file
|
@ -0,0 +1,500 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is part of GameQ.
|
||||
*
|
||||
* GameQ is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GameQ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
namespace GameQ;
|
||||
|
||||
/**
|
||||
* Handles the core functionality for the protocols
|
||||
*
|
||||
* @SuppressWarnings(PHPMD.NumberOfChildren)
|
||||
*
|
||||
* @author Austin Bischoff <austin@codebeard.com>
|
||||
*/
|
||||
abstract class Protocol
|
||||
{
|
||||
|
||||
/**
|
||||
* Constants for class states
|
||||
*/
|
||||
const STATE_TESTING = 1;
|
||||
|
||||
const STATE_BETA = 2;
|
||||
|
||||
const STATE_STABLE = 3;
|
||||
|
||||
const STATE_DEPRECATED = 4;
|
||||
|
||||
/**
|
||||
* Constants for packet keys
|
||||
*/
|
||||
const PACKET_ALL = 'all'; // Some protocols allow all data to be sent back in one call.
|
||||
|
||||
const PACKET_BASIC = 'basic';
|
||||
|
||||
const PACKET_CHALLENGE = 'challenge';
|
||||
|
||||
const PACKET_CHANNELS = 'channels'; // Voice servers
|
||||
|
||||
const PACKET_DETAILS = 'details';
|
||||
|
||||
const PACKET_INFO = 'info';
|
||||
|
||||
const PACKET_PLAYERS = 'players';
|
||||
|
||||
const PACKET_STATUS = 'status';
|
||||
|
||||
const PACKET_RULES = 'rules';
|
||||
|
||||
const PACKET_VERSION = 'version';
|
||||
|
||||
/**
|
||||
* Transport constants
|
||||
*/
|
||||
const TRANSPORT_UDP = 'udp';
|
||||
|
||||
const TRANSPORT_TCP = 'tcp';
|
||||
|
||||
const TRANSPORT_SSL = 'ssl';
|
||||
|
||||
const TRANSPORT_TLS = 'tls';
|
||||
|
||||
/**
|
||||
* Short name of the protocol
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name = 'unknown';
|
||||
|
||||
/**
|
||||
* The longer, fancier name for the protocol
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name_long = 'unknown';
|
||||
|
||||
/**
|
||||
* The difference between the client port and query port
|
||||
*
|
||||
* @type int
|
||||
*/
|
||||
protected $port_diff = 0;
|
||||
|
||||
/**
|
||||
* The transport method to use to actually send the data
|
||||
* Default is UDP
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $transport = self::TRANSPORT_UDP;
|
||||
|
||||
/**
|
||||
* The protocol type used when querying the server
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $protocol = 'unknown';
|
||||
|
||||
/**
|
||||
* Holds the valid packet types this protocol has available.
|
||||
*
|
||||
* @type array
|
||||
*/
|
||||
protected $packets = [];
|
||||
|
||||
/**
|
||||
* Holds the response headers and the method to use to process them.
|
||||
*
|
||||
* @type array
|
||||
*/
|
||||
protected $responses = [];
|
||||
|
||||
/**
|
||||
* Holds the list of methods to run when parsing the packet response(s) data. These
|
||||
* methods should provide all the return information.
|
||||
*
|
||||
* @type array
|
||||
*/
|
||||
protected $process_methods = [];
|
||||
|
||||
/**
|
||||
* The packet responses received
|
||||
*
|
||||
* @type array
|
||||
*/
|
||||
protected $packets_response = [];
|
||||
|
||||
/**
|
||||
* Holds the instance of the result class
|
||||
*
|
||||
* @type null
|
||||
*/
|
||||
protected $result = null;
|
||||
|
||||
/**
|
||||
* Options for this protocol
|
||||
*
|
||||
* @type array
|
||||
*/
|
||||
protected $options = [];
|
||||
|
||||
/**
|
||||
* Define the state of this class
|
||||
*
|
||||
* @type int
|
||||
*/
|
||||
protected $state = self::STATE_STABLE;
|
||||
|
||||
/**
|
||||
* Holds specific normalize settings
|
||||
*
|
||||
* @todo: Remove this ugly bulk by moving specific ones to their specific game(s)
|
||||
*
|
||||
* @type array
|
||||
*/
|
||||
protected $normalize = [
|
||||
// General
|
||||
'general' => [
|
||||
// target => source
|
||||
'dedicated' => [
|
||||
'listenserver',
|
||||
'dedic',
|
||||
'bf2dedicated',
|
||||
'netserverdedicated',
|
||||
'bf2142dedicated',
|
||||
'dedicated',
|
||||
],
|
||||
'gametype' => ['ggametype', 'sigametype', 'matchtype'],
|
||||
'hostname' => ['svhostname', 'servername', 'siname', 'name'],
|
||||
'mapname' => ['map', 'simap'],
|
||||
'maxplayers' => ['svmaxclients', 'simaxplayers', 'maxclients', 'max_players'],
|
||||
'mod' => ['game', 'gamedir', 'gamevariant'],
|
||||
'numplayers' => ['clients', 'sinumplayers', 'num_players'],
|
||||
'password' => ['protected', 'siusepass', 'sineedpass', 'pswrd', 'gneedpass', 'auth', 'passsord'],
|
||||
],
|
||||
// Indvidual
|
||||
'player' => [
|
||||
'name' => ['nick', 'player', 'playername', 'name'],
|
||||
'kills' => ['kills'],
|
||||
'deaths' => ['deaths'],
|
||||
'score' => ['kills', 'frags', 'skill', 'score'],
|
||||
'ping' => ['ping'],
|
||||
],
|
||||
// Team
|
||||
'team' => [
|
||||
'name' => ['name', 'teamname', 'team_t'],
|
||||
'score' => ['score', 'score_t'],
|
||||
],
|
||||
];
|
||||
|
||||
/**
|
||||
* Quick join link
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $join_link = '';
|
||||
|
||||
/**
|
||||
* @param array $options
|
||||
*/
|
||||
public function __construct(array $options = [])
|
||||
{
|
||||
|
||||
// Set the options for this specific instance of the class
|
||||
$this->options = $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* String name of this class
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the port difference between the server's client (game) and query ports
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function portDiff()
|
||||
{
|
||||
|
||||
return $this->port_diff;
|
||||
}
|
||||
|
||||
/**
|
||||
* "Find" the query port based off of the client port and port_diff
|
||||
*
|
||||
* This method is meant to be overloaded for more complex maths or lookup tables
|
||||
*
|
||||
* @param int $clientPort
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function findQueryPort($clientPort)
|
||||
{
|
||||
|
||||
return $clientPort + $this->port_diff;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the join_link as defined by the protocol class
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function joinLink()
|
||||
{
|
||||
|
||||
return $this->join_link;
|
||||
}
|
||||
|
||||
/**
|
||||
* Short (callable) name of this class
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function name()
|
||||
{
|
||||
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Long name of this class
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function nameLong()
|
||||
{
|
||||
|
||||
return $this->name_long;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the status of this Protocol Class
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function state()
|
||||
{
|
||||
|
||||
return $this->state;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the protocol property
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getProtocol()
|
||||
{
|
||||
|
||||
return $this->protocol;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get/set the transport type for this protocol
|
||||
*
|
||||
* @param string|null $type
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function transport($type = null)
|
||||
{
|
||||
|
||||
// Act as setter
|
||||
if (!is_null($type)) {
|
||||
$this->transport = $type;
|
||||
}
|
||||
|
||||
return $this->transport;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the options for the protocol call
|
||||
*
|
||||
* @param array $options
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function options($options = [])
|
||||
{
|
||||
|
||||
// Act as setter
|
||||
if (!empty($options)) {
|
||||
$this->options = $options;
|
||||
}
|
||||
|
||||
return $this->options;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Packet Section
|
||||
*/
|
||||
|
||||
/**
|
||||
* Return specific packet(s)
|
||||
*
|
||||
* @param array $type
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getPacket($type = [])
|
||||
{
|
||||
|
||||
$packets = [];
|
||||
|
||||
|
||||
// We want an array of packets back
|
||||
if (is_array($type) && !empty($type)) {
|
||||
// Loop the packets
|
||||
foreach ($this->packets as $packet_type => $packet_data) {
|
||||
// We want this packet
|
||||
if (in_array($packet_type, $type)) {
|
||||
$packets[$packet_type] = $packet_data;
|
||||
}
|
||||
}
|
||||
} elseif ($type == '!challenge') {
|
||||
// Loop the packets
|
||||
foreach ($this->packets as $packet_type => $packet_data) {
|
||||
// Dont want challenge packets
|
||||
if ($packet_type != self::PACKET_CHALLENGE) {
|
||||
$packets[$packet_type] = $packet_data;
|
||||
}
|
||||
}
|
||||
} elseif (is_string($type)) {
|
||||
// Return specific packet type
|
||||
$packets = $this->packets[$type];
|
||||
} else {
|
||||
// Return all packets
|
||||
$packets = $this->packets;
|
||||
}
|
||||
|
||||
// Return the packets
|
||||
return $packets;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get/set the packet response
|
||||
*
|
||||
* @param array|null $response
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function packetResponse(array $response = null)
|
||||
{
|
||||
|
||||
// Act as setter
|
||||
if (!empty($response)) {
|
||||
$this->packets_response = $response;
|
||||
}
|
||||
|
||||
return $this->packets_response;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Challenge section
|
||||
*/
|
||||
|
||||
/**
|
||||
* Determine whether or not this protocol has a challenge needed before querying
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function hasChallenge()
|
||||
{
|
||||
|
||||
return (isset($this->packets[self::PACKET_CHALLENGE]) && !empty($this->packets[self::PACKET_CHALLENGE]));
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the challenge response and add it to the buffer items that need it.
|
||||
* This should be overloaded by extending class
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
|
||||
*
|
||||
* @param \GameQ\Buffer $challenge_buffer
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function challengeParseAndApply(Buffer $challenge_buffer)
|
||||
{
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply the challenge string to all the packets that need it.
|
||||
*
|
||||
* @param string $challenge_string
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function challengeApply($challenge_string)
|
||||
{
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the normalize settings for the protocol
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getNormalize()
|
||||
{
|
||||
|
||||
return $this->normalize;
|
||||
}
|
||||
|
||||
/*
|
||||
* General
|
||||
*/
|
||||
|
||||
/**
|
||||
* Generic method to allow protocol classes to do work right before the query is sent
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
|
||||
*
|
||||
* @param \GameQ\Server $server
|
||||
*/
|
||||
public function beforeSend(Server $server)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Method called to process query response data. Each extending class has to have one of these functions.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
abstract public function processResponse();
|
||||
}
|
53
GameQ/Protocols/Aa3.php
Normal file
53
GameQ/Protocols/Aa3.php
Normal file
|
@ -0,0 +1,53 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is part of GameQ.
|
||||
*
|
||||
* GameQ is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GameQ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace GameQ\Protocols;
|
||||
|
||||
/**
|
||||
* Class Aa3
|
||||
*
|
||||
* @package GameQ\Protocols
|
||||
* @author Austin Bischoff <austin@codebeard.com>
|
||||
*/
|
||||
class Aa3 extends Source
|
||||
{
|
||||
|
||||
/**
|
||||
* String name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name = 'aa3';
|
||||
|
||||
/**
|
||||
* Longer string name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name_long = "America's Army 3";
|
||||
|
||||
/**
|
||||
* Query port = client_port + 18243
|
||||
*
|
||||
* client_port default 8777
|
||||
* query_port default 27020
|
||||
*
|
||||
* @type int
|
||||
*/
|
||||
protected $port_diff = 18243;
|
||||
}
|
42
GameQ/Protocols/Aapg.php
Normal file
42
GameQ/Protocols/Aapg.php
Normal file
|
@ -0,0 +1,42 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is part of GameQ.
|
||||
*
|
||||
* GameQ is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GameQ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace GameQ\Protocols;
|
||||
|
||||
/**
|
||||
* Class Aapg
|
||||
*
|
||||
* @package GameQ\Protocols
|
||||
* @author Austin Bischoff <austin@codebeard.com>
|
||||
*/
|
||||
class Aapg extends Aa3
|
||||
{
|
||||
/**
|
||||
* String name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name = 'aapg';
|
||||
|
||||
/**
|
||||
* Longer string name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name_long = "America's Army: Proving Grounds";
|
||||
}
|
51
GameQ/Protocols/Arkse.php
Normal file
51
GameQ/Protocols/Arkse.php
Normal file
|
@ -0,0 +1,51 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is part of GameQ.
|
||||
*
|
||||
* GameQ is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GameQ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace GameQ\Protocols;
|
||||
|
||||
/**
|
||||
* Class ARK: Survival Evolved
|
||||
*
|
||||
* @package GameQ\Protocols
|
||||
* @author Austin Bischoff <austin@codebeard.com>
|
||||
*/
|
||||
class Arkse extends Source
|
||||
{
|
||||
|
||||
/**
|
||||
* String name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name = 'arkse';
|
||||
|
||||
/**
|
||||
* Longer string name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name_long = "ARK: Survival Evolved";
|
||||
|
||||
/**
|
||||
* query_port = client_port + 19238
|
||||
* 27015 = 7777 + 19238
|
||||
*
|
||||
* @type int
|
||||
*/
|
||||
protected $port_diff = 19238;
|
||||
}
|
43
GameQ/Protocols/Arma.php
Normal file
43
GameQ/Protocols/Arma.php
Normal file
|
@ -0,0 +1,43 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is part of GameQ.
|
||||
*
|
||||
* GameQ is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GameQ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace GameQ\Protocols;
|
||||
|
||||
/**
|
||||
* Class Arma
|
||||
*
|
||||
* @package GameQ\Protocols
|
||||
*
|
||||
* @author Wilson Jesus <>
|
||||
*/
|
||||
class Arma extends Gamespy2
|
||||
{
|
||||
/**
|
||||
* String name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name = 'arma';
|
||||
|
||||
/**
|
||||
* Longer string name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name_long = "ArmA Armed Assault";
|
||||
}
|
181
GameQ/Protocols/Arma3.php
Normal file
181
GameQ/Protocols/Arma3.php
Normal file
|
@ -0,0 +1,181 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is part of GameQ.
|
||||
*
|
||||
* GameQ is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GameQ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace GameQ\Protocols;
|
||||
|
||||
use GameQ\Buffer;
|
||||
use GameQ\Result;
|
||||
|
||||
/**
|
||||
* Class Armed Assault 3
|
||||
*
|
||||
* Rules protocol reference: https://community.bistudio.com/wiki/Arma_3_ServerBrowserProtocol2
|
||||
*
|
||||
* @package GameQ\Protocols
|
||||
* @author Austin Bischoff <austin@codebeard.com>
|
||||
* @author Memphis017 <https://github.com/Memphis017>
|
||||
*/
|
||||
class Arma3 extends Source
|
||||
{
|
||||
/**
|
||||
* Defines the names for the specific game DLCs
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $dlcNames = [
|
||||
'af82811b' => 'Karts',
|
||||
'94f76a1a' => 'Marksmen',
|
||||
'd0356eec' => 'Helicopters',
|
||||
'19984a71' => 'Zeus',
|
||||
'7fb4b1f3' => 'Apex',
|
||||
'49c2c12b' => 'Jets',
|
||||
'7e766e18' => 'Laws of War',
|
||||
'99d71f90' => 'Malden',
|
||||
'a8b10cdf' => 'Tac-Ops',
|
||||
'37680ce8' => 'Tanks',
|
||||
'43f9c377' => 'Contact',
|
||||
'c4979557' => 'Enoch',
|
||||
];
|
||||
|
||||
/**
|
||||
* String name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name = 'arma3';
|
||||
|
||||
/**
|
||||
* Longer string name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name_long = "Arma3";
|
||||
|
||||
/**
|
||||
* Query port = client_port + 1
|
||||
*
|
||||
* @type int
|
||||
*/
|
||||
protected $port_diff = 1;
|
||||
|
||||
/**
|
||||
* Process the rules since Arma3 changed their response for rules
|
||||
*
|
||||
* @param Buffer $buffer
|
||||
*
|
||||
* @return array
|
||||
* @throws \GameQ\Exception\Protocol
|
||||
*/
|
||||
protected function processRules(Buffer $buffer)
|
||||
{
|
||||
// Total number of packets, burn it
|
||||
$buffer->readInt16();
|
||||
|
||||
// Will hold the data string
|
||||
$data = '';
|
||||
|
||||
// Loop until we run out of strings
|
||||
while ($buffer->getLength()) {
|
||||
// Burn the delimiters (i.e. \x01\x04\x00)
|
||||
$buffer->readString();
|
||||
|
||||
// Add the data to the string, we are reassembling it
|
||||
$data .= $buffer->readString();
|
||||
}
|
||||
|
||||
// Restore escaped sequences
|
||||
$data = str_replace(["\x01\x01", "\x01\x02", "\x01\x03"], ["\x01", "\x00", "\xFF"], $data);
|
||||
|
||||
// Make a new buffer with the reassembled data
|
||||
$responseBuffer = new Buffer($data);
|
||||
|
||||
// Kill the old buffer, should be empty
|
||||
unset($buffer, $data);
|
||||
|
||||
// Set the result to a new result instance
|
||||
$result = new Result();
|
||||
|
||||
// Get results
|
||||
$result->add('rules_protocol_version', $responseBuffer->readInt8());
|
||||
$result->add('overflow', $responseBuffer->readInt8());
|
||||
$dlcBit = decbin($responseBuffer->readInt8()); // Grab DLC bit 1 and use it later
|
||||
$dlcBit2 = decbin($responseBuffer->readInt8()); // Grab DLC bit 2 and use it later
|
||||
$dlcCount = substr_count($dlcBit, '1') + substr_count($dlcBit2, '1'); // Count the DLCs
|
||||
|
||||
// Grab difficulty so we can man handle it...
|
||||
$difficulty = $responseBuffer->readInt8();
|
||||
|
||||
// Process difficulty
|
||||
$result->add('3rd_person', $difficulty >> 7);
|
||||
$result->add('advanced_flight_mode', ($difficulty >> 6) & 1);
|
||||
$result->add('difficulty_ai', ($difficulty >> 3) & 3);
|
||||
$result->add('difficulty_level', $difficulty & 3);
|
||||
|
||||
unset($difficulty);
|
||||
|
||||
// Crosshair
|
||||
$result->add('crosshair', $responseBuffer->readInt8());
|
||||
|
||||
// Loop over the DLC bit so we can pull in the info for the DLC (if enabled)
|
||||
for ($x = 0; $x < $dlcCount; $x++) {
|
||||
$dlcHash = dechex($responseBuffer->readInt32());
|
||||
isset($this->dlcNames[$dlcHash]) ?
|
||||
$result->addSub('dlcs', 'name', $this->dlcNames[$dlcHash])
|
||||
: $result->addSub('dlcs', 'name', 'Unknown');
|
||||
$result->addSub('dlcs', 'hash', $dlcHash);
|
||||
}
|
||||
|
||||
// No longer needed
|
||||
unset($dlcBit, $dlcBit2, $dlcCount, $dlcHash);
|
||||
|
||||
// Grab the mod count
|
||||
$modCount = $responseBuffer->readInt8();
|
||||
|
||||
// Add mod count
|
||||
$result->add('mod_count', $modCount);
|
||||
|
||||
// Loop the mod count and add them
|
||||
for ($x = 0; $x < $modCount; $x++) {
|
||||
// Add the mod to the list
|
||||
$result->addSub('mods', 'hash', dechex($responseBuffer->readInt32()));
|
||||
$result->addSub('mods', 'steam_id', hexdec($responseBuffer->readPascalString(0, true)));
|
||||
$result->addSub('mods', 'name', $responseBuffer->readPascalString(0, true));
|
||||
}
|
||||
|
||||
unset($modCount, $x);
|
||||
|
||||
// Get the signatures count
|
||||
$signatureCount = $responseBuffer->readInt8();
|
||||
$result->add('signature_count', $signatureCount);
|
||||
|
||||
// Make signatures array
|
||||
$signatures = [];
|
||||
|
||||
// Loop until we run out of signatures
|
||||
for ($x = 0; $x < $signatureCount; $x++) {
|
||||
$signatures[] = $responseBuffer->readPascalString(0, true);
|
||||
}
|
||||
|
||||
// Add as a simple array
|
||||
$result->add('signatures', $signatures);
|
||||
|
||||
unset($responseBuffer, $signatureCount, $signatures, $x);
|
||||
|
||||
return $result->fetch();
|
||||
}
|
||||
}
|
50
GameQ/Protocols/Armedassault2oa.php
Normal file
50
GameQ/Protocols/Armedassault2oa.php
Normal file
|
@ -0,0 +1,50 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is part of GameQ.
|
||||
*
|
||||
* GameQ is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GameQ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace GameQ\Protocols;
|
||||
|
||||
/**
|
||||
* Class Armedassault2oa
|
||||
*
|
||||
* @package GameQ\Protocols
|
||||
* @author Austin Bischoff <austin@codebeard.com>
|
||||
*/
|
||||
class Armedassault2oa extends Source
|
||||
{
|
||||
|
||||
/**
|
||||
* String name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name = "armedassault2oa";
|
||||
|
||||
/**
|
||||
* Longer string name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name_long = "Armed Assault 2: Operation Arrowhead";
|
||||
|
||||
/**
|
||||
* Query port = client_port + 1
|
||||
*
|
||||
* @type int
|
||||
*/
|
||||
protected $port_diff = 1;
|
||||
}
|
32
GameQ/Protocols/Armedassault3.php
Normal file
32
GameQ/Protocols/Armedassault3.php
Normal file
|
@ -0,0 +1,32 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is part of GameQ.
|
||||
*
|
||||
* GameQ is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GameQ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace GameQ\Protocols;
|
||||
|
||||
/**
|
||||
* Armed assault 3 dummy Protocol Class
|
||||
*
|
||||
* Added for backward compatibility, please update to class arma3
|
||||
*
|
||||
* @deprecated v3.0.10
|
||||
* @package GameQ\Protocols
|
||||
* @author Austin Bischoff <austin@codebeard.com>
|
||||
*/
|
||||
class Armedassault3 extends Arma3
|
||||
{
|
||||
}
|
208
GameQ/Protocols/Ase.php
Normal file
208
GameQ/Protocols/Ase.php
Normal file
|
@ -0,0 +1,208 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is part of GameQ.
|
||||
*
|
||||
* GameQ is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GameQ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace GameQ\Protocols;
|
||||
|
||||
use GameQ\Protocol;
|
||||
use GameQ\Buffer;
|
||||
use GameQ\Result;
|
||||
|
||||
/**
|
||||
* All-Seeing Eye Protocol class
|
||||
*
|
||||
* @author Marcel Bößendörfer <m.boessendoerfer@marbis.net>
|
||||
* @author Austin Bischoff <austin@codebeard.com>
|
||||
*/
|
||||
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
|
||||
*
|
||||
* @type array
|
||||
*/
|
||||
protected $packets = [
|
||||
self::PACKET_ALL => "s",
|
||||
];
|
||||
|
||||
/**
|
||||
* The query protocol used to make the call
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $protocol = 'ase';
|
||||
|
||||
/**
|
||||
* String name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name = 'ase';
|
||||
|
||||
/**
|
||||
* Longer string name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name_long = "All-Seeing Eye";
|
||||
|
||||
/**
|
||||
* The client join link
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $join_link = null;
|
||||
|
||||
/**
|
||||
* Normalize settings for this protocol
|
||||
*
|
||||
* @type array
|
||||
*/
|
||||
protected $normalize = [
|
||||
// General
|
||||
'general' => [
|
||||
// target => source
|
||||
'dedicated' => 'dedicated',
|
||||
'gametype' => 'gametype',
|
||||
'hostname' => 'servername',
|
||||
'mapname' => 'map',
|
||||
'maxplayers' => 'max_players',
|
||||
'mod' => 'game_dir',
|
||||
'numplayers' => 'num_players',
|
||||
'password' => 'password',
|
||||
],
|
||||
// Individual
|
||||
'player' => [
|
||||
'name' => 'name',
|
||||
'score' => 'score',
|
||||
'team' => 'team',
|
||||
'ping' => 'ping',
|
||||
'time' => 'time',
|
||||
],
|
||||
];
|
||||
|
||||
/**
|
||||
* Process the response
|
||||
*
|
||||
* @return array
|
||||
* @throws \GameQ\Exception\Protocol
|
||||
*/
|
||||
public function processResponse()
|
||||
{
|
||||
|
||||
// Create a new buffer
|
||||
$buffer = new Buffer(implode('', $this->packets_response));
|
||||
|
||||
// Burn the header
|
||||
$buffer->skip(4);
|
||||
|
||||
// Create a new result
|
||||
$result = new Result();
|
||||
|
||||
// Variables
|
||||
$result->add('gamename', $buffer->readPascalString(1, true));
|
||||
$result->add('port', $buffer->readPascalString(1, true));
|
||||
$result->add('servername', $buffer->readPascalString(1, true));
|
||||
$result->add('gametype', $buffer->readPascalString(1, true));
|
||||
$result->add('map', $buffer->readPascalString(1, true));
|
||||
$result->add('version', $buffer->readPascalString(1, true));
|
||||
$result->add('password', $buffer->readPascalString(1, true));
|
||||
$result->add('num_players', $buffer->readPascalString(1, true));
|
||||
$result->add('max_players', $buffer->readPascalString(1, true));
|
||||
$result->add('dedicated', 1);
|
||||
|
||||
// Offload the key/value pair processing
|
||||
$this->processKeyValuePairs($buffer, $result);
|
||||
|
||||
// Offload processing player and team info
|
||||
$this->processPlayersAndTeams($buffer, $result);
|
||||
|
||||
unset($buffer);
|
||||
|
||||
return $result->fetch();
|
||||
}
|
||||
|
||||
/*
|
||||
* Internal methods
|
||||
*/
|
||||
|
||||
/**
|
||||
* Handles processing the extra key/value pairs for server settings
|
||||
*
|
||||
* @param \GameQ\Buffer $buffer
|
||||
* @param \GameQ\Result $result
|
||||
*/
|
||||
protected function processKeyValuePairs(Buffer &$buffer, Result &$result)
|
||||
{
|
||||
|
||||
// Key / value pairs
|
||||
while ($buffer->getLength()) {
|
||||
$key = $buffer->readPascalString(1, true);
|
||||
|
||||
// If we have an empty key, we've reached the end
|
||||
if (empty($key)) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Otherwise, add the pair
|
||||
$result->add(
|
||||
$key,
|
||||
$buffer->readPascalString(1, true)
|
||||
);
|
||||
}
|
||||
|
||||
unset($key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles processing the player and team data into a usable format
|
||||
*
|
||||
* @param \GameQ\Buffer $buffer
|
||||
* @param \GameQ\Result $result
|
||||
*/
|
||||
protected function processPlayersAndTeams(Buffer &$buffer, Result &$result)
|
||||
{
|
||||
|
||||
// Players and team info
|
||||
while ($buffer->getLength()) {
|
||||
// Get the flags
|
||||
$flags = $buffer->readInt8();
|
||||
|
||||
// Get data according to the flags
|
||||
if ($flags & 1) {
|
||||
$result->addPlayer('name', $buffer->readPascalString(1, true));
|
||||
}
|
||||
if ($flags & 2) {
|
||||
$result->addPlayer('team', $buffer->readPascalString(1, true));
|
||||
}
|
||||
if ($flags & 4) {
|
||||
$result->addPlayer('skin', $buffer->readPascalString(1, true));
|
||||
}
|
||||
if ($flags & 8) {
|
||||
$result->addPlayer('score', $buffer->readPascalString(1, true));
|
||||
}
|
||||
if ($flags & 16) {
|
||||
$result->addPlayer('ping', $buffer->readPascalString(1, true));
|
||||
}
|
||||
if ($flags & 32) {
|
||||
$result->addPlayer('time', $buffer->readPascalString(1, true));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
55
GameQ/Protocols/Atlas.php
Normal file
55
GameQ/Protocols/Atlas.php
Normal file
|
@ -0,0 +1,55 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is part of GameQ.
|
||||
*
|
||||
* GameQ is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GameQ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace GameQ\Protocols;
|
||||
|
||||
/**
|
||||
* Class Atlas
|
||||
*
|
||||
* @package GameQ\Protocols
|
||||
* @author Wilson Jesus <>
|
||||
*/
|
||||
class Atlas extends Source
|
||||
{
|
||||
|
||||
/**
|
||||
* String name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name = 'atlas';
|
||||
|
||||
/**
|
||||
* Longer string name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name_long = "Atlas";
|
||||
|
||||
/**
|
||||
* query_port = client_port + 51800
|
||||
* 57561 = 5761 + 51800
|
||||
*
|
||||
* this is the default value for the stock game server, both ports
|
||||
* can be independently changed from the stock ones,
|
||||
* making the port_diff logic useless.
|
||||
*
|
||||
* @type int
|
||||
*/
|
||||
protected $port_diff = 51800;
|
||||
}
|
68
GameQ/Protocols/Batt1944.php
Normal file
68
GameQ/Protocols/Batt1944.php
Normal file
|
@ -0,0 +1,68 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is part of GameQ.
|
||||
*
|
||||
* GameQ is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GameQ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace GameQ\Protocols;
|
||||
|
||||
/**
|
||||
* Class Battalion 1944
|
||||
*
|
||||
* @package GameQ\Protocols
|
||||
* @author TacTicToe66 <https://github.com/TacTicToe66>
|
||||
*/
|
||||
class Batt1944 extends Source
|
||||
{
|
||||
|
||||
/**
|
||||
* String name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name = 'batt1944';
|
||||
|
||||
/**
|
||||
* Longer string name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name_long = "Battalion 1944";
|
||||
|
||||
/**
|
||||
* query_port = client_port + 3
|
||||
*
|
||||
* @type int
|
||||
*/
|
||||
protected $port_diff = 3;
|
||||
|
||||
/**
|
||||
* Normalize main fields
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $normalize = [
|
||||
// General
|
||||
'general' => [
|
||||
// target => source
|
||||
'gametype' => 'bat_gamemode_s',
|
||||
'hostname' => 'bat_name_s',
|
||||
'mapname' => 'bat_map_s',
|
||||
'maxplayers' => 'bat_max_players_i',
|
||||
'numplayers' => 'bat_player_count_s',
|
||||
'password' => 'bat_has_password_s',
|
||||
],
|
||||
];
|
||||
}
|
88
GameQ/Protocols/Bf1942.php
Normal file
88
GameQ/Protocols/Bf1942.php
Normal file
|
@ -0,0 +1,88 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is part of GameQ.
|
||||
*
|
||||
* GameQ is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GameQ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace GameQ\Protocols;
|
||||
|
||||
/**
|
||||
* Class Battlefield 1942
|
||||
*
|
||||
* @package GameQ\Protocols
|
||||
* @author Austin Bischoff <austin@codebeard.com>
|
||||
*/
|
||||
class Bf1942 extends Gamespy
|
||||
{
|
||||
|
||||
/**
|
||||
* String name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name = 'bf1942';
|
||||
|
||||
/**
|
||||
* Longer string name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name_long = "Battlefield 1942";
|
||||
|
||||
/**
|
||||
* query_port = client_port + 8433
|
||||
* 23000 = 14567 + 8433
|
||||
*
|
||||
* @type int
|
||||
*/
|
||||
protected $port_diff = 8433;
|
||||
|
||||
/**
|
||||
* The client join link
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $join_link = "bf1942://%s:%d";
|
||||
|
||||
/**
|
||||
* Normalize settings for this protocol
|
||||
*
|
||||
* @type array
|
||||
*/
|
||||
protected $normalize = [
|
||||
// General
|
||||
'general' => [
|
||||
// target => source
|
||||
'dedicated' => 'dedicated',
|
||||
'gametype' => 'gametype',
|
||||
'hostname' => 'hostname',
|
||||
'mapname' => 'mapname',
|
||||
'maxplayers' => 'maxplayers',
|
||||
'numplayers' => 'numplayers',
|
||||
'password' => 'password',
|
||||
],
|
||||
// Individual
|
||||
'player' => [
|
||||
'name' => 'playername',
|
||||
'kills' => 'kills',
|
||||
'deaths' => 'deaths',
|
||||
'ping' => 'ping',
|
||||
'score' => 'score',
|
||||
],
|
||||
'team' => [
|
||||
'name' => 'teamname',
|
||||
],
|
||||
];
|
||||
}
|
98
GameQ/Protocols/Bf2.php
Normal file
98
GameQ/Protocols/Bf2.php
Normal file
|
@ -0,0 +1,98 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is part of GameQ.
|
||||
*
|
||||
* GameQ is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GameQ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace GameQ\Protocols;
|
||||
|
||||
/**
|
||||
* Class Battlefield 2
|
||||
*
|
||||
* @package GameQ\Protocols
|
||||
* @author Austin Bischoff <austin@codebeard.com>
|
||||
*/
|
||||
class Bf2 extends Gamespy3
|
||||
{
|
||||
|
||||
/**
|
||||
* String name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name = 'bf2';
|
||||
|
||||
/**
|
||||
* Longer string name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name_long = "Battlefield 2";
|
||||
|
||||
/**
|
||||
* query_port = client_port + 8433
|
||||
* 29900 = 16567 + 13333
|
||||
*
|
||||
* @type int
|
||||
*/
|
||||
protected $port_diff = 13333;
|
||||
|
||||
/**
|
||||
* The client join link
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $join_link = "bf2://%s:%d";
|
||||
|
||||
/**
|
||||
* BF2 has a different query packet to send than "normal" Gamespy 3
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $packets = [
|
||||
self::PACKET_ALL => "\xFE\xFD\x00\x10\x20\x30\x40\xFF\xFF\xFF\x01",
|
||||
];
|
||||
|
||||
/**
|
||||
* Normalize settings for this protocol
|
||||
*
|
||||
* @type array
|
||||
*/
|
||||
protected $normalize = [
|
||||
// General
|
||||
'general' => [
|
||||
// target => source
|
||||
'dedicated' => 'dedicated',
|
||||
'gametype' => 'gametype',
|
||||
'hostname' => 'hostname',
|
||||
'mapname' => 'mapname',
|
||||
'maxplayers' => 'maxplayers',
|
||||
'numplayers' => 'numplayers',
|
||||
'password' => 'password',
|
||||
],
|
||||
// Individual
|
||||
'player' => [
|
||||
'name' => 'player',
|
||||
'kills' => 'score',
|
||||
'deaths' => 'deaths',
|
||||
'ping' => 'ping',
|
||||
'score' => 'score',
|
||||
],
|
||||
'team' => [
|
||||
'name' => 'team',
|
||||
'score' => 'score',
|
||||
],
|
||||
];
|
||||
}
|
348
GameQ/Protocols/Bf3.php
Normal file
348
GameQ/Protocols/Bf3.php
Normal file
|
@ -0,0 +1,348 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is part of GameQ.
|
||||
*
|
||||
* GameQ is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GameQ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace GameQ\Protocols;
|
||||
|
||||
use GameQ\Protocol;
|
||||
use GameQ\Buffer;
|
||||
use GameQ\Result;
|
||||
use GameQ\Exception\Protocol as Exception;
|
||||
|
||||
/**
|
||||
* Battlefield 3 Protocol Class
|
||||
*
|
||||
* Good place for doc status and info is http://www.fpsadmin.com/forum/showthread.php?t=24134
|
||||
*
|
||||
* @package GameQ\Protocols
|
||||
* @author Austin Bischoff <austin@codebeard.com>
|
||||
*/
|
||||
class Bf3 extends Protocol
|
||||
{
|
||||
|
||||
/**
|
||||
* Array of packets we want to query.
|
||||
*
|
||||
* @type array
|
||||
*/
|
||||
protected $packets = [
|
||||
self::PACKET_STATUS => "\x00\x00\x00\x21\x1b\x00\x00\x00\x01\x00\x00\x00\x0a\x00\x00\x00serverInfo\x00",
|
||||
self::PACKET_VERSION => "\x00\x00\x00\x22\x18\x00\x00\x00\x01\x00\x00\x00\x07\x00\x00\x00version\x00",
|
||||
self::PACKET_PLAYERS =>
|
||||
"\x00\x00\x00\x23\x24\x00\x00\x00\x02\x00\x00\x00\x0b\x00\x00\x00listPlayers\x00\x03\x00\x00\x00\x61ll\x00",
|
||||
];
|
||||
|
||||
/**
|
||||
* Use the response flag to figure out what method to run
|
||||
*
|
||||
* @type array
|
||||
*/
|
||||
protected $responses = [
|
||||
1627389952 => "processDetails", // a
|
||||
1644167168 => "processVersion", // b
|
||||
1660944384 => "processPlayers", // c
|
||||
];
|
||||
|
||||
/**
|
||||
* The transport mode for this protocol is TCP
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $transport = self::TRANSPORT_TCP;
|
||||
|
||||
/**
|
||||
* The query protocol used to make the call
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $protocol = 'bf3';
|
||||
|
||||
/**
|
||||
* String name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name = 'bf3';
|
||||
|
||||
/**
|
||||
* Longer string name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name_long = "Battlefield 3";
|
||||
|
||||
/**
|
||||
* The client join link
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $join_link = null;
|
||||
|
||||
/**
|
||||
* query_port = client_port + 22000
|
||||
* 47200 = 25200 + 22000
|
||||
*
|
||||
* @type int
|
||||
*/
|
||||
protected $port_diff = 22000;
|
||||
|
||||
/**
|
||||
* Normalize settings for this protocol
|
||||
*
|
||||
* @type array
|
||||
*/
|
||||
protected $normalize = [
|
||||
// General
|
||||
'general' => [
|
||||
// target => source
|
||||
'dedicated' => 'dedicated',
|
||||
'hostname' => 'hostname',
|
||||
'mapname' => 'map',
|
||||
'maxplayers' => 'max_players',
|
||||
'numplayers' => 'num_players',
|
||||
'password' => 'password',
|
||||
],
|
||||
'player' => [
|
||||
'name' => 'name',
|
||||
'score' => 'score',
|
||||
'ping' => 'ping',
|
||||
],
|
||||
'team' => [
|
||||
'score' => 'tickets',
|
||||
],
|
||||
];
|
||||
|
||||
/**
|
||||
* Process the response for the StarMade server
|
||||
*
|
||||
* @return array
|
||||
* @throws \GameQ\Exception\Protocol
|
||||
*/
|
||||
public function processResponse()
|
||||
{
|
||||
|
||||
// Holds the results sent back
|
||||
$results = [];
|
||||
|
||||
// Holds the processed packets after having been reassembled
|
||||
$processed = [];
|
||||
|
||||
// Start up the index for the processed
|
||||
$sequence_id_last = 0;
|
||||
|
||||
foreach ($this->packets_response as $packet) {
|
||||
// Create a new buffer
|
||||
$buffer = new Buffer($packet);
|
||||
|
||||
// Each "good" packet begins with sequence_id (32-bit)
|
||||
$sequence_id = $buffer->readInt32();
|
||||
|
||||
// Sequence id is a response
|
||||
if (array_key_exists($sequence_id, $this->responses)) {
|
||||
$processed[$sequence_id] = $buffer->getBuffer();
|
||||
$sequence_id_last = $sequence_id;
|
||||
} else {
|
||||
// This is a continuation of the previous packet, reset the buffer and append
|
||||
$buffer->jumpto(0);
|
||||
|
||||
// Append
|
||||
$processed[$sequence_id_last] .= $buffer->getBuffer();
|
||||
}
|
||||
}
|
||||
|
||||
unset($buffer, $sequence_id_last, $sequence_id);
|
||||
|
||||
// Iterate over the combined packets and do some work
|
||||
foreach ($processed as $sequence_id => $data) {
|
||||
// Create a new buffer
|
||||
$buffer = new Buffer($data);
|
||||
|
||||
// Get the length of the packet
|
||||
$packetLength = $buffer->getLength();
|
||||
|
||||
// Check to make sure the expected length matches the real length
|
||||
// Subtract 4 for the sequence_id pulled out earlier
|
||||
if ($packetLength != ($buffer->readInt32() - 4)) {
|
||||
throw new Exception(__METHOD__ . " packet length does not match expected length!");
|
||||
}
|
||||
|
||||
// Now we need to call the proper method
|
||||
$results = array_merge(
|
||||
$results,
|
||||
call_user_func_array([$this, $this->responses[$sequence_id]], [$buffer])
|
||||
);
|
||||
}
|
||||
|
||||
return $results;
|
||||
}
|
||||
|
||||
/*
|
||||
* Internal Methods
|
||||
*/
|
||||
|
||||
/**
|
||||
* Decode the buffer into a usable format
|
||||
*
|
||||
* @param \GameQ\Buffer $buffer
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function decode(Buffer $buffer)
|
||||
{
|
||||
|
||||
$items = [];
|
||||
|
||||
// Get the number of words in this buffer
|
||||
$itemCount = $buffer->readInt32();
|
||||
|
||||
// Loop over the number of items
|
||||
for ($i = 0; $i < $itemCount; $i++) {
|
||||
// Length of the string
|
||||
$buffer->readInt32();
|
||||
|
||||
// Just read the string
|
||||
$items[$i] = $buffer->readString();
|
||||
}
|
||||
|
||||
return $items;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the server details
|
||||
*
|
||||
* @param \GameQ\Buffer $buffer
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function processDetails(Buffer $buffer)
|
||||
{
|
||||
|
||||
// Decode into items
|
||||
$items = $this->decode($buffer);
|
||||
|
||||
// Set the result to a new result instance
|
||||
$result = new Result();
|
||||
|
||||
// Server is always dedicated
|
||||
$result->add('dedicated', 1);
|
||||
|
||||
// These are the same no matter what mode the server is in
|
||||
$result->add('hostname', $items[1]);
|
||||
$result->add('num_players', (int)$items[2]);
|
||||
$result->add('max_players', (int)$items[3]);
|
||||
$result->add('gametype', $items[4]);
|
||||
$result->add('map', $items[5]);
|
||||
$result->add('roundsplayed', (int)$items[6]);
|
||||
$result->add('roundstotal', (int)$items[7]);
|
||||
$result->add('num_teams', (int)$items[8]);
|
||||
|
||||
// Set the current index
|
||||
$index_current = 9;
|
||||
|
||||
// Pull the team count
|
||||
$teamCount = $result->get('num_teams');
|
||||
|
||||
// Loop for the number of teams found, increment along the way
|
||||
for ($id = 1; $id <= $teamCount; $id++, $index_current++) {
|
||||
// Shows the tickets
|
||||
$result->addTeam('tickets', $items[$index_current]);
|
||||
// We add an id so we know which team this is
|
||||
$result->addTeam('id', $id);
|
||||
}
|
||||
|
||||
// Get and set the rest of the data points.
|
||||
$result->add('targetscore', (int)$items[$index_current]);
|
||||
$result->add('online', 1); // Forced true, it seems $words[$index_current + 1] is always empty
|
||||
$result->add('ranked', (int)$items[$index_current + 2]);
|
||||
$result->add('punkbuster', (int)$items[$index_current + 3]);
|
||||
$result->add('password', (int)$items[$index_current + 4]);
|
||||
$result->add('uptime', (int)$items[$index_current + 5]);
|
||||
$result->add('roundtime', (int)$items[$index_current + 6]);
|
||||
// Added in R9
|
||||
$result->add('ip_port', $items[$index_current + 7]);
|
||||
$result->add('punkbuster_version', $items[$index_current + 8]);
|
||||
$result->add('join_queue', (int)$items[$index_current + 9]);
|
||||
$result->add('region', $items[$index_current + 10]);
|
||||
$result->add('pingsite', $items[$index_current + 11]);
|
||||
$result->add('country', $items[$index_current + 12]);
|
||||
// Added in R29, No docs as of yet
|
||||
$result->add('quickmatch', (int)$items[$index_current + 13]); // Guessed from research
|
||||
|
||||
unset($items, $index_current, $teamCount, $buffer);
|
||||
|
||||
return $result->fetch();
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the server version
|
||||
*
|
||||
* @param \GameQ\Buffer $buffer
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function processVersion(Buffer $buffer)
|
||||
{
|
||||
|
||||
// Decode into items
|
||||
$items = $this->decode($buffer);
|
||||
|
||||
// Set the result to a new result instance
|
||||
$result = new Result();
|
||||
|
||||
$result->add('version', $items[2]);
|
||||
|
||||
unset($buffer, $items);
|
||||
|
||||
return $result->fetch();
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the players
|
||||
*
|
||||
* @param \GameQ\Buffer $buffer
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function processPlayers(Buffer $buffer)
|
||||
{
|
||||
|
||||
// Decode into items
|
||||
$items = $this->decode($buffer);
|
||||
|
||||
// Set the result to a new result instance
|
||||
$result = new Result();
|
||||
|
||||
// Number of data points per player
|
||||
$numTags = $items[1];
|
||||
|
||||
// Grab the tags for each player
|
||||
$tags = array_slice($items, 2, $numTags);
|
||||
|
||||
// Get the player count
|
||||
$playerCount = $items[$numTags + 2];
|
||||
|
||||
// Iterate over the index until we run out of players
|
||||
for ($i = 0, $x = $numTags + 3; $i < $playerCount; $i++, $x += $numTags) {
|
||||
// Loop over the player tags and extract the info for that tag
|
||||
foreach ($tags as $index => $tag) {
|
||||
$result->addPlayer($tag, $items[($x + $index)]);
|
||||
}
|
||||
}
|
||||
|
||||
return $result->fetch();
|
||||
}
|
||||
}
|
114
GameQ/Protocols/Bf4.php
Normal file
114
GameQ/Protocols/Bf4.php
Normal file
|
@ -0,0 +1,114 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is part of GameQ.
|
||||
*
|
||||
* GameQ is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GameQ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace GameQ\Protocols;
|
||||
|
||||
use GameQ\Buffer;
|
||||
use GameQ\Result;
|
||||
|
||||
/**
|
||||
* Battlefield 4 Protocol class
|
||||
*
|
||||
* Good place for doc status and info is http://battlelog.battlefield.com/bf4/forum/view/2955064768683911198/
|
||||
*
|
||||
* @package GameQ\Protocols
|
||||
* @author Austin Bischoff <austin@codebeard.com>
|
||||
*/
|
||||
class Bf4 extends Bf3
|
||||
{
|
||||
|
||||
/**
|
||||
* String name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name = 'bf4';
|
||||
|
||||
/**
|
||||
* Longer string name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name_long = "Battlefield 4";
|
||||
|
||||
/**
|
||||
* Handle processing details since they are different than BF3
|
||||
*
|
||||
* @param \GameQ\Buffer $buffer
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function processDetails(Buffer $buffer)
|
||||
{
|
||||
|
||||
// Decode into items
|
||||
$items = $this->decode($buffer);
|
||||
|
||||
// Set the result to a new result instance
|
||||
$result = new Result();
|
||||
|
||||
// Server is always dedicated
|
||||
$result->add('dedicated', 1);
|
||||
|
||||
// These are the same no matter what mode the server is in
|
||||
$result->add('hostname', $items[1]);
|
||||
$result->add('num_players', (int) $items[2]);
|
||||
$result->add('max_players', (int) $items[3]);
|
||||
$result->add('gametype', $items[4]);
|
||||
$result->add('map', $items[5]);
|
||||
$result->add('roundsplayed', (int) $items[6]);
|
||||
$result->add('roundstotal', (int) $items[7]);
|
||||
$result->add('num_teams', (int) $items[8]);
|
||||
|
||||
// Set the current index
|
||||
$index_current = 9;
|
||||
|
||||
// Pull the team count
|
||||
$teamCount = $result->get('num_teams');
|
||||
|
||||
// Loop for the number of teams found, increment along the way
|
||||
for ($id = 1; $id <= $teamCount; $id++, $index_current++) {
|
||||
// Shows the tickets
|
||||
$result->addTeam('tickets', $items[$index_current]);
|
||||
// We add an id so we know which team this is
|
||||
$result->addTeam('id', $id);
|
||||
}
|
||||
|
||||
// Get and set the rest of the data points.
|
||||
$result->add('targetscore', (int) $items[$index_current]);
|
||||
$result->add('online', 1); // Forced true, it seems $words[$index_current + 1] is always empty
|
||||
$result->add('ranked', (int) $items[$index_current + 2]);
|
||||
$result->add('punkbuster', (int) $items[$index_current + 3]);
|
||||
$result->add('password', (int) $items[$index_current + 4]);
|
||||
$result->add('uptime', (int) $items[$index_current + 5]);
|
||||
$result->add('roundtime', (int) $items[$index_current + 6]);
|
||||
$result->add('ip_port', $items[$index_current + 7]);
|
||||
$result->add('punkbuster_version', $items[$index_current + 8]);
|
||||
$result->add('join_queue', (int) $items[$index_current + 9]);
|
||||
$result->add('region', $items[$index_current + 10]);
|
||||
$result->add('pingsite', $items[$index_current + 11]);
|
||||
$result->add('country', $items[$index_current + 12]);
|
||||
//$result->add('quickmatch', (int) $items[$index_current + 13]); Supposed to be here according to R42 but is not
|
||||
$result->add('blaze_player_count', (int) $items[$index_current + 13]);
|
||||
$result->add('blaze_game_state', (int) $items[$index_current + 14]);
|
||||
|
||||
unset($items, $index_current, $teamCount, $buffer);
|
||||
|
||||
return $result->fetch();
|
||||
}
|
||||
}
|
326
GameQ/Protocols/Bfbc2.php
Normal file
326
GameQ/Protocols/Bfbc2.php
Normal file
|
@ -0,0 +1,326 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is part of GameQ.
|
||||
*
|
||||
* GameQ is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GameQ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace GameQ\Protocols;
|
||||
|
||||
use GameQ\Protocol;
|
||||
use GameQ\Buffer;
|
||||
use GameQ\Result;
|
||||
use GameQ\Exception\Protocol as Exception;
|
||||
|
||||
/**
|
||||
* Battlefield Bad Company 2 Protocol Class
|
||||
*
|
||||
* NOTE: There are no qualifiers to the response packets sent back from the server as to which response packet
|
||||
* belongs to which query request. For now this class assumes the responses are in the same order as the order in
|
||||
* which the packets were sent to the server. If this assumption turns out to be wrong there is easy way to tell which
|
||||
* response belongs to which query. Hopefully this assumption will hold true as it has in my testing.
|
||||
*
|
||||
* @package GameQ\Protocols
|
||||
* @author Austin Bischoff <austin@codebeard.com>
|
||||
*/
|
||||
class Bfbc2 extends Protocol
|
||||
{
|
||||
|
||||
/**
|
||||
* Array of packets we want to query.
|
||||
*
|
||||
* @type array
|
||||
*/
|
||||
protected $packets = [
|
||||
self::PACKET_VERSION => "\x00\x00\x00\x00\x18\x00\x00\x00\x01\x00\x00\x00\x07\x00\x00\x00version\x00",
|
||||
self::PACKET_STATUS => "\x00\x00\x00\x00\x1b\x00\x00\x00\x01\x00\x00\x00\x0a\x00\x00\x00serverInfo\x00",
|
||||
self::PACKET_PLAYERS => "\x00\x00\x00\x00\x24\x00\x00\x00\x02\x00\x00\x00\x0b\x00\x00\x00listPlayers\x00\x03\x00\x00\x00\x61ll\x00",
|
||||
];
|
||||
|
||||
/**
|
||||
* Use the response flag to figure out what method to run
|
||||
*
|
||||
* @type array
|
||||
*/
|
||||
protected $responses = [
|
||||
"processVersion",
|
||||
"processDetails",
|
||||
"processPlayers",
|
||||
];
|
||||
|
||||
/**
|
||||
* The transport mode for this protocol is TCP
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $transport = self::TRANSPORT_TCP;
|
||||
|
||||
/**
|
||||
* The query protocol used to make the call
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $protocol = 'bfbc2';
|
||||
|
||||
/**
|
||||
* String name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name = 'bfbc2';
|
||||
|
||||
/**
|
||||
* Longer string name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name_long = "Battlefield Bad Company 2";
|
||||
|
||||
/**
|
||||
* The client join link
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $join_link = null;
|
||||
|
||||
/**
|
||||
* query_port = client_port + 29321
|
||||
* 48888 = 19567 + 29321
|
||||
*
|
||||
* @type int
|
||||
*/
|
||||
protected $port_diff = 29321;
|
||||
|
||||
/**
|
||||
* Normalize settings for this protocol
|
||||
*
|
||||
* @type array
|
||||
*/
|
||||
protected $normalize = [
|
||||
// General
|
||||
'general' => [
|
||||
// target => source
|
||||
'dedicated' => 'dedicated',
|
||||
'hostname' => 'hostname',
|
||||
'mapname' => 'map',
|
||||
'maxplayers' => 'max_players',
|
||||
'numplayers' => 'num_players',
|
||||
'password' => 'password',
|
||||
],
|
||||
'player' => [
|
||||
'name' => 'name',
|
||||
'score' => 'score',
|
||||
'ping' => 'ping',
|
||||
],
|
||||
'team' => [
|
||||
'score' => 'tickets',
|
||||
],
|
||||
];
|
||||
|
||||
/**
|
||||
* Process the response for the StarMade server
|
||||
*
|
||||
* @return array
|
||||
* @throws \GameQ\Exception\Protocol
|
||||
*/
|
||||
public function processResponse()
|
||||
{
|
||||
|
||||
//print_r($this->packets_response);
|
||||
|
||||
// Holds the results sent back
|
||||
$results = [];
|
||||
|
||||
// Iterate over the response packets
|
||||
// @todo: This protocol has no packet ordering, ids or anyway to identify which packet coming back belongs to which initial call.
|
||||
foreach ($this->packets_response as $i => $packet) {
|
||||
// Create a new buffer
|
||||
$buffer = new Buffer($packet);
|
||||
|
||||
// Burn first 4 bytes, same across all packets
|
||||
$buffer->skip(4);
|
||||
|
||||
// Get the packet length
|
||||
$packetLength = $buffer->getLength();
|
||||
|
||||
// Check to make sure the expected length matches the real length
|
||||
// Subtract 4 for the header burn
|
||||
if ($packetLength != ($buffer->readInt32() - 4)) {
|
||||
throw new Exception(__METHOD__ . " packet length does not match expected length!");
|
||||
}
|
||||
|
||||
// We assume the packets are coming back in the same order as sent, this maybe incorrect...
|
||||
$results = array_merge(
|
||||
$results,
|
||||
call_user_func_array([$this, $this->responses[$i]], [$buffer])
|
||||
);
|
||||
}
|
||||
|
||||
unset($buffer, $packetLength);
|
||||
|
||||
return $results;
|
||||
}
|
||||
|
||||
/*
|
||||
* Internal Methods
|
||||
*/
|
||||
|
||||
/**
|
||||
* Decode the buffer into a usable format
|
||||
*
|
||||
* @param \GameQ\Buffer $buffer
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function decode(Buffer $buffer)
|
||||
{
|
||||
|
||||
$items = [];
|
||||
|
||||
// Get the number of words in this buffer
|
||||
$itemCount = $buffer->readInt32();
|
||||
|
||||
// Loop over the number of items
|
||||
for ($i = 0; $i < $itemCount; $i++) {
|
||||
// Length of the string
|
||||
$buffer->readInt32();
|
||||
|
||||
// Just read the string
|
||||
$items[$i] = $buffer->readString();
|
||||
}
|
||||
|
||||
return $items;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the server details
|
||||
*
|
||||
* @param \GameQ\Buffer $buffer
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function processDetails(Buffer $buffer)
|
||||
{
|
||||
|
||||
// Decode into items
|
||||
$items = $this->decode($buffer);
|
||||
|
||||
// Set the result to a new result instance
|
||||
$result = new Result();
|
||||
|
||||
// Server is always dedicated
|
||||
$result->add('dedicated', 1);
|
||||
|
||||
// These are the same no matter what mode the server is in
|
||||
$result->add('hostname', $items[1]);
|
||||
$result->add('num_players', (int)$items[2]);
|
||||
$result->add('max_players', (int)$items[3]);
|
||||
$result->add('gametype', $items[4]);
|
||||
$result->add('map', $items[5]);
|
||||
$result->add('roundsplayed', (int)$items[6]);
|
||||
$result->add('roundstotal', (int)$items[7]);
|
||||
$result->add('num_teams', (int)$items[8]);
|
||||
|
||||
// Set the current index
|
||||
$index_current = 9;
|
||||
|
||||
// Pull the team count
|
||||
$teamCount = $result->get('num_teams');
|
||||
|
||||
// Loop for the number of teams found, increment along the way
|
||||
for ($id = 1; $id <= $teamCount; $id++, $index_current++) {
|
||||
// Shows the tickets
|
||||
$result->addTeam('tickets', $items[$index_current]);
|
||||
// We add an id so we know which team this is
|
||||
$result->addTeam('id', $id);
|
||||
}
|
||||
|
||||
// Get and set the rest of the data points.
|
||||
$result->add('targetscore', (int)$items[$index_current]);
|
||||
$result->add('online', 1); // Forced true, shows accepting players
|
||||
$result->add('ranked', (($items[$index_current + 2] == 'true') ? 1 : 0));
|
||||
$result->add('punkbuster', (($items[$index_current + 3] == 'true') ? 1 : 0));
|
||||
$result->add('password', (($items[$index_current + 4] == 'true') ? 1 : 0));
|
||||
$result->add('uptime', (int)$items[$index_current + 5]);
|
||||
$result->add('roundtime', (int)$items[$index_current + 6]);
|
||||
$result->add('mod', $items[$index_current + 7]);
|
||||
|
||||
$result->add('ip_port', $items[$index_current + 9]);
|
||||
$result->add('punkbuster_version', $items[$index_current + 10]);
|
||||
$result->add('join_queue', (($items[$index_current + 11] == 'true') ? 1 : 0));
|
||||
$result->add('region', $items[$index_current + 12]);
|
||||
|
||||
unset($items, $index_current, $teamCount, $buffer);
|
||||
|
||||
return $result->fetch();
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the server version
|
||||
*
|
||||
* @param \GameQ\Buffer $buffer
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function processVersion(Buffer $buffer)
|
||||
{
|
||||
// Decode into items
|
||||
$items = $this->decode($buffer);
|
||||
|
||||
// Set the result to a new result instance
|
||||
$result = new Result();
|
||||
|
||||
$result->add('version', $items[2]);
|
||||
|
||||
unset($buffer, $items);
|
||||
|
||||
return $result->fetch();
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the players
|
||||
*
|
||||
* @param \GameQ\Buffer $buffer
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function processPlayers(Buffer $buffer)
|
||||
{
|
||||
|
||||
// Decode into items
|
||||
$items = $this->decode($buffer);
|
||||
|
||||
// Set the result to a new result instance
|
||||
$result = new Result();
|
||||
|
||||
// Number of data points per player
|
||||
$numTags = $items[1];
|
||||
|
||||
// Grab the tags for each player
|
||||
$tags = array_slice($items, 2, $numTags);
|
||||
|
||||
// Get the player count
|
||||
$playerCount = $items[$numTags + 2];
|
||||
|
||||
// Iterate over the index until we run out of players
|
||||
for ($i = 0, $x = $numTags + 3; $i < $playerCount; $i++, $x += $numTags) {
|
||||
// Loop over the player tags and extract the info for that tag
|
||||
foreach ($tags as $index => $tag) {
|
||||
$result->addPlayer($tag, $items[($x + $index)]);
|
||||
}
|
||||
}
|
||||
|
||||
return $result->fetch();
|
||||
}
|
||||
}
|
43
GameQ/Protocols/Bfh.php
Normal file
43
GameQ/Protocols/Bfh.php
Normal file
|
@ -0,0 +1,43 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is part of GameQ.
|
||||
*
|
||||
* GameQ is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GameQ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace GameQ\Protocols;
|
||||
|
||||
/**
|
||||
* Battlefield Hardline Protocol class
|
||||
*
|
||||
* @package GameQ\Protocols
|
||||
* @author Austin Bischoff <austin@codebeard.com>
|
||||
*/
|
||||
class Bfh extends Bf4
|
||||
{
|
||||
|
||||
/**
|
||||
* String name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name = 'bfh';
|
||||
|
||||
/**
|
||||
* Longer string name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name_long = "Battlefield Hardline";
|
||||
}
|
50
GameQ/Protocols/Brink.php
Normal file
50
GameQ/Protocols/Brink.php
Normal file
|
@ -0,0 +1,50 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is part of GameQ.
|
||||
*
|
||||
* GameQ is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GameQ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace GameQ\Protocols;
|
||||
|
||||
/**
|
||||
* Class Brink
|
||||
*
|
||||
* @package GameQ\Protocols
|
||||
*
|
||||
* @author Wilson Jesus <>
|
||||
*/
|
||||
class Brink extends Source
|
||||
{
|
||||
/**
|
||||
* String name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name = 'brink';
|
||||
|
||||
/**
|
||||
* Longer string name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name_long = "Brink";
|
||||
|
||||
/**
|
||||
* query_port = client_port + 1
|
||||
*
|
||||
* @type int
|
||||
*/
|
||||
protected $port_diff = 1;
|
||||
}
|
43
GameQ/Protocols/Cod.php
Normal file
43
GameQ/Protocols/Cod.php
Normal file
|
@ -0,0 +1,43 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is part of GameQ.
|
||||
*
|
||||
* GameQ is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GameQ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace GameQ\Protocols;
|
||||
|
||||
/**
|
||||
* Call of Duty Protocol Class
|
||||
*
|
||||
* @package GameQ\Protocols
|
||||
*
|
||||
* @author Wilson Jesus <>
|
||||
*/
|
||||
class Cod extends Quake3
|
||||
{
|
||||
/**
|
||||
* String name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name = 'cod';
|
||||
|
||||
/**
|
||||
* Longer string name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name_long = "Call of Duty";
|
||||
}
|
42
GameQ/Protocols/Cod2.php
Normal file
42
GameQ/Protocols/Cod2.php
Normal file
|
@ -0,0 +1,42 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is part of GameQ.
|
||||
*
|
||||
* GameQ is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GameQ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace GameQ\Protocols;
|
||||
|
||||
/**
|
||||
* Call of Duty 2 Protocol Class
|
||||
*
|
||||
* @package GameQ\Protocols
|
||||
* @author Austin Bischoff <austin@codebeard.com>
|
||||
*/
|
||||
class Cod2 extends Quake3
|
||||
{
|
||||
/**
|
||||
* String name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name = 'cod2';
|
||||
|
||||
/**
|
||||
* Longer string name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name_long = "Call of Duty 2";
|
||||
}
|
42
GameQ/Protocols/Cod4.php
Normal file
42
GameQ/Protocols/Cod4.php
Normal file
|
@ -0,0 +1,42 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is part of GameQ.
|
||||
*
|
||||
* GameQ is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GameQ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace GameQ\Protocols;
|
||||
|
||||
/**
|
||||
* Call of Duty 4 Protocol Class
|
||||
*
|
||||
* @package GameQ\Protocols
|
||||
* @author Austin Bischoff <austin@codebeard.com>
|
||||
*/
|
||||
class Cod4 extends Quake3
|
||||
{
|
||||
/**
|
||||
* String name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name = 'cod4';
|
||||
|
||||
/**
|
||||
* Longer string name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name_long = "Call of Duty 4";
|
||||
}
|
50
GameQ/Protocols/Codmw3.php
Normal file
50
GameQ/Protocols/Codmw3.php
Normal file
|
@ -0,0 +1,50 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is part of GameQ.
|
||||
*
|
||||
* GameQ is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GameQ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace GameQ\Protocols;
|
||||
|
||||
/**
|
||||
* Class Codmw3
|
||||
*
|
||||
* @package GameQ\Protocols
|
||||
* @author Austin Bischoff <austin@codebeard.com>
|
||||
*/
|
||||
class Codmw3 extends Source
|
||||
{
|
||||
|
||||
/**
|
||||
* String name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name = 'codmw3';
|
||||
|
||||
/**
|
||||
* Longer string name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name_long = "Call of Duty: Modern Warfare 3";
|
||||
|
||||
/**
|
||||
* query_port = client_port + 2
|
||||
*
|
||||
* @type int
|
||||
*/
|
||||
protected $port_diff = 2;
|
||||
}
|
43
GameQ/Protocols/Coduo.php
Normal file
43
GameQ/Protocols/Coduo.php
Normal file
|
@ -0,0 +1,43 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is part of GameQ.
|
||||
*
|
||||
* GameQ is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GameQ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace GameQ\Protocols;
|
||||
|
||||
/**
|
||||
* Call of Duty United Offensive Class
|
||||
*
|
||||
* @package GameQ\Protocols
|
||||
*
|
||||
* @author Wilson Jesus <>
|
||||
*/
|
||||
class Coduo extends Quake3
|
||||
{
|
||||
/**
|
||||
* String name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name = 'coduo';
|
||||
|
||||
/**
|
||||
* Longer string name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name_long = "Call of Duty: United Offensive";
|
||||
}
|
43
GameQ/Protocols/Codwaw.php
Normal file
43
GameQ/Protocols/Codwaw.php
Normal file
|
@ -0,0 +1,43 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is part of GameQ.
|
||||
*
|
||||
* GameQ is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GameQ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace GameQ\Protocols;
|
||||
|
||||
/**
|
||||
* Call of Duty World at War Class
|
||||
*
|
||||
* @package GameQ\Protocols
|
||||
* @author naXe <naxeify@gmail.com>
|
||||
* @author Austin Bischoff <austin@codebeard.com>
|
||||
*/
|
||||
class Codwaw extends Quake3
|
||||
{
|
||||
/**
|
||||
* String name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name = 'codwaw';
|
||||
|
||||
/**
|
||||
* Longer string name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name_long = "Call of Duty: World at War";
|
||||
}
|
42
GameQ/Protocols/Conanexiles.php
Normal file
42
GameQ/Protocols/Conanexiles.php
Normal file
|
@ -0,0 +1,42 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is part of GameQ.
|
||||
*
|
||||
* GameQ is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GameQ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace GameQ\Protocols;
|
||||
|
||||
/**
|
||||
* Class Conanexiles
|
||||
*
|
||||
* @package GameQ\Protocols
|
||||
* @author Austin Bischoff <austin@codebeard.com>
|
||||
*/
|
||||
class Conanexiles extends Source
|
||||
{
|
||||
/**
|
||||
* String name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name = 'conanexiles';
|
||||
|
||||
/**
|
||||
* Longer string name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name_long = "Conan Exiles";
|
||||
}
|
42
GameQ/Protocols/Contagion.php
Normal file
42
GameQ/Protocols/Contagion.php
Normal file
|
@ -0,0 +1,42 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is part of GameQ.
|
||||
*
|
||||
* GameQ is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GameQ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace GameQ\Protocols;
|
||||
|
||||
/**
|
||||
* Class Contagion
|
||||
*
|
||||
* @package GameQ\Protocols
|
||||
* @author Nikolay Ipanyuk <rostov114@gmail.com>
|
||||
* @author Austin Bischoff <austin@codebeard.com>
|
||||
*/
|
||||
class Contagion extends Source
|
||||
{
|
||||
/**
|
||||
* String name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name = 'contagion';
|
||||
/**
|
||||
* Longer string name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name_long = "Contagion";
|
||||
}
|
43
GameQ/Protocols/Crysis.php
Normal file
43
GameQ/Protocols/Crysis.php
Normal file
|
@ -0,0 +1,43 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is part of GameQ.
|
||||
*
|
||||
* GameQ is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GameQ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace GameQ\Protocols;
|
||||
|
||||
/**
|
||||
* Class Crysis
|
||||
*
|
||||
* @package GameQ\Protocols
|
||||
*
|
||||
* @author Wilson Jesus <>
|
||||
*/
|
||||
class Crysis extends Gamespy3
|
||||
{
|
||||
/**
|
||||
* String name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name = 'crysis';
|
||||
|
||||
/**
|
||||
* Longer string name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name_long = "Crysis";
|
||||
}
|
43
GameQ/Protocols/Crysis2.php
Normal file
43
GameQ/Protocols/Crysis2.php
Normal file
|
@ -0,0 +1,43 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is part of GameQ.
|
||||
*
|
||||
* GameQ is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GameQ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace GameQ\Protocols;
|
||||
|
||||
/**
|
||||
* Class Crysis2
|
||||
*
|
||||
* @package GameQ\Protocols
|
||||
*
|
||||
* @author Wilson Jesus <>
|
||||
*/
|
||||
class Crysis2 extends Gamespy3
|
||||
{
|
||||
/**
|
||||
* String name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name = 'crysis2';
|
||||
|
||||
/**
|
||||
* Longer string name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name_long = "Crysis 2";
|
||||
}
|
43
GameQ/Protocols/Crysiswars.php
Normal file
43
GameQ/Protocols/Crysiswars.php
Normal file
|
@ -0,0 +1,43 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is part of GameQ.
|
||||
*
|
||||
* GameQ is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GameQ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace GameQ\Protocols;
|
||||
|
||||
/**
|
||||
* Class Crysiswars
|
||||
*
|
||||
* @package GameQ\Protocols
|
||||
*
|
||||
* @author Austin Bischoff <austin@codebeard.com>
|
||||
*/
|
||||
class Crysiswars extends Gamespy3
|
||||
{
|
||||
/**
|
||||
* String name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name = 'crysiswars';
|
||||
|
||||
/**
|
||||
* Longer string name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name_long = "Crysis Wars";
|
||||
}
|
45
GameQ/Protocols/Cs15.php
Normal file
45
GameQ/Protocols/Cs15.php
Normal file
|
@ -0,0 +1,45 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is part of GameQ.
|
||||
*
|
||||
* GameQ is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GameQ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace GameQ\Protocols;
|
||||
|
||||
/**
|
||||
* Counter-Strike 1.5 Protocol Class
|
||||
*
|
||||
* @author Nikolay Ipanyuk <rostov114@gmail.com>
|
||||
* @author Austin Bischoff <austin@codebeard.com>
|
||||
*
|
||||
* @package GameQ\Protocols
|
||||
*/
|
||||
class Cs15 extends Won
|
||||
{
|
||||
|
||||
/**
|
||||
* String name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name = 'cs15';
|
||||
|
||||
/**
|
||||
* Longer string name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name_long = "Counter-Strike 1.5";
|
||||
}
|
69
GameQ/Protocols/Cs16.php
Normal file
69
GameQ/Protocols/Cs16.php
Normal file
|
@ -0,0 +1,69 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is part of GameQ.
|
||||
*
|
||||
* GameQ is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GameQ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace GameQ\Protocols;
|
||||
|
||||
/**
|
||||
* Class Cs16
|
||||
*
|
||||
* @package GameQ\Protocols
|
||||
* @author Austin Bischoff <austin@codebeard.com>
|
||||
*/
|
||||
class Cs16 extends Source
|
||||
{
|
||||
|
||||
/**
|
||||
* String name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name = 'cs16';
|
||||
|
||||
/**
|
||||
* Longer string name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name_long = "Counter-Strike 1.6";
|
||||
|
||||
/**
|
||||
* In the case of cs 1.6 we offload split packets here because the split packet response for rules is in
|
||||
* the old gold source format
|
||||
*
|
||||
* @param $packet_id
|
||||
* @param array $packets
|
||||
*
|
||||
* @return string
|
||||
* @throws \GameQ\Exception\Protocol
|
||||
*/
|
||||
protected function processPackets($packet_id, array $packets = [])
|
||||
{
|
||||
|
||||
// The response is gold source if the packets are split
|
||||
$this->source_engine = self::GOLDSOURCE_ENGINE;
|
||||
|
||||
// Offload to the parent
|
||||
$packs = parent::processPackets($packet_id, $packets);
|
||||
|
||||
// Reset the engine
|
||||
$this->source_engine = self::SOURCE_ENGINE;
|
||||
|
||||
// Return the result
|
||||
return $packs;
|
||||
}
|
||||
}
|
263
GameQ/Protocols/Cs2d.php
Normal file
263
GameQ/Protocols/Cs2d.php
Normal file
|
@ -0,0 +1,263 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is part of GameQ.
|
||||
*
|
||||
* GameQ is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GameQ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace GameQ\Protocols;
|
||||
|
||||
use GameQ\Protocol;
|
||||
use GameQ\Buffer;
|
||||
use GameQ\Result;
|
||||
use GameQ\Exception\Protocol as Exception;
|
||||
|
||||
/**
|
||||
* Counter-Strike 2d Protocol Class
|
||||
*
|
||||
* Note:
|
||||
* Unable to make player information calls work as the protocol does not like parallel requests
|
||||
*
|
||||
* @author Austin Bischoff <austin@codebeard.com>
|
||||
*/
|
||||
class Cs2d extends Protocol
|
||||
{
|
||||
|
||||
/**
|
||||
* Array of packets we want to query.
|
||||
*
|
||||
* @type array
|
||||
*/
|
||||
protected $packets = [
|
||||
self::PACKET_STATUS => "\x01\x00\xFB\x01",
|
||||
//self::PACKET_STATUS => "\x01\x00\x03\x10\x21\xFB\x01\x75\x00",
|
||||
self::PACKET_PLAYERS => "\x01\x00\xFB\x05",
|
||||
];
|
||||
|
||||
/**
|
||||
* Use the response flag to figure out what method to run
|
||||
*
|
||||
* @type array
|
||||
*/
|
||||
protected $responses = [
|
||||
"\x01\x00\xFB\x01" => "processDetails",
|
||||
"\x01\x00\xFB\x05" => "processPlayers",
|
||||
];
|
||||
|
||||
/**
|
||||
* The query protocol used to make the call
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $protocol = 'cs2d';
|
||||
|
||||
/**
|
||||
* String name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name = 'cs2d';
|
||||
|
||||
/**
|
||||
* Longer string name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name_long = "Counter-Strike 2d";
|
||||
|
||||
/**
|
||||
* The client join link
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $join_link = "cs2d://%s:%d/";
|
||||
|
||||
/**
|
||||
* Normalize settings for this protocol
|
||||
*
|
||||
* @type array
|
||||
*/
|
||||
protected $normalize = [
|
||||
// General
|
||||
'general' => [
|
||||
// target => source
|
||||
'dedicated' => 'dedicated',
|
||||
'gametype' => 'game_mode',
|
||||
'hostname' => 'hostname',
|
||||
'mapname' => 'mapname',
|
||||
'maxplayers' => 'max_players',
|
||||
'mod' => 'game_dir',
|
||||
'numplayers' => 'num_players',
|
||||
'password' => 'password',
|
||||
],
|
||||
// Individual
|
||||
'player' => [
|
||||
'name' => 'name',
|
||||
'deaths' => 'deaths',
|
||||
'score' => 'score',
|
||||
],
|
||||
];
|
||||
|
||||
/**
|
||||
* Process the response for the Tibia server
|
||||
*
|
||||
* @return array
|
||||
* @throws \GameQ\Exception\Protocol
|
||||
*/
|
||||
public function processResponse()
|
||||
{
|
||||
|
||||
// We have a merged packet, try to split it back up
|
||||
if (count($this->packets_response) == 1) {
|
||||
// Temp buffer to make string manipulation easier
|
||||
$buffer = new Buffer($this->packets_response[0]);
|
||||
|
||||
// Grab the header and set the packet we need to split with
|
||||
$packet = (($buffer->lookAhead(4) === $this->packets[self::PACKET_PLAYERS]) ?
|
||||
self::PACKET_STATUS : self::PACKET_PLAYERS);
|
||||
|
||||
// Explode the merged packet as the response
|
||||
$responses = explode(substr($this->packets[$packet], 2), $buffer->getData());
|
||||
|
||||
// Try to rebuild the second packet to the same as if it was sent as two separate responses
|
||||
$responses[1] = $this->packets[$packet] . ((count($responses) === 2) ? $responses[1] : "");
|
||||
|
||||
unset($buffer);
|
||||
} else {
|
||||
$responses = $this->packets_response;
|
||||
}
|
||||
|
||||
// Will hold the packets after sorting
|
||||
$packets = [];
|
||||
|
||||
// We need to pre-sort these for split packets so we can do extra work where needed
|
||||
foreach ($responses as $response) {
|
||||
$buffer = new Buffer($response);
|
||||
|
||||
// Pull out the header
|
||||
$header = $buffer->read(4);
|
||||
|
||||
// Add the packet to the proper section, we will combine later
|
||||
$packets[$header][] = $buffer->getBuffer();
|
||||
}
|
||||
|
||||
unset($buffer);
|
||||
|
||||
$results = [];
|
||||
|
||||
// Now let's iterate and process
|
||||
foreach ($packets as $header => $packetGroup) {
|
||||
// Figure out which packet response this is
|
||||
if (!array_key_exists($header, $this->responses)) {
|
||||
throw new Exception(__METHOD__ . " response type '" . bin2hex($header) . "' is not valid");
|
||||
}
|
||||
|
||||
// Now we need to call the proper method
|
||||
$results = array_merge(
|
||||
$results,
|
||||
call_user_func_array([$this, $this->responses[$header]], [new Buffer(implode($packetGroup))])
|
||||
);
|
||||
}
|
||||
|
||||
unset($packets);
|
||||
|
||||
return $results;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles processing the details data into a usable format
|
||||
*
|
||||
* @param Buffer $buffer
|
||||
*
|
||||
* @return array
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function processDetails(Buffer $buffer)
|
||||
{
|
||||
// Set the result to a new result instance
|
||||
$result = new Result();
|
||||
|
||||
// First int is the server flags
|
||||
$serverFlags = $buffer->readInt8();
|
||||
|
||||
// Read server flags
|
||||
$result->add('password', (int)$this->readFlag($serverFlags, 0));
|
||||
$result->add('registered_only', (int)$this->readFlag($serverFlags, 1));
|
||||
$result->add('fog_of_war', (int)$this->readFlag($serverFlags, 2));
|
||||
$result->add('friendly_fire', (int)$this->readFlag($serverFlags, 3));
|
||||
$result->add('bots_enabled', (int)$this->readFlag($serverFlags, 5));
|
||||
$result->add('lua_scripts', (int)$this->readFlag($serverFlags, 6));
|
||||
|
||||
// Read the rest of the buffer data
|
||||
$result->add('servername', utf8_encode($buffer->readPascalString(0)));
|
||||
$result->add('mapname', utf8_encode($buffer->readPascalString(0)));
|
||||
$result->add('num_players', $buffer->readInt8());
|
||||
$result->add('max_players', $buffer->readInt8());
|
||||
$result->add('game_mode', $buffer->readInt8());
|
||||
$result->add('num_bots', (($this->readFlag($serverFlags, 5)) ? $buffer->readInt8() : 0));
|
||||
$result->add('dedicated', 1);
|
||||
|
||||
unset($buffer);
|
||||
|
||||
return $result->fetch();
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles processing the player data into a usable format
|
||||
*
|
||||
* @param Buffer $buffer
|
||||
*
|
||||
* @return array
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function processPlayers(Buffer $buffer)
|
||||
{
|
||||
|
||||
// Set the result to a new result instance
|
||||
$result = new Result();
|
||||
|
||||
// First entry is the number of players in this list. Don't care
|
||||
$buffer->read();
|
||||
|
||||
// Parse players
|
||||
while ($buffer->getLength()) {
|
||||
// Player id
|
||||
if (($id = $buffer->readInt8()) !== 0) {
|
||||
// Add the results
|
||||
$result->addPlayer('id', $id);
|
||||
$result->addPlayer('name', utf8_encode($buffer->readPascalString(0)));
|
||||
$result->addPlayer('team', $buffer->readInt8());
|
||||
$result->addPlayer('score', $buffer->readInt32());
|
||||
$result->addPlayer('deaths', $buffer->readInt32());
|
||||
}
|
||||
}
|
||||
|
||||
unset($buffer, $id);
|
||||
|
||||
return $result->fetch();
|
||||
}
|
||||
|
||||
/**
|
||||
* Read flags from stored value
|
||||
*
|
||||
* @param $flags
|
||||
* @param $offset
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function readFlag($flags, $offset)
|
||||
{
|
||||
return !!($flags & (1 << $offset));
|
||||
}
|
||||
}
|
45
GameQ/Protocols/Cscz.php
Normal file
45
GameQ/Protocols/Cscz.php
Normal file
|
@ -0,0 +1,45 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is part of GameQ.
|
||||
*
|
||||
* GameQ is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GameQ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace GameQ\Protocols;
|
||||
|
||||
/**
|
||||
* Class Cscz
|
||||
*
|
||||
* Based off of CS 1.6
|
||||
*
|
||||
* @package GameQ\Protocols
|
||||
* @author Austin Bischoff <austin@codebeard.com>
|
||||
*/
|
||||
class Cscz extends Cs16
|
||||
{
|
||||
|
||||
/**
|
||||
* String name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name = 'cscz';
|
||||
|
||||
/**
|
||||
* Longer string name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name_long = "Counter-Strike: Condition Zero";
|
||||
}
|
43
GameQ/Protocols/Csgo.php
Normal file
43
GameQ/Protocols/Csgo.php
Normal file
|
@ -0,0 +1,43 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is part of GameQ.
|
||||
*
|
||||
* GameQ is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GameQ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace GameQ\Protocols;
|
||||
|
||||
/**
|
||||
* Class Csgo
|
||||
*
|
||||
* @package GameQ\Protocols
|
||||
* @author Austin Bischoff <austin@codebeard.com>
|
||||
*/
|
||||
class Csgo extends Source
|
||||
{
|
||||
|
||||
/**
|
||||
* String name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name = 'csgo';
|
||||
|
||||
/**
|
||||
* Longer string name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name_long = "Counter-Strike: Global Offensive";
|
||||
}
|
42
GameQ/Protocols/Css.php
Normal file
42
GameQ/Protocols/Css.php
Normal file
|
@ -0,0 +1,42 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is part of GameQ.
|
||||
*
|
||||
* GameQ is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GameQ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace GameQ\Protocols;
|
||||
|
||||
/**
|
||||
* Class Css
|
||||
*
|
||||
* @package GameQ\Protocols
|
||||
* @author Austin Bischoff <austin@codebeard.com>
|
||||
*/
|
||||
class Css extends Source
|
||||
{
|
||||
/**
|
||||
* String name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name = 'css';
|
||||
|
||||
/**
|
||||
* Longer string name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name_long = "Counter-Strike: Source";
|
||||
}
|
43
GameQ/Protocols/Dal.php
Normal file
43
GameQ/Protocols/Dal.php
Normal file
|
@ -0,0 +1,43 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is part of GameQ.
|
||||
*
|
||||
* GameQ is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GameQ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace GameQ\Protocols;
|
||||
|
||||
/**
|
||||
* Class Dark and Light
|
||||
*
|
||||
* @package GameQ\Protocols
|
||||
* @author Austin Bischoff <austin@codebeard.com>
|
||||
*/
|
||||
class Dal extends Arkse
|
||||
{
|
||||
|
||||
/**
|
||||
* String name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name = 'dal';
|
||||
|
||||
/**
|
||||
* Longer string name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name_long = "Dark and Light";
|
||||
}
|
66
GameQ/Protocols/Dayz.php
Normal file
66
GameQ/Protocols/Dayz.php
Normal file
|
@ -0,0 +1,66 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is part of GameQ.
|
||||
*
|
||||
* GameQ is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GameQ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace GameQ\Protocols;
|
||||
|
||||
/**
|
||||
* Class Dayz
|
||||
*
|
||||
* @package GameQ\Protocols
|
||||
* @author Austin Bischoff <austin@codebeard.com>
|
||||
*/
|
||||
class Dayz extends Source
|
||||
{
|
||||
|
||||
/**
|
||||
* String name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name = 'dayz';
|
||||
|
||||
/**
|
||||
* Longer string name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name_long = "DayZ Standalone";
|
||||
|
||||
/**
|
||||
* Overload the math used to guess at the Query Port
|
||||
*
|
||||
* @param int $clientPort
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function findQueryPort($clientPort)
|
||||
{
|
||||
|
||||
/*
|
||||
* Port layout:
|
||||
* 2302 - 27016
|
||||
* 2402 - 27017
|
||||
* 2502 - 27018
|
||||
* 2602 - 27019
|
||||
* 2702 - 27020
|
||||
* ...
|
||||
*/
|
||||
|
||||
return 27016 + (($clientPort - 2302) / 100);
|
||||
}
|
||||
}
|
44
GameQ/Protocols/Dayzmod.php
Normal file
44
GameQ/Protocols/Dayzmod.php
Normal file
|
@ -0,0 +1,44 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is part of GameQ.
|
||||
*
|
||||
* GameQ is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GameQ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace GameQ\Protocols;
|
||||
|
||||
/**
|
||||
* Class Dayzmod
|
||||
*
|
||||
* @package GameQ\Protocols
|
||||
* @author Marcel Bößendörfer <m.boessendoerfer@marbis.net>
|
||||
* @author Austin Bischoff <austin@codebeard.com>
|
||||
*/
|
||||
class Dayzmod extends Armedassault2oa
|
||||
{
|
||||
|
||||
/**
|
||||
* String name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name = 'dayzmod';
|
||||
|
||||
/**
|
||||
* Longer string name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name_long = "DayZ Mod";
|
||||
}
|
45
GameQ/Protocols/Dod.php
Normal file
45
GameQ/Protocols/Dod.php
Normal file
|
@ -0,0 +1,45 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is part of GameQ.
|
||||
*
|
||||
* GameQ is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GameQ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace GameQ\Protocols;
|
||||
|
||||
/**
|
||||
* Class Dod
|
||||
*
|
||||
* Based off of CS 1.6
|
||||
*
|
||||
* @package GameQ\Protocols
|
||||
* @author Austin Bischoff <austin@codebeard.com>
|
||||
*/
|
||||
class Dod extends Cs16
|
||||
{
|
||||
|
||||
/**
|
||||
* String name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name = 'dod';
|
||||
|
||||
/**
|
||||
* Longer string name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name_long = "Day of Defeat";
|
||||
}
|
42
GameQ/Protocols/Dods.php
Normal file
42
GameQ/Protocols/Dods.php
Normal file
|
@ -0,0 +1,42 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is part of GameQ.
|
||||
*
|
||||
* GameQ is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GameQ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace GameQ\Protocols;
|
||||
|
||||
/**
|
||||
* Class Dods
|
||||
*
|
||||
* @package GameQ\Protocols
|
||||
* @author Austin Bischoff <austin@codebeard.com>
|
||||
*/
|
||||
class Dods extends Source
|
||||
{
|
||||
/**
|
||||
* String name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name = 'dods';
|
||||
|
||||
/**
|
||||
* Longer string name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name_long = "Day of Defeat: Source";
|
||||
}
|
69
GameQ/Protocols/Dow.php
Normal file
69
GameQ/Protocols/Dow.php
Normal file
|
@ -0,0 +1,69 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is part of GameQ.
|
||||
*
|
||||
* GameQ is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GameQ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace GameQ\Protocols;
|
||||
|
||||
use GameQ\Buffer;
|
||||
|
||||
/**
|
||||
* Class Dow
|
||||
*
|
||||
* Apparently the player response is incomplete as there is no information being returned for that packet
|
||||
*
|
||||
* @package GameQ\Protocols
|
||||
* @author Austin Bischoff <austin@codebeard.com>
|
||||
*/
|
||||
class Dow extends Source
|
||||
{
|
||||
/**
|
||||
* String name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name = 'dow';
|
||||
|
||||
/**
|
||||
* Longer string name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name_long = "Days of War";
|
||||
|
||||
/**
|
||||
* Normalize main fields
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $normalize = [
|
||||
// General
|
||||
'general' => [
|
||||
// target => source
|
||||
'gametype' => 'G_s',
|
||||
'hostname' => 'ONM_s',
|
||||
'mapname' => 'MPN_s',
|
||||
'maxplayers' => 'P_i',
|
||||
'numplayers' => 'N_i',
|
||||
],
|
||||
// Individual
|
||||
'player' => [
|
||||
'name' => 'name',
|
||||
'score' => 'score',
|
||||
'time' => 'time',
|
||||
],
|
||||
];
|
||||
}
|
123
GameQ/Protocols/Eco.php
Normal file
123
GameQ/Protocols/Eco.php
Normal file
|
@ -0,0 +1,123 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is part of GameQ.
|
||||
*
|
||||
* GameQ is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GameQ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace GameQ\Protocols;
|
||||
|
||||
use GameQ\Exception\Protocol as Exception;
|
||||
use GameQ\Result;
|
||||
|
||||
/**
|
||||
* ECO Global Survival Protocol Class
|
||||
*
|
||||
* @author Austin Bischoff <austin@codebeard.com>
|
||||
*/
|
||||
class Eco extends Http
|
||||
{
|
||||
/**
|
||||
* Packets to send
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $packets = [
|
||||
self::PACKET_STATUS => "GET /frontpage HTTP/1.0\r\nAccept: */*\r\n\r\n",
|
||||
];
|
||||
|
||||
/**
|
||||
* Http protocol is SSL
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $transport = self::TRANSPORT_TCP;
|
||||
|
||||
/**
|
||||
* The protocol being used
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $protocol = 'eco';
|
||||
|
||||
/**
|
||||
* String name of this protocol class
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $name = 'eco';
|
||||
|
||||
/**
|
||||
* Longer string name of this protocol class
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $name_long = "ECO Global Survival";
|
||||
|
||||
/**
|
||||
* query_port = client_port + 1
|
||||
*
|
||||
* @type int
|
||||
*/
|
||||
protected $port_diff = 1;
|
||||
|
||||
/**
|
||||
* Normalize some items
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $normalize = [
|
||||
// General
|
||||
'general' => [
|
||||
// target => source
|
||||
'dedicated' => 'dedicated',
|
||||
'hostname' => 'description',
|
||||
'maxplayers' => 'totalplayers',
|
||||
'numplayers' => 'onlineplayers',
|
||||
'password' => 'haspassword',
|
||||
],
|
||||
];
|
||||
|
||||
/**
|
||||
* Process the response
|
||||
*
|
||||
* @return array
|
||||
* @throws Exception
|
||||
*/
|
||||
public function processResponse()
|
||||
{
|
||||
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 Exception("JSON response from Eco server is invalid.");
|
||||
}
|
||||
|
||||
$result = new Result();
|
||||
|
||||
// Server is always dedicated
|
||||
$result->add('dedicated', 1);
|
||||
|
||||
foreach ($json->Info as $info => $setting) {
|
||||
$result->add(strtolower($info), $setting);
|
||||
}
|
||||
|
||||
return $result->fetch();
|
||||
}
|
||||
}
|
51
GameQ/Protocols/Egs.php
Normal file
51
GameQ/Protocols/Egs.php
Normal file
|
@ -0,0 +1,51 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is part of GameQ.
|
||||
*
|
||||
* GameQ is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GameQ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace GameQ\Protocols;
|
||||
|
||||
/**
|
||||
* Class Empyrion - Galactic Survival
|
||||
*
|
||||
* @package GameQ\Protocols
|
||||
* @author Austin Bischoff <austin@codebeard.com>
|
||||
* @author TacTicToe66 <https://github.com/TacTicToe66>
|
||||
*/
|
||||
class EgS extends Source
|
||||
{
|
||||
|
||||
/**
|
||||
* String name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name = 'egs';
|
||||
|
||||
/**
|
||||
* Longer string name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name_long = "Empyrion - Galactic Survival";
|
||||
|
||||
/**
|
||||
* query_port = client_port + 1
|
||||
*
|
||||
* @type int
|
||||
*/
|
||||
protected $port_diff = 1;
|
||||
}
|
43
GameQ/Protocols/Et.php
Normal file
43
GameQ/Protocols/Et.php
Normal file
|
@ -0,0 +1,43 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is part of GameQ.
|
||||
*
|
||||
* GameQ is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GameQ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace GameQ\Protocols;
|
||||
|
||||
/**
|
||||
* Wolfenstein Enemy Territory Protocol Class
|
||||
*
|
||||
* @package GameQ\Protocols
|
||||
*
|
||||
* @author Wilson Jesus <>
|
||||
*/
|
||||
class Et extends Quake3
|
||||
{
|
||||
/**
|
||||
* String name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name = 'et';
|
||||
|
||||
/**
|
||||
* Longer string name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name_long = "Wolfenstein Enemy Territory";
|
||||
}
|
234
GameQ/Protocols/Etqw.php
Normal file
234
GameQ/Protocols/Etqw.php
Normal file
|
@ -0,0 +1,234 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is part of GameQ.
|
||||
*
|
||||
* GameQ is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GameQ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace GameQ\Protocols;
|
||||
|
||||
use GameQ\Buffer;
|
||||
use GameQ\Exception\Protocol as Exception;
|
||||
use GameQ\Protocol;
|
||||
use GameQ\Result;
|
||||
|
||||
/**
|
||||
* Enemy Territory Quake Wars Protocol Class
|
||||
*
|
||||
* @author Austin Bischoff <austin@codebeard.com>
|
||||
*/
|
||||
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
|
||||
*
|
||||
* @type array
|
||||
*/
|
||||
protected $packets = [
|
||||
self::PACKET_STATUS => "\xFF\xFFgetInfoEx\x00\x00\x00\x00",
|
||||
//self::PACKET_STATUS => "\xFF\xFFgetInfo\x00\x00\x00\x00\x00",
|
||||
];
|
||||
|
||||
/**
|
||||
* Use the response flag to figure out what method to run
|
||||
*
|
||||
* @type array
|
||||
*/
|
||||
protected $responses = [
|
||||
"\xFF\xFFinfoExResponse" => "processStatus",
|
||||
];
|
||||
|
||||
/**
|
||||
* The query protocol used to make the call
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $protocol = 'etqw';
|
||||
|
||||
/**
|
||||
* String name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name = 'etqw';
|
||||
|
||||
/**
|
||||
* Longer string name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name_long = "Enemy Territory Quake Wars";
|
||||
|
||||
/**
|
||||
* Normalize settings for this protocol
|
||||
*
|
||||
* @type array
|
||||
*/
|
||||
protected $normalize = [
|
||||
// General
|
||||
'general' => [
|
||||
// target => source
|
||||
'gametype' => 'campaign',
|
||||
'hostname' => 'name',
|
||||
'mapname' => 'map',
|
||||
'maxplayers' => 'maxPlayers',
|
||||
'mod' => 'gamename',
|
||||
'numplayers' => 'numplayers',
|
||||
'password' => 'privateClients',
|
||||
],
|
||||
// Individual
|
||||
'player' => [
|
||||
'name' => 'name',
|
||||
'score' => 'score',
|
||||
'time' => 'time',
|
||||
],
|
||||
];
|
||||
|
||||
/**
|
||||
* Process the response
|
||||
*
|
||||
* @return array
|
||||
* @throws \GameQ\Exception\Protocol
|
||||
*/
|
||||
public function processResponse()
|
||||
{
|
||||
// In case it comes back as multiple packets (it shouldn't)
|
||||
$buffer = new Buffer(implode('', $this->packets_response));
|
||||
|
||||
// Figure out what packet response this is for
|
||||
$response_type = $buffer->readString();
|
||||
|
||||
// Figure out which packet response this is
|
||||
if (!array_key_exists($response_type, $this->responses)) {
|
||||
throw new Exception(__METHOD__ . " response type '{$response_type}' is not valid");
|
||||
}
|
||||
|
||||
// Offload the call
|
||||
$results = call_user_func_array([$this, $this->responses[$response_type]], [$buffer]);
|
||||
|
||||
return $results;
|
||||
}
|
||||
|
||||
/*
|
||||
* Internal methods
|
||||
*/
|
||||
|
||||
/**
|
||||
* Handle processing the status response
|
||||
*
|
||||
* @param Buffer $buffer
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function processStatus(Buffer $buffer)
|
||||
{
|
||||
// Set the result to a new result instance
|
||||
$result = new Result();
|
||||
|
||||
// Defaults
|
||||
$result->add('dedicated', 1);
|
||||
|
||||
// Now burn the challenge, version and size
|
||||
$buffer->skip(16);
|
||||
|
||||
// Key / value pairs
|
||||
while ($buffer->getLength()) {
|
||||
$var = str_replace('si_', '', $buffer->readString());
|
||||
$val = $buffer->readString();
|
||||
if (empty($var) && empty($val)) {
|
||||
break;
|
||||
}
|
||||
// Add the server prop
|
||||
$result->add($var, $val);
|
||||
}
|
||||
// Now let's do the basic player info
|
||||
$this->parsePlayers($buffer, $result);
|
||||
|
||||
// Now grab the rest of the server info
|
||||
$result->add('osmask', $buffer->readInt32());
|
||||
$result->add('ranked', $buffer->readInt8());
|
||||
$result->add('timeleft', $buffer->readInt32());
|
||||
$result->add('gamestate', $buffer->readInt8());
|
||||
$result->add('servertype', $buffer->readInt8());
|
||||
|
||||
// 0: regular server
|
||||
if ($result->get('servertype') == 0) {
|
||||
$result->add('interested_clients', $buffer->readInt8());
|
||||
} else {
|
||||
// 1: tv server
|
||||
$result->add('connected_clients', $buffer->readInt32());
|
||||
$result->add('max_clients', $buffer->readInt32());
|
||||
}
|
||||
|
||||
// Now let's parse the extended player info
|
||||
$this->parsePlayersExtra($buffer, $result);
|
||||
|
||||
unset($buffer);
|
||||
|
||||
return $result->fetch();
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse players out of the status ex response
|
||||
*
|
||||
* @param Buffer $buffer
|
||||
* @param Result $result
|
||||
*/
|
||||
protected function parsePlayers(Buffer &$buffer, Result &$result)
|
||||
{
|
||||
// By default there are 0 players
|
||||
$players = 0;
|
||||
|
||||
// Iterate over the players until we run out
|
||||
while (($id = $buffer->readInt8()) != 32) {
|
||||
$result->addPlayer('id', $id);
|
||||
$result->addPlayer('ping', $buffer->readInt16());
|
||||
$result->addPlayer('name', $buffer->readString());
|
||||
$result->addPlayer('clantag_pos', $buffer->readInt8());
|
||||
$result->addPlayer('clantag', $buffer->readString());
|
||||
$result->addPlayer('bot', $buffer->readInt8());
|
||||
$players++;
|
||||
}
|
||||
|
||||
// Let's add in the current players as a result
|
||||
$result->add('numplayers', $players);
|
||||
|
||||
// Free some memory
|
||||
unset($id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle parsing extra player data
|
||||
*
|
||||
* @param Buffer $buffer
|
||||
* @param Result $result
|
||||
*/
|
||||
protected function parsePlayersExtra(Buffer &$buffer, Result &$result)
|
||||
{
|
||||
// Iterate over the extra player info
|
||||
while (($id = $buffer->readInt8()) != 32) {
|
||||
$result->addPlayer('total_xp', $buffer->readFloat32());
|
||||
$result->addPlayer('teamname', $buffer->readString());
|
||||
$result->addPlayer('total_kills', $buffer->readInt32());
|
||||
$result->addPlayer('total_deaths', $buffer->readInt32());
|
||||
}
|
||||
|
||||
// @todo: Add team stuff
|
||||
|
||||
// Free some memory
|
||||
unset($id);
|
||||
}
|
||||
}
|
43
GameQ/Protocols/Ffe.php
Normal file
43
GameQ/Protocols/Ffe.php
Normal file
|
@ -0,0 +1,43 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is part of GameQ.
|
||||
*
|
||||
* GameQ is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GameQ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace GameQ\Protocols;
|
||||
|
||||
/**
|
||||
* Class Ffe - Fortress Forever
|
||||
*
|
||||
* @package GameQ\Protocols
|
||||
* @author Austin Bischoff <austin@codebeard.com>
|
||||
*/
|
||||
class Ffe extends Source
|
||||
{
|
||||
|
||||
/**
|
||||
* String name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name = 'ffe';
|
||||
|
||||
/**
|
||||
* Longer string name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name_long = "Fortress Forever";
|
||||
}
|
243
GameQ/Protocols/Ffow.php
Normal file
243
GameQ/Protocols/Ffow.php
Normal file
|
@ -0,0 +1,243 @@
|
|||
<?php
|
||||
|
||||
|
||||
namespace GameQ\Protocols;
|
||||
|
||||
use GameQ\Protocol;
|
||||
use GameQ\Buffer;
|
||||
use GameQ\Result;
|
||||
use GameQ\Exception\Protocol as Exception;
|
||||
|
||||
/**
|
||||
* Frontlines Fuel of War Protocol Class
|
||||
*
|
||||
* Handles processing ffow servers
|
||||
*
|
||||
* Class is incomplete due to lack of players to test against.
|
||||
* http://wiki.hlsw.net/index.php/FFOW_Protocol
|
||||
*
|
||||
* @package GameQ\Protocols
|
||||
*/
|
||||
class Ffow extends Protocol
|
||||
{
|
||||
/**
|
||||
* Array of packets we want to look up.
|
||||
* Each key should correspond to a defined method in this or a parent class
|
||||
*
|
||||
* @type array
|
||||
*/
|
||||
protected $packets = [
|
||||
self::PACKET_CHALLENGE => "\xFF\xFF\xFF\xFF\x57",
|
||||
self::PACKET_RULES => "\xFF\xFF\xFF\xFF\x56%s",
|
||||
self::PACKET_PLAYERS => "\xFF\xFF\xFF\xFF\x55%s",
|
||||
self::PACKET_INFO => "\xFF\xFF\xFF\xFF\x46\x4C\x53\x51",
|
||||
];
|
||||
|
||||
/**
|
||||
* Use the response flag to figure out what method to run
|
||||
*
|
||||
* @type array
|
||||
*/
|
||||
protected $responses = [
|
||||
"\xFF\xFF\xFF\xFF\x49\x02" => 'processInfo', // I
|
||||
"\xFF\xFF\xFF\xFF\x45\x00" => 'processRules', // E
|
||||
"\xFF\xFF\xFF\xFF\x44\x00" => 'processPlayers', // D
|
||||
];
|
||||
|
||||
/**
|
||||
* The query protocol used to make the call
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $protocol = 'ffow';
|
||||
|
||||
/**
|
||||
* String name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name = 'ffow';
|
||||
|
||||
/**
|
||||
* Longer string name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name_long = "Frontlines Fuel of War";
|
||||
|
||||
/**
|
||||
* The client join link
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $join_link = null;
|
||||
|
||||
/**
|
||||
* query_port = client_port + 2
|
||||
*
|
||||
* @type int
|
||||
*/
|
||||
protected $port_diff = 2;
|
||||
|
||||
/**
|
||||
* Normalize settings for this protocol
|
||||
*
|
||||
* @type array
|
||||
*/
|
||||
protected $normalize = [
|
||||
// General
|
||||
'general' => [
|
||||
// target => source
|
||||
'gametype' => 'gamemode',
|
||||
'hostname' => 'servername',
|
||||
'mapname' => 'mapname',
|
||||
'maxplayers' => 'max_players',
|
||||
'mod' => 'modname',
|
||||
'numplayers' => 'num_players',
|
||||
'password' => 'password',
|
||||
],
|
||||
// Individual
|
||||
'player' => [
|
||||
'name' => 'name',
|
||||
'ping' => 'ping',
|
||||
'score' => 'frags',
|
||||
],
|
||||
];
|
||||
|
||||
/**
|
||||
* Parse the challenge response and apply it to all the packet types
|
||||
*
|
||||
* @param \GameQ\Buffer $challenge_buffer
|
||||
*
|
||||
* @return bool
|
||||
* @throws \GameQ\Exception\Protocol
|
||||
*/
|
||||
public function challengeParseAndApply(Buffer $challenge_buffer)
|
||||
{
|
||||
// Burn padding
|
||||
$challenge_buffer->skip(5);
|
||||
|
||||
// Apply the challenge and return
|
||||
return $this->challengeApply($challenge_buffer->read(4));
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle response from the server
|
||||
*
|
||||
* @return mixed
|
||||
* @throws Exception
|
||||
*/
|
||||
public function processResponse()
|
||||
{
|
||||
// Init results
|
||||
$results = [];
|
||||
|
||||
foreach ($this->packets_response as $response) {
|
||||
$buffer = new Buffer($response);
|
||||
|
||||
// Figure out what packet response this is for
|
||||
$response_type = $buffer->read(6);
|
||||
|
||||
// Figure out which packet response this is
|
||||
if (!array_key_exists($response_type, $this->responses)) {
|
||||
throw new Exception(__METHOD__ . " response type '" . bin2hex($response_type) . "' is not valid");
|
||||
}
|
||||
|
||||
// Now we need to call the proper method
|
||||
$results = array_merge(
|
||||
$results,
|
||||
call_user_func_array([$this, $this->responses[$response_type]], [$buffer])
|
||||
);
|
||||
|
||||
unset($buffer);
|
||||
}
|
||||
|
||||
return $results;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle processing the server information
|
||||
*
|
||||
* @param Buffer $buffer
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function processInfo(Buffer $buffer)
|
||||
{
|
||||
// Set the result to a new result instance
|
||||
$result = new Result();
|
||||
|
||||
$result->add('servername', $buffer->readString());
|
||||
$result->add('mapname', $buffer->readString());
|
||||
$result->add('modname', $buffer->readString());
|
||||
$result->add('gamemode', $buffer->readString());
|
||||
$result->add('description', $buffer->readString());
|
||||
$result->add('version', $buffer->readString());
|
||||
$result->add('port', $buffer->readInt16());
|
||||
$result->add('num_players', $buffer->readInt8());
|
||||
$result->add('max_players', $buffer->readInt8());
|
||||
$result->add('dedicated', $buffer->readInt8());
|
||||
$result->add('os', $buffer->readInt8());
|
||||
$result->add('password', $buffer->readInt8());
|
||||
$result->add('anticheat', $buffer->readInt8());
|
||||
$result->add('average_fps', $buffer->readInt8());
|
||||
$result->add('round', $buffer->readInt8());
|
||||
$result->add('max_rounds', $buffer->readInt8());
|
||||
$result->add('time_left', $buffer->readInt16());
|
||||
|
||||
unset($buffer);
|
||||
|
||||
return $result->fetch();
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle processing the server rules
|
||||
*
|
||||
* @param Buffer $buffer
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function processRules(Buffer $buffer)
|
||||
{
|
||||
// Set the result to a new result instance
|
||||
$result = new Result();
|
||||
|
||||
// Burn extra header
|
||||
$buffer->skip(1);
|
||||
|
||||
// Read rules until we run out of buffer
|
||||
while ($buffer->getLength()) {
|
||||
$key = $buffer->readString();
|
||||
// Check for map
|
||||
if (strstr($key, "Map:")) {
|
||||
$result->addSub("maplist", "name", $buffer->readString());
|
||||
} else // Regular rule
|
||||
{
|
||||
$result->add($key, $buffer->readString());
|
||||
}
|
||||
}
|
||||
|
||||
unset($buffer);
|
||||
|
||||
return $result->fetch();
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle processing of player data
|
||||
*
|
||||
* @todo: Build this out when there is a server with players to test against
|
||||
*
|
||||
* @param Buffer $buffer
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function processPlayers(Buffer $buffer)
|
||||
{
|
||||
// Set the result to a new result instance
|
||||
$result = new Result();
|
||||
|
||||
unset($buffer);
|
||||
|
||||
return $result->fetch();
|
||||
}
|
||||
}
|
181
GameQ/Protocols/Gamespy.php
Normal file
181
GameQ/Protocols/Gamespy.php
Normal file
|
@ -0,0 +1,181 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is part of GameQ.
|
||||
*
|
||||
* GameQ is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GameQ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace GameQ\Protocols;
|
||||
|
||||
use GameQ\Protocol;
|
||||
use GameQ\Buffer;
|
||||
use GameQ\Result;
|
||||
use \GameQ\Exception\Protocol as Exception;
|
||||
|
||||
/**
|
||||
* GameSpy Protocol class
|
||||
*
|
||||
* @author Austin Bischoff <austin@codebeard.com>
|
||||
*/
|
||||
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
|
||||
*
|
||||
* @type array
|
||||
*/
|
||||
protected $packets = [
|
||||
self::PACKET_STATUS => "\x5C\x73\x74\x61\x74\x75\x73\x5C",
|
||||
];
|
||||
|
||||
/**
|
||||
* The query protocol used to make the call
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $protocol = 'gamespy';
|
||||
|
||||
/**
|
||||
* String name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name = 'gamespy';
|
||||
|
||||
/**
|
||||
* Longer string name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name_long = "GameSpy Server";
|
||||
|
||||
/**
|
||||
* The client join link
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $join_link = null;
|
||||
|
||||
/**
|
||||
* Process the response for this protocol
|
||||
*
|
||||
* @return array
|
||||
* @throws Exception
|
||||
*/
|
||||
public function processResponse()
|
||||
{
|
||||
// Holds the processed packets so we can sort them in case they come in an unordered
|
||||
$processed = [];
|
||||
|
||||
// Iterate over the packets
|
||||
foreach ($this->packets_response as $response) {
|
||||
// Check to see if we had a preg_match error
|
||||
if (($match = preg_match("#^(.*)\\\\queryid\\\\([^\\\\]+)(\\\\|$)#", $response, $matches)) === false
|
||||
|| $match != 1
|
||||
) {
|
||||
throw new Exception(__METHOD__ . " An error occurred while parsing the packets for 'queryid'");
|
||||
}
|
||||
|
||||
// Multiply so we move the decimal point out of the way, if there is one
|
||||
$key = (int)(floatval($matches[2]) * 1000);
|
||||
|
||||
// Add this packet to the processed
|
||||
$processed[$key] = $matches[1];
|
||||
}
|
||||
|
||||
// Sort the new array to make sure the keys (query ids) are in the proper order
|
||||
ksort($processed, SORT_NUMERIC);
|
||||
|
||||
// Create buffer and offload processing
|
||||
return $this->processStatus(new Buffer(implode('', $processed)));
|
||||
}
|
||||
|
||||
/*
|
||||
* Internal methods
|
||||
*/
|
||||
|
||||
/**
|
||||
* Handle processing the status buffer
|
||||
*
|
||||
* @param Buffer $buffer
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function processStatus(Buffer $buffer)
|
||||
{
|
||||
// Set the result to a new result instance
|
||||
$result = new Result();
|
||||
|
||||
// By default dedicted
|
||||
$result->add('dedicated', 1);
|
||||
|
||||
// Lets peek and see if the data starts with a \
|
||||
if ($buffer->lookAhead(1) == '\\') {
|
||||
// Burn the first one
|
||||
$buffer->skip(1);
|
||||
}
|
||||
|
||||
// Explode the data
|
||||
$data = explode('\\', $buffer->getBuffer());
|
||||
|
||||
// No longer needed
|
||||
unset($buffer);
|
||||
|
||||
// Init some vars
|
||||
$numPlayers = 0;
|
||||
$numTeams = 0;
|
||||
|
||||
$itemCount = count($data);
|
||||
|
||||
// Check to make sure we have more than 1 item in the array before trying to loop
|
||||
if (count($data) > 1) {
|
||||
// Now lets loop the array since we have items
|
||||
for ($x = 0; $x < $itemCount; $x += 2) {
|
||||
// Set some local vars
|
||||
$key = $data[$x];
|
||||
$val = $data[$x + 1];
|
||||
|
||||
// Check for <variable>_<count> variable (i.e players)
|
||||
if (($suffix = strrpos($key, '_')) !== false && is_numeric(substr($key, $suffix + 1))) {
|
||||
// See if this is a team designation
|
||||
if (substr($key, 0, $suffix) == 'teamname') {
|
||||
$result->addTeam('teamname', $val);
|
||||
$numTeams++;
|
||||
} else {
|
||||
// Its a player
|
||||
if (substr($key, 0, $suffix) == 'playername') {
|
||||
$numPlayers++;
|
||||
}
|
||||
$result->addPlayer(substr($key, 0, $suffix), utf8_encode($val));
|
||||
}
|
||||
} else {
|
||||
// Regular variable so just add the value.
|
||||
$result->add($key, $val);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add the player and team count
|
||||
$result->add('num_players', $numPlayers);
|
||||
$result->add('num_teams', $numTeams);
|
||||
|
||||
// Unset some stuff to free up memory
|
||||
unset($data, $key, $val, $suffix, $x, $itemCount);
|
||||
|
||||
// Return the result
|
||||
return $result->fetch();
|
||||
}
|
||||
}
|
269
GameQ/Protocols/Gamespy2.php
Normal file
269
GameQ/Protocols/Gamespy2.php
Normal file
|
@ -0,0 +1,269 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is part of GameQ.
|
||||
*
|
||||
* GameQ is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GameQ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace GameQ\Protocols;
|
||||
|
||||
use GameQ\Exception\Protocol as Exception;
|
||||
use GameQ\Protocol;
|
||||
use GameQ\Buffer;
|
||||
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.
|
||||
*
|
||||
* @author Austin Bischoff <austin@codebeard.com>
|
||||
*/
|
||||
class Gamespy2 extends Protocol
|
||||
{
|
||||
|
||||
/**
|
||||
* Define the state of this class
|
||||
*
|
||||
* @type int
|
||||
*/
|
||||
protected $state = self::STATE_BETA;
|
||||
|
||||
/**
|
||||
* Array of packets we want to look up.
|
||||
* Each key should correspond to a defined method in this or a parent class
|
||||
*
|
||||
* @type array
|
||||
*/
|
||||
protected $packets = [
|
||||
self::PACKET_DETAILS => "\xFE\xFD\x00\x43\x4F\x52\x59\xFF\x00\x00",
|
||||
self::PACKET_PLAYERS => "\xFE\xFD\x00\x43\x4F\x52\x58\x00\xFF\xFF",
|
||||
];
|
||||
|
||||
/**
|
||||
* Use the response flag to figure out what method to run
|
||||
*
|
||||
* @type array
|
||||
*/
|
||||
protected $responses = [
|
||||
"\x00\x43\x4F\x52\x59" => "processDetails",
|
||||
"\x00\x43\x4F\x52\x58" => "processPlayers",
|
||||
];
|
||||
|
||||
/**
|
||||
* The query protocol used to make the call
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $protocol = 'gamespy2';
|
||||
|
||||
/**
|
||||
* String name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name = 'gamespy2';
|
||||
|
||||
/**
|
||||
* Longer string name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name_long = "GameSpy2 Server";
|
||||
|
||||
/**
|
||||
* The client join link
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $join_link = null;
|
||||
|
||||
/**
|
||||
* Normalize settings for this protocol
|
||||
*
|
||||
* @type array
|
||||
*/
|
||||
protected $normalize = [
|
||||
// General
|
||||
'general' => [
|
||||
// target => source
|
||||
'dedicated' => 'dedicated',
|
||||
'gametype' => 'gametype',
|
||||
'hostname' => 'hostname',
|
||||
'mapname' => 'mapname',
|
||||
'maxplayers' => 'maxplayers',
|
||||
'mod' => 'mod',
|
||||
'numplayers' => 'numplayers',
|
||||
'password' => 'password',
|
||||
],
|
||||
];
|
||||
|
||||
|
||||
/**
|
||||
* Process the response
|
||||
*
|
||||
* @return array
|
||||
* @throws Exception
|
||||
*/
|
||||
public function processResponse()
|
||||
{
|
||||
|
||||
// Will hold the packets after sorting
|
||||
$packets = [];
|
||||
|
||||
// We need to pre-sort these for split packets so we can do extra work where needed
|
||||
foreach ($this->packets_response as $response) {
|
||||
$buffer = new Buffer($response);
|
||||
|
||||
// Pull out the header
|
||||
$header = $buffer->read(5);
|
||||
|
||||
// Add the packet to the proper section, we will combine later
|
||||
$packets[$header][] = $buffer->getBuffer();
|
||||
}
|
||||
|
||||
unset($buffer);
|
||||
|
||||
$results = [];
|
||||
|
||||
// Now let's iterate and process
|
||||
foreach ($packets as $header => $packetGroup) {
|
||||
// Figure out which packet response this is
|
||||
if (!array_key_exists($header, $this->responses)) {
|
||||
throw new Exception(__METHOD__ . " response type '" . bin2hex($header) . "' is not valid");
|
||||
}
|
||||
|
||||
// Now we need to call the proper method
|
||||
$results = array_merge(
|
||||
$results,
|
||||
call_user_func_array([$this, $this->responses[$header]], [new Buffer(implode($packetGroup))])
|
||||
);
|
||||
}
|
||||
|
||||
unset($packets);
|
||||
|
||||
return $results;
|
||||
}
|
||||
|
||||
/*
|
||||
* Internal methods
|
||||
*/
|
||||
|
||||
/**
|
||||
* Handles processing the details data into a usable format
|
||||
*
|
||||
* @param \GameQ\Buffer $buffer
|
||||
*
|
||||
* @return array
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function processDetails(Buffer $buffer)
|
||||
{
|
||||
|
||||
// Set the result to a new result instance
|
||||
$result = new Result();
|
||||
|
||||
// We go until we hit an empty key
|
||||
while ($buffer->getLength()) {
|
||||
$key = $buffer->readString();
|
||||
if (strlen($key) == 0) {
|
||||
break;
|
||||
}
|
||||
$result->add($key, utf8_encode($buffer->readString()));
|
||||
}
|
||||
|
||||
unset($buffer);
|
||||
|
||||
return $result->fetch();
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles processing the players data into a usable format
|
||||
*
|
||||
* @param \GameQ\Buffer $buffer
|
||||
*
|
||||
* @return array
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function processPlayers(Buffer $buffer)
|
||||
{
|
||||
|
||||
// Set the result to a new result instance
|
||||
$result = new Result();
|
||||
|
||||
// Skip the header
|
||||
$buffer->skip(1);
|
||||
|
||||
// Players are first
|
||||
$this->parsePlayerTeam('players', $buffer, $result);
|
||||
|
||||
// Teams are next
|
||||
$this->parsePlayerTeam('teams', $buffer, $result);
|
||||
|
||||
unset($buffer);
|
||||
|
||||
return $result->fetch();
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the player/team info returned from the player call
|
||||
*
|
||||
* @param string $dataType
|
||||
* @param \GameQ\Buffer $buffer
|
||||
* @param \GameQ\Result $result
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function parsePlayerTeam($dataType, Buffer &$buffer, Result &$result)
|
||||
{
|
||||
|
||||
// Do count
|
||||
$result->add('num_' . $dataType, $buffer->readInt8());
|
||||
|
||||
// Variable names
|
||||
$varNames = [];
|
||||
|
||||
// Loop until we run out of length
|
||||
while ($buffer->getLength()) {
|
||||
$varNames[] = str_replace('_', '', $buffer->readString());
|
||||
|
||||
if ($buffer->lookAhead() === "\x00") {
|
||||
$buffer->skip();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if there are any value entries
|
||||
if ($buffer->lookAhead() == "\x00") {
|
||||
$buffer->skip();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the values
|
||||
while ($buffer->getLength() > 4) {
|
||||
foreach ($varNames as $varName) {
|
||||
$result->addSub($dataType, utf8_encode($varName), utf8_encode($buffer->readString()));
|
||||
}
|
||||
if ($buffer->lookAhead() === "\x00") {
|
||||
$buffer->skip();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
340
GameQ/Protocols/Gamespy3.php
Normal file
340
GameQ/Protocols/Gamespy3.php
Normal file
|
@ -0,0 +1,340 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is part of GameQ.
|
||||
*
|
||||
* GameQ is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GameQ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace GameQ\Protocols;
|
||||
|
||||
use GameQ\Protocol;
|
||||
use GameQ\Buffer;
|
||||
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.
|
||||
*
|
||||
* @author Austin Bischoff <austin@codebeard.com>
|
||||
*/
|
||||
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
|
||||
*
|
||||
* @type array
|
||||
*/
|
||||
protected $packets = [
|
||||
self::PACKET_CHALLENGE => "\xFE\xFD\x09\x10\x20\x30\x40",
|
||||
self::PACKET_ALL => "\xFE\xFD\x00\x10\x20\x30\x40%s\xFF\xFF\xFF\x01",
|
||||
];
|
||||
|
||||
/**
|
||||
* The query protocol used to make the call
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $protocol = 'gamespy3';
|
||||
|
||||
/**
|
||||
* String name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name = 'gamespy3';
|
||||
|
||||
/**
|
||||
* Longer string name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name_long = "GameSpy3 Server";
|
||||
|
||||
/**
|
||||
* The client join link
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $join_link = null;
|
||||
|
||||
/**
|
||||
* This defines the split between the server info and player/team info.
|
||||
* This value can vary by game. This value is the default split.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $packetSplit = "/\\x00\\x00\\x01/m";
|
||||
|
||||
/**
|
||||
* Parse the challenge response and apply it to all the packet types
|
||||
*
|
||||
* @param \GameQ\Buffer $challenge_buffer
|
||||
*
|
||||
* @return bool
|
||||
* @throws \GameQ\Exception\Protocol
|
||||
*/
|
||||
public function challengeParseAndApply(Buffer $challenge_buffer)
|
||||
{
|
||||
// Pull out the challenge
|
||||
$challenge = substr(preg_replace("/[^0-9\-]/si", "", $challenge_buffer->getBuffer()), 1);
|
||||
|
||||
// By default, no challenge result (see #197)
|
||||
$challenge_result = '';
|
||||
|
||||
// Check for valid challenge (see #197)
|
||||
if ($challenge) {
|
||||
// Encode chellenge result
|
||||
$challenge_result = sprintf(
|
||||
"%c%c%c%c",
|
||||
($challenge >> 24),
|
||||
($challenge >> 16),
|
||||
($challenge >> 8),
|
||||
($challenge >> 0)
|
||||
);
|
||||
}
|
||||
|
||||
// Apply the challenge and return
|
||||
return $this->challengeApply($challenge_result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the response
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function processResponse()
|
||||
{
|
||||
|
||||
// Holds the processed packets
|
||||
$processed = [];
|
||||
|
||||
// Iterate over the packets
|
||||
foreach ($this->packets_response as $response) {
|
||||
// Make a buffer
|
||||
$buffer = new Buffer($response, Buffer::NUMBER_TYPE_BIGENDIAN);
|
||||
|
||||
// Packet type = 0
|
||||
$buffer->readInt8();
|
||||
|
||||
// Session Id
|
||||
$buffer->readInt32();
|
||||
|
||||
// We need to burn the splitnum\0 because it is not used
|
||||
$buffer->skip(9);
|
||||
|
||||
// Get the id
|
||||
$id = $buffer->readInt8();
|
||||
|
||||
// Burn next byte not sure what it is used for
|
||||
$buffer->skip(1);
|
||||
|
||||
// Add this packet to the processed
|
||||
$processed[$id] = $buffer->getBuffer();
|
||||
|
||||
unset($buffer, $id);
|
||||
}
|
||||
|
||||
// Sort packets, reset index
|
||||
ksort($processed);
|
||||
|
||||
// Offload cleaning up the packets if they happen to be split
|
||||
$packets = $this->cleanPackets(array_values($processed));
|
||||
|
||||
// Split the packets by type general and the rest (i.e. players & teams)
|
||||
$split = preg_split($this->packetSplit, implode('', $packets));
|
||||
|
||||
// Create a new result
|
||||
$result = new Result();
|
||||
|
||||
// Assign variable due to pass by reference in PHP 7+
|
||||
$buffer = new Buffer($split[0], Buffer::NUMBER_TYPE_BIGENDIAN);
|
||||
|
||||
// First key should be server details and rules
|
||||
$this->processDetails($buffer, $result);
|
||||
|
||||
// The rest should be the player and team information, if it exists
|
||||
if (array_key_exists(1, $split)) {
|
||||
$buffer = new Buffer($split[1], Buffer::NUMBER_TYPE_BIGENDIAN);
|
||||
$this->processPlayersAndTeams($buffer, $result);
|
||||
}
|
||||
|
||||
unset($buffer);
|
||||
|
||||
return $result->fetch();
|
||||
}
|
||||
|
||||
/*
|
||||
* Internal methods
|
||||
*/
|
||||
|
||||
/**
|
||||
* Handles cleaning up packets since the responses can be a bit "dirty"
|
||||
*
|
||||
* @param array $packets
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function cleanPackets(array $packets = [])
|
||||
{
|
||||
|
||||
// Get the number of packets
|
||||
$packetCount = count($packets);
|
||||
|
||||
// Compare last var of current packet with first var of next packet
|
||||
// On a partial match, remove last var from current packet,
|
||||
// variable header from next packet
|
||||
for ($i = 0, $x = $packetCount; $i < $x - 1; $i++) {
|
||||
// First packet
|
||||
$fst = substr($packets[$i], 0, -1);
|
||||
// Second packet
|
||||
$snd = $packets[$i + 1];
|
||||
// Get last variable from first packet
|
||||
$fstvar = substr($fst, strrpos($fst, "\x00") + 1);
|
||||
// Get first variable from last packet
|
||||
$snd = substr($snd, strpos($snd, "\x00") + 2);
|
||||
$sndvar = substr($snd, 0, strpos($snd, "\x00"));
|
||||
// Check if fstvar is a substring of sndvar
|
||||
// If so, remove it from the first string
|
||||
if (!empty($fstvar) && strpos($sndvar, $fstvar) !== false) {
|
||||
$packets[$i] = preg_replace("#(\\x00[^\\x00]+\\x00)$#", "\x00", $packets[$i]);
|
||||
}
|
||||
}
|
||||
|
||||
// Now let's loop the return and remove any dupe prefixes
|
||||
for ($x = 1; $x < $packetCount; $x++) {
|
||||
$buffer = new Buffer($packets[$x], Buffer::NUMBER_TYPE_BIGENDIAN);
|
||||
|
||||
$prefix = $buffer->readString();
|
||||
|
||||
// Check to see if the return before has the same prefix present
|
||||
if ($prefix != null && strstr($packets[($x - 1)], $prefix)) {
|
||||
// Update the return by removing the prefix plus 2 chars
|
||||
$packets[$x] = substr(str_replace($prefix, '', $packets[$x]), 2);
|
||||
}
|
||||
|
||||
unset($buffer);
|
||||
}
|
||||
|
||||
unset($x, $i, $snd, $sndvar, $fst, $fstvar);
|
||||
|
||||
// Return cleaned packets
|
||||
return $packets;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles processing the details data into a usable format
|
||||
*
|
||||
* @param \GameQ\Buffer $buffer
|
||||
* @param \GameQ\Result $result
|
||||
*/
|
||||
protected function processDetails(Buffer &$buffer, Result &$result)
|
||||
{
|
||||
|
||||
// We go until we hit an empty key
|
||||
while ($buffer->getLength()) {
|
||||
$key = $buffer->readString();
|
||||
if (strlen($key) == 0) {
|
||||
break;
|
||||
}
|
||||
$result->add($key, utf8_encode($buffer->readString()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles processing the player and team data into a usable format
|
||||
*
|
||||
* @param \GameQ\Buffer $buffer
|
||||
* @param \GameQ\Result $result
|
||||
*/
|
||||
protected function processPlayersAndTeams(Buffer &$buffer, Result &$result)
|
||||
{
|
||||
|
||||
/*
|
||||
* Explode the data into groups. First is player, next is team (item_t)
|
||||
* Each group should be as follows:
|
||||
*
|
||||
* [0] => item_
|
||||
* [1] => information for item_
|
||||
* ...
|
||||
*/
|
||||
$data = explode("\x00\x00", $buffer->getBuffer());
|
||||
|
||||
// By default item_group is blank, this will be set for each loop thru the data
|
||||
$item_group = '';
|
||||
|
||||
// By default the item_type is blank, this will be set on each loop
|
||||
$item_type = '';
|
||||
|
||||
// Save count as variable
|
||||
$count = count($data);
|
||||
|
||||
// Loop through all of the $data for information and pull it out into the result
|
||||
for ($x = 0; $x < $count - 1; $x++) {
|
||||
// Pull out the item
|
||||
$item = $data[$x];
|
||||
// If this is an empty item, move on
|
||||
if ($item == '' || $item == "\x00") {
|
||||
continue;
|
||||
}
|
||||
/*
|
||||
* Left as reference:
|
||||
*
|
||||
* Each block of player_ and team_t have preceding junk chars
|
||||
*
|
||||
* player_ is actually \x01player_
|
||||
* team_t is actually \x00\x02team_t
|
||||
*
|
||||
* Probably a by-product of the change to exploding the data from the original.
|
||||
*
|
||||
* For now we just strip out these characters
|
||||
*/
|
||||
// Check to see if $item has a _ at the end, this is player info
|
||||
if (substr($item, -1) == '_') {
|
||||
// Set the item group
|
||||
$item_group = 'players';
|
||||
// Set the item type, rip off any trailing stuff and bad chars
|
||||
$item_type = rtrim(str_replace("\x01", '', $item), '_');
|
||||
} elseif (substr($item, -2) == '_t') {
|
||||
// Check to see if $item has a _t at the end, this is team info
|
||||
// Set the item group
|
||||
$item_group = 'teams';
|
||||
// Set the item type, rip off any trailing stuff and bad chars
|
||||
$item_type = rtrim(str_replace(["\x00", "\x02"], '', $item), '_t');
|
||||
} else {
|
||||
// We can assume it is data belonging to a previously defined item
|
||||
|
||||
// Make a temp buffer so we have easier access to the data
|
||||
$buf_temp = new Buffer($item, Buffer::NUMBER_TYPE_BIGENDIAN);
|
||||
// Get the values
|
||||
while ($buf_temp->getLength()) {
|
||||
// No value so break the loop, end of string
|
||||
if (($val = $buf_temp->readString()) === '') {
|
||||
break;
|
||||
}
|
||||
// Add the value to the proper item in the correct group
|
||||
$result->addSub($item_group, $item_type, utf8_encode(trim($val)));
|
||||
}
|
||||
// Unset our buffer
|
||||
unset($buf_temp);
|
||||
}
|
||||
}
|
||||
// Free up some memory
|
||||
unset($count, $data, $item, $item_group, $item_type, $val);
|
||||
}
|
||||
}
|
34
GameQ/Protocols/Gamespy4.php
Normal file
34
GameQ/Protocols/Gamespy4.php
Normal file
|
@ -0,0 +1,34 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is part of GameQ.
|
||||
*
|
||||
* GameQ is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GameQ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace GameQ\Protocols;
|
||||
|
||||
/**
|
||||
* GameSpy4 Protocol Class
|
||||
*
|
||||
* By all accounts GameSpy 4 seems to be GameSpy 3.
|
||||
*
|
||||
* References:
|
||||
* http://www.deletedscreen.com/?p=951
|
||||
* http://pastebin.com/2zZFDuTd
|
||||
*
|
||||
* @author Austin Bischoff <austin@codebeard.com>
|
||||
*/
|
||||
class Gamespy4 extends Gamespy3
|
||||
{
|
||||
}
|
42
GameQ/Protocols/Gmod.php
Normal file
42
GameQ/Protocols/Gmod.php
Normal file
|
@ -0,0 +1,42 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is part of GameQ.
|
||||
*
|
||||
* GameQ is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GameQ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace GameQ\Protocols;
|
||||
|
||||
/**
|
||||
* Class Gmod
|
||||
*
|
||||
* @package GameQ\Protocols
|
||||
* @author Austin Bischoff <austin@codebeard.com>
|
||||
*/
|
||||
class Gmod extends Source
|
||||
{
|
||||
/**
|
||||
* String name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name = 'gmod';
|
||||
|
||||
/**
|
||||
* Longer string name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name_long = "Garry's Mod";
|
||||
}
|
42
GameQ/Protocols/Grav.php
Normal file
42
GameQ/Protocols/Grav.php
Normal file
|
@ -0,0 +1,42 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is part of GameQ.
|
||||
*
|
||||
* GameQ is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GameQ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace GameQ\Protocols;
|
||||
|
||||
/**
|
||||
* Grav Online Protocol Class
|
||||
*
|
||||
* @package GameQ\Protocols
|
||||
* @author Austin Bischoff <austin@codebeard.com>
|
||||
*/
|
||||
class Grav extends Source
|
||||
{
|
||||
/**
|
||||
* String name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name = 'grav';
|
||||
|
||||
/**
|
||||
* Longer string name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name_long = "GRAV Online";
|
||||
}
|
173
GameQ/Protocols/Gta5m.php
Normal file
173
GameQ/Protocols/Gta5m.php
Normal file
|
@ -0,0 +1,173 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is part of GameQ.
|
||||
*
|
||||
* GameQ is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GameQ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace GameQ\Protocols;
|
||||
|
||||
use GameQ\Buffer;
|
||||
use GameQ\Exception\Protocol as Exception;
|
||||
use GameQ\Protocol;
|
||||
use GameQ\Result;
|
||||
|
||||
/**
|
||||
* GTA Five M Protocol Class
|
||||
*
|
||||
* Server base can be found at https://fivem.net/
|
||||
*
|
||||
* Based on code found at https://github.com/LiquidObsidian/fivereborn-query
|
||||
*
|
||||
* @author Austin Bischoff <austin@codebeard.com>
|
||||
*/
|
||||
class Gta5m extends Protocol
|
||||
{
|
||||
|
||||
/**
|
||||
* Array of packets we want to look up.
|
||||
* Each key should correspond to a defined method in this or a parent class
|
||||
*
|
||||
* @type array
|
||||
*/
|
||||
protected $packets = [
|
||||
self::PACKET_STATUS => "\xFF\xFF\xFF\xFFgetinfo xxx",
|
||||
];
|
||||
|
||||
/**
|
||||
* Use the response flag to figure out what method to run
|
||||
*
|
||||
* @type array
|
||||
*/
|
||||
protected $responses = [
|
||||
"\xFF\xFF\xFF\xFFinfoResponse" => "processStatus",
|
||||
];
|
||||
|
||||
/**
|
||||
* The query protocol used to make the call
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $protocol = 'gta5m';
|
||||
|
||||
/**
|
||||
* String name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name = 'gta5m';
|
||||
|
||||
/**
|
||||
* Longer string name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name_long = "GTA Five M";
|
||||
|
||||
/**
|
||||
* Normalize settings for this protocol
|
||||
*
|
||||
* @type array
|
||||
*/
|
||||
protected $normalize = [
|
||||
// General
|
||||
'general' => [
|
||||
// target => source
|
||||
'gametype' => 'gametype',
|
||||
'hostname' => 'hostname',
|
||||
'mapname' => 'mapname',
|
||||
'maxplayers' => 'sv_maxclients',
|
||||
'mod' => 'gamename',
|
||||
'numplayers' => 'clients',
|
||||
'password' => 'privateClients',
|
||||
],
|
||||
];
|
||||
|
||||
/**
|
||||
* Process the response
|
||||
*
|
||||
* @return array
|
||||
* @throws \GameQ\Exception\Protocol
|
||||
*/
|
||||
public function processResponse()
|
||||
{
|
||||
// In case it comes back as multiple packets (it shouldn't)
|
||||
$buffer = new Buffer(implode('', $this->packets_response));
|
||||
|
||||
// Figure out what packet response this is for
|
||||
$response_type = $buffer->readString(PHP_EOL);
|
||||
|
||||
// Figure out which packet response this is
|
||||
if (empty($response_type) || !array_key_exists($response_type, $this->responses)) {
|
||||
throw new Exception(__METHOD__ . " response type '{$response_type}' is not valid");
|
||||
}
|
||||
|
||||
// Offload the call
|
||||
$results = call_user_func_array([$this, $this->responses[$response_type]], [$buffer]);
|
||||
|
||||
return $results;
|
||||
}
|
||||
|
||||
/*
|
||||
* Internal methods
|
||||
*/
|
||||
|
||||
/**
|
||||
* Handle processing the status response
|
||||
*
|
||||
* @param Buffer $buffer
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function processStatus(Buffer $buffer)
|
||||
{
|
||||
// Set the result to a new result instance
|
||||
$result = new Result();
|
||||
|
||||
// Lets peek and see if the data starts with a \
|
||||
if ($buffer->lookAhead(1) == '\\') {
|
||||
// Burn the first one
|
||||
$buffer->skip(1);
|
||||
}
|
||||
|
||||
// Explode the data
|
||||
$data = explode('\\', $buffer->getBuffer());
|
||||
|
||||
// No longer needed
|
||||
unset($buffer);
|
||||
|
||||
$itemCount = count($data);
|
||||
|
||||
// Now lets loop the array
|
||||
for ($x = 0; $x < $itemCount; $x += 2) {
|
||||
// Set some local vars
|
||||
$key = $data[$x];
|
||||
$val = $data[$x + 1];
|
||||
|
||||
if (in_array($key, ['challenge'])) {
|
||||
continue; // skip
|
||||
}
|
||||
|
||||
// Regular variable so just add the value.
|
||||
$result->add($key, $val);
|
||||
}
|
||||
|
||||
/*var_dump($data);
|
||||
var_dump($result->fetch());
|
||||
|
||||
exit;*/
|
||||
|
||||
return $result->fetch();
|
||||
}
|
||||
}
|
163
GameQ/Protocols/Gtan.php
Normal file
163
GameQ/Protocols/Gtan.php
Normal file
|
@ -0,0 +1,163 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is part of GameQ.
|
||||
*
|
||||
* GameQ is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GameQ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
namespace GameQ\Protocols;
|
||||
|
||||
use GameQ\Exception\Protocol as Exception;
|
||||
use GameQ\Result;
|
||||
use GameQ\Server;
|
||||
|
||||
/**
|
||||
* Grand Theft Auto Network Protocol Class
|
||||
* https://stats.gtanet.work/
|
||||
*
|
||||
* Result from this call should be a header + JSON response
|
||||
*
|
||||
* References:
|
||||
* - https://master.gtanet.work/apiservers
|
||||
*
|
||||
* @author Austin Bischoff <austin@codebeard.com>
|
||||
*/
|
||||
class Gtan extends Http
|
||||
{
|
||||
/**
|
||||
* Packets to send
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $packets = [
|
||||
//self::PACKET_STATUS => "GET /apiservers HTTP/1.0\r\nHost: master.gtanet.work\r\nAccept: */*\r\n\r\n",
|
||||
self::PACKET_STATUS => "GET /gtan/api.php?ip=%s&raw HTTP/1.0\r\nHost: multiplayerhosting.info\r\nAccept: */*\r\n\r\n",
|
||||
];
|
||||
|
||||
/**
|
||||
* Http protocol is SSL
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $transport = self::TRANSPORT_SSL;
|
||||
|
||||
/**
|
||||
* The protocol being used
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $protocol = 'gtan';
|
||||
|
||||
/**
|
||||
* String name of this protocol class
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $name = 'gtan';
|
||||
|
||||
/**
|
||||
* Longer string name of this protocol class
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $name_long = "Grand Theft Auto Network";
|
||||
|
||||
/**
|
||||
* Holds the real ip so we can overwrite it back
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $realIp = null;
|
||||
|
||||
protected $realPortQuery = null;
|
||||
|
||||
/**
|
||||
* Normalize some items
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $normalize = [
|
||||
// General
|
||||
'general' => [
|
||||
// target => source
|
||||
'dedicated' => 'dedicated',
|
||||
'hostname' => 'hostname',
|
||||
'mapname' => 'map',
|
||||
'mod' => 'mod',
|
||||
'maxplayers' => 'maxplayers',
|
||||
'numplayers' => 'numplayers',
|
||||
'password' => 'password',
|
||||
],
|
||||
];
|
||||
|
||||
public function beforeSend(Server $server)
|
||||
{
|
||||
// Loop over the packets and update them
|
||||
foreach ($this->packets as $packetType => $packet) {
|
||||
// Fill out the packet with the server info
|
||||
$this->packets[$packetType] = sprintf($packet, $server->ip . ':' . $server->port_query);
|
||||
}
|
||||
|
||||
$this->realIp = $server->ip;
|
||||
$this->realPortQuery = $server->port_query;
|
||||
|
||||
// Override the existing settings
|
||||
//$server->ip = 'master.gtanet.work';
|
||||
$server->ip = 'multiplayerhosting.info';
|
||||
$server->port_query = 443;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the response
|
||||
*
|
||||
* @return array
|
||||
* @throws Exception
|
||||
*/
|
||||
public function processResponse()
|
||||
{
|
||||
// No response, assume offline
|
||||
if (empty($this->packets_response)) {
|
||||
return [
|
||||
'gq_address' => $this->realIp,
|
||||
'gq_port_query' => $this->realPortQuery,
|
||||
];
|
||||
}
|
||||
|
||||
// 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 Exception("JSON response from Gtan protocol is invalid.");
|
||||
}
|
||||
|
||||
$result = new Result();
|
||||
|
||||
// Server is always dedicated
|
||||
$result->add('dedicated', 1);
|
||||
|
||||
$result->add('gq_address', $this->realIp);
|
||||
$result->add('gq_port_query', $this->realPortQuery);
|
||||
|
||||
// Add server items
|
||||
$result->add('hostname', $json->ServerName);
|
||||
$result->add('serverversion', $json->ServerVersion);
|
||||
$result->add('map', ((!empty($json->Map)) ? $json->Map : 'Los Santos/Blaine Country'));
|
||||
$result->add('mod', $json->Gamemode);
|
||||
$result->add('password', (int)$json->Passworded);
|
||||
$result->add('numplayers', $json->CurrentPlayers);
|
||||
$result->add('maxplayers', $json->MaxPlayers);
|
||||
|
||||
return $result->fetch();
|
||||
}
|
||||
}
|
164
GameQ/Protocols/Gtar.php
Normal file
164
GameQ/Protocols/Gtar.php
Normal file
|
@ -0,0 +1,164 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is part of GameQ.
|
||||
*
|
||||
* GameQ is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GameQ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
namespace GameQ\Protocols;
|
||||
|
||||
use GameQ\Exception\Protocol as Exception;
|
||||
use GameQ\Result;
|
||||
use GameQ\Server;
|
||||
|
||||
/**
|
||||
* Grand Theft Auto Rage Protocol Class
|
||||
* https://rage.mp/masterlist/
|
||||
*
|
||||
* Result from this call should be a header + JSON response
|
||||
*
|
||||
* @author K700 <admin@fianna.ru>
|
||||
* @author Austin Bischoff <austin@codebeard.com>
|
||||
*/
|
||||
class Gtar extends Http
|
||||
{
|
||||
/**
|
||||
* Packets to send
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $packets = [
|
||||
self::PACKET_STATUS => "GET /master/ HTTP/1.0\r\nHost: cdn.rage.mp\r\nAccept: */*\r\n\r\n",
|
||||
];
|
||||
|
||||
/**
|
||||
* Http protocol is SSL
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $transport = self::TRANSPORT_SSL;
|
||||
|
||||
/**
|
||||
* The protocol being used
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $protocol = 'gtar';
|
||||
|
||||
/**
|
||||
* String name of this protocol class
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $name = 'gtar';
|
||||
|
||||
/**
|
||||
* Longer string name of this protocol class
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $name_long = "Grand Theft Auto Rage";
|
||||
|
||||
/**
|
||||
* Holds the real ip so we can overwrite it back
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $realIp = null;
|
||||
|
||||
protected $realPortQuery = null;
|
||||
|
||||
/**
|
||||
* Normalize some items
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $normalize = [
|
||||
// General
|
||||
'general' => [
|
||||
// target => source
|
||||
'dedicated' => 'dedicated',
|
||||
'hostname' => 'hostname',
|
||||
'mod' => 'mod',
|
||||
'maxplayers' => 'maxplayers',
|
||||
'numplayers' => 'numplayers',
|
||||
],
|
||||
];
|
||||
|
||||
public function beforeSend(Server $server)
|
||||
{
|
||||
// Loop over the packets and update them
|
||||
foreach ($this->packets as $packetType => $packet) {
|
||||
// Fill out the packet with the server info
|
||||
$this->packets[$packetType] = sprintf($packet, $server->ip . ':' . $server->port_query);
|
||||
}
|
||||
|
||||
$this->realIp = $server->ip;
|
||||
$this->realPortQuery = $server->port_query;
|
||||
|
||||
// Override the existing settings
|
||||
$server->ip = 'cdn.rage.mp';
|
||||
$server->port_query = 443;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the response
|
||||
*
|
||||
* @return array
|
||||
* @throws Exception
|
||||
*/
|
||||
public function processResponse()
|
||||
{
|
||||
// No response, assume offline
|
||||
if (empty($this->packets_response)) {
|
||||
return [
|
||||
'gq_address' => $this->realIp,
|
||||
'gq_port_query' => $this->realPortQuery,
|
||||
];
|
||||
}
|
||||
|
||||
// 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 Exception("JSON response from Gtar protocol is invalid.");
|
||||
}
|
||||
|
||||
$address = $this->realIp.':'.$this->realPortQuery;
|
||||
$server = $json->$address;
|
||||
|
||||
if (empty($server)) {
|
||||
return [
|
||||
'gq_address' => $this->realIp,
|
||||
'gq_port_query' => $this->realPortQuery,
|
||||
];
|
||||
}
|
||||
|
||||
$result = new Result();
|
||||
|
||||
// Server is always dedicated
|
||||
$result->add('dedicated', 1);
|
||||
|
||||
$result->add('gq_address', $this->realIp);
|
||||
$result->add('gq_port_query', $this->realPortQuery);
|
||||
|
||||
// Add server items
|
||||
$result->add('hostname', $server->name);
|
||||
$result->add('mod', $server->gamemode);
|
||||
$result->add('numplayers', $server->players);
|
||||
$result->add('maxplayers', $server->maxplayers);
|
||||
|
||||
return $result->fetch();
|
||||
}
|
||||
}
|
42
GameQ/Protocols/Hl2dm.php
Normal file
42
GameQ/Protocols/Hl2dm.php
Normal file
|
@ -0,0 +1,42 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is part of GameQ.
|
||||
*
|
||||
* GameQ is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GameQ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace GameQ\Protocols;
|
||||
|
||||
/**
|
||||
* Class Hl2dm
|
||||
*
|
||||
* @package GameQ\Protocols
|
||||
* @author Austin Bischoff <austin@codebeard.com>
|
||||
*/
|
||||
class Hl2dm extends Source
|
||||
{
|
||||
/**
|
||||
* String name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name = 'hl2dm';
|
||||
|
||||
/**
|
||||
* Longer string name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name_long = "Half Life 2: Deathmatch";
|
||||
}
|
67
GameQ/Protocols/Http.php
Normal file
67
GameQ/Protocols/Http.php
Normal file
|
@ -0,0 +1,67 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is part of GameQ.
|
||||
*
|
||||
* GameQ is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GameQ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace GameQ\Protocols;
|
||||
|
||||
use GameQ\Protocol;
|
||||
|
||||
/**
|
||||
* Class Http
|
||||
*
|
||||
* Generic HTTP protocol class. Useful for making http based requests
|
||||
*
|
||||
* @package GameQ\Protocols
|
||||
* @author Austin Bischoff <austin@codebeard.com>
|
||||
*/
|
||||
abstract class Http extends Protocol
|
||||
{
|
||||
/**
|
||||
* The query protocol used to make the call
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $protocol = 'http';
|
||||
|
||||
/**
|
||||
* String name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name = 'http';
|
||||
|
||||
/**
|
||||
* Longer string name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name_long = "Generic HTTP protocol";
|
||||
|
||||
/**
|
||||
* Http protocol is TCP
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $transport = self::TRANSPORT_TCP;
|
||||
|
||||
/**
|
||||
* The client join link
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $join_link = null;
|
||||
}
|
42
GameQ/Protocols/Hurtworld.php
Normal file
42
GameQ/Protocols/Hurtworld.php
Normal file
|
@ -0,0 +1,42 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is part of GameQ.
|
||||
*
|
||||
* GameQ is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GameQ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace GameQ\Protocols;
|
||||
|
||||
/**
|
||||
* Class Hurtworld
|
||||
*
|
||||
* @package GameQ\Protocols
|
||||
* @author Nikolay Ipanyuk <rostov114@gmail.com>
|
||||
* @author Austin Bischoff <austin@codebeard.com>
|
||||
*/
|
||||
class Hurtworld extends Source
|
||||
{
|
||||
/**
|
||||
* String name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name = 'hurtworld';
|
||||
/**
|
||||
* Longer string name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name_long = "Hurtworld";
|
||||
}
|
42
GameQ/Protocols/Insurgency.php
Normal file
42
GameQ/Protocols/Insurgency.php
Normal file
|
@ -0,0 +1,42 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is part of GameQ.
|
||||
*
|
||||
* GameQ is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GameQ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace GameQ\Protocols;
|
||||
|
||||
/**
|
||||
* Class Insurgency
|
||||
*
|
||||
* @package GameQ\Protocols
|
||||
* @author Austin Bischoff <austin@codebeard.com>
|
||||
*/
|
||||
class Insurgency extends Source
|
||||
{
|
||||
/**
|
||||
* String name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name = 'insurgency';
|
||||
|
||||
/**
|
||||
* Longer string name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name_long = "Insurgency";
|
||||
}
|
49
GameQ/Protocols/Insurgencysand.php
Normal file
49
GameQ/Protocols/Insurgencysand.php
Normal file
|
@ -0,0 +1,49 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is part of GameQ.
|
||||
*
|
||||
* GameQ is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GameQ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace GameQ\Protocols;
|
||||
|
||||
/**
|
||||
* Insurgency Sandstorm Class
|
||||
*
|
||||
* @package GameQ\Protocols
|
||||
* @author Austin Bischoff <austin@codebeard.com>
|
||||
*/
|
||||
class Insurgencysand extends Source
|
||||
{
|
||||
/**
|
||||
* String name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name = 'insurgencysand';
|
||||
|
||||
/**
|
||||
* Longer string name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name_long = "Insurgency: Sandstorm";
|
||||
|
||||
/**
|
||||
* query_port = client_port + 29
|
||||
*
|
||||
* @type int
|
||||
*/
|
||||
protected $port_diff = 29;
|
||||
}
|
42
GameQ/Protocols/Jediacademy.php
Normal file
42
GameQ/Protocols/Jediacademy.php
Normal file
|
@ -0,0 +1,42 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is part of GameQ.
|
||||
*
|
||||
* GameQ is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GameQ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace GameQ\Protocols;
|
||||
|
||||
/**
|
||||
* Jedi Academy Protocol Class
|
||||
*
|
||||
* @package GameQ\Protocols
|
||||
* @author Austin Bischoff <austin@codebeard.com>
|
||||
*/
|
||||
class Jediacademy extends Quake3
|
||||
{
|
||||
/**
|
||||
* String name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name = 'jediacademy';
|
||||
|
||||
/**
|
||||
* Longer string name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name_long = "Star Wars Jedi Knight: Jedi Academy";
|
||||
}
|
42
GameQ/Protocols/Jedioutcast.php
Normal file
42
GameQ/Protocols/Jedioutcast.php
Normal file
|
@ -0,0 +1,42 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is part of GameQ.
|
||||
*
|
||||
* GameQ is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GameQ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace GameQ\Protocols;
|
||||
|
||||
/**
|
||||
* Jedi Outcast Protocol Class
|
||||
*
|
||||
* @package GameQ\Protocols
|
||||
* @author Austin Bischoff <austin@codebeard.com>
|
||||
*/
|
||||
class Jedioutcast extends Quake3
|
||||
{
|
||||
/**
|
||||
* String name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name = 'jedioutcast';
|
||||
|
||||
/**
|
||||
* Longer string name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name_long = "Star Wars Jedi Knight II: Jedi Outcast";
|
||||
}
|
127
GameQ/Protocols/Justcause2.php
Normal file
127
GameQ/Protocols/Justcause2.php
Normal file
|
@ -0,0 +1,127 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is part of GameQ.
|
||||
*
|
||||
* GameQ is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GameQ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace GameQ\Protocols;
|
||||
|
||||
use GameQ\Buffer;
|
||||
use GameQ\Result;
|
||||
|
||||
/**
|
||||
* Just Cause 2 Multiplayer Protocol Class
|
||||
*
|
||||
* Special thanks to Woet for some insight on packing
|
||||
*
|
||||
* @package GameQ\Protocols
|
||||
* @author Austin Bischoff <austin@codebeard.com>
|
||||
*/
|
||||
class Justcause2 extends Gamespy4
|
||||
{
|
||||
/**
|
||||
* String name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name = 'justcause2';
|
||||
|
||||
/**
|
||||
* Longer string name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name_long = "Just Cause 2 Multiplayer";
|
||||
|
||||
/**
|
||||
* The client join link
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $join_link = "steam://connect/%s:%d/";
|
||||
|
||||
/**
|
||||
* Change the packets used
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $packets = [
|
||||
self::PACKET_CHALLENGE => "\xFE\xFD\x09\x10\x20\x30\x40",
|
||||
self::PACKET_ALL => "\xFE\xFD\x00\x10\x20\x30\x40%s\xFF\xFF\xFF\x02",
|
||||
];
|
||||
|
||||
/**
|
||||
* Override the packet split
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $packetSplit = "/\\x00\\x00\\x00/m";
|
||||
|
||||
/**
|
||||
* Normalize settings for this protocol
|
||||
*
|
||||
* @type array
|
||||
*/
|
||||
protected $normalize = [
|
||||
'general' => [
|
||||
// target => source
|
||||
'dedicated' => 'dedicated',
|
||||
'gametype' => 'gametype',
|
||||
'hostname' => 'hostname',
|
||||
'mapname' => 'mapname',
|
||||
'maxplayers' => 'maxplayers',
|
||||
'numplayers' => 'numplayers',
|
||||
'password' => 'password',
|
||||
],
|
||||
// Individual
|
||||
'player' => [
|
||||
'name' => 'name',
|
||||
'ping' => 'ping',
|
||||
],
|
||||
];
|
||||
|
||||
/**
|
||||
* Overload so we can add in some static data points
|
||||
*
|
||||
* @param Buffer $buffer
|
||||
* @param Result $result
|
||||
*/
|
||||
protected function processDetails(Buffer &$buffer, Result &$result)
|
||||
{
|
||||
parent::processDetails($buffer, $result);
|
||||
|
||||
// Add in map
|
||||
$result->add('mapname', 'Panau');
|
||||
$result->add('dedicated', 'true');
|
||||
}
|
||||
|
||||
/**
|
||||
* Override the parent, this protocol is returned differently
|
||||
*
|
||||
* @param Buffer $buffer
|
||||
* @param Result $result
|
||||
*
|
||||
* @see Gamespy3::processPlayersAndTeams()
|
||||
*/
|
||||
protected function processPlayersAndTeams(Buffer &$buffer, Result &$result)
|
||||
{
|
||||
// Loop until we run out of data
|
||||
while ($buffer->getLength()) {
|
||||
$result->addPlayer('name', $buffer->readString());
|
||||
$result->addPlayer('steamid', $buffer->readString());
|
||||
$result->addPlayer('ping', $buffer->readInt16());
|
||||
}
|
||||
}
|
||||
}
|
50
GameQ/Protocols/Justcause3.php
Normal file
50
GameQ/Protocols/Justcause3.php
Normal file
|
@ -0,0 +1,50 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is part of GameQ.
|
||||
*
|
||||
* GameQ is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GameQ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace GameQ\Protocols;
|
||||
|
||||
/**
|
||||
* Class Just Cause 3
|
||||
*
|
||||
* @package GameQ\Protocols
|
||||
* @author Austin Bischoff <austin@codebeard.com>
|
||||
*/
|
||||
class Justcause3 extends Source
|
||||
{
|
||||
|
||||
/**
|
||||
* String name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name = 'justcause3';
|
||||
|
||||
/**
|
||||
* Longer string name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name_long = "Just Cause 3";
|
||||
|
||||
/**
|
||||
* Query port = client_port + 1
|
||||
*
|
||||
* @type int
|
||||
*/
|
||||
protected $port_diff = 1;
|
||||
}
|
96
GameQ/Protocols/Killingfloor.php
Normal file
96
GameQ/Protocols/Killingfloor.php
Normal file
|
@ -0,0 +1,96 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is part of GameQ.
|
||||
*
|
||||
* GameQ is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GameQ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace GameQ\Protocols;
|
||||
|
||||
use GameQ\Buffer;
|
||||
use GameQ\Result;
|
||||
|
||||
/**
|
||||
* Class Killing floor
|
||||
*
|
||||
* @package GameQ\Protocols
|
||||
* @author Austin Bischoff <austin@codebeard.com>
|
||||
*/
|
||||
class Killingfloor extends Unreal2
|
||||
{
|
||||
|
||||
/**
|
||||
* String name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name = 'killing floor';
|
||||
|
||||
/**
|
||||
* Longer string name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name_long = "Killing Floor";
|
||||
|
||||
/**
|
||||
* query_port = client_port + 1
|
||||
*
|
||||
* @type int
|
||||
*/
|
||||
protected $port_diff = 1;
|
||||
|
||||
/**
|
||||
* The client join link
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $join_link = "steam://connect/%s:%d/";
|
||||
|
||||
/**
|
||||
* Overload the default detail process since this version is different
|
||||
*
|
||||
* @param \GameQ\Buffer $buffer
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function processDetails(Buffer $buffer)
|
||||
{
|
||||
|
||||
// Set the result to a new result instance
|
||||
$result = new Result();
|
||||
|
||||
$result->add('serverid', $buffer->readInt32()); // 0
|
||||
$result->add('serverip', $buffer->readPascalString(1)); // empty
|
||||
$result->add('gameport', $buffer->readInt32());
|
||||
$result->add('queryport', $buffer->readInt32()); // 0
|
||||
|
||||
// We burn the first char since it is not always correct with the hostname
|
||||
$buffer->skip(1);
|
||||
|
||||
// Read as a regular string since the length is incorrect (what we skipped earlier)
|
||||
$result->add('servername', utf8_encode($buffer->readString()));
|
||||
|
||||
// The rest is read as normal
|
||||
$result->add('mapname', utf8_encode($buffer->readPascalString(1)));
|
||||
$result->add('gametype', $buffer->readPascalString(1));
|
||||
$result->add('numplayers', $buffer->readInt32());
|
||||
$result->add('maxplayers', $buffer->readInt32());
|
||||
$result->add('currentwave', $buffer->readInt32());
|
||||
|
||||
unset($buffer);
|
||||
|
||||
return $result->fetch();
|
||||
}
|
||||
}
|
51
GameQ/Protocols/Killingfloor2.php
Normal file
51
GameQ/Protocols/Killingfloor2.php
Normal file
|
@ -0,0 +1,51 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is part of GameQ.
|
||||
*
|
||||
* GameQ is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GameQ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace GameQ\Protocols;
|
||||
|
||||
/**
|
||||
* Class Killing floor
|
||||
*
|
||||
* @package GameQ\Protocols
|
||||
* @author Austin Bischoff <austin@codebeard.com>
|
||||
*/
|
||||
class Killingfloor2 extends Source
|
||||
{
|
||||
|
||||
/**
|
||||
* String name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name = 'killing floor 2';
|
||||
|
||||
/**
|
||||
* Longer string name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name_long = "Killing Floor 2";
|
||||
|
||||
/**
|
||||
* query_port = client_port + 19238
|
||||
* 27015 = 7777 + 19238
|
||||
*
|
||||
* @type int
|
||||
*/
|
||||
protected $port_diff = 19238;
|
||||
}
|
42
GameQ/Protocols/L4d.php
Normal file
42
GameQ/Protocols/L4d.php
Normal file
|
@ -0,0 +1,42 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is part of GameQ.
|
||||
*
|
||||
* GameQ is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GameQ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace GameQ\Protocols;
|
||||
|
||||
/**
|
||||
* Class L4d
|
||||
*
|
||||
* @package GameQ\Protocols
|
||||
* @author Austin Bischoff <austin@codebeard.com>
|
||||
*/
|
||||
class L4d extends Source
|
||||
{
|
||||
/**
|
||||
* String name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name = 'l4d';
|
||||
|
||||
/**
|
||||
* Longer string name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name_long = "Left 4 Dead";
|
||||
}
|
42
GameQ/Protocols/L4d2.php
Normal file
42
GameQ/Protocols/L4d2.php
Normal file
|
@ -0,0 +1,42 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is part of GameQ.
|
||||
*
|
||||
* GameQ is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GameQ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace GameQ\Protocols;
|
||||
|
||||
/**
|
||||
* Class L4d2
|
||||
*
|
||||
* @package GameQ\Protocols
|
||||
* @author Austin Bischoff <austin@codebeard.com>
|
||||
*/
|
||||
class L4d2 extends Source
|
||||
{
|
||||
/**
|
||||
* String name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name = 'l4d2';
|
||||
|
||||
/**
|
||||
* Longer string name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name_long = "Left 4 Dead 2";
|
||||
}
|
214
GameQ/Protocols/Lhmp.php
Normal file
214
GameQ/Protocols/Lhmp.php
Normal file
|
@ -0,0 +1,214 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is part of GameQ.
|
||||
*
|
||||
* GameQ is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GameQ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace GameQ\Protocols;
|
||||
|
||||
use GameQ\Protocol;
|
||||
use GameQ\Buffer;
|
||||
use GameQ\Result;
|
||||
use GameQ\Exception\Protocol as Exception;
|
||||
|
||||
/**
|
||||
* Lost Heaven Protocol class
|
||||
*
|
||||
* Reference: http://lh-mp.eu/wiki/index.php/Query_System
|
||||
*
|
||||
* @author Austin Bischoff <austin@codebeard.com>
|
||||
*/
|
||||
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
|
||||
*
|
||||
* @type array
|
||||
*/
|
||||
protected $packets = [
|
||||
self::PACKET_DETAILS => "LHMPo",
|
||||
self::PACKET_PLAYERS => "LHMPp",
|
||||
];
|
||||
|
||||
/**
|
||||
* Use the response flag to figure out what method to run
|
||||
*
|
||||
* @type array
|
||||
*/
|
||||
protected $responses = [
|
||||
"LHMPo" => "processDetails",
|
||||
"LHMPp" => "processPlayers",
|
||||
];
|
||||
|
||||
/**
|
||||
* The query protocol used to make the call
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $protocol = 'lhmp';
|
||||
|
||||
/**
|
||||
* String name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name = 'lhmp';
|
||||
|
||||
/**
|
||||
* Longer string name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name_long = "Lost Heaven";
|
||||
|
||||
/**
|
||||
* query_port = client_port + 1
|
||||
*
|
||||
* @type int
|
||||
*/
|
||||
protected $port_diff = 1;
|
||||
|
||||
/**
|
||||
* Normalize settings for this protocol
|
||||
*
|
||||
* @type array
|
||||
*/
|
||||
protected $normalize = [
|
||||
// General
|
||||
'general' => [
|
||||
// target => source
|
||||
'gametype' => 'gamemode',
|
||||
'hostname' => 'servername',
|
||||
'mapname' => 'mapname',
|
||||
'maxplayers' => 'maxplayers',
|
||||
'numplayers' => 'numplayers',
|
||||
'password' => 'password',
|
||||
],
|
||||
// Individual
|
||||
'player' => [
|
||||
'name' => 'name',
|
||||
],
|
||||
];
|
||||
|
||||
/**
|
||||
* Process the response
|
||||
*
|
||||
* @return array
|
||||
* @throws \GameQ\Exception\Protocol
|
||||
*/
|
||||
public function processResponse()
|
||||
{
|
||||
// Will hold the packets after sorting
|
||||
$packets = [];
|
||||
|
||||
// We need to pre-sort these for split packets so we can do extra work where needed
|
||||
foreach ($this->packets_response as $response) {
|
||||
$buffer = new Buffer($response);
|
||||
|
||||
// Pull out the header
|
||||
$header = $buffer->read(5);
|
||||
|
||||
// Add the packet to the proper section, we will combine later
|
||||
$packets[$header][] = $buffer->getBuffer();
|
||||
}
|
||||
|
||||
unset($buffer);
|
||||
|
||||
$results = [];
|
||||
|
||||
// Now let's iterate and process
|
||||
foreach ($packets as $header => $packetGroup) {
|
||||
// Figure out which packet response this is
|
||||
if (!array_key_exists($header, $this->responses)) {
|
||||
throw new Exception(__METHOD__ . " response type '{$header}' is not valid");
|
||||
}
|
||||
|
||||
// Now we need to call the proper method
|
||||
$results = array_merge(
|
||||
$results,
|
||||
call_user_func_array([$this, $this->responses[$header]], [new Buffer(implode($packetGroup))])
|
||||
);
|
||||
}
|
||||
|
||||
unset($packets);
|
||||
|
||||
return $results;
|
||||
}
|
||||
|
||||
/*
|
||||
* Internal methods
|
||||
*/
|
||||
|
||||
/**
|
||||
* Handles processing the details data into a usable format
|
||||
*
|
||||
* @param Buffer $buffer
|
||||
*
|
||||
* @return array
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function processDetails(Buffer $buffer)
|
||||
{
|
||||
|
||||
// Set the result to a new result instance
|
||||
$result = new Result();
|
||||
|
||||
$result->add('protocol', $buffer->readString());
|
||||
$result->add('password', $buffer->readString());
|
||||
$result->add('numplayers', $buffer->readInt16());
|
||||
$result->add('maxplayers', $buffer->readInt16());
|
||||
$result->add('servername', utf8_encode($buffer->readPascalString()));
|
||||
$result->add('gamemode', $buffer->readPascalString());
|
||||
$result->add('website', utf8_encode($buffer->readPascalString()));
|
||||
$result->add('mapname', utf8_encode($buffer->readPascalString()));
|
||||
|
||||
unset($buffer);
|
||||
|
||||
return $result->fetch();
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles processing the player data into a usable format
|
||||
*
|
||||
* @param Buffer $buffer
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function processPlayers(Buffer $buffer)
|
||||
{
|
||||
|
||||
// Set the result to a new result instance
|
||||
$result = new Result();
|
||||
|
||||
// Get the number of players
|
||||
$result->add('numplayers', $buffer->readInt16());
|
||||
|
||||
// Parse players
|
||||
while ($buffer->getLength()) {
|
||||
// Player id
|
||||
if (($id = $buffer->readInt16()) !== 0) {
|
||||
// Add the results
|
||||
$result->addPlayer('id', $id);
|
||||
$result->addPlayer('name', utf8_encode($buffer->readPascalString()));
|
||||
}
|
||||
}
|
||||
|
||||
unset($buffer, $id);
|
||||
|
||||
return $result->fetch();
|
||||
}
|
||||
}
|
87
GameQ/Protocols/Minecraft.php
Normal file
87
GameQ/Protocols/Minecraft.php
Normal file
|
@ -0,0 +1,87 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is part of GameQ.
|
||||
*
|
||||
* GameQ is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GameQ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace GameQ\Protocols;
|
||||
|
||||
/**
|
||||
* Minecraft Protocol Class
|
||||
*
|
||||
* Thanks to https://github.com/xPaw/PHP-Minecraft-Query for helping me realize this is
|
||||
* Gamespy 3 Protocol. Make sure you enable the items below for it to work.
|
||||
*
|
||||
* Information from original author:
|
||||
* Instructions
|
||||
*
|
||||
* Before using this class, you need to make sure that your server is running GS4 status listener.
|
||||
*
|
||||
* Look for those settings in server.properties:
|
||||
*
|
||||
* enable-query=true
|
||||
* query.port=25565
|
||||
*
|
||||
* @package GameQ\Protocols
|
||||
*
|
||||
* @author Austin Bischoff <austin@codebeard.com>
|
||||
*/
|
||||
class Minecraft extends Gamespy3
|
||||
{
|
||||
|
||||
/**
|
||||
* String name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name = 'minecraft';
|
||||
|
||||
/**
|
||||
* Longer string name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name_long = "Minecraft";
|
||||
|
||||
/**
|
||||
* The client join link
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $join_link = "minecraft://%s:%d/";
|
||||
|
||||
/**
|
||||
* Normalize settings for this protocol
|
||||
*
|
||||
* @type array
|
||||
*/
|
||||
protected $normalize = [
|
||||
// General
|
||||
'general' => [
|
||||
// target => source
|
||||
'dedicated' => 'dedicated',
|
||||
'gametype' => 'game_id',
|
||||
'hostname' => 'hostname',
|
||||
'mapname' => 'map',
|
||||
'maxplayers' => 'maxplayers',
|
||||
'numplayers' => 'numplayers',
|
||||
'password' => 'password',
|
||||
],
|
||||
// Individual
|
||||
'player' => [
|
||||
'name' => 'player',
|
||||
],
|
||||
];
|
||||
}
|
44
GameQ/Protocols/Minecraftpe.php
Normal file
44
GameQ/Protocols/Minecraftpe.php
Normal file
|
@ -0,0 +1,44 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is part of GameQ.
|
||||
*
|
||||
* GameQ is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GameQ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace GameQ\Protocols;
|
||||
|
||||
/**
|
||||
* Minecraft PE (BE) Protocol Class
|
||||
*
|
||||
* @package GameQ\Protocols
|
||||
*
|
||||
* @author Austin Bischoff <austin@codebeard.com>
|
||||
*/
|
||||
class Minecraftpe extends Minecraft
|
||||
{
|
||||
|
||||
/**
|
||||
* String name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name = 'minecraftpe';
|
||||
|
||||
/**
|
||||
* Longer string name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name_long = "MinecraftPE";
|
||||
}
|
79
GameQ/Protocols/Mohaa.php
Normal file
79
GameQ/Protocols/Mohaa.php
Normal file
|
@ -0,0 +1,79 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is part of GameQ.
|
||||
*
|
||||
* GameQ is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GameQ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace GameQ\Protocols;
|
||||
|
||||
/**
|
||||
* Medal of honor: Allied Assault Protocol Class
|
||||
*
|
||||
* @package GameQ\Protocols
|
||||
* @author Bram <https://github.com/Stormyy>
|
||||
* @author Austin Bischoff <austin@codebeard.com>
|
||||
*/
|
||||
class Mohaa extends Gamespy
|
||||
{
|
||||
/**
|
||||
* String name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name = 'mohaa';
|
||||
|
||||
/**
|
||||
* Longer string name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name_long = "Medal of honor: Allied Assault";
|
||||
|
||||
/**
|
||||
* Normalize settings for this protocol
|
||||
*
|
||||
* @type array
|
||||
*/
|
||||
protected $normalize = [
|
||||
'general' => [
|
||||
// target => source
|
||||
'dedicated' => 'dedicated',
|
||||
'gametype' => 'gametype',
|
||||
'hostname' => 'hostname',
|
||||
'mapname' => 'mapname',
|
||||
'maxplayers' => 'maxplayers',
|
||||
'numplayers' => 'numplayers',
|
||||
'password' => 'password',
|
||||
],
|
||||
// Individual
|
||||
'player' => [
|
||||
'name' => 'player',
|
||||
'score' => 'frags',
|
||||
'ping' => 'ping',
|
||||
],
|
||||
];
|
||||
|
||||
/**
|
||||
* Query port is always the client port + 97 in MOHAA
|
||||
*
|
||||
* @param int $clientPort
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function findQueryPort($clientPort)
|
||||
{
|
||||
return $clientPort + 97;
|
||||
}
|
||||
}
|
53
GameQ/Protocols/Mordhau.php
Normal file
53
GameQ/Protocols/Mordhau.php
Normal file
|
@ -0,0 +1,53 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is part of GameQ.
|
||||
*
|
||||
* GameQ is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GameQ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace GameQ\Protocols;
|
||||
|
||||
/**
|
||||
* Class MORDHAU
|
||||
*
|
||||
* @package GameQ\Protocols
|
||||
* @author Wilson Jesus <>
|
||||
*/
|
||||
class Mordhau extends Source
|
||||
{
|
||||
|
||||
/**
|
||||
* String name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name = 'mordhau';
|
||||
|
||||
/**
|
||||
* Longer string name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name_long = "MORDHAU";
|
||||
|
||||
#protected $port = 7777;
|
||||
|
||||
/**
|
||||
* query_port = client_port + 19238
|
||||
* 27015 = 7777 + 19238
|
||||
*
|
||||
* @type int
|
||||
*/
|
||||
#protected $port_diff = 19238;
|
||||
}
|
59
GameQ/Protocols/Mta.php
Normal file
59
GameQ/Protocols/Mta.php
Normal file
|
@ -0,0 +1,59 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is part of GameQ.
|
||||
*
|
||||
* GameQ is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GameQ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace GameQ\Protocols;
|
||||
|
||||
/**
|
||||
* Class Multi Theft Auto
|
||||
*
|
||||
* @package GameQ\Protocols
|
||||
*
|
||||
* @author Marcel Bößendörfer <m.boessendoerfer@marbis.net>
|
||||
* @author Austin Bischoff <austin@codebeard.com>
|
||||
*/
|
||||
class Mta extends Ase
|
||||
{
|
||||
|
||||
/**
|
||||
* String name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name = 'mta';
|
||||
|
||||
/**
|
||||
* Longer string name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name_long = "Multi Theft Auto";
|
||||
|
||||
/**
|
||||
* query_port = client_port + 123
|
||||
*
|
||||
* @type int
|
||||
*/
|
||||
protected $port_diff = 123;
|
||||
|
||||
/**
|
||||
* The client join link
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $join_link = "mtasa://%s:%d/";
|
||||
}
|
194
GameQ/Protocols/Mumble.php
Normal file
194
GameQ/Protocols/Mumble.php
Normal file
|
@ -0,0 +1,194 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is part of GameQ.
|
||||
*
|
||||
* GameQ is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GameQ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace GameQ\Protocols;
|
||||
|
||||
use GameQ\Protocol;
|
||||
use GameQ\Result;
|
||||
use GameQ\Exception\Protocol as Exception;
|
||||
|
||||
/**
|
||||
* Mumble Protocol class
|
||||
*
|
||||
* References:
|
||||
* https://github.com/edmundask/MurmurQuery - Thanks to skylord123
|
||||
*
|
||||
* @author Austin Bischoff <austin@codebeard.com>
|
||||
*/
|
||||
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
|
||||
*
|
||||
* @type array
|
||||
*/
|
||||
protected $packets = [
|
||||
self::PACKET_ALL => "\x6A\x73\x6F\x6E", // JSON packet
|
||||
];
|
||||
|
||||
/**
|
||||
* The transport mode for this protocol is TCP
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $transport = self::TRANSPORT_TCP;
|
||||
|
||||
/**
|
||||
* The query protocol used to make the call
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $protocol = 'mumble';
|
||||
|
||||
/**
|
||||
* String name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name = 'mumble';
|
||||
|
||||
/**
|
||||
* Longer string name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name_long = "Mumble Server";
|
||||
|
||||
/**
|
||||
* The client join link
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $join_link = "mumble://%s:%d/";
|
||||
|
||||
/**
|
||||
* 27800 = 64738 - 36938
|
||||
*
|
||||
* @type int
|
||||
*/
|
||||
protected $port_diff = -36938;
|
||||
|
||||
/**
|
||||
* Normalize settings for this protocol
|
||||
*
|
||||
* @type array
|
||||
*/
|
||||
protected $normalize = [
|
||||
// General
|
||||
'general' => [
|
||||
'dedicated' => 'dedicated',
|
||||
'gametype' => 'gametype',
|
||||
'hostname' => 'name',
|
||||
'numplayers' => 'numplayers',
|
||||
'maxplayers' => 'x_gtmurmur_max_users',
|
||||
],
|
||||
// Player
|
||||
'player' => [
|
||||
'name' => 'name',
|
||||
'ping' => 'tcpPing',
|
||||
'team' => 'channel',
|
||||
'time' => 'onlinesecs',
|
||||
],
|
||||
// Team
|
||||
'team' => [
|
||||
'name' => 'name',
|
||||
],
|
||||
];
|
||||
|
||||
/**
|
||||
* Process the response
|
||||
*
|
||||
* @return array
|
||||
* @throws \GameQ\Exception\Protocol
|
||||
*/
|
||||
public function processResponse()
|
||||
{
|
||||
|
||||
// Try to json_decode, make it into an array
|
||||
if (($data = json_decode(implode('', $this->packets_response), true)) === null) {
|
||||
throw new Exception(__METHOD__ . " Unable to decode JSON data.");
|
||||
}
|
||||
|
||||
// Set the result to a new result instance
|
||||
$result = new Result();
|
||||
|
||||
// Always dedicated
|
||||
$result->add('dedicated', 1);
|
||||
|
||||
// Let's iterate over the response items, there are a lot
|
||||
foreach ($data as $key => $value) {
|
||||
// Ignore root for now, that is where all of the channel/player info is housed
|
||||
if (in_array($key, ['root'])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Add them as is
|
||||
$result->add($key, $value);
|
||||
}
|
||||
|
||||
// Offload the channel and user parsing
|
||||
$this->processChannelsAndUsers($data['root'], $result);
|
||||
|
||||
unset($data);
|
||||
|
||||
// Manually set the number of players
|
||||
$result->add('numplayers', count($result->get('players')));
|
||||
|
||||
return $result->fetch();
|
||||
}
|
||||
|
||||
/*
|
||||
* Internal methods
|
||||
*/
|
||||
|
||||
/**
|
||||
* Handles processing the the channels and user info
|
||||
*
|
||||
* @param array $data
|
||||
* @param \GameQ\Result $result
|
||||
*/
|
||||
protected function processChannelsAndUsers(array $data, Result &$result)
|
||||
{
|
||||
|
||||
// Let's add all of the channel information
|
||||
foreach ($data as $key => $value) {
|
||||
// We will handle these later
|
||||
if (in_array($key, ['channels', 'users'])) {
|
||||
// skip
|
||||
continue;
|
||||
}
|
||||
|
||||
// Add the channel property as a team
|
||||
$result->addTeam($key, $value);
|
||||
}
|
||||
|
||||
// Itereate over the users in this channel
|
||||
foreach ($data['users'] as $user) {
|
||||
foreach ($user as $key => $value) {
|
||||
$result->addPlayer($key, $value);
|
||||
}
|
||||
}
|
||||
|
||||
// Offload more channels to parse
|
||||
foreach ($data['channels'] as $channel) {
|
||||
$this->processChannelsAndUsers($channel, $result);
|
||||
}
|
||||
}
|
||||
}
|
49
GameQ/Protocols/Ns2.php
Normal file
49
GameQ/Protocols/Ns2.php
Normal file
|
@ -0,0 +1,49 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is part of GameQ.
|
||||
*
|
||||
* GameQ is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GameQ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace GameQ\Protocols;
|
||||
|
||||
/**
|
||||
* Class Ns2
|
||||
*
|
||||
* @package GameQ\Protocols
|
||||
* @author Austin Bischoff <austin@codebeard.com>
|
||||
*/
|
||||
class Ns2 extends Source
|
||||
{
|
||||
/**
|
||||
* String name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name = 'ns2';
|
||||
|
||||
/**
|
||||
* Longer string name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name_long = "Natural Selection 2";
|
||||
|
||||
/**
|
||||
* query_port = client_port + 1
|
||||
*
|
||||
* @type int
|
||||
*/
|
||||
protected $port_diff = 1;
|
||||
}
|
43
GameQ/Protocols/Pixark.php
Normal file
43
GameQ/Protocols/Pixark.php
Normal file
|
@ -0,0 +1,43 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is part of GameQ.
|
||||
*
|
||||
* GameQ is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GameQ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace GameQ\Protocols;
|
||||
|
||||
/**
|
||||
* Class PixARK
|
||||
*
|
||||
* @package GameQ\Protocols
|
||||
* @author Austin Bischoff <austin@codebeard.com>
|
||||
*/
|
||||
class Pixark extends Arkse
|
||||
{
|
||||
|
||||
/**
|
||||
* String name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name = 'pixark';
|
||||
|
||||
/**
|
||||
* Longer string name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name_long = "PixARK";
|
||||
}
|
45
GameQ/Protocols/Projectrealitybf2.php
Normal file
45
GameQ/Protocols/Projectrealitybf2.php
Normal file
|
@ -0,0 +1,45 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is part of GameQ.
|
||||
*
|
||||
* GameQ is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GameQ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace GameQ\Protocols;
|
||||
|
||||
/**
|
||||
* Class Projectrealitybf2
|
||||
*
|
||||
* Based off of BF2
|
||||
*
|
||||
* @package GameQ\Protocols
|
||||
* @author Austin Bischoff <austin@codebeard.com>
|
||||
*/
|
||||
class Projectrealitybf2 extends Bf2
|
||||
{
|
||||
|
||||
/**
|
||||
* String name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name = 'projectrealitybf2';
|
||||
|
||||
/**
|
||||
* Longer string name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name_long = "Project Reality: Battlefield 2";
|
||||
}
|
219
GameQ/Protocols/Quake2.php
Normal file
219
GameQ/Protocols/Quake2.php
Normal file
|
@ -0,0 +1,219 @@
|
|||
<?php
|
||||
|
||||
|
||||
namespace GameQ\Protocols;
|
||||
|
||||
use GameQ\Protocol;
|
||||
use GameQ\Buffer;
|
||||
use GameQ\Result;
|
||||
use GameQ\Exception\Protocol as Exception;
|
||||
|
||||
/**
|
||||
* Quake2 Protocol Class
|
||||
*
|
||||
* Handles processing Quake 3 servers
|
||||
*
|
||||
* @package GameQ\Protocols
|
||||
*/
|
||||
class Quake2 extends Protocol
|
||||
{
|
||||
/**
|
||||
* Array of packets we want to look up.
|
||||
* Each key should correspond to a defined method in this or a parent class
|
||||
*
|
||||
* @type array
|
||||
*/
|
||||
protected $packets = [
|
||||
self::PACKET_STATUS => "\xFF\xFF\xFF\xFFstatus\x00",
|
||||
];
|
||||
|
||||
/**
|
||||
* Use the response flag to figure out what method to run
|
||||
*
|
||||
* @type array
|
||||
*/
|
||||
protected $responses = [
|
||||
"\xFF\xFF\xFF\xFF\x70\x72\x69\x6e\x74" => 'processStatus',
|
||||
];
|
||||
|
||||
/**
|
||||
* The query protocol used to make the call
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $protocol = 'quake2';
|
||||
|
||||
/**
|
||||
* String name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name = 'quake2';
|
||||
|
||||
/**
|
||||
* Longer string name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name_long = "Quake 2 Server";
|
||||
|
||||
/**
|
||||
* The client join link
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $join_link = null;
|
||||
|
||||
/**
|
||||
* Normalize settings for this protocol
|
||||
*
|
||||
* @type array
|
||||
*/
|
||||
protected $normalize = [
|
||||
// General
|
||||
'general' => [
|
||||
// target => source
|
||||
'gametype' => 'gamename',
|
||||
'hostname' => 'hostname',
|
||||
'mapname' => 'mapname',
|
||||
'maxplayers' => 'maxclients',
|
||||
'mod' => 'g_gametype',
|
||||
'numplayers' => 'clients',
|
||||
'password' => 'password',
|
||||
],
|
||||
// Individual
|
||||
'player' => [
|
||||
'name' => 'name',
|
||||
'ping' => 'ping',
|
||||
'score' => 'frags',
|
||||
],
|
||||
];
|
||||
|
||||
/**
|
||||
* Handle response from the server
|
||||
*
|
||||
* @return mixed
|
||||
* @throws Exception
|
||||
*/
|
||||
public function processResponse()
|
||||
{
|
||||
// Make a buffer
|
||||
$buffer = new Buffer(implode('', $this->packets_response));
|
||||
|
||||
// Grab the header
|
||||
$header = $buffer->readString("\x0A");
|
||||
|
||||
// Figure out which packet response this is
|
||||
if (empty($header) || !array_key_exists($header, $this->responses)) {
|
||||
throw new Exception(__METHOD__ . " response type '" . bin2hex($header) . "' is not valid");
|
||||
}
|
||||
|
||||
return call_user_func_array([$this, $this->responses[$header]], [$buffer]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the status response
|
||||
*
|
||||
* @param Buffer $buffer
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function processStatus(Buffer $buffer)
|
||||
{
|
||||
// We need to split the data and offload
|
||||
$results = $this->processServerInfo(new Buffer($buffer->readString("\x0A")));
|
||||
|
||||
$results = array_merge_recursive(
|
||||
$results,
|
||||
$this->processPlayers(new Buffer($buffer->getBuffer()))
|
||||
);
|
||||
|
||||
unset($buffer);
|
||||
|
||||
// Return results
|
||||
return $results;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle processing the server information
|
||||
*
|
||||
* @param Buffer $buffer
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function processServerInfo(Buffer $buffer)
|
||||
{
|
||||
// Set the result to a new result instance
|
||||
$result = new Result();
|
||||
|
||||
// Burn leading \ if one exists
|
||||
$buffer->readString('\\');
|
||||
|
||||
// Key / value pairs
|
||||
while ($buffer->getLength()) {
|
||||
// Add result
|
||||
$result->add(
|
||||
trim($buffer->readString('\\')),
|
||||
utf8_encode(trim($buffer->readStringMulti(['\\', "\x0a"])))
|
||||
);
|
||||
}
|
||||
|
||||
$result->add('password', 0);
|
||||
$result->add('mod', 0);
|
||||
|
||||
unset($buffer);
|
||||
|
||||
return $result->fetch();
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle processing of player data
|
||||
*
|
||||
* @param Buffer $buffer
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function processPlayers(Buffer $buffer)
|
||||
{
|
||||
// Some games do not have a number of current players
|
||||
$playerCount = 0;
|
||||
|
||||
// Set the result to a new result instance
|
||||
$result = new Result();
|
||||
|
||||
// Loop until we are out of data
|
||||
while ($buffer->getLength()) {
|
||||
// Make a new buffer with this block
|
||||
$playerInfo = new Buffer($buffer->readString("\x0A"));
|
||||
|
||||
// Add player info
|
||||
$result->addPlayer('frags', $playerInfo->readString("\x20"));
|
||||
$result->addPlayer('ping', $playerInfo->readString("\x20"));
|
||||
|
||||
// Skip first "
|
||||
$playerInfo->skip(1);
|
||||
|
||||
// Add player name, encoded
|
||||
$result->addPlayer('name', utf8_encode(trim(($playerInfo->readString('"')))));
|
||||
|
||||
// Skip first "
|
||||
$playerInfo->skip(2);
|
||||
|
||||
// Add address
|
||||
$result->addPlayer('address', trim($playerInfo->readString('"')));
|
||||
|
||||
// Increment
|
||||
$playerCount++;
|
||||
|
||||
// Clear
|
||||
unset($playerInfo);
|
||||
}
|
||||
|
||||
$result->add('clients', $playerCount);
|
||||
|
||||
// Clear
|
||||
unset($buffer, $playerCount);
|
||||
|
||||
return $result->fetch();
|
||||
}
|
||||
}
|
214
GameQ/Protocols/Quake3.php
Normal file
214
GameQ/Protocols/Quake3.php
Normal file
|
@ -0,0 +1,214 @@
|
|||
<?php
|
||||
|
||||
|
||||
namespace GameQ\Protocols;
|
||||
|
||||
use GameQ\Protocol;
|
||||
use GameQ\Buffer;
|
||||
use GameQ\Result;
|
||||
use GameQ\Exception\Protocol as Exception;
|
||||
|
||||
/**
|
||||
* Quake3 Protocol Class
|
||||
*
|
||||
* Handles processing Quake 3 servers
|
||||
*
|
||||
* @package GameQ\Protocols
|
||||
*/
|
||||
class Quake3 extends Protocol
|
||||
{
|
||||
/**
|
||||
* Array of packets we want to look up.
|
||||
* Each key should correspond to a defined method in this or a parent class
|
||||
*
|
||||
* @type array
|
||||
*/
|
||||
protected $packets = [
|
||||
self::PACKET_STATUS => "\xFF\xFF\xFF\xFF\x67\x65\x74\x73\x74\x61\x74\x75\x73\x0A",
|
||||
];
|
||||
|
||||
/**
|
||||
* Use the response flag to figure out what method to run
|
||||
*
|
||||
* @type array
|
||||
*/
|
||||
protected $responses = [
|
||||
"\xFF\xFF\xFF\xFFstatusResponse" => 'processStatus',
|
||||
];
|
||||
|
||||
/**
|
||||
* The query protocol used to make the call
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $protocol = 'quake3';
|
||||
|
||||
/**
|
||||
* String name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name = 'quake3';
|
||||
|
||||
/**
|
||||
* Longer string name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name_long = "Quake 3 Server";
|
||||
|
||||
/**
|
||||
* The client join link
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $join_link = null;
|
||||
|
||||
/**
|
||||
* Normalize settings for this protocol
|
||||
*
|
||||
* @type array
|
||||
*/
|
||||
protected $normalize = [
|
||||
// General
|
||||
'general' => [
|
||||
// target => source
|
||||
'gametype' => 'gamename',
|
||||
'hostname' => 'sv_hostname',
|
||||
'mapname' => 'mapname',
|
||||
'maxplayers' => 'sv_maxclients',
|
||||
'mod' => 'g_gametype',
|
||||
'numplayers' => 'clients',
|
||||
'password' => ['g_needpass', 'pswrd'],
|
||||
],
|
||||
// Individual
|
||||
'player' => [
|
||||
'name' => 'name',
|
||||
'ping' => 'ping',
|
||||
'score' => 'frags',
|
||||
],
|
||||
];
|
||||
|
||||
/**
|
||||
* Handle response from the server
|
||||
*
|
||||
* @return mixed
|
||||
* @throws Exception
|
||||
*/
|
||||
public function processResponse()
|
||||
{
|
||||
// Make a buffer
|
||||
$buffer = new Buffer(implode('', $this->packets_response));
|
||||
|
||||
// Grab the header
|
||||
$header = $buffer->readString("\x0A");
|
||||
|
||||
// Figure out which packet response this is
|
||||
if (empty($header) || !array_key_exists($header, $this->responses)) {
|
||||
throw new Exception(__METHOD__ . " response type '" . bin2hex($header) . "' is not valid");
|
||||
}
|
||||
|
||||
return call_user_func_array([$this, $this->responses[$header]], [$buffer]);
|
||||
}
|
||||
|
||||
protected function processStatus(Buffer $buffer)
|
||||
{
|
||||
// We need to split the data and offload
|
||||
$results = $this->processServerInfo(new Buffer($buffer->readString("\x0A")));
|
||||
|
||||
$results = array_merge_recursive(
|
||||
$results,
|
||||
$this->processPlayers(new Buffer($buffer->getBuffer()))
|
||||
);
|
||||
|
||||
unset($buffer);
|
||||
|
||||
// Return results
|
||||
return $results;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle processing the server information
|
||||
*
|
||||
* @param Buffer $buffer
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function processServerInfo(Buffer $buffer)
|
||||
{
|
||||
// Set the result to a new result instance
|
||||
$result = new Result();
|
||||
|
||||
// Burn leading \ if one exists
|
||||
$buffer->readString('\\');
|
||||
|
||||
// Key / value pairs
|
||||
while ($buffer->getLength()) {
|
||||
// Add result
|
||||
$result->add(
|
||||
trim($buffer->readString('\\')),
|
||||
utf8_encode(trim($buffer->readStringMulti(['\\', "\x0a"])))
|
||||
);
|
||||
}
|
||||
|
||||
unset($buffer);
|
||||
|
||||
return $result->fetch();
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle processing of player data
|
||||
*
|
||||
* @param Buffer $buffer
|
||||
*
|
||||
* @return array
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function processPlayers(Buffer $buffer)
|
||||
{
|
||||
// Some games do not have a number of current players
|
||||
$playerCount = 0;
|
||||
|
||||
// Set the result to a new result instance
|
||||
$result = new Result();
|
||||
|
||||
// Loop until we are out of data
|
||||
while ($buffer->getLength()) {
|
||||
// Add player info
|
||||
$result->addPlayer('frags', $buffer->readString("\x20"));
|
||||
$result->addPlayer('ping', $buffer->readString("\x20"));
|
||||
|
||||
// Look ahead to see if we have a name or team
|
||||
$checkTeam = $buffer->lookAhead(1);
|
||||
|
||||
// We have team info
|
||||
if ($checkTeam != '' and $checkTeam != '"') {
|
||||
$result->addPlayer('team', $buffer->readString("\x20"));
|
||||
}
|
||||
|
||||
// Check to make sure we have player name
|
||||
$checkPlayerName = $buffer->read();
|
||||
|
||||
// Bad response
|
||||
if ($checkPlayerName !== '"') {
|
||||
throw new Exception('Expected " but got ' . $checkPlayerName . ' for beginning of player name string!');
|
||||
}
|
||||
|
||||
// Add player name, encoded
|
||||
$result->addPlayer('name', utf8_encode(trim($buffer->readString('"'))));
|
||||
|
||||
// Burn ending delimiter
|
||||
$buffer->read();
|
||||
|
||||
// Increment
|
||||
$playerCount++;
|
||||
}
|
||||
|
||||
$result->add('clients', $playerCount);
|
||||
|
||||
// Clear
|
||||
unset($buffer, $playerCount);
|
||||
|
||||
return $result->fetch();
|
||||
}
|
||||
}
|
42
GameQ/Protocols/Quakelive.php
Normal file
42
GameQ/Protocols/Quakelive.php
Normal file
|
@ -0,0 +1,42 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is part of GameQ.
|
||||
*
|
||||
* GameQ is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GameQ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace GameQ\Protocols;
|
||||
|
||||
/**
|
||||
* Class Quake Live
|
||||
*
|
||||
* @package GameQ\Protocols
|
||||
* @author Austin Bischoff <austin@codebeard.com>
|
||||
*/
|
||||
class Quakelive extends Source
|
||||
{
|
||||
/**
|
||||
* String name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name = 'quakelive';
|
||||
|
||||
/**
|
||||
* Longer string name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name_long = "Quake Live";
|
||||
}
|
50
GameQ/Protocols/Redorchestra2.php
Normal file
50
GameQ/Protocols/Redorchestra2.php
Normal file
|
@ -0,0 +1,50 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is part of GameQ.
|
||||
*
|
||||
* GameQ is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GameQ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace GameQ\Protocols;
|
||||
|
||||
/**
|
||||
* Class Redorchestra2
|
||||
*
|
||||
* @package GameQ\Protocols
|
||||
* @author Austin Bischoff <austin@codebeard.com>
|
||||
*/
|
||||
class Redorchestra2 extends Source
|
||||
{
|
||||
/**
|
||||
* String name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name = 'redorchestra2';
|
||||
|
||||
/**
|
||||
* Longer string name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name_long = "Red Orchestra 2";
|
||||
|
||||
/**
|
||||
* query_port = client_port + 19238
|
||||
* 27015 = 7777 + 19238
|
||||
*
|
||||
* @type int
|
||||
*/
|
||||
protected $port_diff = 19238;
|
||||
}
|
43
GameQ/Protocols/Redorchestraostfront.php
Normal file
43
GameQ/Protocols/Redorchestraostfront.php
Normal file
|
@ -0,0 +1,43 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is part of GameQ.
|
||||
*
|
||||
* GameQ is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GameQ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace GameQ\Protocols;
|
||||
|
||||
/**
|
||||
* Red Orchestra: Ostfront 41-45 Class
|
||||
*
|
||||
* @package GameQ\Protocols
|
||||
* @author naXe <naxeify@gmail.com>
|
||||
* @author Austin Bischoff <austin@codebeard.com>
|
||||
*/
|
||||
class Redorchestraostfront extends Source
|
||||
{
|
||||
/**
|
||||
* String name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name = 'redorchestraostfront';
|
||||
|
||||
/**
|
||||
* Longer string name of this protocol class
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $name_long = "Red Orchestra: Ostfront 41-45";
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue