示例#1
0
 public function preprocess($packets)
 {
     $result = array();
     // Get packet index, remove header
     foreach ($packets as $packet) {
         $p = new GameQ_Buffer($packet);
         $p->skip(14);
         $cur_packet = $p->readInt16();
         $result[$cur_packet] = $p->getBuffer();
     }
     // Sort packets, reset index
     ksort($result);
     $result = array_values($result);
     // 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($result); $i < $x - 1; $i++) {
         // First packet
         $fst = substr($result[$i], 0, -1);
         // Second packet
         $snd = $result[$i + 1];
         // Get last variable from first packet
         $fstvar = substr($fst, strrpos($fst, "") + 1);
         // Get first variable from last packet
         $snd = substr($snd, strpos($snd, "") + 2);
         $sndvar = substr($snd, 0, strpos($snd, ""));
         // Check if fstvar is a substring of sndvar
         // If so, remove it from the first string
         if (strpos($sndvar, $fstvar) !== false) {
             $result[$i] = preg_replace("#(\\x00[^\\x00]+\\x00)\$#", "", $result[$i]);
         }
     }
     // Join packets
     return implode("", $result);
 }
示例#2
0
 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();
 }
示例#3
0
 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();
 }
示例#4
0
 protected function parsePlayerTeamInfoNew(GameQ_Buffer &$buf, GameQ_Result &$result)
 {
     // Read the buffer and replace the team_ sub-section under the players section becasue it is broke
     $buf_fixed = preg_replace('/team_(.*)score_/m', 'score_', $buf->getBuffer());
     // Replace the buffer with the "fixed" buffer
     $buf = new GameQ_Buffer($buf_fixed);
     unset($buf_fixed);
     // Now we continue on with the parent
     return parent::parsePlayerTeamInfo($buf, $result);
 }
示例#5
0
 /**
  * Overload the parse players because the data coming back is different
  * @see GameQ_Protocols_Quake3::parsePlayers()
  */
 protected function parsePlayers(GameQ_Result &$result, $players_info)
 {
     // Explode the arrays out
     $players = explode("\n", $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(" "));
         $result->addPlayer('ping', $buf->readString(" "));
         // Skip first "
         $buf->skip(1);
         // Add player name
         $result->addPlayer('name', trim($buf->readString('"')));
         // Skip space
         $buf->skip(1);
         // Add team
         $result->addPlayer('team', $buf->read());
     }
     // Free some memory
     unset($buf, $players, $player_info);
 }
示例#6
0
 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;
 }
示例#7
0
 /**
  * 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;
 }
示例#8
0
 /**
  * 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 {
                 if (substr($key, 0, $suffix) == 'playername') {
                     $num_players++;
                 }
                 $result->addPlayer(substr($key, 0, $suffix), $val);
             }
         } else {
             $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();
 }
示例#9
0
 /**
  * Read an Unreal Engine 2 string
  *
  * Adapted from original GameQ code
  *
  * @param GameQ_Buffer $buf
  * @return string <string, mixed>
  */
 private function _readUnrealString(GameQ_Buffer &$buf)
 {
     // Normal pascal string
     if (ord($buf->lookAhead(1)) < 129) {
         return $buf->readPascalString(1);
     }
     // UnrealEngine2 color-coded string
     $length = ($buf->readInt8() - 128) * 2 - 3;
     $encstr = $buf->read($length);
     $buf->skip(3);
     // Remove color-code tags
     $encstr = preg_replace('~\\x5e\\0\\x23\\0..~s', '', $encstr);
     // Remove every second character
     // The string is UCS-2, this approximates converting to latin-1
     $str = '';
     for ($i = 0, $ii = strlen($encstr); $i < $ii; $i += 2) {
         $str .= $encstr[$i];
     }
     return $str;
 }
示例#10
0
 /**
  * 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
         if ($buf->getLength() <= 1) {
             break;
         }
         // Only player information is available
         $result->addPlayer('name', $buf->readPascalString(1, TRUE));
     }
     unset($buf);
     return $result->fetch();
 }
示例#11
0
 /**
  * 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('steamappid', 1250);
     // ;)
     $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('ping', $buf->readInt32());
     // 0
     // @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();
 }
示例#12
0
 /**
  * Verify the header of the returned response packet
  *
  * @param GameQ_Buffer $buffer
  * @throws GameQ_ProtocolsException
  */
 protected function verify_header(GameQ_Buffer &$buffer)
 {
     // Check length
     if ($buffer->getLength() < 6) {
         throw new GameQ_ProtocolsException(__METHOD__ . ": Length of buffer is not long enough");
         return FALSE;
     }
     // Check to make sure the header is correct
     if (($type = trim($buffer->readString("\n"))) != '[TS]') {
         throw new GameQ_ProtocolsException(__METHOD__ . ": Header returned did not match.  Returned type {$type}");
         return FALSE;
     }
     // Verify the response and return
     return $this->verify_response(trim($buffer->readString("\n")));
 }
示例#13
0
 /**
  * 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();
 }
示例#14
0
 /**
  * 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("\f", $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();
 }
示例#15
0
 /**
  * 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);
     // Skip the header
     $buf->skip(6);
     $result->add('mod', $buf->readPascalString());
     $result->add('gametype', $buf->readPascalString());
     $result->add('map', $buf->readPascalString());
     // Grab the flag
     $flag = $buf->read();
     $bit = 1;
     foreach (array('dedicated', 'password', 'linux', 'tournament', 'no_alias') as $var) {
         $value = $flag & $bit ? 1 : 0;
         $result->add($var, $value);
         $bit *= 2;
     }
     $result->add('num_players', $buf->readInt8());
     $result->add('max_players', $buf->readInt8());
     $result->add('num_bots', $buf->readInt8());
     $result->add('cpu', $buf->readInt16());
     $result->add('info', $buf->readPascalString());
     $buf->skip(2);
     // Do teams
     $num_teams = $buf->read();
     $result->add('num_teams', $num_teams);
     $buf->skip();
     for ($i = 0; $i < $num_teams; $i++) {
         $result->addTeam('name', $buf->readString("\t"));
         $result->addTeam('score', $buf->readString("\n"));
     }
     // Do players
     // @todo:  No code here to do players, no docs either, need example server with players
     unset($buf, $data);
     return $result->fetch();
 }
示例#16
0
 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();
 }
示例#17
0
 /**
  * Parse the buffer response into an array and return it
  *
  * @param GameQ_Buffer $buffer
  */
 protected function parse_response(GameQ_Buffer &$buffer)
 {
     // The data is in the first block
     $data = explode('|', trim($buffer->readString("\n")));
     // The response is the last block
     $this->verify_response(trim($buffer->readString("\n")));
     $return = array();
     foreach ($data as $part) {
         $variables = explode(' ', $part);
         $info = array();
         foreach ($variables as $variable) {
             // Explode and make sure we always have 2 items in the array
             list($key, $value) = array_pad(explode('=', $variable, 2), 2, '');
             $info[$key] = str_replace(array_keys($this->string_replace), array_values($this->string_replace), $value);
         }
         // Add this to the return
         $return[] = $info;
     }
     return $return;
 }