Ffow::processResponse()   A
last analyzed

Complexity

Conditions 3
Paths 3

Size

Total Lines 26
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 13
CRAP Score 3

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 11
c 1
b 0
f 0
dl 0
loc 26
ccs 13
cts 13
cp 1
rs 9.9
cc 3
nc 3
nop 0
crap 3
1
<?php
2
3
4
namespace GameQ\Protocols;
5
6
use GameQ\Buffer;
7
use GameQ\Exception\Protocol as Exception;
8
use GameQ\Protocol;
9
use GameQ\Result;
10
11
/**
12
 * Frontlines Fuel of War Protocol Class
13
 *
14
 * Handles processing ffow servers
15
 *
16
 * Class is incomplete due to lack of players to test against.
17
 * http://wiki.hlsw.net/index.php/FFOW_Protocol
18
 *
19
 * @package GameQ\Protocols
20
 */
21
class Ffow extends Protocol
22
{
23
    /**
24
     * Array of packets we want to look up.
25
     * Each key should correspond to a defined method in this or a parent class
26
     *
27
     * @var array
28
     */
29
    protected $packets = [
30
        self::PACKET_CHALLENGE => "\xFF\xFF\xFF\xFF\x57",
31
        self::PACKET_RULES     => "\xFF\xFF\xFF\xFF\x56%s",
32
        self::PACKET_PLAYERS   => "\xFF\xFF\xFF\xFF\x55%s",
33
        self::PACKET_INFO      => "\xFF\xFF\xFF\xFF\x46\x4C\x53\x51",
34
    ];
35
36
    /**
37
     * Use the response flag to figure out what method to run
38
     *
39
     * @var array
40
     */
41
    protected $responses = [
42
        "\xFF\xFF\xFF\xFF\x49\x02" => 'processInfo', // I
43
        "\xFF\xFF\xFF\xFF\x45\x00" => 'processRules', // E
44
        "\xFF\xFF\xFF\xFF\x44\x00" => 'processPlayers', // D
45
    ];
46
47
    /**
48
     * The query protocol used to make the call
49
     *
50
     * @var string
51
     */
52
    protected $protocol = 'ffow';
53
54
    /**
55
     * String name of this protocol class
56
     *
57
     * @var string
58
     */
59
    protected $name = 'ffow';
60
61
    /**
62
     * Longer string name of this protocol class
63
     *
64
     * @var string
65
     */
66
    protected $name_long = "Frontlines Fuel of War";
67
68
    /**
69
     * query_port = client_port + 2
70
     *
71
     * @var int
72
     */
73
    protected $port_diff = 2;
74
75
    /**
76
     * Normalize settings for this protocol
77
     *
78
     * @var array
79
     */
80
    protected $normalize = [
81
        // General
82
        'general' => [
83
            // target       => source
84
            'gametype'   => 'gamemode',
85
            'hostname'   => 'servername',
86
            'mapname'    => 'mapname',
87
            'maxplayers' => 'max_players',
88
            'mod'        => 'modname',
89
            'numplayers' => 'num_players',
90
            'password'   => 'password',
91
        ],
92
        // Individual
93
        'player'  => [
94
            'name'  => 'name',
95
            'ping'  => 'ping',
96
            'score' => 'frags',
97
        ],
98
    ];
99
100
    /**
101
     * Parse the challenge response and apply it to all the packet types
102
     *
103
     * @param \GameQ\Buffer $challenge_buffer
104
     *
105
     * @return bool
106
     * @throws \GameQ\Exception\Protocol
107
     */
108 6
    public function challengeParseAndApply(Buffer $challenge_buffer)
109
    {
110
        // Burn padding
111 6
        $challenge_buffer->skip(5);
112
113
        // Apply the challenge and return
114 6
        return $this->challengeApply($challenge_buffer->read(4));
115
    }
116
117
    /**
118
     * Handle response from the server
119
     *
120
     * @return mixed
121
     * @throws Exception
122
     */
123 24
    public function processResponse()
124
    {
125
        // Init results
126 24
        $results = [];
127
128 24
        foreach ($this->packets_response as $response) {
129 24
            $buffer = new Buffer($response);
130
131
            // Figure out what packet response this is for
132 24
            $response_type = $buffer->read(6);
133
134
            // Figure out which packet response this is
135 24
            if (!array_key_exists($response_type, $this->responses)) {
136 12
                throw new Exception(__METHOD__ . " response type '" . bin2hex($response_type) . "' is not valid");
137
            }
138
139
            // Now we need to call the proper method
140 24
            $results = array_merge(
141 24
                $results,
142 24
                call_user_func_array([$this, $this->responses[$response_type]], [$buffer])
143 24
            );
144
145 24
            unset($buffer);
146
        }
147
148 12
        return $results;
149
    }
150
151
    /**
152
     * Handle processing the server information
153
     *
154
     * @param Buffer $buffer
155
     *
156
     * @return array
157
     * @throws \GameQ\Exception\Protocol
158
     */
159 12
    protected function processInfo(Buffer $buffer)
160
    {
161
        // Set the result to a new result instance
162 12
        $result = new Result();
163
164 12
        $result->add('servername', $buffer->readString());
165 12
        $result->add('mapname', $buffer->readString());
166 12
        $result->add('modname', $buffer->readString());
167 12
        $result->add('gamemode', $buffer->readString());
168 12
        $result->add('description', $buffer->readString());
169 12
        $result->add('version', $buffer->readString());
170 12
        $result->add('port', $buffer->readInt16());
171 12
        $result->add('num_players', $buffer->readInt8());
172 12
        $result->add('max_players', $buffer->readInt8());
173 12
        $result->add('dedicated', $buffer->readInt8());
174 12
        $result->add('os', $buffer->readInt8());
175 12
        $result->add('password', $buffer->readInt8());
176 12
        $result->add('anticheat', $buffer->readInt8());
177 12
        $result->add('average_fps', $buffer->readInt8());
178 12
        $result->add('round', $buffer->readInt8());
179 12
        $result->add('max_rounds', $buffer->readInt8());
180 12
        $result->add('time_left', $buffer->readInt16());
181
182 12
        unset($buffer);
183
184 12
        return $result->fetch();
185
    }
186
187
    /**
188
     * Handle processing the server rules
189
     *
190
     * @param Buffer $buffer
191
     *
192
     * @return array
193
     * @throws \GameQ\Exception\Protocol
194
     */
195 24
    protected function processRules(Buffer $buffer)
196
    {
197
        // Set the result to a new result instance
198 24
        $result = new Result();
199
200
        // Burn extra header
201 24
        $buffer->skip(1);
202
203
        // Read rules until we run out of buffer
204 24
        while ($buffer->getLength()) {
205 24
            $key = $buffer->readString();
206
            // Check for map
207 24
            if (strstr($key, "Map:")) {
208 24
                $result->addSub("maplist", "name", $buffer->readString());
209
            } else { // Regular rule
210 24
                $result->add($key, $buffer->readString());
211
            }
212
        }
213
214 24
        unset($buffer);
215
216 24
        return $result->fetch();
217
    }
218
219
    /**
220
     * Handle processing of player data
221
     *
222
     * @todo: Build this out when there is a server with players to test against
223
     *
224
     * @param Buffer $buffer
225
     *
226
     * @return array
227
     */
228 24
    protected function processPlayers(Buffer $buffer)
229
    {
230
        // Set the result to a new result instance
231 24
        $result = new Result();
232
233 24
        unset($buffer);
234
235 24
        return $result->fetch();
236
    }
237
}
238