grr this gitclient sucks
This commit is contained in:
		
							
								
								
									
										103
									
								
								application/core/authentication.mControl.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										103
									
								
								application/core/authentication.mControl.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,103 @@ | ||||
| <?php | ||||
|  | ||||
| namespace mControl; | ||||
|  | ||||
| /** | ||||
|  * Class handling authentication levels | ||||
|  * | ||||
|  * @author steeffeen | ||||
|  */ | ||||
| class Authentication { | ||||
|  | ||||
| 	/** | ||||
| 	 * Constants | ||||
| 	 */ | ||||
| 	public $RIGHTS_LEVELS = array(-1 => 'none', 0 => 'superadmin', 1 => 'admin', 2 => 'operator', 3 => 'all'); | ||||
|  | ||||
| 	/** | ||||
| 	 * Private properties | ||||
| 	 */ | ||||
| 	private $mControl = null; | ||||
|  | ||||
| 	private $config = null; | ||||
|  | ||||
| 	/** | ||||
| 	 * Construct authentication manager | ||||
| 	 */ | ||||
| 	public function __construct($mControl) { | ||||
| 		$this->mControl = $mControl; | ||||
| 		 | ||||
| 		// Load config | ||||
| 		$this->config = Tools::loadConfig('authentication.mControl.xml'); | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Check if the player has enough rights | ||||
| 	 * | ||||
| 	 * @param string $login        	 | ||||
| 	 * @param string $defaultRight        	 | ||||
| 	 * @param string $neededRight        	 | ||||
| 	 * @return bool | ||||
| 	 */ | ||||
| 	public function checkRight($login, $neededRight) { | ||||
| 		$right = $this->getRights($login); | ||||
| 		return $this->compareRights($right, $neededRight); | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Compare if the rights are enough | ||||
| 	 * | ||||
| 	 * @param string $hasRight        	 | ||||
| 	 * @param string $neededRight        	 | ||||
| 	 * @return bool | ||||
| 	 */ | ||||
| 	public function compareRights($hasRight, $neededRight) { | ||||
| 		if (!in_array($hasRight, $this->RIGHTS_LEVELS) || !in_array($neededRight, $this->RIGHTS_LEVELS)) { | ||||
| 			return false; | ||||
| 		} | ||||
| 		$hasLevel = array_search($hasRight, $this->RIGHTS_LEVELS); | ||||
| 		$neededLevel = array_search($neededRight, $this->RIGHTS_LEVELS); | ||||
| 		if ($hasLevel > $neededLevel) { | ||||
| 			return false; | ||||
| 		} | ||||
| 		else { | ||||
| 			return true; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Get rights of the given login | ||||
| 	 * | ||||
| 	 * @param string $login        	 | ||||
| 	 * @param string $defaultRights        	 | ||||
| 	 * @return string | ||||
| 	 */ | ||||
| 	public function getRights($login, $defaultRight = 'all') { | ||||
| 		$groups = $this->config->xpath('//login[text()="' . $login . '"]/..'); | ||||
| 		if (empty($groups)) return $defaultRight; | ||||
| 		$right = $defaultRight; | ||||
| 		$rightLevel = array_search($right, $this->RIGHTS_LEVELS); | ||||
| 		foreach ($groups as $group) { | ||||
| 			$level = array_search($group->getName(), $this->RIGHTS_LEVELS); | ||||
| 			if ($level === false) continue; | ||||
| 			if ($level < $rightLevel || $rightLevel === false) { | ||||
| 				$right = $group->getName(); | ||||
| 				$rightLevel = $level; | ||||
| 			} | ||||
| 		} | ||||
| 		return $right; | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Sends an error message to the login | ||||
| 	 * | ||||
| 	 * @param string $login        	 | ||||
| 	 */ | ||||
| 	public function sendNotAllowed($login) { | ||||
| 		if (!$this->iControl->chat->sendError('You do not have the required rights to perform this command!', $login)) { | ||||
| 			trigger_error("Couldn't send forbidden message to login '" . $login . "'. " . $this->iControl->getClientErrorText()); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| ?> | ||||
							
								
								
									
										191
									
								
								application/core/callbacks.mControl.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										191
									
								
								application/core/callbacks.mControl.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,191 @@ | ||||
| <?php | ||||
|  | ||||
| namespace mControl; | ||||
|  | ||||
| /** | ||||
|  * Class for handling server callbacks | ||||
|  * | ||||
|  * @author steeffeen | ||||
|  */ | ||||
| class Callbacks { | ||||
| 	/** | ||||
| 	 * Constants | ||||
| 	 */ | ||||
| 	// mControl callbacks | ||||
| 	const CB_IC_1_SECOND = 'mControl.1Second'; | ||||
| 	const CB_IC_5_SECOND = 'mControl.5Second'; | ||||
| 	const CB_IC_1_MINUTE = 'mControl.1Minute'; | ||||
| 	const CB_IC_3_MINUTE = 'mControl.3Minute'; | ||||
| 	const CB_IC_ONINIT = 'mControl.OnInit'; | ||||
| 	const CB_IC_CLIENTUPDATED = 'mControl.ClientUpdated'; | ||||
| 	const CB_IC_BEGINMAP = 'mControl.BeginMap'; | ||||
| 	const CB_IC_ENDMAP = 'mControl.EndMap'; | ||||
| 	// ManiaPlanet callbacks | ||||
| 	const CB_MP_SERVERSTART = 'ManiaPlanet.ServerStart'; | ||||
| 	const CB_MP_SERVERSTOP = 'ManiaPlanet.ServerStop'; | ||||
| 	const CB_MP_BEGINMAP = 'ManiaPlanet.BeginMap'; | ||||
| 	const CB_MP_BEGINMATCH = 'ManiaPlanet.BeginMatch'; | ||||
| 	const CB_MP_ENDMATCH = 'ManiaPlanet.EndMatch'; | ||||
| 	const CB_MP_ENDMAP = 'ManiaPlanet.EndMap'; | ||||
| 	const CB_MP_MAPLISTMODIFIED = 'ManiaPlanet.MapListModified'; | ||||
| 	const CB_MP_ECHO = 'ManiaPlanet.Echo'; | ||||
| 	const CB_MP_BILLUPDATED = 'ManiaPlanet.BillUpdated'; | ||||
| 	const CB_MP_PLAYERCHAT = 'ManiaPlanet.PlayerChat'; | ||||
| 	const CB_MP_PLAYERCONNECT = 'ManiaPlanet.PlayerConnect'; | ||||
| 	const CB_MP_PLAYERDISCONNECT = 'ManiaPlanet.PlayerDisconnect'; | ||||
| 	const CB_MP_PLAYERMANIALINKPAGEANSWER = 'ManiaPlanet.PlayerManialinkPageAnswer'; | ||||
| 	const CB_MP_PLAYERINFOCHANGED = 'ManiaPlanet.PlayerInfoChanged'; | ||||
| 	const CB_MP_PLAYERALLIESCHANGED = 'ManiaPlanet.PlayerAlliesChanged'; | ||||
| 	const CB_MP_VOTEUPDATED = 'ManiaPlanet.VoteUpdated'; | ||||
| 	const CB_MP_STATUSCHANGED = 'ManiaPlanet.StatusChanged'; | ||||
| 	const CB_MP_MODESCRIPTCALLBACK = 'ManiaPlanet.ModeScriptCallback'; | ||||
| 	const CB_MP_MODESCRIPTCALLBACKARRAY = 'ManiaPlanet.ModeScriptCallbackArray'; | ||||
| 	const CB_MP_TUNNELDATARECEIVED = 'ManiaPlanet.TunnelDataReceived'; | ||||
| 	// TrackMania callbacks | ||||
| 	const CB_TM_PLAYERCHECKPOINT = 'TrackMania.PlayerCheckpoint'; | ||||
| 	const CB_TM_PLAYERFINISH = 'TrackMania.PlayerFinish'; | ||||
| 	const CB_TM_PLAYERINCOHERENCE = 'TrackMania.PlayerIncoherence'; | ||||
|  | ||||
| 	/** | ||||
| 	 * Private properties | ||||
| 	 */ | ||||
| 	private $mControl = null; | ||||
|  | ||||
| 	private $callbackHandlers = array(); | ||||
|  | ||||
| 	private $last1Second = -1; | ||||
|  | ||||
| 	private $last5Second = -1; | ||||
|  | ||||
| 	private $last1Minute = -1; | ||||
|  | ||||
| 	private $last3Minute = -1; | ||||
|  | ||||
| 	/** | ||||
| 	 * Construct callbacks handler | ||||
| 	 */ | ||||
| 	public function __construct($mControl) { | ||||
| 		$this->mControl = $mControl; | ||||
| 		 | ||||
| 		// Init values | ||||
| 		$this->last1Second = time(); | ||||
| 		$this->last5Second = time(); | ||||
| 		$this->last1Minute = time(); | ||||
| 		$this->last3Minute = time(); | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Perform OnInit callback | ||||
| 	 */ | ||||
| 	public function onInit() { | ||||
| 		// On init callback | ||||
| 		$this->triggerCallback(self::CB_IC_ONINIT, array(self::CB_IC_ONINIT)); | ||||
| 		 | ||||
| 		// Simulate begin map | ||||
| 		$map = $this->iControl->server->getMap(); | ||||
| 		if ($map) { | ||||
| 			$this->triggerCallback(self::CB_IC_BEGINMAP, array(self::CB_IC_BEGINMAP, array($map))); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Handles the given array of callbacks | ||||
| 	 */ | ||||
| 	public function handleCallbacks() { | ||||
| 		// Perform mControl callbacks | ||||
| 		if ($this->last1Second <= time() - 1) { | ||||
| 			$this->last1Second = time(); | ||||
| 			 | ||||
| 			// 1 second | ||||
| 			$this->triggerCallback(self::CB_IC_1_SECOND, array(self::CB_IC_1_SECOND)); | ||||
| 			 | ||||
| 			if ($this->last5Second <= time() - 5) { | ||||
| 				$this->last5Second = time(); | ||||
| 				 | ||||
| 				// 5 second | ||||
| 				$this->triggerCallback(self::CB_IC_5_SECOND, array(self::CB_IC_5_SECOND)); | ||||
| 				 | ||||
| 				if ($this->last1Minute <= time() - 60) { | ||||
| 					$this->last1Minute = time(); | ||||
| 					 | ||||
| 					// 1 minute | ||||
| 					$this->triggerCallback(self::CB_IC_1_MINUTE, array(self::CB_IC_1_MINUTE)); | ||||
| 					 | ||||
| 					if ($this->last3Minute <= time() - 180) { | ||||
| 						$this->last3Minute = time(); | ||||
| 						 | ||||
| 						// 3 minute | ||||
| 						$this->triggerCallback(self::CB_IC_3_MINUTE, array(self::CB_IC_3_MINUTE)); | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 		 | ||||
| 		// Get server callbacks | ||||
| 		if (!$this->iControl->client) return; | ||||
| 		$this->iControl->client->resetError(); | ||||
| 		$this->iControl->client->readCB(); | ||||
| 		$callbacks = $this->iControl->client->getCBResponses(); | ||||
| 		if (!is_array($callbacks) || $this->iControl->client->isError()) { | ||||
| 			trigger_error("Error reading server callbacks. " . $this->iControl->getClientErrorText()); | ||||
| 			return; | ||||
| 		} | ||||
| 		 | ||||
| 		// Handle callbacks | ||||
| 		foreach ($callbacks as $index => $callback) { | ||||
| 			$callbackName = $callback[0]; | ||||
| 			switch ($callbackName) { | ||||
| 				case self::CB_MP_BEGINMAP: | ||||
| 					{ | ||||
| 						// Map begin | ||||
| 						$this->triggerCallback($callbackName, $callback); | ||||
| 						$this->triggerCallback(self::CB_IC_BEGINMAP, $callback); | ||||
| 						break; | ||||
| 					} | ||||
| 				case self::CB_MP_ENDMAP: | ||||
| 					{ | ||||
| 						// Map end | ||||
| 						$this->triggerCallback($callbackName, $callback); | ||||
| 						$this->triggerCallback(self::CB_IC_ENDMAP, $callback); | ||||
| 						break; | ||||
| 					} | ||||
| 				default: | ||||
| 					{ | ||||
| 						$this->triggerCallback($callbackName, $callback); | ||||
| 						break; | ||||
| 					} | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Trigger a specific callback | ||||
| 	 * | ||||
| 	 * @param string $callbackName        	 | ||||
| 	 * @param mixed $data        	 | ||||
| 	 */ | ||||
| 	public function triggerCallback($callbackName, $data) { | ||||
| 		if (!array_key_exists($callbackName, $this->callbackHandlers) || !is_array($this->callbackHandlers[$callbackName])) return; | ||||
| 		foreach ($this->callbackHandlers[$callbackName] as $handler) { | ||||
| 			call_user_func(array($handler[0], $handler[1]), $data); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Add a new callback handler | ||||
| 	 */ | ||||
| 	public function registerCallbackHandler($callback, $handler, $method) { | ||||
| 		if (!is_object($handler) || !method_exists($handler, $method)) { | ||||
| 			trigger_error("Given handler can't handle callback '" . $callback . "' (no method '" . $method . "')!"); | ||||
| 			return; | ||||
| 		} | ||||
| 		if (!array_key_exists($callback, $this->callbackHandlers) || !is_array($this->callbackHandlers[$callback])) { | ||||
| 			// Init callback handler array | ||||
| 			$this->callbackHandlers[$callback] = array(); | ||||
| 		} | ||||
| 		// Register callback handler | ||||
| 		array_push($this->callbackHandlers[$callback], array($handler, $method)); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| ?> | ||||
							
								
								
									
										85
									
								
								application/core/chat.mControl.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										85
									
								
								application/core/chat.mControl.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,85 @@ | ||||
| <?php | ||||
|  | ||||
| namespace mControl; | ||||
|  | ||||
| /** | ||||
|  * Class for chat methods | ||||
|  * | ||||
|  * @author steeffeen | ||||
|  */ | ||||
| class Chat { | ||||
|  | ||||
| 	/** | ||||
| 	 * Private properties | ||||
| 	 */ | ||||
| 	private $mControl = null; | ||||
|  | ||||
| 	private $config = null; | ||||
|  | ||||
| 	private $prefix = 'mControl>'; | ||||
|  | ||||
| 	/** | ||||
| 	 * Construct mControl chat | ||||
| 	 */ | ||||
| 	public function __construct($mControl) { | ||||
| 		$this->mControl = $mControl; | ||||
| 		 | ||||
| 		// Load config | ||||
| 		$this->config = Tools::loadConfig('chat.mControl.xml'); | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Send a chat message to the given login | ||||
| 	 * | ||||
| 	 * @param string $login        	 | ||||
| 	 * @param string $message        	 | ||||
| 	 * @param bool $prefix        	 | ||||
| 	 */ | ||||
| 	public function sendChat($message, $login = null, $prefix = false) { | ||||
| 		if (!$this->iControl->client) return false; | ||||
| 		if ($login === null) { | ||||
| 			return $this->iControl->client->query('ChatSendServerMessage', ($prefix ? $this->prefix : '') . $message); | ||||
| 		} | ||||
| 		else { | ||||
| 			return $this->iControl->client->query('ChatSendServerMessageToLogin', ($prefix ? $this->prefix : '') . $message, $login); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Send an information message to the given login | ||||
| 	 * | ||||
| 	 * @param string $login        	 | ||||
| 	 * @param string $message        	 | ||||
| 	 * @param bool $prefix        	 | ||||
| 	 */ | ||||
| 	public function sendInformation($message, $login = null, $prefix = false) { | ||||
| 		$format = (string) $this->config->messages->information; | ||||
| 		return $this->sendChat($format . $message, $login); | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Send a success message to the given login | ||||
| 	 * | ||||
| 	 * @param string $message        	 | ||||
| 	 * @param string $login        	 | ||||
| 	 * @param bool $prefix        	 | ||||
| 	 */ | ||||
| 	public function sendSuccess($message, $login = null, $prefix = false) { | ||||
| 		$format = (string) $this->config->messages->success; | ||||
| 		return $this->sendChat($format . $message, $login); | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Send an error message to the given login | ||||
| 	 * | ||||
| 	 * @param string $login        	 | ||||
| 	 * @param string $message        	 | ||||
| 	 * @param bool $prefix        	 | ||||
| 	 */ | ||||
| 	public function sendError($message, $login = null, $prefix = false) { | ||||
| 		$format = (string) $this->config->messages->error; | ||||
| 		return $this->sendChat($format . $message, $login); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| ?> | ||||
							
								
								
									
										684
									
								
								application/core/commands.mControl.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										684
									
								
								application/core/commands.mControl.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,684 @@ | ||||
| <?php | ||||
|  | ||||
| namespace mControl; | ||||
|  | ||||
| /** | ||||
|  * Class for handling chat commands | ||||
|  * | ||||
|  * @author steeffeen | ||||
|  */ | ||||
| class Commands { | ||||
|  | ||||
| 	/** | ||||
| 	 * Private properties | ||||
| 	 */ | ||||
| 	private $mControl = null; | ||||
|  | ||||
| 	private $config = null; | ||||
|  | ||||
| 	private $commandHandlers = array(); | ||||
|  | ||||
| 	private $openBills = array(); | ||||
|  | ||||
| 	private $serverShutdownTime = -1; | ||||
|  | ||||
| 	private $serverShutdownEmpty = false; | ||||
|  | ||||
| 	/** | ||||
| 	 * Construct commands handler | ||||
| 	 */ | ||||
| 	public function __construct($mControl) { | ||||
| 		$this->mControl = $mControl; | ||||
| 		 | ||||
| 		// Load config | ||||
| 		$this->config = Tools::loadConfig('commands.mControl.xml'); | ||||
| 		 | ||||
| 		// Register for callbacks | ||||
| 		$this->iControl->callbacks->registerCallbackHandler(Callbacks::CB_IC_5_SECOND, $this, 'each5Seconds'); | ||||
| 		$this->iControl->callbacks->registerCallbackHandler(Callbacks::CB_MP_BILLUPDATED, $this, 'handleBillUpdated'); | ||||
| 		$this->iControl->callbacks->registerCallbackHandler(Callbacks::CB_MP_PLAYERCHAT, $this, 'handleChatCallback'); | ||||
| 		 | ||||
| 		// Register basic commands | ||||
| 		$commands = array('help', 'version', 'shutdown', 'shutdownserver', 'networkstats', 'systeminfo', 'getservername',  | ||||
| 			'setservername', 'getplanets', 'donate', 'pay', 'kick', 'nextmap', 'restartmap', 'addmap', 'removemap', 'startwarmup',  | ||||
| 			'stopwarmup'); | ||||
| 		foreach ($commands as $command) { | ||||
| 			$this->registerCommandHandler($command, $this, 'command_' . $command); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Register a command handler | ||||
| 	 * | ||||
| 	 * @param string $commandName        	 | ||||
| 	 * @param object $handler        	 | ||||
| 	 * @param string $method        	 | ||||
| 	 */ | ||||
| 	public function registerCommandHandler($commandName, $handler, $method) { | ||||
| 		$command = strtolower($commandName); | ||||
| 		if (!is_object($handler) || !method_exists($handler, $method)) { | ||||
| 			trigger_error("Given handler can't handle command '" . $command . "' (no method '" . $method . "')!"); | ||||
| 			return; | ||||
| 		} | ||||
| 		if (!array_key_exists($command, $this->commandHandlers) || !is_array($this->commandHandlers[$command])) { | ||||
| 			// Init handlers array | ||||
| 			$this->commandHandlers[$command] = array(); | ||||
| 		} | ||||
| 		// Register command handler | ||||
| 		array_push($this->commandHandlers[$command], array($handler, $method)); | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Handle chat callback | ||||
| 	 */ | ||||
| 	public function handleChatCallback($callback) { | ||||
| 		$chat = $callback[1]; | ||||
| 		// Check for command | ||||
| 		if (!$chat[3]) return; | ||||
| 		// Check for valid player | ||||
| 		if ($chat[0] <= 0 || strlen($chat[1]) <= 0) return; | ||||
| 		// Handle command | ||||
| 		$command = explode(" ", substr($chat[2], 1)); | ||||
| 		$command = strtolower($command[0]); | ||||
| 		if (!array_key_exists($command, $this->commandHandlers) || !is_array($this->commandHandlers[$command])) { | ||||
| 			// No command handler registered | ||||
| 			return; | ||||
| 		} | ||||
| 		// Inform command handlers | ||||
| 		foreach ($this->commandHandlers[$command] as $handler) { | ||||
| 			call_user_func(array($handler[0], $handler[1]), $callback); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Handle bill updated callback | ||||
| 	 */ | ||||
| 	public function handleBillUpdated($callback) { | ||||
| 		$bill = $callback[1]; | ||||
| 		if (!array_key_exists($bill[0], $this->openBills)) return; | ||||
| 		$login = $this->openBills[$bill[0]]; | ||||
| 		switch ($bill[1]) { | ||||
| 			case 4: | ||||
| 				{ | ||||
| 					// Payed | ||||
| 					$message = 'Success! Thanks.'; | ||||
| 					$this->iControl->chat->sendSuccess($message, $login); | ||||
| 					unset($this->openBills[$bill[0]]); | ||||
| 					break; | ||||
| 				} | ||||
| 			case 5: | ||||
| 				{ | ||||
| 					// Refused | ||||
| 					$message = 'Transaction cancelled.'; | ||||
| 					$this->iControl->chat->sendError($message, $login); | ||||
| 					unset($this->openBills[$bill[0]]); | ||||
| 					break; | ||||
| 				} | ||||
| 			case 6: | ||||
| 				{ | ||||
| 					// Error | ||||
| 					$this->iControl->chat->sendError($bill[2], $login); | ||||
| 					unset($this->openBills[$bill[0]]); | ||||
| 					break; | ||||
| 				} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Retrieve the needed rights level to perform the given command | ||||
| 	 * | ||||
| 	 * @param string $commandName        	 | ||||
| 	 * @param string $defaultLevel        	 | ||||
| 	 * @return string | ||||
| 	 */ | ||||
| 	private function getRightsLevel($commandName, $defaultLevel) { | ||||
| 		$command_rights = $this->config->xpath('//' . strtolower($commandName) . '/..'); | ||||
| 		if (empty($command_rights)) return $defaultLevel; | ||||
| 		$rights = $this->iControl->authentication->RIGHTS_LEVELS; | ||||
| 		$highest_level = null; | ||||
| 		foreach ($command_rights as $right) { | ||||
| 			$levelName = $right->getName(); | ||||
| 			$levelInt = array_search($levelName, $rights); | ||||
| 			if ($levelInt !== false && ($highest_level === null || $highest_level < $levelInt)) { | ||||
| 				$highest_level = $levelInt; | ||||
| 			} | ||||
| 		} | ||||
| 		if ($highest_level === null || !array_key_exists($highest_level, $rights)) return $defaultLevel; | ||||
| 		return $rights[$highest_level]; | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Send mControl version | ||||
| 	 */ | ||||
| 	private function command_version($chat) { | ||||
| 		$login = $chat[1][1]; | ||||
| 		if (!$this->iControl->authentication->checkRight($login, $this->getRightsLevel('version', 'all'))) { | ||||
| 			// Not allowed! | ||||
| 			$this->iControl->authentication->sendNotAllowed($login); | ||||
| 			return; | ||||
| 		} | ||||
| 		if (!$this->iControl->chat->sendInformation('This server is using mControl v' . mControl::VERSION . '!', $login)) { | ||||
| 			trigger_error("Couldn't send version to '" . $login . "'. " . $this->iControl->getClientErrorText()); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Send help list | ||||
| 	 */ | ||||
| 	private function command_help($chat) { | ||||
| 		$login = $chat[1][1]; | ||||
| 		if (!$this->iControl->authentication->checkRight($login, $this->getRightsLevel('help', 'all'))) { | ||||
| 			// Not allowed! | ||||
| 			$this->iControl->authentication->sendNotAllowed($login); | ||||
| 			return; | ||||
| 		} | ||||
| 		// TODO: improve help command | ||||
| 		// TODO: enable help for specific commands | ||||
| 		$list = 'Available commands: '; | ||||
| 		$commands = array_keys($this->commandHandlers); | ||||
| 		$count = count($commands); | ||||
| 		for ($index = 0; $index < $count; $index++) { | ||||
| 			if (!$this->iControl->authentication->checkRight($login, $this->getRightsLevel($commands[$index], 'superadmin'))) { | ||||
| 				unset($commands[$index]); | ||||
| 			} | ||||
| 		} | ||||
| 		$count = count($commands); | ||||
| 		$index = 0; | ||||
| 		foreach ($commands as $command) { | ||||
| 			$list .= $command; | ||||
| 			if ($index < $count - 1) { | ||||
| 				$list .= ', '; | ||||
| 			} | ||||
| 			$index++; | ||||
| 		} | ||||
| 		if (!$this->iControl->chat->sendInformation($list, $login)) { | ||||
| 			trigger_error("Couldn't send help list to '" . $login . "'. " . $this->iControl->getClientErrorText()); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Handle getplanets command | ||||
| 	 */ | ||||
| 	private function command_getplanets($chat) { | ||||
| 		$login = $chat[1][1]; | ||||
| 		if (!$this->iControl->authentication->checkRight($login, $this->getRightsLevel('getplanets', 'admin'))) { | ||||
| 			// Not allowed! | ||||
| 			$this->iControl->authentication->sendNotAllowed($login); | ||||
| 			return; | ||||
| 		} | ||||
| 		if (!$this->iControl->client->query('GetServerPlanets')) { | ||||
| 			trigger_error("Couldn't retrieve server planets. " . $this->iControl->getClientErrorText()); | ||||
| 		} | ||||
| 		else { | ||||
| 			$planets = $this->iControl->client->getResponse(); | ||||
| 			if (!$this->iControl->chat->sendInformation('This Server has ' . $planets . ' Planets!', $login)) { | ||||
| 				trigger_error("Couldn't send server planets to '" . $login . "'. " . $this->iControl->getClientErrorText()); | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Handle donate command | ||||
| 	 */ | ||||
| 	private function command_donate($chat) { | ||||
| 		$login = $chat[1][1]; | ||||
| 		if (!$this->iControl->authentication->checkRight($login, $this->getRightsLevel('donate', 'all'))) { | ||||
| 			// Not allowed! | ||||
| 			$this->iControl->authentication->sendNotAllowed($login); | ||||
| 			return; | ||||
| 		} | ||||
| 		$params = explode(' ', $chat[1][2]); | ||||
| 		if (count($params) < 2) { | ||||
| 			// TODO: send usage information | ||||
| 			return; | ||||
| 		} | ||||
| 		$amount = (int) $params[1]; | ||||
| 		if (!$amount || $amount <= 0) { | ||||
| 			// TODO: send usage information | ||||
| 			return; | ||||
| 		} | ||||
| 		if (count($params) >= 3) { | ||||
| 			$receiver = $params[2]; | ||||
| 			$receiverPlayer = $this->iControl->database->getPlayer($receiver); | ||||
| 			$receiverName = ($receiverPlayer ? $receiverPlayer['NickName'] : $receiver); | ||||
| 		} | ||||
| 		else { | ||||
| 			$receiver = ''; | ||||
| 			$receiverName = $this->iControl->server->getName(); | ||||
| 		} | ||||
| 		$message = 'Donate ' . $amount . ' Planets to $<' . $receiverName . '$>?'; | ||||
| 		if (!$this->iControl->client->query('SendBill', $login, $amount, $message, $receiver)) { | ||||
| 			trigger_error( | ||||
| 					"Couldn't create donation of " . $amount . " planets from '" . $login . "' for '" . $receiver . "'. " . | ||||
| 							 $this->iControl->getClientErrorText()); | ||||
| 			$this->iControl->chat->sendError("Creating donation failed.", $login); | ||||
| 		} | ||||
| 		else { | ||||
| 			$bill = $this->iControl->client->getResponse(); | ||||
| 			$this->openBills[$bill] = $login; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Handle pay command | ||||
| 	 */ | ||||
| 	private function command_pay($chat) { | ||||
| 		$login = $chat[1][1]; | ||||
| 		if (!$this->iControl->authentication->checkRight($login, $this->getRightsLevel('pay', 'superadmin'))) { | ||||
| 			// Not allowed! | ||||
| 			$this->iControl->authentication->sendNotAllowed($login); | ||||
| 			return; | ||||
| 		} | ||||
| 		$params = explode(' ', $chat[1][2]); | ||||
| 		if (count($params) < 2) { | ||||
| 			// TODO: send usage information | ||||
| 			return; | ||||
| 		} | ||||
| 		$amount = (int) $params[1]; | ||||
| 		if (!$amount || $amount <= 0) { | ||||
| 			// TODO: send usage information | ||||
| 			return; | ||||
| 		} | ||||
| 		if (count($params) >= 3) { | ||||
| 			$receiver = $params[2]; | ||||
| 		} | ||||
| 		else { | ||||
| 			$receiver = $login; | ||||
| 		} | ||||
| 		$message = 'Payout from $<' . $this->iControl->server->getName() . '$>.'; | ||||
| 		if (!$this->iControl->client->query('Pay', $receiver, $amount, $message)) { | ||||
| 			trigger_error( | ||||
| 					"Couldn't create payout of" . $amount . " planets by '" . $login . "' for '" . $receiver . "'. " . | ||||
| 							 $this->iControl->getClientErrorText()); | ||||
| 			$this->iControl->chat->sendError("Creating payout failed.", $login); | ||||
| 		} | ||||
| 		else { | ||||
| 			$bill = $this->iControl->client->getResponse(); | ||||
| 			$this->openBills[$bill] = $login; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Handle networkstats command | ||||
| 	 */ | ||||
| 	private function command_networkstats($chat) { | ||||
| 		$login = $chat[1][1]; | ||||
| 		if (!$this->iControl->authentication->checkRight($login, $this->getRightsLevel('networkstats', 'superadmin'))) { | ||||
| 			// Not allowed! | ||||
| 			$this->iControl->authentication->sendNotAllowed($login); | ||||
| 			return; | ||||
| 		} | ||||
| 		$networkStats = $this->iControl->server->getNetworkStats(); | ||||
| 		$message = 'NetworkStats: ' . 'uptime=' . $networkStats['Uptime'] . ', ' . 'nbConn=' . $networkStats['NbrConnection'] . ', ' . | ||||
| 				 'recvRate=' . $networkStats['RecvNetRate'] . ', ' . 'sendRate=' . $networkStats['SendNetRate'] . ', ' . 'recvTotal=' . | ||||
| 				 $networkStats['SendNetRate'] . ', ' . 'sentTotal=' . $networkStats['SendNetRate']; | ||||
| 		if (!$this->iControl->chat->sendInformation($message, $login)) { | ||||
| 			trigger_error("Couldn't send network stats to '" . $login . "'. " . $this->iControl->getClientErrorText()); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Handle systeminfo command | ||||
| 	 */ | ||||
| 	private function command_systeminfo($chat) { | ||||
| 		$login = $chat[1][1]; | ||||
| 		if (!$this->iControl->authentication->checkRight($login, $this->getRightsLevel('systeminfo', 'superadmin'))) { | ||||
| 			// Not allowed! | ||||
| 			$this->iControl->authentication->sendNotAllowed($login); | ||||
| 			return; | ||||
| 		} | ||||
| 		$systemInfo = $this->iControl->server->getSystemInfo(); | ||||
| 		$message = 'SystemInfo: ' . 'ip=' . $systemInfo['PublishedIp'] . ', ' . 'port=' . $systemInfo['Port'] . ', ' . 'p2pPort=' . | ||||
| 				 $systemInfo['P2PPort'] . ', ' . 'title=' . $systemInfo['TitleId'] . ', ' . 'login=' . $systemInfo['ServerLogin'] . ', '; | ||||
| 		if (!$this->iControl->chat->sendInformation($message, $login)) { | ||||
| 			trigger_error("Couldn't send system info to '" . $login . "'. " . $this->iControl->getClientErrorText()); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Handle shutdown command | ||||
| 	 */ | ||||
| 	private function command_shutdown($chat) { | ||||
| 		$login = $chat[1][1]; | ||||
| 		if (!$this->iControl->authentication->checkRight($login, $this->getRightsLevel('shutdown', 'superadmin'))) { | ||||
| 			// Not allowed! | ||||
| 			$this->iControl->authentication->sendNotAllowed($login); | ||||
| 			return; | ||||
| 		} | ||||
| 		$this->iControl->quit("mControl shutdown requested by '" . $login . "'"); | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Handle startwarmup command | ||||
| 	 */ | ||||
| 	private function command_startwarmup($chat) { | ||||
| 		$login = $chat[1][1]; | ||||
| 		if (!$this->iControl->authentication->checkRight($login, $this->getRightsLevel('startwarmup', 'operator'))) { | ||||
| 			// Not allowed! | ||||
| 			$this->iControl->authentication->sendNotAllowed($login); | ||||
| 			return; | ||||
| 		} | ||||
| 		if (!$this->iControl->client->query("SetWarmUp", true)) { | ||||
| 			trigger_error("Couldn't start warmup. " . $this->iControl->getClientErrorText()); | ||||
| 			$player = $this->iControl->database->getPlayer($login); | ||||
| 			$this->iControl->chat->sendInformation('$<' . ($player ? $player['NickName'] : $login) . '$> started WarmUp!'); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Handle stopwarmup command | ||||
| 	 */ | ||||
| 	private function command_stopwarmup($chat) { | ||||
| 		$login = $chat[1][1]; | ||||
| 		if (!$this->iControl->authentication->checkRight($login, $this->getRightsLevel('stopwarmup', 'operator'))) { | ||||
| 			// Not allowed! | ||||
| 			$this->iControl->authentication->sendNotAllowed($login); | ||||
| 			return; | ||||
| 		} | ||||
| 		if (!$this->iControl->client->query("SetWarmUp", false)) { | ||||
| 			trigger_error("Couldn't stop warmup. " . $this->iControl->getClientErrorText()); | ||||
| 		} | ||||
| 		else { | ||||
| 			$player = $this->iControl->database->getPlayer($login); | ||||
| 			$this->iControl->chat->sendInformation('$<' . ($player ? $player['NickName'] : $login) . '$> stopped WarmUp!'); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Handle server shutdown command | ||||
| 	 */ | ||||
| 	private function command_shutdownserver($chat) { | ||||
| 		$login = $chat[1][1]; | ||||
| 		if (!$this->iControl->authentication->checkRight($login, $this->getRightsLevel('shutdownserver', 'superadmin'))) { | ||||
| 			// Not allowed! | ||||
| 			$this->iControl->authentication->sendNotAllowed($login); | ||||
| 			return; | ||||
| 		} | ||||
| 		// Check for delayed shutdown | ||||
| 		$params = explode(' ', $chat[1][2]); | ||||
| 		if (count($params) >= 2) { | ||||
| 			$param = $params[1]; | ||||
| 			if ($param == 'empty') { | ||||
| 				$this->serverShutdownEmpty = !$this->serverShutdownEmpty; | ||||
| 				if ($this->serverShutdownEmpty) { | ||||
| 					$this->iControl->chat->sendInformation("The server will shutdown as soon as it's empty!", $login); | ||||
| 				} | ||||
| 				else { | ||||
| 					$this->iControl->chat->sendInformation("Empty-shutdown cancelled!", $login); | ||||
| 				} | ||||
| 			} | ||||
| 			else { | ||||
| 				$delay = (int) $param; | ||||
| 				if ($delay <= 0) { | ||||
| 					// Cancel shutdown | ||||
| 					$this->serverShutdownTime = -1; | ||||
| 					$this->iControl->chat->sendInformation("Delayed shutdown cancelled!", $login); | ||||
| 				} | ||||
| 				else { | ||||
| 					// Trigger delayed shutdown | ||||
| 					$this->serverShutdownTime = time() + $delay * 60.; | ||||
| 					$this->iControl->chat->sendInformation("The server will shut down in " . $delay . " minutes!", $login); | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 		else { | ||||
| 			$this->shutdownServer($login); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Handle kick command | ||||
| 	 */ | ||||
| 	private function command_kick($chat) { | ||||
| 		$login = $chat[1][1]; | ||||
| 		if (!$this->iControl->authentication->checkRight($login, $this->getRightsLevel('kick', 'operator'))) { | ||||
| 			// Not allowed! | ||||
| 			$this->iControl->authentication->sendNotAllowed($login); | ||||
| 			return; | ||||
| 		} | ||||
| 		$params = explode(' ', $chat[1][2], 3); | ||||
| 		if (count($params) < 2) { | ||||
| 			// TODO: show usage | ||||
| 			return; | ||||
| 		} | ||||
| 		$target = $params[1]; | ||||
| 		$players = $this->iControl->server->getPlayers(); | ||||
| 		foreach ($players as $player) { | ||||
| 			if ($player['Login'] != $target) continue; | ||||
| 			// Kick player | ||||
| 			if (isset($params[2])) { | ||||
| 				$message = $params[2]; | ||||
| 			} | ||||
| 			else { | ||||
| 				$message = ""; | ||||
| 			} | ||||
| 			if (!$this->iControl->client->query('Kick', $target, $message)) { | ||||
| 				trigger_error("Couldn't kick player '" . $target . "'! " . $this->iControl->getClientErrorText()); | ||||
| 			} | ||||
| 			return; | ||||
| 		} | ||||
| 		$this->iControl->chat->sendError("Invalid player login.", $login); | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Handle removemap command | ||||
| 	 */ | ||||
| 	private function command_removemap($chat) { | ||||
| 		$login = $chat[1][1]; | ||||
| 		if (!$this->iControl->authentication->checkRight($login, $this->getRightsLevel('kick', 'operator'))) { | ||||
| 			// Not allowed! | ||||
| 			$this->iControl->authentication->sendNotAllowed($login); | ||||
| 			return; | ||||
| 		} | ||||
| 		// TODO: allow params | ||||
| 		// Get map name | ||||
| 		$map = $this->iControl->server->getMap(); | ||||
| 		if (!$map) { | ||||
| 			$this->iControl->chat->sendError("Couldn't remove map.", $login); | ||||
| 		} | ||||
| 		else { | ||||
| 			$mapName = $map['FileName']; | ||||
| 			 | ||||
| 			// Remove map | ||||
| 			if (!$this->iControl->client->query('RemoveMap', $mapName)) { | ||||
| 				trigger_error("Couldn't remove current map. " . $this->iControl->getClientErrorText()); | ||||
| 			} | ||||
| 			else { | ||||
| 				$this->iControl->chat->sendSuccess('Map removed.', $login); | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Handle addmap command | ||||
| 	 */ | ||||
| 	private function command_addmap($chat) { | ||||
| 		$login = $chat[1][1]; | ||||
| 		if (!$this->iControl->authentication->checkRight($login, $this->getRightsLevel('addmap', 'operator'))) { | ||||
| 			// Not allowed! | ||||
| 			$this->iControl->authentication->sendNotAllowed($login); | ||||
| 			return; | ||||
| 		} | ||||
| 		$params = explode(' ', $chat[1][2], 2); | ||||
| 		if (count($params) < 2) { | ||||
| 			// TODO: show usage | ||||
| 			return; | ||||
| 		} | ||||
| 		// Check if mControl can even write to the maps dir | ||||
| 		if (!$this->iControl->client->query('GetMapsDirectory')) { | ||||
| 			trigger_error("Couldn't get map directory. " . $this->iControl->getClientErrorText()); | ||||
| 			$this->iControl->chat->sendError("mControl couldn't retrieve the maps directory.", $login); | ||||
| 			return; | ||||
| 		} | ||||
| 		else { | ||||
| 			$mapDir = $this->iControl->client->getResponse(); | ||||
| 			if (!is_dir($mapDir)) { | ||||
| 				trigger_error("mControl doesn't have have access to the maps directory in '" . $mapDir . "'."); | ||||
| 				$this->iControl->chat->sendError("mControl doesn't have access to the maps directory.", $login); | ||||
| 				return; | ||||
| 			} | ||||
| 			$dlDir = (string) $this->iControl->config->maps_dir; | ||||
| 			// Create mx directory if necessary | ||||
| 			if (!is_dir($mapDir . $dlDir) && !mkdir($mapDir . $dlDir)) { | ||||
| 				trigger_error("mControl doesn't have to rights to save maps in'" . $mapDir . $dlDir, "'."); | ||||
| 				$this->iControl->chat->sendError("mControl doesn't have to rights to save maps.", $login); | ||||
| 				return; | ||||
| 			} | ||||
| 			$mapDir .= $dlDir . '/'; | ||||
| 			// Download the map | ||||
| 			if (is_numeric($params[1])) { | ||||
| 				$serverInfo = $this->iControl->server->getSystemInfo(); | ||||
| 				$title = strtolower(substr($serverInfo['TitleId'], 0, 2)); | ||||
| 				// Check if map exists | ||||
| 				$url = 'http://' . $title . '.mania-exchange.com/api/tracks/get_track_info/id/' . $params[1] . '?format=json'; | ||||
| 				$mapInfo = Tools::loadFile($url); | ||||
| 				if (!$mapInfo || strlen($mapInfo) <= 0) { | ||||
| 					// Invalid id | ||||
| 					$this->iControl->chat->sendError('Invalid MX-Id!', $login); | ||||
| 					return; | ||||
| 				} | ||||
| 				$mapInfo = json_decode($mapInfo, true); | ||||
| 				$url = 'http://' . $title . '.mania-exchange.com/tracks/download/' . $params[1]; | ||||
| 				$file = Tools::loadFile($url); | ||||
| 				if (!$file) { | ||||
| 					// Download error | ||||
| 					$this->iControl->chat->sendError('Download failed!', $login); | ||||
| 					return; | ||||
| 				} | ||||
| 				// Save map | ||||
| 				$fileName = $mapDir . $mapInfo['TrackID'] . '_' . $mapInfo['Name'] . '.Map.Gbx'; | ||||
| 				if (!file_put_contents($fileName, $file)) { | ||||
| 					// Save error | ||||
| 					$this->iControl->chat->sendError('Saving map failed!', $login); | ||||
| 					return; | ||||
| 				} | ||||
| 				// Check for valid map | ||||
| 				if (!$this->iControl->client->query('CheckMapForCurrentServerParams', $fileName)) { | ||||
| 					trigger_error("Couldn't check if map is valid. " . $this->iControl->getClientErrorText()); | ||||
| 				} | ||||
| 				else { | ||||
| 					$response = $this->iControl->client->getResponse(); | ||||
| 					if (!$response) { | ||||
| 						// Inalid map type | ||||
| 						$this->iControl->chat->sendError("Invalid map type.", $login); | ||||
| 						return; | ||||
| 					} | ||||
| 				} | ||||
| 				// Add map to map list | ||||
| 				if (!$this->iControl->client->query('InsertMap', $fileName)) { | ||||
| 					$this->iControl->chat->sendError("Couldn't add map to match settings!", $login); | ||||
| 					return; | ||||
| 				} | ||||
| 				$this->iControl->chat->sendSuccess('Map $<' . $mapInfo['Name'] . '$> successfully added!'); | ||||
| 			} | ||||
| 			else { | ||||
| 				// TODO: check if map exists locally | ||||
| 				// TODO: load map from direct url | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Handle nextmap command | ||||
| 	 */ | ||||
| 	private function command_nextmap($chat) { | ||||
| 		$login = $chat[1][1]; | ||||
| 		if (!$this->iControl->authentication->checkRight($login, $this->getRightsLevel('nextmap', 'operator'))) { | ||||
| 			// Not allowed! | ||||
| 			$this->iControl->authentication->sendNotAllowed($login); | ||||
| 			return; | ||||
| 		} | ||||
| 		if (!$this->iControl->client->query('NextMap')) { | ||||
| 			trigger_error("Couldn't skip map. " . $this->iControl->getClientErrorText()); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Handle retartmap command | ||||
| 	 */ | ||||
| 	private function command_restartmap($chat) { | ||||
| 		$login = $chat[1][1]; | ||||
| 		if (!$this->iControl->authentication->checkRight($login, $this->getRightsLevel('restartmap', 'operator'))) { | ||||
| 			// Not allowed! | ||||
| 			$this->iControl->authentication->sendNotAllowed($login); | ||||
| 			return; | ||||
| 		} | ||||
| 		if (!$this->iControl->client->query('RestartMap')) { | ||||
| 			trigger_error("Couldn't restart map. " . $this->iControl->getClientErrorText()); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Handle getservername command | ||||
| 	 */ | ||||
| 	private function command_getservername($chat) { | ||||
| 		$login = $chat[1][1]; | ||||
| 		if (!$this->iControl->authentication->checkRight($login, $this->getRightsLevel('getservername', 'operator'))) { | ||||
| 			// Not allowed! | ||||
| 			$this->iControl->authentication->sendNotAllowed($login); | ||||
| 			return; | ||||
| 		} | ||||
| 		$serverName = $this->iControl->server->getName(); | ||||
| 		$this->iControl->chat->sendInformation("Server Name: " . $serverName, $login); | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Handle setservername command | ||||
| 	 */ | ||||
| 	private function command_setservername($chat) { | ||||
| 		$login = $chat[1][1]; | ||||
| 		if (!$this->iControl->authentication->checkRight($login, $this->getRightsLevel('setservername', 'admin'))) { | ||||
| 			// Not allowed! | ||||
| 			$this->iControl->authentication->sendNotAllowed($login); | ||||
| 			return; | ||||
| 		} | ||||
| 		$params = explode(' ', $chat[1][2], 2); | ||||
| 		if (count($params) < 2) { | ||||
| 			// TODO: show usage | ||||
| 			return; | ||||
| 		} | ||||
| 		$serverName = $params[1]; | ||||
| 		if (!$this->iControl->client->query('SetServerName', $serverName)) { | ||||
| 			trigger_error("Couldn't set server name. " . $this->iControl->getClientErrorText()); | ||||
| 			$this->iControl->chat->sendError("Error!"); | ||||
| 		} | ||||
| 		else { | ||||
| 			$serverName = $this->iControl->server->getName(); | ||||
| 			$this->iControl->chat->sendInformation("New Name: " . $serverName); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Check stuff each 5 seconds | ||||
| 	 */ | ||||
| 	public function each5Seconds() { | ||||
| 		// Empty shutdown | ||||
| 		if ($this->serverShutdownEmpty) { | ||||
| 			$players = $this->iControl->server->getPlayers(); | ||||
| 			if (count($players) <= 0) { | ||||
| 				$this->shutdownServer('empty'); | ||||
| 			} | ||||
| 		} | ||||
| 		 | ||||
| 		// Delayed shutdown | ||||
| 		if ($this->serverShutdownTime > 0) { | ||||
| 			if (time() >= $this->serverShutdownTime) { | ||||
| 				$this->shutdownServer('delayed'); | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Perform server shutdown | ||||
| 	 */ | ||||
| 	private function shutdownServer($login = '#') { | ||||
| 		$this->iControl->client->resetError(); | ||||
| 		if (!$this->iControl->client->query('StopServer') || $this->iControl->client->isError()) { | ||||
| 			trigger_error("Server shutdown command from '" . $login . "' failed. " . $this->iControl->getClientErrorText()); | ||||
| 			return; | ||||
| 		} | ||||
| 		$this->iControl->quit("Server shutdown requested by '" . $login . "'"); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| ?> | ||||
							
								
								
									
										348
									
								
								application/core/core.mControl.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										348
									
								
								application/core/core.mControl.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,348 @@ | ||||
| <?php | ||||
|  | ||||
| namespace mControl; | ||||
|  | ||||
| /** | ||||
|  * Needed includes | ||||
|  */ | ||||
| require_once __DIR__ . '/authentication.mControl.php'; | ||||
| require_once __DIR__ . '/callbacks.mControl.php'; | ||||
| require_once __DIR__ . '/chat.mControl.php'; | ||||
| require_once __DIR__ . '/commands.mControl.php'; | ||||
| require_once __DIR__ . '/database.mControl.php'; | ||||
| require_once __DIR__ . '/server.mControl.php'; | ||||
| require_once __DIR__ . '/stats.mControl.php'; | ||||
| require_once __DIR__ . '/tools.mControl.php'; | ||||
| list($endiantest) = array_values(unpack('L1L', pack('V', 1))); | ||||
| if ($endiantest == 1) { | ||||
| 	require_once __DIR__ . '/PhpRemote/GbxRemote.inc.php'; | ||||
| } | ||||
| else { | ||||
| 	require_once __DIR__ . '/PhpRemote/GbxRemote.bem.php'; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * mControl Server Controller for ManiaPlanet Server | ||||
|  * | ||||
|  * @author steeffeen | ||||
|  */ | ||||
| class mControl { | ||||
| 	/** | ||||
| 	 * Constants | ||||
| 	 */ | ||||
| 	const VERSION = '0.1'; | ||||
| 	const API_VERSION = '2013-04-16'; | ||||
| 	const DATE = 'd-m-y h:i:sa T'; | ||||
|  | ||||
| 	/** | ||||
| 	 * Public properties | ||||
| 	 */ | ||||
| 	public $authentication = null; | ||||
|  | ||||
| 	public $callbacks = null; | ||||
|  | ||||
| 	public $client = null; | ||||
|  | ||||
| 	public $chat = null; | ||||
|  | ||||
| 	public $config = null; | ||||
|  | ||||
| 	public $commands = null; | ||||
|  | ||||
| 	public $database = null; | ||||
|  | ||||
| 	public $debug = false; | ||||
|  | ||||
| 	public $server = null; | ||||
|  | ||||
| 	public $startTime = -1; | ||||
|  | ||||
| 	public $stats = null; | ||||
|  | ||||
| 	/** | ||||
| 	 * Private properties | ||||
| 	 */ | ||||
| 	private $plugins = array(); | ||||
|  | ||||
| 	private $shutdownRequested = false; | ||||
|  | ||||
| 	/** | ||||
| 	 * Construct mControl | ||||
| 	 */ | ||||
| 	public function __construct() { | ||||
| 		// Load core | ||||
| 		$this->config = Tools::loadConfig('core.mControl.xml'); | ||||
| 		$this->startTime = time(); | ||||
| 		 | ||||
| 		// Load chat tool | ||||
| 		$this->chat = new Chat($this); | ||||
| 		 | ||||
| 		// Load callbacks handler | ||||
| 		$this->callbacks = new Callbacks($this); | ||||
| 		 | ||||
| 		// Load database | ||||
| 		$this->database = new Database($this); | ||||
| 		 | ||||
| 		// Load server | ||||
| 		$this->server = new Server($this); | ||||
| 		 | ||||
| 		// Load authentication | ||||
| 		$this->authentication = new Authentication($this); | ||||
| 		 | ||||
| 		// Load commands handler | ||||
| 		$this->commands = new Commands($this); | ||||
| 		 | ||||
| 		// Load stats manager | ||||
| 		$this->stats = new Stats($this); | ||||
| 		 | ||||
| 		// Register for core callbacks | ||||
| 		$this->callbacks->registerCallbackHandler(Callbacks::CB_MP_ENDMAP, $this, 'handleEndMap'); | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Return message composed of client error message and error code | ||||
| 	 * | ||||
| 	 * @param object $client        	 | ||||
| 	 * @return string | ||||
| 	 */ | ||||
| 	public function getClientErrorText($client = null) { | ||||
| 		if (is_object($client)) { | ||||
| 			return $client->getErrorMessage() . ' (' . $client->getErrorCode() . ')'; | ||||
| 		} | ||||
| 		return $this->client->getErrorMessage() . ' (' . $this->client->getErrorCode() . ')'; | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Quit mControl and log the given message | ||||
| 	 */ | ||||
| 	public function quit($message = false) { | ||||
| 		if ($this->shutdownRequested) return; | ||||
| 		 | ||||
| 		if ($this->client) { | ||||
| 			// Announce quit | ||||
| 			$this->chat->sendInformation('mControl shutting down.'); | ||||
| 			 | ||||
| 			// Hide manialinks | ||||
| 			$this->client->query('SendHideManialinkPage'); | ||||
| 		} | ||||
| 		 | ||||
| 		// Log quit reason | ||||
| 		if ($message) { | ||||
| 			error_log($message); | ||||
| 		} | ||||
| 		 | ||||
| 		// Shutdown | ||||
| 		if ($this->client) $this->client->Terminate(); | ||||
| 		 | ||||
| 		error_log("Quitting mControl!"); | ||||
| 		exit(); | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Run mControl | ||||
| 	 */ | ||||
| 	public function run($debug = false) { | ||||
| 		error_log('Starting mControl v' . self::VERSION . '!'); | ||||
| 		$this->debug = (bool) $debug; | ||||
| 		 | ||||
| 		// Load plugins | ||||
| 		$this->loadPlugins(); | ||||
| 		 | ||||
| 		// Connect to server | ||||
| 		$this->connect(); | ||||
| 		 | ||||
| 		// Loading finished | ||||
| 		error_log("Loading completed!"); | ||||
| 		 | ||||
| 		// Announce mControl | ||||
| 		if (!$this->chat->sendInformation('mControl v' . self::VERSION . ' successfully started!')) { | ||||
| 			trigger_error("Couldn't announce mControl. " . $this->iControl->getClientErrorText()); | ||||
| 		} | ||||
| 		 | ||||
| 		// OnInit | ||||
| 		$this->callbacks->onInit(); | ||||
| 		 | ||||
| 		// Main loop | ||||
| 		while (!$this->shutdownRequested) { | ||||
| 			$loopStart = microtime(true); | ||||
| 			 | ||||
| 			// Disable script timeout | ||||
| 			set_time_limit(30); | ||||
| 			 | ||||
| 			// Handle server callbacks | ||||
| 			$this->callbacks->handleCallbacks(); | ||||
| 			 | ||||
| 			// Loop plugins | ||||
| 			foreach ($this->plugins as $plugin) { | ||||
| 				if (!method_exists($plugin, 'loop')) { | ||||
| 					continue; | ||||
| 				} | ||||
| 				$plugin->loop(); | ||||
| 			} | ||||
| 			 | ||||
| 			// Yield for next tick | ||||
| 			$loopEnd = microtime(true); | ||||
| 			$sleepTime = 300000 - $loopEnd + $loopStart; | ||||
| 			if ($sleepTime > 0) { | ||||
| 				usleep($sleepTime); | ||||
| 			} | ||||
| 		} | ||||
| 		 | ||||
| 		// Shutdown | ||||
| 		$this->client->Terminate(); | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Connect to ManiaPlanet server | ||||
| 	 */ | ||||
| 	private function connect() { | ||||
| 		$enable = $this->server->config->xpath('enable'); | ||||
| 		$enable = Tools::toBool($enable[0]); | ||||
| 		if (!$enable) return; | ||||
| 		 | ||||
| 		// Load remote client | ||||
| 		$this->client = new \IXR_ClientMulticall_Gbx(); | ||||
| 		 | ||||
| 		$host = $this->server->config->xpath('host'); | ||||
| 		if (!$host) trigger_error("Invalid server configuration (host).", E_USER_ERROR); | ||||
| 		$host = (string) $host[0]; | ||||
| 		$port = $this->server->config->xpath('port'); | ||||
| 		if (!$host) trigger_error("Invalid server configuration (port).", E_USER_ERROR); | ||||
| 		$port = (string) $port[0]; | ||||
| 		$timeout = $this->config->xpath('timeout'); | ||||
| 		if (!$timeout) trigger_error("Invalid core configuration (timeout).", E_USER_ERROR); | ||||
| 		$timeout = (int) $timeout[0]; | ||||
| 		 | ||||
| 		error_log("Connecting to server at " . $host . ":" . $port . "..."); | ||||
| 		 | ||||
| 		// Connect | ||||
| 		if (!$this->client->InitWithIp($host, $port, $timeout)) { | ||||
| 			trigger_error( | ||||
| 					"Couldn't connect to server! " . $this->client->getErrorMessage() . "(" . $this->client->getErrorCode() . ")",  | ||||
| 					E_USER_ERROR); | ||||
| 		} | ||||
| 		 | ||||
| 		$login = $this->server->config->xpath('login'); | ||||
| 		if (!$login) trigger_error("Invalid server configuration (login).", E_USER_ERROR); | ||||
| 		$login = (string) $login[0]; | ||||
| 		$pass = $this->server->config->xpath('pass'); | ||||
| 		if (!$pass) trigger_error("Invalid server configuration (password).", E_USER_ERROR); | ||||
| 		$pass = (string) $pass[0]; | ||||
| 		 | ||||
| 		// Authenticate | ||||
| 		if (!$this->client->query('Authenticate', $login, $pass)) { | ||||
| 			trigger_error( | ||||
| 					"Couldn't authenticate on server with user '" . $login . "'! " . $this->client->getErrorMessage() . "(" . | ||||
| 							 $this->client->getErrorCode() . ")", E_USER_ERROR); | ||||
| 		} | ||||
| 		 | ||||
| 		// Enable callback system | ||||
| 		if (!$this->client->query('EnableCallbacks', true)) { | ||||
| 			trigger_error("Couldn't enable callbacks! " . $this->client->getErrorMessage() . "(" . $this->client->getErrorCode() . ")",  | ||||
| 					E_USER_ERROR); | ||||
| 		} | ||||
| 		 | ||||
| 		// Wait for server to be ready | ||||
| 		if (!$this->server->waitForStatus($this->client, 4)) { | ||||
| 			trigger_error("Server couldn't get ready!", E_USER_ERROR); | ||||
| 		} | ||||
| 		 | ||||
| 		// Set api version | ||||
| 		if (!$this->client->query('SetApiVersion', self::API_VERSION)) { | ||||
| 			trigger_error( | ||||
| 					"Couldn't set API version '" . self::API_VERSION . "'! This might cause problems. " . | ||||
| 							 $this->iControl->getClientErrorText()); | ||||
| 		} | ||||
| 		 | ||||
| 		// Connect finished | ||||
| 		error_log("Server connection succesfully established!"); | ||||
| 		 | ||||
| 		// Enable service announces | ||||
| 		if (!$this->client->query("DisableServiceAnnounces", false)) { | ||||
| 			trigger_error("Couldn't enable service announces. " . $this->iControl->getClientErrorText()); | ||||
| 		} | ||||
| 		 | ||||
| 		// Enable script callbacks if needed | ||||
| 		if ($this->server->getGameMode() === 0) { | ||||
| 			if (!$this->client->query('GetModeScriptSettings')) { | ||||
| 				trigger_error("Couldn't get mode script settings. " . $this->iControl->getClientErrorText()); | ||||
| 			} | ||||
| 			else { | ||||
| 				$scriptSettings = $this->client->getResponse(); | ||||
| 				if (array_key_exists('S_UseScriptCallbacks', $scriptSettings)) { | ||||
| 					$scriptSettings['S_UseScriptCallbacks'] = true; | ||||
| 					if (!$this->client->query('SetModeScriptSettings', $scriptSettings)) { | ||||
| 						trigger_error( | ||||
| 								"Couldn't set mode script settings to enable script callbacks. " . $this->iControl->getClientErrorText()); | ||||
| 					} | ||||
| 					else { | ||||
| 						error_log("Script callbacks successfully enabled."); | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Load mControl plugins | ||||
| 	 */ | ||||
| 	private function loadPlugins() { | ||||
| 		$pluginsConfig = Tools::loadConfig('plugins.mControl.xml'); | ||||
| 		if (!$pluginsConfig || !isset($pluginsConfig->plugin)) { | ||||
| 			trigger_error('Invalid plugins config.'); | ||||
| 			return; | ||||
| 		} | ||||
| 		 | ||||
| 		// Load plugin classes | ||||
| 		$classes = get_declared_classes(); | ||||
| 		foreach ($pluginsConfig->xpath('plugin') as $plugin) { | ||||
| 			$fileName = mControl . '/plugins/' . $plugin; | ||||
| 			if (!file_exists($fileName)) { | ||||
| 				trigger_error("Couldn't load plugin '" . $plugin . "'! File doesn't exist. (/plugins/" . $plugin . ")"); | ||||
| 			} | ||||
| 			else { | ||||
| 				require_once $fileName; | ||||
| 				error_log("Loading plugin: " . $plugin); | ||||
| 			} | ||||
| 		} | ||||
| 		$plugins = array_diff(get_declared_classes(), $classes); | ||||
| 		 | ||||
| 		// Create plugins | ||||
| 		foreach ($plugins as $plugin) { | ||||
| 			$nameIndex = stripos($plugin, 'plugin'); | ||||
| 			if ($nameIndex === false) continue; | ||||
| 			array_push($this->plugins, new $plugin($this)); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Handle EndMap callback | ||||
| 	 */ | ||||
| 	public function handleEndMap($callback) { | ||||
| 		// Autosave match settings | ||||
| 		$autosaveMatchsettings = $this->config->xpath('autosave_matchsettings'); | ||||
| 		if ($autosaveMatchsettings) { | ||||
| 			$autosaveMatchsettings = (string) $autosaveMatchsettings[0]; | ||||
| 			if ($autosaveMatchsettings) { | ||||
| 				if (!$this->client->query('SaveMatchSettings', 'MatchSettings/' . $autosaveMatchsettings)) { | ||||
| 					trigger_error("Couldn't autosave match settings. " . $this->iControl->getClientErrorText()); | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Check config settings | ||||
| 	 */ | ||||
| 	public function checkConfig($config, $settings, $name = 'Config XML') { | ||||
| 		if (!is_array($settings)) $settings = array($settings); | ||||
| 		foreach ($settings as $setting) { | ||||
| 			$settingTags = $config->xpath('//' . $setting); | ||||
| 			if (empty($settingTags)) { | ||||
| 				trigger_error("Missing property '" . $setting . "' in config '" . $name . "'!", E_USER_ERROR); | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| ?> | ||||
							
								
								
									
										401
									
								
								application/core/database.mControl.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										401
									
								
								application/core/database.mControl.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,401 @@ | ||||
| <?php | ||||
|  | ||||
| namespace mControl; | ||||
|  | ||||
| /** | ||||
|  * Class for database connection | ||||
|  * | ||||
|  * @author steeffeen | ||||
|  */ | ||||
| class Database { | ||||
| 	/** | ||||
| 	 * Constants | ||||
| 	 */ | ||||
| 	const TABLE_PLAYERS = 'ic_players'; | ||||
| 	const TABLE_MAPS = 'ic_maps'; | ||||
|  | ||||
| 	/** | ||||
| 	 * Public properties | ||||
| 	 */ | ||||
| 	public $mysqli = null; | ||||
|  | ||||
| 	/** | ||||
| 	 * Private properties | ||||
| 	 */ | ||||
| 	private $mControl = null; | ||||
|  | ||||
| 	private $config = null; | ||||
|  | ||||
| 	private $multiQueries = ''; | ||||
|  | ||||
| 	/** | ||||
| 	 * Construct database connection | ||||
| 	 */ | ||||
| 	public function __construct($mControl) { | ||||
| 		$this->mControl = $mControl; | ||||
| 		 | ||||
| 		// Load config | ||||
| 		$this->config = Tools::loadConfig('database.mControl.xml'); | ||||
| 		$this->iControl->checkConfig($this->config, array("host", "user"), 'database.mControl.xml'); | ||||
| 		 | ||||
| 		// Get mysql server information | ||||
| 		$host = $this->config->xpath('host'); | ||||
| 		if (!$host) trigger_error("Invalid database configuration (host).", E_USER_ERROR); | ||||
| 		$host = (string) $host[0]; | ||||
| 		 | ||||
| 		$port = $this->config->xpath('port'); | ||||
| 		if (!$port) trigger_error("Invalid database configuration (port).", E_USER_ERROR); | ||||
| 		$port = (int) $port[0]; | ||||
| 		 | ||||
| 		$user = $this->config->xpath('user'); | ||||
| 		if (!$user) trigger_error("Invalid database configuration (user).", E_USER_ERROR); | ||||
| 		$user = (string) $user[0]; | ||||
| 		 | ||||
| 		$pass = $this->config->xpath('pass'); | ||||
| 		if (!$pass) trigger_error("Invalid database configuration (pass).", E_USER_ERROR); | ||||
| 		$pass = (string) $pass[0]; | ||||
| 		 | ||||
| 		// Open database connection | ||||
| 		$this->mysqli = new \mysqli($host, $user, $pass, null, $port); | ||||
| 		if ($this->mysqli->connect_error) { | ||||
| 			// Connection error | ||||
| 			throw new \Exception( | ||||
| 					"Error on connecting to mysql server. " . $this->mysqli->connect_error . " (" . $this->mysqli->connect_errno . ")"); | ||||
| 		} | ||||
| 		 | ||||
| 		// Set charset | ||||
| 		$this->mysqli->set_charset("utf8"); | ||||
| 		 | ||||
| 		// Create/Connect database | ||||
| 		$this->initDatabase(); | ||||
| 		 | ||||
| 		// Init tables | ||||
| 		$this->initTables(); | ||||
| 		 | ||||
| 		// Register for callbacks | ||||
| 		$this->iControl->callbacks->registerCallbackHandler(Callbacks::CB_IC_5_SECOND, $this, 'handle5Second'); | ||||
| 		$this->iControl->callbacks->registerCallbackHandler(Callbacks::CB_IC_BEGINMAP, $this, 'handleBeginMap'); | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Destruct database connection | ||||
| 	 */ | ||||
| 	public function __destruct() { | ||||
| 		$this->mysqli->close(); | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Connect to the defined database (create it if needed) | ||||
| 	 */ | ||||
| 	private function initDatabase() { | ||||
| 		$dbname = $this->config->xpath('database'); | ||||
| 		if (!$dbname) trigger_error("Invalid database configuration (database).", E_USER_ERROR); | ||||
| 		$dbname = (string) $dbname[0]; | ||||
| 		 | ||||
| 		// Try to connect | ||||
| 		$result = $this->mysqli->select_db($dbname); | ||||
| 		if (!$result) { | ||||
| 			// Create database | ||||
| 			$query = "CREATE DATABASE `" . $this->escape($dbname) . "`;"; | ||||
| 			$result = $this->mysqli->query($query); | ||||
| 			if (!$result) { | ||||
| 				trigger_error( | ||||
| 						"Couldn't create database '" . $dbname . "'. " . $this->mysqli->error . ' (' . $this->mysqli->errno . ')',  | ||||
| 						E_USER_ERROR); | ||||
| 			} | ||||
| 			else { | ||||
| 				// Connect to database | ||||
| 				$result = $this->mysqli->select_db($dbname); | ||||
| 				if (!$result) { | ||||
| 					trigger_error( | ||||
| 							"Couldn't select database '" . $dbname . "'. " . $this->mysqli->error . ' (' . $this->mysqli->errno . ')',  | ||||
| 							E_USER_ERROR); | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Create the needed tables | ||||
| 	 */ | ||||
| 	private function initTables() { | ||||
| 		$query = ""; | ||||
| 		 | ||||
| 		// Players table | ||||
| 		$query .= "CREATE TABLE IF NOT EXISTS `" . self::TABLE_PLAYERS . "` ( | ||||
| 			`index` int(11) NOT NULL AUTO_INCREMENT, | ||||
| 			`Login` varchar(100) NOT NULL, | ||||
| 			`NickName` varchar(250) NOT NULL, | ||||
| 			`PlayerId` int(11) NOT NULL, | ||||
| 			`LadderRanking` int(11) NOT NULL, | ||||
| 			`Flags` varchar(50) NOT NULL, | ||||
| 			`changed` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, | ||||
| 			PRIMARY KEY (`index`), | ||||
| 			UNIQUE KEY `Login` (`Login`) | ||||
| 			) ENGINE=MyISAM DEFAULT CHARSET=utf8 COMMENT='Store player metadata' AUTO_INCREMENT=1;"; | ||||
| 		 | ||||
| 		// Maps table | ||||
| 		$query .= "CREATE TABLE IF NOT EXISTS `ic_maps` ( | ||||
| 			`index` int(11) NOT NULL AUTO_INCREMENT, | ||||
| 			`UId` varchar(100) NOT NULL, | ||||
| 			`Name` varchar(100) NOT NULL, | ||||
| 			`FileName` varchar(200) NOT NULL, | ||||
| 			`Author` varchar(150) NOT NULL, | ||||
| 			`Environnement` varchar(50) NOT NULL, | ||||
| 			`Mood` varchar(50) NOT NULL, | ||||
| 			`BronzeTime` int(11) NOT NULL DEFAULT '-1', | ||||
| 			`SilverTime` int(11) NOT NULL DEFAULT '-1', | ||||
| 			`GoldTime` int(11) NOT NULL DEFAULT '-1', | ||||
| 			`AuthorTime` int(11) NOT NULL DEFAULT '-1', | ||||
| 			`CopperPrice` int(11) NOT NULL DEFAULT '-1', | ||||
| 			`LapRace` tinyint(1) NOT NULL, | ||||
| 			`NbLaps` int(11) NOT NULL DEFAULT '-1', | ||||
| 			`NbCheckpoints` int(11) NOT NULL DEFAULT '-1', | ||||
| 			`MapType` varchar(100) NOT NULL, | ||||
| 			`MapStyle` varchar(100) NOT NULL, | ||||
| 			`changed` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, | ||||
| 			PRIMARY KEY (`index`), | ||||
| 			UNIQUE KEY `UId` (`UId`) | ||||
| 			) ENGINE=MyISAM DEFAULT CHARSET=utf8 COMMENT='Store map metadata' AUTO_INCREMENT=1;"; | ||||
| 		 | ||||
| 		// Perform queries | ||||
| 		if (!$this->multiQuery($query)) { | ||||
| 			trigger_error("Creating basic tables failed. " . $this->mysqli->error . ' (' . $this->mysqli->errno . ')', E_USER_ERROR); | ||||
| 		} | ||||
| 		 | ||||
| 		// Optimize all existing tables | ||||
| 		$query = "SHOW TABLES;"; | ||||
| 		$result = $this->query($query); | ||||
| 		if (!$result || !is_object($result)) { | ||||
| 			trigger_error("Couldn't select tables. " . $this->mysqli->error . ' (' . $this->mysqli->errno . ')'); | ||||
| 		} | ||||
| 		else { | ||||
| 			$query = "OPTIMIZE TABLE "; | ||||
| 			$count = $result->num_rows; | ||||
| 			$index = 0; | ||||
| 			while ($row = $result->fetch_row()) { | ||||
| 				$query .= "`" . $row[0] . "`"; | ||||
| 				if ($index < $count - 1) $query .= ", "; | ||||
| 				$index++; | ||||
| 			} | ||||
| 			$query .= ";"; | ||||
| 			if (!$this->query($query)) { | ||||
| 				trigger_error("Couldn't optimize tables. " . $this->mysqli->error . ' (' . $this->mysqli->errno . ')'); | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Wrapper for performing a simple query | ||||
| 	 * | ||||
| 	 * @param string $query        	 | ||||
| 	 * @return mixed query result | ||||
| 	 */ | ||||
| 	public function query($query) { | ||||
| 		if (!is_string($query)) return false; | ||||
| 		if (strlen($query) <= 0) return true; | ||||
| 		return $this->mysqli->query($query); | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Perform multi query | ||||
| 	 * | ||||
| 	 * @param | ||||
| 	 *        	string multi_query | ||||
| 	 * @return bool whether no error occured during executing the multi query | ||||
| 	 */ | ||||
| 	public function multiQuery($query) { | ||||
| 		if (!is_string($query)) return false; | ||||
| 		if (strlen($query) <= 0) return true; | ||||
| 		$noError = true; | ||||
| 		$this->mysqli->multi_query($query); | ||||
| 		if ($this->mysqli->error) { | ||||
| 			trigger_error("Executing multi query failed. " . $this->mysqli->error . ' (' . $this->mysqli->errno . ')'); | ||||
| 			$noError = false; | ||||
| 		} | ||||
| 		while ($this->mysqli->more_results() && $this->mysqli->next_result()) { | ||||
| 			if ($this->mysqli->error) { | ||||
| 				trigger_error("Executing multi query failed. " . $this->mysqli->error . ' (' . $this->mysqli->errno . ')'); | ||||
| 				$noError = false; | ||||
| 			} | ||||
| 		} | ||||
| 		return $noError; | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Handle 5Second callback | ||||
| 	 */ | ||||
| 	public function handle5Second($callback = null) { | ||||
| 		// Save current players in database | ||||
| 		$players = $this->iControl->server->getPlayers(); | ||||
| 		if ($players) { | ||||
| 			$query = ""; | ||||
| 			foreach ($players as $player) { | ||||
| 				if (!Tools::isPlayer($player)) continue; | ||||
| 				$query .= $this->composeInsertPlayer($player); | ||||
| 			} | ||||
| 			$this->multiQuery($query); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Handle BeginMap callback | ||||
| 	 */ | ||||
| 	public function handleBeginMap($callback) { | ||||
| 		$map = $callback[1][0]; | ||||
| 		$query = $this->composeInsertMap($map); | ||||
| 		$result = $this->query($query); | ||||
| 		if ($this->mysqli->error) { | ||||
| 			trigger_error("Couldn't save map. " . $this->mysqli->error . ' (' . $this->mysqli->errno . ')'); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Get the player index for the given login | ||||
| 	 * | ||||
| 	 * @param string $login        	 | ||||
| 	 * @return int null | ||||
| 	 */ | ||||
| 	public function getPlayerIndex($login) { | ||||
| 		$query = "SELECT `index` FROM `" . self::TABLE_PLAYERS . "` WHERE `Login` = '" . $this->escape($login) . "';"; | ||||
| 		$result = $this->query($query); | ||||
| 		$result = $result->fetch_assoc(); | ||||
| 		if ($result) { | ||||
| 			return $result['index']; | ||||
| 		} | ||||
| 		return null; | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Get the map index for the given UId | ||||
| 	 * | ||||
| 	 * @param string $uid        	 | ||||
| 	 * @return int null | ||||
| 	 */ | ||||
| 	public function getMapIndex($uid) { | ||||
| 		$query = "SELECT `index` FROM `" . self::TABLE_MAPS . "` WHERE `UId` = '" . $this->escape($uid) . "';"; | ||||
| 		$result = $this->query($query); | ||||
| 		$result = $result->fetch_assoc(); | ||||
| 		if ($result) { | ||||
| 			return $result['index']; | ||||
| 		} | ||||
| 		return null; | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Compose a query string for inserting the given player | ||||
| 	 * | ||||
| 	 * @param array $player        	 | ||||
| 	 */ | ||||
| 	private function composeInsertPlayer($player) { | ||||
| 		if (!Tools::isPlayer($player)) return ""; | ||||
| 		return "INSERT INTO `" . self::TABLE_PLAYERS . "` ( | ||||
| 			`Login`, | ||||
| 			`NickName`, | ||||
| 			`PlayerId`, | ||||
| 			`LadderRanking`, | ||||
| 			`Flags` | ||||
| 			) VALUES ( | ||||
| 			'" . $this->escape($player['Login']) . "', | ||||
| 			'" . $this->escape($player['NickName']) . "', | ||||
| 			" . $player['PlayerId'] . ", | ||||
| 			" . $player['LadderRanking'] . ", | ||||
| 			'" . $this->escape($player['Flags']) . "' | ||||
| 			) ON DUPLICATE KEY UPDATE | ||||
| 			`NickName` = VALUES(`NickName`), | ||||
| 			`PlayerId` = VALUES(`PlayerId`), | ||||
| 			`LadderRanking` = VALUES(`LadderRanking`), | ||||
| 			`Flags` = VALUES(`Flags`);"; | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Compose a query string for inserting the given map | ||||
| 	 * | ||||
| 	 * @param array $map        	 | ||||
| 	 */ | ||||
| 	private function composeInsertMap($map) { | ||||
| 		if (!$map) return ""; | ||||
| 		return "INSERT INTO `" . self::TABLE_MAPS . "` ( | ||||
| 			`UId`, | ||||
| 			`Name`, | ||||
| 			`FileName`, | ||||
| 			`Author`, | ||||
| 			`Environnement`, | ||||
| 			`Mood`, | ||||
| 			`BronzeTime`, | ||||
| 			`SilverTime`, | ||||
| 			`GoldTime`, | ||||
| 			`AuthorTime`, | ||||
| 			`CopperPrice`, | ||||
| 			`LapRace`, | ||||
| 			`NbLaps`, | ||||
| 			`NbCheckpoints`, | ||||
| 			`MapType`, | ||||
| 			`MapStyle` | ||||
| 			) VALUES ( | ||||
| 			'" . $this->escape($map['UId']) . "', | ||||
| 			'" . $this->escape($map['Name']) . "', | ||||
| 			'" . $this->escape($map['FileName']) . "', | ||||
| 			'" . $this->escape($map['Author']) . "', | ||||
| 			'" . $this->escape($map['Environnement']) . "', | ||||
| 			'" . $this->escape($map['Mood']) . "', | ||||
| 			" . $map['BronzeTime'] . ", | ||||
| 			" . $map['SilverTime'] . ", | ||||
| 			" . $map['GoldTime'] . ", | ||||
| 			" . $map['AuthorTime'] . ", | ||||
| 			" . $map['CopperPrice'] . ", | ||||
| 			" . Tools::boolToInt($map['LapRace']) . ", | ||||
| 			" . $map['NbLaps'] . ", | ||||
| 			" . $map['NbCheckpoints'] . ", | ||||
| 			'" . $this->escape($map['MapType']) . "', | ||||
| 			'" . $this->escape($map['MapStyle']) . "' | ||||
| 			) ON DUPLICATE KEY UPDATE | ||||
| 			`Name` = VALUES(`Name`), | ||||
| 			`FileName` = VALUES(`FileName`), | ||||
| 			`Author` = VALUES(`Author`), | ||||
| 			`Environnement` = VALUES(`Environnement`), | ||||
| 			`Mood` = VALUES(`Mood`), | ||||
| 			`BronzeTime` = VALUES(`BronzeTime`), | ||||
| 			`SilverTime` = VALUES(`SilverTime`), | ||||
| 			`GoldTime` = VALUES(`GoldTime`), | ||||
| 			`AuthorTime` = VALUES(`AuthorTime`), | ||||
| 			`CopperPrice` = VALUES(`CopperPrice`), | ||||
| 			`LapRace` = VALUES(`LapRace`), | ||||
| 			`NbLaps` = VALUES(`NbLaps`), | ||||
| 			`NbCheckpoints` = VALUES(`NbCheckpoints`), | ||||
| 			`MapType` = VALUES(`MapType`), | ||||
| 			`MapStyle` = VALUES(`MapStyle`);"; | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Retrieve all information about the player with the given login | ||||
| 	 */ | ||||
| 	public function getPlayer($login) { | ||||
| 		if (!$login) return null; | ||||
| 		$query = "SELECT * FROM `" . self::TABLE_PLAYERS . "` WHERE `Login` = '" . $this->escape($login) . "';"; | ||||
| 		$result = $this->mysqli->query($query); | ||||
| 		if ($this->mysqli->error || !$result) { | ||||
| 			trigger_error( | ||||
| 					"Couldn't select player with login '" . $login . "'. " . $this->mysqli->error . ' (' . $this->mysqli->errno . ')'); | ||||
| 			return null; | ||||
| 		} | ||||
| 		else { | ||||
| 			while ($player = $result->fetch_assoc()) { | ||||
| 				return $player; | ||||
| 			} | ||||
| 			return null; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Escapes the given string for a mysql query | ||||
| 	 * | ||||
| 	 * @param string $string        	 | ||||
| 	 * @return string | ||||
| 	 */ | ||||
| 	public function escape($string) { | ||||
| 		return $this->mysqli->escape_string($string); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| ?> | ||||
							
								
								
									
										381
									
								
								application/core/server.mControl.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										381
									
								
								application/core/server.mControl.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,381 @@ | ||||
| <?php | ||||
|  | ||||
| namespace mControl; | ||||
|  | ||||
| /** | ||||
|  * Class providing information and commands for the connected maniaplanet server | ||||
|  * | ||||
|  * @author steeffeen | ||||
|  */ | ||||
| class Server { | ||||
| 	/** | ||||
| 	 * Constants | ||||
| 	 */ | ||||
| 	const VALIDATIONREPLAYDIR = 'ValidationReplays/'; | ||||
| 	const GHOSTREPLAYDIR = 'GhostReplays/'; | ||||
|  | ||||
| 	/** | ||||
| 	 * Public properties | ||||
| 	 */ | ||||
| 	public $config = null; | ||||
|  | ||||
| 	/** | ||||
| 	 * Private properties | ||||
| 	 */ | ||||
| 	private $mControl = null; | ||||
|  | ||||
| 	/** | ||||
| 	 * Construct server | ||||
| 	 */ | ||||
| 	public function __construct($mControl) { | ||||
| 		$this->mControl = $mControl; | ||||
| 		 | ||||
| 		// Load config | ||||
| 		$this->config = Tools::loadConfig('server.mControl.xml'); | ||||
| 		$this->iControl->checkConfig($this->config, array('host', 'port', 'login', 'pass'), 'server'); | ||||
| 		 | ||||
| 		// Register for callbacks | ||||
| 		$this->iControl->callbacks->registerCallbackHandler(Callbacks::CB_IC_1_SECOND, $this, 'eachSecond'); | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Perform actions every second | ||||
| 	 */ | ||||
| 	public function eachSecond() { | ||||
| 		// Delete cached information | ||||
| 		$this->players = null; | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Fetch game directory of the server | ||||
| 	 * | ||||
| 	 * @return string | ||||
| 	 */ | ||||
| 	public function getDataDirectory() { | ||||
| 		if (!$this->iControl->client->query('GameDataDirectory')) { | ||||
| 			trigger_error("Couldn't get data directory. " . $this->iControl->getClientErrorText()); | ||||
| 			return null; | ||||
| 		} | ||||
| 		return $this->iControl->client->getResponse(); | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Checks if mControl has access to the given directory (server data directory if no param) | ||||
| 	 * | ||||
| 	 * @param string $directory        	 | ||||
| 	 * @return bool | ||||
| 	 */ | ||||
| 	public function checkAccess($directory = null) { | ||||
| 		if (!$directory) { | ||||
| 			$directory = $this->getDataDirectory(); | ||||
| 		} | ||||
| 		return is_dir($directory) && is_writable($directory); | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Fetch server login | ||||
| 	 */ | ||||
| 	public function getLogin($client = null) { | ||||
| 		$systemInfo = $this->getSystemInfo(false, $client); | ||||
| 		if (!$systemInfo) return null; | ||||
| 		return $systemInfo['ServerLogin']; | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Get detailed server info | ||||
| 	 */ | ||||
| 	public function getInfo($detailed = false) { | ||||
| 		if ($detailed) { | ||||
| 			$login = $this->getLogin(); | ||||
| 			if (!$this->iControl->client->query('GetDetailedPlayerInfo', $login)) { | ||||
| 				trigger_error("Couldn't fetch detailed server player info. " . $this->iControl->getClientErrorText()); | ||||
| 				return null; | ||||
| 			} | ||||
| 		} | ||||
| 		else { | ||||
| 			if (!$this->iControl->client->query('GetMainServerPlayerInfo')) { | ||||
| 				trigger_error("Couldn't fetch server player info. " . $this->iControl->getClientErrorText()); | ||||
| 				return null; | ||||
| 			} | ||||
| 		} | ||||
| 		return $this->iControl->client->getResponse(); | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Get server options | ||||
| 	 */ | ||||
| 	public function getOptions() { | ||||
| 		if (!$this->iControl->client->query('GetServerOptions')) { | ||||
| 			trigger_error("Couldn't fetch server options. " . $this->iControl->getClientErrorText()); | ||||
| 			return null; | ||||
| 		} | ||||
| 		return $this->iControl->client->getResponse(); | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Fetch server name | ||||
| 	 */ | ||||
| 	public function getName() { | ||||
| 		if (!$this->iControl->client->query('GetServerName')) { | ||||
| 			trigger_error("Couldn't fetch server name. " . $this->iControl->getClientErrorText()); | ||||
| 			return null; | ||||
| 		} | ||||
| 		return $this->iControl->client->getResponse(); | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Fetch server version | ||||
| 	 */ | ||||
| 	public function getVersion($forceRefresh = false) { | ||||
| 		if (isset($this->iControl->client->version) && !$forceRefresh) return $this->iControl->client->version; | ||||
| 		if (!$this->iControl->client->query('GetVersion')) { | ||||
| 			trigger_error("Couldn't fetch server version. " . $this->iControl->getClientErrorText()); | ||||
| 			return null; | ||||
| 		} | ||||
| 		else { | ||||
| 			$this->iControl->client->version = $this->iControl->client->getResponse(); | ||||
| 			return $this->iControl->client->version; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Fetch server system info | ||||
| 	 */ | ||||
| 	public function getSystemInfo($forceRefresh = false, &$client = null) { | ||||
| 		if (!$this->iControl->client && !$client) return null; | ||||
| 		if (!$client) $client = $this->iControl->client; | ||||
| 		if (isset($client->systemInfo) && !$forceRefresh) return $client->systemInfo; | ||||
| 		if (!$client->query('GetSystemInfo')) { | ||||
| 			trigger_error("Couldn't fetch server system info. " . $this->iControl->getClientErrorText($client)); | ||||
| 			return null; | ||||
| 		} | ||||
| 		else { | ||||
| 			$client->systemInfo = $client->getResponse(); | ||||
| 			return $client->systemInfo; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Fetch network status | ||||
| 	 */ | ||||
| 	public function getNetworkStats($forceRefresh = false) { | ||||
| 		if (isset($this->iControl->client->networkStats) && !$forceRefresh) return $this->iControl->client->networkStats; | ||||
| 		if (!$this->iControl->client->query('GetNetworkStats')) { | ||||
| 			trigger_error("Couldn't fetch network stats. " . $this->iControl->getClientErrorText()); | ||||
| 			return null; | ||||
| 		} | ||||
| 		else { | ||||
| 			$this->iControl->client->networkStats = $this->iControl->client->getResponse(); | ||||
| 			return $this->iControl->client->networkStats; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Fetch current game mode | ||||
| 	 * | ||||
| 	 * @param bool $stringValue        	 | ||||
| 	 * @param int $parseValue        	 | ||||
| 	 * @return int | string | ||||
| 	 */ | ||||
| 	public function getGameMode($stringValue = false, $parseValue = null) { | ||||
| 		if (is_int($parseValue)) { | ||||
| 			$gameMode = $parseValue; | ||||
| 		} | ||||
| 		else { | ||||
| 			if (!$this->iControl->client->query('GetGameMode')) { | ||||
| 				trigger_error("Couldn't fetch current game mode. " . $this->iControl->getClientErrorText()); | ||||
| 				return null; | ||||
| 			} | ||||
| 			$gameMode = $this->iControl->client->getResponse(); | ||||
| 		} | ||||
| 		if ($stringValue) { | ||||
| 			switch ($gameMode) { | ||||
| 				case 0: | ||||
| 					{ | ||||
| 						return 'Script'; | ||||
| 					} | ||||
| 				case 1: | ||||
| 					{ | ||||
| 						return 'Rounds'; | ||||
| 					} | ||||
| 				case 2: | ||||
| 					{ | ||||
| 						return 'TimeAttack'; | ||||
| 					} | ||||
| 				case 3: | ||||
| 					{ | ||||
| 						return 'Team'; | ||||
| 					} | ||||
| 				case 4: | ||||
| 					{ | ||||
| 						return 'Laps'; | ||||
| 					} | ||||
| 				case 5: | ||||
| 					{ | ||||
| 						return 'Cup'; | ||||
| 					} | ||||
| 				case 6: | ||||
| 					{ | ||||
| 						return 'Stunts'; | ||||
| 					} | ||||
| 				default: | ||||
| 					{ | ||||
| 						return 'Unknown'; | ||||
| 					} | ||||
| 			} | ||||
| 		} | ||||
| 		return $gameMode; | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Fetch player info | ||||
| 	 * | ||||
| 	 * @param string $login        	 | ||||
| 	 * @return struct | ||||
| 	 */ | ||||
| 	public function getPlayer($login, $detailed = false) { | ||||
| 		if (!$login) return null; | ||||
| 		$command = ($detailed ? 'GetDetailedPlayerInfo' : 'GetPlayerInfo'); | ||||
| 		if (!$this->iControl->client->query($command, $login)) { | ||||
| 			trigger_error("Couldn't player info for '" . $login . "'. " . $this->iControl->getClientErrorText()); | ||||
| 			return null; | ||||
| 		} | ||||
| 		return $this->iControl->client->getResponse(); | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Fetch all players | ||||
| 	 */ | ||||
| 	public function getPlayers(&$client = null, &$purePlayers = null, &$pureSpectators = null) { | ||||
| 		if (!$this->iControl->client && !$client) return null; | ||||
| 		if (!$client) $client = $this->iControl->client; | ||||
| 		$fetchLength = 30; | ||||
| 		$offset = 0; | ||||
| 		$players = array(); | ||||
| 		if (!is_array($purePlayers)) $purePlayers = array(); | ||||
| 		if (!is_array($pureSpectators)) $pureSpectators = array(); | ||||
| 		$tries = 0; | ||||
| 		while ($tries < 10) { | ||||
| 			if (!$client->query('GetPlayerList', $fetchLength, $offset)) { | ||||
| 				trigger_error("Couldn't get player list. " . $this->iControl->getClientErrorText($client)); | ||||
| 				$tries++; | ||||
| 			} | ||||
| 			else { | ||||
| 				$chunk = $client->getResponse(); | ||||
| 				$count = count($chunk); | ||||
| 				$serverLogin = $this->getLogin($client); | ||||
| 				for ($index = 0; $index < $count; $index++) { | ||||
| 					$login = $chunk[$index]['Login']; | ||||
| 					if ($login === $serverLogin) { | ||||
| 						// Ignore server | ||||
| 						unset($chunk[$index]); | ||||
| 					} | ||||
| 					else { | ||||
| 						if ($chunk[$index]['SpectatorStatus'] > 0) { | ||||
| 							// Pure spectator | ||||
| 							array_push($pureSpectators, $chunk[$index]); | ||||
| 						} | ||||
| 						else { | ||||
| 							// Pure player | ||||
| 							array_push($purePlayers, $chunk[$index]); | ||||
| 						} | ||||
| 					} | ||||
| 				} | ||||
| 				$players = array_merge($players, $chunk); | ||||
| 				$offset += $count; | ||||
| 				if ($count < $fetchLength) break; | ||||
| 			} | ||||
| 		} | ||||
| 		return $players; | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Retrieve validation replay for given login | ||||
| 	 * | ||||
| 	 * @param string $login        	 | ||||
| 	 * @return string | ||||
| 	 */ | ||||
| 	public function getValidationReplay($login) { | ||||
| 		if (!$login) return null; | ||||
| 		if (!$this->iControl->client->query('GetValidationReplay', $login)) { | ||||
| 			trigger_error("Couldn't get validation replay of '" . $login . "'. " . $this->iControl->getClientErrorText()); | ||||
| 			return null; | ||||
| 		} | ||||
| 		return $this->iControl->client->getResponse(); | ||||
| 	} | ||||
|  | ||||
| 	public function getGhostReplay($login) { | ||||
| 		$dataDir = $this->getDataDirectory(); | ||||
| 		if (!$this->checkAccess($dataDir)) { | ||||
| 			return null; | ||||
| 		} | ||||
| 		 | ||||
| 		// Build file name | ||||
| 		$map = $this->getMap(); | ||||
| 		$gameMode = $this->getGameMode(); | ||||
| 		$time = time(); | ||||
| 		$fileName = 'Ghost.' . $login . '.' . $gameMode . '.' . $time . '.' . $map['UId'] . '.Replay.Gbx'; | ||||
| 		 | ||||
| 		// Save ghost replay | ||||
| 		if (!$this->iControl->client->query('SaveBestGhostsReplay', $login, self::GHOSTREPLAYDIR . $fileName)) { | ||||
| 			trigger_error("Couldn't save ghost replay. " . $this->iControl->getClientErrorText()); | ||||
| 			return null; | ||||
| 		} | ||||
| 		 | ||||
| 		// Load replay file | ||||
| 		$ghostReplay = file_get_contents($dataDir . 'Replays/' . self::GHOSTREPLAYDIR . $fileName); | ||||
| 		if (!$ghostReplay) { | ||||
| 			trigger_error("Couldn't retrieve saved ghost replay."); | ||||
| 			return null; | ||||
| 		} | ||||
| 		return $ghostReplay; | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Fetch current map | ||||
| 	 */ | ||||
| 	public function getMap() { | ||||
| 		if (!$this->iControl->client) return null; | ||||
| 		if (!$this->iControl->client->query('GetCurrentMapInfo')) { | ||||
| 			trigger_error("Couldn't fetch map info. " . $this->iControl->getClientErrorText()); | ||||
| 			return null; | ||||
| 		} | ||||
| 		return $this->iControl->client->getResponse(); | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Waits for the server to have the given status | ||||
| 	 */ | ||||
| 	public function waitForStatus($client, $statusCode = 4) { | ||||
| 		$client->query('GetStatus'); | ||||
| 		$response = $client->getResponse(); | ||||
| 		// Check if server reached given status | ||||
| 		if ($response['Code'] === 4) return true; | ||||
| 		// Server not yet in given status -> Wait for it... | ||||
| 		$waitBegin = time(); | ||||
| 		$timeoutTags = $this->iControl->config->xpath('timeout'); | ||||
| 		$maxWaitTime = (!empty($timeoutTags) ? (int) $timeoutTags[0] : 20); | ||||
| 		$lastStatus = $response['Name']; | ||||
| 		error_log("Waiting for server to reach status " . $statusCode . "..."); | ||||
| 		error_log("Current Status: " . $lastStatus); | ||||
| 		while ($response['Code'] !== 4) { | ||||
| 			sleep(1); | ||||
| 			$client->query('GetStatus'); | ||||
| 			$response = $client->getResponse(); | ||||
| 			if ($lastStatus !== $response['Name']) { | ||||
| 				error_log("New Status: " . $response['Name']); | ||||
| 				$lastStatus = $response['Name']; | ||||
| 			} | ||||
| 			if (time() - $maxWaitTime > $waitBegin) { | ||||
| 				// It took too long to reach the status | ||||
| 				trigger_error( | ||||
| 						"Server couldn't reach status " . $statusCode . " after " . $maxWaitTime . " seconds! " . | ||||
| 								 $this->iControl->getClientErrorText()); | ||||
| 				return false; | ||||
| 			} | ||||
| 		} | ||||
| 		return true; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| ?> | ||||
							
								
								
									
										297
									
								
								application/core/stats.mControl.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										297
									
								
								application/core/stats.mControl.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,297 @@ | ||||
| <?php | ||||
|  | ||||
| namespace mControl; | ||||
|  | ||||
| /** | ||||
|  * Stats class | ||||
|  * | ||||
|  * @author steeffeen | ||||
|  */ | ||||
| class Stats { | ||||
| 	/** | ||||
| 	 * Constants | ||||
| 	 */ | ||||
| 	const TABLE_STATS_SERVER = 'ic_stats_server'; | ||||
| 	const TABLE_STATS_PLAYERS = 'ic_stats_players'; | ||||
|  | ||||
| 	/** | ||||
| 	 * Private properties | ||||
| 	 */ | ||||
| 	private $mControl = null; | ||||
|  | ||||
| 	private $config = null; | ||||
|  | ||||
| 	/** | ||||
| 	 * Constuct stats manager | ||||
| 	 */ | ||||
| 	public function __construct($mControl) { | ||||
| 		$this->mControl = $mControl; | ||||
| 		 | ||||
| 		// Load config | ||||
| 		$this->config = Tools::loadConfig('stats.mControl.xml'); | ||||
| 		$this->loadSettings(); | ||||
| 		 | ||||
| 		// Init database tables | ||||
| 		$this->initTables(); | ||||
| 		 | ||||
| 		// Register for needed callbacks | ||||
| 		$this->iControl->callbacks->registerCallbackHandler(Callbacks::CB_MP_ENDMAP, $this, 'handleEndMap'); | ||||
| 		$this->iControl->callbacks->registerCallbackHandler(Callbacks::CB_MP_PLAYERCHAT, $this, 'handlePlayerChat'); | ||||
| 		$this->iControl->callbacks->registerCallbackHandler(Callbacks::CB_MP_PLAYERCONNECT, $this, 'handlePlayerConnect'); | ||||
| 		$this->iControl->callbacks->registerCallbackHandler(Callbacks::CB_MP_PLAYERDISCONNECT, $this, 'handlePlayerDisconnect'); | ||||
| 		$this->iControl->callbacks->registerCallbackHandler(Callbacks::CB_TM_PLAYERFINISH, $this, 'handlePlayerFinish'); | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Create the database tables | ||||
| 	 */ | ||||
| 	private function initTables() { | ||||
| 		$query = ""; | ||||
| 		 | ||||
| 		// Server stats | ||||
| 		$query .= "CREATE TABLE IF NOT EXISTS `" . self::TABLE_STATS_SERVER . "` ( | ||||
| 		`index` int(11) NOT NULL AUTO_INCREMENT, | ||||
| 		`day` date NOT NULL, | ||||
| 		`connectCount` int(11) NOT NULL DEFAULT '0', | ||||
| 		`maxPlayerCount` int(11) NOT NULL DEFAULT '0', | ||||
| 		`playedMaps` int(11) NOT NULL DEFAULT '0', | ||||
| 		`finishCount` int(11) NOT NULL DEFAULT '0', | ||||
| 		`changed` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, | ||||
| 		PRIMARY KEY (`index`), | ||||
| 		UNIQUE KEY `day` (`day`) | ||||
| 		) ENGINE=MyISAM DEFAULT CHARSET=utf8 COMMENT='Stores server stats' AUTO_INCREMENT=1;"; | ||||
| 		 | ||||
| 		// Player stats | ||||
| 		$query .= "CREATE TABLE IF NOT EXISTS `" . self::TABLE_STATS_PLAYERS . "` ( | ||||
| 		`index` int(11) NOT NULL AUTO_INCREMENT, | ||||
| 		`Login` varchar(100) NOT NULL, | ||||
| 		`playTime` int(11) NOT NULL DEFAULT '0', | ||||
| 		`connectCount` int(11) NOT NULL DEFAULT '0', | ||||
| 		`chatCount` int(11) NOT NULL DEFAULT '0', | ||||
| 		`finishCount` int(11) NOT NULL DEFAULT '0', | ||||
| 		`hitCount` int(11) NOT NULL DEFAULT '0', | ||||
| 		`eliminationCount` int(11) NOT NULL DEFAULT '0', | ||||
| 		`lastJoin` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', | ||||
| 		`changed` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, | ||||
| 		PRIMARY KEY (`index`), | ||||
| 		UNIQUE KEY `Login` (`Login`) | ||||
| 		) ENGINE=MyISAM DEFAULT CHARSET=utf8 COMMENT='Tracks player stats' AUTO_INCREMENT=1;"; | ||||
| 		 | ||||
| 		// Perform queries | ||||
| 		if (!$this->iControl->database->multiQuery($query)) { | ||||
| 			trigger_error("Creating stats tables failed."); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Load settings from config | ||||
| 	 */ | ||||
| 	private function loadSettings() { | ||||
| 		$this->settings = new \stdClass(); | ||||
| 		 | ||||
| 		$this->settings->track_server_connects = Tools::checkSetting($this->config, 'track_server_connects'); | ||||
| 		$this->settings->track_server_max_players = Tools::checkSetting($this->config, 'track_server_max_players'); | ||||
| 		$this->settings->track_server_played_maps = Tools::checkSetting($this->config, 'track_server_played_maps'); | ||||
| 		$this->settings->track_server_finishes = Tools::checkSetting($this->config, 'track_server_finishes'); | ||||
| 		 | ||||
| 		$this->settings->track_player_connects = Tools::checkSetting($this->config, 'track_player_connects'); | ||||
| 		$this->settings->track_player_playtime = Tools::checkSetting($this->config, 'track_player_playtime'); | ||||
| 		$this->settings->track_player_chats = Tools::checkSetting($this->config, 'track_player_chats'); | ||||
| 		$this->settings->track_player_finishes = Tools::checkSetting($this->config, 'track_player_finishes'); | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Handle EndMap callback | ||||
| 	 */ | ||||
| 	public function handleEndMap($callback) { | ||||
| 		$multiquery = ""; | ||||
| 		 | ||||
| 		// Track played server maps | ||||
| 		if ($this->settings->track_server_played_maps) { | ||||
| 			$multiquery .= "INSERT INTO `" . self::TABLE_STATS_SERVER . "` ( | ||||
| 			`day`, | ||||
| 			`playedMaps` | ||||
| 			) VALUES ( | ||||
| 			CURDATE(), | ||||
| 			1 | ||||
| 			) ON DUPLICATE KEY UPDATE | ||||
| 			`playedMaps` = `playedMaps` + VALUES(`playedMaps`) | ||||
| 			;"; | ||||
| 		} | ||||
| 		 | ||||
| 		// Perform query | ||||
| 		if (!$this->iControl->database->multiQuery($multiquery)) { | ||||
| 			trigger_error("Perform queries on end map failed."); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Handle PlayerChat callback | ||||
| 	 */ | ||||
| 	public function handlePlayerChat($callback) { | ||||
| 		if ($callback[1][0] <= 0) return; | ||||
| 		$multiquery = ""; | ||||
| 		$login = $callback[1][1]; | ||||
| 		 | ||||
| 		// Track chats | ||||
| 		if ($this->settings->track_player_chats) { | ||||
| 			$multiquery .= "INSERT INTO `" . self::TABLE_STATS_PLAYERS . "` ( | ||||
| 			`Login`, | ||||
| 			`chatCount` | ||||
| 			) VALUES ( | ||||
| 			'" . $this->iControl->database->escape($login) . "', | ||||
| 			1 | ||||
| 			) ON DUPLICATE KEY UPDATE | ||||
| 			`chatCount` = `chatCount` + VALUES(`chatCount`) | ||||
| 			;"; | ||||
| 		} | ||||
| 		 | ||||
| 		// Perform query | ||||
| 		if (!$this->iControl->database->multiQuery($multiquery)) { | ||||
| 			trigger_error("Perform queries on player chat failed."); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Handle PlayerConnect callback | ||||
| 	 */ | ||||
| 	public function handlePlayerConnect($callback) { | ||||
| 		$multiquery = ""; | ||||
| 		$login = $callback[1][0]; | ||||
| 		 | ||||
| 		// Track server connect | ||||
| 		if ($this->settings->track_server_connects) { | ||||
| 			$multiquery .= "INSERT INTO `" . self::TABLE_STATS_SERVER . "` ( | ||||
| 			`day`, | ||||
| 			`connectCount` | ||||
| 			) VALUES ( | ||||
| 			CURDATE(), | ||||
| 			1 | ||||
| 			) ON DUPLICATE KEY UPDATE | ||||
| 			`connectCount` = `connectCount` + VALUES(`connectCount`) | ||||
| 			;"; | ||||
| 		} | ||||
| 		 | ||||
| 		// Track server max players | ||||
| 		if ($this->settings->track_server_max_players) { | ||||
| 			$players = $this->iControl->server->getPlayers(); | ||||
| 			$multiquery .= "INSERT INTO `" . self::TABLE_STATS_SERVER . "` ( | ||||
| 			`day`, | ||||
| 			`maxPlayerCount` | ||||
| 			) VALUES ( | ||||
| 			CURDATE(), | ||||
| 			" . count($players) . " | ||||
| 			) ON DUPLICATE KEY UPDATE | ||||
| 			`maxPlayerCount` = GREATEST(`maxPlayerCount`, VALUES(`maxPlayerCount`)) | ||||
| 			;"; | ||||
| 		} | ||||
| 		 | ||||
| 		// Track player connect | ||||
| 		if ($this->settings->track_player_connects) { | ||||
| 			$multiquery .= "INSERT INTO `" . self::TABLE_STATS_PLAYERS . "` ( | ||||
| 			`Login`, | ||||
| 			`lastJoin`, | ||||
| 			`connectCount` | ||||
| 			) VALUES ( | ||||
| 			'" . $this->iControl->database->escape($login) . "', | ||||
| 			NOW(), | ||||
| 			1 | ||||
| 			) ON DUPLICATE KEY UPDATE | ||||
| 			`lastJoin` = VALUES(`lastJoin`), | ||||
| 			`connectCount` = `connectCount` + VALUES(`connectCount`) | ||||
| 			;"; | ||||
| 		} | ||||
| 		 | ||||
| 		// Perform query | ||||
| 		if (!$this->iControl->database->multiQuery($multiquery)) { | ||||
| 			trigger_error("Perform queries on player connect failed."); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Handle PlayerDisconnect callback | ||||
| 	 */ | ||||
| 	public function handlePlayerDisconnect($callback) { | ||||
| 		$multiquery = ""; | ||||
| 		$login = $callback[1][0]; | ||||
| 		 | ||||
| 		// Track player playtime | ||||
| 		if ($this->settings->track_player_playtime) { | ||||
| 			$query = "SELECT `lastJoin` FROM `" . self::TABLE_STATS_PLAYERS . "` | ||||
| 			WHERE `Login` = '" . $this->iControl->database->escape($login) . "' | ||||
| 			;"; | ||||
| 			$result = $this->iControl->database->query($query); | ||||
| 			if (!$result) { | ||||
| 				// Error | ||||
| 				trigger_error("Error selecting player join time from '" . $login . "'."); | ||||
| 			} | ||||
| 			else { | ||||
| 				// Add play time | ||||
| 				while ($row = $result->fetch_object()) { | ||||
| 					if (!property_exists($row, 'lastJoin')) continue; | ||||
| 					$lastJoin = strtotime($row->lastJoin); | ||||
| 					$lastJoin = ($lastJoin > $this->iControl->startTime ? $lastJoin : $this->iControl->startTime); | ||||
| 					$multiquery .= "INSERT INTO `" . self::TABLE_STATS_PLAYERS . "` ( | ||||
| 					`Login`, | ||||
| 					`playTime` | ||||
| 					) VALUES ( | ||||
| 					'" . $this->iControl->database->escape($login) . "', | ||||
| 					TIMESTAMPDIFF(SECOND, '" . Tools::timeToTimestamp($lastJoin) . "', NOW()) | ||||
| 					) ON DUPLICATE KEY UPDATE | ||||
| 					`playTime` = `playTime` + VALUES(`playTime`) | ||||
| 					;"; | ||||
| 					break; | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 		 | ||||
| 		// Perform query | ||||
| 		if (!$this->iControl->database->multiQuery($multiquery)) { | ||||
| 			trigger_error("Perform queries on player connect failed."); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Handle the PlayerFinish callback | ||||
| 	 */ | ||||
| 	public function handlePlayerFinish($callback) { | ||||
| 		if ($callback[1][0] <= 0) return; | ||||
| 		if ($callback[1][2] <= 0) return; | ||||
| 		 | ||||
| 		$multiquery = ""; | ||||
| 		$login = $callback[1][1]; | ||||
| 		 | ||||
| 		// Track server finishes | ||||
| 		if ($this->settings->track_server_finishes) { | ||||
| 			$multiquery .= "INSERT INTO `" . self::TABLE_STATS_SERVER . "` ( | ||||
| 			`day`, | ||||
| 			`finishCount` | ||||
| 			) VALUES ( | ||||
| 			CURDATE(), | ||||
| 			1 | ||||
| 			) ON DUPLICATE KEY UPDATE | ||||
| 			`finishCount` = `finishCount` + VALUES(`finishCount`) | ||||
| 			;"; | ||||
| 		} | ||||
| 		 | ||||
| 		// Track player finishes | ||||
| 		if ($this->settings->track_player_finishes) { | ||||
| 			$multiquery .= "INSERT INTO `" . self::TABLE_STATS_PLAYERS . "` ( | ||||
| 			`Login`, | ||||
| 			`finishCount` | ||||
| 			) VALUES ( | ||||
| 			'" . $this->iControl->database->escape($login) . "', | ||||
| 			1 | ||||
| 			) ON DUPLICATE KEY UPDATE | ||||
| 			`finishCount` = `finishCount` + VALUES(`finishCount`) | ||||
| 			;"; | ||||
| 		} | ||||
| 		 | ||||
| 		// Perform query | ||||
| 		if (!$this->iControl->database->multiQuery($multiquery)) { | ||||
| 			trigger_error("Perform queries on player finish failed."); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| ?> | ||||
							
								
								
									
										240
									
								
								application/core/tools.mControl.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										240
									
								
								application/core/tools.mControl.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,240 @@ | ||||
| <?php | ||||
|  | ||||
| namespace mControl; | ||||
|  | ||||
| /** | ||||
|  * Class for basic tools | ||||
|  * | ||||
|  * @author steeffeen | ||||
|  */ | ||||
| class Tools { | ||||
|  | ||||
| 	/** | ||||
| 	 * Check if the given setting is enabled | ||||
| 	 * | ||||
| 	 * @param simple_xml_element $config        	 | ||||
| 	 * @param string $setting        	 | ||||
| 	 */ | ||||
| 	public static function checkSetting($config, $setting) { | ||||
| 		$settings = $config->xpath('//' . $setting); | ||||
| 		if (empty($settings)) { | ||||
| 			return false; | ||||
| 		} | ||||
| 		else { | ||||
| 			foreach ($settings as $setting) { | ||||
| 				return self::toBool((string) $setting[0]); | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Check if the given data describes a player | ||||
| 	 * | ||||
| 	 * @param array $player        	 | ||||
| 	 * @return bool | ||||
| 	 */ | ||||
| 	public static function isPlayer($player) { | ||||
| 		if (!$player || !is_array($player)) return false; | ||||
| 		if (!array_key_exists('PlayerId', $player) || !is_int($player['PlayerId']) || $player['PlayerId'] <= 0) return false; | ||||
| 		return true; | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Convert the given time int to mysql timestamp | ||||
| 	 * | ||||
| 	 * @param int $time        	 | ||||
| 	 * @return string | ||||
| 	 */ | ||||
| 	public static function timeToTimestamp($time) { | ||||
| 		return date("Y-m-d H:i:s", $time); | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Add alignment attributes to an xml element | ||||
| 	 * | ||||
| 	 * @param simple_xml_element $xml        	 | ||||
| 	 * @param string $halign        	 | ||||
| 	 * @param string $valign        	 | ||||
| 	 */ | ||||
| 	public static function addAlignment($xml, $halign = 'center', $valign = 'center2') { | ||||
| 		if (!is_object($xml) || !method_exists($xml, 'addAttribute')) return; | ||||
| 		if (!property_exists($xml, 'halign')) $xml->addAttribute('halign', $halign); | ||||
| 		if (!property_exists($xml, 'valign')) $xml->addAttribute('valign', $valign); | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Add translate attribute to an xml element | ||||
| 	 * | ||||
| 	 * @param simple_xml_element $xml        	 | ||||
| 	 * @param bool $translate        	 | ||||
| 	 */ | ||||
| 	public static function addTranslate($xml, $translate = true) { | ||||
| 		if (!is_object($xml) || !method_exists($xml, 'addAttribute')) return; | ||||
| 		if (!property_exists($xml, 'translate')) $xml->addAttribute('translate', ($translate ? 1 : 0)); | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Load a remote file | ||||
| 	 * | ||||
| 	 * @param string $url        	 | ||||
| 	 * @return string || null | ||||
| 	 */ | ||||
| 	public static function loadFile($url) { | ||||
| 		if (!$url) return false; | ||||
| 		$urlData = parse_url($url); | ||||
| 		$port = (isset($urlData['port']) ? $urlData['port'] : 80); | ||||
| 		 | ||||
| 		$fsock = fsockopen($urlData['host'], $port); | ||||
| 		stream_set_timeout($fsock, 3); | ||||
| 		 | ||||
| 		$query = 'GET ' . $urlData['path'] . ' HTTP/1.0' . PHP_EOL; | ||||
| 		$query .= 'Host: ' . $urlData['host'] . PHP_EOL; | ||||
| 		$query .= 'Content-Type: UTF-8' . PHP_EOL; | ||||
| 		$query .= 'User-Agent: mControl v' . mControl::VERSION . PHP_EOL; | ||||
| 		$query .= PHP_EOL; | ||||
| 		 | ||||
| 		fwrite($fsock, $query); | ||||
| 		 | ||||
| 		$buffer = ''; | ||||
| 		$info = array('timed_out' => false); | ||||
| 		while (!feof($fsock) && !$info['timed_out']) { | ||||
| 			$buffer .= fread($fsock, 1024); | ||||
| 			$info = stream_get_meta_data($fsock); | ||||
| 		} | ||||
| 		fclose($fsock); | ||||
| 		 | ||||
| 		if ($info['timed_out'] || !$buffer) { | ||||
| 			return null; | ||||
| 		} | ||||
| 		if (substr($buffer, 9, 3) != "200") { | ||||
| 			return null; | ||||
| 		} | ||||
| 		 | ||||
| 		$result = explode("\r\n\r\n", $buffer, 2); | ||||
| 		 | ||||
| 		if (count($result) < 2) { | ||||
| 			return null; | ||||
| 		} | ||||
| 		 | ||||
| 		return $result[1]; | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Formats the given time (milliseconds) | ||||
| 	 * | ||||
| 	 * @param int $time        	 | ||||
| 	 * @return string | ||||
| 	 */ | ||||
| 	public static function formatTime($time) { | ||||
| 		if (!is_int($time)) $time = (int) $time; | ||||
| 		$milliseconds = $time % 1000; | ||||
| 		$seconds = floor($time / 1000); | ||||
| 		$minutes = floor($seconds / 60); | ||||
| 		$hours = floor($minutes / 60); | ||||
| 		$minutes -= $hours * 60; | ||||
| 		$seconds -= $hours * 60 + $minutes * 60; | ||||
| 		$format = ($hours > 0 ? $hours . ':' : ''); | ||||
| 		$format .= ($hours > 0 && $minutes < 10 ? '0' : '') . $minutes . ':'; | ||||
| 		$format .= ($seconds < 10 ? '0' : '') . $seconds . ':'; | ||||
| 		$format .= ($milliseconds < 100 ? '0' : '') . ($milliseconds < 10 ? '0' : '') . $milliseconds; | ||||
| 		return $format; | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Convert given data to real boolean | ||||
| 	 * | ||||
| 	 * @param | ||||
| 	 *        	mixed data | ||||
| 	 */ | ||||
| 	public static function toBool($var) { | ||||
| 		if ($var === true) return true; | ||||
| 		if ($var === false) return false; | ||||
| 		if ($var === null) return false; | ||||
| 		if (is_object($var)) { | ||||
| 			$var = (string) $var; | ||||
| 		} | ||||
| 		if (is_int($var)) { | ||||
| 			return ($var > 0); | ||||
| 		} | ||||
| 		else if (is_string($var)) { | ||||
| 			$text = strtolower($var); | ||||
| 			if ($text === 'true' || $text === 'yes') { | ||||
| 				return true; | ||||
| 			} | ||||
| 			else if ($text === 'false' || $text === 'no') { | ||||
| 				return false; | ||||
| 			} | ||||
| 			else { | ||||
| 				return ((int) $text > 0); | ||||
| 			} | ||||
| 		} | ||||
| 		else { | ||||
| 			return (bool) $var; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Converts the given boolean to an int representation | ||||
| 	 * | ||||
| 	 * @param bool $bool        	 | ||||
| 	 * @return int | ||||
| 	 */ | ||||
| 	public static function boolToInt($bool) { | ||||
| 		return ($bool ? 1 : 0); | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Build new simple xml element | ||||
| 	 * | ||||
| 	 * @param string $name        	 | ||||
| 	 * @param string $id        	 | ||||
| 	 * @return \SimpleXMLElement | ||||
| 	 */ | ||||
| 	public static function newManialinkXml($id = null) { | ||||
| 		$xml = new \SimpleXMLElement('<?xml version="1.0" encoding="UTF-8" standalone="yes"?><manialink/>'); | ||||
| 		$xml->addAttribute('version', '1'); | ||||
| 		if ($id) $xml->addAttribute('id', $id); | ||||
| 		return $xml; | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Load config xml-file | ||||
| 	 * | ||||
| 	 * @param string $fileName        	 | ||||
| 	 * @return \SimpleXMLElement | ||||
| 	 */ | ||||
| 	public static function loadConfig($fileName) { | ||||
| 		// Load config file from configs folder | ||||
| 		$fileLocation = mControl . '/configs/' . $fileName; | ||||
| 		if (!file_exists($fileLocation)) { | ||||
| 			trigger_error("Config file doesn't exist! (" . $fileName . ")", E_USER_ERROR); | ||||
| 		} | ||||
| 		return simplexml_load_file($fileLocation); | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Send the given manialink to players | ||||
| 	 * | ||||
| 	 * @param string $manialink        	 | ||||
| 	 * @param array $logins        	 | ||||
| 	 */ | ||||
| 	public static function sendManialinkPage($client, $manialink, $logins = null, $timeout = 0, $hideOnClick = false) { | ||||
| 		if (!$client || !$manialink) return; | ||||
| 		if (!$logins) { | ||||
| 			// Send manialink to all players | ||||
| 			$client->query('SendDisplayManialinkPage', $manialink, $timeout, $hideOnClick); | ||||
| 		} | ||||
| 		else if (is_array($logins)) { | ||||
| 			// Send manialink to players | ||||
| 			foreach ($logins as $login) { | ||||
| 				$client->query('SendDisplayManialinkPageToLogin', $login, $manialink, $timeout, $hideOnClick); | ||||
| 			} | ||||
| 		} | ||||
| 		else if (is_string($logins)) { | ||||
| 			// Send manialink to player | ||||
| 			$client->query('SendDisplayManialinkPageToLogin', $logins, $manialink, $timeout, $hideOnClick); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| ?> | ||||
		Reference in New Issue
	
	Block a user