1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace eXpansion\Bundle\Maps\Plugins; |
4
|
|
|
|
5
|
|
|
use eXpansion\Bundle\Maps\Model\Map; |
6
|
|
|
use eXpansion\Bundle\Maps\Model\MapQuery; |
7
|
|
|
use eXpansion\Bundle\Maps\Model\Mxmap; |
8
|
|
|
use eXpansion\Bundle\Maps\Model\MxmapQuery; |
9
|
|
|
use eXpansion\Bundle\Maps\Services\JukeboxService; |
10
|
|
|
use eXpansion\Bundle\Maps\Structure\MxInfo; |
11
|
|
|
use eXpansion\Framework\AdminGroups\Helpers\AdminGroups; |
12
|
|
|
use eXpansion\Framework\Core\DataProviders\Listener\ListenerInterfaceExpApplication; |
13
|
|
|
use eXpansion\Framework\Core\Helpers\ChatNotification; |
14
|
|
|
use eXpansion\Framework\Core\Helpers\FileSystem; |
15
|
|
|
use eXpansion\Framework\Core\Helpers\Http; |
16
|
|
|
use eXpansion\Framework\Core\Helpers\Structures\HttpResult; |
17
|
|
|
use eXpansion\Framework\Core\Helpers\TMString; |
18
|
|
|
use eXpansion\Framework\Core\Services\Console; |
19
|
|
|
use eXpansion\Framework\Core\Services\DedicatedConnection\Factory; |
20
|
|
|
use eXpansion\Framework\Core\Storage\GameDataStorage; |
21
|
|
|
use Maniaplanet\DedicatedServer\Structures\Map as DedicatedMap; |
22
|
|
|
use Propel\Runtime\Map\TableMap; |
23
|
|
|
use Psr\Log\LoggerInterface; |
24
|
|
|
|
25
|
|
|
class ManiaExchange implements ListenerInterfaceExpApplication |
26
|
|
|
{ |
27
|
|
|
const SITE_TM = "TM"; |
28
|
|
|
const SITE_SM = "SM"; |
29
|
|
|
|
30
|
|
|
/** @var bool */ |
31
|
|
|
private $downloadProgressing = false; |
32
|
|
|
|
33
|
|
|
/** |
34
|
|
|
* @var Factory |
35
|
|
|
*/ |
36
|
|
|
private $factory; |
37
|
|
|
/** |
38
|
|
|
* @var ChatNotification |
39
|
|
|
*/ |
40
|
|
|
private $chatNotification; |
41
|
|
|
|
42
|
|
|
/** |
43
|
|
|
* @var Http |
44
|
|
|
*/ |
45
|
|
|
private $http; |
46
|
|
|
|
47
|
|
|
/** |
48
|
|
|
* @var AdminGroups |
49
|
|
|
*/ |
50
|
|
|
private $adminGroups; |
51
|
|
|
|
52
|
|
|
/** |
53
|
|
|
* @var GameDataStorage |
54
|
|
|
*/ |
55
|
|
|
private $gameDataStorage; |
56
|
|
|
|
57
|
|
|
/** |
58
|
|
|
* @var Console |
59
|
|
|
*/ |
60
|
|
|
private $console; |
61
|
|
|
|
62
|
|
|
/** |
63
|
|
|
* @var LoggerInterface |
64
|
|
|
*/ |
65
|
|
|
private $logger; |
66
|
|
|
|
67
|
|
|
/** |
68
|
|
|
* @var JukeboxService |
69
|
|
|
*/ |
70
|
|
|
private $jukebox; |
71
|
|
|
|
72
|
|
|
/** |
73
|
|
|
* @var FileSystem |
74
|
|
|
*/ |
75
|
|
|
protected $fileSystem; |
76
|
|
|
|
77
|
|
|
|
78
|
|
|
protected $addQueue = []; |
79
|
|
|
|
80
|
|
|
/** |
81
|
|
|
* ManiaExchange constructor. |
82
|
|
|
* |
83
|
|
|
* @param Factory $factory |
84
|
|
|
* @param ChatNotification $chatNotification |
85
|
|
|
* @param Http $http |
86
|
|
|
* @param AdminGroups $adminGroups |
87
|
|
|
* @param GameDataStorage $gameDataStorage |
88
|
|
|
* @param Console $console |
89
|
|
|
* @param LoggerInterface $logger |
90
|
|
|
* @param JukeboxService $jukebox |
91
|
|
|
* @param FileSystem $fileSystem |
92
|
|
|
*/ |
93
|
|
View Code Duplication |
public function __construct( |
|
|
|
|
94
|
|
|
Factory $factory, |
95
|
|
|
ChatNotification $chatNotification, |
96
|
|
|
Http $http, |
97
|
|
|
AdminGroups $adminGroups, |
98
|
|
|
GameDataStorage $gameDataStorage, |
99
|
|
|
Console $console, |
100
|
|
|
LoggerInterface $logger, |
|
|
|
|
101
|
|
|
JukeboxService $jukebox, |
102
|
|
|
FileSystem $fileSystem |
103
|
|
|
) { |
104
|
|
|
$this->factory = $factory; |
105
|
|
|
$this->chatNotification = $chatNotification; |
106
|
|
|
$this->http = $http; |
107
|
|
|
$this->adminGroups = $adminGroups; |
108
|
|
|
$this->gameDataStorage = $gameDataStorage; |
109
|
|
|
$this->console = $console; |
110
|
|
|
$this->jukebox = $jukebox; |
111
|
|
|
$this->fileSystem = $fileSystem; |
112
|
|
|
} |
113
|
|
|
|
114
|
|
|
/** @var Mxmap[] $maps */ |
115
|
|
|
public function addAllMaps($login, $maps) |
116
|
|
|
{ |
117
|
|
|
if (!$this->adminGroups->hasPermission($login, "maps.add")) { |
118
|
|
|
$this->chatNotification->sendMessage('expansion_mx.chat.nopermission', $login); |
119
|
|
|
|
120
|
|
|
return; |
121
|
|
|
} |
122
|
|
|
|
123
|
|
|
$this->addQueue = $maps; |
124
|
|
|
$this->chatNotification->sendMessage("expansion_mx.chat.downloadstart", null, ["%lenght%" => count($this->addQueue)]); |
125
|
|
|
$map = array_shift($this->addQueue); |
126
|
|
|
$this->addMap($login, $map['mxid'], $map['mxsite']); |
127
|
|
|
} |
128
|
|
|
|
129
|
|
|
/** |
130
|
|
|
* add map to queue |
131
|
|
|
* @param string $login |
132
|
|
|
* @param integer $id |
133
|
|
|
* @param string $mxsite "TM" or "SM" |
134
|
|
|
*/ |
135
|
|
|
public function addMapToQueue($login, $id, $mxsite) |
136
|
|
|
{ |
137
|
|
|
|
138
|
|
|
if (!$this->adminGroups->hasPermission($login, "maps.add")) { |
139
|
|
|
$this->chatNotification->sendMessage('expansion_mx.chat.nopermission', $login); |
140
|
|
|
|
141
|
|
|
return; |
142
|
|
|
} |
143
|
|
|
|
144
|
|
|
if ($this->downloadProgressing || count($this->addQueue) > 1) { |
145
|
|
|
|
146
|
|
|
$this->addQueue[] = ['mxid' => $id, 'mxsite' => $mxsite]; |
147
|
|
|
$this->chatNotification->sendMessage("|info| Adding map to download queue...", $login); |
148
|
|
|
|
149
|
|
|
return; |
150
|
|
|
} else { |
151
|
|
|
$this->addMap($login, $id, $mxsite); |
152
|
|
|
} |
153
|
|
|
|
154
|
|
|
} |
155
|
|
|
|
156
|
|
|
/** |
157
|
|
|
* @param $login |
158
|
|
|
* @param $id |
159
|
|
|
* @param $mxsite |
160
|
|
|
*/ |
161
|
|
|
public function addMap($login, $id, $mxsite) |
162
|
|
|
{ |
163
|
|
|
|
164
|
|
|
$options = [ |
165
|
|
|
CURLOPT_HTTPHEADER => [ |
166
|
|
|
"Content-Type" => "application/json", |
167
|
|
|
"X-ManiaPlanet-ServerLogin" => $this->gameDataStorage->getSystemInfo()->serverLogin, |
168
|
|
|
], |
169
|
|
|
]; |
170
|
|
|
|
171
|
|
|
if (!$mxsite) { |
172
|
|
|
$mxsite = $this->gameDataStorage->getTitleGame(); |
173
|
|
|
} |
174
|
|
|
|
175
|
|
|
$group = $this->adminGroups->getLoginUserGroups($login); |
176
|
|
|
|
177
|
|
|
$this->chatNotification->sendMessage( |
178
|
|
|
'expansion_mx.chat.start', |
179
|
|
|
$group, |
180
|
|
|
["%id%" => $id, "%site%" => $mxsite] |
181
|
|
|
); |
182
|
|
|
$this->downloadProgressing = true; |
183
|
|
|
$this->http->get("https://api.mania-exchange.com/".strtolower($mxsite)."/maps?ids=".$id, |
184
|
|
|
[$this, 'callbackAddMap1'], |
185
|
|
|
['login' => $login, 'site' => $mxsite, 'mxId' => $id], $options); |
186
|
|
|
|
187
|
|
|
} |
188
|
|
|
|
189
|
|
|
|
190
|
|
|
public function callbackAddMap1(HttpResult $result) |
191
|
|
|
{ |
192
|
|
|
$additionalData = $result->getAdditionalData(); |
193
|
|
|
$group = $this->adminGroups->getLoginUserGroups($additionalData['login']); |
194
|
|
|
|
195
|
|
|
$json = json_decode($result->getResponse(), true); |
196
|
|
|
|
197
|
|
|
if (isset($json['StatusCode'])) { |
198
|
|
|
$this->chatNotification->sendMessage( |
199
|
|
|
'expansion_mx.chat.apierror', |
200
|
|
|
$group, |
201
|
|
|
["%status%" => $json['StatusCode'], "%message%" => $json['Message']] |
202
|
|
|
); |
203
|
|
|
$this->downloadProgressing = false; |
204
|
|
|
|
205
|
|
|
return; |
206
|
|
|
} |
207
|
|
|
if (!isset($json[0])) { |
208
|
|
|
$this->chatNotification->sendMessage( |
209
|
|
|
'expansion_mx.chat.json', |
210
|
|
|
$group, |
211
|
|
|
["%message%" => "Can't find info structure."] |
212
|
|
|
); |
213
|
|
|
|
214
|
|
|
return; |
215
|
|
|
} |
216
|
|
|
|
217
|
|
|
$mxInfo = new MxInfo($json[0]); |
218
|
|
|
$additionalData['mxInfo'] = $mxInfo; |
219
|
|
|
|
220
|
|
|
if (!$result->hasError()) { |
221
|
|
|
$options = [ |
222
|
|
|
CURLOPT_FOLLOWLOCATION => false, |
223
|
|
|
CURLOPT_HTTPHEADER => [ |
224
|
|
|
"Content-Type" => "application/json", |
225
|
|
|
"X-ManiaPlanet-ServerLogin" => $this->gameDataStorage->getSystemInfo()->serverLogin, |
226
|
|
|
], |
227
|
|
|
]; |
228
|
|
|
|
229
|
|
|
$this->http->get("https://".strtolower($additionalData['site']). |
230
|
|
|
".mania-exchange.com/tracks/download/".$additionalData['mxId'], |
231
|
|
|
[$this, 'callbackAddMap2'], |
232
|
|
|
$additionalData, $options); |
233
|
|
|
} else { |
234
|
|
|
$this->chatNotification->sendMessage( |
235
|
|
|
'expansion_mx.chat.httperror', |
236
|
|
|
$group, |
237
|
|
|
["%status%" => $result->getHttpCode(), "%message%" => $result->getError()] |
238
|
|
|
); |
239
|
|
|
} |
240
|
|
|
} |
241
|
|
|
|
242
|
|
|
public function callbackAddMap2(HttpResult $result) |
243
|
|
|
{ |
244
|
|
|
$data = $result->getAdditionalData(); |
245
|
|
|
$group = $this->adminGroups->getLoginUserGroups($data['login']); |
246
|
|
|
|
247
|
|
|
if ($result->hasError()) { |
248
|
|
|
|
249
|
|
|
if ($result->getHttpCode() == 302) { |
250
|
|
|
$this->chatNotification->sendMessage( |
251
|
|
|
'expansion_mx.chat.decline', |
252
|
|
|
$group, |
253
|
|
|
[] |
254
|
|
|
); |
255
|
|
|
$this->downloadProgressing = false; |
256
|
|
|
|
257
|
|
|
return; |
258
|
|
|
} |
259
|
|
|
|
260
|
|
|
$this->chatNotification->sendMessage( |
261
|
|
|
'expansion_mx.chat.httperror', |
262
|
|
|
$group, |
263
|
|
|
["%status%" => $result->getHttpCode(), "%message%" => $result->getError()] |
264
|
|
|
); |
265
|
|
|
|
266
|
|
|
$this->downloadProgressing = false; |
267
|
|
|
|
268
|
|
|
return; |
269
|
|
|
} |
270
|
|
|
|
271
|
|
|
/** @var MxInfo $info */ |
272
|
|
|
$info = $data['mxInfo']; |
273
|
|
|
|
274
|
|
|
$authorName = $this->cleanString($info->username); |
275
|
|
|
$mapName = $this->cleanString( |
276
|
|
|
trim( |
277
|
|
|
mb_convert_encoding( |
278
|
|
|
substr(TMString::trimStyles($info->gbxMapName), 0, 20), |
279
|
|
|
"7bit", |
280
|
|
|
"UTF-8" |
281
|
|
|
) |
282
|
|
|
) |
283
|
|
|
); |
284
|
|
|
|
285
|
|
|
$filename = $data['mxId']."-".$authorName."-".$mapName.".Map.Gbx"; |
286
|
|
|
|
287
|
|
|
try { |
288
|
|
|
$titlepack = $this->gameDataStorage->getSystemInfo()->titleId; |
289
|
|
|
$fileSystem = $this->fileSystem->getUserData(); |
290
|
|
|
$dir = 'Maps'.DIRECTORY_SEPARATOR.$titlepack; |
291
|
|
|
$file = $dir.DIRECTORY_SEPARATOR.$filename; |
292
|
|
|
|
293
|
|
|
if (!$fileSystem->createDir($dir)) { |
294
|
|
|
$this->console->writeln('<error>Error while adding map, can\'t create folder!</error>'); |
295
|
|
|
|
296
|
|
|
return; |
297
|
|
|
} |
298
|
|
|
|
299
|
|
|
if (!$fileSystem->has($file)) { |
300
|
|
|
$fileSystem->write($file, $result->getResponse()); |
301
|
|
|
} |
302
|
|
|
|
303
|
|
|
if (!$this->factory->getConnection()->checkMapForCurrentServerParams($titlepack.DIRECTORY_SEPARATOR.$filename)) { |
304
|
|
|
$this->chatNotification->sendMessage("expansion_mx.chat.fail"); |
305
|
|
|
|
306
|
|
|
return; |
307
|
|
|
} |
308
|
|
|
|
309
|
|
|
$map = $this->factory->getConnection()->getMapInfo($titlepack.DIRECTORY_SEPARATOR.$filename); |
310
|
|
|
$this->factory->getConnection()->addMap($map->fileName); |
311
|
|
|
|
312
|
|
|
$this->jukebox->addMap($map, $data['login']); |
313
|
|
|
$this->chatNotification->sendMessage( |
314
|
|
|
'expansion_mx.chat.success', |
315
|
|
|
null, |
316
|
|
|
[ |
317
|
|
|
"%mxid%" => $data['mxId'], |
318
|
|
|
"%mapauthor%" => $map->author, |
319
|
|
|
"%mapname%" => TMString::trimControls($map->name), |
320
|
|
|
] |
321
|
|
|
); |
322
|
|
|
|
323
|
|
|
$this->persistMapData($map, $info); |
324
|
|
|
$this->downloadProgressing = false; |
325
|
|
|
} catch (\Exception $e) { |
326
|
|
|
$this->chatNotification->sendMessage( |
327
|
|
|
'expansion_mx.chat.dedicatedexception', |
328
|
|
|
$group, ["%message%" => $e->getMessage()] |
329
|
|
|
); |
330
|
|
|
// $this->logger->alert("Error while adding map : ".$e->getMessage(), ['exception' => $e]); |
331
|
|
|
$this->downloadProgressing = false; |
332
|
|
|
} |
333
|
|
|
|
334
|
|
|
if (count($this->addQueue) > 0) { |
335
|
|
|
$map = array_shift($this->addQueue); |
336
|
|
|
$this->chatNotification->sendMessage("expansion_mx.chat.queue", null, |
337
|
|
|
["%length%" => count($this->addQueue)]); |
338
|
|
|
$this->addMap($data['login'], $map['mxid'], $map['mxsite']); |
339
|
|
|
} |
340
|
|
|
} |
341
|
|
|
|
342
|
|
|
/** |
343
|
|
|
* @param DedicatedMap $map |
344
|
|
|
* @param MxInfo $mxInfo |
345
|
|
|
* @throws \Propel\Runtime\Exception\PropelException |
346
|
|
|
*/ |
347
|
|
|
protected function persistMapData($map, $mxInfo) |
348
|
|
|
{ |
349
|
|
|
|
350
|
|
|
$mapquery = new MapQuery(); |
351
|
|
|
$dbMap = $mapquery->findOneByMapuid($map->uId); |
352
|
|
|
|
353
|
|
|
if ($dbMap) { |
354
|
|
|
$dbMap->fromArray($this->convertMap($map), TableMap::TYPE_FIELDNAME); |
355
|
|
|
} else { |
356
|
|
|
$dbMap = new Map(); |
357
|
|
|
$dbMap->fromArray($this->convertMap($map), TableMap::TYPE_FIELDNAME); |
358
|
|
|
} |
359
|
|
|
|
360
|
|
|
$mxquery = new MxmapQuery(); |
361
|
|
|
$mxMap = $mxquery->findOneByTrackuid($map->uId); |
362
|
|
|
|
363
|
|
|
if ($mxMap) { |
364
|
|
|
$mxMap->fromArray($mxInfo->toArray(), TableMap::TYPE_FIELDNAME); |
365
|
|
|
} else { |
366
|
|
|
$mxMap = new Mxmap(); |
367
|
|
|
$mxMap->fromArray($mxInfo->toArray(), TableMap::TYPE_FIELDNAME); |
368
|
|
|
} |
369
|
|
|
$dbMap->addMxmap($mxMap); |
370
|
|
|
$dbMap->save(); |
371
|
|
|
$mxMap->save(); |
372
|
|
|
} |
373
|
|
|
|
374
|
|
|
/** |
375
|
|
|
* @param DedicatedMap $map |
376
|
|
|
* @return array |
377
|
|
|
*/ |
378
|
|
|
private function convertMap($map) |
379
|
|
|
{ |
380
|
|
|
$outMap = (array)$map; |
381
|
|
|
$outMap["mapUid"] = $map->uId; |
382
|
|
|
|
383
|
|
|
return $outMap; |
384
|
|
|
|
385
|
|
|
} |
386
|
|
|
|
387
|
|
|
/** |
388
|
|
|
* Remove special characters from map name |
389
|
|
|
* |
390
|
|
|
* @param string $string |
391
|
|
|
* @return mixed |
392
|
|
|
*/ |
393
|
|
|
protected function cleanString($string) |
394
|
|
|
{ |
395
|
|
|
return str_replace(array("/", "\\", ":", ".", "?", "*", '"', "|", "<", ">", "'"), "", $string); |
396
|
|
|
} |
397
|
|
|
|
398
|
|
|
|
399
|
|
|
/** |
400
|
|
|
* called at eXpansion init |
401
|
|
|
* |
402
|
|
|
* @return void |
403
|
|
|
*/ |
404
|
|
|
public function onApplicationInit() |
405
|
|
|
{ |
406
|
|
|
// Nothin here. |
407
|
|
|
} |
408
|
|
|
|
409
|
|
|
/** |
410
|
|
|
* called when init is done and callbacks are enabled |
411
|
|
|
* |
412
|
|
|
* @return void |
413
|
|
|
*/ |
414
|
|
|
public function onApplicationReady() |
415
|
|
|
{ |
416
|
|
|
// Nothin here. |
417
|
|
|
} |
418
|
|
|
|
419
|
|
|
/** |
420
|
|
|
* called when requesting application stop |
421
|
|
|
* |
422
|
|
|
* @return void |
423
|
|
|
*/ |
424
|
|
|
public function onApplicationStop() |
425
|
|
|
{ |
426
|
|
|
// Nothin here. |
427
|
|
|
} |
428
|
|
|
} |
429
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.