fix gameq on php8.*

This commit is contained in:
Alix 2023-05-18 22:56:56 +03:30
parent 2aa99a4e80
commit a70a395706
162 changed files with 3 additions and 18722 deletions

View File

@ -43,7 +43,6 @@ if ((!isset($admin_id) or $main != 1) or (isset($admin_id) and !$pa['gimages']))
include(EASYWIDIR . '/stuff/keyphrasefile.php');
include(EASYWIDIR . '/third_party/gameq/GameQ/Autoloader.php');
include(EASYWIDIR . '/third_party/gameq_v2/GameQ.php');
include(EASYWIDIR . '/stuff/methods/functions_gs.php');
$sprache = getlanguagefile('images', $user_language, $resellerLockupID);

View File

@ -110,7 +110,7 @@ if (!function_exists('eacchange')) {
$mysql_port = (port($mysql_port)) ? $mysql_port : 3306;
$eacSql = new PDO("mysql:host=${mysql_server};dbname=${mysql_db};port=${mysql_port}", $mysql_user, $mysql_password, array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8"));
$eacSql = new PDO("mysql:host={$mysql_server};dbname={$mysql_db};port={$mysql_port}", $mysql_user, $mysql_password, array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8"));
if ($dbConnect['debug'] == 1) {
$eacSql->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
@ -269,7 +269,7 @@ if (!function_exists('eacchange')) {
$protocols = array();
// Protocol list code taken from https://github.com/Austinb/GameQ/blob/v2/examples/list.php
$protocols_path = GAMEQ_BASE . 'gameq/protocols/';
$protocols_path = 'third_party/gameq/GameQ/Protocols';
// Grab the dir with all the classes available
$dir = dir($protocols_path);

View File

@ -76,7 +76,7 @@ if (isset($debug) and $debug == 1) {
$dbConnect['debug'] = 0;
}
try {
$dbConnect['connect']="${dbConnect['type']}:host=${dbConnect['host']};dbname=${dbConnect['db']};charset=${dbConnect['charset']}";
$dbConnect['connect']="{$dbConnect['type']}:host={$dbConnect['host']};dbname={$dbConnect['db']};charset={$dbConnect['charset']}";
$sql = new \PDO($dbConnect['connect'], $dbConnect['user'], $dbConnect['pwd']);
if ($dbConnect['debug'] == 1) {

View File

@ -1,877 +0,0 @@
<?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/>.
*/
/*
* Init some stuff
*/
// Figure out where we are so we can set the proper references
define('GAMEQ_BASE', realpath(dirname(__FILE__)).DIRECTORY_SEPARATOR);
// Define the autoload so we can require files easy
spl_autoload_register(array('GameQ', 'auto_load'));
/**
* Base GameQ Class
*
* This class should be the only one that is included when you use GameQ to query
* any games servers. All necessary sub-classes are loaded as needed.
*
* Requirements: See wiki or README for more information on the requirements
* - PHP 5.2+ (Recommended 5.3+)
* * Bzip2 - http://www.php.net/manual/en/book.bzip2.php
* * Zlib - http://www.php.net/manual/en/book.zlib.php
*
* @author Austin Bischoff <austin@codebeard.com>
*/
class GameQ
{
/*
* Constants
*/
const VERSION = '2.0.1';
/*
* Server array keys
*/
const SERVER_TYPE = 'type';
const SERVER_HOST = 'host';
const SERVER_ID = 'id';
const SERVER_OPTIONS = 'options';
/* Static Section */
protected static $instance = NULL;
/**
* Create a new instance of this class
*/
public static function factory()
{
// Create a new instance
self::$instance = new self();
// Return this new instance
return self::$instance;
}
/**
* Attempt to auto-load a class based on the name
*
* @param string $class
* @throws GameQException
*/
public static function auto_load($class)
{
try
{
// Transform the class name into a path
$file = str_replace('_', '/', strtolower($class));
// Find the file and return the full path, if it exists
if ($path = self::find_file($file))
{
// Load the class file
require $path;
// Class has been found
return TRUE;
}
// Class is not in the filesystem
return FALSE;
}
catch (Exception $e)
{
throw new GameQException($e->getMessage(), $e->getCode(), $e);
die;
}
}
/**
* Try to find the file based on the class passed.
*
* @param string $file
*/
public static function find_file($file)
{
$found = FALSE; // By default we did not find anything
// Create a partial path of the filename
$path = GAMEQ_BASE.$file.'.php';
// Is a file so we can include it
if(is_file($path))
{
$found = $path;
}
return $found;
}
/* Dynamic Section */
/**
* Defined options by default
*
* @var array()
*/
protected $options = array(
'debug' => FALSE,
'timeout' => 3, // Seconds
'filters' => array(),
// 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 writting to server sockets, helps cpu usage
);
/**
* Array of servers being queried
*
* @var array
*/
protected $servers = array();
/**
* Holds the list of active sockets. This array is automaically cleaned as needed
*
* @var array
*/
protected $sockets = array();
/**
* Make new class and check for requirements
*
* @throws GameQException
* @return boolean
*/
public function __construct()
{
// @todo: Add PHP version check?
}
/**
* Get an option's value
*
* @param string $option
*/
public function __get($option)
{
return isset($this->options[$option]) ? $this->options[$option] : NULL;
}
/**
* Set an option's value
*
* @param string $option
* @param mixed $value
* @return boolean
*/
public function __set($option, $value)
{
$this->options[$option] = $value;
return TRUE;
}
/**
* Chainable call to __set, uses set as the actual setter
*
* @param string $var
* @param mixed $value
* @return GameQ
*/
public function setOption($var, $value)
{
// Use magic
$this->{$var} = $value;
return $this; // Make chainable
}
/**
* Set an output filter.
*
* @param string $name
* @param array $params
* @return GameQ
*/
public function setFilter($name, $params = array())
{
// Create the proper filter class name
$filter_class = 'GameQ_Filters_'.$name;
try
{
// Pass any parameters and make the class
$this->options['filters'][$name] = new $filter_class($params);
}
catch (GameQ_FiltersException $e)
{
// We catch the exception here, thus the filter is not applied
// but we issue a warning
error_log($e->getMessage(), E_USER_WARNING);
}
return $this; // Make chainable
}
/**
* Remove a global output filter.
*
* @param string $name
* @return GameQ
*/
public function removeFilter($name)
{
unset($this->options['filters'][$name]);
return $this; // Make chainable
}
/**
* Add a server to be queried
*
* Example:
* $this->addServer(array(
* // Required keys
* 'type' => 'cs',
* 'host' => '127.0.0.1:27015', '127.0.0.1' or 'somehost.com:27015'
* Port not required, but will use the default port in the class which may not be correct for the
* specific server being queried.
*
* // Optional keys
* 'id' => 'someServerId', // By default will use pased host info (i.e. 127.0.0.1:27015)
* 'options' => array('timeout' => 5), // By default will use global options
* ));
*
* @param array $server_info
* @throws GameQException
* @return boolean|GameQ
*/
public function addServer(Array $server_info=NULL)
{
// Check for server type
if(!key_exists(self::SERVER_TYPE, $server_info) || empty($server_info[self::SERVER_TYPE]))
{
throw new GameQException("Missing server info key '".self::SERVER_TYPE."'");
return FALSE;
}
// Check for server host
if(!key_exists(self::SERVER_HOST, $server_info) || empty($server_info[self::SERVER_HOST]))
{
throw new GameQException("Missing server info key '".self::SERVER_HOST."'");
return FALSE;
}
// Check for server id
if(!key_exists(self::SERVER_ID, $server_info) || empty($server_info[self::SERVER_ID]))
{
// Make an id so each server has an id when returned
$server_info[self::SERVER_ID] = $server_info[self::SERVER_HOST];
}
// Check for options
if(!key_exists(self::SERVER_OPTIONS, $server_info)
|| !is_array($server_info[self::SERVER_OPTIONS])
|| empty($server_info[self::SERVER_OPTIONS]))
{
// Default the options to an empty array
$server_info[self::SERVER_OPTIONS] = array();
}
// Define these
$server_id = $server_info[self::SERVER_ID];
$server_ip = '127.0.0.1';
$server_port = FALSE;
// We have an IPv6 address (and maybe a port)
if(substr_count($server_info[self::SERVER_HOST], ':') > 1)
{
// See if we have a port, input should be in the format [::1]:27015 or similar
if(strstr($server_info[self::SERVER_HOST], ']:'))
{
// Explode to get port
$server_addr = explode(':', $server_info[self::SERVER_HOST]);
// Port is the last item in the array, remove it and save
$server_port = array_pop($server_addr);
// The rest is the address, recombine
$server_ip = implode(':', $server_addr);
unset($server_addr);
}
// Just the IPv6 address, no port defined
else
{
$server_ip = $server_info[self::SERVER_HOST];
}
// Now let's validate the IPv6 value sent, remove the square brackets ([]) first
if(!filter_var(trim($server_ip, '[]'), FILTER_VALIDATE_IP, array(
'flags' => FILTER_FLAG_IPV6,
)))
{
throw new GameQException("The IPv6 address '{$server_ip}' is invalid.");
return FALSE;
}
}
// IPv4
else
{
// We have a port defined
if(strstr($server_info[self::SERVER_HOST], ':'))
{
list($server_ip, $server_port) = explode(':', $server_info[self::SERVER_HOST]);
}
// No port, just IPv4
else
{
$server_ip = $server_info[self::SERVER_HOST];
}
// Validate the IPv4 value, if FALSE is not a valid IP, maybe a hostname. Try to resolve
if(!filter_var($server_ip, FILTER_VALIDATE_IP, array(
'flags' => FILTER_FLAG_IPV4,
)))
{
// When gethostbyname() fails it returns the original string
// so if ip and the result from gethostbyname() are equal this failed.
if($server_ip === gethostbyname($server_ip))
{
throw new GameQException("The host '{$server_ip}' is unresolvable to an IP address.");
return FALSE;
}
}
}
// Create the class so we can reference it properly later
$protocol_class = 'GameQ_Protocols_'.ucfirst($server_info[self::SERVER_TYPE]);
// Create the new instance and add it to the servers list
$this->servers[$server_id] = new $protocol_class(
$server_ip,
$server_port,
array_merge($this->options, $server_info[self::SERVER_OPTIONS])
);
return $this; // Make calls chainable
}
/**
* Add multiple servers at once
*
* @param array $servers
* @return GameQ
*/
public function addServers(Array $servers=NULL)
{
// Loop thru all the servers and add them
foreach($servers AS $server_info)
{
$this->addServer($server_info);
}
return $this; // Make calls chainable
}
/**
* Clear all the added servers. Creates clean instance.
*
* @return GameQ
*/
public function clearServers()
{
// Reset all the servers
$this->servers = array();
$this->sockets = array();
return $this; // Make Chainable
}
/**
* Make all the data requests (i.e. challenges, queries, etc...)
*
* @return multitype:Ambigous <multitype:, multitype:boolean string mixed >
*/
public function requestData()
{
// Data returned array
$data = array();
// Init the query array
$queries = array(
'multi' => array(
'challenges' => array(),
'info' => array(),
),
'linear' => array(),
);
// Loop thru all of the servers added and categorize them
foreach($this->servers AS $server_id => $instance)
{
// Check to see what kind of server this is and how we can send packets
if($instance->packet_mode() == GameQ_Protocols::PACKET_MODE_LINEAR)
{
$queries['linear'][$server_id] = $instance;
}
else // We can send this out in a multi request
{
// Check to see if we should issue a challenge first
if($instance->hasChallenge())
{
$queries['multi']['challenges'][$server_id] = $instance;
}
// Add this instance to do info query
$queries['multi']['info'][$server_id] = $instance;
}
}
// First lets do the faster, multi queries
if(count($queries['multi']['info']) > 0)
{
$this->requestMulti($queries['multi']);
}
// Now lets do the slower linear queries.
if(count($queries['linear']) > 0)
{
$this->requestLinear($queries['linear']);
}
// Now let's loop the servers and process the response data
foreach($this->servers AS $server_id => $instance)
{
// Lets process this and filter
$data[$server_id] = $this->filterResponse($instance);
}
// Send back the data array, could be empty if nothing went to plan
return $data;
}
/* Working Methods */
/**
* Apply all set filters to the data returned by gameservers.
*
* @param GameQ_Protocols $protocol_instance
* @return array
*/
protected function filterResponse(GameQ_Protocols $protocol_instance)
{
// Let's pull out the "raw" data we are going to filter
$data = $protocol_instance->processResponse();
// Loop each of the filters we have attached
foreach($this->options['filters'] AS $filter_name => $filter_instance)
{
// Overwrite the data with the "filtered" data
$data = $filter_instance->filter($data, $protocol_instance);
}
return $data;
}
/**
* Process "linear" servers. Servers that do not support multiple packet calls at once. So Slow!
* This method also blocks the socket, you have been warned!!
*
* @param array $servers
* @return boolean
*/
protected function requestLinear($servers=array())
{
// Loop thru all the linear servers
foreach($servers AS $server_id => $instance)
{
// First we need to get a socket and we need to block because this is linear
if(($socket = $this->socket_open($instance, TRUE)) === FALSE)
{
// Skip it
continue;
}
// Socket id
$socket_id = (int) $socket;
// See if we have challenges to send off
if($instance->hasChallenge())
{
// Now send off the challenge packet
fwrite($socket, $instance->getPacket('challenge'));
// Read in the challenge response
$instance->challengeResponse(array(fread($socket, 4096)));
// Now we need to parse and apply the challenge response to all the packets that require it
$instance->challengeVerifyAndParse();
}
// Invoke the beforeSend method
$instance->beforeSend();
// Grab the packets we need to send, minus the challenge packet
$packets = $instance->getPacket('!challenge');
// Now loop the packets, begin the slowness
foreach($packets AS $packet_type => $packet)
{
// Add the socket information so we can retreive it easily
$this->sockets = array(
$socket_id => array(
'server_id' => $server_id,
'packet_type' => $packet_type,
'socket' => $socket,
)
);
// Write the packet
fwrite($socket, $packet);
// Get the responses from the query
$responses = $this->sockets_listen();
// Lets look at our responses
foreach($responses AS $socket_id => $response)
{
// Save the response from this packet
$instance->packetResponse($packet_type, $response);
}
}
}
// Now close all the socket(s) and clean up any data
$this->sockets_close();
return TRUE;
}
/**
* Process the servers that support multi requests. That means multiple packets can be sent out at once.
*
* @param array $servers
* @return boolean
*/
protected function requestMulti($servers=array())
{
// See if we have any challenges to send off
if(count($servers['challenges']) > 0)
{
// Now lets send off all the challenges
$this->sendChallenge($servers['challenges']);
// Now let's process the challenges
// Loop thru all the instances
foreach($servers['challenges'] AS $server_id => $instance)
{
$instance->challengeVerifyAndParse();
}
}
// Send out all the query packets to get data for
$this->queryServerInfo($servers['info']);
return TRUE;
}
/**
* Send off needed challenges and get the response
*
* @param array $instances
* @return boolean
*/
protected function sendChallenge(Array $instances=NULL)
{
// Loop thru all the instances we need to send out challenges for
foreach($instances AS $server_id => $instance)
{
// Make a new socket
if(($socket = $this->socket_open($instance)) === FALSE)
{
// Skip it
continue;
}
// Now write the challenge packet to the socket.
fwrite($socket, $instance->getPacket(GameQ_Protocols::PACKET_CHALLENGE));
// Add the socket information so we can retreive it easily
$this->sockets[(int) $socket] = array(
'server_id' => $server_id,
'packet_type' => GameQ_Protocols::PACKET_CHALLENGE,
'socket' => $socket,
);
// Let's sleep shortly so we are not hammering out calls rapid fire style hogging cpu
usleep($this->write_wait);
}
// Now we need to listen for challenge response(s)
$responses = $this->sockets_listen();
// Lets look at our responses
foreach($responses AS $socket_id => $response)
{
// Back out the server_id we need to update the challenge response for
$server_id = $this->sockets[$socket_id]['server_id'];
// Now set the proper response for the challenge because we will need it later
$this->servers[$server_id]->challengeResponse($response);
}
// Now close all the socket(s) and clean up any data
$this->sockets_close();
return TRUE;
}
/**
* Query the server for actual server information (i.e. info, players, rules, etc...)
*
* @param array $instances
* @return boolean
*/
protected function queryServerInfo(Array $instances=NULL)
{
// Loop all the server instances
foreach($instances AS $server_id => $instance)
{
// Invoke the beforeSend method
$instance->beforeSend();
// Get all the non-challenge packets we need to send
$packets = $instance->getPacket('!challenge');
if(count($packets) == 0)
{
// Skip nothing else to do for some reason.
continue;
}
// Now lets send off the packets
foreach($packets AS $packet_type => $packet)
{
// Make a new socket
if(($socket = $this->socket_open($instance)) === FALSE)
{
// Skip it
continue;
}
// Now write the packet to the socket.
fwrite($socket, $packet);
// Add the socket information so we can retreive it easily
$this->sockets[(int) $socket] = array(
'server_id' => $server_id,
'packet_type' => $packet_type,
'socket' => $socket,
);
// Let's sleep shortly so we are not hammering out calls raipd fire style
usleep($this->write_wait);
}
}
// Now we need to listen for packet response(s)
$responses = $this->sockets_listen();
// Lets look at our responses
foreach($responses AS $socket_id => $response)
{
// Back out the server_id
$server_id = $this->sockets[$socket_id]['server_id'];
// Back out the packet type
$packet_type = $this->sockets[$socket_id]['packet_type'];
// Save the response from this packet
$this->servers[$server_id]->packetResponse($packet_type, $response);
}
// Now close all the socket(s) and clean up any data
$this->sockets_close();
return TRUE;
}
/* Sockets/streams stuff */
/**
* Open a new socket based on the instance information
*
* @param GameQ_Protocols $instance
* @param bool $blocking
* @throws GameQException
* @return boolean|resource
*/
protected function socket_open(GameQ_Protocols $instance, $blocking=FALSE)
{
// Create the remote address
$remote_addr = sprintf("%s://%s:%d", $instance->transport(), $instance->ip(), $instance->port());
// Create context
$context = stream_context_create(array(
'socket' => array(
'bindto' => '0:0', // Bind to any available IP and OS decided port
),
));
// Create the socket
if(($socket = @stream_socket_client($remote_addr, $errno = NULL, $errstr = NULL, $this->timeout, STREAM_CLIENT_CONNECT, $context)) !== FALSE)
{
// Set the read timeout on the streams
stream_set_timeout($socket, $this->timeout);
// Set blocking mode
stream_set_blocking($socket, $blocking);
}
else // Throw an error
{
// Check to see if we are in debug mode, if so throw the exception
if($this->debug)
{
throw new GameQException(__METHOD__." Error creating socket to server {$remote_addr}. Error: ".$errstr, $errno);
}
// We didnt create so we need to return false.
return FALSE;
}
unset($context, $remote_addr);
// return the socket
return $socket;
}
/**
* Listen to all the created sockets and return the responses
*
* @return array
*/
protected function sockets_listen()
{
// Set the loop to active
$loop_active = TRUE;
// To store the responses
$responses = array();
// To store the sockets
$sockets = array();
// Loop and pull out all the actual sockets we need to listen on
foreach($this->sockets AS $socket_id => $socket_data)
{
// Append the actual socket we are listening to
$sockets[$socket_id] = $socket_data['socket'];
}
// Init some variables
$read = $sockets;
$write = NULL;
$except = NULL;
// Check to see if $read is empty, if so stream_select() will throw a warning
if(empty($read))
{
return $responses;
}
// This is when it should stop
$time_stop = microtime(TRUE) + $this->timeout;
// Let's loop until we break something.
while ($loop_active && microtime(TRUE) < $time_stop)
{
// Now lets listen for some streams, but do not cross the streams!
$streams = stream_select($read, $write, $except, 0, $this->stream_timeout);
// We had error or no streams left, kill the loop
if($streams === FALSE || ($streams <= 0))
{
$loop_active = FALSE;
break;
}
// Loop the sockets that received data back
foreach($read AS $socket)
{
// See if we have a response
if(($response = stream_socket_recvfrom($socket, 8192)) === FALSE)
{
continue; // No response yet so lets continue.
}
// Check to see if the response is empty, if so we are done
// @todo: Verify that this does not affect other protocols, added for Minequery
// Initial testing showed this change did not affect any of the other protocols
if(strlen($response) == 0)
{
// End the while loop
$loop_active = FALSE;
break;
}
// Add the response we got back
$responses[(int) $socket][] = $response;
}
// Because stream_select modifies read we need to reset it each
// time to the original array of sockets
$read = $sockets;
}
// Free up some memory
unset($streams, $read, $write, $except, $sockets, $time_stop, $response);
return $responses;
}
/**
* Close all the open sockets
*/
protected function sockets_close()
{
// Loop all the existing sockets, valid or not
foreach($this->sockets AS $socket_id => $data)
{
fclose($data['socket']);
unset($this->sockets[$socket_id]);
}
return TRUE;
}
}
/**
* GameQ Exception Class
*
* Thrown when there is any kind of internal configuration error or
* some unhandled or unexpected error or response.
*
* @author Austin Bischoff <austin@codebeard.com>
*/
class GameQException extends Exception {}

View File

@ -1,674 +0,0 @@
GNU 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.
Preamble
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. You must make sure that they, too, receive
or can get the source code. And you must show them these terms so they
know their rights.
Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Use with the GNU Affero General Public License.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU 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
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program 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.
This program 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/>.
Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:
<program> Copyright (C) <year> <name of author>
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
<http://www.gnu.org/licenses/>.
The GNU General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
<http://www.gnu.org/philosophy/why-not-lgpl.html>.

View File

@ -1,44 +0,0 @@
Information
===========
GameQ is a PHP program that allows you to query multiple types of multiplayer game servers at the same time.
GameQ v2 is based off of the original GameQ PHP program from http://gameq.sourceforge.net/. That project was no longer being supported.
Requirements
============
* PHP 5.2 (Recommended 5.3, 5.4)
Extras you might need:
* Bzip2 - Used for A2S compressed responses (http://www.php.net/manual/en/book.bzip2.php)
* Zlib - Used for AA3 (before version 3.2) compressed responses (http://www.php.net/manual/en/book.zlib.php)
Example
=======
Usage & Examples: https://github.com/Austinb/GameQ/wiki/Usage-&-examples-v2
Quick and Dirty:
$gq = new GameQ();
$gq->addServer(array(
'id' => 'my_server',
'type' => 'css', // Counter-Strike: Source
'host' => '127.0.0.1:27015',
));
$results = $gq->requestData(); // Returns an array of results
print_r($results);
Want more? Check out the wiki page or /examples for more.
ChangeLog
=========
See https://github.com/Austinb/GameQ/commits/v2 for an incremental list of changes
License
=======
See LICENSE for more information
Donations
=========
If you like this project and use it a lot please feel free to donate here: https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=VAU2KADATP5PU.

View File

@ -1,60 +0,0 @@
<?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;
}
});

View File

@ -1,659 +0,0 @@
<?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;
}
public function getServers()
{
return $this->servers;
}
public function getOptions()
{
return $this->options;
}
/**
* 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 $exception) {
// Check to see if we are in debug, if so bubble up the exception
if ($this->debug) {
throw new \Exception($exception->getMessage(), $exception->getCode(), $exception);
}
}
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 $exception) {
// Check to see if we are in debug, if so bubble up the exception
if ($this->debug) {
throw new \Exception($exception->getMessage(), $exception->getCode(), $exception);
}
continue;
}
// 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 $exception) {
// Invalid, skip it
continue;
}
}
return $results;
}
}

View File

@ -1,500 +0,0 @@
<?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();
}

View File

@ -1,389 +0,0 @@
<?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\Server as Exception;
/**
* Server class to represent each server entity
*
* @author Austin Bischoff <austin@codebeard.com>
*/
class Server
{
/*
* Server array keys
*/
const SERVER_TYPE = 'type';
const SERVER_HOST = 'host';
const SERVER_ID = 'id';
const SERVER_OPTIONS = 'options';
/*
* Server options keys
*/
/*
* Use this option when the query_port and client connect ports are different
*/
const SERVER_OPTIONS_QUERY_PORT = 'query_port';
/**
* The protocol class for this server
*
* @type \GameQ\Protocol
*/
protected $protocol = null;
/**
* Id of this server
*
* @type string
*/
public $id = null;
/**
* IP Address of this server
*
* @type string
*/
public $ip = null;
/**
* The server's client port (connect port)
*
* @type int
*/
public $port_client = null;
/**
* The server's query port
*
* @type int
*/
public $port_query = null;
/**
* Holds other server specific options
*
* @type array
*/
protected $options = [];
/**
* Holds the sockets already open for this server
*
* @type array
*/
protected $sockets = [];
/**
* Construct the class with the passed options
*
* @param array $server_info
*
* @throws \GameQ\Exception\Server
*/
public function __construct(array $server_info = [])
{
// Check for server type
if (!array_key_exists(self::SERVER_TYPE, $server_info) || empty($server_info[self::SERVER_TYPE])) {
throw new Exception("Missing server info key '" . self::SERVER_TYPE . "'!");
}
// Check for server host
if (!array_key_exists(self::SERVER_HOST, $server_info) || empty($server_info[self::SERVER_HOST])) {
throw new Exception("Missing server info key '" . self::SERVER_HOST . "'!");
}
// IP address and port check
$this->checkAndSetIpPort($server_info[self::SERVER_HOST]);
// Check for server id
if (array_key_exists(self::SERVER_ID, $server_info) && !empty($server_info[self::SERVER_ID])) {
// Set the server id
$this->id = $server_info[self::SERVER_ID];
} else {
// Make an id so each server has an id when returned
$this->id = sprintf('%s:%d', $this->ip, $this->port_client);
}
// Check and set server options
if (array_key_exists(self::SERVER_OPTIONS, $server_info)) {
// Set the options
$this->options = $server_info[self::SERVER_OPTIONS];
}
try {
// Make the protocol class for this type
$class = new \ReflectionClass(
sprintf('GameQ\\Protocols\\%s', ucfirst(strtolower($server_info[self::SERVER_TYPE])))
);
$this->protocol = $class->newInstanceArgs([$this->options]);
} catch (\ReflectionException $e) {
throw new Exception("Unable to locate Protocols class for '{$server_info[self::SERVER_TYPE]}'!");
}
// Check and set any server options
$this->checkAndSetServerOptions();
unset($server_info, $class);
}
/**
* Check and set the ip address for this server
*
* @param $ip_address
*
* @throws \GameQ\Exception\Server
*/
protected function checkAndSetIpPort($ip_address)
{
// Test for IPv6
if (substr_count($ip_address, ':') > 1) {
// See if we have a port, input should be in the format [::1]:27015 or similar
if (strstr($ip_address, ']:')) {
// Explode to get port
$server_addr = explode(':', $ip_address);
// Port is the last item in the array, remove it and save
$this->port_client = (int)array_pop($server_addr);
// The rest is the address, recombine
$this->ip = implode(':', $server_addr);
unset($server_addr);
} else {
// Just the IPv6 address, no port defined, fail
throw new Exception(
"The host address '{$ip_address}' is missing the port. All "
. "servers must have a port defined!"
);
}
// Now let's validate the IPv6 value sent, remove the square brackets ([]) first
if (!filter_var(trim($this->ip, '[]'), FILTER_VALIDATE_IP, ['flags' => FILTER_FLAG_IPV6,])) {
throw new Exception("The IPv6 address '{$this->ip}' is invalid.");
}
} else {
// We have IPv4 with a port defined
if (strstr($ip_address, ':')) {
list($this->ip, $this->port_client) = explode(':', $ip_address);
// Type case the port
$this->port_client = (int)$this->port_client;
} else {
// No port, fail
throw new Exception(
"The host address '{$ip_address}' is missing the port. All "
. "servers must have a port defined!"
);
}
// Validate the IPv4 value, if FALSE is not a valid IP, maybe a hostname.
if (! filter_var($this->ip, FILTER_VALIDATE_IP, ['flags' => FILTER_FLAG_IPV4,])) {
// Try to resolve the hostname to IPv4
$resolved = gethostbyname($this->ip);
// When gethostbyname() fails it returns the original string
if ($this->ip === $resolved) {
// so if ip and the result from gethostbyname() are equal this failed.
throw new Exception("Unable to resolve the host '{$this->ip}' to an IP address.");
} else {
$this->ip = $resolved;
}
}
}
}
/**
* Check and set any server specific options
*/
protected function checkAndSetServerOptions()
{
// Specific query port defined
if (array_key_exists(self::SERVER_OPTIONS_QUERY_PORT, $this->options)) {
$this->port_query = (int)$this->options[self::SERVER_OPTIONS_QUERY_PORT];
} else {
// Do math based on the protocol class
$this->port_query = $this->protocol->findQueryPort($this->port_client);
}
}
/**
* Set an option for this server
*
* @param $key
* @param $value
*
* @return $this
*/
public function setOption($key, $value)
{
$this->options[$key] = $value;
return $this; // Make chainable
}
/**
* Return set option value
*
* @param mixed $key
*
* @return mixed
*/
public function getOption($key)
{
return (array_key_exists($key, $this->options)) ? $this->options[$key] : null;
}
public function getOptions()
{
return $this->options;
}
/**
* Get the ID for this server
*
* @return string
*/
public function id()
{
return $this->id;
}
/**
* Get the IP address for this server
*
* @return string
*/
public function ip()
{
return $this->ip;
}
/**
* Get the client port for this server
*
* @return int
*/
public function portClient()
{
return $this->port_client;
}
/**
* Get the query port for this server
*
* @return int
*/
public function portQuery()
{
return $this->port_query;
}
/**
* Return the protocol class for this server
*
* @return \GameQ\Protocol
*/
public function protocol()
{
return $this->protocol;
}
/**
* Get the join link for this server
*
* @return string
*/
public function getJoinLink()
{
return sprintf($this->protocol->joinLink(), $this->ip, $this->portClient());
}
/*
* Socket holding
*/
/**
* Add a socket for this server to be reused
*
* @codeCoverageIgnore
*
* @param \GameQ\Query\Core $socket
*/
public function socketAdd(Query\Core $socket)
{
$this->sockets[] = $socket;
}
/**
* Get a socket from the list to reuse, if any are available
*
* @codeCoverageIgnore
*
* @return \GameQ\Query\Core|null
*/
public function socketGet()
{
$socket = null;
if (count($this->sockets) > 0) {
$socket = array_pop($this->sockets);
}
return $socket;
}
/**
* Clear any sockets still listed and attempt to close them
*
* @codeCoverageIgnore
*/
public function socketCleanse()
{
// Close all of the sockets available
foreach ($this->sockets as $socket) {
/* @var $socket \GameQ\Query\Core */
$socket->close();
}
// Reset the sockets list
$this->sockets = [];
}
}

View File

@ -1,526 +0,0 @@
<?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|string &$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 ($index = strpos($this->data, $delim, min($this->index, $this->length))) {
$pos[] = $index;
}
}
// 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($length = 4)
{
// Change the integer type we are looking up
$littleEndian = null;
switch ($this->number_type) {
case self::NUMBER_TYPE_BIGENDIAN:
$type = 'N';
$littleEndian = false;
break;
case self::NUMBER_TYPE_LITTLEENDIAN:
$type = 'V';
$littleEndian = true;
break;
default:
$type = 'L';
}
// read from the buffer and append/prepend empty bytes for shortened int32
$corrected = $this->read($length);
// Unpack the number
$int = unpack($type . 'int', self::extendBinaryString($corrected, 4, $littleEndian));
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'];
}
private static function extendBinaryString($input, $length = 4, $littleEndian = null)
{
if (is_null($littleEndian)) {
$littleEndian = self::isLittleEndian();
}
$extension = str_repeat(pack($littleEndian ? 'V' : 'N', 0b0000), $length - strlen($input));
if ($littleEndian) {
return $input . $extension;
} else {
return $extension . $input;
}
}
private static function isLittleEndian()
{
return 0x00FF === current(unpack('v', pack('S', 0x00FF)));
}
}

View File

@ -1,30 +0,0 @@
<?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
{
}

View File

@ -1,30 +0,0 @@
<?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
{
}

View File

@ -1,30 +0,0 @@
<?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
{
}

View File

@ -1,63 +0,0 @@
<?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;
}
public function getOptions()
{
return $this->options;
}
/**
* Apply the filter to the data
*
* @param array $result
* @param \GameQ\Server $server
*
* @return mixed
*/
abstract public function apply(array $result, Server $server);
}

View File

@ -1,133 +0,0 @@
<?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;
}
}

View File

@ -1,121 +0,0 @@
<?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;
}
}

View File

@ -1,118 +0,0 @@
<?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;
case 'gta5m':
array_walk_recursive($result, [$this, 'stripQuake']);
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 Source based games
*
* @param string $string
*/
protected function stripSource(&$string)
{
$string = strip_tags($string);
}
/**
* Strip color codes from Unreal based games
*
* @param string $string
*/
protected function stripUnreal(&$string)
{
$string = preg_replace('/\x1b.../', '', $string);
}
}

View File

@ -1,47 +0,0 @@
<?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;
}
}

View File

@ -1,42 +0,0 @@
<?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";
}

View File

@ -1,51 +0,0 @@
<?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;
}

View File

@ -1,43 +0,0 @@
<?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";
}

View File

@ -1,221 +0,0 @@
<?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
{
// Base DLC names
const BASE_DLC_KART = 'Karts';
const BASE_DLC_MARKSMEN = 'Marksmen';
const BASE_DLC_HELI = 'Helicopters';
const BASE_DLC_CURATOR = 'Curator';
const BASE_DLC_EXPANSION = 'Expansion';
const BASE_DLC_JETS = 'Jets';
const BASE_DLC_ORANGE = 'Laws of War';
const BASE_DLC_ARGO = 'Malden';
const BASE_DLC_TACOPS = 'Tac-Ops';
const BASE_DLC_TANKS = 'Tanks';
const BASE_DLC_CONTACT = 'Contact';
const BASE_DLC_ENOCH = 'Contact (Platform)';
// Special
const BASE_DLC_AOW = 'Art of War';
// Creator DLC names
const CREATOR_DLC_GM = 'Global Mobilization';
const CREATOR_DLC_VN = 'S.O.G. Prairie Fire';
const CREATOR_DLC_CSLA = 'ČSLA - Iron Curtain';
const CREATOR_DLC_WS = 'Western Sahara';
/**
* DLC Flags/Bits as defined in the documentation.
*
* @see https://community.bistudio.com/wiki/Arma_3:_ServerBrowserProtocol3
*
* @var array
*/
protected $dlcFlags = [
0b0000000000000001 => self::BASE_DLC_KART,
0b0000000000000010 => self::BASE_DLC_MARKSMEN,
0b0000000000000100 => self::BASE_DLC_HELI,
0b0000000000001000 => self::BASE_DLC_CURATOR,
0b0000000000010000 => self::BASE_DLC_EXPANSION,
0b0000000000100000 => self::BASE_DLC_JETS,
0b0000000001000000 => self::BASE_DLC_ORANGE,
0b0000000010000000 => self::BASE_DLC_ARGO,
0b0000000100000000 => self::BASE_DLC_TACOPS,
0b0000001000000000 => self::BASE_DLC_TANKS,
0b0000010000000000 => self::BASE_DLC_CONTACT,
0b0000100000000000 => self::BASE_DLC_ENOCH,
0b0001000000000000 => self::BASE_DLC_AOW,
0b0010000000000000 => 'Unknown',
0b0100000000000000 => 'Unknown',
0b1000000000000000 => 'Unknown',
];
/**
* 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()); // read protocol version
$result->add('overflow', $responseBuffer->readInt8()); // Read overflow flags
$dlcByte = $responseBuffer->readInt8(); // Grab DLC byte 1 and use it later
$dlcByte2 = $responseBuffer->readInt8(); // Grab DLC byte 2 and use it later
$dlcBits = ($dlcByte2 << 8) | $dlcByte; // concatenate DLC bits to 16 Bit int
// 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 base DLC bits so we can pull in the info for the DLC (if enabled)
foreach ($this->dlcFlags as $dlcFlag => $dlcName) {
// Check that the DLC bit is enabled
if (($dlcBits & $dlcFlag) === $dlcFlag) {
// Add the DLC to the list
$result->addSub('dlcs', 'name', $dlcName);
$result->addSub('dlcs', 'hash', dechex($responseBuffer->readInt32()));
}
}
// Read the mount of mods, these include DLC as well as Creator DLC and custom modifications
$modCount = $responseBuffer->readInt8();
// Add mod count
$result->add('mod_count', $modCount);
// Loop over the mods
while ($modCount) {
// Read the mods hash
$result->addSub('mods', 'hash', dechex($responseBuffer->readInt32()));
// Get the information byte containing DLC flag and steamId length
$infoByte = $responseBuffer->readInt8();
// Determine isDLC by flag, first bit in upper nibble
$result->addSub('mods', 'dlc', ($infoByte & 0b00010000) === 0b00010000);
// Read the steam id of the mod/CDLC (might be less than 4 bytes)
$result->addSub('mods', 'steam_id', $responseBuffer->readInt32($infoByte & 0x0F));
// Read the name of the mod
$result->addSub('mods', 'name', $responseBuffer->readPascalString(0, true) ?: 'Unknown');
--$modCount;
}
// No longer needed
unset($dlcByte, $dlcByte2, $dlcBits);
// 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();
}
}

View File

@ -1,55 +0,0 @@
<?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;
}

View File

@ -1,48 +0,0 @@
<?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;
/**
* Avorion Protocol Class
*
* @package GameQ\Protocols
*/
class Avorion extends Source
{
/**
* String name of this protocol class
*
* @type string
*/
protected $name = 'avorion';
/**
* Longer string name of this protocol class
*
* @type string
*/
protected $name_long = "Avorion";
/**
* query_port = client_port + 1
*
* @type int
* protected $port_diff = 1;
*/
}

View File

@ -1,49 +0,0 @@
<?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;
/**
* Barotrauma Protocol Class
*
* @package GameQ\Protocols
* @author Jesse Lukas <eranio@g-one.org>
*/
class Barotrauma extends Source
{
/**
* String name of this protocol class
*
* @type string
*/
protected $name = 'barotrauma';
/**
* Longer string name of this protocol class
*
* @type string
*/
protected $name_long = "Barotrauma";
/**
* query_port = client_port + 1
*
* @type int
*/
protected $port_diff = 1;
}

View File

@ -1,68 +0,0 @@
<?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',
],
];
}

