Completed
Push — v3 ( 3e8e8b...2fd840 )
by Austin
04:41
created

Ffow::processPlayers()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 9
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 9
ccs 4
cts 4
cp 1
rs 9.6666
c 0
b 0
f 0
cc 1
eloc 4
nc 1
nop 1
crap 1
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
 * 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
     * @type 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
     * @type 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
     * @type string
51
     */
52
    protected $protocol = 'ffow';
53
54
    /**
55
     * String name of this protocol class
56
     *
57
     * @type string
58
     */
59
    protected $name = 'ffow';
60
61
    /**
62
     * Longer string name of this protocol class
63
     *
64
     * @type string
65
     */
66
    protected $name_long = "Frontlines Fuel of War";
67
68
    /**
69
     * The client join link
70
     *
71
     * @type string
72
     */
73
    protected $join_link = null;
74
75
    /**
76
     * query_port = client_port + 2
77
     *
78
     * @type int
79
     */
80
    protected $port_diff = 2;
81
82
    /**
83
     * Normalize settings for this protocol
84
     *
85
     * @type array
86
     */
87
    protected $normalize = [
88
        // General
89
        'general' => [
90
            // target       => source
91
            'gametype'   => 'gamemode',
92
            'hostname'   => 'servername',
93
            'mapname'    => 'mapname',
94
            'maxplayers' => 'max_players',
95
            'mod'        => 'modname',
96
            'numplayers' => 'num_players',
97
            'password'   => 'password',
98
        ],
99
        // Individual
100
        'player'  => [
101
            'name'  => 'name',
102
            'ping'  => 'ping',
103
            'score' => 'frags',
104
        ],
105
    ];
106
107
    /**
108
     * Parse the challenge response and apply it to all the packet types
109
     *
110
     * @param \GameQ\Buffer $challenge_buffer
111
     *
112
     * @return bool
113
     * @throws \GameQ\Exception\Protocol
114
     */
115 1
    public function challengeParseAndApply(Buffer $challenge_buffer)
116
    {
117
        // Burn padding
118 1
        $challenge_buffer->skip(5);
119
120
        // Apply the challenge and return
121 1
        return $this->challengeApply($challenge_buffer->read(4));
122
    }
123
124
    /**
125
     * Handle response from the server
126
     *
127
     * @return mixed
128
     * @throws Exception
129
     */
130 4
    public function processResponse()
131
    {
132
        // Init results
133 4
        $results = [];
134
135 4
        foreach ($this->packets_response as $response) {
136 4
            $buffer = new Buffer($response);
137
138
            // Figure out what packet response this is for
139 4
            $response_type = $buffer->read(6);
140
141
            // Figure out which packet response this is
142 4
            if (!array_key_exists($response_type, $this->responses)) {
143 2
                throw new Exception(__METHOD__ . " response type '" . bin2hex($response_type) . "' is not valid");
144
            }
145
146
            // Now we need to call the proper method
147 4
            $results = array_merge(
148
                $results,
149 4
                call_user_func_array([$this, $this->responses[$response_type]], [$buffer])
150
            );
151
152 4
            unset($buffer);
153
        }
154
155 2
        return $results;
156
    }
157
158
    /**
159
     * Handle processing the server information
160
     *
161
     * @param Buffer $buffer
162
     *
163
     * @return array
164
     */
165 2
    protected function processInfo(Buffer $buffer)
166
    {
167
        // Set the result to a new result instance
168 2
        $result = new Result();
169
170 2
        $result->add('servername', $buffer->readString());
171 2
        $result->add('mapname', $buffer->readString());
172 2
        $result->add('modname', $buffer->readString());
173 2
        $result->add('gamemode', $buffer->readString());
174 2
        $result->add('description', $buffer->readString());
175 2
        $result->add('version', $buffer->readString());
176 2
        $result->add('port', $buffer->readInt16());
177 2
        $result->add('num_players', $buffer->readInt8());
178 2
        $result->add('max_players', $buffer->readInt8());
179 2
        $result->add('dedicated', $buffer->readInt8());
180 2
        $result->add('os', $buffer->readInt8());
181 2
        $result->add('password', $buffer->readInt8());
182 2
        $result->add('anticheat', $buffer->readInt8());
183 2
        $result->add('average_fps', $buffer->readInt8());
184 2
        $result->add('round', $buffer->readInt8());
185 2
        $result->add('max_rounds', $buffer->readInt8());
186 2
        $result->add('time_left', $buffer->readInt16());
187
188 2
        unset($buffer);
189
190 2
        return $result->fetch();
191
    }
192
193
    /**
194
     * Handle processing the server rules
195
     *
196
     * @param Buffer $buffer
197
     *
198
     * @return array
199
     */
200 4
    protected function processRules(Buffer $buffer)
201
    {
202
        // Set the result to a new result instance
203 4
        $result = new Result();
204
205
        // Burn extra header
206 4
        $buffer->skip(1);
207
208
        // Read rules until we run out of buffer
209 4
        while ($buffer->getLength()) {
210 4
            $key = $buffer->readString();
211
            // Check for map
212 4
            if (strstr($key, "Map:")) {
213 4
                $result->addSub("maplist", "name", $buffer->readString());
214
            } else // Regular rule
215
            {
216 4
                $result->add($key, $buffer->readString());
217
            }
218
        }
219
220 4
        unset($buffer);
221
222 4
        return $result->fetch();
223
    }
224
225
    /**
226
     * Handle processing of player data
227
     *
228
     * @todo: Build this out when there is a server with players to test against
229
     *
230
     * @param Buffer $buffer
231
     *
232
     * @return array
233
     */
234 4
    protected function processPlayers(Buffer $buffer)
235
    {
236
        // Set the result to a new result instance
237 4
        $result = new Result();
238
239 4
        unset($buffer);
240
241 4
        return $result->fetch();
242
    }
243
}
244