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