View File

@ -1,43 +0,0 @@
<?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";
}

View File

@ -1,42 +0,0 @@
<?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;
/**
* Blackmesa Protocol Class
*
* @package GameQ\Protocols
* @author Jesse Lukas <eranio@g-one.org>
*/
class Blackmesa extends Source
{
/**
* String name of this protocol class
*
* @type string
*/
protected $name = 'blackmesa';
/**
* Longer string name of this protocol class
*
* @type string
*/
protected $name_long = "Black Mesa";
}

View File

@ -1,42 +0,0 @@
<?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;
/**
* Citadel Protocol Class
*
* @package GameQ\Protocols
* @author Jesse Lukas <eranio@g-one.org>
*/
class Citadel extends Source
{
/**
* String name of this protocol class
*
* @type string
*/
protected $name = 'citadel';
/**
* Longer string name of this protocol class
*
* @type string
*/
protected $name_long = "Citadel";
}

View File

@ -1,89 +0,0 @@
<?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;
/**
* Call of Duty: Modern Warfare 2 Protocol Class
*
* @package GameQ\Protocols
* @author Wilson Jesus <>
*/
class Codmw2 extends Quake3
{
/**
* String name of this protocol class
*
* @type string
*/
protected $name = 'codmw2';
/**
* Longer string name of this protocol class
*
* @type string
*/
protected $name_long = "Call of Duty: Modern Warfare 2";
protected function processPlayers(Buffer $buffer)
{
// Temporarily cache players in order to remove last
$players = [];
// Loop until we are out of data
while ($buffer->getLength()) {
// Make a new buffer with this block
$playerInfo = new Buffer($buffer->readString("\x0A"));
// Read player info
$player = [
'frags' => $playerInfo->readString("\x20"),
'ping' => $playerInfo->readString("\x20"),
];
// Skip first "
$playerInfo->skip(1);
// Add player name, encoded
$player['name'] = utf8_encode(trim(($playerInfo->readString('"'))));
// Add player
$players[] = $player;
}
// Remove last, empty player
array_pop($players);
// Set the result to a new result instance
$result = new Result();
// Add players
$result->add('players', $players);
// Add Playercount
$result->add('clients', count($players));
// Clear
unset($buffer, $players);
return $result->fetch();
}
}

View File

@ -1,42 +0,0 @@
<?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";
}

View File

@ -1,42 +0,0 @@
<?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";
}

View File

@ -1,45 +0,0 @@
<?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";
}

View File

@ -1,263 +0,0 @@
<?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));
}
}

View File

@ -1,43 +0,0 @@
<?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";
}

View File

@ -1,69 +0,0 @@
<?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',
],
];
}

View File

@ -1,123 +0,0 @@
<?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();
}
}

View File

@ -1,51 +0,0 @@
<?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;
}

View File

@ -1,42 +0,0 @@
<?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";
}

View File

@ -1,173 +0,0 @@
<?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();
}
}

View File

@ -1,163 +0,0 @@
<?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();
}
}

View File

@ -1,164 +0,0 @@
<?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();
}
}

View File

@ -1,75 +0,0 @@
<?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;
/**
* Hidden & Dangerous 2 Protocol Class
*
* @author Wilson Jesus <>
*/
class Had2 extends Gamespy2
{
/**
* String name of this protocol class
*
* @type string
*/
protected $name = 'had2';
/**
* Longer string name of this protocol class
*
* @type string
*/
protected $name_long = "Hidden & Dangerous 2";
/**
* The difference between the client port and query port
*
* @type int
*/
protected $port_diff = 3;
/**
* Normalize settings for this protocol
*
* @type array
*/
protected $normalize = [
// General
'general' => [
// target => source
'dedicated' => 'isdedicated',
'gametype' => 'gametype',
'hostname' => 'hostname',
'mapname' => 'mapname',
'maxplayers' => 'maxplayers',
'numplayers' => 'numplayers',
'password' => 'password',
],
// Individual
'player' => [
'name' => 'player',
'score' => 'score',
'deaths' => 'deaths',
'ping' => 'ping',
],
];
}

