No changes

This commit is contained in:
Frank Harris 2025-09-11 13:29:15 -04:00
parent 8680a02b13
commit b6b398f5bf
17374 changed files with 2475441 additions and 0 deletions

View file

@ -0,0 +1,396 @@
<?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/>.
*
*
*/
/**
* Provide an interface for easy manipulation of a server response
*
* @author Aidan Lister <aidan@php.net>
* @author Tom Buskens <t.buskens@deviation.nl>
* @version $Revision: 1.4 $
*/
class GameQ_Buffer
{
/**
* The original data
*
* @var string
* @access public
*/
private $data;
/**
* The original data
*
* @var string
* @access public
*/
private $length;
/**
* Position of pointer
*
* @var string
* @access public
*/
private $index = 0;
/**
* Constructor
*
* @param string|array $response The data
*/
public function __construct($data)
{
$this->data = $data;
$this->length = strlen($data);
}
/**
* Return all the data
*
* @return string|array The data
*/
public function getData()
{
return $this->data;
}
/**
* Return data currently in the buffer
*
* @return string|array 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 Length of data to read
* @return string The data read
*/
public function read($length = 1)
{
if (($length + $this->index) > $this->length) {
throw new GameQ_ProtocolsException('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 The data read
*/
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 Length of data to read
* @return string The data read
*/
public function lookAhead($length = 1)
{
$string = substr($this->data, $this->index, $length);
return $string;
}
/**
* Skip forward in the buffer
*
* @param int $length Length of data to skip
* @return void
*/
public function skip($length = 1)
{
$this->index += $length;
}
/**
* Jump to a specific position in the buffer,
* will not jump past end of buffer
*
* @param int $index Position to go to
* @return void
*/
public function jumpto($index)
{
$this->index = min($index, $this->length - 1);
}
/**
* Get the current pointer position
*
* @return int The current pointer position
*/
public function getPosition()
{
return $this->index;
}
/**
* Read from buffer until delimiter is reached
*
* If not found, return everything
*
* @param string $delim Read until this character is reached
* @return string The data read
*/
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
*
* @paran 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 The data read
*/
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 array $delims Read until these characters are reached
* @return string The data read
*/
public function readStringMulti($delims, &$delimfound = null)
{
// Get position of delimiters
$pos = array();
foreach ($delims as $delim) {
if ($p = strpos($this->data, $delim, min($this->index, $this->length))) {
$pos[] = $p;
}
}
// If none are found then return whole buffer
if (empty($pos)) {
return $this->read(strlen($this->data) - $this->index);
}
// Read the string and remove the delimiter
sort($pos);
$string = $this->read($pos[0] - $this->index);
$delimfound = $this->read();
return $string;
}
/**
* Read a 32-bit unsigned integer
*/
public function readInt32()
{
$int = unpack('Lint', $this->read(4));
return $int['int'];
}
/**
* Read a 32-bit signed integer
*/
public function readInt32Signed()
{
$int = unpack('lint', $this->read(4));
return $int['int'];
}
/**
* Read a 16-bit unsigned integer
*/
public function readInt16()
{
$int = unpack('Sint', $this->read(2));
return $int['int'];
}
/**
* Read a 16-bit signed integer
*/
public function readInt16Signed()
{
$int = unpack('sint', $this->read(2));
return $int['int'];
}
/**
* Read a 16-bit unsigned little endian integer
*/
public function readInt16LE()
{
$int = unpack('vint', $this->read(2));
return $int['int'];
}
/**
* Read a 16-bit unsigned big endian integer
*/
public function readInt16BE()
{
$int = unpack('nint', $this->read(2));
return $int['int'];
}
/**
* Read an int8 from the buffer
*
* @return int The data read
*/
public function readInt8()
{
return ord($this->read(1));
}
/**
* Read an float32 from the buffer
*
* @return int The data read
*/
public function readFloat32()
{
$float = unpack('ffloat', $this->read(4));
return $float['float'];
}
/**
* Conversion to float
*
* @access public
* @param string $string String to convert
* @return float 32 bit float
*/
public function toFloat($string)
{
// Check length
if (strlen($string) !== 4) {
return false;
}
// Convert
$float = unpack('ffloat', $string);
return $float['float'];
}
/**
* Conversion to integer
*
* @access public
* @param string $string String to convert
* @param int $bits Number of bits
* @return int Integer according to type
*/
public function toInt($string, $bits = 8)
{
// Check length
if (strlen($string) !== ($bits / 8)) {
return false;
}
// Convert
switch($bits) {
// 8 bit unsigned
case 8:
$int = ord($string);
break;
// 16 bit unsigned
case 16:
$int = unpack('Sint', $string);
$int = $int['int'];
break;
// 32 bit unsigned
case 32:
$int = unpack('Lint', $string);
$int = $int['int'];
break;
// Invalid type
default:
$int = false;
break;
}
return $int;
}
}

View file

@ -0,0 +1,34 @@
<?php
/**
* This file is part of GameQ.
*
* GameQ is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* GameQ is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* Generic function to make extending shorter
*
* @author Austin Bischoff <austin@codebeard.com>
*/
abstract class GameQ_Filters extends GameQ_Filters_Core {}
/**
* GameQ Filters Exception
*
* Allows for a level of exception handling incase there is an issue/error within
* a filter or a required dependency has not been met.
*
* @author Austin Bischoff <austin@codebeard.com>
*/
class GameQ_FiltersException extends Exception {}

View file

@ -0,0 +1,55 @@
<?php
/**
* This file is part of GameQ.
*
* GameQ is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* GameQ is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* Abstract class which all filters must inherit
*
* @author Austin Bischoff <austin@codebeard.com>
*/
abstract class GameQ_Filters_Core
{
protected $params = array();
/**
* Constructor, receives parameters
*
* @param array $params Filter parameters
*/
function __construct($params)
{
if(is_array($params))
{
foreach ($params as $key => $param)
{
$this->params[$key] = $param;
}
}
else
{
$this->params = $params;
}
}
/**
* Actually apply the filter to the passed results
*
* @param array $results
* @param GameQ_Protocols_Core $protocol_instance
*/
abstract public function filter($results, GameQ_Protocols_Core $protocol_instance);
}

View file

@ -0,0 +1,193 @@
<?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/>.
*/
/**
* This filter makes sure a fixed set of properties (i.e. gq_) is always available regardless of protocol
*
* @author Austin Bischoff <austin@codebeard.com>
*/
class GameQ_Filters_Normalise extends GameQ_Filters
{
/**
* Default normalization items. Can be overwritten on a protocol basis.
*
* @var array
*/
protected $normalize = array(
// General
'general' => array(
// target => source
'dedicated' => array('listenserver', 'dedic', 'bf2dedicated', 'netserverdedicated', 'bf2142dedicated'),
'gametype' => array('ggametype', 'sigametype', 'matchtype'),
'hostname' => array('svhostname', 'servername', 'siname', 'name'),
'mapname' => array('map', 'simap'),
'maxplayers' => array('svmaxclients', 'simaxplayers', 'maxclients'),
'mod' => array('game', 'gamedir', 'gamevariant'),
'numplayers' => array('clients', 'sinumplayers'),
'password' => array('protected', 'siusepass', 'sineedpass', 'pswrd', 'gneedpass', 'auth'),
'players' => array('players'),
'teams' => array('team'),
),
// Indvidual
'player' => array(
'name' => array('nick', 'player', 'playername', 'name'),
'kills' => array('kills'),
'deaths' => array('deaths'),
'score' => array('kills', 'frags', 'skill', 'score'),
'ping' => array('ping'),
),
// Team
'team' => array(
'name' => array('name', 'teamname', 'team_t'),
'score' => array('score', 'score_t'),
),
);
/**
* Normalize the server data
* @see GameQ_Filters_Core::filter()
*/
public function filter($data, GameQ_Protocols_Core $protocol_instance)
{
$result = array();
// No data passed so something bad happened
if(empty($data))
{
return $result;
}
// Here we check to see if we override these defaults.
if(($normalize = $protocol_instance->getNormalize()) !== FALSE)
{
// Merge this stuff in
$this->normalize = array_merge_recursive($this->normalize, $normalize);
}
// normalize the general items
$result = $this->normalize($data, 'general');
// normalize players
if (isset($result['gq_players']) && is_array($result['gq_players']))
{
// Don't rename the players array
$result['players'] = $result['gq_players'];
foreach ($result['players'] as $key => $player)
{
$result['players'][$key] = array_merge($player, $this->normalize($player, 'player'));
}
$result['gq_numplayers'] = count($result['players']);
}
else
{
$result['players'] = array();
}
// normalize teams
if (isset($result['gq_teams']) && is_array($result['gq_teams']))
{
// Don't rename the teams array
$result['teams'] = $result['gq_teams'];
foreach ($result['teams'] as $key => $team)
{
$result['teams'][$key] = array_merge($team, $this->normalize($team, 'team'));
}
$result['gq_numteams'] = count($result['teams']);
}
else
{
$result['teams'] = array();
}
unset($result['gq_players'], $result['gq_teams']);
// Merge and sort array
$result = (array_merge($data, $result));
ksort($result);
return $result;
}
/**
* normalize an array
*
* @param array $data The data to normalize
* @param array $properties The properties we want to normalize
* @return array A normalized array
*/
private function normalize($data, $properties)
{
// Make sure this is not empty
if(!isset($this->normalize[$properties]))
{
// We just return empty array
return array();
}
$props = $this->normalize[$properties];
// Create a new array, with all the specified variables
$new = $this->fill($props);
foreach ($data as $var => $value)
{
// normalize values
$stripped = strtolower(str_replace('_', '', $var));
foreach ($props as $target => $sources)
{
if ($target == $stripped or in_array($stripped, $sources))
{
$new['gq_' . $target] = $value;
//unset($vars[$target]);
break;
}
}
}
return $new;
}
/**
* Fill array with array keys
*
* @param array $vars The array keys
* @param mixed $val Value of each key
* @return array An array filled with keys
*/
private function fill($vars, $val = false)
{
$data = array();
foreach ($vars as $target => $source)
{
$data['gq_' . $target] = $val;
}
return $data;
}
}

View file

@ -0,0 +1,76 @@
<?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/>.
*/
/**
* Strip color codes from specific protocol types. This code was adapted from the original filter class
*
* @author Austin Bischoff <austin@codebeard.com>
*/
class GameQ_Filters_Stripcolor extends GameQ_Filters
{
/**
* Strip all the color junk from returns
* @see GameQ_Filters_Core::filter()
*/
public function filter($data, GameQ_Protocols_Core $protocol_instance)
{
// Check the type of protocol
switch($protocol_instance->protocol())
{
case 'quake2':
case 'quake3':
case 'doom3':
array_walk_recursive($data, array($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($data, array($this, 'stripUT'));
break;
default:
break;
}
return $data;
}
/**
* Strips quake color tags
*
* @param $string string String to strip
* @param $key string Array key
*/
protected function stripQuake(&$string, $key)
{
$string = preg_replace('#(\^.)#', '', $string);
}
/**
* Strip UT color tags
*
* @param $string string String to strip
* @param $key string Array key
*/
protected function stripUT(&$string, $key)
{
$string = preg_replace('/\x1b.../', '', $string);
}
}

View file

@ -0,0 +1,37 @@
<?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/>.
*/
/**
* Generic function to make extending shorter
*
* @author Austin Bischoff <austin@codebeard.com>
*/
abstract class GameQ_Protocols extends GameQ_Protocols_Core
{
}
/**
* GameQ Protocol Exception
*
* Allows for another level of exception handling when doing loops. Makes it possible to recover and continue
* when there is an exception within one of the protocol classes.
*
* @author Austin Bischoff <austin@codebeard.com>
*/
class GameQ_ProtocolsException extends Exception {}

View file

@ -0,0 +1,44 @@
<?php
/**
* This file is part of GameQ.
*
* GameQ is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* GameQ is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* 7 Days to Die Protocol Class
*
* @author Austin Bischoff <austin@codebeard.com>
*/
class GameQ_Protocols_7d2d extends GameQ_Protocols_Source
{
protected $name = "7d2d";
protected $name_long = "7 Days to Die";
/**
* Overload for client port
*
* @param string $ip
* @param integer $port
* @param array $options
*/
public function __construct($ip = FALSE, $port = FALSE, $options = array())
{
// Got to do this first
parent::__construct($ip, $port, $options);
// Correct the client port since query_port = client_port + 1
$this->port_client(($this->port_client() - 1));
}
}

View file

@ -0,0 +1,32 @@
<?php
/**
* This file is part of GameQ.
*
* GameQ is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* GameQ is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* America's Army 1/2 Protocol Class
*
* @author Austin Bischoff <austin@codebeard.com>
*/
class GameQ_Protocols_Aa extends GameQ_Protocols_Gamespy2
{
protected $name = "aa";
protected $name_long = "America's Army";
protected $link_join = "aao://%s:%d/";
protected $port = 1717;
}

View file

@ -0,0 +1,32 @@
<?php
/**
* This file is part of GameQ.
*
* GameQ is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* GameQ is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* America's Army 3 Protocol Class (Version 3.2+)
*
* @author Austin Bischoff <austin@codebeard.com>
*/
class GameQ_Protocols_Aa3 extends GameQ_Protocols_Source
{
protected $name = "aa3";
protected $name_long = " America's Army 3 (> 3.2)";
protected $link_join = "aa3://%s:%d/";
protected $port = 27020;
}

View file

@ -0,0 +1,425 @@
<?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/>.
*/
/**
* America's Army 3 Protocol Class (Version < 3.2)
*
* @author Austin Bischoff <austin@codebeard.com>
*/
class GameQ_Protocols_Aa3pre32 extends GameQ_Protocols
{
/**
* This class is no longer valid
*
* @var int
*/
protected $state = self::STATE_DEPRECATED;
/**
* Array of packets we want to look up.
* Each key should correspond to a defined method in this or a parent class
*
* @var array
*/
protected $packets = array(
self::PACKET_ALL => "\x4A\x35\xFF\xFF\x02\x00\x02\x00\x01\x00%s",
);
/**
* Methods to be run when processing the response(s)
*
* @var array
*/
protected $process_methods = array(
"process_all",
);
/**
* Default port for this server type
*
* @var int
*/
protected $port = 39300; // Default port, used if not set when instanced
/**
* The protocol being used
*
* @var string
*/
protected $protocol = 'aa3pre32';
/**
* String name of this protocol class
*
* @var string
*/
protected $name = 'aa3pre32';
/**
* Longer string name of this protocol class
*
* @var string
*/
protected $name_long = "America's Army 3 (< 3.2)";
/*
* Internal methods
*/
/**
* Called before the $this->packets are sent.
*
* @see GameQ_Protocols_Core::beforeSend()
*/
public function beforeSend()
{
// Encrypt the data we want to send
$enc_data = $this->ssc_crypt("\x0A\x00playerName\x06\x06\x00query\x00", TRUE);
// Apply this to the packet
$this->packets[self::PACKET_ALL] = sprintf($this->packets[self::PACKET_ALL], $enc_data);
return TRUE;
}
protected function preProcess_all($packets=array())
{
// Check to make sure we have zlib installed
if(!function_exists('gzuncompress'))
{
throw new GameQ_ProtocolsException('Zlib is not installed. See http://www.php.net/manual/en/book.zlib.php for more info.', 0);
return FALSE;
}
// We only got one packet
if(count($packets) == 1)
{
// @todo: Looking for example to test and verify
$packets[0] = substr($packets[0], 10);
}
else // Multiple Packets
{
$packets_sorted = array();
// We need to sort the packets to make sure they are in the proper order
foreach($packets AS $packet)
{
$packets_sorted[ord($packet[10])] = substr($packet, 14);
}
// Key sort the packets
ksort($packets_sorted);
$packets = $packets_sorted;
unset($packet, $packets_sorted);
}
// Merge all the packets and decypt the data
$data = $this->ssc_crypt(trim(implode("", $packets)), FALSE);
// Decompress and return
return gzuncompress($data);
}
protected function process_all()
{
// Make sure we have a valid response
if(!$this->hasValidResponse(self::PACKET_ALL))
{
return array();
}
// Set the result to a new result instance
$result = new GameQ_Result();
// Let's preprocess the rules
$data = $this->preProcess_all($this->packets_response[self::PACKET_ALL]);
// Lets parse out all the data
if(preg_match('/attributeNames(.+)attributeValues(.+)resultCode(.*)/ism', $data, $m) === FALSE)
{
throw new GameQ_ProtocolsException("AA3 Packet response is not in a valid format");
return array();
}
// Init temp array
$tmp = array(
"keys" => array(),
"values" => array(),
);
// Pull the array into named vars
list($all, $keys, $values, $resultcode) = $m;
// Lets look at all the keys
$buf = new GameQ_Buffer($keys);
// Skip
$buf->skip(4);
while($buf->getLength())
{
// Pull out the string and strip out any junk
$str = preg_replace('/[^[:alnum:][:punct:]\s]/', '', trim($buf->readString(), "\x00..\x1F"));
// Do not continue on empty strings
if(strlen($str) == 0)
{
continue;
}
// Add to the temp list. We will clean this up later
$tmp['keys'][] = $str;
}
// Now lets loop the values
$buf = new GameQ_Buffer($values);
// Skip
$buf->skip(4);
while($buf->getLength())
{
$str = preg_replace('/[^[:alnum:][:punct:]\s]/', '', trim($buf->readString(), "\x00..\x1F"));
// Do not continue on empty strings
if(strlen($str) == 0)
{
continue;
}
// Add to the temp list. We will clean this up later
$tmp['values'][] = $str;
}
// Combine the keys and values
$tmp = array_combine($tmp['keys'], $tmp['values']);
$teams = array();
$team = FALSE;
// Let's parse the combined array and make the result.
foreach($tmp AS $key => $value)
{
// Is player
if(preg_match('/^player(\D+)(\d+)$/', $key, $matches))
{
$result->addPlayer($matches[1], $value);
// See if this is a team value
if($matches[1] == 'Team')
{
$team = $value;
}
elseif ($matches[1] == 'TeamIndex' && !array_key_exists($value, $teams))
{
$teams[$value] = $team;
}
}
else // Is server var
{
$result->add(substr($key, 6), $value);
}
}
// Do the teams
foreach ($teams AS $teamIndex => $teamName)
{
$result->addTeam('name', $teamName);
$result->addTeam('index', $teamIndex);
}
unset($buf, $tmp, $data, $keys, $values, $resultcode, $matches, $teams);
return $result->fetch();
}
/**
* encrypt|decrypt the buffer.
*
* @param string $buffer
* @param bool $encrypt
*/
protected function ssc_crypt($buffer, $encrypt = FALSE)
{
$master_key = pack("H*",
"f5c5914b27235dc0dc274200ddd187c32fe02aed5fc5c079518f49208e4c5548aaef313c5d2e7c91dc580d3cd9e1aec577595325d3c5c84b44a020802becb17e".
"7d6b6b87e8a4ebc8e4cafbaf5720f9600818b334ad2695ba0f19e1fbd48d0139f05e9059e98a15c79ebabb4f3aa8039d8720aef2bf1b4693a67a20a114b8505b".
"693cf5b24a236503582ecdb8109a7d89a8d90d660b96435b4656ecec3fff2086e94c54988843d2aa55adefb2d47fc804c0024a7897e993b2326e8990e425f7c8".
"38aef55f2002f22d84479f43849de260a8a2de6a7de09225c275a172729e65be687182bde68cb17b3fd77bf513c8045f0b6696d3a501b255db0632e36c0e7806".
"c5c193b5b9a9c621f0ac9a0ee72196edbb336e7431b75eba95d02191048ab7c3874578218d79a2623e308184fdac98a1568c09b8907d8411e29c53823a3a68bc".
"c785547ebb29401822da7fa59c6fc412cf2a9201f31336bcdffe78501058b1d7814e920ceee7aca8fa798f10f0a8ba19a1deae864e1c77f974880e5571a4380b".
"52d3357ec8cbf8ff6ff7e8f3fa6223f923e4a7bb1918054bcd2a115e466307f39d964c051983f8b2e5db0b39332ec08c94d9b36a4594ab5e868bc888e4586687".
"b6e62b2bb06ad0903544e379d744896f95346a0238b2b72c6d38ed1bf011185bad1910812cfe2c5b38db10433088f2e5a3746e7302467d35e8f07722fad1f7d4".
"283fbea23fa6f50f710491b1f0a8dd3a187939e7f344de57c256ffb063791fc556d3791570a873537c3f05f8ca08aa1eb2e3f641e0fb46fde7394f8fb4c216d7".
"55c020b405a21b8e4340136fc9583800afd87a677d3d9b6b95585ba502d6db2dec504f25b612340e29be64700682f4f012908e2672916ba83d35deb58d826d83".
"d75a61f726876747d78df10a31f6acb36cb64dec47b7da11c7e7177dcc097965a50065e8e5f91732e20647604c00c0fa451f7ee140d93515b7b5e6f9e0c92ad0".
"29648ab1e0ea363c5a19d12832c54c0ae67baa7e029217ede5f97cd07ebf3aaf14c020f4646e3792e2472409299868b9ee1ce7a69a30203218289523d848a2ee".
"42b96edf05f24182491dfb048c17f815aa8983d9ab72723defbe9750cd694bc1318c92862ed7b7ab1e37472b986a7f4745224fd723e4e6ef53ff6d5f51f1b8cd".
"34b32b9ac92968e5ec8b631aa750e7cec51e7fddca5da1cdc836c0243ab2a2f86d072479c117738fafba4d72db6fee13274d652a7c76ff962c1389b32f95f3c0".
"04d178b71646fe084507e7dd4b4db98405cb72399f78f989c188fb2ed6e18e5aa417adae504d33ad8414f9e3a6e466837062e8ea91664f63134539679b119d6b".
"3918f833ceddc249933b0ae83e0965b38fb86d3da02622d02f57c7282e5f0cdb18f71e7450c538ddca55588575f80754dd0c89840bcf7e246e8f041309069f15".
"a49c27fa0a5913c72be881ae27ff6b0332701d96dc295576d2a9bc0fd266f5604da647f78d1c2ced95c4cf8a929c55bf524198898b444c67040d7c7debcc3cc9".
"7cab1a8fe190f4db097beaccea9a34e38380b43bd2b2bf98f471c02894aaaf3944680988497aa74d293238d503a4df19d90af204fdcbb1875170a96b7f3e288c".
"0f24e1c8b9ce4f77f2b03944c2abbacba69331a244923c38f731f368d10eca82dd503bdece016064c68cb38a4e3408712959cb5216dc42bf5365eb789c484bcc".
"5813a1f1680fc5606e8da06bd5a68a73bd593fcd4aeb9aca06bb258f84a38dd0d4c6c0c355c4d5e0e1a97abaa11869f26285a99db4dfb8eab0b0f53e80d2486b".
"9a6cc63affac0b830b12434ddbc1c4ef3ee46af67fcc711b88a352d2b324c0acfb35bfbe74865afd7f3293a944cd9f69230a206c5112ed9858497ddc118c0338".
"63f1a974b033a225c74e83c9d1bec1a3e6a7b2b7ddab58aec40fe4bed9e2fd1beaded608c695dafaf4d683fdf3b9175d1283d7d99b47c40209a555c317e29bad".
"574ac49e78ae91896b527d27f04d89b10d5f754b953d1218bf01fc06086c031ff334eab692e9c6fb221ac0f3027283ac5350d860f2d6125d31edf4b7ac806f21".
"abeb04f84230e8c17455e54a27d6862cfb3279370eae1cdb1f84c10209e89241182c307b45a6b97520a62bc263c66f78d27b52ad9728f5d78c1626297b1d1cdd".
"e47fd67d9f1f4846a3643810359f2cc6b22a662683836eb48f6e1605be3a830fe29f0c54412e7d82aefff9748a2fddb368dd0103161e2a17da69216e22adf6b5".
"7ce255e400279188655820eedd5a1935aa3d8cf621fa312bab89cbb3071bfbe7e0635126de8217bd5c342f35824511769ac6b72de09b87012cd85f2cbef53e11".
"9aba484771b15bddda183501230ae6a16fcde55a161df16f178e04478a3711437dc91eeabe92e14b44d2f49036532be42c425346df9d91288aa409a63272e061".
"baaaca491cc04c44b2ac739290baa76d9fdc7b66733548af6411a6ba790c4962ddf033e63fab462bc0ccbfa45d45ce377d32f4c7e905cab5fbbb524f8c2907d0".
"41b304d1f38f348efd34a7d51c118445d05353b5f0449f368450782df457ca55169bdfa817a94e1082faf4115cf3d6d890481affb2feb95145691f152485465d".
"0f8dba4cde2079784574fadbe805222e3a132934f1a419cda032b310fd7dfa2830d3f3385d646ba0c373cba4d624a6267300014cdd2dd5e87999aa5b0e5df0a8".
"de50f3473918474ccf82f9c8ab9f31379a9d8d00bead3bc8b9d00f4ebba9c7b0ea882454e3a785e096d7887b3a507f089dba88925df12c633241ed2f9f68905b".
"66775d1d0ca3cc312f7be8641856be8de24248e55dd737df8410e23e9457024f534261f09ab278821b1c89da824f7f546a4163f4d53ccf07ee9bd59adb673822".
"87092b94a7847141a796a6abf90f7bfa5d8967bfba2275283863bfc3f8283f0e5b223748a55dff04f3c6bf228bb1e0bfd2c80289abf5819e165268b4e687bcf4".
"a33f1c42c47a6236ca14c26778ad2cbe013c20807e45276d49a4e0df7df7c42d2c73f298f61fc8e778ba953a71c6b7d1779624552df0f3896a790671a3a981fa".
"17914d856321d0997ff4b2d05944335ceac60b63b1d827eab5ef7483990e9bd1b5453a473e1efd476ba1e093466cb21dc72e35dc12bb8c8d3bb29db420251590".
"32441b8a7e9458cad9cdc1551ce52312bb27d858a8ae319e525b38f20242a60933b2a21bd858e147cc6ee702983c84bf535d1575a54dc46c03cdb42a39d1a64e".
"433d9bea41f9915f7d9d462d4308baccb19bb1adc3e0125715950f7c7f8b54312826204fd512386da587bad7bf81069dc554fd8fd77153832225e56a7fa4046b".
"d588ed258dc7e54ccf1c021f9800376376bdcfc62116555ab0e06b3161b3b7a6a7a87de2371215207c43fce54c82feddc5d444b08f6a30c0095007d526da1b02".
"41563a9360f86ef3b824294bd174679f4dee74912acdeb00ac96a713ad86dc212a544b7420fa6c83d5dec48400e1f11f8163e20c932bc893820a8261939e0f85".
"fdb416c6a0a18cc0182d675702a8362694f23ce686962150f862357fe84a0b572068c7e0578909d7f82c87cd17e7ef50e5566eab694ac76edb4b6d8a85cd2910".
"0b93272b0a524a24db8db7d4622fae63d982e4090fb519e30736d5b5152d58a234919d216d0294628841cba91ed72d985ba92f7cc548378e7ddf812816ad99dd".
"27adffdf5b6d762a79a942d8af9a8f0ac81afc98869dcdcc06835478947ced5ccbb22d02624e207c774042fa8c133221c362bef69582c52ca9c014db1ec2d351".
"a1d72bb01c06e32ca0a4ecfe923737f0f7145b27c943a9be1f174dd46d3af58e7a2f612177affd11ae7e1b9231aadb46bcb732ee79de7e62f467721f06d8e9e5".
"59b526bb702ddbc0f0b46a2162458c15c0154cbb1b1edad3fa198a0781279ecc5e5391269c335bc94b2f21da781cf943cd0e700206128fe1f1e3af4e70bfbaec".
"1c7ae4884c7e7544050036b001f87fc2f10762888701c160010e7691ea2b53b646d22178ebf1a56eb9cba86ffa2b570d846e231037d403298103c61732b04113".
"ff7ec74e0a671332f7df9da231f995c1fb53523c17c23105312b7d8ab63e5f6a0e7b9d106f3ce575d14befb3a5803aabcc9edb5f1ddf9dcabff4efbd785b169d".
"f7fb1b991faf63f064b5fc8f2c7fcac4b35a61f19c92dec36a6aadf02dc3942dde51d7225aefeaf6b7527183c2adc832c6bc8735bc7be2c18ad3d70653f91581".
"ce42a275ef6715932ae7513d0ecb726be54c167cc89445a08cb8e12fc583aee815b3947bd1ac781fcbfbdda25fe3e931a21c47058197ceffbe9bd2ac6394b2d5".
"95c3e10076c3aceba33b1556029edfbc04849e0d66713f7beeb1517dcd43279a5073ec9fa221bfaceef0f639e771a44156778cbb696af28e2437eea3fc025d27".
"70b1409d978e4ec808c58288d525ac977db0ace80d9554925bf8767b8e91a9bf1ed25deabdbb93315ca08f711ae3f768a911eeacd93bfa6db3957da83c0fd945".
"a7e596b66530aa7347e04590fd31db6b49485a9ea8208c0aab4068f482b185aaed6ee69e32f9ff7b882763da34f6e3bce94c79353ef6849d47e6345d8727e076".
"f1aa0133c2399e4d777525fe9aa29e75d23df6e829f9058580413d5c24f85568beb1343430f393adee28ab54e220b4c884fa6ebc2825705f863ba7d82977f653".
"edb2088abd84ad52a1810a52abc6e7c3b5687f3bf4744941ce48c876205f2497b641e6e4bb565ab816425c348e1f034104efda9a21723b00cdadc6ed2af6b225".
"524ae512afba6bc19c471e14bbba042dba641424005a816f25aee44ee84cf2f729b79b1b9d58218f0274d92168c9bb1cd1c141b5f8341a3a4dc78c0ddf08dfd4".
"110b4eb0b71b265fe70aa5a4b2186cafad5ff94dafd5b4b4560bac45cb47c4c863274ac2d84af46b75bfde496d39984ff0af8ab7d98bc12c02ce782b23268d03".
"864826b0201d8d1e0c09c9ab229a2f7fe1504795bafa8b8ae13fb046a2f35233a49b772b57862ada835951742439693ed9f3a080aea7a1309de4ae04b1ce3d78".
"72cdd85a3544906afaf55aff8255bdb2367c7ecf184c91c8f4c60a1301b80f8bb9f0ff6d80ac6e1c9d6c9fafbc65199790e0a9c323e68b105f5c56eed2f60294".
"5ab59d79698829ba092cc97f37dd023595d3fa014e718cda23d6bdbbfd70c2c6cc1b9121d22eae0bde7b94277dc8e5e096d60351f2740ddb986c7e10e0af8a40".
"e9bd526f863cde028dd253e18013d3c76c2006a9ab9ec3e7b6b1aca865b2ace8c8debb50ae1efbc0e49dd69f128c28bd02d79f22717e2679d5142540733cb278".
"0969944106122d5f2baf97f7e09ef67b894cd191411126ad962e4b9c5a0bbe83215563662ce5f063ce2a76c2e09613539fbb094d389e739ca0a3fc34bd1692ba".
"f0601e2122a70fdf68ede6c431090896622362c59801000727718f4b551f32340fc5f740e15fc0a023791aa57a6cc97af3077f5d71d33cbc864049b30cb11ea5".
"23c15141ea5ac620aec5f81e6661bf8f01a3c817ac1ab592570b63764402e4934d776df03cadae448c5d9082c30c00737e4bbe5c184a1167507d9b99bdd05592".
"456ac25dadb5beafe282028611db969c44db7bfb2cad349c0ecbebc281a00ad4f70cfd889b3533833ab845f86403e6a1970da6b5c8b8e82e9f42a82c7c14e535".
"16b3d9efbaae6ca6b9c93977f17f58ec29a1a8bb188fb15f377bf50d37e84781ca1716052f657a361cbe44eb227002a57390873e54b8695f76fe0f84f873e021".
"c92945f3d7b54861be3c237701c140c3a4e1b84fa4bab910cd265393e0172293d6fc40fa1872e175d7d3f06153a9eca3f8db85c2166f68415eda3bf4aee35adc".
"0231cd6cfe5d3a23b51fb0105176b9cdadc28304d27fef698cf4155235d07ecfaf5a2c5f8610a63ee809b0e0260251c33873dceebdda1ec3725d1376031e45cc".
"731a870b39edc97b549b96624c891984acf7a422584bc56f2104256f15da552d0a8376a546b6966153728ca1f38514df0d458375e99bc01fa498b07abb33803f".
"da07c4149e6e5773f9ec65ac3c87ca7c515f263de3cda2d53edbc20c47486ee33f9810c8226bbc9c52fcadb1f01fe28bf099b8afb9f1798e0b9815210c559187".
"c562b5e45350a5d0708c2fb96bad405ef4b8b535066ed02da198e4a3a4eaf075450c87f6d9840c8e00b8e316bcc7a5c6113fefbd72b0c7f6860fcecc8a3f33fb".
"a2999e4f3f3e3da5d7bfcf5d22a93f4d16ae6dd053685dfc7223628f92086735d09551bd29e8d0f537d06f33536fce8360d7443f583e9079685efce0347c1ffa".
"fedd0b7d1125f0dfc9bb21460079f286abbbeb549bb744aeea0b7a6bc66a272c8af945621b57b8380d40fa067c3060b9d44b79bd4333ec96d47632124a9aad0a".
"2df287eda9312f70f12f544fd7bdef9e6cc5e110effb8dbdebb821571f0fa95301db9da0bb60b77af6d5b7de00ca26039f1dda92f7a777c75d02fc340f1b81b5".
"e7c5efc6aaa6ffe3b77db348b7a5973a9465cb1e01841fa10f398318bfb73a4f8f53a4bded656f35db0ef00685826d8eac3aa0941623b3401ffdaba927bc91f4".
"808818548a60f653e9f340f79e40d666525923c4847ac3c0a9b36f3069620b0aea677ee7afa2c333987d9a5afade1b0e1e22ef7470228b07c9f482a6c343a37c".
"462a749c02d4cc86447cc16c3c68955afa80e63a3a41aaa1375c7ca0cffa0335e96e599e1b6841ae5693b5fa6ff437c3c1dca20075b7a58aafa81845af0aa8f6".
"30520d89a362d667447045c2b39f88f573f6b76b95ea4a98950ad797570b841975e9841306223dbefd21a4f092d69452c4539c664e27e110622ae7a7db5073d6".
"17eb023b36f28a13eeeebdbd964df63dcb18762950b6bd3eeead2a25b9bba48060ac8b82af3f41ecafbb7134140ca8cc687b92eded8bdabd9567e50950ed617a".
"a114d3db8648f9ab48a622456aec56fe79cfa6225fc7fd3fb0607f9dbc1bd861b316600fc10163fe8098ea685bc3fe06435f51cb1ce7ffebae67b3114fadf8c8".
"808a4044bb06638d05bc9a73c44c5b1eb7c83cdb4bde51ffa85413a97fbd534ddb17dc899fc4e2ced6ed81eeb117b4c77f9ecd03251367649a5649ec58567907".
"4fc8c2702dc42a58308f4023fb2cd30c79ecb9a952cde77dfcf92d8ef234811c327112abd568c49d4bf693f611d07e433fcd0a396530c6a279eb3ba567d780b7".
"271b6bfc7f1683a6b9159e143788662e8c5f73dd25ab623633efe781edd647b32003c9f3eaf236d968244e4561bc855848b839bfb93af2ea3e230a30089230c4".
"2e593ed3b9be53d677a7c9da744ee1961aaccac237f9e0bc1f886a92d5f335c6c0b0250ea76fbdcd85ae9cf6afe7ab25fd6b4753be6505b986757b003b94a089".
"d6a42b1fb24d2249ec917bb0ad50c8bd31265f82071a0816c3f8985edf0311205f83eaf8ff5587a3c7c24938a3f0cf9ff438b567d71407a51292e6d7e3f939e6".
"cdbecd49e913793f73cb964406934907ca4d48f44bec301bdf0110986757fcac6c2cca84eb7c5fad1662d1a833d24fa356771d6b772759a4837d9872d23ff1ab".
"219597aadc062f317d6cbc044bf65dc5ddda95ddc34d68584b7db991c8441a43e0511f71b88dda141f36b7cb326650c3244b989f1b992d2baa318e2a76dd1c34".
"a946c843255f65c6896eac3a6774ceff50b6f66b752672f5ce8dc84149ba6b227da844254d01bf470f6c987e8b5df2168414bcee11ad8c131d16e43addbdd493".
"595117f4f211c5d6460ee1be41e72b42c21252ce6dcd9838e53b0e1fd8d1864c2d3d219b82d42d0446865848431658732a78f0d9348f8044fa7f576d11562d25".
"d7b681f714c4b43532543d27069a21d1d152e646c56d75229bb198f87676108306e68fa49751f3b1d678bbf1ea38b2e0712d896882b5ea1494136f23a7e1d528".
"ca456c6c2a2cfc8cb6b6e7e6526aaa1da082653492b624936213569892706d8f9c6496b1193ec5a4294e3c1da14b25c24337cf9bb3490ea3f8a54e0a5b9f77af".
"fc70fe8dcb7687a9f45c7ae3ee8f2a94fa58e6c920cce1f447fd60526fa71b6f1048a3dcc7680e3b20ac66d78290bfc3878e72d4876e014036b0b80b6be4bf2e".
"a358125bea811b51af76a0077b3a615750a9ca3368d1d17e060a0d37bfd3b13c91412ca83298b06aea3048607f718c04667dcfc7faa4ac5a594be1c1551140ba".
"9c1ea7cebc074b1fbd338eef831fa3eb1f39088bcf1cf13bf706b1d287e12b165f4fb3e6c4586067c5e2f461c4cc86400b456428e8767c1b57a7bc3e64a8abe6".
"d253646f8796763b2a33de35c6f1667d06f30bb12c0fd0e28e4859ebdc2f96236af4a895d9a7d6fb90cbb60084db28a0c628faf7653c316ec69b5c5103aea495".
"792efd58ec42bc950f8608d5fa6834aab7bd2aaece33b3e16756f518a5410e8957dd534437e8c152451d86beb20124e8fb9e672d13fb7e98e153c124fdb2eaf7".
"f94a23efffeea25ec31f821e492d9de00a6d056c67e565f734f864d425035bb13620b7a1f44ec02ab7a6b1c4a38511b6902cfcf199d3918eb07da11d634add44".
"0860d123fa2b8003f87270777c6415e32f1b34dd6e1e22df3a78684e1169fce84b61cf461544f4e891fcd9d1f5a1e5fef148aeddbfcc922f5d7bfd3bd2480e8a".
"3318c75ce0afc24ca179fc0e832ab64368c174407bf2cd45a72cd5c9e7dd0b9def7500cec54d4d692938a1bb18289189d4b2445640d8abc9a0b70c3ffc8ba3c8".
"d483119a4f63851a57cf30f48c88616785a5ee00cb9221db45dd8dff118ca33bb4ae254937891f2c971edc8614fa3fc43e56f297a44a234fb1737f23d44a15f0".
"6a9e364fe1daa8e28bf72927526296202713f76dc8342e3843483b479ff793697b11a934bdc206905dd020e2f321cf8d65c245a8e7c4275f87301211800f0751".
"4e9cb59b88540f5441e6b09b4b73112d855ba0dffd4affd670c4f76ec11ac07a6cc2201ac65c83b3b3e4dc10d991ef4424cd001d34f0393dc262957df641469a".
"e00f74c527f8c99f50432c5ff4c4260ec6998b7ef2a0223290762126542d8aa89bfd241ac59e3a9a6c6f13afc9d69a771d124d16359525e4b374605b699e32bd".
"fb393d9397767bce32ab2d5557d05c33fa54183b0d5facc73a097441aa34abf7d6ac36fb35d6be7f19d0c26c7ad564c06f8a4f616ff4819c53e8b29e782b8791".
"c4039e5d049bd36819ae6d01a113eae6260e25150b935ee364011558dea97e1ee0e7f2938b7368ad9a5a86bae4f89a9ffbd06638566a785cb6ad3982b133ce6a".
"3edb13aa2c4ad4db7052ac646fcf336b375efb6a360d448862f2b711db3d8e657a706c14013664beae06b1a067fd078b0a8800c01dd610d583bee4fa4634e4f3".
"5251372b8144a7194ed60dc2539283ce909e7d65338a9050b09b66b647f30b6d595d7e03d9a77029afce140df7717f64949ae1362f94602dc2e70840e3117ab1".
"a26cc8e8ffd068ec225f0b75b2de63e3511f4485c87fb0087e4421675f3754bc4bc9c0a38db6392661e8a59802d83f887cf81aa99ed13a10b4b8a176144f76ce".
"3a192cc77b09e3f8a087db488f3d304d048623f46a031ba9251896cd08ff601dd0b933f5110b4cc9d943b5705b2435fa1c0adaad6c3aed88022f57cc3d71048f".
"9d5f420cfaf737b8a9f2434601b296b14384618fa9b76e6acbf1b55ad7130f582f36920a5aff71e15d120b11d6e0dd374554803538f3b12305512cf24322ed52".
"cd7ce5f409efd2f2752684bc326bf4548fa17169028c819ba342ee672682860a6de09752f509caad897484160895dc712b70bd05d588fe218fd85718b9b833ff".
"2c18e2566416ce1e52c3d7dc696cca1ad02b9b99e2953f92d8fe7ac0e4d75bd2ae2834b9ad8e87f179cdaf5e75609abdf1236787fe366347c32991f20c7faf41".
"b65da4ed5edc3cab1134a4ee0a3b565cab7c6dcd6f93feb528ddf0a1e992f6ad4814e51d338433dc5b52fddd8e780a312d12c80c4dbdaf8818b1c84883d8be41".
"186de5fdeeb9c7b7542a8429e53645a313cd8c9a53c3790b9fcf0143421da3bb586762790c91b0110f68b5fd111338560437d7d77457fb5587efb40a90ed1c02".
"838ba4e83b0c6adb175d94b6e14767a4f4a127e80f79be7741f4dc446c520176fd5b0412cc4d7a8f3d293e438d50e4e79e52bbc2c3bc6707d97b6289f1b39733".
"48c9351b66be55b2152bee9b76c42dc057d12134180488f45aee9491fe72f8634e3beeda8006869a829d2d58614150ab489dca7af268c09dde668cc20428ff88".
"366a3c0119446bdba29c39b0723fcd639393d397d138ab241c187beac647d8f73e5e42b3468e3958e0e73908c081ce0b6c894f0409f3bd321807a1633860a8e7".
"49cb4a10875a65b3f0a073f48f141747c88afe9039ef0795752dbd07ef51a2dadb40bb09bb9d4fcb328f68af28f8d76085fccaef4afe848a93c4cac43f55863a".
"21b540e6d408eb55fdfbd2a0c13fbae6fdf68e51423737f6966105d1ed57570bb521adb9576b06988d7d5a6445fe77d177076d47ca45b437a9780b376d49689e".
"6b0be983d90f46dbf935e14b53f3bf7ac7aec7fc1b92c14f161e59ae2620f7552206f22a365c91476943b8b51e920661efc19d040070407ba1cf011d3a0e072e".
"68d10e064619aa2184d7e848729b254af6b83db15fca2134d0d54efc761fff25c1169d608ed2434de8ae3cafb8c3af0b5b23a16183b5ead5dc5d175c955f4db5".
"454623d611244c462776118992ba03e8e20e6e1d9d6101d2286d7e040d5a56f22d6e3ae86bd6a0605c8b34d7a385fee5f3c9b6d0cf550f7aa67f338d8a014dfd".
"639cade855e8d25df73ea01bc5635bb5e032269b2a10f6b2baea7c4a88ede42caf91d7c9d3b2802608fdc361e23ee8cdcc1c954da86f929e9721130ef6d74e99".
"180f8c8c2263b41f538e105bc5f411f8dd1c2d3e0dc4540ff9cbdb9a6c44524ebcdfe37d9427a43dc24fd28c2fc25baef96490ae847b435ef4eea87db030829d".
"06b4c5d9271c8ffda114c336f5d82f9e6ca0d140112f364b1613cfe84c6e924629cba51a7d21f92ce26802bda0651340a8aad0c1ef439acc5552634304321cf6".
"02851751630d671a8cce7028f1cc6fdbce64f762c8ed522c2a81c2886986999a85d41a87d2ba5281dcbc2dbd728559470017e12fd70a97a771de499d2953c49b".
"0e60abac5ced203dd26bb75df922938723b1341bb07b0250d7af1bf91788994f8ed193221dd829e6665b114763e490fd8482955b097ac3b5b124bf92ae8ce902".
"1897b67db820cbfd646fe2c61e63baa972651a47bb1aae56f5e623a1167beff84166ea78cc9854b21a9478ebf3a1429226213c20a7a9ce8031eced508b937263".
"1357591069d5c482c0f6f99e4a6084f34fdab7b26399b4efcb0e5217e4e9115d0f6011bcfe55e0f05d3d8850febab0a6100bab8142a3913662a568f9d32367bf".
"5db46b6572cb76bd6a49d84bd567e1f834bbd705dd395c1609e9eba7fe8b9c59f1c4cb2561461204805c25a384140314e515f84050949529050279393884f8d0");
$game_key = "c6mw4it2kg7sz5o0813d9qyufenhj\x00";
$buffer_length = strlen($buffer);
$game_key_length = strlen($game_key);
// We want to encrpt the data
if ($encrypt)
{
for ($i=1; $i<$buffer_length; $i++)
{
$buffer[$i] = chr(ord($buffer[$i]) ^ ord($buffer[$i-1]));
}
for ($i=0; $i<$buffer_length; $i++)
{
$buffer[$i] = chr(ord($buffer[$i]) ^ ord($game_key[($i % 128) % $game_key_length]) ^ ord($master_key[$i % 128]) ^ ord($master_key[$i]));
}
}
else // We need to decrypt the data
{
for ($i=0; $i<$buffer_length; $i++)
{
$buffer[$i] = chr(ord($buffer[$i]) ^ ord($master_key[$i]) ^ ord($master_key[$i%128]) ^ ord($game_key[($i%128) % $game_key_length]));
}
for ($i=($buffer_length-1); $i>0; $i--)
{
$buffer[$i] = chr(ord($buffer[$i]) ^ ord($buffer[$i-1]));
}
}
return $buffer;
}
}

View file

@ -0,0 +1,28 @@
<?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/>.
*/
/**
* America's Army Proving Grounds
*
* @author Austin Bischoff <austin@codebeard.com>
*/
class GameQ_Protocols_Aapg extends GameQ_Protocols_Aa3
{
protected $name = "aapg";
protected $name_long = "America's Army: Proving Grounds";
}

View file

@ -0,0 +1,28 @@
<?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/>.
*/
/**
* Alien Swarm Protocol Class
*
* @author Austin Bischoff <austin@codebeard.com>
*/
class GameQ_Protocols_Alienswarm extends GameQ_Protocols_Source
{
protected $name = "alienswarm";
protected $name_long = "Alien Swarm";
}

View file

@ -0,0 +1,28 @@
<?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/>.
*/
/**
* Age of Chivalry Protocol Class
*
* @author Austin Bischoff <austin@codebeard.com>
*/
class GameQ_Protocols_Aoc extends GameQ_Protocols_Source
{
protected $name = "aoc";
protected $name_long = "Age of Chivalry";
}

View file

@ -0,0 +1,28 @@
<?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/>.
*/
/**
* Ark Survival Evolved Protocol Class
*
* @author Mikael Nielsen <miscni@ghostmail.com>
*/
class GameQ_Protocols_Arkse extends GameQ_Protocols_Source
{
protected $name = "arkse";
protected $name_long = "Ark Survival Evolved";
}

View file

@ -0,0 +1,30 @@
<?php
/**
* This file is part of GameQ.
*
* GameQ is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* GameQ is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* Armed Assault Protocol Class
*
* @author Austin Bischoff <austin@codebeard.com>
*/
class GameQ_Protocols_Armedassault extends GameQ_Protocols_Gamespy2
{
protected $name = "armedassault";
protected $name_long = "Armed Assault";
protected $port = 2302;
}

View file

@ -0,0 +1,33 @@
<?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/>.
*/
/**
* Armed Assault 2 Protocol Class
*
* @author Austin Bischoff <austin@codebeard.com>
*/
class GameQ_Protocols_Armedassault2 extends GameQ_Protocols_Gamespy3
{
protected $name = "armedassault2";
protected $name_long = "Armed Assault 2";
protected $port = 2302;
}

View file

@ -0,0 +1,30 @@
<?php
/**
* This file is part of GameQ.
*
* GameQ is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* GameQ is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* Armed Assault 2: Operation Arrowhead Protocol Class
*
* @author Austin Bischoff <austin@codebeard.com>
*/
class GameQ_Protocols_Armedassault2oa extends GameQ_Protocols_Source
{
protected $name = "armedassault2oa";
protected $name_long = "Armed Assault 2: Operation Arrowhead";
protected $port = 2302;
}

View file

@ -0,0 +1,33 @@
<?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/>.
*/
/**
* Armed Assault 2 Protocol Class
*
* Special thanks to firefly2442 for linking working python script that
* supported both GSv2&3
*
* @author Austin Bischoff <austin@codebeard.com>
*/
class GameQ_Protocols_Armedassault3 extends GameQ_Protocols_Source
{
protected $name = "armedassault3";
protected $name_long = "Armed Assault 3";
protected $port = 2302;
}

View file

@ -0,0 +1,164 @@
<?php
/**
* This file is part of GameQ.
*
* GameQ is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* GameQ is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* All-Seeing Eye Protocol Class
*
* This class is used as the basis for all game servers
* that use the All-Seeing Eye (ASE) protocol for querying
* server status.
*
* Most of the logic is taken from the original GameQ
* by Tom Buskens <t.buskens@deviation.nl>
*
* @author Marcel Bößendörfer <m.boessendoerfer@marbis.net>
* @author Austin Bischoff <austin@codebeard.com>
*/
abstract class GameQ_Protocols_ASE extends GameQ_Protocols
{
/**
* Array of packets we want to look up.
* Each key should correspond to a defined method in this or a parent class
*
* @var array
*/
protected $packets = array(
self::PACKET_ALL => "s",
);
/**
* Methods to be run when processing the response(s)
*
* @var array
*/
protected $process_methods = array(
"process_all",
);
/**
* Default port for this server type
*
* @var int
*/
protected $port = 1; // Default port, used if not set when instanced
/**
* The protocol being used
*
* @var string
*/
protected $protocol = 'ase';
/**
* String name of this protocol class
*
* @var string
*/
protected $name = 'ase';
/**
* Longer string name of this protocol class
*
* @var string
*/
protected $name_long = "All-Seeing Eye";
/*
* Internal methods
*/
protected function process_all()
{
if(!$this->hasValidResponse(self::PACKET_ALL))
{
return array();
}
$data = $this->packets_response[self::PACKET_ALL][0];
$buf = new GameQ_Buffer($data);
$result = new GameQ_Result();
// Grab the header
$header = $buf->read(4);
// Header does not match
if ($header !== 'EYE1')
{
throw new GameQException("Exepcted header to be 'EYE1' but got '{$header}' instead.");
}
// Variables
$result->add('gamename', $buf->readPascalString(1, true));
$result->add('port', $buf->readPascalString(1, true));
$result->add('servername', $buf->readPascalString(1, true));
$result->add('gametype', $buf->readPascalString(1, true));
$result->add('map', $buf->readPascalString(1, true));
$result->add('version', $buf->readPascalString(1, true));
$result->add('password', $buf->readPascalString(1, true));
$result->add('num_players', $buf->readPascalString(1, true));
$result->add('max_players', $buf->readPascalString(1, true));
// Key / value pairs
while($buf->getLength())
{
// If we have an empty key, we've reached the end
$key = $buf->readPascalString(1, true);
if (empty($key))
{
break;
}
// Otherwise, add the pair
$result->add(
$key,
$buf->readPascalString(1, true)
);
}
// Players
while ($buf->getLength())
{
// Get the flags
$flags = $buf->readInt8();
// Get data according to the flags
if ($flags & 1) {
$result->addPlayer('name', $buf->readPascalString(1, true));
}
if ($flags & 2) {
$result->addPlayer('team', $buf->readPascalString(1, true));
}
if ($flags & 4) {
$result->addPlayer('skin', $buf->readPascalString(1, true));
}
if ($flags & 8) {
$result->addPlayer('score', $buf->readPascalString(1, true));
}
if ($flags & 16) {
$result->addPlayer('ping', $buf->readPascalString(1, true));
}
if ($flags & 32) {
$result->addPlayer('time', $buf->readPascalString(1, true));
}
}
return $result->fetch();
}
}

View file

@ -0,0 +1,30 @@
<?php
/**
* This file is part of GameQ.
*
* GameQ is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* GameQ is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* Aliens vs Preadtor Protocol Class
*
* @author Austin Bischoff <austin@codebeard.com>
*/
class GameQ_Protocols_Avp extends GameQ_Protocols_Gamespy
{
protected $name = "avp";
protected $name_long = "Aliens vs Preadtor";
protected $port = 27888;
}

View file

@ -0,0 +1,32 @@
<?php
/**
* This file is part of GameQ.
*
* GameQ is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* GameQ is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* Aliens vs Predator 2 Protocol Class
*
* @author Austin Bischoff <austin@codebeard.com>
*/
class GameQ_Protocols_Avp2 extends GameQ_Protocols_Gamespy
{
protected $name = "avp2";
protected $name_long = "Aliens vs Predator 2";
protected $state = self::STATE_TESTING;
protected $port = 27888;
}

View file

@ -0,0 +1,30 @@
<?php
/**
* This file is part of GameQ.
*
* GameQ is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* GameQ is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* Battlefield 1942 Protocol Class
*
* @author Austin Bischoff <austin@codebeard.com>
*/
class GameQ_Protocols_Bf1942 extends GameQ_Protocols_Gamespy
{
protected $name = "bf1942";
protected $name_long = "Battlefield 1942";
protected $port = 23000;
}

View file

@ -0,0 +1,56 @@
<?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/>.
*/
/**
* Battlefield 2 Protocol Class
*
* @author Austin Bischoff <austin@codebeard.com>
*/
class GameQ_Protocols_Bf2 extends GameQ_Protocols_Gamespy3
{
protected $name = "bf2";
protected $name_long = "Battlefield 2";
protected $port = 29900;
/**
* Set the packet mode to multi, Gamespy v3 is by default a linear set of calls
*
* @var string
*/
protected $packet_mode = self::PACKET_MODE_MULTI;
/**
* Array of packets we want to look up.
* Each key should correspond to a defined method in this or a parent class
*
* @var array
*/
protected $packets = array(
self::PACKET_ALL => "\xFE\xFD\x00\x10\x20\x30\x40\xFF\xFF\xFF\x01",
);
/**
* Methods to be run when processing the response(s)
*
* @var array
*/
protected $process_methods = array(
"process_all",
);
}

View file

@ -0,0 +1,30 @@
<?php
/**
* This file is part of GameQ.
*
* GameQ is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* GameQ is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* Battlefield 2142 Protocol Class
*
* @author Austin Bischoff <austin@codebeard.com>
*/
class GameQ_Protocols_Bf2142 extends GameQ_Protocols_Gamespy3
{
protected $name = "bf2142";
protected $name_long = "Battlefield 2142";
protected $port = 29900;
}

View file

@ -0,0 +1,329 @@
<?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/>.
*/
/**
* Battlefield 3 Protocol Class
*
* Good place for doc status and info is http://www.fpsadmin.com/forum/showthread.php?t=24134
*
* @author Austin Bischoff <austin@codebeard.com>
*/
class GameQ_Protocols_Bf3 extends GameQ_Protocols
{
/**
* Normalization for this protocol class
*
* @var array
*/
protected $normalize = array(
// General
'general' => array(
'dedicated' => array('dedicated'),
'hostname' => array('hostname'),
'password' => array('password'),
'numplayers' => array('numplayers'),
'maxplayers' => array('maxplayers'),
'mapname' => array('map'),
'gametype' => array('gametype'),
'players' => array('players'),
'teams' => array('team'),
),
// Player
'player' => array(
'score' => array('score'),
),
// Team
'team' => array(
'score' => array('tickets'),
),
);
/**
* Array of packets we want to look up.
* Each key should correspond to a defined method in this or a parent class
*
* @var array
*/
protected $packets = array(
self::PACKET_STATUS => "\x00\x00\x00\x00\x1b\x00\x00\x00\x01\x00\x00\x00\x0a\x00\x00\x00serverInfo\x00",
self::PACKET_VERSION => "\x00\x00\x00\x00\x18\x00\x00\x00\x01\x00\x00\x00\x07\x00\x00\x00version\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",
);
/**
* Set the transport to use TCP
*
* @var string
*/
protected $transport = self::TRANSPORT_TCP;
/**
* Methods to be run when processing the response(s)
*
* @var array
*/
protected $process_methods = array(
"process_status",
"process_version",
"process_players",
);
/**
* Default port for this server type
*
* @var int
*/
protected $port = 47200; // Default port, used if not set when instanced
/**
* The protocol being used
*
* @var string
*/
protected $protocol = 'bf3';
/**
* String name of this protocol class
*
* @var string
*/
protected $name = 'bf3';
/**
* Longer string name of this protocol class
*
* @var string
*/
protected $name_long = "Battlefield 3";
/*
* Internal methods
*/
protected function preProcess_status($packets=array())
{
// Implode and return
return implode('', $packets);
}
protected function process_status()
{
// Make sure we have a valid response
if(!$this->hasValidResponse(self::PACKET_STATUS))
{
return array();
}
// Make buffer for data
$buf = new GameQ_Buffer($this->preProcess_status($this->packets_response[self::PACKET_STATUS]));
$buf->skip(8); /* skip header */
// Decode the words into an array so we can use this data
$words = $this->decodeWords($buf);
// Make sure we got OK
if (!isset ($words[0]) || $words[0] != 'OK')
{
throw new GameQ_ProtocolsException('Packet Response was not OK! Buffer:'.$buf->getBuffer());
}
// Set the result to a new result instance
$result = new GameQ_Result();
// Server is always dedicated
$result->add('dedicated', TRUE);
// No mods, as of yet
$result->add('mod', FALSE);
// These are the same no matter what mode the server is in
$result->add('hostname', $words[1]);
$result->add('numplayers', $words[2]);
$result->add('maxplayers', $words[3]);
$result->add('gametype', $words[4]);
$result->add('map', $words[5]);
$result->add('roundsplayed', $words[6]);
$result->add('roundstotal', $words[7]);
// Figure out the number of teams
$num_teams = intval($words[8]);
// Set the current index
$index_current = 9;
// Loop for the number of teams found, increment along the way
for($id=1; $id<=$num_teams; $id++)
{
$result->addSub('teams', 'tickets', $words[$index_current]);
$result->addSub('teams', 'id', $id);
// Increment
$index_current++;
}
// Get and set the rest of the data points.
$result->add('targetscore', $words[$index_current]);
$result->add('online', TRUE); // Forced TRUE, it seems $words[$index_current + 1] is always empty
$result->add('ranked', $words[$index_current + 2] === 'true');
$result->add('punkbuster', $words[$index_current + 3] === 'true');
$result->add('password', $words[$index_current + 4] === 'true');
$result->add('uptime', $words[$index_current + 5]);
$result->add('roundtime', $words[$index_current + 6]);
// Added in R9
$result->add('ip_port', $words[$index_current + 7]);
$result->add('punkbuster_version', $words[$index_current + 8]);
$result->add('join_queue', $words[$index_current + 9] === 'true');
$result->add('region', $words[$index_current + 10]);
$result->add('pingsite', $words[$index_current + 11]);
$result->add('country', $words[$index_current + 12]);
// Added in R29, No docs as of yet
$result->add('quickmatch', $words[$index_current + 13] === 'true'); // Guessed from research
unset($buf, $words);
return $result->fetch();
}
protected function preProcess_version($packets=array())
{
// Implode and return
return implode('', $packets);
}
protected function process_version()
{
// Make sure we have a valid response
if(!$this->hasValidResponse(self::PACKET_VERSION))
{
return array();
}
// Set the result to a new result instance
$result = new GameQ_Result();
// Make buffer for data
$buf = new GameQ_Buffer($this->preProcess_version($this->packets_response[self::PACKET_VERSION]));
$buf->skip(8); /* skip header */
$words = $this->decodeWords($buf);
// Not too important if version is missing
if (!isset ($words[0]) || $words[0] != 'OK')
{
return array();
}
$result->add('version', $words[2]);
unset($buf, $words);
return $result->fetch();
}
protected function preProcess_players($packets=array())
{
// Implode and return
return implode('', $packets);
}
protected function process_players()
{
// Make sure we have a valid response
if(!$this->hasValidResponse(self::PACKET_PLAYERS))
{
return array();
}
// Set the result to a new result instance
$result = new GameQ_Result();
// Make buffer for data
$buf = new GameQ_Buffer($this->preProcess_players($this->packets_response[self::PACKET_PLAYERS]));
$buf->skip(8); /* skip header */
$words = $this->decodeWords($buf);
// Not too important if players are missing.
if (!isset ($words[0]) || $words[0] != 'OK')
{
return array();
}
// Count the number of words and figure out the highest index.
$words_total = count($words)-1;
// The number of player info points
$num_tags = $words[1];
// Pull out the tags, they start at index=3, length of num_tags
$tags = array_slice($words, 2, $num_tags);
// Just incase this changed between calls.
$result->add('numplayers', $words[$num_tags+2]);
// Loop until we run out of positions
for($pos=(3+$num_tags);$pos<=$words_total;$pos+=$num_tags)
{
// Pull out this player
$player = array_slice($words, $pos, $num_tags);
// Loop the tags and add the proper value for the tag.
foreach($tags AS $tag_index => $tag)
{
$result->addPlayer($tag, $player[$tag_index]);
}
// No pings in this game
$result->addPlayer('ping', FALSE);
}
// @todo: Add some team definition stuff
unset($buf, $tags, $words, $player);
return $result->fetch();
}
/**
* Decode words from the response
*
* @param GameQ_Buffer $buf
*/
protected function decodeWords(GameQ_Buffer &$buf)
{
$result = array();
$num_words = $buf->readInt32();
for ($i = 0; $i < $num_words; $i++)
{
$len = $buf->readInt32();
$result[] = $buf->read($len);
$buf->read(1); /* 0x00 string ending */
}
return $result;
}
}

View file

@ -0,0 +1,189 @@
<?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/>.
*/
/**
* Battlefield 4 Protocol Class
*
* Good place for doc status and info is http://battlelog.battlefield.com/bf4/forum/view/2955064768683911198/
*
* @author Austin Bischoff <austin@codebeard.com>
*/
class GameQ_Protocols_Bf4 extends GameQ_Protocols_Bf3
{
/**
* The protocol being used
*
* @var string
*/
protected $protocol = 'bf4';
/**
* String name of this protocol class
*
* @var string
*/
protected $name = 'bf4';
/**
* Longer string name of this protocol class
*
* @var string
*/
protected $name_long = "Battlefield 4";
/*
* Internal Methods
*/
protected function process_status()
{
// Make sure we have a valid response
if(!$this->hasValidResponse(self::PACKET_STATUS))
{
return array();
}
// Make buffer for data
$buf = new GameQ_Buffer($this->preProcess_status($this->packets_response[self::PACKET_STATUS]));
$buf->skip(8); /* skip header */
// Decode the words into an array so we can use this data
$words = $this->decodeWords($buf);
// Make sure we got OK
if (!isset ($words[0]) || $words[0] != 'OK')
{
throw new GameQ_ProtocolsException('Packet Response was not OK! Buffer:'.$buf->getBuffer());
}
// Set the result to a new result instance
$result = new GameQ_Result();
// Server is always dedicated
$result->add('dedicated', TRUE);
// No mods, as of yet
$result->add('mod', FALSE);
// These are the same no matter what mode the server is in
$result->add('hostname', $words[1]);
$result->add('numplayers', $words[2]);
$result->add('maxplayers', $words[3]);
$result->add('gametype', $words[4]);
$result->add('map', $words[5]);
$result->add('roundsplayed', $words[6]);
$result->add('roundstotal', $words[7]);
// Figure out the number of teams
$num_teams = intval($words[8]);
// Set the current index
$index_current = 9;
// Loop for the number of teams found, increment along the way
for($id=1; $id<=$num_teams; $id++)
{
$result->addSub('teams', 'tickets', $words[$index_current]);
$result->addSub('teams', 'id', $id);
// Increment
$index_current++;
}
// Get and set the rest of the data points.
$result->add('targetscore', $words[$index_current]);
$result->add('online', TRUE); // Forced TRUE, it seems $words[$index_current + 1] is always empty
$result->add('ranked', $words[$index_current + 2] === 'true');
$result->add('punkbuster', $words[$index_current + 3] === 'true');
$result->add('password', $words[$index_current + 4] === 'true');
$result->add('uptime', $words[$index_current + 5]);
$result->add('roundtime', $words[$index_current + 6]);
$result->add('ip_port', $words[$index_current + 7]);
$result->add('punkbuster_version', $words[$index_current + 8]);
$result->add('join_queue', $words[$index_current + 9] === 'true');
$result->add('region', $words[$index_current + 10]);
$result->add('pingsite', $words[$index_current + 11]);
$result->add('country', $words[$index_current + 12]);
// @todo: Supposed to be a field here <matchMakingEnabled: boolean>, its in R13 docs but doesnt return in response
$result->add('blaze_player_count', $words[$index_current + 13]);
$result->add('blaze_game_state', $words[$index_current + 14]);
unset($buf, $words);
return $result->fetch();
}
protected function process_players()
{
// Make sure we have a valid response
if(!$this->hasValidResponse(self::PACKET_PLAYERS))
{
return array();
}
// Set the result to a new result instance
$result = new GameQ_Result();
// Make buffer for data
$buf = new GameQ_Buffer($this->preProcess_players($this->packets_response[self::PACKET_PLAYERS]));
$buf->skip(8); /* skip header */
$words = $this->decodeWords($buf);
// Not too important if players are missing.
if (!isset ($words[0]) || $words[0] != 'OK')
{
return array();
}
// Count the number of words and figure out the highest index.
$words_total = count($words)-1;
// The number of player info points
$num_tags = $words[1];
// Pull out the tags, they start at index=3, length of num_tags
$tags = array_slice($words, 2, $num_tags);
// Just incase this changed between calls.
$result->add('numplayers', $words[($num_tags+2)]);
// Loop until we run out of positions
for($pos=(3+$num_tags);$pos<=$words_total;$pos+=$num_tags)
{
// Pull out this player
$player = array_slice($words, $pos, $num_tags);
// Loop the tags and add the proper value for the tag.
foreach($tags AS $tag_index => $tag)
{
$result->addPlayer($tag, $player[$tag_index]);
}
}
// @todo: Add some team definition stuff
unset($buf, $tags, $words, $player);
return $result->fetch();
}
}

View file

@ -0,0 +1,249 @@
<?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/>.
*/
/**
* Battlefield Bad Company 2 Protocol Class
*
* @author Austin Bischoff <austin@codebeard.com>
*/
class GameQ_Protocols_Bfbc2 extends GameQ_Protocols
{
/**
* Array of packets we want to look up.
* Each key should correspond to a defined method in this or a parent class
*
* @var array
*/
protected $packets = array(
self::PACKET_STATUS => "\x00\x00\x00\x00\x1b\x00\x00\x00\x01\x00\x00\x00\x0a\x00\x00\x00serverInfo\x00",
self::PACKET_VERSION => "\x00\x00\x00\x00\x18\x00\x00\x00\x01\x00\x00\x00\x07\x00\x00\x00version\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",
);
/**
* Set the transport to use TCP
*
* @var string
*/
protected $transport = self::TRANSPORT_TCP;
/**
* Methods to be run when processing the response(s)
*
* @var array
*/
protected $process_methods = array(
"process_status",
"process_version",
"process_players",
);
/**
* Default port for this server type
*
* @var int
*/
protected $port = 48888; // Default port, used if not set when instanced
/**
* The protocol being used
*
* @var string
*/
protected $protocol = 'bfbc2';
/**
* String name of this protocol class
*
* @var string
*/
protected $name = 'bfbc2';
/**
* Longer string name of this protocol class
*
* @var string
*/
protected $name_long = "Battlefield Bad Company 2";
/*
* Internal methods
*/
protected function preProcess_status($packets=array())
{
// Implode and return
return implode('', $packets);
}
protected function process_status()
{
// Make sure we have a valid response
if(!$this->hasValidResponse(self::PACKET_STATUS))
{
return array();
}
// Set the result to a new result instance
$result = new GameQ_Result();
// Make buffer for data
$buf = new GameQ_Buffer($this->preProcess_status($this->packets_response[self::PACKET_STATUS]));
$buf->skip(8); /* skip header */
$words = $this->decodeWords($buf);
if (!isset ($words[0]) || $words[0] != 'OK')
{
throw new GameQ_ProtocolsException('Packet Response was not OK! Buffer:'.$buf->getBuffer());
}
$result->add('hostname', $words[1]);
$result->add('numplayers', $words[2]);
$result->add('maxplayers', $words[3]);
$result->add('gametype', $words[4]);
$result->add('map', $words[5]);
// @todo: Add some team definition stuff
unset($buf);
return $result->fetch();
}
protected function preProcess_version($packets=array())
{
// Implode and return
return implode('', $packets);
}
protected function process_version()
{
// Make sure we have a valid response
if(!$this->hasValidResponse(self::PACKET_VERSION))
{
return array();
}
// Set the result to a new result instance
$result = new GameQ_Result();
// Make buffer for data
$buf = new GameQ_Buffer($this->preProcess_version($this->packets_response[self::PACKET_VERSION]));
$buf->skip(8); /* skip header */
$words = $this->decodeWords($buf);
// Not too important if version is missing
if (!isset ($words[0]) || $words[0] != 'OK')
{
return array();
}
$result->add('version', $words[2]);
unset($buf);
return $result->fetch();
}
protected function preProcess_players($packets=array())
{
// Implode and return
return implode('', $packets);
}
protected function process_players()
{
// Make sure we have a valid response
if(!$this->hasValidResponse(self::PACKET_PLAYERS))
{
return array();
}
// Set the result to a new result instance
$result = new GameQ_Result();
// Make buffer for data
$buf = new GameQ_Buffer($this->preProcess_players($this->packets_response[self::PACKET_PLAYERS]));
$buf->skip(8); /* skip header */
$words = $this->decodeWords($buf);
// Not too important if players are missing.
if (!isset ($words[0]) || $words[0] != 'OK')
{
return array();
}
// The number of player info points
$num_tags = $words[1];
$position = 2;
$tags = array();
for (; $position < $num_tags + 2 ; $position++)
{
$tags[] = $words[$position];
}
$num_players = $words[$position];
$position++;
$start_position = $position;
for (; $position < $num_players * $num_tags + $start_position;
$position += $num_tags)
{
for ($a = $position, $b = 0; $a < $position + $num_tags;
$a++, $b++)
{
$result->addPlayer($tags[$b], $words[$a]);
}
}
// @todo: Add some team definition stuff
unset($buf);
return $result->fetch();
}
/**
* Decode words from the response
*
* @param GameQ_Buffer $buf
*/
protected function decodeWords(GameQ_Buffer &$buf)
{
$result = array();
$num_words = $buf->readInt32();
for ($i = 0; $i < $num_words; $i++)
{
$len = $buf->readInt32();
$result[] = $buf->read($len);
$buf->read(1); /* 0x00 string ending */
}
return $result;
}
}

View file

@ -0,0 +1,46 @@
<?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/>.
*/
/**
* Battlefield Hardline Protocol Class
*
* @author Austin Bischoff <austin@codebeard.com>
*/
class GameQ_Protocols_Bfh extends GameQ_Protocols_Bf4
{
/**
* The protocol being used
*
* @var string
*/
protected $protocol = 'bfh';
/**
* String name of this protocol class
*
* @var string
*/
protected $name = 'bfh';
/**
* Longer string name of this protocol class
*
* @var string
*/
protected $name_long = "Battlefield Hardline";
}

View file

@ -0,0 +1,30 @@
<?php
/**
* This file is part of GameQ.
*
* GameQ is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* GameQ is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* Battlefield Vietnam Protocol Class
*
* @author Austin Bischoff <austin@codebeard.com>
*/
class GameQ_Protocols_Bfv extends GameQ_Protocols_Gamespy2
{
protected $name = "bfv";
protected $name_long = "Battlefield Vietnam";
protected $port = 23000;
}

View file

@ -0,0 +1,28 @@
<?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/>.
*/
/**
* Brink Protocol Class
*
* @author Austin Bischoff <austin@codebeard.com>
*/
class GameQ_Protocols_Brink extends GameQ_Protocols_Source
{
protected $name = "brink";
protected $name_long = "Brink";
}

View file

@ -0,0 +1,30 @@
<?php
/**
* This file is part of GameQ.
*
* GameQ is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* GameQ is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* Call of Duty Protocol Class
*
* @author Austin Bischoff <austin@codebeard.com>
*/
class GameQ_Protocols_Cod extends GameQ_Protocols_Quake3
{
protected $name = "cod";
protected $name_long = "Call of Duty";
protected $port = 28960;
}

View file

@ -0,0 +1,30 @@
<?php
/**
* This file is part of GameQ.
*
* GameQ is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* GameQ is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* Call of Duty 2 Protocol Class
*
* @author Austin Bischoff <austin@codebeard.com>
*/
class GameQ_Protocols_Cod2 extends GameQ_Protocols_Quake3
{
protected $name = "cod2";
protected $name_long = "Call of Duty 2";
protected $port = 28960;
}

View file

@ -0,0 +1,30 @@
<?php
/**
* This file is part of GameQ.
*
* GameQ is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* GameQ is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* Call of Duty 4 Protocol Class
*
* @author Austin Bischoff <austin@codebeard.com>
*/
class GameQ_Protocols_Cod4 extends GameQ_Protocols_Quake3
{
protected $name = "cod4";
protected $name_long = "Call of Duty 4";
protected $port = 28960;
}

View file

@ -0,0 +1,30 @@
<?php
/**
* This file is part of GameQ.
*
* GameQ is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* GameQ is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* Call of Duty: Modern Warfare 3 Protocol Class
*
* @author Austin Bischoff <austin@codebeard.com>
*/
class GameQ_Protocols_Codmw3 extends GameQ_Protocols_Source
{
protected $name = "codmw3";
protected $name_long = "Call of Duty: Modern Warfare 3";
protected $port = 27015;
}

View file

@ -0,0 +1,30 @@
<?php
/**
* This file is part of GameQ.
*
* GameQ is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* GameQ is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* Call of Duty: United Offensive Protocol Class
*
* @author Austin Bischoff <austin@codebeard.com>
*/
class GameQ_Protocols_Coduo extends GameQ_Protocols_Quake3
{
protected $name = "coduo";
protected $name_long = "Call of Duty: United Offensive";
protected $port = 28960;
}

View file

@ -0,0 +1,30 @@
<?php
/**
* This file is part of GameQ.
*
* GameQ is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* GameQ is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* Call of Duty: World at War Protocol Class
*
* @author Austin Bischoff <austin@codebeard.com>
*/
class GameQ_Protocols_Codwaw extends GameQ_Protocols_Quake3
{
protected $name = "codwaw";
protected $name_long = "Call of Duty: World at War";
protected $port = 28960;
}

View file

@ -0,0 +1,709 @@
<?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/>.
*
*
*/
/**
* Handles the core functionality for the protocols
*
* @author Austin Bischoff <austin@codebeard.com>
*/
abstract class GameQ_Protocols_Core
{
/*
* 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';
/**
* Can only send one packet at a time, slower
*
* @var string
*/
const PACKET_MODE_LINEAR = 'linear';
/**
* Can send multiple packets at once and get responses, after challenge request (if required)
*
* @var string
*/
const PACKET_MODE_MULTI = 'multi';
/**
* Current version of this class
*
* @var string
*/
protected $version = '2.0';
/**
* Short name of the protocol
*
* @var string
*/
protected $name = 'unnamed';
/**
* The longer, fancier name for the protocol
*
* @var string
*/
protected $name_long = 'unnamed';
/**
* IP address of the server we are querying.
*
* @var string
*/
protected $ip = '127.0.0.1';
/**
* Port of the server we are querying.
*
* @var mixed FALSE|int
*/
protected $port = NULL;
/**
* The port the client can connect on, usually the same as self::$port
* but not always.
*
* @var integer
*/
protected $port_client = NULL;
/**
* The trasport method to use to actually send the data
* Default is UDP
*
* @var string UDP|TCP
*/
protected $transport = self::TRANSPORT_UDP;
/**
* The protocol type used when querying the server
*
* @var string
*/
protected $protocol = 'unknown';
/**
* Packets Mode is multi by default since most games support it
*
* @var string
*/
protected $packet_mode = self::PACKET_MODE_MULTI;
/**
* Holds the valid packet types this protocol has available.
*
* @var array
*/
protected $packets = array();
/**
* Holds the list of methods to run when parsing the packet response(s) data. These
* methods should provide all the return information.
*
* @var array()
*/
protected $process_methods = array();
/**
* The packet responses received
*
* @var array
*/
protected $packets_response = array();
/**
* Holds the instance of the result class
*
* @var GameQ_Result
*/
protected $result = NULL;
/**
* Options for this protocol
*
* @var array
*/
protected $options = array();
/**
* Holds the challenge response, if there is a challenge needed.
*
* @var array
*/
protected $challenge_response = NULL;
/**
* Holds the challenge buffer.
*
* @var GameQ_Buffer
*/
protected $challenge_buffer = NULL;
/**
* Holds the result of the challenge, if any
* Will hold the error here
*
* @var mixed
*/
protected $challenge_result = TRUE;
/**
* Define the state of this class
*
* @var int
*/
protected $state = self::STATE_STABLE;
/**
* Holds and changes we want to make to the normailze filter
*
* @var array
*/
protected $normalize = FALSE;
/**
* Quick join link for specific games
*
* @var string
*/
protected $join_link = NULL;
/**
* Create the instance.
*
* @param string $ip
* @param mixed $port false|int
* @param array $options
*/
public function __construct($ip = FALSE, $port = FALSE, $options = array())
{
// Set the ip
$this->ip($ip);
// We have a specific port set so let's set it.
if($port !== FALSE)
{
// Set the port
$this->port($port);
/*
* By default we set the client port = to the query port. Note that
* this is not always the case
*/
$this->port_client($port);
}
// We have passed options so let's set them
if(!empty($options))
{
// Set the passed options
$this->options($options);
// We have an option passed for client connect port
if(isset($options['client_connect_port']) && !empty($options['client_connect_port']))
{
// Overwrite the default connect port
$this->port_client($options['client_connect_port']);
}
}
}
/**
* String name of this class
*/
public function __toString()
{
return $this->name;
}
/**
* Get an option's value
*
* @param string $option
* @return mixed
*/
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;
}
/**
* Short (callable) name of this class
*
* @return string
*/
public function name()
{
return $this->name;
}
/**
* Long name of this class
*/
public function name_long()
{
return $this->name_long;
}
/**
* Return the status of this Protocol Class
*/
public function state()
{
return $this->state;
}
/**
* Return the packet mode for this protocol
*/
public function packet_mode()
{
return $this->packet_mode;
}
/**
* Return the protocol property
*
*/
public function protocol()
{
return $this->protocol;
}
/**
* Get/set the ip address of the server
*
* @param string $ip
*/
public function ip($ip = FALSE)
{
// Act as setter
if($ip !== FALSE)
{
$this->ip = $ip;
}
return $this->ip;
}
/**
* Get/set the port of the server
*
* @param int $port
*/
public function port($port = FALSE)
{
// Act as setter
if($port !== FALSE)
{
$this->port = $port;
}
return $this->port;
}
/**
* Get/set the client port of the server
*
* @param integer $port
*/
public function port_client($port = FALSE)
{
// Act as setter
if($port !== FALSE)
{
$this->port_client = $port;
}
return $this->port_client;
}
/**
* Get/set the transport type for this protocol
*
* @param string $type
*/
public function transport($type = FALSE)
{
// Act as setter
if($type !== FALSE)
{
$this->transport = $type;
}
return $this->transport;
}
/**
* Set the options for the protocol call
*
* @param array $options
*/
public function options($options = Array())
{
// Act as setter
if(!empty($options))
{
$this->options = $options;
}
return $this->options;
}
/**
* Determine whether or not this protocol has some kind of challenge
*/
public function hasChallenge()
{
return (isset($this->packets[self::PACKET_CHALLENGE]) && !empty($this->packets[self::PACKET_CHALLENGE]));
}
/**
* See if the challenge was ok
*/
public function challengeOK()
{
return ($this->challenge_result === TRUE);
}
/**
* Get/set the challenge response
*
* @param array $response
*/
public function challengeResponse($response = Array())
{
// Act as setter
if(!empty($response))
{
$this->challenge_response = $response;
}
return $this->challenge_response;
}
/**
* Get/set the challenge result
*
* @param string $result
*/
public function challengeResult($result = FALSE)
{
// Act as setter
if(!empty($result))
{
$this->challenge_result = $result;
}
return $this->challenge_result;
}
/**
* Get/set the challenge buffer
*
* @param GameQ_Buffer $buffer
*/
public function challengeBuffer($buffer = NULL)
{
// Act as setter
if(!empty($buffer))
{
$this->challenge_buffer = $buffer;
}
return $this->challenge_buffer;
}
/**
* Verify the challenge response and parse it
*/
public function challengeVerifyAndParse()
{
// Check to make sure the response exists
if(!isset($this->challenge_response[0]))
{
// Set error and skip
$this->challenge_result = 'Challenge Response Empty';
return FALSE;
}
// Challenge is good to go
$this->challenge_result = TRUE;
// Now let's create a new buffer with this response
$this->challenge_buffer = new GameQ_Buffer($this->challenge_response[0]);
// Now parse the challenge and apply it
return $this->parseChallengeAndApply();
}
/**
* Get/set the packet response
*
* @param string $packet_type
* @param array $response
*/
public function packetResponse($packet_type, $response = Array())
{
// Act as setter
if(!empty($response))
{
$this->packets_response[$packet_type] = $response;
}
return $this->packets_response[$packet_type];
}
/**
* Return specific packet(s)
*
* @param mixed $type array|string
*/
public function getPacket($type = array())
{
// We want an array of packets back
if(is_array($type) && !empty($type))
{
$packets = array();
// 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;
}
}
return $packets;
}
elseif($type == '!challenge')
{
$packets = array();
// Loop the packets
foreach($this->packets AS $packet_type => $packet_data)
{
// Dont want challenge packets
if($packet_type == self::PACKET_CHALLENGE)
{
continue;
}
$packets[$packet_type] = $packet_data;
}
return $packets;
}
elseif(is_string($type))
{
return $this->packets[$type];
}
// Return all the packets
return $this->packets;
}
/* Begin working methods */
/**
* Process the response and return the raw data as an array.
*
* @throws GameQException
*/
public function processResponse()
{
// Init the array
$results = array();
// Let's loop all the requred methods to get all the data we want/need.
foreach ($this->process_methods AS $method)
{
// Lets make sure the data method defined exists.
if(!method_exists($this, $method))
{
// We should never get here in a production environment
throw new GameQException('Unable to load method '.__CLASS__.'::'.$method);
return FALSE;
}
// Setup a catch for protocol level errors
try
{
// Call the proper process method. All methods should return an array of data.
// Preprocessing should be handled by these methods internally as well.
// Merge in the results when done.
$results = array_merge($results, call_user_func_array(array($this, $method), array()));
}
catch (GameQ_ProtocolsException $e)
{
// Check to see if we are in debug, if so bubble up the exception
if($this->debug)
{
throw new GameQException($e->getMessage(), $e->getCode(), $e);
return FALSE;
}
// We ignore this and continue
continue;
}
}
// Now add some default stuff
$results['gq_online'] = (count($results) > 0);
$results['gq_address'] = $this->ip;
$results['gq_port'] = $this->port;
$results['gq_protocol'] = $this->protocol;
$results['gq_type'] = (string) $this;
$results['gq_name'] = $this->name_long();
$results['gq_transport'] = $this->transport;
// Process the join link
if(!isset($results['gq_joinlink']) || empty($results['gq_joinlink']))
{
$results['gq_joinlink'] = $this->getJoinLink();
}
// Return the raw results
return $results;
}
/**
* This method is called before the actual query packets are sent to the server. This allows
* the class to modify any changes before being sent.
*
* @return boolean
*/
public function beforeSend()
{
return TRUE;
}
/**
* Get the normalize property
*/
public function getNormalize()
{
return $this->normalize;
}
/**
* Apply the challenge string to all the packets that need it.
*
* @param string $challenge_string
*/
protected function challengeApply($challenge_string)
{
// Let's loop thru 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;
}
/**
* Parse the challenge buffer and get the proper challenge string out
*/
protected function parseChallengeAndApply()
{
return TRUE;
}
/**
* Determine whether or not the response is valid for a specific packet type
*
* @param string $packet_type
*/
protected function hasValidResponse($packet_type)
{
// Check for valid packet. All packet responses should have atleast 1 array key (0).
if(isset($this->packets_response[$packet_type][0])
&& !empty($this->packets_response[$packet_type][0])
)
{
return TRUE;
}
return FALSE;
}
/**
* Create a server join link based on the server information
*
* @return string
*/
protected function getJoinLink()
{
$link = '';
// We have a join_link defined
if(!empty($this->join_link))
{
$link = sprintf($this->join_link, $this->ip, $this->port_client);
}
return $link;
}
}

View file

@ -0,0 +1,30 @@
<?php
/**
* This file is part of GameQ.
*
* GameQ is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* GameQ is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* Crysis Protocol Class
*
* @author Austin Bischoff <austin@codebeard.com>
*/
class GameQ_Protocols_Crysis extends GameQ_Protocols_Gamespy3
{
protected $name = "crysis";
protected $name_long = "Crysis";
protected $port = 64087;
}

View file

@ -0,0 +1,30 @@
<?php
/**
* This file is part of GameQ.
*
* GameQ is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* GameQ is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* Crysis 2 Protocol Class
*
* @author Austin Bischoff <austin@codebeard.com>
*/
class GameQ_Protocols_Crysis2 extends GameQ_Protocols_Gamespy3
{
protected $name = "crysis2";
protected $name_long = "Crysis 2";
protected $port = 64000;
}

View file

@ -0,0 +1,30 @@
<?php
/**
* This file is part of GameQ.
*
* GameQ is free software; you can redistribute it and/or modify
* it under the terms of the GNU 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/>.
*/
/**
* Crysis Warhead Protocol Class
*
* @author Austin Bischoff <austin@codebeard.com>
*/
class GameQ_Protocols_Crysiswarhead extends GameQ_Protocols_Gamespy3
{
protected $name = "crysiswarhead";
protected $name_long = "Crysis Warhead";
protected $port = 64100;
}

View file

@ -0,0 +1,30 @@
<?php
/**
* This file is part of GameQ.
*
* GameQ is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* GameQ is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* Crysis Wars Protocol Class
*
* @author Austin Bischoff <austin@codebeard.com>
*/
class GameQ_Protocols_Crysiswars extends GameQ_Protocols_Gamespy3
{
protected $name = "crysiswars";
protected $name_long = "Crysis Wars";
protected $port = 64100;
}

View file

@ -0,0 +1,28 @@
<?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/>.
*/
/**
* Counter-Strike 1.5 Protocol Class
*
* @author Nikolay Ipanyuk <rostov114@gmail.com>
*/
class GameQ_Protocols_Cs15 extends GameQ_Protocols_Won
{
protected $name = "cs15";
protected $name_long = "Counter-Strike 1.5";
}

View file

@ -0,0 +1,49 @@
<?php
/**
* This file is part of GameQ.
*
* GameQ is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* GameQ is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* Counter-Strike 1.6 Protocol Class
*
* @author Austin Bischoff <austin@codebeard.com>
*/
class GameQ_Protocols_Cs16 extends GameQ_Protocols_Source
{
protected $name = "cs16";
protected $name_long = "Counter-Strike 1.6";
/**
* We have to overload this function to cheat the rules processing because of some wierdness, old ass game!
*
* @see GameQ_Protocols_Source::preProcess_rules()
*/
protected function preProcess_rules($packets)
{
$engine_orig = $this->source_engine;
// Override the engine type for rules, not sure why its like that
$this->source_engine = self::GOLDSOURCE_ENGINE;
// Now process the rules
$ret = parent::preProcess_rules($packets);
// Reset the engine type
$this->source_engine = $engine_orig;
return $ret;
}
}

View file

@ -0,0 +1,49 @@
<?php
/**
* This file is part of GameQ.
*
* GameQ is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* GameQ is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* Counter-Strike: Condition Zero Protocol Class
*
* @author Austin Bischoff <austin@codebeard.com>
*/
class GameQ_Protocols_Cscz extends GameQ_Protocols_Source
{
protected $name = "cscz";
protected $name_long = "Counter-Strike: Condition Zero";
/**
* We have to overload this function to cheat the rules processing because of some wierdness, old ass game!
*
* @see GameQ_Protocols_Source::preProcess_rules()
*/
protected function preProcess_rules($packets)
{
$engine_orig = $this->source_engine;
// Override the engine type for rules, not sure why its like that
$this->source_engine = self::GOLDSOURCE_ENGINE;
// Now process the rules
$ret = parent::preProcess_rules($packets);
// Reset the engine type
$this->source_engine = $engine_orig;
return $ret;
}
}

View file

@ -0,0 +1,28 @@
<?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/>.
*/
/**
* Counter-Strike: Global Offensive Protocol Class
*
* @author Austin Bischoff <austin@codebeard.com>
*/
class GameQ_Protocols_Csgo extends GameQ_Protocols_Source
{
protected $name = "csgo";
protected $name_long = "Counter-Strike: Global Offensive";
}

View file

@ -0,0 +1,28 @@
<?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/>.
*/
/**
* Counter-Strike: Source Protocol Class
*
* @author Austin Bischoff <austin@codebeard.com>
*/
class GameQ_Protocols_Css extends GameQ_Protocols_Source
{
protected $name = "css";
protected $name_long = "Counter-Strike: Source";
}

View file

@ -0,0 +1,175 @@
<?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/>.
*/
/**
* Cube 2: Sauerbraten Protocol Class
*
* References:
* https://qstat.svn.sourceforge.net/svnroot/qstat/trunk/qstat2/cube2.c
*
* @author Austin Bischoff <austin@codebeard.com>
*/
class GameQ_Protocols_Cube2 extends GameQ_Protocols
{
protected $state = self::STATE_BETA;
protected $normalize = array(
// General
'general' => array(
'hostname' => array('servername'),
'numplayers' => array('num_players'),
'maxplayers' => array('max_players'),
'mapname' => array('map'),
'gametype' => array('gametype'),
),
);
/**
* Array of packets we want to look up.
* Each key should correspond to a defined method in this or a parent class
*
* @var array
*/
protected $packets = array(
self::PACKET_STATUS => "server",
);
/**
* Methods to be run when processing the response(s)
*
* @var array
*/
protected $process_methods = array(
"process_status",
);
/**
* Default port for this server type
*
* @var int
*/
protected $port = 28802; // Default port, used if not set when instanced
/**
* The query protocol used to make the call
*
* @var string
*/
protected $protocol = 'cube2';
/**
* String name of this protocol class
*
* @var string
*/
protected $name = 'cube2';
/**
* Longer string name of this protocol class
*
* @var string
*/
protected $name_long = "Cube 2: Sauerbraten";
/**
* Pre-process the server status data that was returned.
*
* @param array $packets
*/
protected function preProcess_status($packets)
{
// Process the packets
return implode('', $packets);
}
/**
* Handles processing the status data into a usable format
*
* @throws GameQ_ProtocolsException
*/
protected function process_status()
{
// Make sure we have a valid response
if(!$this->hasValidResponse(self::PACKET_STATUS))
{
return array();
}
// Set the result to a new result instance
$result = new GameQ_Result();
// Let's preprocess the rules
$data = $this->preProcess_status($this->packets_response[self::PACKET_STATUS]);
// Create a new buffer
$buf = new GameQ_Buffer($data);
// Check the header, should be the same response as the packet we sent
if($buf->read(6) != $this->packets[self::PACKET_STATUS])
{
throw new GameQ_ProtocolsException("Data for ".__METHOD__." does not have the proper header type (should be {$this->packets[self::PACKET_STATUS]}).");
return array();
}
// NOTE: the following items were figured out using some source and trial and error
$result->add('num_players', $this->readInt($buf));
$result->add('version', $this->readInt($buf));
$result->add('protocol', $this->readInt($buf));
$result->add('mode', $this->readInt($buf));
$result->add('time_remaining', $this->readInt($buf));
$result->add('max_players', $this->readInt($buf));
$result->add('mastermode', $this->readInt($buf));
// @todo: Sometimes there is an extra char here before the map string. Not sure what causes it or how
// to even check for its existance.
$result->add('map', $buf->readString());
$result->add('servername', $buf->readString());
unset($buf, $data);
return $result->fetch();
}
/**
* Function to check for varying int values in the responses. Makes life a little easier
*
* @param GameQ_Buffer $buf
* @return number
*/
protected function readInt(GameQ_Buffer &$buf)
{
// Look ahead and see if 32-bit int
if($buf->lookAhead(1) == "\x81")
{
$buf->skip(1);
return $buf->readInt32();
}
// Look ahead and see if 16-bit int
elseif($buf->lookAhead(1) == "\x80")
{
$buf->skip(1);
return $buf->readInt16();
}
else // 8-bit
{
return $buf->readInt8();
}
}
}

View file

@ -0,0 +1,30 @@
<?php
/**
* This file is part of GameQ.
*
* GameQ is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* GameQ is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* DayZ Standalone Protocol Class
*
* Note that this is not DayZ Mod but a standalone game in Steam
*
* @author Austin Bischoff <austin@codebeard.com>
*/
class GameQ_Protocols_Dayz extends GameQ_Protocols_Source
{
protected $name = "dayz";
protected $name_long = "DayZ Standalone";
}

View file

@ -0,0 +1,29 @@
<?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/>.
*/
/**
* DayZ Mod Protocol Class
*
* @author Marcel Bößendörfer <m.boessendoerfer@marbis.net>
* @author Austin Bischoff <austin@codebeard.com>
*/
class GameQ_Protocols_Dayzmod extends GameQ_Protocols_Source
{
protected $name = "dayzmod";
protected $name_long = "DayZ Mod";
}

View file

@ -0,0 +1,28 @@
<?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/>.
*/
/**
* Day of Defeat Protocol Class
*
* @author Austin Bischoff <austin@codebeard.com>
*/
class GameQ_Protocols_Dod extends GameQ_Protocols_Source
{
protected $name = "dod";
protected $name_long = "Day of Defeat";
}

View file

@ -0,0 +1,28 @@
<?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/>.
*/
/**
* Day of Defeat: Source Protocol Class
*
* @author Austin Bischoff <austin@codebeard.com>
*/
class GameQ_Protocols_Dods extends GameQ_Protocols_Source
{
protected $name = "dods";
protected $name_long = "Day of Defeat: Source";
}

View file

@ -0,0 +1,163 @@
<?php
/**
* This file is part of GameQ.
*
* GameQ is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* GameQ is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* Doom3 Protocol Class
*
* @author Austin Bischoff <austin@codebeard.com>
*/
class GameQ_Protocols_Doom3 extends GameQ_Protocols
{
/**
* Array of packets we want to look up.
* Each key should correspond to a defined method in this or a parent class
*
* @var array
*/
protected $packets = array(
self::PACKET_ALL => "\xFF\xFFgetInfo\x00PiNGPoNG\x00",
);
/**
* Methods to be run when processing the response(s)
*
* @var array
*/
protected $process_methods = array(
"process_all",
);
/**
* Default port for this server type
*
* @var int
*/
protected $port = 27666; // Default port, used if not set when instanced
/**
* The protocol being used
*
* @var string
*/
protected $protocol = 'doom3';
/**
* String name of this protocol class
*
* @var string
*/
protected $name = 'doom3';
/**
* Longer string name of this protocol class
*
* @var string
*/
protected $name_long = "Doom 3";
/*
* Internal methods
*/
protected function preProcess_all($packets=array())
{
// Implode and return
return implode('', $packets);
}
protected function process_all()
{
// Make sure we have a valid response
if(!$this->hasValidResponse(self::PACKET_ALL))
{
return array();
}
// Set the result to a new result instance
$result = new GameQ_Result();
// Parse the response
$data = $this->preProcess_all($this->packets_response[self::PACKET_ALL]);
// Create a new buffer
$buf = new GameQ_Buffer($data);
// Header
if ($buf->readInt16() !== 65535 or $buf->readString() !== 'infoResponse')
{
throw new GameQ_ProtocolsException('Header for response does not match. Buffer:'.$this->packets_response[self::PACKET_ALL]);
return array();
}
$result->add('version', $buf->readInt8() . '.' . $buf->readInt8());
// Var / value pairs, delimited by an empty pair
while ($buf->getLength())
{
$var = $buf->readString();
$val = $buf->readString();
// Something is empty so we are done
if (empty($var) && empty($val))
{
break;
}
$result->add($var, $val);
}
// Now lets parse the players
$this->parsePlayers($buf, $result);
unset($buf, $data);
// Return the result
return $result->fetch();
}
/**
* Parse the players. Set as its own method so it can be overloaded.
*
* @param GameQ_Buffer $buf
* @param GameQ_Result $result
*/
protected function parsePlayers(GameQ_Buffer &$buf, GameQ_Result &$result)
{
// There is no way to see the number of players so we have to increment
// a variable and do it that way.
$players = 0;
// Loop thru the buffer until we run out of data
while (($id = $buf->readInt8()) != 32)
{
$result->addPlayer('id', $id);
$result->addPlayer('ping', $buf->readInt16());
$result->addPlayer('rate', $buf->readInt32());
$result->addPlayer('name', $buf->readString());
$players++;
}
// Add the number of players to the result
$result->add('numplayers', $players);
return TRUE;
}
}

View file

@ -0,0 +1,48 @@
<?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/>.
*/
/**
* Terraria Protocol Class
*
* This class utilizes the Tshock protocol
*
* @author Austin Bischoff <austin@codebeard.com>
*/
class GameQ_Protocols_Eco extends GameQ_Protocols_Ecoapi
{
/**
* Default port for this server type
*
* @var int
*/
protected $port = 10001; // Default port, used if not set when instanced
/**
* String name of this protocol class
*
* @var string
*/
protected $name = 'eco';
/**
* Longer string name of this protocol class
*
* @var string
*/
protected $name_long = "ECO";
}

View file

@ -0,0 +1,149 @@
<?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/>.
*/
abstract class GameQ_Protocols_Ecoapi extends GameQ_Protocols_Http
{
/**
* Array of packets we want to look up.
* Each key should correspond to a defined method in this or a parent class
*
* @var array
*/
protected $packets = array(
self::PACKET_STATUS => "GET /info HTTP/1.0\r\nAccept: */*\r\n\r\n",
self::PACKET_PLAYERS => "GET /api/v1/analysis/playstyles HTTP/1.0\r\nAccept: */*\r\n\r\n",
);
/**
* Methods to be run when processing the response(s)
*
* @var array
*/
protected $process_methods = array(
"process_status",
"process_players",
);
/**
* The protocol being used
*
* @var string
*/
protected $protocol = 'ecoapi';
/**
* String name of this protocol class
*
* @var string
*/
protected $name = 'ecoapi';
/**
* Longer string name of this protocol class
*
* @var string
*/
protected $name_long = "ECO API";
/*
* Internal methods
*/
protected function preProcess_status($packets)
{
// Implode and rip out the JSON
preg_match('/\{(.*)\}/ms', implode('', $packets), $m);
return $m[0];
}
protected function process_status()
{
// Make sure we have a valid response
if(!$this->hasValidResponse(self::PACKET_STATUS))
{
return array();
}
// Return should be JSON, let's validate
if(($json = json_decode($this->preProcess_status($this->packets_response[self::PACKET_STATUS]))) === NULL)
{
throw new GameQ_ProtocolsException("JSON response from ECO API is invalid.");
}
// Set the result to a new result instance
$result = new GameQ_Result();
// Server is always dedicated
$result->add('dedicated', $json->IsLAN);
// No mods, as of yet
$result->add('mod', FALSE);
// These are the same no matter what mode the server is in
$result->add('hostname', $json->Description);
$result->add('game_port', $json->GamePort);
$result->add('num_players', $json->OnlinePlayers);
$result->add('maxplayers', $json->TotalPlayers);
return $result->fetch();
}
/**
* Pre-process the player data sent
*
* @param array $packets
*/
protected function preProcess_players($packets)
{
// Implode and rip out the JSON
//preg_match('/\{(.*)\}/ms', implode('', $packets), $m);
echo $packets;
return $packets;
}
protected function process_players()
{
// Make sure we have a valid response
if(!$this->hasValidResponse(self::PACKET_PLAYERS))
{
return array();
}
// Return should be JSON, let's validate
if(($json = json_decode($this->preProcess_players($this->packets_response[self::PACKET_PLAYERS]))) === NULL)
{
throw new GameQ_ProtocolsException("JSON response from ECO API is invalid.");
}
// Set the result to a new result instance
$result = new GameQ_Result();
// Players are a comma(space) seperated list
if(isset($json) && !empty($json))
{
// Do the players
foreach($json AS $player)
{
$result->addPlayer('name', $player->Username);
}
}
return $result->fetch();
}
}

View file

@ -0,0 +1,30 @@
<?php
/**
* This file is part of GameQ.
*
* GameQ is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* GameQ is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* Wolfenstein Enemy Territory Protocol Class
*
* @author Austin Bischoff <austin@codebeard.com>
*/
class GameQ_Protocols_Et extends GameQ_Protocols_Quake3
{
protected $name = "et";
protected $name_long = "Wolfenstein Enemy Territory";
protected $port = 27960;
}

View file

@ -0,0 +1,225 @@
<?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/>.
*/
/**
* Enemy Territory: Quake Wars Protocol Class
*
* @author Austin Bischoff <austin@codebeard.com>
*/
class GameQ_Protocols_Etqw extends GameQ_Protocols
{
/**
* Array of packets we want to look up.
* Each key should correspond to a defined method in this or a parent class
*
* @var array
*/
protected $packets = array(
self::PACKET_STATUS => "\xFF\xFFgetInfoEx\x00\x00\x00\x00",
//self::PACKET_STATUS => "\xFF\xFFgetInfo\x00\x00\x00\x00\x00",
);
/**
* Methods to be run when processing the response(s)
*
* @var array
*/
protected $process_methods = array(
"process_status",
);
/**
* Default port for this server type
*
* @var int
*/
protected $port = 27733; // Default port, used if not set when instanced
/**
* The protocol being used
*
* @var string
*/
protected $protocol = 'etqw';
/**
* String name of this protocol class
*
* @var string
*/
protected $name = 'etqw';
/**
* Longer string name of this protocol class
*
* @var string
*/
protected $name_long = "Enemy Territory: Quake Wars";
/*
* Internal methods
*/
protected function preProcess_status($packets)
{
// Should only be one packet
if (count($packets) > 1)
{
throw new GameQ_ProtocolsException('Enemy Territor: Quake Wars status has more than 1 packet');
}
// Make buffer so we can check this out
$buf = new GameQ_Buffer($packets[0]);
// Grab the header
$header = $buf->readString();
// Now lets verify the header
if(!strstr($header, 'infoExResponse'))
{
throw new GameQ_ProtocolsException('Unable to match Enemy Territor: Quake Wars response header. Header: '. $header);
return FALSE;
}
// Return the data with the header stripped, ready to go.
return $buf->getBuffer();
}
/**
* Process the server status
*
* @throws GameQ_ProtocolsException
*/
protected function process_status()
{
// Make sure we have a valid response
if(!$this->hasValidResponse(self::PACKET_STATUS))
{
return array();
}
// Set the result to a new result instance
$result = new GameQ_Result();
// Lets pre process and make sure these things are in the proper order by id
$data = $this->preProcess_status($this->packets_response[self::PACKET_STATUS]);
// Make buffer
$buf = new GameQ_Buffer($data);
// Now burn the challenge, version and size
$buf->skip(16);
// Key / value pairs
while ($buf->getLength())
{
$var = str_replace('si_', '', $buf->readString());
$val = $buf->readString();
if (empty($var) && empty($val))
{
break;
}
// Add the server prop
$result->add($var, $val);
}
// Now let's do the basic player info
$this->parsePlayers($buf, $result);
// Now grab the rest of the server info
$result->add('osmask', $buf->readInt32());
$result->add('ranked', $buf->readInt8());
$result->add('timeleft', $buf->readInt32());
$result->add('gamestate', $buf->readInt8());
$result->add('servertype', $buf->readInt8());
// 0: regular server
if ($result->get('servertype') == 0)
{
$result->add('interested_clients', $buf->readInt8());
}
// 1: tv server
else
{
$result->add('connected_clients', $buf->readInt32());
$result->add('max_clients', $buf->readInt32());
}
// Now let's parse the extended player info
$this->parsePlayersExtra($buf, $result);
// Free some memory
unset($sections, $buf, $data);
// Return the result
return $result->fetch();
}
/**
* Parse the players and add them to the return.
*
* @param GameQ_Buffer $buf
* @param GameQ_Result $result
*/
protected function parsePlayers(GameQ_Buffer &$buf, GameQ_Result &$result)
{
$players = 0;
while (($id = $buf->readInt8()) != 32)
{
$result->addPlayer('id', $id);
$result->addPlayer('ping', $buf->readInt16());
$result->addPlayer('name', $buf->readString());
$result->addPlayer('clantag_pos', $buf->readInt8());
$result->addPlayer('clantag', $buf->readString());
$result->addPlayer('bot', $buf->readInt8());
$players++;
}
// Let's add in the current players as a result
$result->add('numplayers', $players);
// Free some memory
unset($id);
}
/**
* Parse the players extra info and add them to the return.
*
* @param GameQ_Buffer $buf
* @param GameQ_Result $result
*/
protected function parsePlayersExtra(GameQ_Buffer &$buf, GameQ_Result &$result)
{
while (($id = $buf->readInt8()) != 32)
{
$result->addPlayer('total_xp', $buf->readFloat32());
$result->addPlayer('teamname', $buf->readString());
$result->addPlayer('total_kills', $buf->readInt32());
$result->addPlayer('total_deaths', $buf->readInt32());
}
// @todo: Add team stuff
// Free some memory
unset($id);
}
}

View file

@ -0,0 +1,30 @@
<?php
/**
* This file is part of GameQ.
*
* GameQ is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* GameQ is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* F.E.A.R. Protocol Class
*
* @author Austin Bischoff <austin@codebeard.com>
*/
class GameQ_Protocols_Fear extends GameQ_Protocols_Gamespy2
{
protected $name = "fear";
protected $name_long = "F.E.A.R.";
protected $port = 27888;
}

View file

@ -0,0 +1,28 @@
<?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/>.
*/
/**
* Fortress Forever Protocol Class
*
* @author Austin Bischoff <austin@codebeard.com>
*/
class GameQ_Protocols_Ffe extends GameQ_Protocols_Source
{
protected $name = "ffe";
protected $name_long = "Fortress Forever";
}

View file

@ -0,0 +1,246 @@
<?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/>.
*/
/**
* Frontlines: Fuel of War Protocol Class
*
* Class is incomplete due to the lack of servers with players active.
*
* http://wiki.hlsw.net/index.php/FFOW_Protocol
*
* @author Austin Bischoff <austin@codebeard.com>
*/
class GameQ_Protocols_Ffow extends GameQ_Protocols
{
/**
* Array of packets we want to look up.
* Each key should correspond to a defined method in this or a parent class
*
* @var array
*/
protected $packets = array(
self::PACKET_CHALLENGE => "\xFF\xFF\xFF\xFF\x57",
self::PACKET_RULES => "\xFF\xFF\xFF\xFF\x56%s",
//self::PACKET_PLAYERS => "\xFF\xFF\xFF\xFF\x55%s",
self::PACKET_INFO => "\xFF\xFF\xFF\xFF\x46\x4C\x53\x51",
);
protected $state = self::STATE_TESTING;
/**
* Set the packet mode to linear
*
* @var string
*/
protected $packet_mode = self::PACKET_MODE_LINEAR;
/**
* Methods to be run when processing the response(s)
*
* @var array
*/
protected $process_methods = array(
"process_info",
"process_rules",
//"process_players",
);
/**
* Default port for this server type
*
* @var int
*/
protected $port = 5478; // Default port, used if not set when instanced
/**
* The protocol being used
*
* @var string
*/
protected $protocol = 'ffow';
/**
* String name of this protocol class
*
* @var string
*/
protected $name = 'ffow';
/**
* Longer string name of this protocol class
*
* @var string
*/
protected $name_long = "Frontlines: Fuel of War";
/*
* Internal methods
*/
/**
* Parse the challenge response and apply it to all the packet types
* that require it.
*
* @see GameQ_Protocols_Core::parseChallengeAndApply()
*/
protected function parseChallengeAndApply()
{
// Skip the header
$this->challenge_buffer->skip(5);
// Apply the challenge and return
return $this->challengeApply($this->challenge_buffer->read(4));
}
/**
* Preprocess the server info packet(s)
*
* @param unknown_type $packets
*/
protected function preProcess_info($packets=array())
{
// Implode and return
return implode('', $packets);
}
protected function process_info()
{
// Make sure we have a valid response
if(!$this->hasValidResponse(self::PACKET_INFO))
{
return array();
}
// Set the result to a new result instance
$result = new GameQ_Result();
// Parse the response
$data = $this->preProcess_info($this->packets_response[self::PACKET_INFO]);
// Create a new buffer
$buf = new GameQ_Buffer($data);
// Skip Header
$buf->skip(6);
$result->add('servername', $buf->readString());
$result->add('mapname', $buf->readString());
$result->add('modname', $buf->readString());
$result->add('gamemode', $buf->readString());
$result->add('description', $buf->readString());
$result->add('version', $buf->readString());
$result->add('port', $buf->readInt16());
$result->add('num_players', $buf->readInt8());
$result->add('max_players', $buf->readInt8());
$result->add('dedicated', $buf->readInt8());
$result->add('os', $buf->readInt8());
$result->add('password', $buf->readInt8());
$result->add('anticheat', $buf->readInt8());
$result->add('average_fps', $buf->readInt8());
$result->add('round', $buf->readInt8());
$result->add('max_rounds', $buf->readInt8());
$result->add('time_left', $buf->readInt16());
unset($buf, $data);
// Return the result
return $result->fetch();
}
/**
* Preprocess the rule packets returned. Not sure if this is final, need server to test against.
*
* @param array $packets
*/
protected function preProcess_rules($packets=array())
{
// Implode and return
return implode('', $packets);
}
/**
* Process the rules and return the data result
*/
protected function process_rules()
{
// Make sure we have a valid response
if(!$this->hasValidResponse(self::PACKET_RULES))
{
return array();
}
// Set the result to a new result instance
$result = new GameQ_Result();
// Parse the response
$data = $this->preProcess_rules($this->packets_response[self::PACKET_RULES]);
// Create a new buffer
$buf = new GameQ_Buffer($data);
// Skip Header
$buf->skip(6);
while($buf->getLength())
{
$key = $buf->readString();
if(strlen($key) == 0)
{
break;
}
// Check for map
if(strstr($key, "Map:"))
{
$result->addSub("maplist", "name", $buf->readString());
}
else // Regular rule
{
$result->add($key, $buf->readString());
}
}
unset($buf, $data);
// Return the result
return $result->fetch();
}
/**
* Pre process the player packets, Not final. Need server to test against
*
* @param array $packets
*/
protected function preProcess_players($packets=array())
{
// Implode and return
return implode('', $packets);
}
protected function process_players()
{
// Make sure we have a valid response
if(!$this->hasValidResponse(self::PACKET_PLAYERS))
{
return array();
}
return array();
}
}

View file

@ -0,0 +1,216 @@
<?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/>.
*/
/**
* GameSpy Protocol Class
*
* This class is used as the basis for all game servers
* that use the GameSpy protocol for querying
* server status.
*
* @author Austin Bischoff <austin@codebeard.com>
*/
class GameQ_Protocols_Gamespy extends GameQ_Protocols
{
/**
* Array of packets we want to look up.
* Each key should correspond to a defined method in this or a parent class
*
* Note: We only send the status packet since that has all the information we ever need.
* The other packets are left for reference purposes
*
* @var array
*/
protected $packets = array(
self::PACKET_STATUS => "\x5C\x73\x74\x61\x74\x75\x73\x5C",
//self::PACKET_PLAYERS => "\x5C\x70\x6C\x61\x79\x65\x72\x73\x5C",
//self::PACKET_DETAILS => "\x5C\x69\x6E\x66\x6F\x5C",
//self::PACKET_BASIC => "\x5C\x62\x61\x73\x69\x63\x5C",
//self::PACKET_RULES => "\x5C\x72\x75\x6C\x65\x73\x5C",
);
/**
* Methods to be run when processing the response(s)
*
* @var array
*/
protected $process_methods = array(
"process_status",
);
/**
* Default port for this server type
*
* @var int
*/
protected $port = 1; // Default port, used if not set when instanced
/**
* The protocol being used
*
* @var string
*/
protected $protocol = 'gamespy';
/**
* String name of this protocol class
*
* @var string
*/
protected $name = 'gamespy';
/**
* Longer string name of this protocol class
*
* @var string
*/
protected $name_long = "Gamespy";
/*
* Internal methods
*/
protected function preProcess($packets)
{
// Only one packet so its in order
if (count($packets) == 1)
{
return $packets[0];
}
// Holds the new list of packets, which will be stripped of queryid and ordered properly.
$packets_ordered = array();
// Loop thru the packets
foreach ($packets as $packet)
{
// Check to see if we had a preg_match error
if(preg_match("#^(.*)\\\\queryid\\\\([^\\\\]+)(\\\\|$)#", $packet, $matches) === FALSE)
{
throw new GameQ_ProtocolsException('An error occured while parsing the status packets');
return $packets_ordered;
}
// Lets make the key proper incase of decimal points
if(strstr($matches[2], '.'))
{
list($req_id, $req_num) = explode('.', $matches[2]);
// Now lets put back the number but make sure we pad the req_num so it is correct
// Should make sure the length is always 4 digits past the decimal point
// For some reason the req_num is 1->12.. instead of 01->12 ... so it doesnt ksort properly
$key = $req_id . sprintf(".%04s", $req_num);
}
else
{
$key = $matches[2];
}
// Add this stripped queryid to the new array with the id as the key
$packets_ordered[$key] = $matches[1];
}
// Sort the new array to make sure the keys (query ids) are in the proper order
ksort($packets_ordered, SORT_NUMERIC);
// Implode and return only the values as we dont care about the keys anymore
return implode('', array_values($packets_ordered));
}
/**
* Process the server status
*
* @throws GameQ_ProtocolsException
*/
protected function process_status()
{
// Make sure we have a valid response
if(!$this->hasValidResponse(self::PACKET_STATUS))
{
return array();
}
// Set the result to a new result instance
$result = new GameQ_Result();
// Lets pre process and make sure these things are in the proper order by id
$data = $this->preProcess($this->packets_response[self::PACKET_STATUS]);
// Create a new buffer
$buf = new GameQ_Buffer($data);
// Lets peek and see if the data starts with a \
if($buf->lookAhead(1) == '\\')
{
// Burn the first one
$buf->skip(1);
}
// Explode the data
$data = explode('\\', $buf->getBuffer());
// Remove the last 2 "items" as it should be final\
array_pop($data);
array_pop($data);
// Init some vars
$num_players = 0;
$num_teams = 0;
// Now lets loop the array
for($x=0;$x<count($data);$x+=2)
{
// Set some local vars
$key = $data[$x];
$val = $data[$x+1];
// Check for <variable>_<count> variable (i.e players)
if(($suffix = strrpos($key, '_')) !== FALSE && is_numeric(substr($key, $suffix+1)))
{
// See if this is a team designation
if(substr($key, 0, $suffix) == 'teamname')
{
$result->addTeam('teamname', $val);
$num_teams++;
}
else // Its a player
{
if(substr($key, 0, $suffix) == 'playername')
{
$num_players++;
}
$result->addPlayer(substr($key, 0, $suffix), $val);
}
}
else // Regular variable so just add the value.
{
$result->add($key, $val);
}
}
// Add the player and team count
$result->add('num_players', $num_players);
$result->add('num_teams', $num_teams);
unset($buf, $data, $key, $val, $suffix, $x);
return $result->fetch();
}
}

View file

@ -0,0 +1,261 @@
<?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/>.
*/
/**
* GameSpy2 Protocol Class
*
* This class is used as the basis for all game servers
* that use the GameSpy2 protocol for querying
* server status.
*
* @author Austin Bischoff <austin@codebeard.com>
*/
class GameQ_Protocols_Gamespy2 extends GameQ_Protocols
{
/**
* Array of packets we want to look up.
* Each key should correspond to a defined method in this or a parent class
*
* @var array
*/
protected $packets = array(
self::PACKET_DETAILS => "\xFE\xFD\x00\x43\x4F\x52\x59\xFF\x00\x00",
self::PACKET_PLAYERS => "\xFE\xFD\x00\x43\x4F\x52\x59\x00\xFF\xFF",
);
/**
* Methods to be run when processing the response(s)
*
* @var array
*/
protected $process_methods = array(
"process_details",
"process_players",
);
/**
* Default port for this server type
*
* @var int
*/
protected $port = 1; // Default port, used if not set when instanced
/**
* The protocol being used
*
* @var string
*/
protected $protocol = 'gamespy2';
/**
* String name of this protocol class
*
* @var string
*/
protected $name = 'gamespy2';
/**
* Longer string name of this protocol class
*
* @var string
*/
protected $name_long = "Gamespy2";
/*
* Internal methods
*/
/**
* Pre-process the server details data that was returned.
*
* @param array $packets
*/
protected function preProcess_details($packets)
{
return $packets[0];
}
/**
* Process the server details
*
* @throws GameQ_ProtocolsException
*/
protected function process_details()
{
// Make sure we have a valid response
if(!$this->hasValidResponse(self::PACKET_DETAILS))
{
return array();
}
// Set the result to a new result instance
$result = new GameQ_Result();
// Let's preprocess the rules
$data = $this->preProcess_details($this->packets_response[self::PACKET_DETAILS]);
// Create a new buffer
$buf = new GameQ_Buffer($data);
// Make sure the data is formatted properly
if($buf->lookAhead(5) != "\x00\x43\x4F\x52\x59")
{
throw new GameQ_ProtocolsException("Data for ".__METHOD__." does not have the proper header. Header: ".$buf->lookAhead(5));
return false;
}
// Now verify the end of the data is correct
if($buf->readLast() !== "\x00")
{
throw new GameQ_ProtocolsException("Data for ".__METHOD__." does not have the proper ending. Ending: ".$buf->readLast());
return false;
}
// Skip the header
$buf->skip(5);
// Loop thru all of the settings and add them
while ($buf->getLength())
{
// Temp vars
$key = $buf->readString();
$val = $buf->readString();
// Check to make sure there is a valid pair
if(!empty($key))
{
$result->add($key, $val);
}
}
unset($buf, $data, $key, $var);
return $result->fetch();
}
/**
* Pre-process the player data that was returned.
*
* @param array $packets
*/
protected function preProcess_players($packets)
{
return $packets[0];
}
/**
* Process the player data
*
* @throws GameQ_ProtocolsException
*/
protected function process_players()
{
// Make sure we have a valid response
if(!$this->hasValidResponse(self::PACKET_PLAYERS))
{
return array();
}
// Set the result to a new result instance
$result = new GameQ_Result();
// Let's preprocess the rules
$data = $this->preProcess_players($this->packets_response[self::PACKET_PLAYERS]);
// Create a new buffer
$buf = new GameQ_Buffer($data);
// Make sure the data is formatted properly
if($buf->lookAhead(6) != "\x00\x43\x4F\x52\x59\x00")
{
throw new GameQ_ProtocolsException("Data for ".__METHOD__." does not have the proper header. Header: ".$buf->lookAhead(6));
return false;
}
// Now verify the end of the data is correct
if($buf->readLast() !== "\x00")
{
throw new GameQ_ProtocolsException("Data for ".__METHOD__." does not have the proper ending. Ending: ".$buf->readLast());
return false;
}
// Skip the header
$buf->skip(6);
// Players are first
$this->parse_playerteam('players', $buf, $result);
// Teams are next
$this->parse_playerteam('teams', $buf, $result);
unset($buf, $data);
return $result->fetch();
}
/**
* Parse the player/team info returned from the player call
*
* @param string $type
* @param GameQ_Buffer $buf
* @param GameQ_Result $result
*/
protected function parse_playerteam($type, &$buf, &$result)
{
// Do count
$result->add('num_'.$type, $buf->readInt8());
// Variable names
$varnames = array();
// Loop until we run out of length
while ($buf->getLength())
{
$varnames[] = str_replace('_', '', $buf->readString());
if ($buf->lookAhead() === "\x00")
{
$buf->skip();
break;
}
}
// Check if there are any value entries
if ($buf->lookAhead() == "\x00")
{
$buf->skip();
return;
}
// Get the values
while ($buf->getLength() > 4)
{
foreach ($varnames as $varname)
{
$result->addSub($type, $varname, $buf->readString());
}
if ($buf->lookAhead() === "\x00")
{
$buf->skip();
break;
}
}
return;
}
}

View file

@ -0,0 +1,446 @@
<?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/>.
*/
/**
* GameSpy3 Protocol Class
*
* This class is used as the basis for all game servers
* that use the GameSpy3 protocol for querying
* server status.
*
* Note: UT3 and Crysis2 have known issues with GSv3 responses
*
* @author Austin Bischoff <austin@codebeard.com>
*/
class GameQ_Protocols_Gamespy3 extends GameQ_Protocols
{
/**
* Set the packet mode to linear
*
* @var string
*/
protected $packet_mode = self::PACKET_MODE_LINEAR;
/**
* Array of packets we want to look up.
* Each key should correspond to a defined method in this or a parent class
*
* @var array
*/
protected $packets = array(
self::PACKET_CHALLENGE => "\xFE\xFD\x09\x10\x20\x30\x40",
self::PACKET_ALL => "\xFE\xFD\x00\x10\x20\x30\x40%s\xFF\xFF\xFF\x01",
);
/**
* Methods to be run when processing the response(s)
*
* @var array
*/
protected $process_methods = array(
"process_all",
);
/**
* Default port for this server type
*
* @var int
*/
protected $port = 1; // Default port, used if not set when instanced
/**
* The protocol being used
*
* @var string
*/
protected $protocol = 'gamespy3';
/**
* String name of this protocol class
*
* @var string
*/
protected $name = 'gamespy3';
/**
* Longer string name of this protocol class
*
* @var string
*/
protected $name_long = "Gamespy3";
/**
* Parse the challenge response and apply it to all the packet types
* that require it.
*
* @see GameQ_Protocols_Core::parseChallengeAndApply()
*/
protected function parseChallengeAndApply()
{
// Pull out the challenge
$challenge = substr(preg_replace( "/[^0-9\-]/si", "", $this->challenge_buffer->getBuffer()), 1);
$challenge_result = sprintf(
"%c%c%c%c",
( $challenge >> 24 ),
( $challenge >> 16 ),
( $challenge >> 8 ),
( $challenge >> 0 )
);
// Apply the challenge and return
return $this->challengeApply($challenge_result);
}
/*
* Internal methods
*/
protected function preProcess_all($packets)
{
$return = array();
// Get packet index, remove header
foreach ($packets as $index => $packet)
{
// Make new buffer
$buf = new GameQ_Buffer($packet);
// Skip the header
$buf->skip(14);
// Get the current packet and make a new index in the array
$return[$buf->readInt16()] = $buf->getBuffer();
}
unset($buf);
// Sort packets, reset index
ksort($return);
// Grab just the values
$return = array_values($return);
// Compare last var of current packet with first var of next packet
// On a partial match, remove last var from current packet,
// variable header from next packet
for ($i = 0, $x = count($return); $i < $x - 1; $i++)
{
// First packet
$fst = substr($return[$i], 0, -1);
// Second packet
$snd = $return[$i+1];
// Get last variable from first packet
$fstvar = substr($fst, strrpos($fst, "\x00")+1);
// Get first variable from last packet
$snd = substr($snd, strpos($snd, "\x00")+2);
$sndvar = substr($snd, 0, strpos($snd, "\x00"));
// Check if fstvar is a substring of sndvar
// If so, remove it from the first string
if (strpos($sndvar, $fstvar) !== false)
{
$return[$i] = preg_replace("#(\\x00[^\\x00]+\\x00)$#", "\x00", $return[$i]);
}
}
// Now let's loop the return and remove any dupe prefixes
for($x = 1; $x < count($return); $x++)
{
$buf = new GameQ_Buffer($return[$x]);
$prefix = $buf->readString();
// Check to see if the return before has the same prefix present
if($prefix != null && strstr($return[($x-1)], $prefix))
{
// Update the return by removing the prefix plus 2 chars
$return[$x] = substr(str_replace($prefix, '', $return[$x]), 2);
}
unset($buf);
}
unset($x, $i, $snd, $sndvar, $fst, $fstvar);
// Implode into a string and return
return implode("", $return);
}
protected function process_all()
{
// Make sure we have a valid response
if(!$this->hasValidResponse(self::PACKET_ALL))
{
return array();
}
// Set the result to a new result instance
$result = new GameQ_Result();
// Parse the response
$data = $this->preProcess_all($this->packets_response[self::PACKET_ALL]);
// Create a new buffer
$buf = new GameQ_Buffer($data);
// We go until we hit an empty key
while($buf->getLength())
{
$key = $buf->readString();
if (strlen($key) == 0)
{
break;
}
$result->add($key, $buf->readString());
}
// Now we need to offload to parse the remaining data, player and team information
$this->parsePlayerTeamInfo($buf, $result);
// Return the result
return $result->fetch();
}
protected function delete_result(&$result, $array)
{
foreach($array as $key)
{
unset($result[$key]);
}
return TRUE;
}
protected function move_result(&$result, $old, $new)
{
if (isset($result[$old]))
{
$result[$new] = $result[$old];
unset($result[$old]);
}
return TRUE;
}
/**
* Parse the player and team information but do it smartly. Update to the old parseSub method.
*
* @param GameQ_Buffer $buf
* @param GameQ_Result $result
*/
protected function parsePlayerTeamInfo(GameQ_Buffer &$buf, GameQ_Result &$result)
{
/*
* Explode the data into groups. First is player, next is team (item_t)
*
* Each group should be as follows:
*
* [0] => item_
* [1] => information for item_
* ...
*/
$data = explode("\x00\x00", $buf->getBuffer());
// By default item_group is blank, this will be set for each loop thru the data
$item_group = '';
// By default the item_type is blank, this will be set on each loop
$item_type = '';
// Loop through all of the $data for information and pull it out into the result
for($x=0; $x < count($data)-1; $x++)
{
// Pull out the item
$item = $data[$x];
// If this is an empty item, move on
if($item == '' || $item == "\x00")
{
continue;
}
/*
* Left as reference:
*
* Each block of player_ and team_t have preceeding junk chars
*
* player_ is actually \x01player_
* team_t is actually \x00\x02team_t
*
* Probably a by-product of the change to exploding the data from the original.
*
* For now we just strip out these characters
*/
// Check to see if $item has a _ at the end, this is player info
if(substr($item, -1) == '_')
{
// Set the item group
$item_group = 'players';
// Set the item type, rip off any trailing stuff and bad chars
$item_type = rtrim(str_replace("\x01", '', $item), '_');
}
// Check to see if $item has a _t at the end, this is team info
elseif(substr($item, -2) == '_t')
{
// Set the item group
$item_group = 'teams';
// Set the item type, rip off any trailing stuff and bad chars
$item_type = rtrim(str_replace(array("\x00", "\x02"), '', $item), '_t');
}
// We can assume it is data belonging to a previously defined item
else
{
// Make a temp buffer so we have easier access to the data
$buf_temp = new GameQ_Buffer($item);
// Get the values
while ($buf_temp->getLength())
{
// No value so break the loop, end of string
if (($val = $buf_temp->readString()) === '')
{
break;
}
// Add the value to the proper item in the correct group
$result->addSub($item_group, $item_type, trim($val));
}
// Unset out buffer
unset($buf_temp);
}
}
// Free up some memory
unset($data, $item, $item_group, $item_type, $val);
}
/**
* Parse the player and team info
*
* @param GameQ_Buffer $buf
* @param GameQ_Result $result
* @throws GameQ_ProtocolsException
* @return boolean
*/
protected function parsePlayerTeamInfoNew(GameQ_Buffer &$buf, GameQ_Result &$result)
{
/**
* Player info is always first, team info (if defined) is second.
*
* Reference:
*
* Player info is preceeded by a hex code of \x01
* Team info is preceeded by a hex code of \x02
*/
// Check the header to make sure the player data is proper
if($buf->read(1) != "\x01")
{
//throw new GameQ_ProtocolsException("First character in player buffer != '\x01'");
return FALSE;
}
// Offload the player parsing
$this->parseSubInfo('players', $buf->readString("\x00\x00\x00"), $result);
// Check to make sure we have team information
if($buf->getLength() >= 6)
{
// Burn chars
$buf->skip(2);
// Check the header to make sure the data is proper
if($buf->read(1) != "\x02")
{
//throw new GameQ_ProtocolsException("First character in team buffer != '\x02'");
return FALSE;
}
// Offload the team parsing
$this->parseSubInfo('teams', $buf->readString("\x00\x00\x00"), $result);
}
return TRUE;
}
/**
* Parse the sub-item information for players and teams
*
* @param string $section
* @param string $data
* @param GameQ_Result $result
* @return boolean
*/
protected function parseSubInfo($section, $data, GameQ_Result &$result)
{
/*
* Explode the items so we can iterate easier
*
* Items should split up as follows:
*
* [0] => item_
* [1] => data for item_
* [2] => item2_
* [3] => data for item2_
* ...
*/
$items = explode("\x00\x00", $data);
print_r($items);
// Loop through all of the items
for($x = 0; $x < count($items); $x += 2)
{
// $x is always the key for the item (i.e. player_, ping_, team_, score_, etc...)
$item_type = rtrim($items[$x], '_,_t');
// $x+1 is always the data for the above item
// Make a temp buffer so we have easier access to the data
$buf_temp = new GameQ_Buffer($items[$x+1]);
// Get the values
while ($buf_temp->getLength())
{
// No value so break the loop, end of string
if (($val = $buf_temp->readString()) === '')
{
break;
}
// Add the value to the proper item in the correct group
$result->addSub($section, $item_type, trim($val));
}
// Unset out buffer
unset($buf_temp, $val);
}
unset($x, $items, $item_type);
return TRUE;
}
}

View file

@ -0,0 +1,30 @@
<?php
/**
* This file is part of GameQ.
*
* GameQ is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* GameQ is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* GameSpy4 Protocol Class
*
* By all accounts GameSpy 4 seems to be GameSpy 3.
*
* References:
* http://www.deletedscreen.com/?p=951
* http://pastebin.com/2zZFDuTd
*
* @author Austin Bischoff <austin@codebeard.com>
*/
class GameQ_Protocols_Gamespy4 extends GameQ_Protocols_Gamespy3 {}

View file

@ -0,0 +1,28 @@
<?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/>.
*/
/**
* Garry's Mod Protocol Class
*
* @author Austin Bischoff <austin@codebeard.com>
*/
class GameQ_Protocols_Gmod extends GameQ_Protocols_Source
{
protected $name = "gmod";
protected $name_long = "Garry's Mod";
}

View file

@ -0,0 +1,30 @@
<?php
/**
* This file is part of GameQ.
*
* GameQ is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* GameQ is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* Gore Protocol Class
*
* @author Austin Bischoff <austin@codebeard.com>
*/
class GameQ_Protocols_Gore extends GameQ_Protocols_Gamespy
{
protected $name = "gore";
protected $name_long = "Gore";
protected $port = 27778;
}

View file

@ -0,0 +1,30 @@
<?php
/**
* This file is part of GameQ.
*
* GameQ is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* GameQ is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* Ghost Recon: Advanced Warfighter Protocol Class
*
* @author Austin Bischoff <austin@codebeard.com>
*/
class GameQ_Protocols_Graw extends GameQ_Protocols_Gamespy2
{
protected $name = "graw";
protected $name_long = "Ghost Recon: Advanced Warfighter";
protected $port = 15250;
}

View file

@ -0,0 +1,30 @@
<?php
/**
* This file is part of GameQ.
*
* GameQ is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* GameQ is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* Ghost Recon: Advanced Warfighter 2 Protocol Class
*
* @author Austin Bischoff <austin@codebeard.com>
*/
class GameQ_Protocols_Graw2 extends GameQ_Protocols_Gamespy2
{
protected $name = "graw2";
protected $name_long = "Ghost Recon: Advanced Warfighter 2";
protected $port = 16250;
}

View file

@ -0,0 +1,28 @@
<?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/>.
*/
/**
* Half Life 2: Deathmatch Protocol Class
*
* @author Austin Bischoff <austin@codebeard.com>
*/
class GameQ_Protocols_Hl2dm extends GameQ_Protocols_Source
{
protected $name = "hl2dm";
protected $name_long = "Half Life 2: Deathmatch";
}

View file

@ -0,0 +1,28 @@
<?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/>.
*/
/**
* Half Life Deathmatch Protocol Class
*
* @author Austin Bischoff <austin@codebeard.com>
*/
class GameQ_Protocols_Hldm extends GameQ_Protocols_Source
{
protected $name = "hldm";
protected $name_long = "Half Life: Deathmatch";
}

View file

@ -0,0 +1,28 @@
<?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/>.
*/
/**
* Homefront Protocol Class
*
* @author Austin Bischoff <austin@codebeard.com>
*/
class GameQ_Protocols_Homefront extends GameQ_Protocols_Source
{
protected $name = "homefront";
protected $name_long = "Homefront";
}

View file

@ -0,0 +1,42 @@
<?php
/**
* This file is part of GameQ.
*
* GameQ is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* GameQ is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* Http Protocol Class
*
* Used for making actual http requests to servers for information
*
* @author Austin Bischoff <austin@codebeard.com>
*/
abstract class GameQ_Protocols_Http extends GameQ_Protocols
{
/**
* Set the transport to use TCP
*
* @var string
*/
protected $transport = self::TRANSPORT_TCP;
/**
* Default port for this server type
*
* @var int
*/
protected $port = 80; // Default port, used if not set when instanced
}

View file

@ -0,0 +1,28 @@
<?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/>.
*/
/**
* Insurgency Mod Protocol Class
*
* @author Austin Bischoff <austin@codebeard.com>
*/
class GameQ_Protocols_Insurgency extends GameQ_Protocols_Source
{
protected $name = "insurgency";
protected $name_long = "Insurgency";
}

View file

@ -0,0 +1,60 @@
<?php
/**
* This file is part of GameQ.
*
* GameQ is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* GameQ is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* Just Cause 2 Multiplayer Protocol Class
*
* Special thanks to Woet for some insight on packing
*
* @author Austin Bischoff <austin@codebeard.com>
*/
class GameQ_Protocols_Jc2 extends GameQ_Protocols_Gamespy4
{
protected $name = "jc2";
protected $name_long = "Just Cause 2 Multiplayer";
protected $port = 7777;
public function __construct($ip = FALSE, $port = FALSE, $options = array())
{
// Setup the parent first
parent::__construct($ip, $port, $options);
// Tweak the packet used
$this->packets[self::PACKET_ALL] = "\xFE\xFD\x00\x10\x20\x30\x40%s\xFF\xFF\xFF\x02";
}
/**
* Override the parent, this protocol is returned differently
*
* @see GameQ_Protocols_Gamespy3::parsePlayerTeamInfo()
*/
protected function parsePlayerTeamInfo(GameQ_Buffer &$buf, GameQ_Result &$result)
{
// First is the number of players, let's use this. Should have actual players, not connecting
$result->add('numplayers', $buf->readInt16BE());
// Loop until we run out of data
while($buf->getLength())
{
$result->addPlayer('name', $buf->readString());
$result->addPlayer('steamid', $buf->readString());
$result->addPlayer('ping', $buf->readInt16BE());
}
}
}

View file

@ -0,0 +1,78 @@
<?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/>.
*/
/**
* Killing floor Protocol Class
*
* @author Austin Bischoff <austin@codebeard.com>
*/
class GameQ_Protocols_Killingfloor extends GameQ_Protocols_Unreal2
{
protected $name = "killingfloor";
protected $name_long = "Killing Floor";
protected $port = 7708;
/**
* Overloaded for Killing Floor servername issue, could be all unreal2 games though
*
* @see GameQ_Protocols_Unreal2::process_details()
*/
protected function process_details()
{
// Make sure we have a valid response
if(!$this->hasValidResponse(self::PACKET_DETAILS))
{
return array();
}
// Set the result to a new result instance
$result = new GameQ_Result();
// Let's preprocess the rules
$data = $this->preProcess_details($this->packets_response[self::PACKET_DETAILS]);
// Create a buffer
$buf = new GameQ_Buffer($data);
$result->add('serverid', $buf->readInt32()); // 0
$result->add('serverip', $buf->readPascalString(1)); // empty
$result->add('gameport', $buf->readInt32());
$result->add('queryport', $buf->readInt32()); // 0
// We burn the first char since it is not always correct with the hostname
$buf->skip(1);
// Read as a regular string since the length is incorrect (what we skipped earlier)
$result->add('servername', $buf->readString());
// The rest is read as normal
$result->add('mapname', $buf->readPascalString(1));
$result->add('gametype', $buf->readPascalString(1));
$result->add('playercount', $buf->readInt32());
$result->add('maxplayers', $buf->readInt32());
$result->add('currentwave', $buf->readInt32());
// @todo: There is extra data after this point (~9 bytes), cant find any reference on what it is
unset($buf);
// Return the result
return $result->fetch();
}
}

View file

@ -0,0 +1,28 @@
<?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/>.
*/
/**
* Left 4 Dead Protocol Class
*
* @author Austin Bischoff <austin@codebeard.com>
*/
class GameQ_Protocols_L4d extends GameQ_Protocols_Source
{
protected $name = "l4d";
protected $name_long = "Left 4 Dead";
}

View file

@ -0,0 +1,28 @@
<?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/>.
*/
/**
* Left 4 Dead 2 Protocol Class
*
* @author Austin Bischoff <austin@codebeard.com>
*/
class GameQ_Protocols_L4d2 extends GameQ_Protocols_Source
{
protected $name = "l4d2";
protected $name_long = "Left 4 Dead 2";
}

View file

@ -0,0 +1,154 @@
<?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/>.
*/
/**
* Mafia 2 Multiplayer Protocol Class
*
* Loosely based on SAMP protocol
*
* Query port = server port + 1
*
* Thanks to rststeam for example protocol information
*
* @author Austin Bischoff <austin@codebeard.com>
*/
class GameQ_Protocols_M2mp extends GameQ_Protocols
{
/**
* Array of packets we want to look up.
* Each key should correspond to a defined method in this or a parent class
*
* @var array
*/
protected $packets = array(
self::PACKET_ALL => "M2MP",
);
/**
* Methods to be run when processing the response(s)
*
* @var array
*/
protected $process_methods = array(
"process_all",
);
/**
* Default port for this server type
*
* @var int
*/
protected $port = 27016; // Default port, used if not set when instanced
/**
* The protocol being used
*
* @var string
*/
protected $protocol = 'm2mp';
/**
* String name of this protocol class
*
* @var string
*/
protected $name = 'm2mp';
/**
* Longer string name of this protocol class
*
* @var string
*/
protected $name_long = "Mafia 2 Multiplayer";
/*
* Internal methods
*/
/**
* Pre-process the server details data that was returned.
*
* @param array $packets
*/
protected function preProcess($packets)
{
// Make buffer so we can check this out
$buf = new GameQ_Buffer(implode('', $packets));
// Grab the header
$header = $buf->read(4);
// Now lets verify the header
if($header != "M2MP")
{
throw new GameQ_ProtocolsException('Unable to match M2MP response header. Header: '. $header);
return FALSE;
}
// Return the data with the header stripped, ready to go.
return $buf->getBuffer();
}
/**
* Process the server details
*
* @throws GameQ_ProtocolsException
*/
protected function process_all()
{
// Make sure we have a valid response
if(!$this->hasValidResponse(self::PACKET_ALL))
{
return array();
}
// Set the result to a new result instance
$result = new GameQ_Result();
// Always dedicated
$result->add('dedicated', TRUE);
// Preprocess and make buffer
$buf = new GameQ_Buffer($this->preProcess($this->packets_response[self::PACKET_ALL]));
// Pull out the server information
// Note the length information is incorrect, we correct using offset options in pascal method
$result->add('servername', $buf->readPascalString(1, TRUE));
$result->add('num_players', $buf->readPascalString(1, TRUE));
$result->add('max_players', $buf->readPascalString(1, TRUE));
$result->add('gamemode', $buf->readPascalString(1, TRUE));
$result->add('password', (bool) $buf->readInt8());
// Read the player info, it's in the same query response for some odd reason.
while($buf->getLength())
{
// Check to see if we ran out of info, length bug from response
if($buf->getLength() <= 1)
{
break;
}
// Only player name information is available
$result->addPlayer('name', $buf->readPascalString(1, TRUE));
}
unset($buf);
return $result->fetch();
}
}

View file

@ -0,0 +1,43 @@
<?php
/**
* This file is part of GameQ.
*
* GameQ is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* GameQ is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* Mincraft Protocol Class
*
* Thanks to https://github.com/xPaw/PHP-Minecraft-Query for helping me realize this is
* Gamespy 3 Protocol. Make sure you enable the items below for it to work.
*
* Information from original author:
* Instructions
*
* Before using this class, you need to make sure that your server is running GS4 status listener.
*
* Look for those settings in server.properties:
*
* enable-query=true
* query.port=25565
*
* @author Austin Bischoff <austin@codebeard.com>
*/
class GameQ_Protocols_Minecraft extends GameQ_Protocols_Gamespy4
{
protected $name = "minecraft";
protected $name_long = "Minecraft";
protected $port = 25565;
}

View file

@ -0,0 +1,133 @@
<?php
/**
* This file is part of GameQ.
*
* GameQ is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* GameQ is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* Minequery Protocol Class
*
* This class is used as the basis for all game servers
* that use the Minequery protocol for querying
* server status.
*
* Make sure you have Minequery running. Check the GameQ github wiki for specifics.
*
* @author Austin Bischoff <austin@codebeard.com>
*/
class GameQ_Protocols_Minequery extends GameQ_Protocols
{
/**
* Array of packets we want to look up.
* Each key should correspond to a defined method in this or a parent class
*
* @var array
*/
protected $packets = array(
self::PACKET_STATUS => "QUERY_JSON\n",
);
/**
* Methods to be run when processing the response(s)
*
* @var array
*/
protected $process_methods = array(
"process_status",
);
/**
* Set the transport to use TCP
*
* @var string
*/
protected $transport = self::TRANSPORT_TCP;
/**
* Default port for this server type
*
* @var int
*/
protected $port = 25566; // Default port, used if not set when instanced
/**
* The protocol being used
*
* @var string
*/
protected $protocol = 'minequery';
/**
* String name of this protocol class
*
* @var string
*/
protected $name = 'minequery';
/**
* Longer string name of this protocol class
*
* @var string
*/
protected $name_long = "Minequery";
/*
* Internal methods
*/
/**
* Process the server status
*
* @throws GameQ_ProtocolsException
*/
protected function process_status()
{
// Make sure we have a valid response
if(!$this->hasValidResponse(self::PACKET_STATUS))
{
return array();
}
// The response should be a single string so just combine all the packets into a single string
$response = implode('', $this->packets_response[self::PACKET_STATUS]);
// Check to see if this is valid JSON.
if(($data = json_decode($response)) === NULL)
{
throw new GameQ_ProtocolsException('Unable to decode the JSON data for Minequery');
return FALSE;
}
// Set the result to a new result instance
$result = new GameQ_Result();
// Server is always dedicated
$result->add('dedicated', TRUE);
// Add the address and port info
$result->add('serverport', $data->serverPort);
$result->add('numplayers', $data->playerCount);
$result->add('maxplayers', $data->maxPlayers);
// Do the players
foreach($data->playerList AS $i => $name)
{
$result->addPlayer('name', $name);
}
return $result->fetch();
}
}

View file

@ -0,0 +1,30 @@
<?php
/**
* This file is part of GameQ.
*
* GameQ is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* GameQ is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* Medal of Honor: Allied Assault Protocol Class
*
* @author Marcel Bößendörfer <m.boessendoerfer@marbis.net>
*/
class GameQ_Protocols_Mohaa extends GameQ_Protocols_Gamespy
{
protected $name = "mohaa";
protected $name_long = "Medal of Honor: Allied Assault";
protected $port = 12300;
}

View file

@ -0,0 +1,30 @@
<?php
/**
* This file is part of GameQ.
*
* GameQ is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* GameQ is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* Medal of Honor: Spearhead Protocol Class
*
* @author Marcel Bößendörfer <m.boessendoerfer@marbis.net>
*/
class GameQ_Protocols_Mohsh extends GameQ_Protocols_Gamespy
{
protected $name = "mohsh";
protected $name_long = "Medal of Honor: Spearhead";
protected $port = 12300;
}

View file

@ -0,0 +1,131 @@
<?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/>.
*/
/**
* Medal of Honor Warfighter Protocol Class
*
* MOHWF is the same as BF3 minus some quirks in the status query hence the extension
*
* @author Austin Bischoff <austin@codebeard.com>
*/
class GameQ_Protocols_Mohwf extends GameQ_Protocols_Bf3
{
/**
* The protocol being used
*
* @var string
*/
protected $protocol = 'mohwf';
/**
* String name of this protocol class
*
* @var string
*/
protected $name = 'mohwf';
/**
* Longer string name of this protocol class
*
* @var string
*/
protected $name_long = "Medal of Honor Warfighter";
/*
* Internal Methods
*/
protected function process_status()
{
// Make sure we have a valid response
if(!$this->hasValidResponse(self::PACKET_STATUS))
{
return array();
}
// Make buffer for data
$buf = new GameQ_Buffer($this->preProcess_status($this->packets_response[self::PACKET_STATUS]));
$buf->skip(8); /* skip header */
// Decode the words into an array so we can use this data
$words = $this->decodeWords($buf);
// Make sure we got OK
if (!isset ($words[0]) || $words[0] != 'OK')
{
throw new GameQ_ProtocolsException('Packet Response was not OK! Buffer:'.$buf->getBuffer());
}
// Set the result to a new result instance
$result = new GameQ_Result();
// Server is always dedicated
$result->add('dedicated', TRUE);
// No mods, as of yet
$result->add('mod', FALSE);
// These are the same no matter what mode the server is in
$result->add('hostname', $words[1]);
$result->add('numplayers', $words[2]);
$result->add('maxplayers', $words[3]);
$result->add('gametype', $words[4]);
$result->add('map', $words[5]);
$result->add('roundsplayed', $words[6]);
$result->add('roundstotal', $words[7]);
// Figure out the number of teams
$num_teams = intval($words[8]);
// Set the current index
$index_current = 9;
// Loop for the number of teams found, increment along the way
for($id=1; $id<=$num_teams; $id++)
{
$result->addSub('teams', 'tickets', $words[$index_current]);
$result->addSub('teams', 'id', $id);
// Increment
$index_current++;
}
// Get and set the rest of the data points.
$result->add('targetscore', $words[$index_current]);
$result->add('online', TRUE); // Forced TRUE, it seems $words[$index_current + 1] is always empty
$result->add('ranked', $words[$index_current + 2] === 'true');
$result->add('punkbuster', $words[$index_current + 3] === 'true');
$result->add('password', $words[$index_current + 4] === 'true');
$result->add('uptime', $words[$index_current + 5]);
$result->add('roundtime', $words[$index_current + 6]);
// The next 3 are empty in MOHWF, kept incase they start to work some day
$result->add('ip_port', $words[$index_current + 7]);
$result->add('punkbuster_version', $words[$index_current + 8]);
$result->add('join_queue', $words[$index_current + 9] === 'true');
$result->add('region', $words[$index_current + 10]);
$result->add('pingsite', $words[$index_current + 11]);
$result->add('country', $words[$index_current + 12]);
unset($buf, $words);
return $result->fetch();
}
}

View file

@ -0,0 +1,30 @@
<?php
/**
* This file is part of GameQ.
*
* GameQ is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* GameQ is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* Multi Theft Auto Protocol Class
*
* @author Marcel Bößendörfer <m.boessendoerfer@marbis.net>
*/
class GameQ_Protocols_Mta extends GameQ_Protocols_ASE
{
protected $name = "mta";
protected $name_long = "Multi Theft Auto";
protected $port = 22126;
}

View file

@ -0,0 +1,196 @@
<?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/>.
*/
/**
* Mumble Protocol Class
*
* References:
* https://github.com/edmundask/MurmurQuery - Thanks to skylord123
*
* @author Austin Bischoff <austin@codebeard.com>
*/
class GameQ_Protocols_Mumble extends GameQ_Protocols
{
/**
* Normalization for this protocol class
*
* @var array
*/
protected $normalize = array(
// General
'general' => array(
'dedicated' => array('dedicated'),
'numplayers' => array(),
'maxplayers' => array('xgtmurmurmaxusers'),
'joinlink' => array('xconnecturl'),
'players' => array('players'),
'teams' => array('teams'),
),
// Player
'player' => array(
'ping' => array('tcpPing'),
'team' => array('channel'),
),
);
/**
* Array of packets we want to look up.
* Each key should correspond to a defined method in this or a parent class
*
* @var array
*/
protected $packets = array(
self::PACKET_ALL => "\x6A\x73\x6F\x6E", // JSON packet
);
/**
* Methods to be run when processing the response(s)
*
* @var array
*/
protected $process_methods = array(
"process_all",
);
/**
* Default port for this server type
*
* @var int
*/
protected $port = 27800; // Default port, used if not set when instanced
/**
* The protocol being used
*
* @var string
*/
protected $protocol = 'mumble';
/**
* String name of this protocol class
*
* @var string
*/
protected $name = 'mumble';
/**
* Longer string name of this protocol class
*
* @var string
*/
protected $name_long = "Mumble";
/**
* Transport protocol
*
* @var string
*/
protected $transport = self::TRANSPORT_TCP;
/*
* Internal methods
*/
public function preProcess_all($packets=array())
{
return implode('', $packets);
}
protected function process_all()
{
if(!$this->hasValidResponse(self::PACKET_ALL))
{
return array();
}
// Let's preprocess the status, JSON is the response
$json = $this->preProcess_all($this->packets_response[self::PACKET_ALL]);
// Try to json_decode, make it into an array
if(($data = json_decode($json, TRUE)) === NULL)
{
throw new GameQ_ProtocolsException("Unable to decode JSON data.");
}
// Set the result to a new result instance
$result = new GameQ_Result();
// Always dedicated
$result->add('dedicated', TRUE);
$result->add('maxplayers', 0);
$result->add('numplayers', 0);
// Let's iterate over the response items, there are alot
foreach($data AS $key => $value)
{
// Ignore root for now, that is where all of the channel/player info is housed
if(in_array($key, array('root')))
{
continue;
}
// Add them as is
$result->add($key, $value);
}
// Now let's parse the channel/user info
$this->process_channels_users($result, $data['root']);
return $result->fetch();
}
/**
* Process the channel and user information
*
* @param GameQ_Result $result
* @param array $item
*/
protected function process_channels_users(GameQ_Result &$result, $item)
{
// Let's add all of the channel information
foreach($item AS $key => $value)
{
// We will handle these later
if(in_array($key, array('channels', 'users')))
{
// skip
continue;
}
// Add the channel property as a team
$result->addTeam($key, $value);
}
// Itereate over the users in this channel
foreach($item['users'] AS $user)
{
foreach($user AS $key => $value)
{
$result->addPlayer($key, $value);
}
}
// Offload more channels to parse
foreach($item['channels'] AS $channel)
{
$this->process_channels_users($result, $channel);
}
}
}

View file

@ -0,0 +1,28 @@
<?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/>.
*/
/**
* Natural Selection Protocol Class
*
* @author Austin Bischoff <austin@codebeard.com>
*/
class GameQ_Protocols_Ns extends GameQ_Protocols_Source
{
protected $name = "ns";
protected $name_long = "Natural Selection";
}

View file

@ -0,0 +1,37 @@
<?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/>.
*/
/**
* Natural Selection 2 Protocol Class
*
* Note that the query port is the server connect port + 1
*
* @author Austin Bischoff <austin@codebeard.com>
*/
class GameQ_Protocols_Ns2 extends GameQ_Protocols_Source
{
protected $name = "ns2";
protected $name_long = "Natural Selection 2";
/**
* Default port for this server type
*
* @var int
*/
protected $port = 27016;
}

View file

@ -0,0 +1,205 @@
<?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/>.
*/
/**
* Quake 2 Protocol Class
*
* This class is used as the basis for all game servers
* that use the Quake 2 protocol for querying
* server status.
*
* @author Austin Bischoff <austin@codebeard.com>
*/
class GameQ_Protocols_Quake2 extends GameQ_Protocols
{
/**
* Array of packets we want to look up.
* Each key should correspond to a defined method in this or a parent class
*
* @var array
*/
protected $packets = array(
self::PACKET_STATUS => "\xFF\xFF\xFF\xFFstatus\x00",
);
/**
* Methods to be run when processing the response(s)
*
* @var array
*/
protected $process_methods = array(
"process_status",
);
/**
* Default port for this server type
*
* @var int
*/
protected $port = 27910; // Default port, used if not set when instanced
/**
* The protocol being used
*
* @var string
*/
protected $protocol = 'quake2';
/**
* String name of this protocol class
*
* @var string
*/
protected $name = 'quake2';
/**
* Longer string name of this protocol class
*
* @var string
*/
protected $name_long = "Quake 2";
/*
* Internal methods
*/
protected function preProcess_status($packets)
{
// Should only be one packet
if (count($packets) > 1)
{
throw new GameQ_ProtocolsException('Quake 2 status has more than 1 packet');
}
// Make buffer so we can check this out
$buf = new GameQ_Buffer($packets[0]);
// Grab the header
$header = $buf->read(11);
// Now lets verify the header
if($header != "\xFF\xFF\xFF\xFFprint\x0a\\")
{
throw new GameQ_ProtocolsException('Unable to match Gamespy 2 status response header. Header: '. $header);
return FALSE;
}
// Return the data with the header stripped, ready to go.
return $buf->getBuffer();
}
/**
* Process the server status
*
* @throws GameQ_ProtocolsException
*/
protected function process_status()
{
// Make sure we have a valid response
if(!$this->hasValidResponse(self::PACKET_STATUS))
{
return array();
}
// Set the result to a new result instance
$result = new GameQ_Result();
// Lets pre process and make sure these things are in the proper order by id
$data = $this->preProcess_status($this->packets_response[self::PACKET_STATUS]);
// Make buffer
$buf = new GameQ_Buffer($data);
// First section is the server info, the rest is player info
$server_info = $buf->readString("\x0A");
$player_info = $buf->getBuffer();
unset($buf);
// Make a new buffer for the server info
$buf_server = new GameQ_Buffer($server_info);
// Key / value pairs
while ($buf_server->getLength())
{
$result->add(
$buf_server->readString('\\'),
$buf_server->readStringMulti(array('\\', "\x0a"), $delimfound)
);
if ($delimfound === "\x0a")
{
break;
}
}
// Now send the rest to players
$this->parsePlayers($result, $player_info);
// Free some memory
unset($sections, $player_info, $server_info, $delimfound, $buf_server, $data);
// Return the result
return $result->fetch();
}
/**
* Parse the players and add them to the return.
*
* This is overloadable because it seems that different games return differen info.
*
* @param GameQ_Result $result
* @param string $players_info
*/
protected function parsePlayers(GameQ_Result &$result, $players_info)
{
// Explode the arrays out
$players = explode("\x0A", $players_info);
// Remove the last array item as it is junk
array_pop($players);
// Add total number of players
$result->add('num_players', count($players));
// Loop the players
foreach($players AS $player_info)
{
$buf = new GameQ_Buffer($player_info);
// Add player info
$result->addPlayer('frags', $buf->readString("\x20"));
$result->addPlayer('ping', $buf->readString("\x20"));
// Skip first "
$buf->skip(1);
// Add player name
$result->addPlayer('name', trim($buf->readString('"')));
// Skip first "
$buf->skip(2);
// Add address
$result->addPlayer('address', trim($buf->readString('"')));
}
// Free some memory
unset($buf, $players, $player_info);
}
}

View file

@ -0,0 +1,200 @@
<?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/>.
*/
/**
* Quake 3 Protocol Class
*
* This class is used as the basis for all game servers
* that use the Quake 3 protocol for querying
* server status.
*
* @author Austin Bischoff <austin@codebeard.com>
*/
class GameQ_Protocols_Quake3 extends GameQ_Protocols
{
/**
* Array of packets we want to look up.
* Each key should correspond to a defined method in this or a parent class
*
* @var array
*/
protected $packets = array(
self::PACKET_STATUS => "\xFF\xFF\xFF\xFF\x67\x65\x74\x73\x74\x61\x74\x75\x73\x0A",
//self::PACKET_DETAILS => "\xFF\xFF\xFF\xFFgetinfo\x00",
);
/**
* Methods to be run when processing the response(s)
*
* @var array
*/
protected $process_methods = array(
"process_status",
);
/**
* Default port for this server type
*
* @var int
*/
protected $port = 27960; // Default port, used if not set when instanced
/**
* The protocol being used
*
* @var string
*/
protected $protocol = 'quake3';
/**
* String name of this protocol class
*
* @var string
*/
protected $name = 'quake3';
/**
* Longer string name of this protocol class
*
* @var string
*/
protected $name_long = "Quake 3";
/*
* Internal methods
*/
protected function preProcess_status($packets)
{
// Should only be one packet
if (count($packets) > 1)
{
throw new GameQ_ProtocolsException('Quake 3 status has more than 1 packet');
}
// Make buffer so we can check this out
$buf = new GameQ_Buffer($packets[0]);
// Grab the header
$header = $buf->read(20);
// Now lets verify the header
if($header != "\xFF\xFF\xFF\xFFstatusResponse\x0A\x5C")
{
throw new GameQ_ProtocolsException('Unable to match Gamespy 3 challenge response header. Header: '. $header);
return FALSE;
}
// Return the data with the header stripped, ready to go.
return $buf->getBuffer();
}
/**
* Process the server status
*
* @throws GameQ_ProtocolsException
*/
protected function process_status()
{
// Make sure we have a valid response
if(!$this->hasValidResponse(self::PACKET_STATUS))
{
return array();
}
// Set the result to a new result instance
$result = new GameQ_Result();
// Lets pre process and make sure these things are in the proper order by id
$data = $this->preProcess_status($this->packets_response[self::PACKET_STATUS]);
// Make buffer
$buf = new GameQ_Buffer($data);
// First section is the server info, the rest is player info
$server_info = $buf->readString("\x0A");
$player_info = $buf->getBuffer();
unset($buf);
// Make a new buffer for the server info
$buf_server = new GameQ_Buffer($server_info);
// Key / value pairs
while ($buf_server->getLength())
{
$result->add(
$buf_server->readString('\\'),
$buf_server->readStringMulti(array('\\', "\x0a"), $delimfound)
);
if ($delimfound === "\x0a")
{
break;
}
}
// Now send the rest to players
$this->parsePlayers($result, $player_info);
// Free some memory
unset($sections, $player_info, $server_info, $delimfound, $buf_server, $data);
// Return the result
return $result->fetch();
}
/**
* Parse the players and add them to the return.
*
* This is overloadable because it seems that different games return differen info.
*
* @param GameQ_Result $result
* @param string $players_info
*/
protected function parsePlayers(GameQ_Result &$result, $players_info)
{
// Explode the arrays out
$players = explode("\x0A", $players_info);
// Remove the last array item as it is junk
array_pop($players);
// Add total number of players
$result->add('num_players', count($players));
// Loop the players
foreach($players AS $player_info)
{
$buf = new GameQ_Buffer($player_info);
// Add player info
$result->addPlayer('frags', $buf->readString("\x20"));
$result->addPlayer('ping', $buf->readString("\x20"));
// Skip first "
$buf->skip(1);
// Add player name
$result->addPlayer('name', trim($buf->readString('"')));
}
// Free some memory
unset($buf, $players, $player_info);
}
}

View file

@ -0,0 +1,44 @@
<?php
/**
* This file is part of GameQ.
*
* GameQ is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* GameQ is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* Quake 4 Protocol Class
*
* @author Austin Bischoff <austin@codebeard.com>
*/
class GameQ_Protocols_Quake4 extends GameQ_Protocols_Doom3
{
protected $name = "quake4";
protected $name_long = "Quake 4";
protected $port = 28004;
protected function parsePlayers(GameQ_Buffer &$buf, GameQ_Result &$result)
{
while (($id = $buf->readInt8()) != 32)
{
$result->addPlayer('id', $id);
$result->addPlayer('ping', $buf->readInt16());
$result->addPlayer('rate', $buf->readInt32());
$result->addPlayer('name', $buf->readString());
$result->addPlayer('clantag', $buf->readString());
}
return true;
}
}

View file

@ -0,0 +1,212 @@
<?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/>.
*/
/**
* Red Eclipse
*
* This game is based off of Cube 2 but the protocol response is way
* different than Cube 2
*
* Thanks to Poil for information to help build out this protocol class
*
* References:
* https://github.com/stainsby/redflare/blob/master/poller.js
* https://github.com/stainsby/redflare/blob/master/lib/protocol.js
*
* @author Austin Bischoff <austin@codebeard.com>
*/
class GameQ_Protocols_Redeclipse extends GameQ_Protocols_Cube2
{
/**
* The query protocol used to make the call
*
* @var string
*/
protected $protocol = 'redeclipse';
/**
* String name of this protocol class
*
* @var string
*/
protected $name = 'redeclipse';
/**
* Longer string name of this protocol class
*
* @var string
*/
protected $name_long = "Red Eclipse";
/**
* Defined Game mutators
*
* @var array
*/
protected $mutators = array(
'multi' => 1,
'ffa' => 2,
'coop' => 4,
'insta' => 8,
'medieval' => 16,
'kaboom' => 32,
'duel' => 64,
'survivor' => 128,
'classic' => 256,
'onslaught' => 512,
'jetpack' => 1024,
'vampire' => 2048,
'expert' => 4096,
'resize' => 8192,
);
/**
* Defined Master modes (i.e access restrictions)
*
* @var array
*/
protected $mastermodes = array(
'open', // 0
'veto', // 1
'locked', // 2
'private', // 3
'password', // 4
);
/**
* Defined Game modes
*
* @var array
*/
protected $gamemodes = array(
'demo', // 0
'edit', // 1
'deathmatch', // 2
'capture-the-flag', // 3
'defend-the-flag', // 4
'bomberball', // 5
'time-trial', // 6
'gauntlet' // 7
);
/**
* Process the status result. This result is different from the parent
*
* @see GameQ_Protocols_Cube2::process_status()
*/
protected function process_status()
{
// Make sure we have a valid response
if(!$this->hasValidResponse(self::PACKET_STATUS))
{
return array();
}
// Set the result to a new result instance
$result = new GameQ_Result();
// Let's preprocess the rules
$data = $this->preProcess_status($this->packets_response[self::PACKET_STATUS]);
// Create a new buffer
$buf = new GameQ_Buffer($data);
// Check the header, should be the same response as the packet we sent
if($buf->read(6) != $this->packets[self::PACKET_STATUS])
{
throw new GameQ_ProtocolsException("Data for ".__METHOD__." does not have the proper header type (should be {$this->packets[self::PACKET_STATUS]}).");
return array();
}
/**
* Reference chart for ints by position
*
* 0 - Num players
* 1 - Number of items to follow (i.e. 8), not used yet
* 2 - Version
* 3 - gamemode (dm, ctf, etc...)
* 4 - mutators (sum of power of 2)
* 5 - Time remaining
* 6 - max players
* 7 - Mastermode (open, password, etc)
* 8 - variable count
* 9 - modification count
*/
$result->add('num_players', $this->readInt($buf));
$items = $this->readInt($buf); // We dump this as we dont use it for now
$result->add('version', $this->readInt($buf));
$result->add('gamemode', $this->gamemodes[$this->readInt($buf)]);
// This is a sum of power's of 2 (2^1, 1 << 1)
$mutators_number = $this->readInt($buf);
$mutators = array();
foreach($this->mutators AS $mutator => $flag)
{
if($flag & $mutators_number)
{
$mutators[] = $mutator;
}
}
$result->add('mutators', $mutators);
$result->add('mutators_number', $mutators_number);
$result->add('time_remaining', $this->readInt($buf));
$result->add('max_players', $this->readInt($buf));
$mastermode = $this->readInt($buf);
$result->add('mastermode', $this->mastermodes[$mastermode]);
$result->add('password', ((in_array($mastermode, array(4)))?TRUE:FALSE));
// @todo: No idea what these next 2 are used for
$result->add('variableCount', $this->readInt($buf));
$result->add('modificationCount', $this->readInt($buf));
$result->add('map', $buf->readString());
$result->add('servername', $buf->readString());
// The rest from here is player information, we read until we run out of strings (\x00)
while($raw = $buf->readString())
{
// Items seem to be seperated by \xc
$items = explode("\xc", $raw);
// Indexes 0, 1 & 5 seem to be junk
// Indexes 2, 3, 4 seem to have something of use, not sure about #3
$result->addPlayer('guid', (int) trim($items[2], "[]"));
// Index 4 has the player name with some kind int added on to the front, icon or something?
// Anyway remove it for now...
if(preg_match('/(\[[0-9]+\])(.*)/i', $items[4], $name))
{
$result->addPlayer('name', $name[2]);
}
}
unset($buf, $data);
return $result->fetch();
}
}

View file

@ -0,0 +1,121 @@
<?php
/**
* This file is part of GameQ.
*
* GameQ is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* GameQ is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* Red Faction Protocol Class
*
* @author Austin Bischoff <austin@codebeard.com>
*/
class GameQ_Protocols_Redfaction extends GameQ_Protocols
{
/**
* Array of packets we want to look up.
* Each key should correspond to a defined method in this or a parent class
*
* @var array
*/
protected $packets = array(
self::PACKET_STATUS => "\x00\x00\x00\x00",
);
protected $state = self::STATE_TESTING;
/**
* Methods to be run when processing the response(s)
*
* @var array
*/
protected $process_methods = array(
"process_status",
);
/**
* Default port for this server type
*
* @var int
*/
protected $port = 7755; // Default port, used if not set when instanced
/**
* The protocol being used
*
* @var string
*/
protected $protocol = 'redfaction';
/**
* String name of this protocol class
*
* @var string
*/
protected $name = 'redfaction';
/**
* Longer string name of this protocol class
*
* @var string
*/
protected $name_long = "Red Faction";
/*
* Internal methods
*/
/**
* Process the server status
*
* @throws GameQ_ProtocolsException
*/
protected function process_status()
{
// Make sure we have a valid response
if(!$this->hasValidResponse(self::PACKET_STATUS))
{
return array();
}
// Set the result to a new result instance
$result = new GameQ_Result();
// Header, we're being carefull here
if ($buf->read() !== "\x00")
{
throw new GameQ_ProtocolsException('Header error in Red Faction');
return FALSE;
}
// Dunno
while ($buf->read() !== "\x00") {}
$buf->read();
// Data
$result->add('servername', $buf->readString());
$result->add('gametype', $buf->readInt8());
$result->add('num_players', $buf->readInt8());
$result->add('max_players', $buf->readInt8());
$result->add('map', $buf->readString());
$buf->read();
$result->add('dedicated', $buf->readInt8());
// Free some memory
unset($sections, $buf, $data);
// Return the result
return $result->fetch();
}
}

View file

@ -0,0 +1,30 @@
<?php
/**
* This file is part of GameQ.
*
* GameQ is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* GameQ is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* Red Orchestra: Ostfront 41-45 Protocol Class
*
* @author Austin Bischoff <austin@codebeard.com>
*/
class GameQ_Protocols_Redorchestra extends GameQ_Protocols_Gamespy
{
protected $name = "redorchestra";
protected $name_long = "Red Orchestra: Ostfront 41-45";
protected $port = 7767;
}

View file

@ -0,0 +1,32 @@
<?php
/**
* This file is part of GameQ.
*
* GameQ is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* GameQ is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* Red Orchestra 2 Protocol Class
*
* Thanks to http://forums.tripwireinteractive.com/showthread.php?t=72439 for information about the protocol
*
* @author Austin Bischoff <austin@codebeard.com>
*/
class GameQ_Protocols_Redorchestra2 extends GameQ_Protocols_Source
{
protected $name = "redorchestra2";
protected $name_long = "Red Orchestra 2";
protected $port = 27015;
}

View file

@ -0,0 +1,30 @@
<?php
/**
* This file is part of GameQ.
*
* GameQ is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* GameQ is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* Return to Castle Wolfenstein Protocol Class
*
* @author Austin Bischoff <austin@codebeard.com>
*/
class GameQ_Protocols_Rtcw extends GameQ_Protocols_Quake3
{
protected $name = "rtcw";
protected $name_long = "Return to Castle Wolfenstein";
protected $port = 27960;
}

View file

@ -0,0 +1,46 @@
<?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/>.
*/
/**
* Rust Protocol Class
*
* Seems to respond to A2S but no rules, unsure if players is complete
*
* @author Austin Bischoff <austin@codebeard.com>
*/
class GameQ_Protocols_Rust extends GameQ_Protocols_Source
{
protected $name = "rust";
protected $name_long = "Rust";
/**
* Overload for client port
*
* @param string $ip
* @param integer $port
* @param array $options
*/
public function __construct($ip = FALSE, $port = FALSE, $options = array())
{
// Got to do this first
parent::__construct($ip, $port, $options);
// Correct the client port since query_port = client_port + 1
$this->port(($this->port() - 1));
}
}

View file

@ -0,0 +1,239 @@
<?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/>.
*/
/**
* San Andreas Multiplayer Protocol Class
*
* This class holds the query info and processing for SAMP
*
* @author Austin Bischoff <austin@codebeard.com>
*/
class GameQ_Protocols_Samp extends GameQ_Protocols
{
/**
* Array of packets we want to look up.
* Each key should correspond to a defined method in this or a parent class
*
* @var array
*/
protected $packets = array(
self::PACKET_STATUS => "SAMP%s%si",
self::PACKET_PLAYERS => "SAMP%s%sd",
self::PACKET_RULES => "SAMP%s%sr",
);
/**
* Methods to be run when processing the response(s)
*
* @var array
*/
protected $process_methods = array(
"process_status",
"process_players",
"process_rules",
);
/**
* Default port for this server type
*
* @var int
*/
protected $port = 7777; // Default port, used if not set when instanced
/**
* The protocol being used
*
* @var string
*/
protected $protocol = 'samp';
/**
* String name of this protocol class
*
* @var string
*/
protected $name = 'samp';
/**
* Longer string name of this protocol class
*
* @var string
*/
protected $name_long = "San Andreas Multiplayer";
/*
* Internal methods
*/
/**
* We need to modify the packets before they are sent for this protocol
*
* @see GameQ_Protocols_Core::beforeSend()
*/
public function beforeSend()
{
// We need to repack the IP address of the server
$address = implode('', array_map('chr', explode('.', $this->ip)));
// Repack the server port
$port = pack ("S", $this->port);
// Let's loop the packets and set the proper pieces
foreach($this->packets AS $packet_type => $packet)
{
// Fill out the packet with the server info
$this->packets[$packet_type] = sprintf($packet, $address, $port);
}
// Free up some memory
unset($address, $port);
return TRUE;
}
protected function preProcess($packets)
{
// Make buffer so we can check this out
$buf = new GameQ_Buffer(implode('', $packets));
// Grab the header
$header = $buf->read(11);
// Now lets verify the header
if(substr($header, 0, 4) != "SAMP")
{
throw new GameQ_ProtocolsException('Unable to match SAMP response header. Header: '. $header);
return FALSE;
}
// Return the data with the header stripped, ready to go.
return $buf->getBuffer();
}
/**
* Process the server status
*
* @throws GameQ_ProtocolsException
*/
protected function process_status()
{
// Make sure we have a valid response
if(!$this->hasValidResponse(self::PACKET_STATUS))
{
return array();
}
// Set the result to a new result instance
$result = new GameQ_Result();
// Always dedicated
$result->add('dedicated', TRUE);
// Preprocess and make buffer
$buf = new GameQ_Buffer($this->preProcess($this->packets_response[self::PACKET_STATUS]));
// Pull out the server information
$result->add('password', (bool) $buf->readInt8());
$result->add('num_players', $buf->readInt16());
$result->add('max_players', $buf->readInt16());
// These are read differently for these last 3
$result->add('servername', $buf->read($buf->readInt32()));
$result->add('gametype', $buf->read($buf->readInt32()));
$result->add('map', $buf->read($buf->readInt32()));
// Free some memory
unset($buf);
// Return the result
return $result->fetch();
}
/**
* Process server rules
*/
protected function process_rules()
{
// Make sure we have a valid response
if(!$this->hasValidResponse(self::PACKET_RULES))
{
return array();
}
// Set the result to a new result instance
$result = new GameQ_Result();
// Preprocess and make buffer
$buf = new GameQ_Buffer($this->preProcess($this->packets_response[self::PACKET_RULES]));
// Number of rules
$result->add('num_rules', $buf->readInt16());
// Run until we run out of buffer
while ($buf->getLength())
{
$result->add($buf->readPascalString(), $buf->readPascalString());
}
// Free some memory
unset($buf);
// Return the result
return $result->fetch();
}
/**
* Process the players
*
* NOTE: There is a restriction on the SAMP server side that if there are too many players
* the player return will be empty. Nothing can really be done about this unless you bug
* the game developers to fix it.
*/
protected function process_players()
{
// Make sure we have a valid response
if(!$this->hasValidResponse(self::PACKET_PLAYERS))
{
return array();
}
// Set the result to a new result instance
$result = new GameQ_Result();
// Preprocess and make buffer
$buf = new GameQ_Buffer($this->preProcess($this->packets_response[self::PACKET_PLAYERS]));
// Number of players
$result->add('num_players', $buf->readInt16());
// Run until we run out of buffer
while ($buf->getLength())
{
$result->addPlayer('id', $buf->readInt8());
$result->addPlayer('name', $buf->readPascalString());
$result->addPlayer('score', $buf->readInt32());
$result->addPlayer('ping', $buf->readInt32());
}
// Free some memory
unset($buf);
// Return the result
return $result->fetch();
}
}

View file

@ -0,0 +1,97 @@
<?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/>.
*/
/**
* The Ship Protocol Class
*
* @author Nikolay Ipanyuk <rostov114@gmail.com>
* @author Austin Bischoff <austin@codebeard.com>
*/
class GameQ_Protocols_Ship extends GameQ_Protocols_Source
{
protected $name = "ship";
protected $name_long = "The Ship";
/**
* Special player parse for The Ship
*
* @return array|mixed
* @throws \GameQ_ProtocolsException
*/
protected function process_players()
{
// Make sure we have a valid response
if (!$this->hasValidResponse(self::PACKET_PLAYERS)) {
return [ ];
}
// Set the result to a new result instance
$result = new GameQ_Result();
// Let's preprocess the rules
$data = $this->preProcess_players($this->packets_response[self::PACKET_PLAYERS]);
// Create a new buffer
$buf = new GameQ_Buffer($data);
// Make sure the data is formatted properly
if (($header = $buf->read(5)) != "\xFF\xFF\xFF\xFF\x44") {
throw new GameQ_ProtocolsException("Data for " . __METHOD__
. " does not have the proper header (should be 0xFF0xFF0xFF0xFF0x44). Header: "
. bin2hex($header));
return [ ];
}
// Pull out the number of players
$num_players = $buf->readInt8();
// Player count
$result->add('num_players', $num_players);
// No players so no need to look any further
if ($num_players == 0) {
return $result->fetch();
}
// Players list
for ($player = 0; $player < $num_players; $player++)
{
$result->addPlayer('id', $buf->readInt8());
$result->addPlayer('name', $buf->readString());
$result->addPlayer('score', $buf->readInt32Signed());
$result->addPlayer('time', $buf->readFloat32());
}
// Addotional player info
if ($buf->getLength() > 0)
{
for ($player = 0; $player < $num_players; $player++)
{
$result->addPlayer('deaths', $buf->readInt32Signed());
$result->addPlayer('money', $buf->readInt32Signed());
}
}
unset($buf);
return $result->fetch();
}
}

View file

@ -0,0 +1,30 @@
<?php
/**
* This file is part of GameQ.
*
* GameQ is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* GameQ is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* Soldier of Fortune 2 Protocol Class
*
* @author Austin Bischoff <austin@codebeard.com>
*/
class GameQ_Protocols_Sof2 extends GameQ_Protocols_Quake3
{
protected $name = "sof2";
protected $name_long = "Soldier of Fortune 2";
protected $port = 20100;
}

View file

@ -0,0 +1,30 @@
<?php
/**
* This file is part of GameQ.
*
* GameQ is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* GameQ is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* Soldat Protocol Class
*
* @author Marcel Bößendörfer <m.boessendoerfer@marbis.net>
*/
class GameQ_Protocols_Soldat extends GameQ_Protocols_ASE
{
protected $name = "soldat";
protected $name_long = "Soldat";
protected $port = 23196;
}

View file

@ -0,0 +1,497 @@
<?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/>.
*/
/**
* Valve Source Engine Protocol Class
*
* This class is used as the basis for all other source based servers
* that rely on the source protocol for game querying
*
* @author Austin Bischoff <austin@codebeard.com>
*/
class GameQ_Protocols_Source extends GameQ_Protocols
{
/*
* Source engine type constants
*/
const SOURCE_ENGINE = 0;
const GOLDSOURCE_ENGINE = 1;
/**
* Array of packets we want to look up.
* Each key should correspond to a defined method in this or a parent class
*
* @var array
*/
protected $packets = [
self::PACKET_CHALLENGE => "\xFF\xFF\xFF\xFF\x56\x00\x00\x00\x00",
self::PACKET_DETAILS => "\xFF\xFF\xFF\xFFTSource Engine Query\x00",
self::PACKET_PLAYERS => "\xFF\xFF\xFF\xFF\x55%s",
self::PACKET_RULES => "\xFF\xFF\xFF\xFF\x56%s",
];
/**
* Methods to be run when processing the response(s)
*
* @var array
*/
protected $process_methods = [
"process_details",
"process_players",
"process_rules",
];
/**
* Default port for this server type
*
* @var int
*/
protected $port = 27015; // Default port, used if not set when instanced
/**
* The query protocol used to make the call
*
* @var string
*/
protected $protocol = 'source';
/**
* String name of this protocol class
*
* @var string
*/
protected $name = 'source';
/**
* Longer string name of this protocol class
*
* @var string
*/
protected $name_long = "Source Server";
/**
* Define the Source engine type. By default it is assumed to be Source
*
* @var int
*/
protected $source_engine = self::SOURCE_ENGINE;
protected $join_link = "steam://connect/%s:%d/";
/**
* Parse the challenge response and apply it to all the packet types
* that require it.
*
* @see GameQ_Protocols_Core::parseChallengeAndApply()
*/
protected function parseChallengeAndApply()
{
// Skip the header
$this->challenge_buffer->skip(5);
// Apply the challenge and return
return $this->challengeApply($this->challenge_buffer->read(4));
}
/*
* Internal methods
*/
/**
* Pre-process the server details data that was returned.
*
* @param array $packets
*/
protected function preProcess_details($packets)
{
// Process the packets
return $this->process_packets($packets);
}
/**
* Handles processing the details data into a usable format
*
* @throws GameQ_ProtocolsException
*/
protected function process_details()
{
// Make sure we have a valid response
if (!$this->hasValidResponse(self::PACKET_DETAILS)) {
return [ ];
}
// Set the result to a new result instance
$result = new GameQ_Result();
// Let's preprocess the rules
$data = $this->preProcess_details($this->packets_response[self::PACKET_DETAILS]);
// Create a new buffer
$buf = new GameQ_Buffer($data);
// Skip the header (0xFF0xFF0xFF0xFF)
$buf->skip(4);
// Get the type
$type = $buf->read(1);
// Make sure the data is formatted properly
// Source is 0x49, Goldsource is 0x6d, 0x44 I am not sure about
if (!in_array($type, [ "\x49", "\x44", "\x6d" ])) {
throw new GameQ_ProtocolsException("Data for " . __METHOD__
. " does not have the proper header type (should be 0x49|0x44|0x6d). Header type: 0x"
. bin2hex($type));
return [ ];
}
// Update the engine type for other calls and other methods, if necessary
if (bin2hex($type) == '6d') {
$this->source_engine = self::GOLDSOURCE_ENGINE;
}
// Check engine type
if ($this->source_engine == self::GOLDSOURCE_ENGINE) {
$result->add('address', $buf->readString());
} else {
$result->add('protocol', $buf->readInt8());
}
$result->add('hostname', $buf->readString());
$result->add('map', $buf->readString());
$result->add('game_dir', $buf->readString());
$result->add('game_descr', $buf->readString());
// Check engine type
if ($this->source_engine != self::GOLDSOURCE_ENGINE) {
$result->add('steamappid', $buf->readInt16());
}
$result->add('num_players', $buf->readInt8());
$result->add('max_players', $buf->readInt8());
// Check engine type
if ($this->source_engine == self::GOLDSOURCE_ENGINE) {
$result->add('version', $buf->readInt8());
} else {
$result->add('num_bots', $buf->readInt8());
}
$result->add('dedicated', $buf->read());
$result->add('os', $buf->read());
$result->add('password', $buf->readInt8());
// Check engine type
if ($this->source_engine == self::GOLDSOURCE_ENGINE) {
$result->add('ismod', $buf->readInt8());
if ($result->get('ismod')) {
$result->add('mod_urlinfo', $buf->readString());
$result->add('mod_urldl', $buf->readString());
$buf->skip();
$result->add('mod_version', $buf->readInt32Signed());
$result->add('mod_size', $buf->readInt32Signed());
$result->add('mod_type', $buf->readInt8());
$result->add('mod_cldll', $buf->readInt8());
}
}
$result->add('secure', $buf->readInt8());
if ($this->source_engine == self::SOURCE_ENGINE) {
if ($result->get('steamappid') == 2400) {
$result->add('game_mode', $buf->readInt8());
$result->add('witness_count', $buf->readInt8());
$result->add('witness_time', $buf->readInt8());
}
}
// Check engine type
if ($this->source_engine == self::GOLDSOURCE_ENGINE) {
$result->add('num_bots', $buf->readInt8());
} else {
$result->add('version', $buf->readString());
}
// Extra data flag
if ($buf->lookAhead(1) !== false) {
// Extra data flag
$edf = $buf->readInt8();
if ($edf & 0x80) {
$result->add('port', $buf->readInt16Signed());
}
if ($edf & 0x10) {
$a = $buf->readInt32();
$b = $buf->readInt32();
$result->add('steam_id', ($b << 32) | $a);
unset($a, $b);
}
if ($edf & 0x40) {
$result->add('sourcetv_port', $buf->readInt16Signed());
$result->add('sourcetv_name', $buf->readString());
}
if ($edf & 0x20) {
$result->add('keywords', $buf->readString());
}
if ($edf & 0x01) {
$a = $buf->readInt32();
$b = $buf->readInt32();
$result->add('game_id', ($b << 32) | $a);
unset($a, $b);
}
unset($edf);
}
unset($buf);
return $result->fetch();
}
/**
* Pre-process the player data sent
*
* @param array $packets
*/
protected function preProcess_players($packets)
{
// Process the packets
return $this->process_packets($packets);
}
/**
* Handles processing the player data into a useable format
*
* @throws GameQ_ProtocolsException
*/
protected function process_players()
{
// Make sure we have a valid response
if (!$this->hasValidResponse(self::PACKET_PLAYERS)) {
return [ ];
}
// Set the result to a new result instance
$result = new GameQ_Result();
// Let's preprocess the rules
$data = $this->preProcess_players($this->packets_response[self::PACKET_PLAYERS]);
// Create a new buffer
$buf = new GameQ_Buffer($data);
// Make sure the data is formatted properly
if (($header = $buf->read(5)) != "\xFF\xFF\xFF\xFF\x44") {
throw new GameQ_ProtocolsException("Data for " . __METHOD__
. " does not have the proper header (should be 0xFF0xFF0xFF0xFF0x44). Header: "
. bin2hex($header));
return [ ];
}
// Pull out the number of players
$num_players = $buf->readInt8();
// Player count
$result->add('num_players', $num_players);
// No players so no need to look any further
if ($num_players == 0) {
return $result->fetch();
}
// Players list
while ($buf->getLength()) {
$result->addPlayer('id', $buf->readInt8());
$result->addPlayer('name', $buf->readString());
$result->addPlayer('score', $buf->readInt32Signed());
$result->addPlayer('time', $buf->readFloat32());
}
unset($buf);
return $result->fetch();
}
/**
* Pre process the rules data that was returned. Make sure the return
* data is in a single string
*
* @param array $packets
*/
protected function preProcess_rules($packets)
{
// Process the packets
return $this->process_packets($packets);
}
/**
* Handles processing the rules data into a usable format
*
* @throws GameQ_ProtocolsException
*/
protected function process_rules()
{
// Make sure we have a valid response
if (!$this->hasValidResponse(self::PACKET_RULES)) {
return [ ];
}
// Set the result to a new result instance
$result = new GameQ_Result();
// Let's preprocess the rules
$data = $this->preProcess_rules($this->packets_response[self::PACKET_RULES]);
$buf = new GameQ_Buffer($data);
// Make sure the data is formatted properly
if (($header = $buf->read(5)) != "\xFF\xFF\xFF\xFF\x45") {
throw new GameQ_ProtocolsException("Data for " . __METHOD__
. " does not have the proper header (should be 0xFF0xFF0xFF0xFF0x45). Header: "
. bin2hex($header));
return [ ];
}
// Count the number of rules
$num_rules = $buf->readInt16Signed();
// Add the count of the number of rules this server has
$result->add('num_rules', $num_rules);
// Rules
while ($buf->getLength()) {
$result->add($buf->readString(), $buf->readString());
}
unset($buf);
return $result->fetch();
}
/**
* Process the packets to make sure we combine and decompress as needed
*
* @param array $packets
*
* @throws GameQ_ProtocolsException
* @return string
*/
protected function process_packets($packets)
{
// Make a buffer to see if we should have multiple packets
$buffer = new GameQ_Buffer($packets[0]);
// First we need to see if the packet is split
// -2 = split packets
// -1 = single packet
$packet_type = $buffer->readInt32Signed();
// This is one packet so just return the rest of the buffer
if ($packet_type == -1) {
// Free some memory
unset($buffer);
// We always return the packet as expected, with null included
return $packets[0];
}
// Free some memory
unset($buffer);
// Init array so we can order
$packs = [ ];
// We have multiple packets so we need to get them and order them
foreach ($packets AS $packet) {
// Make a buffer so we can read this info
$buffer = new GameQ_Buffer($packet);
// Pull some info
$packet_type = $buffer->readInt32Signed();
$request_id = $buffer->readInt32Signed();
// Check to see if this is compressed
if ($request_id & 0x80000000) {
// Check to see if we have Bzip2 installed
if (!function_exists('bzdecompress')) {
throw new GameQ_ProtocolsException('Bzip2 is not installed. See http://www.php.net/manual/en/book.bzip2.php for more info.',
0);
return false;
}
// Get some info
$num_packets = $buffer->readInt8();
$cur_packet = $buffer->readInt8();
$packet_length = $buffer->readInt32();
$packet_checksum = $buffer->readInt32();
// Try to decompress
$result = bzdecompress($buffer->getBuffer());
// Now verify the length
if (strlen($result) != $packet_length) {
throw new GameQ_ProtocolsException("Checksum for compressed packet failed! Length expected: {$packet_length}, length returned: "
. strlen($result));
}
// Set the new packs
$packs[$cur_packet] = $result;
} else // Normal packet
{
// Gold source does things a bit different
if ($this->source_engine == self::GOLDSOURCE_ENGINE) {
$packet_number = $buffer->readInt8();
} else // New source
{
$packet_number = $buffer->readInt16Signed();
$split_length = $buffer->readInt16Signed();
}
// Now add the rest of the packet to the new array with the packet_number as the id so we can order it
$packs[$packet_number] = $buffer->getBuffer();
}
unset($buffer);
}
// Free some memory
unset($packets, $packet);
// Sort the packets by packet number
ksort($packs);
// Now combine the packs into one and return
return implode("", $packs);
}
}

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