Completed
Push — v3 ( 339589...25b7b0 )
by Austin
07:32
created

Quake2::processResponse()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 15
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 3

Importance

Changes 0
Metric Value
dl 0
loc 15
ccs 6
cts 6
cp 1
rs 9.4285
c 0
b 0
f 0
cc 3
eloc 6
nc 2
nop 0
crap 3
1
<?php
2
3
4
namespace GameQ\Protocols;
5
6
use GameQ\Protocol;
7
use GameQ\Buffer;
8
use GameQ\Result;
9
use GameQ\Exception\Protocol as Exception;
10
11
/**
12
 * Quake2 Protocol Class
13
 *
14
 * Handles processing Quake 3 servers
15
 *
16
 * @package GameQ\Protocols
17
 */
18
class Quake2 extends Protocol
19
{
20
    /**
21
     * Array of packets we want to look up.
22
     * Each key should correspond to a defined method in this or a parent class
23
     *
24
     * @type array
25
     */
26
    protected $packets = [
27
        self::PACKET_STATUS => "\xFF\xFF\xFF\xFFstatus\x00",
28
    ];
29
30
    /**
31
     * Use the response flag to figure out what method to run
32
     *
33
     * @type array
34
     */
35
    protected $responses = [
36
        "\xFF\xFF\xFF\xFF\x70\x72\x69\x6e\x74" => 'processStatus',
37
    ];
38
39
    /**
40
     * The query protocol used to make the call
41
     *
42
     * @type string
43
     */
44
    protected $protocol = 'quake2';
45
46
    /**
47
     * String name of this protocol class
48
     *
49
     * @type string
50
     */
51
    protected $name = 'quake2';
52
53
    /**
54
     * Longer string name of this protocol class
55
     *
56
     * @type string
57
     */
58
    protected $name_long = "Quake 2 Server";
59
60
    /**
61
     * The client join link
62
     *
63
     * @type string
64
     */
65
    protected $join_link = null;
66
67
    /**
68
     * Normalize settings for this protocol
69
     *
70
     * @type array
71
     */
72
    protected $normalize = [
73
        // General
74
        'general' => [
75
            // target       => source
76
            'gametype'   => 'gamename',
77
            'hostname'   => 'hostname',
78
            'mapname'    => 'mapname',
79
            'maxplayers' => 'maxclients',
80
            'mod'        => 'g_gametype',
81
            'numplayers' => 'clients',
82
            'password'   => 'password',
83
        ],
84
        // Individual
85
        'player'  => [
86
            'name'  => 'name',
87
            'ping'  => 'ping',
88
            'score' => 'frags',
89
        ],
90
    ];
91
92
    /**
93
     * Handle response from the server
94
     *
95
     * @return mixed
96
     * @throws Exception
97
     */
98 5
    public function processResponse()
99
    {
100
        // Make a buffer
101 5
        $buffer = new Buffer(implode('', $this->packets_response));
102
103
        // Grab the header
104 5
        $header = $buffer->readString("\x0A");
105
106
        // Figure out which packet response this is
107 5
        if (empty($header) || !array_key_exists($header, $this->responses)) {
108 2
            throw new Exception(__METHOD__ . " response type '" . bin2hex($header) . "' is not valid");
109
        }
110
111 3
        return call_user_func_array([$this, $this->responses[$header]], [$buffer]);
112
    }
113
114
    /**
115
     * Process the status response
116
     *
117
     * @param Buffer $buffer
118
     *
119
     * @return array
120
     */
121 3
    protected function processStatus(Buffer $buffer)
122
    {
123
        // We need to split the data and offload
124 3
        $results = $this->processServerInfo(new Buffer($buffer->readString("\x0A")));
125
126 3
        $results = array_merge_recursive(
127
            $results,
128 3
            $this->processPlayers(new Buffer($buffer->getBuffer()))
129
        );
130
131 3
        unset($buffer);
132
133
        // Return results
134 3
        return $results;
135
    }
136
137
    /**
138
     * Handle processing the server information
139
     *
140
     * @param Buffer $buffer
141
     *
142
     * @return array
143
     */
144 3
    protected function processServerInfo(Buffer $buffer)
145
    {
146
        // Set the result to a new result instance
147 3
        $result = new Result();
148
149
        // Burn leading \ if one exists
150 3
        $buffer->readString('\\');
151
152
        // Key / value pairs
153 3
        while ($buffer->getLength()) {
154
            // Add result
155 3
            $result->add(
156 3
                trim($buffer->readString('\\')),
157 3
                utf8_encode(trim($buffer->readStringMulti(['\\', "\x0a"])))
158
            );
159
        }
160
161 3
        $result->add('password', 0);
162 3
        $result->add('mod', 0);
163
164 3
        unset($buffer);
165
166 3
        return $result->fetch();
167
    }
168
169
    /**
170
     * Handle processing of player data
171
     *
172
     * @param Buffer $buffer
173
     *
174
     * @return array
175
     */
176 3
    protected function processPlayers(Buffer $buffer)
177
    {
178
        // Some games do not have a number of current players
179 3
        $playerCount = 0;
180
181
        // Set the result to a new result instance
182 3
        $result = new Result();
183
184
        // Loop until we are out of data
185 3
        while ($buffer->getLength()) {
186
            // Make a new buffer with this block
187 2
            $playerInfo = new Buffer($buffer->readString("\x0A"));
188
189
            // Add player info
190 2
            $result->addPlayer('frags', $playerInfo->readString("\x20"));
191 2
            $result->addPlayer('ping', $playerInfo->readString("\x20"));
192
193
            // Skip first "
194 2
            $playerInfo->skip(1);
195
196
            // Add player name, encoded
197 2
            $result->addPlayer('name', utf8_encode(trim(($playerInfo->readString('"')))));
198
199
            // Skip first "
200 2
            $playerInfo->skip(2);
201
202
            // Add address
203 2
            $result->addPlayer('address', trim($playerInfo->readString('"')));
204
205
            // Increment
206 2
            $playerCount++;
207
208
            // Clear
209 2
            unset($playerInfo);
210
        }
211
212 3
        $result->add('clients', $playerCount);
213
214
        // Clear
215 3
        unset($buffer, $playerCount);
216
217 3
        return $result->fetch();
218
    }
219
}
220