View File

@ -1,42 +0,0 @@
<?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;
/**
* Halo: Combat Evolved Protocol Class
*
* @author Wilson Jesus <>
*/
class Halo extends Gamespy2
{
/**
* String name of this protocol class
*
* @type string
*/
protected $name = 'halo';
/**
* Longer string name of this protocol class
*
* @type string
*/
protected $name_long = "Halo: Combat Evolved";
}

View File

@ -1,43 +0,0 @@
<?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 Hl1
*
* @package GameQ\Protocols
* @author Austin Bischoff <austin@codebeard.com>
* @author Jesse Lukas <eranio@g-one.org>
*/
class Hl1 extends Source
{
/**
* String name of this protocol class
*
* @type string
*/
protected $name = 'hl1';
/**
* Longer string name of this protocol class
*
* @type string
*/
protected $name_long = "Half Life";
}

View File

@ -1,68 +0,0 @@
<?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 Hll
*
* @package GameQ\Protocols
* @author Wilson Jesus <>
*/
class Hll extends Source
{
/**
* String name of this protocol class
*
* @type string
*/
protected $name = 'hll';
/**
* Longer string name of this protocol class
*
* @type string
*/
protected $name_long = "Hell Let Loose";
/**
* query_port = client_port + 15
* 64015 = 64000 + 15
*
* @type int
*/
protected $port_diff = 15;
/**
* Normalize settings for this protocol
*
* @type array
*/
/*protected $normalize = [
'general' => [
// target => source
'dedicated' => 'dedicated',
'gametype' => 'gametype',
'servername' => 'hostname',
'mapname' => 'mapname',
'maxplayers' => 'maxplayers',
'numplayers' => 'numplayers',
'password' => 'password',
],
];*/
}

