SyncStructures   A
last analyzed

Complexity

Total Complexity 32

Size/Duplication

Total Lines 241
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 2

Test Coverage

Coverage 0%

Importance

Changes 0
Metric Value
wmc 32
lcom 1
cbo 2
dl 0
loc 241
ccs 0
cts 122
cp 0
rs 9.6
c 0
b 0
f 0

8 Methods

Rating   Name   Duplication   Size   Complexity  
A fire() 0 4 1
A handle() 0 8 1
A loadSourceCode() 0 7 1
A getBetween() 0 11 2
D prepareStructures() 0 48 16
A saveStructures() 0 16 3
B convertNames() 0 12 5
A replaceKnown() 0 17 3
1
<?php namespace FreedomCore\TrinityCore\Support\DB2Reader\Commands;
2
3
use File;
4
use Illuminate\Console\Command;
5
use Symfony\Component\Console\Helper\ProgressBar;
6
use Symfony\Component\Console\Output\ConsoleOutput;
7
8
/**
9
 * Class SyncStructures
10
 * @package FreedomCore\TrinityCore\Support\DB2Reader\Commands
11
 */
12
class SyncStructures extends Command
13
{
14
15
    /**
16
     * The console command name.
17
     * @var string
18
     */
19
    protected $name = 'db2:structure:sync';
20
21
    /**
22
     * @inheritdoc
23
     * @var string
24
     */
25
    protected $signature = 'db2:structure:sync {--build=25549}';
26
27
    /**
28
     * The console command description.
29
     * @var string
30
     */
31
    protected $description = 'Synchronize structures with TrinityCore Github Repository';
32
33
    /**
34
     * Game Build Number
35
     * @var null|int
36
     */
37
    protected $build = null;
38
39
    /**
40
     * Github Content
41
     * @var null|string
42
     */
43
    protected $content = null;
44
45
    /**
46
     * Where structures will be saved
47
     * @var null|string
48
     */
49
    protected $saveLocation = null;
50
51
    /**
52
     * Array of parsed structures
53
     * @var array
54
     */
55
    protected $structures = [];
56
57
    /**
58
     * Structure Info Array
59
     * @var array
60
     */
61
    protected $structureInfo = [
62
        'name'      =>  null,
63
        'start'     =>  null,
64
        'end'       =>  null,
65
        'fields'    =>  []
66
    ];
67
68
    /**
69
     * Array for items which require to be replaced
70
     * @var array
71
     */
72
    protected $replaceArray = [
73
        'LocalizedString*',
74
        'uint32',
75
        'uint16',
76
        'uint8',
77
        'int32',
78
        'int16',
79
        'int8',
80
        'float',
81
        ';',
82
        'char',
83
        'const*',
84
        'const',
85
        'DBCPosition3D',
86
        'DBCPosition2D'
87
    ];
88
89
    /**
90
     * Fire Installation
91
     * @return mixed
92
     */
93
    public function fire()
94
    {
95
        return $this->handle();
96
    }
97
98
    /**
99
     * Handle Installation
100
     */
101
    public function handle()
102
    {
103
        $this->build = intval($this->option('build'));
104
        $this->loadSourceCode();
105
        $this->prepareStructures();
106
        $this->info('Total amount of structures: ' . count($this->structures));
107
        $this->saveStructures();
108
    }
109
110
    /**
111
     * Load Source Code
112
     */
113
    private function loadSourceCode()
114
    {
115
        $this->content = file_get_contents('https://raw.githubusercontent.com/TrinityCore/TrinityCore/master/src/server/game/DataStores/DB2Structure.h');
116
        $this->saveLocation = str_replace('Commands', 'Structures', __DIR__) . DIRECTORY_SEPARATOR;
117
        $extra = '/*' . $this->getBetween($this->content, '/*', 'struct LocalizedString;') . 'struct LocalizedString;';
118
        $this->content = str_replace($extra, '', $this->content);
119
    }
120
121
    /**
122
     * Get text between two strings
123
     * @param string $string
124
     * @param string $start
125
     * @param string $end
126
     * @return string
127
     */
128
    private function getBetween(string $string, string $start, string $end) : string
129
    {
130
        $string = ' ' . $string;
131
        $ini = strpos($string, $start);
132
        if ($ini == 0) {
133
            return '';
134
        }
135
        $ini += strlen($start);
136
        $len = strpos($string, $end, $ini) - $ini;
137
        return substr($string, $ini, $len);
138
    }
139
140
    /**
141
     * Prepare Structures
142
     */
143
    private function prepareStructures()
144
    {
145
        $skipToEnd = false;
146
        foreach (explode("\n", $this->content) as $index => $line) {
147
            $line = trim($line);
148
            if (strlen($line) < 2) {
149
                continue;
150
            }
151
            if (strstr($line, '#define') || strstr($line, '#pragma pack(pop)') || strstr($line, '#endif')) {
152
                continue;
153
            }
154
155
            if (strstr($line, 'struct')) {
156
                $this->structureInfo['name'] = trim($this->getBetween($line, 'struct', 'Entry'));
157
                if ($this->structureInfo['name'] === 'Criteria') {
158
                    $skipToEnd = true;
159
                }
160
                $this->structureInfo['start'] = $index;
161
            }
162
            if (strstr($line, '};')) {
163
                $skipToEnd = false;
164
                $this->structureInfo['end'] = $index;
165
                if (!empty($this->structureInfo['fields'])) {
166
                    $this->structures[] = $this->structureInfo;
167
                }
168
                $this->structureInfo = [
169
                    'name'      =>  null,
170
                    'start'     =>  null,
171
                    'end'       =>  null,
172
                    'fields'    =>  []
173
                ];
174
            }
175
            if ($index > $this->structureInfo['start'] + 1) {
176
                if ($skipToEnd) {
177
                    continue;
178
                }
179
                $fieldName = trim(strtok(str_replace($this->replaceArray, '', $line), '/'));
180
                if (strstr($fieldName, 'bool') || strstr($fieldName, 'return')) {
181
                    $skipToEnd = true;
182
                    continue;
183
                }
184
                $converted = $this->convertNames($fieldName);
185
                if (!strstr($converted, '}') && !$skipToEnd) {
186
                    $this->structureInfo['fields'][] = $converted;
187
                }
188
            }
189
        }
190
    }
191
192
    /**
193
     * Save Structures
194
     */
195
    private function saveStructures()
196
    {
197
        File::makeDirectory($this->saveLocation . $this->build, 0775, true);
198
        $progress = new ProgressBar(new ConsoleOutput(), count($this->structures));
199
        $progress->start();
200
        foreach ($this->structures as $structure) {
201
            if (strlen($structure['name']) > 2) {
202
                $filePointer = fopen($this->saveLocation . $this->build . DIRECTORY_SEPARATOR . $structure['name'] . '.txt', 'w');
203
                fwrite($filePointer, implode(PHP_EOL, $structure['fields']));
204
                fclose($filePointer);
205
                $progress->advance();
206
            }
207
        }
208
        $progress->finish();
209
        $this->info(PHP_EOL . PHP_EOL . 'Successfully created files for ' . count($this->structures) . ' structures!');
210
    }
211
212
    /**
213
     * Convert field names to appropriate ones
214
     * @param string $fieldName
215
     * @return mixed|string
216
     */
217
    private function convertNames(string $fieldName)
218
    {
219
        if ($fieldName === 'helpers' || $fieldName === 'Helpers' || strstr($fieldName, '(')) {
220
            return '}';
221
        }
222
        if (strstr($fieldName, 'PvP')) {
223
            $fieldName = str_replace('PvP', 'Pvp', $fieldName);
224
        }
225
        $splitted = preg_split('/(?<=\\w)(?=[A-Z])/', $fieldName);
226
        $splitted = array_map('strtolower', $splitted);
227
        return $this->replaceKnown(implode('_', $splitted));
228
    }
229
230
    /**
231
     * Replace known issues with fields names
232
     * @param string $fieldName
233
     * @return mixed|string
234
     */
235
    private function replaceKnown(string $fieldName)
236
    {
237
        $replaceData = [
238
            ['_i_d', 'i_d', '_id', 'id'],
239
            ['_u_i', 'u_i', '_ui', 'ui'],
240
            ['_u_w', 'u_w', '_uw', 'uw'],
241
            ['_w_m_o', 'w_m_o', '_wmo', 'wmo']
242
        ];
243
        foreach ($replaceData as $array) {
244
            $chunk = array_chunk($array, count($array) / 2);
245
            $fieldName = str_replace($chunk[0], $chunk[1], $fieldName);
246
        }
247
        if (strstr($fieldName, '[')) {
248
            return strstr($fieldName, '[', true);
249
        }
250
        return $fieldName;
251
    }
252
}
253