download maps asynchronously
This commit is contained in:
		
				
					committed by
					
						 Steffen Schröder
						Steffen Schröder
					
				
			
			
				
	
			
			
			
						parent
						
							4875c14a7d
						
					
				
				
					commit
					4c8b247896
				
			| @@ -10,6 +10,16 @@ use ManiaControl\ManiaControl; | ||||
|  * @author kremsy & steeffeen | ||||
|  */ | ||||
| class AsynchronousFileReader implements TimerListener { | ||||
| 	/** | ||||
| 	 * Constants | ||||
| 	 */ | ||||
| 	const TIMEOUT_ERROR        = 'Timed out while reading data'; | ||||
| 	const RESPONSE_ERROR       = 'Connection or response error'; | ||||
| 	const NO_DATA_ERROR        = 'No data returned'; | ||||
| 	const INVALID_RESULT_ERROR = 'Invalid Result'; | ||||
| 	const SOCKET_TIMEOUT       = 10; | ||||
|  | ||||
|  | ||||
| 	/** | ||||
| 	 * Private Properties | ||||
| 	 */ | ||||
| @@ -27,37 +37,33 @@ class AsynchronousFileReader implements TimerListener { | ||||
|  | ||||
| 	/** | ||||
| 	 * Appends the Data | ||||
| 	 * @throws \Exception | ||||
| 	 */ | ||||
| 	public function appendData() { | ||||
| 		foreach($this->sockets as $key => &$socket) { | ||||
| 			/** @var SocketStructure $socket */ | ||||
| 			$socket->streamBuffer .= fread($socket->socket, 1024); | ||||
| 			$info = stream_get_meta_data($socket->socket); | ||||
| 			$socket->streamBuffer .= fread($socket->socket, 4096); | ||||
|  | ||||
| 			if (feof($socket->socket) || $info['timed_out']) { | ||||
| 			if (feof($socket->socket) || time() > ($socket->creationTime + self::SOCKET_TIMEOUT)) { | ||||
| 				fclose($socket->socket); | ||||
| 				unset($this->sockets[$key]); | ||||
|  | ||||
| 				if ($info['timed_out']) { | ||||
| 					throw new \Exception("Timed out while reading data from " . $socket->url); | ||||
| 				$result = array(); | ||||
| 				$error  = 0; | ||||
| 				if (time() > ($socket->creationTime + self::SOCKET_TIMEOUT)) { | ||||
| 					$error = self::TIMEOUT_ERROR; | ||||
| 				} else if (substr($socket->streamBuffer, 9, 3) != "200") { | ||||
| 					$error = self::RESPONSE_ERROR; | ||||
| 				} else if ($socket->streamBuffer == '') { | ||||
| 					$error = self::NO_DATA_ERROR; | ||||
| 				} else { | ||||
| 					$result = explode("\r\n\r\n", $socket->streamBuffer, 2); | ||||
|  | ||||
| 					if (count($result) < 2) { | ||||
| 						$error = self::INVALID_RESULT_ERROR; | ||||
| 					} | ||||
| 				} | ||||
|  | ||||
| 				if (substr($socket->streamBuffer, 9, 3) != "200") { | ||||
| 					throw new \Exception("Connection or response error on " . $socket->url); | ||||
| 				} | ||||
|  | ||||
| 				if ($socket->streamBuffer == '') { | ||||
| 					throw new \Exception("No data returned from " . $socket->url); | ||||
| 				} | ||||
|  | ||||
| 				$result = explode("\r\n\r\n", $socket->streamBuffer, 2); | ||||
|  | ||||
| 				if (count($result) < 2) { | ||||
| 					throw new \Exception("Invalid Result"); | ||||
| 				} | ||||
|  | ||||
| 				call_user_func($socket->function, $result[1]); | ||||
| 				call_user_func($socket->function, $result[1], $error); | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| @@ -87,7 +93,6 @@ class AsynchronousFileReader implements TimerListener { | ||||
| 		if (!$socket) { | ||||
| 			return false; | ||||
| 		} | ||||
| 		stream_set_timeout($socket, 10); | ||||
|  | ||||
| 		$query = 'GET ' . $urlData['path'] . $urlQuery . ' HTTP/1.0' . PHP_EOL; | ||||
| 		$query .= 'Host: ' . $urlData['host'] . PHP_EOL; | ||||
|   | ||||
| @@ -14,11 +14,13 @@ class SocketStructure { | ||||
| 	public $socket; | ||||
| 	public $function; | ||||
| 	public $url; | ||||
| 	public $creationTime; | ||||
|  | ||||
| 	public function __construct($url, $socket, $function) { | ||||
| 		$this->url          = $url; | ||||
| 		$this->socket       = $socket; | ||||
| 		$this->function     = $function; | ||||
| 		$this->creationTime = time(); | ||||
| 		$this->streamBuffer = ''; | ||||
| 	} | ||||
| } | ||||
| @@ -107,7 +107,7 @@ class ManiaExchangeList implements CallbackListener, ManialinkPageAnswerListener | ||||
| 		}; | ||||
|  | ||||
| 		// search for matching maps | ||||
| 		$this->maniaControl->mapManager->mxManager->getMapsAssync($function, $searchString, $author, $environment); | ||||
| 		$this->maniaControl->mapManager->mxManager->getMapsAsync($function, $searchString, $author, $environment); | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
|   | ||||
| @@ -212,7 +212,7 @@ class ManiaExchangeManager { | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Get the Whole Maplist from MX by Mixed Uid and Id String fetch | ||||
| 	 * Get the Whole MapList from MX by Mixed Uid and Id String fetch | ||||
| 	 * | ||||
| 	 * @param $string | ||||
| 	 * @return array|null | ||||
| @@ -225,33 +225,44 @@ class ManiaExchangeManager { | ||||
| 		// compile search URL | ||||
| 		$url = 'http://api.mania-exchange.com/' . $titlePrefix . '/maps/?ids=' . $string; | ||||
|  | ||||
| 		try { //FIXME exceptions get not caught here? | ||||
| 			$success = $this->maniaControl->fileReader->loadFile($url, function ($mapInfo) use ($titlePrefix, $url) { | ||||
| 				$mxMapList = json_decode($mapInfo); | ||||
| 				if ($mxMapList === null) { | ||||
| 					trigger_error('Cannot decode searched JSON data from ' . $url); | ||||
| 					return null; | ||||
| 				} | ||||
| 		$success = $this->maniaControl->fileReader->loadFile($url, function ($mapInfo, $error) use ($titlePrefix, $url) { | ||||
| 			if ($error) { | ||||
| 				trigger_error($error); | ||||
| 				return null; | ||||
| 			} | ||||
|  | ||||
| 				$maps = array(); | ||||
| 				foreach($mxMapList as $map) { | ||||
| 					if (!empty($map)) { | ||||
| 						array_push($maps, new MXMapInfo($titlePrefix, $map)); | ||||
| 					} | ||||
| 				} | ||||
| 			$mxMapList = json_decode($mapInfo); | ||||
| 			if ($mxMapList === null) { | ||||
| 				trigger_error('Cannot decode searched JSON data from ' . $url); | ||||
| 				return null; | ||||
| 			} | ||||
|  | ||||
| 				$this->updateMapObjectsWithManiaExchangeIds($maps); | ||||
| 				return true; | ||||
| 			}, "application/json"); | ||||
| 		} catch(\Exception $e) { | ||||
| 			$this->maniaControl->log("Error while fetching Map Infos" . $e->getTraceAsString()); | ||||
| 			return false; | ||||
| 		} | ||||
| 			$maps = array(); | ||||
| 			foreach($mxMapList as $map) { | ||||
| 				if (!empty($map)) { | ||||
| 					array_push($maps, new MXMapInfo($titlePrefix, $map)); | ||||
| 				} | ||||
| 			} | ||||
|  | ||||
| 			$this->updateMapObjectsWithManiaExchangeIds($maps); | ||||
| 			return true; | ||||
| 		}, "application/json"); | ||||
|  | ||||
| 		return $success; | ||||
| 	} | ||||
|  | ||||
| 	public function getMapsAssync($function, $name = '', $author = '', $env = '', $maxMapsReturned = 100, $searchOrder = self::SEARCH_ORDER_UPDATED_NEWEST) { | ||||
| 	/** | ||||
| 	 * Fetch a MapList Asynchronously | ||||
| 	 * | ||||
| 	 * @param        $function | ||||
| 	 * @param string $name | ||||
| 	 * @param string $author | ||||
| 	 * @param string $env | ||||
| 	 * @param int    $maxMapsReturned | ||||
| 	 * @param int    $searchOrder | ||||
| 	 * @return bool | ||||
| 	 */ | ||||
| 	public function getMapsAsync($function, $name = '', $author = '', $env = '', $maxMapsReturned = 100, $searchOrder = self::SEARCH_ORDER_UPDATED_NEWEST) { | ||||
| 		if (!is_callable($function)) { | ||||
| 			$this->maniaControl->log("Function is not callable"); | ||||
| 			return false; | ||||
| @@ -283,105 +294,36 @@ class ManiaExchangeManager { | ||||
| 		$url .= '&limit=' . $maxMapsReturned; | ||||
| 		$url .= '&mtype=' . $mapTypes; | ||||
|  | ||||
| 		try { | ||||
| 			$success = $this->maniaControl->fileReader->loadFile($url, function ($mapInfo) use (&$function) { | ||||
| 				// Get Title Id | ||||
| 				$titleId     = $this->maniaControl->server->titleId; | ||||
| 				$titlePrefix = strtolower(substr($titleId, 0, 2)); | ||||
|  | ||||
| 				$mxMapList = json_decode($mapInfo); | ||||
| 				if ($mxMapList === null) { | ||||
| 					trigger_error('Cannot decode searched JSON data'); | ||||
| 					return null; | ||||
| 		$fileFunc = function ($mapInfo, $error) use (&$function, $titlePrefix) { | ||||
| 			if ($error) { | ||||
| 				trigger_error($error); | ||||
| 				return null; | ||||
| 			} | ||||
|  | ||||
| 			$mxMapList = json_decode($mapInfo); | ||||
| 			if ($mxMapList === null) { | ||||
| 				trigger_error('Cannot decode searched JSON data'); | ||||
| 				return null; | ||||
| 			} | ||||
|  | ||||
| 			$maps = array(); | ||||
| 			foreach($mxMapList as $map) { | ||||
| 				if (!empty($map)) { | ||||
| 					array_push($maps, new MXMapInfo($titlePrefix, $map)); | ||||
| 				} | ||||
| 			} | ||||
|  | ||||
| 				$maps = array(); | ||||
| 				foreach($mxMapList as $map) { | ||||
| 					if (!empty($map)) { | ||||
| 						array_push($maps, new MXMapInfo($titlePrefix, $map)); | ||||
| 					} | ||||
| 				} | ||||
| 			call_user_func($function, $maps); | ||||
|  | ||||
| 				call_user_func($function, $maps); | ||||
| 			return true; | ||||
| 		}; | ||||
|  | ||||
| 				return true; | ||||
| 			}, "application/json"); | ||||
| 		} catch(\Exception $e) { | ||||
| 			var_dump($e); | ||||
| 			return false; | ||||
| 		} | ||||
| 		$success = $this->maniaControl->fileReader->loadFile($url, $fileFunc, "application/json"); | ||||
|  | ||||
| 		return $success; | ||||
| 	} | ||||
|  | ||||
|  | ||||
| 	/** | ||||
| 	 * Gets a Maplist from Mania Exchange | ||||
| 	 * | ||||
| 	 * @param string $name | ||||
| 	 * @param string $author | ||||
| 	 * @param string $env | ||||
| 	 * @param int    $maxMapsReturned | ||||
| 	 * @param int    $searchOrder | ||||
| 	 * @return array null | ||||
| 	 */ | ||||
| 	public function getMaps($name = '', $author = '', $env = '', $maxMapsReturned = 100, $searchOrder = self::SEARCH_ORDER_UPDATED_NEWEST) { | ||||
| 		// Get Title Id | ||||
| 		$titleId     = $this->maniaControl->server->titleId; | ||||
| 		$titlePrefix = strtolower(substr($titleId, 0, 2)); | ||||
|  | ||||
| 		// Get MapTypes | ||||
| 		$scriptInfos = $this->maniaControl->client->getModeScriptInfo(); | ||||
|  | ||||
| 		$mapTypes = $scriptInfos->compatibleMapTypes; | ||||
|  | ||||
| 		// compile search URL | ||||
| 		$url = 'http://' . $titlePrefix . '.mania-exchange.com/tracksearch?api=on'; | ||||
|  | ||||
| 		if ($env != '') { | ||||
| 			$url .= '&environments=' . $this->getEnvironment($env); | ||||
| 		} | ||||
| 		if ($name != '') { | ||||
| 			$url .= '&trackname=' . str_replace(" ", "%20", $name); | ||||
| 		} | ||||
| 		if ($author != '') { | ||||
| 			$url .= '&author=' . $author; | ||||
| 		} | ||||
|  | ||||
| 		$url .= '&priord=' . $searchOrder; | ||||
| 		$url .= '&limit=' . $maxMapsReturned; | ||||
| 		$url .= '&mtype=' . $mapTypes; | ||||
|  | ||||
| 		$mapInfo = FileUtil::loadFile($url, "application/json"); | ||||
|  | ||||
| 		if ($mapInfo === false) { | ||||
| 			$this->error = 'Connection or response error on ' . $url; | ||||
| 			return array(); | ||||
| 		} elseif ($mapInfo === -1) { | ||||
| 			$this->error = 'Timed out while reading data from ' . $url; | ||||
| 			return array(); | ||||
| 		} elseif ($mapInfo == '') { | ||||
| 			if (empty($maps)) { | ||||
| 				$this->error = 'No data returned from ' . $url; | ||||
| 				return array(); | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		$mxMapList = json_decode($mapInfo); | ||||
| 		if ($mxMapList === null) { | ||||
| 			trigger_error('Cannot decode searched JSON data from ' . $url); | ||||
| 			return null; | ||||
| 		} | ||||
|  | ||||
| 		$maps = array(); | ||||
| 		foreach($mxMapList as $map) { | ||||
| 			if (!empty($map)) { | ||||
| 				array_push($maps, new MXMapInfo($titlePrefix, $map)); | ||||
| 			} | ||||
| 		} | ||||
| 		return $maps; | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Gets the Current Environemnt by String | ||||
| 	 * | ||||
|   | ||||
| @@ -10,6 +10,7 @@ use ManiaControl\Formatter; | ||||
| use ManiaControl\ManiaControl; | ||||
| use ManiaControl\ManiaExchange\ManiaExchangeList; | ||||
| use ManiaControl\ManiaExchange\ManiaExchangeManager; | ||||
| use ManiaControl\ManiaExchange\MXMapInfo; | ||||
| use ManiaControl\Players\Player; | ||||
|  | ||||
| /** | ||||
| @@ -531,97 +532,114 @@ class MapManager implements CallbackListener { | ||||
| 				return; | ||||
| 			} | ||||
|  | ||||
| 			$url  = "http://{$title}.mania-exchange.com/tracks/download/{$mapId}"; | ||||
| 			$file = FileUtil::loadFile($url); | ||||
| 			if (!$file) { | ||||
| 				// Download error | ||||
| 				$this->maniaControl->chat->sendError('Download failed!', $login); | ||||
| 			$url = "http://{$title}.mania-exchange.com/tracks/download/{$mapId}"; | ||||
|  | ||||
| 			//Download the file | ||||
| 			$function = function ($file, $error) use (&$login, &$mapInfo, &$mapDir, &$update) { | ||||
| 				if (!$file) { | ||||
| 					// Download error | ||||
| 					$this->maniaControl->chat->sendError('Download failed!', $login); | ||||
| 					return; | ||||
| 				} | ||||
| 				$this->processMapFile($file, $mapInfo, $mapDir, $login, $update); | ||||
| 			}; | ||||
| 			$this->maniaControl->fileReader->loadFile($url, $function); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Process the MapFile | ||||
| 	 * | ||||
| 	 * @param           $file | ||||
| 	 * @param MXMapInfo $mapInfo | ||||
| 	 * @param           $mapDir | ||||
| 	 * @param           $login | ||||
| 	 * @param           $update | ||||
| 	 */ | ||||
| 	private function processMapFile($file, MXMapInfo $mapInfo, $mapDir, $login, $update) { | ||||
| 		//Check if map is already on the server | ||||
| 		if ($this->getMapByUid($mapInfo->uid) != null) { | ||||
| 			// Download error | ||||
| 			$this->maniaControl->chat->sendError('Map is already on the server!', $login); | ||||
| 			return; | ||||
| 		} | ||||
|  | ||||
| 		// Save map | ||||
| 		$fileName = $mapInfo->id . '_' . $mapInfo->name . '.Map.Gbx'; | ||||
| 		$fileName = FileUtil::getClearedFileName($fileName); | ||||
|  | ||||
| 		$downloadDirectory = $this->maniaControl->settingManager->getSetting($this, 'MapDownloadDirectory', 'MX'); | ||||
|  | ||||
| 		$mapFileName = $downloadDirectory . '/' . $fileName; | ||||
|  | ||||
| 		//Check if it can get locally Written | ||||
| 		if (is_dir($mapDir)) { | ||||
| 			// Create download directory if necessary | ||||
| 			if (!is_dir($mapDir . $downloadDirectory) && !mkdir($mapDir . $downloadDirectory)) { | ||||
| 				trigger_error("ManiaControl doesn't have to rights to save maps in '{$mapDir}{$downloadDirectory}'."); | ||||
| 				$this->maniaControl->chat->sendError("ManiaControl doesn't have the rights to save maps.", $login); | ||||
| 				return; | ||||
| 			} | ||||
|  | ||||
| 			//Check if map is already on the server | ||||
| 			if ($this->getMapByUid($mapInfo->uid) != null) { | ||||
| 				// Download error | ||||
| 				$this->maniaControl->chat->sendError('Map is already on the server!', $login); | ||||
| 			$mapDir .= $downloadDirectory . '/'; | ||||
|  | ||||
| 			if (!file_put_contents($mapDir . $fileName, $file)) { | ||||
| 				// Save error | ||||
| 				$this->maniaControl->chat->sendError('Saving map failed!', $login); | ||||
| 				return; | ||||
| 			} | ||||
|  | ||||
| 			// Save map | ||||
| 			$fileName = $mapId . '_' . $mapInfo->name . '.Map.Gbx'; | ||||
| 			$fileName = FileUtil::getClearedFileName($fileName); | ||||
|  | ||||
| 			$downloadDirectory = $this->maniaControl->settingManager->getSetting($this, 'MapDownloadDirectory', 'MX'); | ||||
|  | ||||
| 			$mapFileName = $downloadDirectory . '/' . $fileName; | ||||
|  | ||||
| 			//Check if it can get locally Written | ||||
| 			if (is_dir($mapDir)) { | ||||
| 				// Create download directory if necessary | ||||
| 				if (!is_dir($mapDir . $downloadDirectory) && !mkdir($mapDir . $downloadDirectory)) { | ||||
| 					trigger_error("ManiaControl doesn't have to rights to save maps in '{$mapDir}{$downloadDirectory}'."); | ||||
| 					$this->maniaControl->chat->sendError("ManiaControl doesn't have the rights to save maps.", $login); | ||||
| 					return; | ||||
| 				} | ||||
|  | ||||
| 				$mapDir .= $downloadDirectory . '/'; | ||||
|  | ||||
| 				if (!file_put_contents($mapDir . $fileName, $file)) { | ||||
| 					// Save error | ||||
| 					$this->maniaControl->chat->sendError('Saving map failed!', $login); | ||||
| 					return; | ||||
| 				} | ||||
| 				//Write via Write File Method | ||||
| 			} else { | ||||
| 				try { | ||||
| 					$this->maniaControl->client->writeFileFromString($mapFileName, $file); | ||||
| 				} catch(\Exception $e) { | ||||
| 					$this->maniaControl->chat->sendError("Map is too big for a remote save.", $login); | ||||
| 					return; | ||||
| 				} | ||||
| 			} | ||||
|  | ||||
| 			// Check for valid map | ||||
| 			//Write via Write File Method | ||||
| 		} else { | ||||
| 			try { | ||||
| 				$this->maniaControl->client->checkMapForCurrentServerParams($mapFileName); | ||||
| 				$this->maniaControl->client->writeFileFromString($mapFileName, $file); | ||||
| 			} catch(\Exception $e) { | ||||
| 				trigger_error("Couldn't check if map is valid ('{$mapFileName}'). " . $e->getMessage()); | ||||
| 				$this->maniaControl->chat->sendError('Wrong MapType or not validated!', $login); | ||||
| 				$this->maniaControl->chat->sendError("Map is too big for a remote save.", $login); | ||||
| 				return; | ||||
| 			} | ||||
|  | ||||
| 			// Add map to map list | ||||
| 			try { | ||||
| 				$this->maniaControl->client->insertMap($mapFileName); | ||||
| 			} catch(\Exception $e) { | ||||
| 				$this->maniaControl->chat->sendError("Couldn't add map to match settings!", $login); | ||||
| 				return; | ||||
| 			} | ||||
|  | ||||
| 			$this->updateFullMapList(); | ||||
|  | ||||
| 			//Update Mx MapInfo | ||||
| 			$this->maniaControl->mapManager->mxManager->updateMapObjectsWithManiaExchangeIds(array($mapInfo)); | ||||
|  | ||||
| 			//Update last updated time | ||||
| 			$map = $this->maps[$mapInfo->uid]; | ||||
| 			/** @var Map $map */ | ||||
| 			$map->lastUpdate = time(); | ||||
|  | ||||
| 			$player = $this->maniaControl->playerManager->getPlayer($login); | ||||
|  | ||||
| 			if (!$update) { | ||||
| 				//Message | ||||
| 				$message = '$<' . $player->nickname . '$> added $<' . $mapInfo->name . '$>!'; | ||||
| 				$this->maniaControl->chat->sendSuccess($message); | ||||
| 				$this->maniaControl->log($message, true); | ||||
| 				// Queue requested Map | ||||
| 				$this->maniaControl->mapManager->mapQueue->addMapToMapQueue($login, $mapInfo->uid); | ||||
| 			} else { | ||||
| 				$message = '$<' . $player->nickname . '$> updated $<' . $mapInfo->name . '$>!'; | ||||
| 				$this->maniaControl->chat->sendSuccess($message); | ||||
| 				$this->maniaControl->log($message, true); | ||||
| 			} | ||||
| 		} | ||||
| 		// TODO: add local map by filename | ||||
|  | ||||
| 		// Check for valid map | ||||
| 		try { | ||||
| 			$this->maniaControl->client->checkMapForCurrentServerParams($mapFileName); | ||||
| 		} catch(\Exception $e) { | ||||
| 			trigger_error("Couldn't check if map is valid ('{$mapFileName}'). " . $e->getMessage()); | ||||
| 			$this->maniaControl->chat->sendError('Wrong MapType or not validated!', $login); | ||||
| 			return; | ||||
| 		} | ||||
|  | ||||
| 		// Add map to map list | ||||
| 		try { | ||||
| 			$this->maniaControl->client->insertMap($mapFileName); | ||||
| 		} catch(\Exception $e) { | ||||
| 			$this->maniaControl->chat->sendError("Couldn't add map to match settings!", $login); | ||||
| 			return; | ||||
| 		} | ||||
|  | ||||
| 		$this->updateFullMapList(); | ||||
|  | ||||
| 		//Update Mx MapInfo | ||||
| 		$this->maniaControl->mapManager->mxManager->updateMapObjectsWithManiaExchangeIds(array($mapInfo)); | ||||
|  | ||||
| 		//Update last updated time | ||||
| 		$map = $this->maps[$mapInfo->uid]; | ||||
| 		/** @var Map $map */ | ||||
| 		$map->lastUpdate = time(); | ||||
|  | ||||
| 		$player = $this->maniaControl->playerManager->getPlayer($login); | ||||
|  | ||||
| 		if (!$update) { | ||||
| 			//Message | ||||
| 			$message = '$<' . $player->nickname . '$> added $<' . $mapInfo->name . '$>!'; | ||||
| 			$this->maniaControl->chat->sendSuccess($message); | ||||
| 			$this->maniaControl->log($message, true); | ||||
| 			// Queue requested Map | ||||
| 			$this->maniaControl->mapManager->mapQueue->addMapToMapQueue($login, $mapInfo->uid); | ||||
| 		} else { | ||||
| 			$message = '$<' . $player->nickname . '$> updated $<' . $mapInfo->name . '$>!'; | ||||
| 			$this->maniaControl->chat->sendSuccess($message); | ||||
| 			$this->maniaControl->log($message, true); | ||||
| 		} | ||||
| 	} | ||||
| 	// TODO: add local map by filename | ||||
|  | ||||
| }  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user