View File

@ -1,42 +0,0 @@
<?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";
}

View File

@ -1,49 +0,0 @@
<?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;
}

View File

@ -1,42 +0,0 @@
<?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";
}

View File

@ -1,42 +0,0 @@
<?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";
}

View File

@ -1,127 +0,0 @@
<?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());
}
}
}

View File

@ -1,50 +0,0 @@
<?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;
}

View File

@ -1,51 +0,0 @@
<?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;
}

View File

@ -1,43 +0,0 @@
<?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;
/**
* Kingpin: Life of Crime Protocol Class
*
* @package GameQ\Protocols
*
* @author Wilson Jesus <>
*/
class Kingpin extends Quake2
{
/**
* String name of this protocol class
*
* @type string
*/
protected $name = 'kingpin';
/**
* Longer string name of this protocol class
*
* @type string
*/
protected $name_long = "Kingpin: Life of Crime";
}

View File

@ -1,214 +0,0 @@
<?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();
}
}

View File

@ -1,44 +0,0 @@
<?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";
}

View File

@ -1,68 +0,0 @@
<?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 Miscreated
*
* @package GameQ\Protocols
* @author Wilson Jesus <>
*/
class Miscreated extends Source
{
/**
* String name of this protocol class
*
* @type string
*/
protected $name = 'miscreated';
/**
* Longer string name of this protocol class
*
* @type string
*/
protected $name_long = "Miscreated";
/**
* query_port = client_port + 2
* 64092 = 64090 + 2
*
* @type int
*/
protected $port_diff = 2;
/**
* Normalize settings for this protocol
*
* @type array
*/
protected $normalize = [
'general' => [
// target => source
'dedicated' => 'dedicated',
'gametype' => 'gametype',
'servername' => 'hostname',
'mapname' => 'mapname',
'maxplayers' => 'maxplayers',
'numplayers' => 'numplayers',
'password' => 'password',
],
];
}

View File

@ -1,43 +0,0 @@
<?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 Modiverse
*
* @package GameQ\Protocols
* @author Austin Bischoff <austin@codebeard.com>
* @author Jesse Lukas <eranio@g-one.org>
*/
class Modiverse extends Source
{
/**
* String name of this protocol class
*
* @type string
*/
protected $name = 'modiverse';
/**
* Longer string name of this protocol class
*
* @type string
*/
protected $name_long = "Modiverse";
}

View File

@ -1,53 +0,0 @@
<?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;
}

View File

@ -1,43 +0,0 @@
<?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 Open Fortress
*
* @package GameQ\Protocols
* @author Austin Bischoff <austin@codebeard.com>
* @author Jesse Lukas <eranio@g-one.org>
*/
class Of extends Source
{
/**
* Open Fortress protocol class
*
* @type string
*/
protected $name = 'of';
/**
* Longer string name of this protocol class
*
* @type string
*/
protected $name_long = "Open Fortress";
}

View File

@ -1,183 +0,0 @@
<?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;
/**
* OpenTTD Protocol Class
*
* Handles processing Open Transport Tycoon Deluxe servers
*
* @package GameQ\Protocols
* @author Wilson Jesus <>
*/
class Openttd 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 => "\x03\x00\x00",
];
/**
* The query protocol used to make the call
*
* @type string
*/
protected $protocol = 'openttd';
/**
* String name of this protocol class
*
* @type string
*/
protected $name = 'openttd';
/**
* Longer string name of this protocol class
*
* @type string
*/
protected $name_long = "Open Transport Tycoon Deluxe";
/**
* The client join link
*
* @type string
*/
protected $join_link = null;
/**
* Normalize settings for this protocol
*
* @type array
*/
protected $normalize = [
// General
'general' => [
// target => source
'hostname' => 'hostname',
'mapname' => 'map',
'maxplayers' => 'max_clients',
'numplayers' => 'clients',
'password' => 'password',
'dedicated' => 'dedicated',
],
];
/**
* Handle response from the server
*
* @return mixed
* @throws Exception
*/
public function processResponse()
{
// Make a buffer
$buffer = new Buffer(implode('', $this->packets_response));
// Get the length of the packet
$packetLength = $buffer->getLength();
// Grab the header
$length = $buffer->readInt16();
//$type = $buffer->readInt8();
$buffer->skip(1); // Skip the "$type" as its not used in the code, and to comply with phpmd it cant be assigned and not used.
// Header
// Figure out which packet response this is
if ($packetLength != $length) {
throw new Exception(__METHOD__ . " response type '" . bin2hex($length) . "' is not valid");
}
return call_user_func_array([$this, 'processServerInfo'], [$buffer]);
}
/**
* 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();
$protocol_version = $buffer->readInt8();
$result->add('protocol_version', $protocol_version);
switch ($protocol_version) {
case 4:
$num_grfs = $buffer->readInt8(); #number of grfs
$result->add('num_grfs', $num_grfs);
//$buffer->skip ($num_grfs * 20); #skip grfs id and md5 hash
for ($i=0; $i<$num_grfs; $i++) {
$result->add('grfs_'.$i.'_ID', strtoupper(bin2hex($buffer->read(4))));
$result->add('grfs_'.$i.'_MD5', strtoupper(bin2hex($buffer->read(16))));
}
// No break, cascades all the down even if case is meet
case 3:
$result->add('game_date', $buffer->readInt32());
$result->add('start_date', $buffer->readInt32());
// Cascades all the way down even if case is meet
case 2:
$result->add('companies_max', $buffer->readInt8());
$result->add('companies_on', $buffer->readInt8());
$result->add('spectators_max', $buffer->readInt8());
// Cascades all the way down even if case is meet
case 1:
$result->add('hostname', $buffer->readString());
$result->add('version', $buffer->readString());
$language = $buffer->readInt8();
$result->add('language', $language);
$result->add('language_icon', '//media.openttd.org/images/server/'.$language.'_lang.gif');
$result->add('password', $buffer->readInt8());
$result->add('max_clients', $buffer->readInt8());
$result->add('clients', $buffer->readInt8());
$result->add('spectators', $buffer->readInt8());
if ($protocol_version < 3) {
$days = ( 365 * 1920 + 1920 / 4 - 1920 / 100 + 1920 / 400 );
$result->add('game_date', $buffer->readInt16() + $days);
$result->add('start_date', $buffer->readInt16() + $days);
}
$result->add('map', $buffer->readString());
$result->add('map_width', $buffer->readInt16());
$result->add('map_height', $buffer->readInt16());
$result->add('map_type', $buffer->readInt8());
$result->add('dedicated', $buffer->readInt8());
// Cascades all the way down even if case is meet
}
unset($buffer);
return $result->fetch();
}
}

View File

@ -1,43 +0,0 @@
<?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";
}

View File

@ -1,50 +0,0 @@
<?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 Postscriptum
*
* @package GameQ\Protocols
* @author Austin Bischoff <austin@codebeard.com>
*/
class Postscriptum extends Source
{
/**
* String name of this protocol class
*
* @type string
*/
protected $name = 'postscriptum';
/**
* Longer string name of this protocol class
*
* @type string
*/
protected $name_long = "Post Scriptum";
/**
* query_port = client_port + 10
* 64092 = 64090 + 10
*
* @type int
*/
protected $port_diff = 10;
}

View File

@ -1,45 +0,0 @@
<?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";
}

View File

@ -1,42 +0,0 @@
<?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";
}

View File

@ -1,43 +0,0 @@
<?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";
}

View File

@ -1,50 +0,0 @@
<?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 rFactor2
*
* @package GameQ\Protocols
* @author Wilson Jesus <>
*/
class Rf2 extends Source
{
/**
* String name of this protocol class
*
* @type string
*/
protected $name = 'rf2';
/**
* Longer string name of this protocol class
*
* @type string
*/
protected $name_long = "rFactor 2";
/**
* query_port = client_port + 2
* 64092 = 64090 + 2
*
* @type int
*/
protected $port_diff = 2;
}

View File

