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\Helpers\Str;
24: use GameQ\Protocol;
25: use GameQ\Result;
26:
27: /**
28: * GameSpy Protocol class
29: *
30: * @author Austin Bischoff <austin@codebeard.com>
31: */
32: class Gamespy extends Protocol
33: {
34: /**
35: * Array of packets we want to look up.
36: * Each key should correspond to a defined method in this or a parent class
37: *
38: * @var array
39: */
40: protected $packets = [
41: self::PACKET_STATUS => "\x5C\x73\x74\x61\x74\x75\x73\x5C",
42: ];
43:
44: /**
45: * The query protocol used to make the call
46: *
47: * @var string
48: */
49: protected $protocol = 'gamespy';
50:
51: /**
52: * String name of this protocol class
53: *
54: * @var string
55: */
56: protected $name = 'gamespy';
57:
58: /**
59: * Longer string name of this protocol class
60: *
61: * @var string
62: */
63: protected $name_long = "GameSpy Server";
64:
65: /**
66: * Process the response for this protocol
67: *
68: * @return array
69: * @throws Exception
70: */
71: public function processResponse()
72: {
73: // Holds the processed packets so we can sort them in case they come in an unordered
74: $processed = [];
75:
76: // Iterate over the packets
77: foreach ($this->packets_response as $response) {
78: // Check to see if we had a preg_match error
79: if (($match = preg_match("#^(.*)\\\\queryid\\\\([^\\\\]+)(\\\\|$)#", $response, $matches)) === false
80: || $match != 1
81: ) {
82: throw new Exception(__METHOD__ . " An error occurred while parsing the packets for 'queryid'");
83: }
84:
85: // Multiply so we move the decimal point out of the way, if there is one
86: $key = (int)(floatval($matches[2]) * 1000);
87:
88: // Add this packet to the processed
89: $processed[$key] = $matches[1];
90: }
91:
92: // Sort the new array to make sure the keys (query ids) are in the proper order
93: ksort($processed, SORT_NUMERIC);
94:
95: // Create buffer and offload processing
96: return $this->processStatus(new Buffer(implode('', $processed)));
97: }
98:
99: // Internal methods
100:
101: /**
102: * Handle processing the status buffer
103: *
104: * @param Buffer $buffer
105: *
106: * @return array
107: */
108: protected function processStatus(Buffer $buffer)
109: {
110: // Set the result to a new result instance
111: $result = new Result();
112:
113: // By default dedicted
114: $result->add('dedicated', 1);
115:
116: // Lets peek and see if the data starts with a \
117: if ($buffer->lookAhead(1) == '\\') {
118: // Burn the first one
119: $buffer->skip(1);
120: }
121:
122: // Explode the data
123: $data = explode('\\', $buffer->getBuffer());
124:
125: // No longer needed
126: unset($buffer);
127:
128: // Init some vars
129: $numPlayers = 0;
130: $numTeams = 0;
131:
132: $itemCount = count($data);
133:
134: // Check to make sure we have more than 1 item in the array before trying to loop
135: if (count($data) > 1) {
136: // Now lets loop the array since we have items
137: for ($x = 0; $x < $itemCount; $x += 2) {
138: // Set some local vars
139: $key = $data[$x];
140: $val = $data[$x + 1];
141:
142: // Check for <variable>_<count> variable (i.e players)
143: if (($suffix = strrpos($key, '_')) !== false && is_numeric(substr($key, $suffix + 1))) {
144: // See if this is a team designation
145: if (substr($key, 0, $suffix) == 'teamname') {
146: $result->addTeam('teamname', $val);
147: $numTeams++;
148: } else {
149: // Its a player
150: if (substr($key, 0, $suffix) == 'playername') {
151: $numPlayers++;
152: }
153: $result->addPlayer(substr($key, 0, $suffix), Str::isoToUtf8($val));
154: }
155: } else {
156: // Regular variable so just add the value.
157: $result->add($key, $val);
158: }
159: }
160: }
161:
162: // Add the player and team count
163: $result->add('num_players', $numPlayers);
164: $result->add('num_teams', $numTeams);
165:
166: // Unset some stuff to free up memory
167: unset($data, $key, $val, $suffix, $x, $itemCount);
168:
169: // Return the result
170: return $result->fetch();
171: }
172: }
173: