1
0

Ffow.php 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  1. <?php
  2. namespace GameQ\Protocols;
  3. use GameQ\Protocol;
  4. use GameQ\Buffer;
  5. use GameQ\Result;
  6. use GameQ\Exception\Protocol as Exception;
  7. /**
  8. * Frontlines Fuel of War Protocol Class
  9. *
  10. * Handles processing ffow servers
  11. *
  12. * Class is incomplete due to lack of players to test against.
  13. * http://wiki.hlsw.net/index.php/FFOW_Protocol
  14. *
  15. * @package GameQ\Protocols
  16. */
  17. class Ffow extends Protocol
  18. {
  19. /**
  20. * Array of packets we want to look up.
  21. * Each key should correspond to a defined method in this or a parent class
  22. *
  23. * @type array
  24. */
  25. protected $packets = [
  26. self::PACKET_CHALLENGE => "\xFF\xFF\xFF\xFF\x57",
  27. self::PACKET_RULES => "\xFF\xFF\xFF\xFF\x56%s",
  28. self::PACKET_PLAYERS => "\xFF\xFF\xFF\xFF\x55%s",
  29. self::PACKET_INFO => "\xFF\xFF\xFF\xFF\x46\x4C\x53\x51",
  30. ];
  31. /**
  32. * Use the response flag to figure out what method to run
  33. *
  34. * @type array
  35. */
  36. protected $responses = [
  37. "\xFF\xFF\xFF\xFF\x49\x02" => 'processInfo', // I
  38. "\xFF\xFF\xFF\xFF\x45\x00" => 'processRules', // E
  39. "\xFF\xFF\xFF\xFF\x44\x00" => 'processPlayers', // D
  40. ];
  41. /**
  42. * The query protocol used to make the call
  43. *
  44. * @type string
  45. */
  46. protected $protocol = 'ffow';
  47. /**
  48. * String name of this protocol class
  49. *
  50. * @type string
  51. */
  52. protected $name = 'ffow';
  53. /**
  54. * Longer string name of this protocol class
  55. *
  56. * @type string
  57. */
  58. protected $name_long = "Frontlines Fuel of War";
  59. /**
  60. * The client join link
  61. *
  62. * @type string
  63. */
  64. protected $join_link = null;
  65. /**
  66. * query_port = client_port + 2
  67. *
  68. * @type int
  69. */
  70. protected $port_diff = 2;
  71. /**
  72. * Normalize settings for this protocol
  73. *
  74. * @type array
  75. */
  76. protected $normalize = [
  77. // General
  78. 'general' => [
  79. // target => source
  80. 'gametype' => 'gamemode',
  81. 'hostname' => 'servername',
  82. 'mapname' => 'mapname',
  83. 'maxplayers' => 'max_players',
  84. 'mod' => 'modname',
  85. 'numplayers' => 'num_players',
  86. 'password' => 'password',
  87. ],
  88. // Individual
  89. 'player' => [
  90. 'name' => 'name',
  91. 'ping' => 'ping',
  92. 'score' => 'frags',
  93. ],
  94. ];
  95. /**
  96. * Parse the challenge response and apply it to all the packet types
  97. *
  98. * @param \GameQ\Buffer $challenge_buffer
  99. *
  100. * @return bool
  101. * @throws \GameQ\Exception\Protocol
  102. */
  103. public function challengeParseAndApply(Buffer $challenge_buffer)
  104. {
  105. // Burn padding
  106. $challenge_buffer->skip(5);
  107. // Apply the challenge and return
  108. return $this->challengeApply($challenge_buffer->read(4));
  109. }
  110. /**
  111. * Handle response from the server
  112. *
  113. * @return mixed
  114. * @throws Exception
  115. */
  116. public function processResponse()
  117. {
  118. // Init results
  119. $results = [];
  120. foreach ($this->packets_response as $response) {
  121. $buffer = new Buffer($response);
  122. // Figure out what packet response this is for
  123. $response_type = $buffer->read(6);
  124. // Figure out which packet response this is
  125. if (!array_key_exists($response_type, $this->responses)) {
  126. throw new Exception(__METHOD__ . " response type '" . bin2hex($response_type) . "' is not valid");
  127. }
  128. // Now we need to call the proper method
  129. $results = array_merge(
  130. $results,
  131. call_user_func_array([$this, $this->responses[$response_type]], [$buffer])
  132. );
  133. unset($buffer);
  134. }
  135. return $results;
  136. }
  137. /**
  138. * Handle processing the server information
  139. *
  140. * @param Buffer $buffer
  141. *
  142. * @return array
  143. */
  144. protected function processInfo(Buffer $buffer)
  145. {
  146. // Set the result to a new result instance
  147. $result = new Result();
  148. $result->add('servername', $buffer->readString());
  149. $result->add('mapname', $buffer->readString());
  150. $result->add('modname', $buffer->readString());
  151. $result->add('gamemode', $buffer->readString());
  152. $result->add('description', $buffer->readString());
  153. $result->add('version', $buffer->readString());
  154. $result->add('port', $buffer->readInt16());
  155. $result->add('num_players', $buffer->readInt8());
  156. $result->add('max_players', $buffer->readInt8());
  157. $result->add('dedicated', $buffer->readInt8());
  158. $result->add('os', $buffer->readInt8());
  159. $result->add('password', $buffer->readInt8());
  160. $result->add('anticheat', $buffer->readInt8());
  161. $result->add('average_fps', $buffer->readInt8());
  162. $result->add('round', $buffer->readInt8());
  163. $result->add('max_rounds', $buffer->readInt8());
  164. $result->add('time_left', $buffer->readInt16());
  165. unset($buffer);
  166. return $result->fetch();
  167. }
  168. /**
  169. * Handle processing the server rules
  170. *
  171. * @param Buffer $buffer
  172. *
  173. * @return array
  174. */
  175. protected function processRules(Buffer $buffer)
  176. {
  177. // Set the result to a new result instance
  178. $result = new Result();
  179. // Burn extra header
  180. $buffer->skip(1);
  181. // Read rules until we run out of buffer
  182. while ($buffer->getLength()) {
  183. $key = $buffer->readString();
  184. // Check for map
  185. if (strstr($key, "Map:")) {
  186. $result->addSub("maplist", "name", $buffer->readString());
  187. } else // Regular rule
  188. {
  189. $result->add($key, $buffer->readString());
  190. }
  191. }
  192. unset($buffer);
  193. return $result->fetch();
  194. }
  195. /**
  196. * Handle processing of player data
  197. *
  198. * @todo: Build this out when there is a server with players to test against
  199. *
  200. * @param Buffer $buffer
  201. *
  202. * @return array
  203. */
  204. protected function processPlayers(Buffer $buffer)
  205. {
  206. // Set the result to a new result instance
  207. $result = new Result();
  208. unset($buffer);
  209. return $result->fetch();
  210. }
  211. }