@ -1,55 +0,0 @@
<?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 Rising Storm 2
*
* @package GameQ\Protocols
* @author Austin Bischoff <austin@codebeard.com>
*/
class Risingstorm2 extends Source
{
/**
* String name of this protocol class
*
* @type string
*/
protected $name = 'rising storm 2';
/**
* Longer string name of this protocol class
*
* @type string
*/
protected $name_long = "Rising Storm 2";
/**
* Query port is always 27015
*
* @param int $clientPort
*
* @return int
*/
public function findQueryPort($clientPort)
{
return 27015;
}
}

View File

@ -1,50 +0,0 @@
<?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 Sven Co-op
*
* @package GameQ\Protocols
* @author Austin Bischoff <austin@codebeard.com>
* @author Jesse Lukas <eranio@g-one.org>
*/
class Sco extends Source
{
/**
* Sven Co-op protocol class
*
* @type string
*/
protected $name = 'sco';
/**
* Longer string name of this protocol class
*
* @type string
*/
protected $name_long = "Sven Co-op";
/**
* query_port = client_port + 1
*
* @type int
*/
protected $port_diff = 1;
}

View File

@ -1,75 +0,0 @@
<?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;
/**
* Serious Sam Protocol Class
*
* @author ZCaliptium <zcaliptium@gmail.com>
*/
class Serioussam extends Gamespy
{
/**
* String name of this protocol class
*
* @type string
*/
protected $name = 'serioussam';
/**
* Longer string name of this protocol class
*
* @type string
*/
protected $name_long = "Serious Sam";
/**
* query_port = client_port + 1
*
* @type int
*/
protected $port_diff = 1;
/**
* Normalize settings for this protocol
*
* @type array
*/
protected $normalize = [
// General
'general' => [
// target => source
'dedicated' => 'dedicated',
'gametype' => 'gametype',
'hostname' => 'hostname',
'mapname' => 'mapname',
'maxplayers' => 'maxplayers',
'mod' => 'activemod',
'numplayers' => 'numplayers',
'password' => 'password',
],
// Individual
'player' => [
'name' => 'player',
'ping' => 'ping',
'score' => 'frags',
],
];
}

View File

@ -1,49 +0,0 @@
<?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 7 Days to Die
*
* @package GameQ\Protocols
* @author Austin Bischoff <austin@codebeard.com>
*/
class Sevendaystodie extends Source
{
/**
* String name of this protocol class
*
* @type string
*/
protected $name = 'sevendaystodie';
/**
* Longer string name of this protocol class
*
* @type string
*/
protected $name_long = "7 Days to Die";
/**
* query_port = client_port + 0
*
* @type int
*/
protected $port_diff = 0;
}

View File

@ -1,95 +0,0 @@
<?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;
use GameQ\Buffer;
use GameQ\Result;
/**
* Class Ship
*
* @package GameQ\Protocols
*
* @author Nikolay Ipanyuk <rostov114@gmail.com>
* @author Austin Bischoff <austin@codebeard.com>
*/
class Ship extends Source
{
/**
* String name of this protocol class
*
* @type string
*/
protected $name = 'ship';
/**
* Longer string name of this protocol class
*
* @type string
*/
protected $name_long = "The Ship";
/**
* Specific player parse for The Ship
*
* Player response has unknown data after the last real player
*
* @param \GameQ\Buffer $buffer
*
* @return array
*/
protected function processPlayers(Buffer $buffer)
{
// Set the result to a new result instance
$result = new Result();
// We need to read the number of players because this response has other data at the end usually
$num_players = $buffer->readInt8();
// Player count
$result->add('num_players', $num_players);
// No players, no work
if ($num_players == 0) {
return $result->fetch();
}
// Players list
for ($player = 0; $player < $num_players; $player++) {
$result->addPlayer('id', $buffer->readInt8());
$result->addPlayer('name', $buffer->readString());
$result->addPlayer('score', $buffer->readInt32Signed());
$result->addPlayer('time', $buffer->readFloat32());
}
// Extra data
if ($buffer->getLength() > 0) {
for ($player = 0; $player < $num_players; $player++) {
$result->addPlayer('deaths', $buffer->readInt32Signed());
$result->addPlayer('money', $buffer->readInt32Signed());
}
}
unset($buffer);
return $result->fetch();
}
}

View File

@ -1,42 +0,0 @@
<?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;
/**
* Space Engineers Protocol Class
*
* @package GameQ\Protocols
* @author Austin Bischoff <austin@codebeard.com>
*/
class Spaceengineers extends Source
{
/**
* String name of this protocol class
*
* @type string
*/
protected $name = 'spaceengineers';
/**
* Longer string name of this protocol class
*
* @type string
*/
protected $name_long = "Space Engineers";
}

View File

@ -1,53 +0,0 @@
<?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 Squad
*
* Port reference: http://forums.joinsquad.com/topic/9559-query-ports/
*
* @package GameQ\Protocols
* @author Austin Bischoff <austin@codebeard.com>
*/
class Squad extends Source
{
/**
* String name of this protocol class
*
* @type string
*/
protected $name = 'squad';
/**
* Longer string name of this protocol class
*
* @type string
*/
protected $name_long = "Squad";
/**
* query_port = client_port + 19378
* 27165 = 7787 + 19378
*
* @type int
*/
protected $port_diff = 19378;
}

View File

@ -1,226 +0,0 @@
<?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;
/**
* StarMade Protocol Class
*
* StarMade server query protocol class
*
* Credit to Robin Promesberger <schema@star-made.org> for providing Java based querying as a roadmap
*
* @author Austin Bischoff <austin@codebeard.com>
*/
class Starmade extends Protocol
{
/**
* Array of packets we want to query.
*
* @type array
*/
protected $packets = [
self::PACKET_STATUS => "\x00\x00\x00\x09\x2a\xff\xff\x01\x6f\x00\x00\x00\x00",
];
/**
* 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 = 'starmade';
/**
* String name of this protocol class
*
* @type string
*/
protected $name = 'starmade';
/**
* Longer string name of this protocol class
*
* @type string
*/
protected $name_long = "StarMade";
/**
* 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',
'hostname' => 'hostname',
'maxplayers' => 'max_players',
'numplayers' => 'num_players',
'password' => 'password',
],
];
/**
* Process the response for the StarMade server
*
* @return array
* @throws \GameQ\Exception\Protocol
*/
public function processResponse()
{
// Implode the packets, not sure if there is any split logic for multiple packets
$buffer = new Buffer(implode('', $this->packets_response), Buffer::NUMBER_TYPE_BIGENDIAN);
// Get the passed length in the data side of the packet
$buffer->readInt32Signed();
// Read off the timestamp (in milliseconds)
$buffer->readInt64();
// Burn the check id == 42
$buffer->readInt8();
// Read packetId, unused
$buffer->readInt16Signed();
// Read commandId, unused
$buffer->readInt8Signed();
// Read type, unused
$buffer->readInt8Signed();
$parsed = $this->parseServerParameters($buffer);
// Set the result to a new result instance
$result = new Result();
// Best guess info version is the type of response to expect. As of this commit the version is "2".
$result->add('info_version', $parsed[0]);
$result->add('version', $parsed[1]);
$result->add('hostname', $parsed[2]);
$result->add('game_descr', $parsed[3]);
$result->add('start_time', $parsed[4]);
$result->add('num_players', $parsed[5]);
$result->add('max_players', $parsed[6]);
$result->add('dedicated', 1); // All servers are dedicated as far as I can tell
$result->add('password', 0); // Unsure if you can password servers, cant read that value
//$result->add('map', 'Unknown');
unset($parsed);
return $result->fetch();
}
/**
* Parse the server response parameters
*
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
*
* @param \GameQ\Buffer $buffer
*
* @return array
* @throws \GameQ\Exception\Protocol
*/
protected function parseServerParameters(Buffer &$buffer)
{
// Init the parsed data array
$parsed = [];
// Read the number of parameters to parse
$parameterSize = $buffer->readInt32Signed();
// Iterate over the parameter size
for ($i = 0; $i < $parameterSize; $i++) {
// Read the type of return this is
$dataType = $buffer->readInt8Signed();
switch ($dataType) {
// 32-bit int
case 1:
$parsed[$i] = $buffer->readInt32Signed();
break;
// 64-bit int
case 2:
$parsed[$i] = $buffer->readInt64();
break;
// Float
case 3:
$parsed[$i] = $buffer->readFloat32();
break;
// String
case 4:
// The first 2 bytes are the string length
$strLength = $buffer->readInt16Signed();
// Read the above length from the buffer
$parsed[$i] = $buffer->read($strLength);
unset($strLength);
break;
// Boolean
case 5:
$parsed[$i] = (bool)$buffer->readInt8Signed();
break;
// 8-bit int
case 6:
$parsed[$i] = $buffer->readInt8Signed();
break;
// 16-bit int
case 7:
$parsed[$i] = $buffer->readInt16Signed();
break;
// Array
case 8:
// Not implemented
throw new Exception("StarMade array parsing is not implemented!");
}
}
return $parsed;
}
}

View File

