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:
19: namespace GameQ\Protocols;
20:
21: use GameQ\Buffer;
22: use GameQ\Exception\Protocol as Exception;
23: use GameQ\Protocol;
24: use GameQ\Result;
25:
26: /**
27: * StarMade Protocol Class
28: *
29: * StarMade server query protocol class
30: *
31: * Credit to Robin Promesberger <schema@star-made.org> for providing Java based querying as a roadmap
32: *
33: * @author Austin Bischoff <austin@codebeard.com>
34: */
35: class Starmade extends Protocol
36: {
37: /**
38: * Array of packets we want to query.
39: *
40: * @var array
41: */
42: protected $packets = [
43: self::PACKET_STATUS => "\x00\x00\x00\x09\x2a\xff\xff\x01\x6f\x00\x00\x00\x00",
44: ];
45:
46: /**
47: * The transport mode for this protocol is TCP
48: *
49: * @var string
50: */
51: protected $transport = self::TRANSPORT_TCP;
52:
53: /**
54: * The query protocol used to make the call
55: *
56: * @var string
57: */
58: protected $protocol = 'starmade';
59:
60: /**
61: * String name of this protocol class
62: *
63: * @var string
64: */
65: protected $name = 'starmade';
66:
67: /**
68: * Longer string name of this protocol class
69: *
70: * @var string
71: */
72: protected $name_long = "StarMade";
73:
74: /**
75: * Normalize settings for this protocol
76: *
77: * @var array
78: */
79: protected $normalize = [
80: // General
81: 'general' => [
82: // target => source
83: 'dedicated' => 'dedicated',
84: 'hostname' => 'hostname',
85: 'maxplayers' => 'max_players',
86: 'numplayers' => 'num_players',
87: 'password' => 'password',
88: ],
89: ];
90:
91: /**
92: * Process the response for the StarMade server
93: *
94: * @return array
95: * @throws \GameQ\Exception\Protocol
96: */
97: public function processResponse()
98: {
99: // Implode the packets, not sure if there is any split logic for multiple packets
100: $buffer = new Buffer(implode('', $this->packets_response), Buffer::NUMBER_TYPE_BIGENDIAN);
101:
102: // Get the passed length in the data side of the packet
103: $buffer->readInt32Signed();
104:
105: // Read off the timestamp (in milliseconds)
106: $buffer->readInt64();
107:
108: // Burn the check id == 42
109: $buffer->readInt8();
110:
111: // Read packetId, unused
112: $buffer->readInt16Signed();
113:
114: // Read commandId, unused
115: $buffer->readInt8Signed();
116:
117: // Read type, unused
118: $buffer->readInt8Signed();
119:
120: $parsed = $this->parseServerParameters($buffer);
121:
122: // Set the result to a new result instance
123: $result = new Result();
124:
125: // Best guess info version is the type of response to expect. As of this commit the version is "2".
126: $result->add('info_version', $parsed[0]);
127: $result->add('version', $parsed[1]);
128: $result->add('hostname', $parsed[2]);
129: $result->add('game_descr', $parsed[3]);
130: $result->add('start_time', $parsed[4]);
131: $result->add('num_players', $parsed[5]);
132: $result->add('max_players', $parsed[6]);
133: $result->add('dedicated', 1); // All servers are dedicated as far as I can tell
134: $result->add('password', 0); // Unsure if you can password servers, cant read that value
135: //$result->add('map', 'Unknown');
136:
137: unset($parsed);
138:
139: return $result->fetch();
140: }
141:
142: /**
143: * Parse the server response parameters
144: *
145: * @SuppressWarnings(PHPMD.CyclomaticComplexity)
146: *
147: * @param \GameQ\Buffer $buffer
148: * @return array
149: * @throws \GameQ\Exception\Protocol
150: */
151: protected function parseServerParameters(Buffer &$buffer)
152: {
153: // Init the parsed data array
154: $parsed = [];
155:
156: // Read the number of parameters to parse
157: $parameterSize = $buffer->readInt32Signed();
158:
159: // Iterate over the parameter size
160: for ($i = 0; $i < $parameterSize; $i++) {
161: // Read the type of return this is
162: $dataType = $buffer->readInt8Signed();
163:
164: switch ($dataType) {
165: // 32-bit int
166: case 1:
167: $parsed[$i] = $buffer->readInt32Signed();
168: break;
169:
170: // 64-bit int
171: case 2:
172: $parsed[$i] = $buffer->readInt64();
173: break;
174:
175: // Float
176: case 3:
177: $parsed[$i] = $buffer->readFloat32();
178: break;
179:
180: // String
181: case 4:
182: // The first 2 bytes are the string length
183: $strLength = $buffer->readInt16Signed();
184:
185: // Read the above length from the buffer
186: $parsed[$i] = $buffer->read($strLength);
187:
188: unset($strLength);
189: break;
190:
191: // Boolean
192: case 5:
193: $parsed[$i] = (bool)$buffer->readInt8Signed();
194: break;
195:
196: // 8-bit int
197: case 6:
198: $parsed[$i] = $buffer->readInt8Signed();
199: break;
200:
201: // 16-bit int
202: case 7:
203: $parsed[$i] = $buffer->readInt16Signed();
204: break;
205:
206: // Array
207: case 8:
208: // Not implemented
209: throw new Exception("StarMade array parsing is not implemented!");
210: }
211: }
212:
213: return $parsed;
214: }
215: }
216: