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(); }
/** * 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() !== "") { throw new GameQ_ProtocolsException('Header error in Red Faction'); return FALSE; } // Dunno while ($buf->read() !== "") { } $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(); }
/** * 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); }
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; }
/** * 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(); }
/** * 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(); }
/** * Process the player return data */ 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]); // Make a new buffer $buf = new GameQ_Buffer($data); // Parse players while ($buf->getLength()) { // Player id if (($id = $buf->readInt32()) === 0) { break; } $result->addPlayer('id', $id); $result->addPlayer('name', $this->_readUnrealString($buf)); $result->addPlayer('ping', $buf->readInt32()); $result->addPlayer('score', $buf->readInt32()); $buf->skip(4); } unset($buf, $id); // Return the result return $result->fetch(); }
/** * 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(); }
/** * 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(); }
/** * 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(); }
/** * Process the players response */ protected function process_players() { // Make sure we have a valid response if (!$this->hasValidResponse(self::PACKET_PLAYERS)) { return array(); } // Let's preprocess the status $buffer = $this->preProcess($this->packets_response[self::PACKET_PLAYERS]); // Set the result to a new result instance $result = new GameQ_Result(); // The first line holds the column names, data returned is in column/row format $columns = explode("\t", trim($buffer->readString("\n")), 16); // Loop thru the rows until we run out of information while ($buffer->getLength()) { // Grab the row, which is a tabbed list of items // Check for end of packet if (($row = trim($buffer->readString("\n"))) == 'OK') { break; } // Explode and merge the data with the columns, then parse $data = array_combine($columns, explode("\t", $row, 16)); foreach ($data as $key => $value) { // Now add the data to the result $result->addPlayer($key, $value); } } unset($data, $buffer, $row, $columns, $key, $value); 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); } }
/** * 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(); }
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(); }
/** * 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(); }
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 Tshock protocol is invalid."); } // Check the status response if ($json->status != 200) { throw new GameQ_ProtocolsException("JSON status from Tshock protocol response was '{$json->status}', expected '200'."); } // 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', $json->name); $result->add('game_port', $json->port); $result->add('numplayers', $json->playercount); $result->add('maxplayers', $json->maxplayers); $result->add('map', $json->world); $result->add('gameport', $json->port); // Players are a comma(space) seperated list $players = explode(', ', $json->players); // Do the players foreach ($players as $player) { $result->addPlayer('name', $player); } return $result->fetch(); }
protected function process_players() { // Make sure we have a valid response if (!$this->hasValidResponse(self::PACKET_PLAYERS)) { return array(); } // Let's preprocess the status $buffer = $this->preProcess($this->packets_response[self::PACKET_PLAYERS]); // Process the buffer response $data = $this->parse_response($buffer); // Set the result to a new result instance $result = new GameQ_Result(); foreach ($data as $player) { // filter out query clients if ($player['client_type'] == 1) { continue; } $player['client_nickname'] = htmlentities($player['client_nickname'], ENT_QUOTES, "UTF-8"); foreach ($player as $key => $value) { $result->addPlayer($key, $value); } } unset($data, $buffer, $player, $key, $value); 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(); }
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(); }