BotParser::__construct()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 1 Features 0
Metric Value
eloc 1
c 1
b 1
f 0
dl 0
loc 3
rs 10
cc 1
nc 1
nop 1
1
<?php
2
3
namespace Application\Service;
4
5
use Carbon\Carbon;
6
7
class BotParser
8
{
9
    const ONLINE_COLOR = '#0080e1';
10
    const OFFLINE_COLOR = '#d30000';
11
    const ITEM_COLOR = '#ff8000';
12
    const UNIQUE_ITEM_COLOR = '#e1c000';
13
    private $items = [
14
        'amulet',
15
        'boots',
16
        'charm',
17
        'gloves',
18
        'helm',
19
        'leggings',
20
        'ring',
21
        'shield',
22
        'tunic',
23
        'weapon',
24
    ];
25
    private $penalties = [
26
        'kick',
27
        'logout',
28
        'msg',
29
        'nick',
30
        'part',
31
        'quest',
32
        'quit',
33
    ];
34
    private $config;
35
36
    public function __construct(array $config)
37
    {
38
        $this->config = $config;
39
    }
40
41
    /**
42
     * Converts a DateInterval to a human readable format.
43
     * Returns 'None' if the difference is zero.
44
     * @param int $seconds
45
     * @param int $start
46
     * @return string
47
     */
48
    private function secondsToTime(int $seconds, int $start = 0)
49
    {
50
        $result = 'None';
51
52
        if ($seconds > 0) {
53
            $dtF = new Carbon("@$start");
54
            $dtT = new Carbon("@$seconds");
55
            $result = $dtF->diffForHumans($dtT, true, false, 2);
0 ignored issues
show
Bug introduced by
true of type true is incompatible with the type array|integer expected by parameter $syntax of Carbon\Carbon::diffForHumans(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

55
            $result = $dtF->diffForHumans($dtT, /** @scrutinizer ignore-type */ true, false, 2);
Loading history...
56
        }
57
58
        return $result;
59
    }
60
61
    /**
62
     * Returns the alignment.
63
     * @param string $alignment
64
     * @return string
65
     */
66
    private function parseAlignment(string $alignment)
67
    {
68
        $align = "";
69
        switch ($alignment) {
70
            case 'n':
71
                $align = "Neutral";
72
                break;
73
            case 'e':
74
                $align = "Evil";
75
                break;
76
            case 'g':
77
                $align = "Good";
78
                break;
79
        }
80
        return $align;
81
    }
82
83
    /**
84
     * Returns the name of item if it is unique, or null if it isn't.
85
     * @param mixed $itemValue
86
     * @return null|string
87
     */
88
    private function parseUniqueItem($itemValue)
89
    {
90
        $items = [
91
            "a" => "Mattt's Omniscience Grand Crown",
92
            "b" => "Res0's Protectorate Plate Mail",
93
            "c" => "Dwyn's Storm Magic Amulet",
94
            "d" => "Jotun's Fury Colossal Sword",
95
            "e" => "Drdink's Cane of Blind Rage",
96
            "f" => "Mrquick's Magical Boots of Swiftness",
97
            "g" => "Jeff's Cluehammer of Doom",
98
            "h" => "Juliet's Glorious Ring of Sparkliness"
99
        ];
100
        $result = null;
101
102
        $regex = '/\d+([a-h])/';
103
        preg_match($regex, $itemValue, $matches);
104
105
        if (isset($matches[1]) && array_key_exists($matches[1], $items)) {
106
            $result = $items[$matches[1]];
107
        }
108
109
        return $result;
110
    }
111
112
    /**
113
     * Sums the values from the keys of the array $record from $start till $end.
114
     * @param array $record
115
     * @param int $start
116
     * @param int $end
117
     * @return int
118
     */
119
    private function sumFields(array $record, int $start, int $end)
120
    {
121
        $total = 0;
122
        for ($i = $start; $i <= $end; $i++) {
123
            $total += (int) $record[$i];
124
        }
125
        return $total;
126
    }
127
128
    /**
129
     * @return array
130
     */
131
    public function getPenaltiesList()
132
    {
133
        return $this->penalties;
134
    }
135
136
    /**
137
     * @return array
138
     */
139
    public function getItemsList()
140
    {
141
        return $this->items;
142
    }
143
144
    /**
145
     * Returns an array with a list of all the Items from the database.
146
     * @return array
147
     */
148
    public function getItems()
149
    {
150
        $items = [];
151
        $row = 0;
152
        if (($handle = fopen($this->config['bot_item'], "r")) !== false) {
153
            while (($data = fgetcsv($handle, 1024, "\t")) !== false) {
154
                $row++;
155
                if ($row == 1) {
156
                    continue;
157
                }
158
159
                $record = [
160
                    'x_pos' => (int) $data[0],
161
                    'y_pos' => (int) $data[1],
162
                    'type'  => $data[2],
163
                    'level' => $data[3],
164
                    'age'   => (int) $data[4],
165
                    'color' => (is_numeric($data[3]) ? self::ITEM_COLOR : self::UNIQUE_ITEM_COLOR)
166
                ];
167
168
                $items[] = $record;
169
            }
170
            fclose($handle);
171
        }
172
173
        return $items;
174
    }
175
176
    /**
177
     * Returns an array with the Players, sorted by level.
178
     * Includes the fields needed for the scoreboard page.
179
     * @return array
180
     */
181
    public function getScoreboard()
182
    {
183
        $players = [];
184
        $row = 0;
185
        if (($handle = fopen($this->config['bot_db'], "r")) !== false) {
186
            while (($data = fgetcsv($handle, 1024, "\t")) !== false) {
187
                $row++;
188
                if ($row == 1) {
189
                    continue;
190
                }
191
                $players[] = [
192
                    'nick'    => $data[0],
193
                    'level'   => (int) $data[3],
194
                    'class'   => $data[4],
195
                    'ttl'     => $this->secondsToTime((int) $data[5]),
196
                    'ttl_num' => (int) $data[5],
197
                    'status'  => (bool) $data[8],
198
                ];
199
            }
200
            fclose($handle);
201
        }
202
        usort($players, function ($valueA, $valueB) {
203
            return $valueB['level'] - $valueA['level'] ?: $valueA['ttl_num'] - $valueB['ttl_num'];
204
        });
205
206
        return $players;
207
    }
208
209
    /**
210
     * Returns a list with (almost) all the fields from the Players database.
211
     * If the parameter $nick is used, only returns the data for that Player
212
     * or 0 if that Player doesn't exist.
213
     * @param string|null $nick
214
     * @return array|int|mixed
215
     */
216
    public function getDatabase(string $nick = null)
217
    {
218
        $database = [];
219
        $row = 0;
220
        if (($handle = fopen($this->config['bot_db'], "r")) !== false) {
221
            while (($data = fgetcsv($handle, 1024, "\t")) !== false) {
222
                $row++;
223
                if ($row == 1) {
224
                    continue;
225
                }
226
227
                if ($nick !== null && strcmp($data[0], $nick) !== 0) {
228
                    continue;
229
                }
230
231
                $record = [
232
                    'nick' => $data[0], // nick
233
                    'level' => (int) $data[3], // level
234
                    'admin' => ($data[2] ? 'Yes' : 'No'), // admin
235
                    'class' => $data[4], // class
236
                    'ttl' => [
237
                        'display' => $this->secondsToTime((int) $data[5]),
238
                        'numeric' => (int) $data[5], // ttl
239
                    ],
240
                    'nick_host' => $data[7], // nick and host
241
                    'online' => ($data[8] ? 'Yes' : 'No'), // online
242
                    'idled' => [
243
                        'display' => $this->secondsToTime((int) $data[9]), // idled
244
                        'numeric' => (int) $data[9],
245
                    ],
246
                    'x_pos' => (int) $data[10], // x pos
247
                    'y_pos' => (int) $data[11], // y pos
248
                    'msg_pen' => [
249
                        'display' => $this->secondsToTime((int) $data[12]), // msg pen
250
                        'numeric' => (int) $data[12],
251
                    ],
252
                    'nick_pen' => [
253
                        'display' => $this->secondsToTime((int) $data[13]), // nick pen
254
                        'numeric' => (int) $data[13],
255
                    ],
256
                    'part_pen' => [
257
                        'display' => $this->secondsToTime((int) $data[14]), // part pen
258
                        'numeric' => (int) $data[14],
259
                    ],
260
                    'kick_pen' => [
261
                        'display' => $this->secondsToTime((int) $data[15]), // kick pen
262
                        'numeric' => (int) $data[15],
263
                    ],
264
                    'quit_pen' => [
265
                        'display' => $this->secondsToTime((int) $data[16]), // quit pen
266
                        'numeric' => (int) $data[16],
267
                    ],
268
                    'quest_pen' => [
269
                        'display' => $this->secondsToTime((int) $data[17]), // quest pen
270
                        'numeric' => (int) $data[17],
271
                    ],
272
                    'logout_pen' => [
273
                        'display' => $this->secondsToTime((int) $data[18]), // logout pen
274
                        'numeric' => (int) $data[18],
275
                    ],
276
                    'total_pen' => [
277
                        'display' => $this->secondsToTime($this->sumFields($data, 12, 18)),
278
                        'numeric' => $this->sumFields($data, 12, 18),
279
                    ],
280
                    'created' => [
281
                        'display' => date('Y-m-d H:i:s', (int) $data[19]), // created
282
                        'numeric' => (int) $data[19],
283
                    ],
284
                    'last_login' => [
285
                        'display' => date('Y-m-d H:i:s', (int) $data[20]), // last login
286
                        'numeric' => (int) $data[20],
287
                    ],
288
                    'amulet' => [
289
                        'display' => $data[21], // amulet
290
                        'numeric' => (int) $data[21],
291
                        'unique' => $this->parseUniqueItem($data[21])
292
                    ],
293
                    'charm' => [
294
                        'display' => $data[22], // charm
295
                        'numeric' => (int) $data[22],
296
                        'unique' => $this->parseUniqueItem($data[22])
297
                    ],
298
                    'helm' => [
299
                        'display' => $data[23], // helm
300
                        'numeric' => (int) $data[23],
301
                        'unique' => $this->parseUniqueItem($data[23])
302
                    ],
303
                    'boots' => [
304
                        'display' => $data[24], // boots
305
                        'numeric' => (int) $data[24],
306
                        'unique' => $this->parseUniqueItem($data[24])
307
                    ],
308
                    'gloves' => [
309
                        'display' => $data[25], // gloves
310
                        'numeric' => (int) $data[25],
311
                        'unique' => $this->parseUniqueItem($data[25])
312
                    ],
313
                    'ring' => [
314
                        'display' => $data[26], // ring
315
                        'numeric' => (int) $data[26],
316
                        'unique' => $this->parseUniqueItem($data[26])
317
                    ],
318
                    'leggings' => [
319
                        'display' => $data[27], // leggings
320
                        'numeric' => (int) $data[27],
321
                        'unique' => $this->parseUniqueItem($data[27])
322
                    ],
323
                    'shield' => [
324
                        'display' => $data[28], // shield
325
                        'numeric' => (int) $data[28],
326
                        'unique' => $this->parseUniqueItem($data[28])
327
                    ],
328
                    'tunic' => [
329
                        'display' => $data[29], // tunic
330
                        'numeric' => (int) $data[29],
331
                        'unique' => $this->parseUniqueItem($data[29])
332
                    ],
333
                    'weapon' => [
334
                        'display' => $data[30], // weapon
335
                        'numeric' => (int) $data[30],
336
                        'unique' => $this->parseUniqueItem($data[30])
337
                    ],
338
                    'sum' => $this->sumFields($data, 21, 30),
339
                    'alignment' => $this->parseAlignment($data[31]), // alignment
340
                ];
341
342
                if ($nick !== null) {
343
                    return $record;
344
                }
345
346
                $database[] = $record;
347
            }
348
            fclose($handle);
349
        }
350
351
        if ($nick !== null) {
352
            return 0;
353
        }
354
355
        return $database;
356
    }
357
358
    /**
359
     * Returns the last $limit events [from the user $nick].
360
     * If $limit is 0 returns all.
361
     * @param int $limit
362
     * @param string|null $nick
363
     * @return array|mixed
364
     */
365
    public function getEvents(int $limit, string $nick = null)
366
    {
367
        $modifiers = [
368
            'items' => [],
369
            'total' => 0,
370
        ];
371
372
        $tmp = [];
373
        $handle = fopen($this->config['bot_mod'], "r");
374
        if ($handle !== false) {
375
            while (($line = fgets($handle)) !== false) {
376
                if ($nick !== null && strpos($line, $nick) !== false) {
377
                    $tmp[] = trim($line);
378
                }
379
380
                if ($nick === null) {
381
                    $tmp[] = trim($line);
382
                }
383
            }
384
            fclose($handle);
385
        }
386
387
        $tmp = array_reverse($tmp);
388
        $modifiers['total'] = count($tmp);
389
        $modifiers['items'] = array_slice($tmp, 0, ($limit > 0) ? $limit : null);
390
391
        return $modifiers;
392
    }
393
394
    /**
395
     * Returns an array with the coordinates and name of all Players and Items.
396
     * @return array
397
     */
398
    public function getCoordinates()
399
    {
400
        $coordinates = [];
401
402
        $players = $this->getDatabase();
403
        $items = $this->getItems();
404
405
        foreach ($players as $player) {
406
            $coordinates[] = [
407
                'x'     => $player['x_pos'],
408
                'y'     => $player['y_pos'],
409
                'text'  => $player['nick'],
410
                'color' => ($player['online'] == 'Yes' ? self::ONLINE_COLOR : self::OFFLINE_COLOR)
411
            ];
412
        }
413
414
        foreach ($items as $item) {
415
            $coordinates[] = [
416
                'x'     => $item['x_pos'],
417
                'y'     => $item['y_pos'],
418
                'text'  => $item['type'],
419
                'color' => $item['color'],
420
            ];
421
        }
422
423
        return $coordinates;
424
    }
425
426
    /**
427
     * Returns an array with all the data associated with the current quest
428
     * @return array
429
     */
430
    public function getQuestData()
431
    {
432
        $quest = [];
433
        if (($handle = fopen($this->config['bot_quest'], "r")) !== false) {
434
            while (($data = fgets($handle, 1024)) !== false) {
435
                // T - title
436
                if (! isset($data['title']) && $data[0] == "T") {
437
                    $quest['title'] = trim(substr($data, 2));
438
                }
439
                // Y - type. 1 for time based, 2 for stages
440
                if (! isset($data['type']) && $data[0] == "Y") {
441
                    $quest['type'] = (int) substr($data, 2);
442
                }
443
                // S - objective
444
                if ($data[0] == "S") {
445
                    if ($quest['type'] == 1) {
446
                        // Time to end
447
                        $quest['objective'] = $this->secondsToTime((int) substr($data, 2), time());
448
                        $quest['objective_num'] = (int) substr($data, 2);
449
                    } elseif ($quest['type'] == 2) {
450
                        // Stage
451
                        $quest['objective'] = (int) substr($data, 2);
452
                    }
453
                }
454
                if ($data[0] == "P") {
455
                    $data_exploded = explode(" ", $data);
456
                    // P - stages position
457
                    if ($data_exploded[0] == "P") {
458
                        $quest['stages'] = [
459
                            [
460
                                'x_pos' => (int) $data_exploded[1],
461
                                'y_pos' => (int) $data_exploded[2],
462
                                'color' => self::OFFLINE_COLOR,
463
                            ],
464
                            [
465
                                'x_pos' => (int) $data_exploded[3],
466
                                'y_pos' => (int) $data_exploded[4],
467
                                'color' => self::OFFLINE_COLOR,
468
                            ],
469
                        ];
470
                    }
471
                    // P{1-4} - player position
472
                    if (isset($data_exploded[0][1])) {
473
                        if ($quest['type'] == 2) {
474
                            $quest['players'][] = [
475
                                'nick'  => trim($data_exploded[1]),
476
                                'x_pos' => (int) $data_exploded[2],
477
                                'y_pos' => (int) $data_exploded[3],
478
                                'color' => self::ONLINE_COLOR,
479
                            ];
480
                        } elseif ($quest['type'] == 1) {
481
                            $quest['players'][] = [
482
                                'nick' => trim($data_exploded[1]),
483
                            ];
484
                        }
485
                    }
486
                }
487
            }
488
            fclose($handle);
489
        }
490
491
        return $quest;
492
    }
493
494
    /**
495
     * Returns an array with all the Players nicks.
496
     * @return array
497
     */
498
    public function getPlayers()
499
    {
500
        $players = [];
501
502
        $row = 0;
503
        if (($handle = fopen($this->config['bot_db'], "r")) !== false) {
504
            while (($data = fgetcsv($handle, 1024, "\t")) !== false) {
505
                $row++;
506
                if ($row == 1) {
507
                    continue;
508
                }
509
510
                $players[] = $data[0]; // nick
511
            }
512
        }
513
514
        return $players;
515
    }
516
517
    /**
518
     * Returns an array with the dimensions of the map image.
519
     * @return array
520
     */
521
    public function getMapDimensions()
522
    {
523
        return [
524
            'height' => $this->config['map_height'],
525
            'width'  => $this->config['map_width'],
526
        ];
527
    }
528
}
529