diff --git a/third_party/gameq/GameQ/Buffer.php b/third_party/gameq/GameQ/Buffer.php
index e9e1552d..ca23eb6d 100644
--- a/third_party/gameq/GameQ/Buffer.php
+++ b/third_party/gameq/GameQ/Buffer.php
@@ -276,8 +276,8 @@ class Buffer
// Get position of delimiters
$pos = [];
foreach ($delims as $delim) {
- if ($p = strpos($this->data, $delim, min($this->index, $this->length))) {
- $pos[] = $p;
+ if ($index = strpos($this->data, $delim, min($this->index, $this->length))) {
+ $pos[] = $index;
}
}
diff --git a/third_party/gameq/GameQ/Filters/Secondstohuman.php b/third_party/gameq/GameQ/Filters/Secondstohuman.php
index 5de72693..1b413f74 100644
--- a/third_party/gameq/GameQ/Filters/Secondstohuman.php
+++ b/third_party/gameq/GameQ/Filters/Secondstohuman.php
@@ -104,6 +104,8 @@ class Secondstohuman extends Base
// Iterate and update the result
$result[$key] = $this->iterate($value);
} elseif (in_array($key, $this->options[self::OPTION_TIMEKEYS])) {
+ // Make sure the value is a float (throws E_WARNING in PHP 7.1+)
+ $value = floatval($value);
// We match one of the keys we are wanting to convert so add it and move on
$result[sprintf(self::RESULT_KEY, $key)] = sprintf(
"%02d:%02d:%02d",
diff --git a/third_party/gameq/GameQ/Filters/Stripcolors.php b/third_party/gameq/GameQ/Filters/Stripcolors.php
index 635061c8..58953042 100644
--- a/third_party/gameq/GameQ/Filters/Stripcolors.php
+++ b/third_party/gameq/GameQ/Filters/Stripcolors.php
@@ -33,6 +33,8 @@ class Stripcolors extends Base
/**
* Apply this filter
*
+ * @SuppressWarnings(PHPMD.CyclomaticComplexity)
+ *
* @param array $result
* @param \GameQ\Server $server
*
@@ -62,6 +64,9 @@ class Stripcolors extends Base
case 'gamespy2':
array_walk_recursive($result, [$this, 'stripUnreal']);
break;
+ case 'source':
+ array_walk_recursive($result, [$this, 'stripSource']);
+ break;
}
/*$data['filtered'][ $server->id() ] = $result;
@@ -97,4 +102,14 @@ class Stripcolors extends Base
{
$string = preg_replace('/\x1b.../', '', $string);
}
+
+ /**
+ * Strip color codes from Source based games
+ *
+ * @param string $string
+ */
+ protected function stripSource(&$string)
+ {
+ $string = strip_tags($string);
+ }
}
diff --git a/third_party/gameq/GameQ/GameQ.php b/third_party/gameq/GameQ/GameQ.php
index b0a8b60e..fdc8ef70 100644
--- a/third_party/gameq/GameQ/GameQ.php
+++ b/third_party/gameq/GameQ/GameQ.php
@@ -15,6 +15,7 @@
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*/
+
namespace GameQ;
use GameQ\Exception\Protocol as ProtocolException;
@@ -43,6 +44,7 @@ class GameQ
/*
* Constants
*/
+ const PROTOCOLS_DIRECTORY = __DIR__ . '/Protocols';
/* Static Section */
@@ -408,10 +410,10 @@ class GameQ
'server_id' => $server_id,
'socket' => $socket,
];
- } catch (QueryException $e) {
+ } catch (QueryException $exception) {
// Check to see if we are in debug, if so bubble up the exception
if ($this->debug) {
- throw new \Exception($e->getMessage(), $e->getCode(), $e);
+ throw new \Exception($exception->getMessage(), $exception->getCode(), $exception);
}
}
@@ -509,13 +511,13 @@ class GameQ
'server_id' => $server_id,
'socket' => $socket,
];
- } catch (QueryException $e) {
+ } catch (QueryException $exception) {
// Check to see if we are in debug, if so bubble up the exception
if ($this->debug) {
- throw new \Exception($e->getMessage(), $e->getCode(), $e);
+ throw new \Exception($exception->getMessage(), $exception->getCode(), $exception);
}
- break;
+ continue;
}
// Clean up the sockets, if any left over
@@ -636,7 +638,7 @@ class GameQ
// Apply the filter to the data
$results = $filter->apply($results, $server);
- } catch (\ReflectionException $e) {
+ } catch (\ReflectionException $exception) {
// Invalid, skip it
continue;
}
diff --git a/third_party/gameq/GameQ/Protocols/Aoc.php b/third_party/gameq/GameQ/Protocols/Arma.php
similarity index 85%
rename from third_party/gameq/GameQ/Protocols/Aoc.php
rename to third_party/gameq/GameQ/Protocols/Arma.php
index 581c52c2..2653872f 100644
--- a/third_party/gameq/GameQ/Protocols/Aoc.php
+++ b/third_party/gameq/GameQ/Protocols/Arma.php
@@ -19,24 +19,25 @@
namespace GameQ\Protocols;
/**
- * Class Aoc
+ * Class Arma
*
* @package GameQ\Protocols
- * @author Austin Bischoff
+ *
+ * @author Wilson Jesus <>
*/
-class Aoc extends Source
+class Arma extends Gamespy2
{
/**
* String name of this protocol class
*
* @type string
*/
- protected $name = 'aoc';
+ protected $name = 'arma';
/**
* Longer string name of this protocol class
*
* @type string
*/
- protected $name_long = "Age of Chivalry";
+ protected $name_long = "ArmA Armed Assault";
}
diff --git a/third_party/gameq/GameQ/Protocols/Arma3.php b/third_party/gameq/GameQ/Protocols/Arma3.php
index 99ff9544..51d6e5da 100644
--- a/third_party/gameq/GameQ/Protocols/Arma3.php
+++ b/third_party/gameq/GameQ/Protocols/Arma3.php
@@ -1,4 +1,5 @@
* @author Austin Bischoff
- * @author Memphis017
*/
-class Arma3 extends Source
+class Arma3 extends Armedassault2oa
{
- /**
- * Defines the names for the specific game DLCs
- *
- * @var array
- */
- protected $dlcNames = [
- 'Karts',
- 'Marksmen',
- 'Helicopters',
- 'Apex',
- 'Jets',
- 'Laws of War',
- 'Tac-Ops',
- 'Tanks',
- ];
/**
* String name of this protocol class
@@ -61,127 +42,4 @@ class Arma3 extends Source
* @type string
*/
protected $name_long = "Arma3";
-
- /**
- * Query port = client_port + 1
- *
- * @type int
- */
- protected $port_diff = 1;
-
- /**
- * Process the rules since Arma3 changed their response for rules
- *
- * @param Buffer $buffer
- *
- * @return array
- * @throws \GameQ\Exception\Protocol
- */
- protected function processRules(Buffer $buffer)
- {
- // Total number of packets, burn it
- $buffer->readInt16();
-
- // Will hold the data string
- $data = '';
-
- // Loop until we run out of strings
- while ($buffer->getLength()) {
- // Burn the delimiters (i.e. \x01\x04\x00)
- $buffer->readString();
-
- // Add the data to the string, we are reassembling it
- $data .= $buffer->readString();
- }
-
- // Restore escaped sequences
- $data = str_replace(["\x01\x01", "\x01\x02", "\x01\x03"], ["\x01", "\x00", "\xFF"], $data);
-
- // Make a new buffer with the reassembled data
- $responseBuffer = new Buffer($data);
-
- // Kill the old buffer, should be empty
- unset($buffer, $data);
-
- // Set the result to a new result instance
- $result = new Result();
-
- // Get results
- $result->add('rules_protocol_version', $responseBuffer->readInt8());
- $result->add('overflow', $responseBuffer->readInt8());
- $dlcBit = $responseBuffer->readInt8(); // Grab DLC bit and use it later
- $responseBuffer->skip(); // Reserved, burn it
- // Grab difficulty so we can man handle it...
- $difficulty = $responseBuffer->readInt8();
-
- // Process difficulty
- $result->add('3rd_person', $difficulty >> 7);
- $result->add('advanced_flight_mode', ($difficulty >> 6) & 1);
- $result->add('difficulty_ai', ($difficulty >> 3) & 3);
- $result->add('difficulty_level', $difficulty & 3);
-
- unset($difficulty);
-
- // Crosshair
- $result->add('crosshair', $responseBuffer->readInt8());
-
- /*
- * Due to a bug in the DLC byte response from the ARMA servers we end here until the DLC byte bug can be fixed
- * or can code around the issue.
- * See https://github.com/Austinb/GameQ/issues/420
- */
- unset($dlcBit);
- return $result->fetch();
-
- //$dlcBit = 255;
-
- /*// Loop over the DLC bit so we can pull in the infor for the DLC (if enabled)
- for ($x = 0; $x < 8; $x++) {
- if (($dlcBit >> $x) & 1) {
- $result->addSub('dlcs', 'name', $this->dlcNames[$x]);
- $result->addSub('dlcs', 'hash', dechex($responseBuffer->readInt32()));
- }
- }
-
- // No longer needed
- unset($dlcBit);
-
- // Grab the mod count
- $modCount = $responseBuffer->readInt8();
-
- // Add mod count
- $result->add('mod_count', $modCount);
-
- // Loop the mod count and add them
- for ($x = 0; $x < $modCount; $x++) {
- // Add the mod to the list
- $result->addSub('mods', 'hash', dechex($responseBuffer->readInt32()));
- $result->addSub('mods', 'steam_id', hexdec($responseBuffer->readPascalString(0, true)));
- $result->addSub('mods', 'name', $responseBuffer->readPascalString(0, true));
- }
-
- unset($modCount, $x);
-
- // Burn the signatures count, we will just loop until we run out of strings
- $responseBuffer->read();
-
- // Make signatures array
- $signatures = [];
-
- // Loop until we run out of strings
- while ($responseBuffer->getLength()) {
- //$result->addSub('signatures', 0, $responseBuffer->readPascalString(0, true));
- $signatures[] = $responseBuffer->readPascalString(0, true);
- }
-
- // Add as a simple array
- $result->add('signatures', $signatures);
-
- // Add signatures count
- $result->add('signature_count', count($signatures));
-
- unset($responseBuffer, $signatures);
-
- return $result->fetch();*/
- }
}
diff --git a/third_party/gameq/GameQ/Protocols/Armedassault2oa.php b/third_party/gameq/GameQ/Protocols/Armedassault2oa.php
index 34fbc845..e527a38d 100644
--- a/third_party/gameq/GameQ/Protocols/Armedassault2oa.php
+++ b/third_party/gameq/GameQ/Protocols/Armedassault2oa.php
@@ -42,9 +42,9 @@ class Armedassault2oa extends Source
protected $name_long = "Armed Assault 2: Operation Arrowhead";
/**
- * Query port = client_port - 1
+ * Query port = client_port + 1
*
* @type int
*/
- protected $port_diff = -1;
+ protected $port_diff = 1;
}
diff --git a/third_party/gameq/GameQ/Protocols/Ase.php b/third_party/gameq/GameQ/Protocols/Ase.php
index cb5c6a42..abc47818 100644
--- a/third_party/gameq/GameQ/Protocols/Ase.php
+++ b/third_party/gameq/GameQ/Protocols/Ase.php
@@ -105,12 +105,21 @@ class Ase extends Protocol
*/
public function processResponse()
{
-
// Create a new buffer
$buffer = new Buffer(implode('', $this->packets_response));
- // Burn the header
- $buffer->skip(4);
+ // Check for valid response
+ if ($buffer->getLength() < 4) {
+ throw new \GameQ\Exception\Protocol(sprintf('%s The response from the server was empty.', __METHOD__));
+ }
+
+ // Read the header
+ $header = $buffer->read(4);
+
+ // Verify header
+ if ($header !== 'EYE1') {
+ throw new \GameQ\Exception\Protocol(sprintf('%s The response header "%s" does not match expected "EYE1"', __METHOD__, $header));
+ }
// Create a new result
$result = new Result();
diff --git a/third_party/gameq/GameQ/Protocols/Atlas.php b/third_party/gameq/GameQ/Protocols/Atlas.php
new file mode 100644
index 00000000..83406bae
--- /dev/null
+++ b/third_party/gameq/GameQ/Protocols/Atlas.php
@@ -0,0 +1,55 @@
+.
+ */
+
+namespace GameQ\Protocols;
+
+/**
+ * Class Atlas
+ *
+ * @package GameQ\Protocols
+ * @author Wilson Jesus <>
+ */
+class Atlas extends Source
+{
+
+ /**
+ * String name of this protocol class
+ *
+ * @type string
+ */
+ protected $name = 'atlas';
+
+ /**
+ * Longer string name of this protocol class
+ *
+ * @type string
+ */
+ protected $name_long = "Atlas";
+
+ /**
+ * query_port = client_port + 51800
+ * 57561 = 5761 + 51800
+ *
+ * this is the default value for the stock game server, both ports
+ * can be independently changed from the stock ones,
+ * making the port_diff logic useless.
+ *
+ * @type int
+ */
+ protected $port_diff = 51800;
+}
diff --git a/third_party/gameq/GameQ/Protocols/Brink.php b/third_party/gameq/GameQ/Protocols/Brink.php
new file mode 100644
index 00000000..20226525
--- /dev/null
+++ b/third_party/gameq/GameQ/Protocols/Brink.php
@@ -0,0 +1,50 @@
+.
+ */
+
+namespace GameQ\Protocols;
+
+/**
+ * Class Brink
+ *
+ * @package GameQ\Protocols
+ *
+ * @author Wilson Jesus <>
+ */
+class Brink extends Source
+{
+ /**
+ * String name of this protocol class
+ *
+ * @type string
+ */
+ protected $name = 'brink';
+
+ /**
+ * Longer string name of this protocol class
+ *
+ * @type string
+ */
+ protected $name_long = "Brink";
+
+ /**
+ * query_port = client_port + 1
+ *
+ * @type int
+ */
+ protected $port_diff = 1;
+}
diff --git a/third_party/gameq/GameQ/Protocols/Fof.php b/third_party/gameq/GameQ/Protocols/Cod.php
similarity index 85%
rename from third_party/gameq/GameQ/Protocols/Fof.php
rename to third_party/gameq/GameQ/Protocols/Cod.php
index 2875fbf8..2425ea67 100644
--- a/third_party/gameq/GameQ/Protocols/Fof.php
+++ b/third_party/gameq/GameQ/Protocols/Cod.php
@@ -19,24 +19,25 @@
namespace GameQ\Protocols;
/**
- * Class Fof
+ * Call of Duty Protocol Class
*
* @package GameQ\Protocols
- * @author Austin Bischoff
+ *
+ * @author Wilson Jesus <>
*/
-class Fof extends Source
+class Cod extends Quake3
{
/**
* String name of this protocol class
*
* @type string
*/
- protected $name = 'fof';
+ protected $name = 'cod';
/**
* Longer string name of this protocol class
*
* @type string
*/
- protected $name_long = "Fistful of Frags";
+ protected $name_long = "Call of Duty";
}
diff --git a/third_party/gameq/GameQ/Protocols/Alienswarm.php b/third_party/gameq/GameQ/Protocols/Coduo.php
similarity index 83%
rename from third_party/gameq/GameQ/Protocols/Alienswarm.php
rename to third_party/gameq/GameQ/Protocols/Coduo.php
index 204f957f..2dd9a182 100644
--- a/third_party/gameq/GameQ/Protocols/Alienswarm.php
+++ b/third_party/gameq/GameQ/Protocols/Coduo.php
@@ -19,24 +19,25 @@
namespace GameQ\Protocols;
/**
- * Class Alienswarm
+ * Call of Duty United Offensive Class
*
* @package GameQ\Protocols
- * @author Austin Bischoff
+ *
+ * @author Wilson Jesus <>
*/
-class Alienswarm extends Source
+class Coduo extends Quake3
{
/**
* String name of this protocol class
*
* @type string
*/
- protected $name = 'alienswarm';
+ protected $name = 'coduo';
/**
* Longer string name of this protocol class
*
* @type string
*/
- protected $name_long = "Alien Swarm";
+ protected $name_long = "Call of Duty: United Offensive";
}
diff --git a/third_party/gameq/GameQ/Protocols/Codwaw.php b/third_party/gameq/GameQ/Protocols/Codwaw.php
new file mode 100644
index 00000000..f730678e
--- /dev/null
+++ b/third_party/gameq/GameQ/Protocols/Codwaw.php
@@ -0,0 +1,43 @@
+.
+ */
+
+namespace GameQ\Protocols;
+
+/**
+ * Call of Duty World at War Class
+ *
+ * @package GameQ\Protocols
+ * @author naXe
+ * @author Austin Bischoff
+ */
+class Codwaw extends Quake3
+{
+ /**
+ * String name of this protocol class
+ *
+ * @type string
+ */
+ protected $name = 'codwaw';
+
+ /**
+ * Longer string name of this protocol class
+ *
+ * @type string
+ */
+ protected $name_long = "Call of Duty: World at War";
+}
diff --git a/third_party/gameq/GameQ/Protocols/Nmrih.php b/third_party/gameq/GameQ/Protocols/Contagion.php
similarity index 85%
rename from third_party/gameq/GameQ/Protocols/Nmrih.php
rename to third_party/gameq/GameQ/Protocols/Contagion.php
index c8f01aeb..64d0b76e 100644
--- a/third_party/gameq/GameQ/Protocols/Nmrih.php
+++ b/third_party/gameq/GameQ/Protocols/Contagion.php
@@ -19,25 +19,24 @@
namespace GameQ\Protocols;
/**
- * Class Nmrih
+ * Class Contagion
*
* @package GameQ\Protocols
+ * @author Nikolay Ipanyuk
* @author Austin Bischoff
*/
-class Nmrih extends Source
+class Contagion extends Source
{
-
/**
* String name of this protocol class
*
* @type string
*/
- protected $name = 'nmrih';
-
+ protected $name = 'contagion';
/**
* Longer string name of this protocol class
*
* @type string
*/
- protected $name_long = "No More Room in Hell";
+ protected $name_long = "Contagion";
}
diff --git a/third_party/gameq/GameQ/Protocols/Zps.php b/third_party/gameq/GameQ/Protocols/Crysis.php
similarity index 85%
rename from third_party/gameq/GameQ/Protocols/Zps.php
rename to third_party/gameq/GameQ/Protocols/Crysis.php
index 4f60b229..e09a673d 100644
--- a/third_party/gameq/GameQ/Protocols/Zps.php
+++ b/third_party/gameq/GameQ/Protocols/Crysis.php
@@ -19,24 +19,25 @@
namespace GameQ\Protocols;
/**
- * Class Zps
+ * Class Crysis
*
* @package GameQ\Protocols
- * @author Austin Bischoff
+ *
+ * @author Wilson Jesus <>
*/
-class Zps extends Source
+class Crysis extends Gamespy3
{
/**
* String name of this protocol class
*
* @type string
*/
- protected $name = 'zps';
+ protected $name = 'crysis';
/**
* Longer string name of this protocol class
*
* @type string
*/
- protected $name_long = "Zombie Panic Source";
+ protected $name_long = "Crysis";
}
diff --git a/third_party/gameq/GameQ/Protocols/Crysis2.php b/third_party/gameq/GameQ/Protocols/Crysis2.php
new file mode 100644
index 00000000..75c6614a
--- /dev/null
+++ b/third_party/gameq/GameQ/Protocols/Crysis2.php
@@ -0,0 +1,43 @@
+.
+ */
+
+namespace GameQ\Protocols;
+
+/**
+ * Class Crysis2
+ *
+ * @package GameQ\Protocols
+ *
+ * @author Wilson Jesus <>
+ */
+class Crysis2 extends Gamespy3
+{
+ /**
+ * String name of this protocol class
+ *
+ * @type string
+ */
+ protected $name = 'crysis2';
+
+ /**
+ * Longer string name of this protocol class
+ *
+ * @type string
+ */
+ protected $name_long = "Crysis 2";
+}
diff --git a/third_party/gameq/GameQ/Protocols/Cs2d.php b/third_party/gameq/GameQ/Protocols/Cs2d.php
new file mode 100644
index 00000000..0f238fdd
--- /dev/null
+++ b/third_party/gameq/GameQ/Protocols/Cs2d.php
@@ -0,0 +1,263 @@
+.
+ */
+
+namespace GameQ\Protocols;
+
+use GameQ\Protocol;
+use GameQ\Buffer;
+use GameQ\Result;
+use GameQ\Exception\Protocol as Exception;
+
+/**
+ * Counter-Strike 2d Protocol Class
+ *
+ * Note:
+ * Unable to make player information calls work as the protocol does not like parallel requests
+ *
+ * @author Austin Bischoff
+ */
+class Cs2d extends Protocol
+{
+
+ /**
+ * Array of packets we want to query.
+ *
+ * @type array
+ */
+ protected $packets = [
+ self::PACKET_STATUS => "\x01\x00\xFB\x01",
+ //self::PACKET_STATUS => "\x01\x00\x03\x10\x21\xFB\x01\x75\x00",
+ self::PACKET_PLAYERS => "\x01\x00\xFB\x05",
+ ];
+
+ /**
+ * Use the response flag to figure out what method to run
+ *
+ * @type array
+ */
+ protected $responses = [
+ "\x01\x00\xFB\x01" => "processDetails",
+ "\x01\x00\xFB\x05" => "processPlayers",
+ ];
+
+ /**
+ * The query protocol used to make the call
+ *
+ * @type string
+ */
+ protected $protocol = 'cs2d';
+
+ /**
+ * String name of this protocol class
+ *
+ * @type string
+ */
+ protected $name = 'cs2d';
+
+ /**
+ * Longer string name of this protocol class
+ *
+ * @type string
+ */
+ protected $name_long = "Counter-Strike 2d";
+
+ /**
+ * The client join link
+ *
+ * @type string
+ */
+ protected $join_link = "cs2d://%s:%d/";
+
+ /**
+ * Normalize settings for this protocol
+ *
+ * @type array
+ */
+ protected $normalize = [
+ // General
+ 'general' => [
+ // target => source
+ 'dedicated' => 'dedicated',
+ 'gametype' => 'game_mode',
+ 'hostname' => 'hostname',
+ 'mapname' => 'mapname',
+ 'maxplayers' => 'max_players',
+ 'mod' => 'game_dir',
+ 'numplayers' => 'num_players',
+ 'password' => 'password',
+ ],
+ // Individual
+ 'player' => [
+ 'name' => 'name',
+ 'deaths' => 'deaths',
+ 'score' => 'score',
+ ],
+ ];
+
+ /**
+ * Process the response for the Tibia server
+ *
+ * @return array
+ * @throws \GameQ\Exception\Protocol
+ */
+ public function processResponse()
+ {
+
+ // We have a merged packet, try to split it back up
+ if (count($this->packets_response) == 1) {
+ // Temp buffer to make string manipulation easier
+ $buffer = new Buffer($this->packets_response[0]);
+
+ // Grab the header and set the packet we need to split with
+ $packet = (($buffer->lookAhead(4) === $this->packets[self::PACKET_PLAYERS]) ?
+ self::PACKET_STATUS : self::PACKET_PLAYERS);
+
+ // Explode the merged packet as the response
+ $responses = explode(substr($this->packets[$packet], 2), $buffer->getData());
+
+ // Try to rebuild the second packet to the same as if it was sent as two separate responses
+ $responses[1] = $this->packets[$packet] . ((count($responses) === 2) ? $responses[1] : "");
+
+ unset($buffer);
+ } else {
+ $responses = $this->packets_response;
+ }
+
+ // Will hold the packets after sorting
+ $packets = [];
+
+ // We need to pre-sort these for split packets so we can do extra work where needed
+ foreach ($responses as $response) {
+ $buffer = new Buffer($response);
+
+ // Pull out the header
+ $header = $buffer->read(4);
+
+ // Add the packet to the proper section, we will combine later
+ $packets[$header][] = $buffer->getBuffer();
+ }
+
+ unset($buffer);
+
+ $results = [];
+
+ // Now let's iterate and process
+ foreach ($packets as $header => $packetGroup) {
+ // Figure out which packet response this is
+ if (!array_key_exists($header, $this->responses)) {
+ throw new Exception(__METHOD__ . " response type '" . bin2hex($header) . "' is not valid");
+ }
+
+ // Now we need to call the proper method
+ $results = array_merge(
+ $results,
+ call_user_func_array([$this, $this->responses[$header]], [new Buffer(implode($packetGroup))])
+ );
+ }
+
+ unset($packets);
+
+ return $results;
+ }
+
+ /**
+ * Handles processing the details data into a usable format
+ *
+ * @param Buffer $buffer
+ *
+ * @return array
+ * @throws Exception
+ */
+ protected function processDetails(Buffer $buffer)
+ {
+ // Set the result to a new result instance
+ $result = new Result();
+
+ // First int is the server flags
+ $serverFlags = $buffer->readInt8();
+
+ // Read server flags
+ $result->add('password', (int)$this->readFlag($serverFlags, 0));
+ $result->add('registered_only', (int)$this->readFlag($serverFlags, 1));
+ $result->add('fog_of_war', (int)$this->readFlag($serverFlags, 2));
+ $result->add('friendly_fire', (int)$this->readFlag($serverFlags, 3));
+ $result->add('bots_enabled', (int)$this->readFlag($serverFlags, 5));
+ $result->add('lua_scripts', (int)$this->readFlag($serverFlags, 6));
+
+ // Read the rest of the buffer data
+ $result->add('servername', utf8_encode($buffer->readPascalString(0)));
+ $result->add('mapname', utf8_encode($buffer->readPascalString(0)));
+ $result->add('num_players', $buffer->readInt8());
+ $result->add('max_players', $buffer->readInt8());
+ $result->add('game_mode', $buffer->readInt8());
+ $result->add('num_bots', (($this->readFlag($serverFlags, 5)) ? $buffer->readInt8() : 0));
+ $result->add('dedicated', 1);
+
+ unset($buffer);
+
+ return $result->fetch();
+ }
+
+ /**
+ * Handles processing the player data into a usable format
+ *
+ * @param Buffer $buffer
+ *
+ * @return array
+ * @throws Exception
+ */
+ protected function processPlayers(Buffer $buffer)
+ {
+
+ // Set the result to a new result instance
+ $result = new Result();
+
+ // First entry is the number of players in this list. Don't care
+ $buffer->read();
+
+ // Parse players
+ while ($buffer->getLength()) {
+ // Player id
+ if (($id = $buffer->readInt8()) !== 0) {
+ // Add the results
+ $result->addPlayer('id', $id);
+ $result->addPlayer('name', utf8_encode($buffer->readPascalString(0)));
+ $result->addPlayer('team', $buffer->readInt8());
+ $result->addPlayer('score', $buffer->readInt32());
+ $result->addPlayer('deaths', $buffer->readInt32());
+ }
+ }
+
+ unset($buffer, $id);
+
+ return $result->fetch();
+ }
+
+ /**
+ * Read flags from stored value
+ *
+ * @param $flags
+ * @param $offset
+ *
+ * @return bool
+ */
+ protected function readFlag($flags, $offset)
+ {
+ return !!($flags & (1 << $offset));
+ }
+}
diff --git a/third_party/gameq/GameQ/Protocols/Jc2.php b/third_party/gameq/GameQ/Protocols/Dal.php
similarity index 89%
rename from third_party/gameq/GameQ/Protocols/Jc2.php
rename to third_party/gameq/GameQ/Protocols/Dal.php
index e179f3ad..6b05037d 100644
--- a/third_party/gameq/GameQ/Protocols/Jc2.php
+++ b/third_party/gameq/GameQ/Protocols/Dal.php
@@ -19,12 +19,12 @@
namespace GameQ\Protocols;
/**
- * Class Jc2
+ * Class Dark and Light
*
* @package GameQ\Protocols
* @author Austin Bischoff
*/
-class Jc2 extends Source
+class Dal extends Arkse
{
/**
@@ -32,12 +32,12 @@ class Jc2 extends Source
*
* @type string
*/
- protected $name = 'jc2';
+ protected $name = 'dal';
/**
* Longer string name of this protocol class
*
* @type string
*/
- protected $name_long = "Just Cause 2 Multiplayer";
+ protected $name_long = "Dark and Light";
}
diff --git a/third_party/gameq/GameQ/Protocols/Dayzmod.php b/third_party/gameq/GameQ/Protocols/Dayzmod.php
index 2ce1076d..80b798e3 100644
--- a/third_party/gameq/GameQ/Protocols/Dayzmod.php
+++ b/third_party/gameq/GameQ/Protocols/Dayzmod.php
@@ -1,4 +1,5 @@
.
+ */
+
+namespace GameQ\Protocols;
+
+use GameQ\Exception\Protocol as Exception;
+use GameQ\Result;
+
+/**
+ * ECO Global Survival Protocol Class
+ *
+ * @author Austin Bischoff
+ */
+class Eco extends Http
+{
+ /**
+ * Packets to send
+ *
+ * @var array
+ */
+ protected $packets = [
+ self::PACKET_STATUS => "GET /frontpage HTTP/1.0\r\nAccept: */*\r\n\r\n",
+ ];
+
+ /**
+ * Http protocol is SSL
+ *
+ * @var string
+ */
+ protected $transport = self::TRANSPORT_TCP;
+
+ /**
+ * The protocol being used
+ *
+ * @var string
+ */
+ protected $protocol = 'eco';
+
+ /**
+ * String name of this protocol class
+ *
+ * @var string
+ */
+ protected $name = 'eco';
+
+ /**
+ * Longer string name of this protocol class
+ *
+ * @var string
+ */
+ protected $name_long = "ECO Global Survival";
+
+ /**
+ * query_port = client_port + 1
+ *
+ * @type int
+ */
+ protected $port_diff = 1;
+
+ /**
+ * Normalize some items
+ *
+ * @var array
+ */
+ protected $normalize = [
+ // General
+ 'general' => [
+ // target => source
+ 'dedicated' => 'dedicated',
+ 'hostname' => 'description',
+ 'maxplayers' => 'totalplayers',
+ 'numplayers' => 'onlineplayers',
+ 'password' => 'haspassword',
+ ],
+ ];
+
+ /**
+ * Process the response
+ *
+ * @return array
+ * @throws Exception
+ */
+ public function processResponse()
+ {
+ if (empty($this->packets_response)) {
+ return [];
+ }
+
+ // Implode and rip out the JSON
+ preg_match('/\{(.*)\}/ms', implode('', $this->packets_response), $matches);
+
+ // Return should be JSON, let's validate
+ if (!isset($matches[0]) || ($json = json_decode($matches[0])) === null) {
+ throw new Exception("JSON response from Eco server is invalid.");
+ }
+
+ $result = new Result();
+
+ // Server is always dedicated
+ $result->add('dedicated', 1);
+
+ foreach ($json->Info as $info => $setting) {
+ $result->add(strtolower($info), $setting);
+ }
+
+ return $result->fetch();
+ }
+}
diff --git a/third_party/gameq/GameQ/Protocols/Egs.php b/third_party/gameq/GameQ/Protocols/Egs.php
index 4f82aa8c..aab79aea 100644
--- a/third_party/gameq/GameQ/Protocols/Egs.php
+++ b/third_party/gameq/GameQ/Protocols/Egs.php
@@ -25,7 +25,7 @@ namespace GameQ\Protocols;
* @author Austin Bischoff
* @author TacTicToe66
*/
-class EgS extends Source
+class Egs extends Source
{
/**
diff --git a/third_party/gameq/GameQ/Protocols/Aapg.php b/third_party/gameq/GameQ/Protocols/Et.php
similarity index 83%
rename from third_party/gameq/GameQ/Protocols/Aapg.php
rename to third_party/gameq/GameQ/Protocols/Et.php
index a207d4fe..63b5beb7 100644
--- a/third_party/gameq/GameQ/Protocols/Aapg.php
+++ b/third_party/gameq/GameQ/Protocols/Et.php
@@ -19,24 +19,25 @@
namespace GameQ\Protocols;
/**
- * Class Aapg
+ * Wolfenstein Enemy Territory Protocol Class
*
* @package GameQ\Protocols
- * @author Austin Bischoff
+ *
+ * @author Wilson Jesus <>
*/
-class Aapg extends Aa3
+class Et extends Quake3
{
/**
* String name of this protocol class
*
* @type string
*/
- protected $name = 'aapg';
+ protected $name = 'et';
/**
* Longer string name of this protocol class
*
* @type string
*/
- protected $name_long = "America's Army: Proving Grounds";
+ protected $name_long = "Wolfenstein Enemy Territory";
}
diff --git a/third_party/gameq/GameQ/Protocols/Gamespy.php b/third_party/gameq/GameQ/Protocols/Gamespy.php
index 37a951e3..b1a1e4fa 100644
--- a/third_party/gameq/GameQ/Protocols/Gamespy.php
+++ b/third_party/gameq/GameQ/Protocols/Gamespy.php
@@ -140,28 +140,31 @@ class Gamespy extends Protocol
$itemCount = count($data);
- // Now lets loop the array
- for ($x = 0; $x < $itemCount; $x += 2) {
- // Set some local vars
- $key = $data[$x];
- $val = $data[$x + 1];
+ // Check to make sure we have more than 1 item in the array before trying to loop
+ if (count($data) > 1) {
+ // Now lets loop the array since we have items
+ for ($x = 0; $x < $itemCount; $x += 2) {
+ // Set some local vars
+ $key = $data[$x];
+ $val = $data[$x + 1];
- // Check for _ variable (i.e players)
- if (($suffix = strrpos($key, '_')) !== false && is_numeric(substr($key, $suffix + 1))) {
- // See if this is a team designation
- if (substr($key, 0, $suffix) == 'teamname') {
- $result->addTeam('teamname', $val);
- $numTeams++;
- } else {
- // Its a player
- if (substr($key, 0, $suffix) == 'playername') {
- $numPlayers++;
+ // Check for _ variable (i.e players)
+ if (($suffix = strrpos($key, '_')) !== false && is_numeric(substr($key, $suffix + 1))) {
+ // See if this is a team designation
+ if (substr($key, 0, $suffix) == 'teamname') {
+ $result->addTeam('teamname', $val);
+ $numTeams++;
+ } else {
+ // Its a player
+ if (substr($key, 0, $suffix) == 'playername') {
+ $numPlayers++;
+ }
+ $result->addPlayer(substr($key, 0, $suffix), utf8_encode($val));
}
- $result->addPlayer(substr($key, 0, $suffix), utf8_encode($val));
+ } else {
+ // Regular variable so just add the value.
+ $result->add($key, $val);
}
- } else {
- // Regular variable so just add the value.
- $result->add($key, $val);
}
}
diff --git a/third_party/gameq/GameQ/Protocols/Gamespy2.php b/third_party/gameq/GameQ/Protocols/Gamespy2.php
new file mode 100644
index 00000000..c7788d9e
--- /dev/null
+++ b/third_party/gameq/GameQ/Protocols/Gamespy2.php
@@ -0,0 +1,269 @@
+.
+ */
+
+namespace GameQ\Protocols;
+
+use GameQ\Exception\Protocol as Exception;
+use GameQ\Protocol;
+use GameQ\Buffer;
+use GameQ\Result;
+
+/**
+ * GameSpy2 Protocol class
+ *
+ * Given the ability for non utf-8 characters to be used as hostnames, player names, etc... this
+ * version returns all strings utf-8 encoded (utf8_encode). To access the proper version of a
+ * string response you must use utf8_decode() on the specific response.
+ *
+ * @author Austin Bischoff
+ */
+class Gamespy2 extends Protocol
+{
+
+ /**
+ * Define the state of this class
+ *
+ * @type int
+ */
+ protected $state = self::STATE_BETA;
+
+ /**
+ * Array of packets we want to look up.
+ * Each key should correspond to a defined method in this or a parent class
+ *
+ * @type array
+ */
+ protected $packets = [
+ self::PACKET_DETAILS => "\xFE\xFD\x00\x43\x4F\x52\x59\xFF\x00\x00",
+ self::PACKET_PLAYERS => "\xFE\xFD\x00\x43\x4F\x52\x58\x00\xFF\xFF",
+ ];
+
+ /**
+ * Use the response flag to figure out what method to run
+ *
+ * @type array
+ */
+ protected $responses = [
+ "\x00\x43\x4F\x52\x59" => "processDetails",
+ "\x00\x43\x4F\x52\x58" => "processPlayers",
+ ];
+
+ /**
+ * The query protocol used to make the call
+ *
+ * @type string
+ */
+ protected $protocol = 'gamespy2';
+
+ /**
+ * String name of this protocol class
+ *
+ * @type string
+ */
+ protected $name = 'gamespy2';
+
+ /**
+ * Longer string name of this protocol class
+ *
+ * @type string
+ */
+ protected $name_long = "GameSpy2 Server";
+
+ /**
+ * The client join link
+ *
+ * @type string
+ */
+ protected $join_link = null;
+
+ /**
+ * Normalize settings for this protocol
+ *
+ * @type array
+ */
+ protected $normalize = [
+ // General
+ 'general' => [
+ // target => source
+ 'dedicated' => 'dedicated',
+ 'gametype' => 'gametype',
+ 'hostname' => 'hostname',
+ 'mapname' => 'mapname',
+ 'maxplayers' => 'maxplayers',
+ 'mod' => 'mod',
+ 'numplayers' => 'numplayers',
+ 'password' => 'password',
+ ],
+ ];
+
+
+ /**
+ * Process the response
+ *
+ * @return array
+ * @throws Exception
+ */
+ public function processResponse()
+ {
+
+ // Will hold the packets after sorting
+ $packets = [];
+
+ // We need to pre-sort these for split packets so we can do extra work where needed
+ foreach ($this->packets_response as $response) {
+ $buffer = new Buffer($response);
+
+ // Pull out the header
+ $header = $buffer->read(5);
+
+ // Add the packet to the proper section, we will combine later
+ $packets[$header][] = $buffer->getBuffer();
+ }
+
+ unset($buffer);
+
+ $results = [];
+
+ // Now let's iterate and process
+ foreach ($packets as $header => $packetGroup) {
+ // Figure out which packet response this is
+ if (!array_key_exists($header, $this->responses)) {
+ throw new Exception(__METHOD__ . " response type '" . bin2hex($header) . "' is not valid");
+ }
+
+ // Now we need to call the proper method
+ $results = array_merge(
+ $results,
+ call_user_func_array([$this, $this->responses[$header]], [new Buffer(implode($packetGroup))])
+ );
+ }
+
+ unset($packets);
+
+ return $results;
+ }
+
+ /*
+ * Internal methods
+ */
+
+ /**
+ * Handles processing the details data into a usable format
+ *
+ * @param \GameQ\Buffer $buffer
+ *
+ * @return array
+ * @throws Exception
+ */
+ protected function processDetails(Buffer $buffer)
+ {
+
+ // Set the result to a new result instance
+ $result = new Result();
+
+ // We go until we hit an empty key
+ while ($buffer->getLength()) {
+ $key = $buffer->readString();
+ if (strlen($key) == 0) {
+ break;
+ }
+ $result->add($key, utf8_encode($buffer->readString()));
+ }
+
+ unset($buffer);
+
+ return $result->fetch();
+ }
+
+ /**
+ * Handles processing the players data into a usable format
+ *
+ * @param \GameQ\Buffer $buffer
+ *
+ * @return array
+ * @throws Exception
+ */
+ protected function processPlayers(Buffer $buffer)
+ {
+
+ // Set the result to a new result instance
+ $result = new Result();
+
+ // Skip the header
+ $buffer->skip(1);
+
+ // Players are first
+ $this->parsePlayerTeam('players', $buffer, $result);
+
+ // Teams are next
+ $this->parsePlayerTeam('teams', $buffer, $result);
+
+ unset($buffer);
+
+ return $result->fetch();
+ }
+
+ /**
+ * Parse the player/team info returned from the player call
+ *
+ * @param string $dataType
+ * @param \GameQ\Buffer $buffer
+ * @param \GameQ\Result $result
+ *
+ * @throws Exception
+ */
+ protected function parsePlayerTeam($dataType, Buffer &$buffer, Result &$result)
+ {
+
+ // Do count
+ $result->add('num_' . $dataType, $buffer->readInt8());
+
+ // Variable names
+ $varNames = [];
+
+ // Loop until we run out of length
+ while ($buffer->getLength()) {
+ $varNames[] = str_replace('_', '', $buffer->readString());
+
+ if ($buffer->lookAhead() === "\x00") {
+ $buffer->skip();
+ break;
+ }
+ }
+
+ // Check if there are any value entries
+ if ($buffer->lookAhead() == "\x00") {
+ $buffer->skip();
+
+ return;
+ }
+
+ // Get the values
+ while ($buffer->getLength() > 4) {
+ foreach ($varNames as $varName) {
+ $result->addSub($dataType, utf8_encode($varName), utf8_encode($buffer->readString()));
+ }
+ if ($buffer->lookAhead() === "\x00") {
+ $buffer->skip();
+ break;
+ }
+ }
+
+ return;
+ }
+}
diff --git a/third_party/gameq/GameQ/Protocols/Gamespy3.php b/third_party/gameq/GameQ/Protocols/Gamespy3.php
index ab742060..2df0a4bd 100644
--- a/third_party/gameq/GameQ/Protocols/Gamespy3.php
+++ b/third_party/gameq/GameQ/Protocols/Gamespy3.php
@@ -277,10 +277,15 @@ class Gamespy3 extends Protocol
// By default item_group is blank, this will be set for each loop thru the data
$item_group = '';
+
// By default the item_type is blank, this will be set on each loop
$item_type = '';
+
+ // Save count as variable
+ $count = count($data);
+
// Loop through all of the $data for information and pull it out into the result
- for ($x = 0; $x < count($data) - 1; $x++) {
+ for ($x = 0; $x < $count - 1; $x++) {
// Pull out the item
$item = $data[$x];
// If this is an empty item, move on
@@ -330,6 +335,6 @@ class Gamespy3 extends Protocol
}
}
// Free up some memory
- unset($data, $item, $item_group, $item_type, $val);
+ unset($count, $data, $item, $item_group, $item_type, $val);
}
}
diff --git a/third_party/gameq/GameQ/Protocols/Gtar.php b/third_party/gameq/GameQ/Protocols/Gtar.php
new file mode 100644
index 00000000..2121e07c
--- /dev/null
+++ b/third_party/gameq/GameQ/Protocols/Gtar.php
@@ -0,0 +1,164 @@
+.
+ */
+namespace GameQ\Protocols;
+
+use GameQ\Exception\Protocol as Exception;
+use GameQ\Result;
+use GameQ\Server;
+
+/**
+ * Grand Theft Auto Rage Protocol Class
+ * https://rage.mp/masterlist/
+ *
+ * Result from this call should be a header + JSON response
+ *
+ * @author K700
+ * @author Austin Bischoff
+ */
+class Gtar extends Http
+{
+ /**
+ * Packets to send
+ *
+ * @var array
+ */
+ protected $packets = [
+ self::PACKET_STATUS => "GET /master/ HTTP/1.0\r\nHost: cdn.rage.mp\r\nAccept: */*\r\n\r\n",
+ ];
+
+ /**
+ * Http protocol is SSL
+ *
+ * @var string
+ */
+ protected $transport = self::TRANSPORT_SSL;
+
+ /**
+ * The protocol being used
+ *
+ * @var string
+ */
+ protected $protocol = 'gtar';
+
+ /**
+ * String name of this protocol class
+ *
+ * @var string
+ */
+ protected $name = 'gtar';
+
+ /**
+ * Longer string name of this protocol class
+ *
+ * @var string
+ */
+ protected $name_long = "Grand Theft Auto Rage";
+
+ /**
+ * Holds the real ip so we can overwrite it back
+ *
+ * @var string
+ */
+ protected $realIp = null;
+
+ protected $realPortQuery = null;
+
+ /**
+ * Normalize some items
+ *
+ * @var array
+ */
+ protected $normalize = [
+ // General
+ 'general' => [
+ // target => source
+ 'dedicated' => 'dedicated',
+ 'hostname' => 'hostname',
+ 'mod' => 'mod',
+ 'maxplayers' => 'maxplayers',
+ 'numplayers' => 'numplayers',
+ ],
+ ];
+
+ public function beforeSend(Server $server)
+ {
+ // Loop over the packets and update them
+ foreach ($this->packets as $packetType => $packet) {
+ // Fill out the packet with the server info
+ $this->packets[$packetType] = sprintf($packet, $server->ip . ':' . $server->port_query);
+ }
+
+ $this->realIp = $server->ip;
+ $this->realPortQuery = $server->port_query;
+
+ // Override the existing settings
+ $server->ip = 'cdn.rage.mp';
+ $server->port_query = 443;
+ }
+
+ /**
+ * Process the response
+ *
+ * @return array
+ * @throws Exception
+ */
+ public function processResponse()
+ {
+ // No response, assume offline
+ if (empty($this->packets_response)) {
+ return [
+ 'gq_address' => $this->realIp,
+ 'gq_port_query' => $this->realPortQuery,
+ ];
+ }
+
+ // Implode and rip out the JSON
+ preg_match('/\{(.*)\}/ms', implode('', $this->packets_response), $matches);
+
+ // Return should be JSON, let's validate
+ if (!isset($matches[0]) || ($json = json_decode($matches[0])) === null) {
+ throw new Exception("JSON response from Gtar protocol is invalid.");
+ }
+
+ $address = $this->realIp.':'.$this->realPortQuery;
+ $server = $json->$address;
+
+ if (empty($server)) {
+ return [
+ 'gq_address' => $this->realIp,
+ 'gq_port_query' => $this->realPortQuery,
+ ];
+ }
+
+ $result = new Result();
+
+ // Server is always dedicated
+ $result->add('dedicated', 1);
+
+ $result->add('gq_address', $this->realIp);
+ $result->add('gq_port_query', $this->realPortQuery);
+
+ // Add server items
+ $result->add('hostname', $server->name);
+ $result->add('mod', $server->gamemode);
+ $result->add('numplayers', $server->players);
+ $result->add('maxplayers', $server->maxplayers);
+
+ return $result->fetch();
+ }
+}
diff --git a/third_party/gameq/GameQ/Protocols/Projectcars.php b/third_party/gameq/GameQ/Protocols/Hurtworld.php
similarity index 85%
rename from third_party/gameq/GameQ/Protocols/Projectcars.php
rename to third_party/gameq/GameQ/Protocols/Hurtworld.php
index fc9baaac..fa54654a 100644
--- a/third_party/gameq/GameQ/Protocols/Projectcars.php
+++ b/third_party/gameq/GameQ/Protocols/Hurtworld.php
@@ -19,25 +19,24 @@
namespace GameQ\Protocols;
/**
- * Class Projectcars
+ * Class Hurtworld
*
* @package GameQ\Protocols
+ * @author Nikolay Ipanyuk
* @author Austin Bischoff
*/
-class Projectcars extends Source
+class Hurtworld extends Source
{
-
/**
* String name of this protocol class
*
* @type string
*/
- protected $name = 'projectcars';
-
+ protected $name = 'hurtworld';
/**
* Longer string name of this protocol class
*
* @type string
*/
- protected $name_long = "Project Cars";
+ protected $name_long = "Hurtworld";
}
diff --git a/third_party/gameq/GameQ/Protocols/Insurgencysand.php b/third_party/gameq/GameQ/Protocols/Insurgencysand.php
new file mode 100644
index 00000000..407d6e26
--- /dev/null
+++ b/third_party/gameq/GameQ/Protocols/Insurgencysand.php
@@ -0,0 +1,49 @@
+.
+ */
+
+namespace GameQ\Protocols;
+
+/**
+ * Insurgency Sandstorm Class
+ *
+ * @package GameQ\Protocols
+ * @author Austin Bischoff
+ */
+class Insurgencysand extends Source
+{
+ /**
+ * String name of this protocol class
+ *
+ * @type string
+ */
+ protected $name = 'insurgencysand';
+
+ /**
+ * Longer string name of this protocol class
+ *
+ * @type string
+ */
+ protected $name_long = "Insurgency: Sandstorm";
+
+ /**
+ * query_port = client_port + 29
+ *
+ * @type int
+ */
+ protected $port_diff = 29;
+}
diff --git a/third_party/gameq/GameQ/Protocols/Killingfloor.php b/third_party/gameq/GameQ/Protocols/Killingfloor.php
index 9cc19643..0947b48a 100644
--- a/third_party/gameq/GameQ/Protocols/Killingfloor.php
+++ b/third_party/gameq/GameQ/Protocols/Killingfloor.php
@@ -35,7 +35,7 @@ class Killingfloor extends Unreal2
*
* @type string
*/
- protected $name = 'killing floor';
+ protected $name = 'killingfloor';
/**
* Longer string name of this protocol class
diff --git a/third_party/gameq/GameQ/Protocols/Killingfloor2.php b/third_party/gameq/GameQ/Protocols/Killingfloor2.php
index a134f258..fd5432bf 100644
--- a/third_party/gameq/GameQ/Protocols/Killingfloor2.php
+++ b/third_party/gameq/GameQ/Protocols/Killingfloor2.php
@@ -32,7 +32,7 @@ class Killingfloor2 extends Source
*
* @type string
*/
- protected $name = 'killing floor 2';
+ protected $name = 'killingfloor2';
/**
* Longer string name of this protocol class
diff --git a/third_party/gameq/GameQ/Protocols/Mohaa.php b/third_party/gameq/GameQ/Protocols/Mohaa.php
index d4ebb5ad..66ddd7e7 100644
--- a/third_party/gameq/GameQ/Protocols/Mohaa.php
+++ b/third_party/gameq/GameQ/Protocols/Mohaa.php
@@ -74,6 +74,6 @@ class Mohaa extends Gamespy
*/
public function findQueryPort($clientPort)
{
- return $clientPort+97;
+ return $clientPort + 97;
}
}
diff --git a/third_party/gameq/GameQ/Protocols/Aa3.php b/third_party/gameq/GameQ/Protocols/Mordhau.php
similarity index 76%
rename from third_party/gameq/GameQ/Protocols/Aa3.php
rename to third_party/gameq/GameQ/Protocols/Mordhau.php
index 6ffd412a..fa305ce1 100644
--- a/third_party/gameq/GameQ/Protocols/Aa3.php
+++ b/third_party/gameq/GameQ/Protocols/Mordhau.php
@@ -19,12 +19,12 @@
namespace GameQ\Protocols;
/**
- * Class Aa3
+ * Class MORDHAU
*
* @package GameQ\Protocols
- * @author Austin Bischoff
+ * @author Wilson Jesus <>
*/
-class Aa3 extends Source
+class Mordhau extends Source
{
/**
@@ -32,22 +32,22 @@ class Aa3 extends Source
*
* @type string
*/
- protected $name = 'aa3';
+ protected $name = 'mordhau';
/**
* Longer string name of this protocol class
*
* @type string
*/
- protected $name_long = "America's Army 3";
+ protected $name_long = "MORDHAU";
+
+ #protected $port = 7777;
/**
- * Query port = client_port + 18243
- *
- * client_port default 8777
- * query_port default 27020
+ * query_port = client_port + 19238
+ * 27015 = 7777 + 19238
*
* @type int
*/
- protected $port_diff = 18243;
+ #protected $port_diff = 19238;
}
diff --git a/third_party/gameq/GameQ/Protocols/Tfc.php b/third_party/gameq/GameQ/Protocols/Pixark.php
similarity index 89%
rename from third_party/gameq/GameQ/Protocols/Tfc.php
rename to third_party/gameq/GameQ/Protocols/Pixark.php
index aed24027..2e67af04 100644
--- a/third_party/gameq/GameQ/Protocols/Tfc.php
+++ b/third_party/gameq/GameQ/Protocols/Pixark.php
@@ -19,12 +19,12 @@
namespace GameQ\Protocols;
/**
- * Class Tfc
+ * Class PixARK
*
* @package GameQ\Protocols
* @author Austin Bischoff
*/
-class Tfc extends Source
+class Pixark extends Arkse
{
/**
@@ -32,12 +32,12 @@ class Tfc extends Source
*
* @type string
*/
- protected $name = 'tfc';
+ protected $name = 'pixark';
/**
* Longer string name of this protocol class
*
* @type string
*/
- protected $name_long = "Team Fortress Classic";
+ protected $name_long = "PixARK";
}
diff --git a/third_party/gameq/GameQ/Protocols/Quake3.php b/third_party/gameq/GameQ/Protocols/Quake3.php
index 3ed177bb..6269b927 100644
--- a/third_party/gameq/GameQ/Protocols/Quake3.php
+++ b/third_party/gameq/GameQ/Protocols/Quake3.php
@@ -162,6 +162,7 @@ class Quake3 extends Protocol
* @param Buffer $buffer
*
* @return array
+ * @throws Exception
*/
protected function processPlayers(Buffer $buffer)
{
@@ -173,24 +174,34 @@ class Quake3 extends Protocol
// Loop until we are out of data
while ($buffer->getLength()) {
- // Make a new buffer with this block
- $playerInfo = new Buffer($buffer->readString("\x0A"));
-
// Add player info
- $result->addPlayer('frags', $playerInfo->readString("\x20"));
- $result->addPlayer('ping', $playerInfo->readString("\x20"));
+ $result->addPlayer('frags', $buffer->readString("\x20"));
+ $result->addPlayer('ping', $buffer->readString("\x20"));
- // Skip first "
- $playerInfo->skip(1);
+ // Look ahead to see if we have a name or team
+ $checkTeam = $buffer->lookAhead(1);
+
+ // We have team info
+ if ($checkTeam != '' and $checkTeam != '"') {
+ $result->addPlayer('team', $buffer->readString("\x20"));
+ }
+
+ // Check to make sure we have player name
+ $checkPlayerName = $buffer->read();
+
+ // Bad response
+ if ($checkPlayerName !== '"') {
+ throw new Exception('Expected " but got ' . $checkPlayerName . ' for beginning of player name string!');
+ }
// Add player name, encoded
- $result->addPlayer('name', utf8_encode(trim(($playerInfo->readString('"')))));
+ $result->addPlayer('name', utf8_encode(trim($buffer->readString('"'))));
+
+ // Burn ending delimiter
+ $buffer->read();
// Increment
$playerCount++;
-
- // Clear
- unset($playerInfo);
}
$result->add('clients', $playerCount);
diff --git a/third_party/gameq/GameQ/Protocols/Redorchestraostfront.php b/third_party/gameq/GameQ/Protocols/Redorchestraostfront.php
new file mode 100644
index 00000000..4c83b7eb
--- /dev/null
+++ b/third_party/gameq/GameQ/Protocols/Redorchestraostfront.php
@@ -0,0 +1,43 @@
+.
+ */
+
+namespace GameQ\Protocols;
+
+/**
+ * Red Orchestra: Ostfront 41-45 Class
+ *
+ * @package GameQ\Protocols
+ * @author naXe
+ * @author Austin Bischoff
+ */
+class Redorchestraostfront extends Source
+{
+ /**
+ * String name of this protocol class
+ *
+ * @type string
+ */
+ protected $name = 'redorchestraostfront';
+
+ /**
+ * Longer string name of this protocol class
+ *
+ * @type string
+ */
+ protected $name_long = "Red Orchestra: Ostfront 41-45";
+}
diff --git a/third_party/gameq/GameQ/Protocols/Samp.php b/third_party/gameq/GameQ/Protocols/Samp.php
index e96358a7..cf01f834 100644
--- a/third_party/gameq/GameQ/Protocols/Samp.php
+++ b/third_party/gameq/GameQ/Protocols/Samp.php
@@ -86,6 +86,13 @@ class Samp extends Protocol
*/
protected $server_code = null;
+ /**
+ * The client join link
+ *
+ * @type string
+ */
+ protected $join_link = "samp://%s:%d/";
+
/**
* Normalize settings for this protocol
*
@@ -120,7 +127,7 @@ class Samp extends Protocol
// Build the server code
$this->server_code = implode('', array_map('chr', explode('.', $server->ip()))) .
- pack("S", $server->portClient());
+ pack("S", $server->portClient());
// Loop over the packets and update them
foreach ($this->packets as $packetType => $packet) {
@@ -139,7 +146,7 @@ class Samp extends Protocol
{
// Results that will be returned
- $results = [ ];
+ $results = [];
// Get the length of the server code so we can figure out how much to read later
$serverCodeLength = strlen($this->server_code);
@@ -170,7 +177,7 @@ class Samp extends Protocol
// Now we need to call the proper method
$results = array_merge(
$results,
- call_user_func_array([ $this, $this->responses[$response_type] ], [ $buffer ])
+ call_user_func_array([$this, $this->responses[$response_type]], [$buffer])
);
unset($buffer);
@@ -206,7 +213,7 @@ class Samp extends Protocol
$result->add('max_players', $buffer->readInt16());
// These are read differently for these last 3
- $result->add('servername', $buffer->read($buffer->readInt32()));
+ $result->add('servername', utf8_encode($buffer->read($buffer->readInt32())));
$result->add('gametype', $buffer->read($buffer->readInt32()));
$result->add('language', $buffer->read($buffer->readInt32()));
@@ -234,7 +241,7 @@ class Samp extends Protocol
// Run until we run out of buffer
while ($buffer->getLength()) {
$result->addPlayer('id', $buffer->readInt8());
- $result->addPlayer('name', $buffer->readPascalString());
+ $result->addPlayer('name', utf8_encode($buffer->readPascalString()));
$result->addPlayer('score', $buffer->readInt32());
$result->addPlayer('ping', $buffer->readInt32());
}
diff --git a/third_party/gameq/GameQ/Protocols/Serioussam.php b/third_party/gameq/GameQ/Protocols/Serioussam.php
new file mode 100644
index 00000000..64a03cf7
--- /dev/null
+++ b/third_party/gameq/GameQ/Protocols/Serioussam.php
@@ -0,0 +1,75 @@
+.
+ */
+
+namespace GameQ\Protocols;
+
+/**
+ * Serious Sam Protocol Class
+ *
+ * @author ZCaliptium
+ */
+class Serioussam extends Gamespy
+{
+
+ /**
+ * String name of this protocol class
+ *
+ * @type string
+ */
+ protected $name = 'serioussam';
+
+ /**
+ * Longer string name of this protocol class
+ *
+ * @type string
+ */
+ protected $name_long = "Serious Sam";
+
+ /**
+ * query_port = client_port + 1
+ *
+ * @type int
+ */
+ protected $port_diff = 1;
+
+ /**
+ * Normalize settings for this protocol
+ *
+ * @type array
+ */
+ protected $normalize = [
+ // General
+ 'general' => [
+ // target => source
+ 'dedicated' => 'dedicated',
+ 'gametype' => 'gametype',
+ 'hostname' => 'hostname',
+ 'mapname' => 'mapname',
+ 'maxplayers' => 'maxplayers',
+ 'mod' => 'activemod',
+ 'numplayers' => 'numplayers',
+ 'password' => 'password',
+ ],
+ // Individual
+ 'player' => [
+ 'name' => 'player',
+ 'ping' => 'ping',
+ 'score' => 'frags',
+ ],
+ ];
+}
diff --git a/third_party/gameq/GameQ/Protocols/Sof2.php b/third_party/gameq/GameQ/Protocols/Sof2.php
new file mode 100644
index 00000000..96a4db25
--- /dev/null
+++ b/third_party/gameq/GameQ/Protocols/Sof2.php
@@ -0,0 +1,49 @@
+.
+ */
+
+namespace GameQ\Protocols;
+
+/**
+ * Soldier of Fortune 2 Class
+ *
+ * @package GameQ\Protocols
+ * @author Austin Bischoff
+ */
+class Sof2 extends Quake3
+{
+ /**
+ * String name of this protocol class
+ *
+ * @type string
+ */
+ protected $name = 'sof2';
+
+ /**
+ * Longer string name of this protocol class
+ *
+ * @type string
+ */
+ protected $name_long = "Solder of Fortune II";
+
+ /**
+ * The client join link
+ *
+ * @type string
+ */
+ protected $join_link = "sof2mp://%s:%d/";
+}
diff --git a/third_party/gameq/GameQ/Protocols/Source.php b/third_party/gameq/GameQ/Protocols/Source.php
index 9e4cb5dd..dbf9212a 100644
--- a/third_party/gameq/GameQ/Protocols/Source.php
+++ b/third_party/gameq/GameQ/Protocols/Source.php
@@ -50,7 +50,7 @@ class Source extends Protocol
*/
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_DETAILS => "\xFF\xFF\xFF\xFFTSource Engine Query\x00%s",
self::PACKET_PLAYERS => "\xFF\xFF\xFF\xFF\x55%s",
self::PACKET_RULES => "\xFF\xFF\xFF\xFF\x56%s",
];
diff --git a/third_party/gameq/GameQ/Protocols/Swat4.php b/third_party/gameq/GameQ/Protocols/Swat4.php
new file mode 100644
index 00000000..7b8e1200
--- /dev/null
+++ b/third_party/gameq/GameQ/Protocols/Swat4.php
@@ -0,0 +1,50 @@
+.
+ */
+
+namespace GameQ\Protocols;
+
+/**
+ * Class Swat4
+ *
+ * @package GameQ\Protocols
+ *
+ * @author Wilson Jesus <>
+ */
+class Swat4 extends Gamespy2
+{
+ /**
+ * String name of this protocol class
+ *
+ * @type string
+ */
+ protected $name = 'swat4';
+
+ /**
+ * Longer string name of this protocol class
+ *
+ * @type string
+ */
+ protected $name_long = "SWAT 4";
+
+ /**
+ * query_port = client_port + 1
+ *
+ * @type int
+ */
+ protected $port_diff = 1;
+}
diff --git a/third_party/gameq/GameQ/Protocols/Teamspeak3.php b/third_party/gameq/GameQ/Protocols/Teamspeak3.php
index c66f6a44..24c0d722 100644
--- a/third_party/gameq/GameQ/Protocols/Teamspeak3.php
+++ b/third_party/gameq/GameQ/Protocols/Teamspeak3.php
@@ -1,4 +1,5 @@
options[Server::SERVER_OPTIONS_QUERY_PORT])
+ if (
+ !isset($this->options[Server::SERVER_OPTIONS_QUERY_PORT])
|| empty($this->options[Server::SERVER_OPTIONS_QUERY_PORT])
) {
throw new Exception(__METHOD__ . " Missing required setting '" . Server::SERVER_OPTIONS_QUERY_PORT . "'.");
diff --git a/third_party/gameq/GameQ/Protocols/Urbanterror.php b/third_party/gameq/GameQ/Protocols/Urbanterror.php
new file mode 100644
index 00000000..682f91e6
--- /dev/null
+++ b/third_party/gameq/GameQ/Protocols/Urbanterror.php
@@ -0,0 +1,49 @@
+.
+ */
+
+namespace GameQ\Protocols;
+
+/**
+ * Urban Terror Class
+ *
+ * @package GameQ\Protocols
+ * @author Austin Bischoff
+ */
+class Urbanterror extends Quake3
+{
+ /**
+ * String name of this protocol class
+ *
+ * @type string
+ */
+ protected $name = 'urbanterror';
+
+ /**
+ * Longer string name of this protocol class
+ *
+ * @type string
+ */
+ protected $name_long = "Urban Terror";
+
+ /**
+ * The client join link
+ *
+ * @type string
+ */
+ protected $join_link = "urt://%s:%d/";
+}
diff --git a/third_party/gameq/GameQ/Protocols/Valheim.php b/third_party/gameq/GameQ/Protocols/Valheim.php
new file mode 100644
index 00000000..106a66e8
--- /dev/null
+++ b/third_party/gameq/GameQ/Protocols/Valheim.php
@@ -0,0 +1,41 @@
+.
+ */
+
+namespace GameQ\Protocols;
+
+/**
+ * Class Valheim
+ *
+ * @package GameQ\Protocols
+ *
+ */
+class Valheim extends Source
+{
+ /**
+ * String name of this protocol class
+ *
+ * @type string
+ */
+ protected $name = 'valheim';
+ /**
+ * Longer string name of this protocol class
+ *
+ * @type string
+ */
+ protected $name_long = "Valheim";
+}
diff --git a/third_party/gameq/GameQ/Protocols/Ventrilo.php b/third_party/gameq/GameQ/Protocols/Ventrilo.php
index 8a1e0e8e..6986bedc 100644
--- a/third_party/gameq/GameQ/Protocols/Ventrilo.php
+++ b/third_party/gameq/GameQ/Protocols/Ventrilo.php
@@ -778,11 +778,11 @@ class Ventrilo extends Protocol
$characterCount = count($chars);
$key = 0;
- for ($i = 1; $i <= $characterCount; $i++) {
- $chars[$i] -= ($table[$a2] + (($i - 1) % 5)) & 0xFF;
+ for ($index = 1; $index <= $characterCount; $index++) {
+ $chars[$index] -= ($table[$a2] + (($index - 1) % 5)) & 0xFF;
$a2 = ($a2 + $a1) & 0xFF;
- if (($i % 2) == 0) {
- $short_array = unpack("n1", pack("C2", $chars[$i - 1], $chars[$i]));
+ if (($index % 2) == 0) {
+ $short_array = unpack("n1", pack("C2", $chars[$index - 1], $chars[$index]));
$header_items[$key] = $short_array[1];
++$key;
}
@@ -818,10 +818,10 @@ class Ventrilo extends Protocol
$data = "";
$characterCount = count($chars);
- for ($i = 1; $i <= $characterCount; $i++) {
- $chars[$i] -= ($table[$a2] + (($i - 1) % 72)) & 0xFF;
+ for ($index = 1; $index <= $characterCount; $index++) {
+ $chars[$index] -= ($table[$a2] + (($index - 1) % 72)) & 0xFF;
$a2 = ($a2 + $a1) & 0xFF;
- $data .= chr($chars[$i]);
+ $data .= chr($chars[$index]);
}
//@todo: Check CRC ???
$decrypted[$header_items['pck']] = $data;
diff --git a/third_party/gameq/GameQ/Query/Native.php b/third_party/gameq/GameQ/Query/Native.php
index b078c9c4..24200b0c 100644
--- a/third_party/gameq/GameQ/Query/Native.php
+++ b/third_party/gameq/GameQ/Query/Native.php
@@ -112,6 +112,12 @@ class Native extends Core
// Set blocking mode
stream_set_blocking($this->socket, $this->blocking);
+
+ // Set the read buffer
+ stream_set_read_buffer($this->socket, 0);
+
+ // Set the write buffer
+ stream_set_write_buffer($this->socket, 0);
} else {
// Reset socket
$this->socket = null;
@@ -193,7 +199,7 @@ class Native extends Core
/* @var $socket resource */
// See if we have a response
- if (($response = fread($socket, 8192)) === false) {
+ if (($response = fread($socket, 32768)) === false) {
continue; // No response yet so lets continue.
}
diff --git a/third_party/gameq/GameQ/Result.php b/third_party/gameq/GameQ/Result.php
index 1fe33d89..7023f17a 100644
--- a/third_party/gameq/GameQ/Result.php
+++ b/third_party/gameq/GameQ/Result.php
@@ -37,8 +37,8 @@ class Result
/**
* Adds variable to results
*
- * @param string $name Variable name
- * @param string $value Variable value
+ * @param string $name Variable name
+ * @param string|array $value Variable value
*/
public function add($name, $value)
{
@@ -49,8 +49,8 @@ class Result
/**
* Adds player variable to output
*
- * @param string $name Variable name
- * @param string $value Variable value
+ * @param string $name Variable name
+ * @param string $value Variable value
*/
public function addPlayer($name, $value)
{
@@ -61,8 +61,8 @@ class Result
/**
* Adds player variable to output
*
- * @param string $name Variable name
- * @param string $value Variable value
+ * @param string $name Variable name
+ * @param string $value Variable value
*/
public function addTeam($name, $value)
{
@@ -87,7 +87,8 @@ class Result
// Find the first entry that doesn't have this variable
$found = false;
- for ($i = 0; $i != count($this->result[$sub]); $i++) {
+ $count = count($this->result[$sub]);
+ for ($i = 0; $i != $count; $i++) {
if (!isset($this->result[$sub][$i][$key])) {
$this->result[$sub][$i][$key] = $value;
$found = true;
@@ -99,6 +100,8 @@ class Result
if (!$found) {
$this->result[$sub][][$key] = $value;
}
+
+ unset($count);
}
/**
@@ -115,7 +118,7 @@ class Result
/**
* Return a single variable
*
- * @param string $var The variable name
+ * @param string $var The variable name
*
* @return mixed The variable value
*/