@ -1,50 +0,0 @@
<?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 Stormworks
*
* @package GameQ\Protocols
* @author Austin Bischoff <austin@codebeard.com>
* @author Jesse Lukas <eranio@g-one.org>
*/
class Stormworks extends Source
{
/**
* Stormworks protocol class
*
* @type string
*/
protected $name = 'stormworks';
/**
* Longer string name of this protocol class
*
* @type string
*/
protected $name_long = "Stormworks";
/**
* query_port = client_port + 1
*
* @type int
*/
protected $port_diff = 1;
}

View File

@ -1,50 +0,0 @@
<?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 Swat4
*
* @package GameQ\Protocols
*
* @author Wilson Jesus <>
*/
class Swat4 extends Gamespy2
{
/**
* String name of this protocol class
*
* @type string
*/
protected $name = 'swat4';
/**
* Longer string name of this protocol class
*
* @type string
*/
protected $name_long = "SWAT 4";
/**
* query_port = client_port + 1
*
* @type int
*/
protected $port_diff = 1;
}

View File

@ -1,50 +0,0 @@
<?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 Theforrest
*
* @package GameQ\Protocols
* @author Austin Bischoff <austin@codebeard.com>
*/
class Theforrest extends Source
{
/**
* String name of this protocol class
*
* @type string
*/
protected $name = 'theforrest';
/**
* Longer string name of this protocol class
*
* @type string
*/
protected $name_long = "The Forrest";
/**
* query_port = client_port + 1
*
* @type int
*/
protected $port_diff = 1;
}

View File

@ -1,142 +0,0 @@
<?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;
/**
* Tibia Protocol Class
*
* Tibia server query protocol class
*
* Credit to Ahmad Fatoum for providing Perl based querying as a roadmap
*
* @author Yive <admin@yive.me>
* @author Austin Bischoff <austin@codebeard.com>
*/
class Tibia extends Protocol
{
/**
* Array of packets we want to query.
*
* @type array
*/
protected $packets = [
self::PACKET_STATUS => "\x06\x00\xFF\xFF\x69\x6E\x66\x6F",
];
/**
* 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 = 'tibia';
/**
* String name of this protocol class
*
* @type string
*/
protected $name = 'tibia';
/**
* Longer string name of this protocol class
*
* @type string
*/
protected $name_long = "Tibia";
/**
* The client join link
*
* @type string
*/
protected $join_link = "otserv://%s/%d/";
/**
* Normalize settings for this protocol
*
* @type array
*/
protected $normalize = [
// General
'general' => [
// target => source
'dedicated' => 'dedicated',
'gametype' => 'server',
'hostname' => 'servername',
'motd' => 'motd',
'maxplayers' => 'players_max',
'numplayers' => 'players_online',
'map' => 'map_name',
],
];
/**
* Process the response for the Tibia server
*
* @return array
* @throws \GameQ\Exception\Protocol
*/
public function processResponse()
{
// Merge the response packets
$xmlString = implode('', $this->packets_response);
// Check to make sure this is will decode into a valid XML Document
if (($xmlDoc = @simplexml_load_string($xmlString)) === false) {
throw new Exception(__METHOD__ . " Unable to load XML string.");
}
// Set the result to a new result instance
$result = new Result();
// All servers are dedicated as far as I can tell
$result->add('dedicated', 1);
// Iterate over the info
foreach (['serverinfo', 'owner', 'map', 'npcs', 'monsters', 'players'] as $property) {
foreach ($xmlDoc->{$property}->attributes() as $key => $value) {
if (!in_array($property, ['serverinfo'])) {
$key = $property . '_' . $key;
}
// Add the result
$result->add($key, (string)$value);
}
}
$result->add("motd", (string)$xmlDoc->motd);
unset($xmlDoc, $xmlDoc);
return $result->fetch();
}
}

View File

@ -1,49 +0,0 @@
<?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;
/**
* Unturned Protocol Class
*
* @package GameQ\Protocols
* @author Austin Bischoff <austin@codebeard.com>
*/
class Unturned extends Source
{
/**
* String name of this protocol class
*
* @type string
*/
protected $name = 'unturned';
/**
* Longer string name of this protocol class
*
* @type string
*/
protected $name_long = "Unturned";
/**
* query_port = client_port + 1
*
* @type int
*/
protected $port_diff = 1;
}

View File

@ -1,49 +0,0 @@
<?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;
/**
* Urban Terror Class
*
* @package GameQ\Protocols
* @author Austin Bischoff <austin@codebeard.com>
*/
class Urbanterror extends Quake3
{
/**
* String name of this protocol class
*
* @type string
*/
protected $name = 'urbanterror';
/**
* Longer string name of this protocol class
*
* @type string
*/
protected $name_long = "Urban Terror";
/**
* The client join link
*
* @type string
*/
protected $join_link = "urt://%s:%d/";
}

View File

@ -1,48 +0,0 @@
<?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;
/**
* Valheim Protocol Class
*
* @package GameQ\Protocols
*/
class Valheim extends Source
{
/**
* String name of this protocol class
*
* @type string
*/
protected $name = 'valheim';
/**
* Longer string name of this protocol class
*
* @type string
*/
protected $name_long = "Valheim";
/**
* query_port = client_port + 1
*
* @type int
*/
protected $port_diff = 1;
}

View File

@ -1,48 +0,0 @@
<?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;
/**
* V Rining Protocol Class
*
* @package GameQ\Protocols
*/
class Vrising extends Source
{
/**
* String name of this protocol class
*
* @type string
*/
protected $name = 'vrising';
/**
* Longer string name of this protocol class
*
* @type string
*/
protected $name_long = "V Rising";
/**
* query_port = client_port + 1
*
* @type int
*/
protected $port_diff = 1;
}

View File

@ -1,66 +0,0 @@
<?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;
/**
* World Opponent Network (WON) class
*
* Pre-cursor to the A2S (source) protocol system
*
* @author Nikolay Ipanyuk <rostov114@gmail.com>
* @author Austin Bischoff <austin@codebeard.com>
*
* @package GameQ\Protocols
*/
class Won extends Source
{
/**
* Array of packets we want to look up.
* Each key should correspond to a defined method in this or a parent class
*
* @type array
*/
protected $packets = [
self::PACKET_DETAILS => "\xFF\xFF\xFF\xFFdetails\x00",
self::PACKET_PLAYERS => "\xFF\xFF\xFF\xFFplayers",
self::PACKET_RULES => "\xFF\xFF\xFF\xFFrules",
];
/**
* The query protocol used to make the call
*
* @type string
*/
protected $protocol = 'won';
/**
* String name of this protocol class
*
* @type string
*/
protected $name = 'won';
/**
* Longer string name of this protocol class
*
* @type string
*/
protected $name_long = "World Opponent Network";
}

View File

@ -1,42 +0,0 @@
<?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;
/**
* Wurm Unlimited Protocol Class
*
* @package GameQ\Protocols
* @author Austin Bischoff <austin@codebeard.com>
*/
class Wurm extends Source
{
/**
* String name of this protocol class
*
* @type string
*/
protected $name = 'wurm';
/**
* Longer string name of this protocol class
*
* @type string
*/
protected $name_long = "Wurm Unlimited";
}

View File

@ -1,42 +0,0 @@
<?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;
/**
* Project Zomboid Protocol Class
*
* @package GameQ\Protocols
* @author Austin Bischoff <austin@codebeard.com>
*/
class Zomboid extends Source
{
/**
* String name of this protocol class
*
* @type string
*/
protected $name = 'zomboid';
/**
* Longer string name of this protocol class
*
* @type string
*/
protected $name_long = "Project Zomboid";
}

View File

@ -1,53 +0,0 @@
<?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;
}

View File

@ -1,50 +0,0 @@
<?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;
}

View File

@ -1,32 +0,0 @@
<?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
{
}

View File

@ -1,217 +0,0 @@
<?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));
// Check for valid response
if ($buffer->getLength() < 4) {
throw new \GameQ\Exception\Protocol(sprintf('%s The response from the server was empty.', __METHOD__));
}
// Read the header
$header = $buffer->read(4);
// Verify header
if ($header !== 'EYE1') {
throw new \GameQ\Exception\Protocol(sprintf('%s The response header "%s" does not match expected "EYE1"', __METHOD__, $header));
}
// 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));
}
}
}
}

View File

@ -1,88 +0,0 @@
<?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',
],
];
}

View File

@ -1,98 +0,0 @@
<?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',
],
];
}

View File

@ -1,348 +0,0 @@
<?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();
}
}

View File

@ -1,114 +0,0 @@
<?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();
}
}

View File

@ -1,326 +0,0 @@
<?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();
}
}

View File

@ -1,50 +0,0 @@
<?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;
}

View File

@ -1,43 +0,0 @@
<?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";
}

View File

@ -1,42 +0,0 @@
<?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";
}

View File

@ -1,42 +0,0 @@
<?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";
}

Some files were not shown because too many files have changed in this diff Show More