. */ namespace GameQ\Protocols; use GameQ\Protocol; use GameQ\Buffer; use GameQ\Result; use GameQ\Exception\Protocol as Exception; /** * Teeworlds Protocol class * * Only supports versions > 0.5 * * @author Austin Bischoff * @author Marcel Bößendörfer */ class Teeworlds extends Protocol { /** * Array of packets we want to look up. * Each key should correspond to a defined method in this or a parent class * * @type array */ protected $packets = [ self::PACKET_ALL => "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x67\x69\x65\x33\x05", // 0.5 Packet (not compatible, maybe some wants to implement "Teeworldsold") //self::PACKET_STATUS => "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFFgief", ]; /** * Use the response flag to figure out what method to run * * @type array */ protected $responses = [ "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xffinf35" => "processAll", ]; /** * The query protocol used to make the call * * @type string */ protected $protocol = 'teeworlds'; /** * String name of this protocol class * * @type string */ protected $name = 'teeworlds'; /** * Longer string name of this protocol class * * @type string */ protected $name_long = "Teeworlds Server"; /** * The client join link * * @type string */ protected $join_link = "steam://connect/%s:%d/"; /** * Normalize settings for this protocol * * @type array */ protected $normalize = [ // General 'general' => [ // target => source 'dedicated' => 'dedicated', 'hostname' => 'hostname', 'mapname' => 'map', 'maxplayers' => 'num_players_total', ], // Individual 'player' => [ 'name' => 'name', 'score' => 'score', ], ]; /** * Process the response * * @return array * @throws Exception */ public function processResponse() { // Holds the results $results = []; // Iterate over the packets foreach ($this->packets_response as $response) { // Make a buffer $buffer = new Buffer($response); // Grab the header $header = $buffer->readString(); // 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]], [$buffer]) ); } unset($buffer); return $results; } /** * Handle processing all of the data returned * * @param Buffer $buffer * * @return array */ protected function processAll(Buffer $buffer) { // Set the result to a new result instance $result = new Result(); // Always dedicated $result->add('dedicated', 1); $result->add('version', $buffer->readString()); $result->add('hostname', $buffer->readString()); $result->add('map', $buffer->readString()); $result->add('game_descr', $buffer->readString()); $result->add('flags', $buffer->readString()); // not sure about that $result->add('num_players', $buffer->readString()); $result->add('maxplayers', $buffer->readString()); $result->add('num_players_total', $buffer->readString()); $result->add('maxplayers_total', $buffer->readString()); // Players while ($buffer->getLength()) { $result->addPlayer('name', $buffer->readString()); $result->addPlayer('clan', $buffer->readString()); $result->addPlayer('flag', $buffer->readString()); $result->addPlayer('score', $buffer->readString()); $result->addPlayer('team', $buffer->readString()); } unset($buffer); return $result->fetch(); } }