Arma3.php 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. <?php
  2. /**
  3. * This file is part of GameQ.
  4. *
  5. * GameQ is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU Lesser General Public License as published by
  7. * the Free Software Foundation; either version 3 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * GameQ is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU Lesser General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU Lesser General Public License
  16. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. namespace GameQ\Protocols;
  19. use GameQ\Buffer;
  20. use GameQ\Result;
  21. /**
  22. * Class Armed Assault 3
  23. *
  24. * Rules protocol reference: https://community.bistudio.com/wiki/Arma_3_ServerBrowserProtocol2
  25. *
  26. * @package GameQ\Protocols
  27. * @author Austin Bischoff <[email protected]>
  28. * @author Memphis017 <https://github.com/Memphis017>
  29. */
  30. class Arma3 extends Source
  31. {
  32. /**
  33. * Defines the names for the specific game DLCs
  34. *
  35. * @var array
  36. */
  37. protected $dlcNames = [
  38. 'af82811b' => 'Karts',
  39. '94f76a1a' => 'Marksmen',
  40. 'd0356eec' => 'Helicopters',
  41. '19984a71' => 'Zeus',
  42. '7fb4b1f3' => 'Apex',
  43. '49c2c12b' => 'Jets',
  44. '7e766e18' => 'Laws of War',
  45. '99d71f90' => 'Malden',
  46. 'a8b10cdf' => 'Tac-Ops',
  47. '37680ce8' => 'Tanks',
  48. '43f9c377' => 'Contact',
  49. 'c4979557' => 'Enoch',
  50. ];
  51. /**
  52. * String name of this protocol class
  53. *
  54. * @type string
  55. */
  56. protected $name = 'arma3';
  57. /**
  58. * Longer string name of this protocol class
  59. *
  60. * @type string
  61. */
  62. protected $name_long = "Arma3";
  63. /**
  64. * Query port = client_port + 1
  65. *
  66. * @type int
  67. */
  68. protected $port_diff = 1;
  69. /**
  70. * Process the rules since Arma3 changed their response for rules
  71. *
  72. * @param Buffer $buffer
  73. *
  74. * @return array
  75. * @throws \GameQ\Exception\Protocol
  76. */
  77. protected function processRules(Buffer $buffer)
  78. {
  79. // Total number of packets, burn it
  80. $buffer->readInt16();
  81. // Will hold the data string
  82. $data = '';
  83. // Loop until we run out of strings
  84. while ($buffer->getLength()) {
  85. // Burn the delimiters (i.e. \x01\x04\x00)
  86. $buffer->readString();
  87. // Add the data to the string, we are reassembling it
  88. $data .= $buffer->readString();
  89. }
  90. // Restore escaped sequences
  91. $data = str_replace(["\x01\x01", "\x01\x02", "\x01\x03"], ["\x01", "\x00", "\xFF"], $data);
  92. // Make a new buffer with the reassembled data
  93. $responseBuffer = new Buffer($data);
  94. // Kill the old buffer, should be empty
  95. unset($buffer, $data);
  96. // Set the result to a new result instance
  97. $result = new Result();
  98. // Get results
  99. $result->add('rules_protocol_version', $responseBuffer->readInt8());
  100. $result->add('overflow', $responseBuffer->readInt8());
  101. $dlcBit = decbin($responseBuffer->readInt8()); // Grab DLC bit 1 and use it later
  102. $dlcBit2 = decbin($responseBuffer->readInt8()); // Grab DLC bit 2 and use it later
  103. $dlcCount = substr_count($dlcBit, '1') + substr_count($dlcBit2, '1'); // Count the DLCs
  104. // Grab difficulty so we can man handle it...
  105. $difficulty = $responseBuffer->readInt8();
  106. // Process difficulty
  107. $result->add('3rd_person', $difficulty >> 7);
  108. $result->add('advanced_flight_mode', ($difficulty >> 6) & 1);
  109. $result->add('difficulty_ai', ($difficulty >> 3) & 3);
  110. $result->add('difficulty_level', $difficulty & 3);
  111. unset($difficulty);
  112. // Crosshair
  113. $result->add('crosshair', $responseBuffer->readInt8());
  114. // Loop over the DLC bit so we can pull in the info for the DLC (if enabled)
  115. for ($x = 0; $x < $dlcCount; $x++) {
  116. $dlcHash = dechex($responseBuffer->readInt32());
  117. isset($this->dlcNames[$dlcHash]) ?
  118. $result->addSub('dlcs', 'name', $this->dlcNames[$dlcHash])
  119. : $result->addSub('dlcs', 'name', 'Unknown');
  120. $result->addSub('dlcs', 'hash', $dlcHash);
  121. }
  122. // No longer needed
  123. unset($dlcBit, $dlcBit2, $dlcCount, $dlcHash);
  124. // Grab the mod count
  125. $modCount = $responseBuffer->readInt8();
  126. // Add mod count
  127. $result->add('mod_count', $modCount);
  128. // Loop the mod count and add them
  129. for ($x = 0; $x < $modCount; $x++) {
  130. // Add the mod to the list
  131. $result->addSub('mods', 'hash', dechex($responseBuffer->readInt32()));
  132. $result->addSub('mods', 'steam_id', hexdec($responseBuffer->readPascalString(0, true)));
  133. $result->addSub('mods', 'name', $responseBuffer->readPascalString(0, true));
  134. }
  135. unset($modCount, $x);
  136. // Get the signatures count
  137. $signatureCount = $responseBuffer->readInt8();
  138. $result->add('signature_count', $signatureCount);
  139. // Make signatures array
  140. $signatures = [];
  141. // Loop until we run out of signatures
  142. for ($x = 0; $x < $signatureCount; $x++) {
  143. $signatures[] = $responseBuffer->readPascalString(0, true);
  144. }
  145. // Add as a simple array
  146. $result->add('signatures', $signatures);
  147. unset($responseBuffer, $signatureCount, $signatures, $x);
  148. return $result->fetch();
  149. }
  150. }