diff --git a/application/.idea/workspace.xml b/application/.idea/workspace.xml index 855b8922..e7b71b4d 100644 --- a/application/.idea/workspace.xml +++ b/application/.idea/workspace.xml @@ -23,10 +23,46 @@ - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -35,34 +71,16 @@ - + - - - - - - - - - - + - - - - - - - - - - + @@ -80,9 +98,12 @@ @@ -119,7 +140,18 @@ - + + + + + + + + + + @@ -166,6 +198,20 @@ + + + + + + + + @@ -240,24 +286,24 @@ - + - + - - - - + + + + + - @@ -276,51 +322,65 @@ - + - + - + - + - + - + - + - + - + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - + diff --git a/application/configs/plugins.ManiaControl.xml b/application/configs/plugins.ManiaControl.xml index 7f546f47..d9022328 100644 --- a/application/configs/plugins.ManiaControl.xml +++ b/application/configs/plugins.ManiaControl.xml @@ -1,12 +1,12 @@ - + diff --git a/application/core/authentication.ManiaControl.php b/application/core/authentication.ManiaControl.php deleted file mode 100644 index a083b215..00000000 --- a/application/core/authentication.ManiaControl.php +++ /dev/null @@ -1,103 +0,0 @@ - '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.ManiaControl.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()); - } - } -} - -?> diff --git a/application/core/callbacks.ManiaControl.php b/application/core/callbacks.ManiaControl.php deleted file mode 100644 index 6a6d7a0f..00000000 --- a/application/core/callbacks.ManiaControl.php +++ /dev/null @@ -1,191 +0,0 @@ -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 ManiaControl 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)); - } -} - -?> diff --git a/application/core/chat.ManiaControl.php b/application/core/chat.ManiaControl.php deleted file mode 100644 index 1e4895ae..00000000 --- a/application/core/chat.ManiaControl.php +++ /dev/null @@ -1,85 +0,0 @@ -'; - - /** - * Construct ManiaControl chat - */ - public function __construct($mControl) { - $this->mControl = $mControl; - - // Load config - $this->config = Tools::loadConfig('chat.ManiaControl.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); - } -} - -?> diff --git a/application/core/commands.ManiaControl.php b/application/core/commands.ManiaControl.php deleted file mode 100644 index 2ac5bb22..00000000 --- a/application/core/commands.ManiaControl.php +++ /dev/null @@ -1,684 +0,0 @@ -mControl = $mControl; - - // Load config - $this->config = Tools::loadConfig('commands.ManiaControl.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 ManiaControl 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 ManiaControl v' . ManiaControl::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("ManiaControl 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 ManiaControl 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("ManiaControl couldn't retrieve the maps directory.", $login); - return; - } - else { - $mapDir = $this->iControl->client->getResponse(); - if (!is_dir($mapDir)) { - trigger_error("ManiaControl doesn't have have access to the maps directory in '" . $mapDir . "'."); - $this->iControl->chat->sendError("ManiaControl 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("ManiaControl doesn't have to rights to save maps in'" . $mapDir . $dlDir, "'."); - $this->iControl->chat->sendError("ManiaControl 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 . "'"); - } -} - -?> diff --git a/application/core/core.ManiaControl.php b/application/core/core.ManiaControl.php deleted file mode 100644 index 8b781b0a..00000000 --- a/application/core/core.ManiaControl.php +++ /dev/null @@ -1,348 +0,0 @@ -config = Tools::loadConfig('core.ManiaControl.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 ManiaControl and log the given message - */ - public function quit($message = false) { - if ($this->shutdownRequested) return; - - if ($this->client) { - // Announce quit - $this->chat->sendInformation('ManiaControl 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 ManiaControl!"); - exit(); - } - - /** - * Run ManiaControl - */ - public function run($debug = false) { - error_log('Starting ManiaControl v' . self::VERSION . '!'); - $this->debug = (bool) $debug; - - // Load plugins - $this->loadPlugins(); - - // Connect to server - $this->connect(); - - // Loading finished - error_log("Loading completed!"); - - // Announce ManiaControl - if (!$this->chat->sendInformation('ManiaControl v' . self::VERSION . ' successfully started!')) { - trigger_error("Couldn't announce ManiaControl. " . $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 ManiaControl plugins - */ - private function loadPlugins() { - $pluginsConfig = Tools::loadConfig('plugins.ManiaControl.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 = ManiaControlDir . '/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); - } - } - } -} - -?> diff --git a/application/core/database.ManiaControl.php b/application/core/database.ManiaControl.php deleted file mode 100644 index 57fe8865..00000000 --- a/application/core/database.ManiaControl.php +++ /dev/null @@ -1,401 +0,0 @@ -mControl = $mControl; - - // Load config - $this->config = Tools::loadConfig('database.ManiaControl.xml'); - $this->mControl->checkConfig($this->config, array("host", "user"), 'database.ManiaControl.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->mControl->callbacks->registerCallbackHandler(Callbacks::CB_IC_5_SECOND, $this, 'handle5Second'); - $this->mControl->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->mControl->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); - } -} - -?> diff --git a/application/core/plugin.php b/application/core/plugin.php index 1f5c3aa4..8664ff04 100644 --- a/application/core/plugin.php +++ b/application/core/plugin.php @@ -14,20 +14,21 @@ namespace ManiaControl; /** * Private properties */ - private $mControl; + private $mc; private $version; private $author; private $updateUrl; private $name; + private $active; - - - public function __construct($mControl, $name, $version = 0, $author = '', $updateUrl = ''){ - $this->mControl = $mControl; + public function __construct($mc, $name, $version = 0, $author = '', $updateUrl = ''){ + $this->mc = $mc; $this->name = $name; $this->version = $version; $this->author = $author; $this->updateUrl = $updateUrl; + + $this->mc->pluginHandler->registerPlugin($this); } /** @@ -37,13 +38,37 @@ namespace ManiaControl; * @return array with manialink Ids */ public function reserveManialinkIds($count){ - return $this->mControl->manialinkIdHandler->reserveManialikIds($count); + return $this->mc->manialinkIdHandler->reserveManialikIds($count); } - + public function checkUpdate(){ } + /** + * Enables the Plugin + */ + public function enablePlugin() + { + $this->active = true; + } + + /** + * Disable the Plugin + */ + public function disablePlugin() + { + $this->active = true; + } + + /** + * @return mixed + */ + public function isActive() + { + return $this->active; + } + /** * @param mixed $author */ diff --git a/application/core/pluginHandler.php b/application/core/pluginHandler.php index 5b5d0f19..850be99a 100644 --- a/application/core/pluginHandler.php +++ b/application/core/pluginHandler.php @@ -11,6 +11,19 @@ namespace ManiaControl; class PluginHandler { + /** + * Private properties + */ + private $mc; + private $plugins; + public function __construct($mc){ + $this->mControl = $mc; + $this->plugins = array(); + } + + public function registerPlugin($plugin){ + array_push($this->plugins, $plugin); + } } ?> \ No newline at end of file diff --git a/application/core/server.ManiaControl.php b/application/core/server.ManiaControl.php deleted file mode 100644 index 3018bd0e..00000000 --- a/application/core/server.ManiaControl.php +++ /dev/null @@ -1,381 +0,0 @@ -mControl = $mControl; - - // Load config - $this->config = Tools::loadConfig('server.ManiaControl.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 ManiaControl 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; - } -} - -?> diff --git a/application/core/stats.ManiaControl.php b/application/core/stats.ManiaControl.php deleted file mode 100644 index 8a5e7c52..00000000 --- a/application/core/stats.ManiaControl.php +++ /dev/null @@ -1,297 +0,0 @@ -mControl = $mControl; - - // Load config - $this->config = Tools::loadConfig('stats.ManiaControl.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."); - } - } -} - -?> diff --git a/application/core/tools.ManiaControl.php b/application/core/tools.ManiaControl.php deleted file mode 100644 index 76d959b7..00000000 --- a/application/core/tools.ManiaControl.php +++ /dev/null @@ -1,240 +0,0 @@ -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: ManiaControl v' . ManiaControl::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->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 = ManiaControlDir . '/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); - } - } -} - -?> diff --git a/application/plugins/chatlog.plugin.php b/application/plugins/chatlog.plugin.php deleted file mode 100644 index 8b77449b..00000000 --- a/application/plugins/chatlog.plugin.php +++ /dev/null @@ -1,85 +0,0 @@ -mControl = $mControl; - - // Load config - $this->config = Tools::loadConfig('chatlog.plugin.xml'); - - // Check for enabled setting - if (!Tools::toBool($this->config->enabled)) return; - - // Load settings - $this->loadSettings(); - - // Register for callbacksc - $this->iControl->callbacks->registerCallbackHandler(Callbacks::CB_MP_PLAYERCHAT, $this, 'handlePlayerChatCallback'); - - error_log('Chatlog Pugin v' . self::VERSION . ' ready!'); - } - - /** - * Load settings from config - */ - private function loadSettings() { - $this->settings = new \stdClass(); - - // File name - $fileName = (string) $this->config->filename; - $this->settings->fileName = ManiaControlDir . '/' . $fileName; - - // log_server_messages - $log_server_messages = $this->config->xpath('log_server_messages'); - $this->settings->log_server_messages = ($log_server_messages ? (Tools::toBool($log_server_messages[0])) : false); - } - - /** - * Handle PlayerChat callback - */ - public function handlePlayerChatCallback($callback) { - $data = $callback[1]; - if ($data[0] <= 0 && !$this->settings->log_server_messages) { - // Skip server message - return; - } - $this->logText($data[2], $data[1]); - } - - /** - * Log the given message - * - * @param string $message - * @param string $login - */ - private function logText($text, $login = null) { - $message = date(ManiaControl::DATE) . '>> ' . ($login ? $login . ': ' : '') . $text . PHP_EOL; - file_put_contents($this->settings->fileName, $message, FILE_APPEND); - } -} - -?> diff --git a/application/plugins/karma.plugin.php b/application/plugins/karma.plugin.php deleted file mode 100644 index 26b5cf91..00000000 --- a/application/plugins/karma.plugin.php +++ /dev/null @@ -1,305 +0,0 @@ -mControl = $mControl; - - // Load config - $this->config = Tools::loadConfig('karma.plugin.xml'); - if (!Tools::toBool($this->config->enabled)) return; - - // Init database - $this->initDatabase(); - - // Register for callbacks - $this->iControl->callbacks->registerCallbackHandler(Callbacks::CB_IC_ONINIT, $this, 'handleOnInitCallback'); - $this->iControl->callbacks->registerCallbackHandler(Callbacks::CB_IC_BEGINMAP, $this, 'handleBeginMapCallback'); - $this->iControl->callbacks->registerCallbackHandler(Callbacks::CB_MP_PLAYERCONNECT, $this, 'handlePlayerConnectCallback'); - $this->iControl->callbacks->registerCallbackHandler(Callbacks::CB_MP_PLAYERMANIALINKPAGEANSWER, $this, - 'handleManialinkPageAnswerCallback'); - - error_log('Karma Pugin v' . self::VERSION . ' ready!'); - } - - /** - * Repetitive actions - */ - public function loop() { - if ($this->sendManialinkRequested > 0 && $this->sendManialinkRequested <= time()) { - $this->sendManialinkRequested = -1; - - // Send manialink to all players - $players = $this->iControl->server->getPlayers(); - foreach ($players as $player) { - $login = $player['Login']; - $manialink = $this->buildManialink($login); - if (!$manialink) { - // Skip and retry - $this->sendManialinkRequested = time() + 5; - continue; - } - Tools::sendManialinkPage($this->iControl->client, $manialink->asXml(), $login); - } - } - } - - /** - * Handle OnInit ManiaControl callback - * - * @param array $callback - */ - public function handleOnInitCallback($callback) { - // Send manialink to all players once - $this->sendManialinkRequested = time() + 3; - } - - /** - * Handle ManiaControl BeginMap callback - * - * @param array $callback - */ - public function handleBeginMapCallback($callback) { - // Send manialink to all players once - $this->sendManialinkRequested = time() + 2; - } - - /** - * Handle PlayerConnect callback - * - * @param array $callback - */ - public function handlePlayerConnectCallback($callback) { - $login = $callback[1][0]; - $manialink = $this->buildManialink($login); - if (!$manialink) return; - Tools::sendManialinkPage($this->iControl->client, $manialink->asXml(), $login); - } - - /** - * Create necessary tables - */ - private function initDatabase() { - $query = "CREATE TABLE IF NOT EXISTS `" . self::TABLE_KARMA . "` ( - `index` int(11) NOT NULL AUTO_INCREMENT, - `mapIndex` int(11) NOT NULL, - `playerIndex` int(11) NOT NULL, - `vote` tinyint(1) NOT NULL, - `changed` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, - PRIMARY KEY (`index`), - UNIQUE KEY `player_map_vote` (`mapIndex`, `playerIndex`) - ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COMMENT='Save players map votes' AUTO_INCREMENT=1;"; - $result = $this->iControl->database->query($query); - if ($this->iControl->database->mysqli->error) { - trigger_error('MySQL Error on creating karma table. ' . $this->iControl->database->mysqli->error, E_USER_ERROR); - } - } - - /** - * Handle ManialinkPageAnswer callback - * - * @param array $callback - */ - public function handleManialinkPageAnswerCallback($callback) { - $action = $callback[1][2]; - if (substr($action, 0, strlen(self::MLID_KARMA)) !== self::MLID_KARMA) return; - - // Get vote - $action = substr($action, -4); - $vote = null; - switch ($action) { - case '.pos': - { - $vote = 1; - break; - } - case '.neu': - { - $vote = 0; - break; - } - case '.neg': - { - $vote = -1; - break; - } - default: - { - return; - } - } - - // Save vote - $login = $callback[1][1]; - $playerIndex = $this->iControl->database->getPlayerIndex($login); - $map = $this->iControl->server->getMap(); - $mapIndex = $this->iControl->database->getMapIndex($map['UId']); - $query = "INSERT INTO `" . self::TABLE_KARMA . "` ( - `mapIndex`, - `playerIndex`, - `vote` - ) VALUES ( - " . $mapIndex . ", - " . $playerIndex . ", - " . $vote . " - ) ON DUPLICATE KEY UPDATE - `vote` = VALUES(`vote`);"; - $result = $this->iControl->database->query($query); - if (!$result) return; - - // Send success message - $this->iControl->chat->sendSuccess('Vote successfully updated!', $login); - - // Send updated manialink - $this->sendManialinkRequested = time() + 1; - } - - /** - * Build karma voting manialink xml for the given login - */ - private function buildManialink($login) { - // Get config - $title = (string) $this->config->title; - $pos_x = (float) $this->config->pos_x; - $pos_y = (float) $this->config->pos_y; - - $mysqli = $this->iControl->database->mysqli; - - // Get indezes - $playerIndex = $this->iControl->database->getPlayerIndex($login); - if ($playerIndex === null) return null; - $map = $this->iControl->server->getMap(); - if (!$map) return null; - $mapIndex = $this->iControl->database->getMapIndex($map['UId']); - if ($mapIndex === null) return null; - - // Get votings - $query = "SELECT - (SELECT `vote` FROM `" . - self::TABLE_KARMA . "` WHERE `mapIndex` = " . $mapIndex . " AND `playerIndex` = " . $playerIndex . ") as `playerVote`, - (SELECT COUNT(`vote`) FROM `" . - self::TABLE_KARMA . "` WHERE `mapIndex` = " . $mapIndex . " AND `vote` = 1) AS `positiveVotes`, - (SELECT COUNT(`vote`) FROM `" . - self::TABLE_KARMA . "` WHERE `mapIndex` = " . $mapIndex . " AND `vote` = 0) AS `neutralVotes`, - (SELECT COUNT(`vote`) FROM `" . - self::TABLE_KARMA . "` WHERE `mapIndex` = " . $mapIndex . " AND `vote` = -1) AS `negativeVotes` - FROM `" . self::TABLE_KARMA . "`;"; - $result = $mysqli->query($query); - if ($mysqli->error) { - trigger_error('MySQL ERROR: ' . $mysqli->error); - } - $votes = $result->fetch_assoc(); - if (!$votes) { - $votes = array('playerVote' => null, 'positiveVotes' => 0, 'neutralVotes' => 0, 'negativeVotes' => 0); - } - - // Build manialink - $xml = Tools::newManialinkXml(self::MLID_KARMA); - - $frameXml = $xml->addChild('frame'); - $frameXml->addAttribute('posn', $pos_x . ' ' . $pos_y); - - // Title - $labelXml = $frameXml->addChild('label'); - Tools::addAlignment($labelXml); - $labelXml->addAttribute('posn', '0 4.5 -1'); - $labelXml->addAttribute('sizen', '22 0'); - $labelXml->addAttribute('style', 'TextTitle1'); - $labelXml->addAttribute('textsize', '1'); - $labelXml->addAttribute('text', $title); - - // Background - $quadXml = $frameXml->addChild('quad'); - Tools::addAlignment($quadXml); - $quadXml->addAttribute('sizen', '23 15 -2'); - $quadXml->addAttribute('style', 'Bgs1InRace'); - $quadXml->addAttribute('substyle', 'BgTitleShadow'); - - // Votes - for ($i = 1; $i >= -1; $i--) { - $x = $i * 7.; - - // Vote button - $quadXml = $frameXml->addChild('quad'); - Tools::addAlignment($quadXml); - $quadXml->addAttribute('posn', $x . ' 0 0'); - $quadXml->addAttribute('sizen', '6 6'); - $quadXml->addAttribute('style', 'Icons64x64_1'); - - // Vote count - $labelXml = $frameXml->addChild('label'); - Tools::addAlignment($labelXml); - $labelXml->addAttribute('posn', $x . ' -4.5 0'); - $labelXml->addAttribute('style', 'TextTitle1'); - $labelXml->addAttribute('textsize', '2'); - - if ((string) $i === $votes['playerVote']) { - // Player vote X - $voteQuadXml = $frameXml->addChild('quad'); - Tools::addAlignment($voteQuadXml); - $voteQuadXml->addAttribute('posn', $x . ' 0 1'); - $voteQuadXml->addAttribute('sizen', '6 6'); - $voteQuadXml->addAttribute('style', 'Icons64x64_1'); - $voteQuadXml->addAttribute('substyle', 'Close'); - } - - switch ($i) { - case 1: - { - // Positive - $quadXml->addAttribute('substyle', 'LvlGreen'); - $quadXml->addAttribute('action', self::MLID_KARMA . '.pos'); - $labelXml->addAttribute('text', $votes['positiveVotes']); - break; - } - case 0: - { - // Neutral - $quadXml->addAttribute('substyle', 'LvlYellow'); - $quadXml->addAttribute('action', self::MLID_KARMA . '.neu'); - $labelXml->addAttribute('text', $votes['neutralVotes']); - break; - } - case -1: - { - // Negative - $quadXml->addAttribute('substyle', 'LvlRed'); - $quadXml->addAttribute('action', self::MLID_KARMA . '.neg'); - $labelXml->addAttribute('text', $votes['negativeVotes']); - break; - } - } - } - - return $xml; - } -} - -?> diff --git a/application/plugins/obstacle.plugin.php b/application/plugins/obstacle.plugin.php deleted file mode 100644 index 0084b486..00000000 --- a/application/plugins/obstacle.plugin.php +++ /dev/null @@ -1,63 +0,0 @@ -mControl = $mControl; - - // Load config - $this->config = Tools::loadConfig('obstacle.plugin.xml'); - - // Check for enabled setting - if (!Tools::toBool($this->config->enabled)) return; - - // Register for jump command - $this->iControl->commands->registerCommandHandler('jumpto', $this, 'command_jumpto'); - - error_log('Obstacle Pugin v' . self::VERSION . ' ready!'); - } - - /** - * Handle jumpto command - */ - public function command_jumpto($chat) { - $login = $chat[1][1]; - $rightLevel = (string) $this->config->jumps_rightlevel; - if (!$this->iControl->authentication->checkRight($login, $rightLevel)) { - // Not allowed - $this->iControl->authentication->sendNotAllowed($login); - } - else { - // Send jump callback - $params = explode(' ', $chat[1][2], 2); - $param = $login . ";" . $params[1] . ";"; - if (!$this->iControl->client->query('TriggerModeScriptEvent', self::CB_JUMPTO, $param)) { - trigger_error("Couldn't send jump callback for '" . $login . "'. " . $this->iControl->getClientErrorText()); - } - } - } -} - -?> diff --git a/application/plugins/plugin.ManiaControl.php b/application/plugins/plugin.ManiaControl.php deleted file mode 100644 index a51d9066..00000000 --- a/application/plugins/plugin.ManiaControl.php +++ /dev/null @@ -1,37 +0,0 @@ -mControl = $mControl; - - error_log('Pugin v' . self::VERSION . ' ready!'); - } - - /** - * Perform actions during each loop - */ - public function loop() { - } -} - -?> diff --git a/application/plugins/records.plugin.php b/application/plugins/records.plugin.php deleted file mode 100644 index 71dbbefd..00000000 --- a/application/plugins/records.plugin.php +++ /dev/null @@ -1,1216 +0,0 @@ -mControl = $mControl; - - // Load config - $this->config = Tools::loadConfig('records.plugin.xml'); - - // Check for enabled setting - if (!Tools::toBool($this->config->enabled)) return; - - // Load settings - $this->loadSettings(); - - // Init tables - $this->initTables(); - - // Register for callbacks - $this->iControl->callbacks->registerCallbackHandler(Callbacks::CB_IC_ONINIT, $this, 'handleOnInit'); - $this->iControl->callbacks->registerCallbackHandler(Callbacks::CB_IC_1_SECOND, $this, 'handle1Second'); - $this->iControl->callbacks->registerCallbackHandler(Callbacks::CB_IC_1_MINUTE, $this, 'handle1Minute'); - $this->iControl->callbacks->registerCallbackHandler(Callbacks::CB_IC_3_MINUTE, $this, 'handle3Minute'); - $this->iControl->callbacks->registerCallbackHandler(Callbacks::CB_IC_BEGINMAP, $this, 'handleMapBegin'); - $this->iControl->callbacks->registerCallbackHandler(Callbacks::CB_IC_CLIENTUPDATED, $this, 'handleClientUpdated'); - $this->iControl->callbacks->registerCallbackHandler(Callbacks::CB_IC_ENDMAP, $this, 'handleMapEnd'); - $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'); - $this->iControl->callbacks->registerCallbackHandler(Callbacks::CB_TM_PLAYERCHECKPOINT, $this, 'handlePlayerCheckpoint'); - - error_log('Records Pugin v' . self::VERSION . ' ready!'); - } - - /** - * Init needed database tables - */ - private function initTables() { - $database = $this->iControl->database; - - // Records table - $query = "CREATE TABLE IF NOT EXISTS `" . self::TABLE_RECORDS . "` ( - `index` int(11) NOT NULL AUTO_INCREMENT, - `mapUId` varchar(100) NOT NULL, - `Login` varchar(100) NOT NULL, - `time` int(11) NOT NULL, - `changed` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, - PRIMARY KEY (`index`), - UNIQUE KEY `player_map_record` (`mapUId`,`Login`) - ) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1;"; - if (!$database->query($query)) { - trigger_error("Couldn't create records table. " . $database->mysqli->error); - } - } - - /** - * Load settings from config - */ - private function loadSettings() { - $this->settings = new \stdClass(); - - $this->settings->enabled = Tools::toBool($this->config->enabled); - - $this->settings->local_records_enabled = $this->settings->enabled && Tools::toBool($this->config->local_records->enabled); - $this->settings->dedimania_enabled = $this->settings->enabled && Tools::toBool($this->config->dedimania_records->enabled); - } - - /** - * Handle ManiaControl init - */ - public function handleOnInit($callback = null) { - // Let manialinks update - if ($this->settings->local_records_enabled) { - $this->updateManialinks[self::MLID_LOCAL] = true; - } - - // Update mapinfo - $this->mapInfo = $this->getMapInfo(); - - if ($this->settings->dedimania_enabled) { - // Open dedimania session - $accounts = $this->config->xpath('dedimania_records/account'); - if (!$accounts) { - trigger_error('Invalid dedimania_code in config.'); - $this->settings->dedimania_enabled = false; - } - else { - $this->openDedimaniaSession(); - } - $this->fetchDedimaniaRecords(); - $this->updateManialinks[self::MLID_DEDI] = true; - } - } - - /** - * Fetch dedimania records of the current map - */ - private function fetchDedimaniaRecords($reset = true) { - if (!isset($this->dedimaniaData['context'])) return false; - if ($reset || !isset($this->dedimaniaData['records']) && !is_array($this->dedimaniaData['records'])) { - // Reset records - $this->dedimaniaData['records'] = array(); - } - - // Fetch records - $servInfo = $this->getSrvInfo(); - $playerInfo = $this->getPlayerList(); - $gameMode = $this->getGameModeString(); - $data = array($this->dedimaniaData['sessionId'], $this->mapInfo, $gameMode, $servInfo, $playerInfo); - $request = $this->encode_request(self::DEDIMANIA_GETRECORDS, $data); - stream_context_set_option($this->dedimaniaData['context'], 'http', 'content', $request); - $file = file_get_contents(self::DEDIMANIA_URL, false, $this->dedimaniaData['context']); - - // Handle response - $response = $this->decode($file); - if (is_array($response)) { - foreach ($response as $index => $methodResponse) { - if (xmlrpc_is_fault($methodResponse)) { - $this->handleXmlRpcFault($methodResponse); - return false; - } - else if ($index <= 0) { - $responseData = $methodResponse[0]; - $this->dedimaniaData['records'] = $responseData; - } - } - } - return true; - } - - /** - * Checks dedimania session - */ - private function checkDedimaniaSession() { - if (!$this->settings->dedimania_enabled) return false; - if (!isset($this->dedimaniaData['context'])) return false; - if (!isset($this->dedimaniaData['sessionId']) || !is_string($this->dedimaniaData['sessionId'])) return false; - - // Check session - $request = $this->encode_request(self::DEDIMANIA_CHECKSESSION, array($this->dedimaniaData['sessionId'])); - stream_context_set_option($this->dedimaniaData['context'], 'http', 'content', $request); - $file = file_get_contents(self::DEDIMANIA_URL, false, $this->dedimaniaData['context']); - - // Handle response - $response = $this->decode($file); - $result = false; - if (is_array($response)) { - foreach ($response as $methodResponse) { - if (xmlrpc_is_fault($methodResponse)) { - $this->handleXmlRpcFault($methodResponse); - } - else { - $responseData = $methodResponse[0]; - if (is_bool($responseData)) { - $result = $responseData; - } - } - } - } - return $result; - } - - /** - * Renews dedimania session - */ - private function openDedimaniaSession($init = false) { - if (!$this->settings->dedimania_enabled) return false; - - // Get server data - if ($init || !array_key_exists('serverData', $this->dedimaniaData) || !is_array($this->dedimaniaData['serverData'])) { - $serverData = array(); - $serverData['Game'] = 'TM2'; - $serverInfo = $this->iControl->server->getInfo(true); - - // Get dedimania account data - $accounts = $this->config->xpath('dedimania_records/account'); - foreach ($accounts as $account) { - $login = (string) $account->login; - if ($login != $serverInfo['Login']) continue; - $code = (string) $account->code; - $serverData['Login'] = $login; - $serverData['Code'] = $code; - break; - } - - if (!isset($serverData['Login']) || !isset($serverData['Code'])) { - // Wrong configuration for current server - trigger_error("Records Plugin: Invalid dedimania configuration for login '" . $serverInfo['Login'] . "'."); - if (isset($this->dedimaniaData['context'])) unset($this->dedimaniaData['context']); - if (isset($this->dedimaniaData['sessionId'])) unset($this->dedimaniaData['sessionId']); - return false; - } - - // Complete seesion data - $serverData['Path'] = $serverInfo['Path']; - $systemInfo = $this->iControl->server->getSystemInfo(); - $serverData['Packmask'] = substr($systemInfo['TitleId'], 2); - $serverVersion = $this->iControl->server->getVersion(); - $serverData['ServerVersion'] = $serverVersion['Version']; - $serverData['ServerBuild'] = $serverVersion['Build']; - $serverData['Tool'] = 'ManiaControl'; - $serverData['Version'] = ManiaControl::VERSION; - $this->dedimaniaData['serverData'] = $serverData; - } - - // Init header - if ($init || !array_key_exists('header', $this->dedimaniaData) || !is_array($this->dedimaniaData['header'])) { - $header = ''; - $header .= 'Accept-Charset: utf-8;' . PHP_EOL; - $header .= 'Accept-Encoding: gzip;' . PHP_EOL; - $header .= 'Content-Type: text/xml; charset=utf-8;' . PHP_EOL; - $header .= 'Keep-Alive: 300;' . PHP_EOL; - $header .= 'User-Agent: ManiaControl v' . ManiaControl::VERSION . ';' . PHP_EOL; - $this->dedimaniaData['header'] = $header; - } - - // Open session - $request = $this->encode_request(self::DEDIMANIA_OPENSESSION, array($this->dedimaniaData['serverData'])); - $context = stream_context_create(array('http' => array('method' => 'POST', 'header' => $this->dedimaniaData['header']))); - stream_context_set_option($context, 'http', 'content', $request); - $file = file_get_contents(self::DEDIMANIA_URL, false, $context); - - // Handle response - $response = $this->decode($file); - $result = false; - if (is_array($response)) { - foreach ($response as $index => $methodResponse) { - if (xmlrpc_is_fault($methodResponse)) { - $this->handleXmlRpcFault($methodResponse); - } - else if ($index <= 0) { - $responseData = $methodResponse[0]; - $this->dedimaniaData['context'] = $context; - $this->dedimaniaData['sessionId'] = $responseData['SessionId']; - $result = true; - } - } - } - if ($result) error_log("Dedimania connection successfully established."); - return $result; - } - - /** - * Handle 1Second callback - */ - public function handle1Second() { - if (!$this->settings->enabled) return; - - // Send records manialinks if needed - foreach ($this->updateManialinks as $id => $update) { - if (!$update) continue; - if (array_key_exists($id, $this->lastSendManialinks) && $this->lastSendManialinks[$id] + 2 > time()) continue; - - switch ($id) { - case self::MLID_LOCAL: - { - $this->manialinks[$id] = $this->buildLocalManialink(); - break; - } - case self::MLID_DEDI: - { - $this->manialinks[$id] = $this->buildDedimaniaManialink(); - break; - } - default: - { - continue 2; - break; - } - } - $this->updateManialinks[$id] = false; - $this->lastSendManialinks[$id] = time(); - $this->sendManialink($this->manialinks[$id]); - } - } - - /** - * Handle 1Minute callback - */ - public function handle1Minute($callback = null) { - if ($this->settings->dedimania_enabled) { - // Keep dedimania session alive - if (!$this->checkDedimaniaSession()) { - // Renew session - $this->openDedimaniaSession(); - } - } - } - - /** - * Handle PlayerConnect callback - */ - public function handlePlayerConnect($callback) { - $login = $callback[1][0]; - if ($this->settings->local_records_enabled) $this->sendManialink($this->manialinks[self::MLID_LOCAL], $login); - - if ($this->settings->dedimania_enabled && $this->dedimaniaData['context']) { - $player = $this->iControl->server->getPlayer($login, true); - if ($player) { - // Send dedimania request - $data = array($this->dedimaniaData['sessionId'], $player['Login'], $player['NickName'], $player['Path'], - $player['IsSpectator']); - $request = $this->encode_request(self::DEDIMANIA_PLAYERCONNECT, $data); - stream_context_set_option($this->dedimaniaData['context'], 'http', 'content', $request); - $file = file_get_contents(self::DEDIMANIA_URL, false, $this->dedimaniaData['context']); - - // Handle response - $response = $this->decode($file); - if (is_array($response)) { - foreach ($response as $methodResponse) { - if (xmlrpc_is_fault($methodResponse)) { - $this->handleXmlRpcFault($methodResponse); - } - } - } - else { - if (!$response) { - trigger_error('XmlRpc Error.'); - var_dump($response); - } - } - } - $this->sendManialink($this->manialinks[self::MLID_DEDI], $login); - } - } - - /** - * Handle PlayerDisconnect callback - */ - public function handlePlayerDisconnect($callback) { - $login = $callback[1][0]; - - if ($this->settings->dedimania_enabled && $this->dedimaniaData['context']) { - // Send dedimania request - $data = array($this->dedimaniaData['sessionId'], $login, ''); - $request = $this->encode_request(self::DEDIMANIA_PLAYERDISCONNECT, $data); - stream_context_set_option($this->dedimaniaData['context'], 'http', 'content', $request); - $file = file_get_contents(self::DEDIMANIA_URL, false, $this->dedimaniaData['context']); - - // Handle response - $response = $this->decode($file); - if (is_array($response)) { - foreach ($response as $methodResponse) { - if (xmlrpc_is_fault($methodResponse)) { - $this->handleXmlRpcFault($methodResponse); - } - } - } - else { - if (!$response) { - trigger_error('XmlRpc Error.'); - var_dump($response); - } - } - } - } - - /** - * Handle BeginMap callback - */ - public function handleMapBegin($callback) { - // Update map - $this->mapInfo = $this->getMapInfo(); - - if ($this->settings->local_records_enabled) { - // Update local records - $this->updateManialinks[self::MLID_LOCAL] = true; - } - - if ($this->settings->dedimania_enabled) { - // Update dedimania records - $this->fetchDedimaniaRecords(true); - $this->updateManialinks[self::MLID_DEDI] = true; - } - } - - /** - * Build map info struct for dedimania requests - */ - private function getMapInfo() { - $map = $this->iControl->server->getMap(); - if (!$map) return null; - $mapInfo = array(); - $mapInfo['UId'] = $map['UId']; - $mapInfo['Name'] = $map['Name']; - $mapInfo['Author'] = $map['Author']; - $mapInfo['Environment'] = $map['Environnement']; - $mapInfo['NbCheckpoints'] = $map['NbCheckpoints']; - $mapInfo['NbLaps'] = $map['NbLaps']; - return $mapInfo; - } - - /** - * Handle EndMap callback - */ - public function handleMapEnd($callback) { - if ($this->settings->dedimania_enabled) { - // Send dedimania records - $gameMode = $this->getGameModeString(); - $times = array(); - $replays = array(); - foreach ($this->dedimaniaData['records']['Records'] as $record) { - if (!isset($record['New']) || !$record['New']) continue; - array_push($times, array('Login' => $record['Login'], 'Best' => $record['Best'], 'Checks' => $record['Checks'])); - if (!isset($replays['VReplay'])) { - $replays['VReplay'] = $record['VReplay']; - } - if (!isset($replays['Top1GReplay']) && isset($record['Top1GReplay'])) { - $replays['Top1GReplay'] = $record['Top1GReplay']; - } - // TODO: VReplayChecks - } - if (!isset($replays['VReplay'])) $replays['VReplay'] = ''; - if (!isset($replays['VReplayChecks'])) $replays['VReplayChecks'] = ''; - if (!isset($replays['Top1GReplay'])) $replays['Top1GReplay'] = ''; - - xmlrpc_set_type($replays['VReplay'], 'base64'); - xmlrpc_set_type($replays['Top1GReplay'], 'base64'); - - $data = array($this->dedimaniaData['sessionId'], $this->mapInfo, $gameMode, $times, $replays); - $request = $this->encode_request(self::DEDIMANIA_SETCHALLENGETIMES, $data); - stream_context_set_option($this->dedimaniaData['context'], 'http', 'content', $request); - $file = file_get_contents(self::DEDIMANIA_URL, false, $this->dedimaniaData['context']); - - // Handle response - $response = $this->decode($file); - if (is_array($response)) { - foreach ($response as $index => $methodResponse) { - if (xmlrpc_is_fault($methodResponse)) { - $this->handleXmlRpcFault($methodResponse); - } - else { - if ($index <= 0) { - // Called method response - $responseData = $methodResponse[0]; - if (!$responseData) { - trigger_error("Records Plugin: Submitting dedimania records failed."); - } - continue; - } - - // Warnings and TTR - $errors = $methodResponse[0]['methods'][0]['errors']; - if ($errors) { - trigger_error($errors); - } - } - } - } - } - } - - /** - * Get current checkpoint string for dedimania record - * - * @param string $login - * @return string - */ - private function getChecks($login) { - if (!$login || !isset($this->checkpoints[$login])) return null; - $string = ''; - $count = count($this->checkpoints[$login]); - foreach ($this->checkpoints[$login] as $index => $check) { - $string .= $check; - if ($index < $count - 1) $string .= ','; - } - return $string; - } - - /** - * Build server info struct for callbacks - */ - private function getSrvInfo() { - $server = $this->iControl->server->getOptions(); - if (!$server) return null; - $client = null; - $players = null; - $spectators = null; - $this->iControl->server->getPlayers($client, $players, $spectators); - if (!is_array($players) || !is_array($spectators)) return null; - return array('SrvName' => $server['Name'], 'Comment' => $server['Comment'], 'Private' => (strlen($server['Password']) > 0), - 'NumPlayers' => count($players), 'MaxPlayers' => $server['CurrentMaxPlayers'], 'NumSpecs' => count($spectators), - 'MaxSpecs' => $server['CurrentMaxSpectators']); - } - - /** - * Build simple player list for callbacks - */ - private function getPlayerList($votes = false) { - $client = null; - $players; - $spectators; - $allPlayers = $this->iControl->server->getPlayers($client, $players, $spectators); - if (!is_array($players) || !is_array($spectators)) return null; - $playerInfo = array(); - foreach ($allPlayers as $player) { - array_push($playerInfo, array('Login' => $player['Login'], 'IsSpec' => in_array($player, $spectators))); - } - return $playerInfo; - } - - /** - * Get dedi string representation of the current game mode - */ - private function getGameModeString() { - $gameMode = $this->iControl->server->getGameMode(); - if ($gameMode === null) { - trigger_error("Couldn't retrieve game mode. " . $this->iControl->getClientErrorText()); - return null; - } - switch ($gameMode) { - case 1: - case 3: - case 5: - { - return 'Rounds'; - } - case 2: - case 4: - { - return 'TA'; - } - } - return null; - } - - /** - * Build votes info struct for callbacks - */ - private function getVotesInfo() { - $map = $this->iControl->server->getMap(); - if (!$map) return null; - $gameMode = $this->getGameModeString(); - if (!$gameMode) return null; - return array('UId' => $map['UId'], 'GameMode' => $gameMode); - } - - /** - * Handle 3Minute callback - */ - public function handle3Minute($callback = null) { - if ($this->settings->dedimania_enabled) { - // Update dedimania players - $servInfo = $this->getSrvInfo(); - $votesInfo = $this->getVotesInfo(); - $playerList = $this->getPlayerList(true); - if ($servInfo && $votesInfo && $playerList) { - $data = array($this->dedimaniaData['sessionId'], $servInfo, $votesInfo, $playerList); - $request = $this->encode_request(self::DEDIMANIA_UPDATESERVERPLAYERS, $data); - stream_context_set_option($this->dedimaniaData['context'], 'http', 'content', $request); - $file = file_get_contents(self::DEDIMANIA_URL, false, $this->dedimaniaData['context']); - - // Handle response - $response = $this->decode($file); - if (is_array($response)) { - foreach ($response as $methodResponse) { - if (xmlrpc_is_fault($methodResponse)) { - $this->handleXmlRpcFault($methodResponse); - } - } - } - else if (!$response) { - trigger_error('XmlRpc Error.'); - var_dump($response); - } - } - } - } - - /** - * Handle PlayerCheckpoint callback - */ - public function handlePlayerCheckpoint($callback) { - $data = $callback[1]; - $login = $data[1]; - $time = $data[2]; - $lap = $data[3]; - $cpIndex = $data[4]; - if (!isset($this->checkpoints[$login]) || $cpIndex <= 0) $this->checkpoints[$login] = array(); - $this->checkpoints[$login][$cpIndex] = $time; - } - - /** - * Handle PlayerFinish callback - */ - public function handlePlayerFinish($callback) { - $data = $callback[1]; - if ($data[0] <= 0 || $data[2] <= 0) return; - - $login = $data[1]; - $time = $data[2]; - $newMap = $this->iControl->server->getMap(); - if (!$newMap) return; - if (!$this->mapInfo || $this->mapInfo['UId'] !== $newMap['UId']) { - $this->mapInfo = $this->getMapInfo(); - } - $map = $newMap; - - $player = $this->iControl->server->getPlayer($login); - - if ($this->settings->local_records_enabled) { - // Get old record of the player - $oldRecord = $this->getLocalRecord($map['UId'], $login); - $save = true; - if ($oldRecord) { - if ($oldRecord['time'] < $time) { - // Not improved - $save = false; - } - else if ($oldRecord['time'] == $time) { - // Same time - $message = '$<' . $player['NickName'] . '$> equalized her/his $<$o' . $oldRecord['rank'] . '.$> Local Record: ' . - Tools::formatTime($oldRecord['time']); - $this->iControl->chat->sendInformation($message); - $save = false; - } - } - if ($save) { - // Save time - $database = $this->iControl->database; - $query = "INSERT INTO `" . self::TABLE_RECORDS . "` ( - `mapUId`, - `Login`, - `time` - ) VALUES ( - '" . $database->escape($map['UId']) . "', - '" . $database->escape($login) . "', - " . $time . " - ) ON DUPLICATE KEY UPDATE - `time` = VALUES(`time`);"; - if (!$database->query($query)) { - trigger_error("Couldn't save player record. " . $database->mysqli->error); - } - else { - // Announce record - $newRecord = $this->getLocalRecord($map['UId'], $login); - if ($oldRecord == null || $newRecord['rank'] < $oldRecord['rank']) { - // Gained rank - $improvement = 'gained the'; - } - else { - // Only improved time - $improvement = 'improved her/his'; - } - $message = '$<' . $player['NickName'] . '$> ' . $improvement . ' $<$o' . $newRecord['rank'] . '.$> Local Record: ' . - Tools::formatTime($newRecord['time']); - $this->iControl->chat->sendInformation($message); - $this->updateManialinks[self::MLID_LOCAL] = true; - } - } - } - - if ($this->settings->dedimania_enabled) { - // Get old record of the player - $oldRecord = $this->getDediRecord($login); - $save = true; - if ($oldRecord) { - if ($oldRecord['Best'] < $time) { - // Not improved - $save = false; - } - else if ($oldRecord['Best'] == $time) { - // Same time - $save = false; - } - } - if ($save) { - // Save time - $newRecord = array('Login' => $login, 'NickName' => $player['NickName'], 'Best' => $data[2], - 'Checks' => $this->getChecks($login), 'New' => true); - $inserted = $this->insertDediRecord($newRecord, $oldRecord); - if ($inserted) { - // Get newly saved record - foreach ($this->dedimaniaData['records']['Records'] as $key => &$record) { - if ($record['Login'] !== $newRecord['Login']) continue; - $newRecord = $record; - break; - } - - // Announce record - if (!$oldRecord || $newRecord['Rank'] < $oldRecord['Rank']) { - // Gained rank - $improvement = 'gained the'; - } - else { - // Only improved time - $improvement = 'improved her/his'; - } - $message = '$<' . $player['NickName'] . '$> ' . $improvement . ' $<$o' . $newRecord['Rank'] . - '.$> Dedimania Record: ' . Tools::formatTime($newRecord['Best']); - $this->iControl->chat->sendInformation($message); - $this->updateManialinks[self::MLID_DEDI] = true; - } - } - } - } - - /** - * Get max rank for given login - */ - private function getMaxRank($login) { - if (!isset($this->dedimaniaData['records'])) return null; - $records = $this->dedimaniaData['records']; - $maxRank = $records['ServerMaxRank']; - foreach ($records['Players'] as $player) { - if ($player['Login'] === $login) { - if ($player['MaxRank'] > $maxRank) $maxRank = $player['MaxRank']; - break; - } - } - return $maxRank; - } - - /** - * Inserts the given new dedimania record at the proper position - * - * @param struct $newRecord - * @return bool - */ - private function insertDediRecord(&$newRecord, $oldRecord) { - if (!$newRecord || !isset($this->dedimaniaData['records']) || !isset($this->dedimaniaData['records']['Records'])) return false; - - $insert = false; - $newRecords = array(); - - // Get max possible rank - $maxRank = $this->getMaxRank($newRecord['Login']); - if (!$maxRank) $maxRank = 30; - - // Loop through existing records - foreach ($this->dedimaniaData['records']['Records'] as $key => &$record) { - if ($record['Rank'] > $maxRank) { - // Max rank reached - return false; - } - - if ($record['Login'] === $newRecord['Login']) { - // Old record of the same player - if ($record['Best'] <= $newRecord['Best']) { - // It's better - Do nothing - return false; - } - - // Replace old record - unset($this->dedimaniaData['records']['Records'][$key]); - $insert = true; - break; - } - - // Other player's record - if ($record['Best'] <= $newRecord['Best']) { - // It's better - Skip - continue; - } - - // New record is better - Insert it - $insert = true; - if ($oldRecord) { - // Remove old record - foreach ($this->dedimaniaData['records']['Records'] as $key2 => $record2) { - if ($record2['Login'] !== $oldRecord['Login']) continue; - unset($this->dedimaniaData['records']['Records'][$key2]); - break; - } - } - break; - } - - if (!$insert && count($this->dedimaniaData['records']['Records']) < $maxRank) { - // Records list not full - Append new record - $insert = true; - } - - if ($insert) { - // Insert new record - array_push($this->dedimaniaData['records']['Records'], $newRecord); - - // Update ranks - $this->updateDediRecordRanks(); - - // Save replays - foreach ($this->dedimaniaData['records']['Records'] as $key => &$record) { - if ($record['Login'] !== $newRecord['Login']) continue; - $this->setRecordReplays($record); - break; - } - - // Record inserted - return true; - } - - // No new record - return false; - } - - /** - * Updates the replay values for the given record - * - * @param struct $record - */ - private function setRecordReplays(&$record) { - if (!$record || !$this->settings->dedimania_enabled) return; - - // Set validation replay - $validationReplay = $this->iControl->server->getValidationReplay($record['Login']); - if ($validationReplay) $record['VReplay'] = $validationReplay; - - // Set ghost replay - if ($record['Rank'] <= 1) { - $dataDirectory = $this->iControl->server->getDataDirectory(); - if (!isset($this->dedimaniaData['directoryAccessChecked'])) { - $access = $this->iControl->server->checkAccess($dataDirectory); - if (!$access) { - trigger_error("No access to the servers data directory. Can't retrieve ghost replays."); - } - $this->dedimaniaData['directoryAccessChecked'] = $access; - } - if ($this->dedimaniaData['directoryAccessChecked']) { - $ghostReplay = $this->iControl->server->getGhostReplay($record['Login']); - if ($ghostReplay) $record['Top1GReplay'] = $ghostReplay; - } - } - } - - /** - * Update the sorting and the ranks of all dedimania records - */ - private function updateDediRecordRanks() { - if (!isset($this->dedimaniaData['records']) || !isset($this->dedimaniaData['records']['Records'])) return; - - // Sort records - usort($this->dedimaniaData['records']['Records'], array($this, 'compareRecords')); - - // Update ranks - $rank = 1; - foreach ($this->dedimaniaData['records']['Records'] as &$record) { - $record['Rank'] = $rank; - $rank++; - } - } - - /** - * Compare function for sorting dedimania records - * - * @param struct $first - * @param struct $second - * @return int - */ - private function compareRecords($first, $second) { - if ($first['Best'] < $second['Best']) { - return -1; - } - else if ($first['Best'] > $second['Best']) { - return 1; - } - else { - if ($first['Rank'] < $second['Rank']) { - return -1; - } - else { - return 1; - } - } - } - - /** - * Get the dedimania record of the given login - * - * @param string $login - * @return struct - */ - private function getDediRecord($login) { - if (!isset($this->dedimaniaData['records'])) return null; - $records = $this->dedimaniaData['records']['Records']; - foreach ($records as $index => $record) { - if ($record['Login'] === $login) return $record; - } - return null; - } - - /** - * Send manialink to clients - */ - private function sendManialink($manialink, $login = null) { - if (!$manialink || !$this->iControl->client) return; - if (!$login) { - if (!$this->iControl->client->query('SendDisplayManialinkPage', $manialink->asXML(), 0, false)) { - trigger_error("Couldn't send manialink to players. " . $this->iControl->getClientErrorText()); - } - } - else { - if (!$this->iControl->client->query('SendDisplayManialinkPageToLogin', $login, $manialink->asXML(), 0, false)) { - trigger_error("Couldn't send manialink to player '" . $login . "'. " . $this->iControl->getClientErrorText()); - } - } - } - - /** - * Handle ClientUpdated callback - * - * @param mixed $data - */ - public function handleClientUpdated($data) { - $this->openDedimaniaSession(true); - if (isset($this->updateManialinks[self::MLID_LOCAL])) $this->updateManialinks[self::MLID_LOCAL] = true; - if (isset($this->updateManialinks[self::MLID_DEDI])) $this->updateManialinks[self::MLID_DEDI] = true; - } - - /** - * Update local records manialink - */ - private function buildLocalManialink() { - $map = $this->iControl->server->getMap(); - if (!$map) { - return null; - } - - $pos_x = (float) $this->config->local_records->widget->pos_x; - $pos_y = (float) $this->config->local_records->widget->pos_y; - $title = (string) $this->config->local_records->widget->title; - $width = (float) $this->config->local_records->widget->width; - $lines = (int) $this->config->local_records->widget->lines; - $line_height = (float) $this->config->local_records->widget->line_height; - - $recordResult = $this->getLocalRecords($map['UId']); - if (!$recordResult) { - trigger_error("Couldn't fetch player records."); - return null; - } - - $xml = Tools::newManialinkXml(self::MLID_LOCAL); - - $frame = $xml->addChild('frame'); - $frame->addAttribute('posn', $pos_x . ' ' . $pos_y); - - // Background - $quad = $frame->addChild('quad'); - Tools::addAlignment($quad, 'center', 'top'); - $quad->addAttribute('sizen', ($width * 1.05) . ' ' . (7. + $lines * $line_height)); - $quad->addAttribute('style', 'Bgs1InRace'); - $quad->addAttribute('substyle', 'BgTitleShadow'); - - // Title - $label = $frame->addChild('label'); - Tools::addAlignment($label); - Tools::addTranslate($xml); - $label->addAttribute('posn', '0 ' . ($line_height * -0.9)); - $label->addAttribute('sizen', $width . ' 0'); - $label->addAttribute('style', 'TextTitle1'); - $label->addAttribute('textsize', '2'); - $label->addAttribute('text', $title); - - // Times - $index = 0; - while ($record = $recordResult->fetch_assoc()) { - $y = -8. - $index * $line_height; - - $recordFrame = $frame->addChild('frame'); - $recordFrame->addAttribute('posn', '0 ' . $y); - - // Background - $quad = $recordFrame->addChild('quad'); - Tools::addAlignment($quad); - $quad->addAttribute('sizen', $width . ' ' . $line_height); - $quad->addAttribute('style', 'Bgs1InRace'); - $quad->addAttribute('substyle', 'BgTitleGlow'); - - // Rank - $label = $recordFrame->addChild('label'); - Tools::addAlignment($label, 'left'); - $label->addAttribute('posn', ($width * -0.47) . ' 0'); - $label->addAttribute('sizen', ($width * 0.06) . ' ' . $line_height); - $label->addAttribute('textsize', '1'); - $label->addAttribute('textprefix', '$o'); - $label->addAttribute('text', $record['rank']); - - // Name - $label = $recordFrame->addChild('label'); - Tools::addAlignment($label, 'left'); - $label->addAttribute('posn', ($width * -0.4) . ' 0'); - $label->addAttribute('sizen', ($width * 0.6) . ' ' . $line_height); - $label->addAttribute('textsize', '1'); - $label->addAttribute('text', $record['NickName']); - - // Time - $label = $recordFrame->addChild('label'); - Tools::addAlignment($label, 'right'); - $label->addAttribute('posn', ($width * 0.47) . ' 0'); - $label->addAttribute('sizen', ($width * 0.25) . ' ' . $line_height); - $label->addAttribute('textsize', '1'); - $label->addAttribute('text', Tools::formatTime($record['time'])); - - $index++; - } - - return $xml; - } - - /** - * Update dedimania records manialink - */ - private function buildDedimaniaManialink() { - if (!isset($this->dedimaniaData['records'])) { - return; - } - $records = $this->dedimaniaData['records']['Records']; - - $pos_x = (float) $this->config->dedimania_records->widget->pos_x; - $pos_y = (float) $this->config->dedimania_records->widget->pos_y; - $title = (string) $this->config->dedimania_records->widget->title; - $width = (float) $this->config->dedimania_records->widget->width; - $lines = (int) $this->config->dedimania_records->widget->lines; - $line_height = (float) $this->config->dedimania_records->widget->line_height; - - $xml = Tools::newManialinkXml(self::MLID_DEDI); - - $frame = $xml->addChild('frame'); - $frame->addAttribute('posn', $pos_x . ' ' . $pos_y); - - // Background - $quad = $frame->addChild('quad'); - Tools::addAlignment($quad, 'center', 'top'); - $quad->addAttribute('sizen', ($width * 1.05) . ' ' . (7. + $lines * $line_height)); - $quad->addAttribute('style', 'Bgs1InRace'); - $quad->addAttribute('substyle', 'BgTitleShadow'); - - // Title - $label = $frame->addChild('label'); - Tools::addAlignment($label); - Tools::addTranslate($xml); - $label->addAttribute('posn', '0 ' . ($line_height * -0.9)); - $label->addAttribute('sizen', $width . ' 0'); - $label->addAttribute('style', 'TextTitle1'); - $label->addAttribute('textsize', '2'); - $label->addAttribute('text', $title); - - // Times - foreach ($records as $index => $record) { - $y = -8. - $index * $line_height; - - $recordFrame = $frame->addChild('frame'); - $recordFrame->addAttribute('posn', '0 ' . $y); - - // Background - $quad = $recordFrame->addChild('quad'); - Tools::addAlignment($quad); - $quad->addAttribute('sizen', $width . ' ' . $line_height); - $quad->addAttribute('style', 'Bgs1InRace'); - $quad->addAttribute('substyle', 'BgTitleGlow'); - - // Rank - $label = $recordFrame->addChild('label'); - Tools::addAlignment($label, 'left'); - $label->addAttribute('posn', ($width * -0.47) . ' 0'); - $label->addAttribute('sizen', ($width * 0.06) . ' ' . $line_height); - $label->addAttribute('textsize', '1'); - $label->addAttribute('textprefix', '$o'); - $label->addAttribute('text', $record['Rank']); - - // Name - $label = $recordFrame->addChild('label'); - Tools::addAlignment($label, 'left'); - $label->addAttribute('posn', ($width * -0.4) . ' 0'); - $label->addAttribute('sizen', ($width * 0.6) . ' ' . $line_height); - $label->addAttribute('textsize', '1'); - $label->addAttribute('text', $record['NickName']); - - // Time - $label = $recordFrame->addChild('label'); - Tools::addAlignment($label, 'right'); - $label->addAttribute('posn', ($width * 0.47) . ' 0'); - $label->addAttribute('sizen', ($width * 0.25) . ' ' . $line_height); - $label->addAttribute('textsize', '1'); - $label->addAttribute('text', Tools::formatTime($record['Best'])); - - if ($index >= $lines - 1) break; - } - - return $xml; - } - - /** - * Fetch local records for the given map - * - * @param string $mapUId - * @param int $limit - * @return array - */ - private function getLocalRecords($mapUId, $limit = -1) { - $query = "SELECT * FROM ( - SELECT recs.*, @rank := @rank + 1 as `rank` FROM `" . self::TABLE_RECORDS . "` recs, (SELECT @rank := 0) ra - WHERE recs.`mapUId` = '" . $this->iControl->database->escape($mapUId) . "' - ORDER BY recs.`time` ASC - " . ($limit > 0 ? "LIMIT " . $limit : "") . ") records - LEFT JOIN `" . Database::TABLE_PLAYERS . "` players - ON records.`Login` = players.`Login`;"; - return $this->iControl->database->query($query); - } - - /** - * Retrieve the local record for the given map and login - * - * @param string $mapUId - * @param string $login - * @return array - */ - private function getLocalRecord($mapUId, $login) { - if (!$mapUId || !$login) return null; - $database = $this->iControl->database; - $query = "SELECT records.* FROM ( - SELECT recs.*, @rank := @rank + 1 as `rank` FROM `" . self::TABLE_RECORDS . "` `recs`, (SELECT @rank := 0) r - WHERE recs.`mapUid` = '" . $database->escape($mapUId) . "' - ORDER BY recs.`time` ASC) `records` - WHERE records.`Login` = '" . $database->escape($login) . "';"; - $result = $database->query($query); - if (!$result || !is_object($result)) { - trigger_error("Couldn't retrieve player record for '" . $login . "'." . $database->mysqli->error); - return null; - } - while ($record = $result->fetch_assoc()) { - return $record; - } - return null; - } - - /** - * Encodes the given xml rpc method and params - * - * @param string $method - * @param array $params - * @return string - */ - private function encode_request($method, $params) { - $paramArray = array(array('methodName' => $method, 'params' => $params), - array('methodName' => self::DEDIMANIA_WARNINGSANDTTR2, 'params' => array())); - return xmlrpc_encode_request(self::XMLRPC_MULTICALL, array($paramArray), array('encoding' => 'UTF-8', 'escaping' => 'markup')); - } - - /** - * Decodes xml rpc response - * - * @param string $response - * @return mixed - */ - private function decode($response) { - return xmlrpc_decode($response, 'utf-8'); - } - - /** - * Handles xml rpc fault - * - * @param struct $fault - */ - private function handleXmlRpcFault($fault) { - trigger_error('XmlRpc Fault: ' . $fault['faultString'] . ' (' . $fault['faultCode'] . ')'); - } -} - -?> diff --git a/application/plugins/united.plugin.php b/application/plugins/united.plugin.php deleted file mode 100644 index f4cdb774..00000000 --- a/application/plugins/united.plugin.php +++ /dev/null @@ -1,677 +0,0 @@ -mControl = $mControl; - - // Load config - $this->config = Tools::loadConfig('united.plugin.xml'); - $this->loadSettings(); - - // Check for enabled setting - if (!$this->settings->enabled) return; - - // Load clients - $this->loadClients(); - - // Register for callbacks - $this->iControl->callbacks->registerCallbackHandler(Callbacks::CB_IC_ONINIT, $this, 'handleOnInitCallback'); - $this->iControl->callbacks->registerCallbackHandler(Callbacks::CB_IC_5_SECOND, $this, 'handle5Seconds'); - $this->iControl->callbacks->registerCallbackHandler(Callbacks::CB_MP_PLAYERCONNECT, $this, 'handlePlayerConnect'); - $this->iControl->callbacks->registerCallbackHandler(Callbacks::CB_MP_PLAYERMANIALINKPAGEANSWER, $this, - 'handleManialinkPageAnswer'); - - // Register for commands - $this->iControl->commands->registerCommandHandler('nextserver', $this, 'handleNextServerCommand'); - - if ($this->settings->widgets_enabled) { - // Build addfavorite manialink - $this->buildFavoriteManialink(); - } - - error_log('United Pugin v' . self::VERSION . ' ready!'); - } - - /** - * Handle ManiaControl OnInit callback - * - * @param array $callback - */ - public function handleOnInitCallback($callback) { - if ($this->settings->widgets_enabled) { - // Send widgets to all players - - if (Tools::toBool($this->config->widgets->addfavorite->enabled)) { - // Send favorite widget - if (!$this->iControl->client->query('SendDisplayManialinkPage', $this->manialinks[self::ML_ADDFAVORITE]->asXml(), 0, - false)) { - trigger_error("Couldn't send favorite widget! " . $this->iControl->getClientErrorText()); - } - } - } - } - - /** - * Load settings from config - */ - private function loadSettings() { - $this->settings = new \stdClass(); - - // Enabled - $this->settings->enabled = Tools::toBool($this->config->enabled); - - // Timeout - $timeout = $this->iControl->server->config->xpath('timeout'); - if ($timeout) { - $this->settings->timeout = (int) $timeout[0]; - } - else { - $this->settings->timeout = 30; - } - - // Game mode - $mode = $this->config->xpath('mode'); - if ($mode) { - $mode = (int) $mode[0]; - if ($mode < 1 || $mode > 6) { - $this->settings->gamemode = 2; - } - else { - $this->settings->gamemode = $mode; - } - } - - // Server status - $hide_game_server = $this->config->xpath('hide_game_server'); - if ($hide_game_server) { - $this->settings->hide_game_server = Tools::toBool($hide_game_server[0]); - } - else { - $this->settings->hide_game_server = true; - } - - // Passwords - $lobbyPassword = $this->config->xpath('lobbies/password'); - if ($lobbyPassword) { - $this->settings->lobbyPassword = (string) $lobbyPassword[0]; - } - else { - $this->settings->lobbyPassword = ''; - } - $gamePassword = $this->config->xpath('gameserver/password'); - if ($gamePassword) { - $this->settings->gamePassword = (string) $gamePassword[0]; - } - else { - $this->settings->gamePassword = ''; - } - - // Widgets - $this->settings->widgets_enabled = Tools::toBool($this->config->widgets->enabled); - } - - /** - * Loop events on clients - */ - public function loop() { - if (!$this->settings->enabled) return; - - // Check callbacks all clients - $clients = array_merge($this->gameServer, $this->lobbies); - $currentServer = $this->gameServer[$this->currentClientIndex]; - foreach ($clients as $index => $client) { - $client->resetError(); - $client->readCB(); - $callbacks = $client->getCBResponses(); - if (!is_array($callbacks) || $client->isError()) { - trigger_error("Error reading server callbacks! " . $this->iControl->getClientErrorText($client)); - } - else { - if ($client == $currentServer) { - // Currently active game server - foreach ($callbacks as $index => $callback) { - $callbackName = $callback[0]; - switch ($callbackName) { - case Callbacks::CB_MP_ENDMAP: - { - $this->switchToNextServer(false); - break; - } - } - } - - if ($this->lastStatusCheck + 2 > time()) continue; - $this->lastStatusCheck = time(); - - if (!$client->query('CheckEndMatchCondition')) { - trigger_error("Couldn't get game server status. " . $this->iControl->getClientErrorText($client)); - } - else { - $response = $client->getResponse(); - switch ($response) { - case 'Finished': - { - if ($this->finishedBegin < 0) { - $this->finishedBegin = time(); - } - else if ($this->finishedBegin + 13 <= time()) { - $this->switchToNextServer(true); - } - break; - } - default: - { - $this->finishedBegin = -1; - break; - } - } - } - } - else { - // Lobby or inactive game server -> Redirect players - foreach ($callbacks as $callback) { - switch ($callback[0]) { - case Callbacks::CB_MP_PLAYERCONNECT: - { - $this->playerJoinedLobby($client, $callback); - break; - } - } - } - } - } - } - - // Check for switch server request - if ($this->switchServerRequested > 0 && $this->switchServerRequested <= time()) { - $this->switchServerRequested = -1; - - // Switch server - $this->switchToNextServer(true); - } - } - - /** - * Handle 5 seconds callback - */ - public function handle5Seconds($callback = null) { - // Update lobby infos - $players = $this->iControl->server->getPlayers(); - if (is_array($players)) { - $playerCount = count($players); - $playerLevel = 0.; - if ($playerCount > 0) { - foreach ($players as $player) { - $playerLevel += $player['LadderRanking']; - } - $playerLevel /= $playerCount; - } - foreach ($this->lobbies as $lobby) { - if (!$lobby->query('SetLobbyInfo', true, $playerCount, 255, $playerLevel)) { - trigger_error("Couldn't update lobby info. " . $this->iControl->getClientErrorText($lobby)); - } - } - } - - // Check for not-redirected players - $clients = array_merge($this->gameServer, $this->lobbies); - $joinLink = $this->getJoinLink(); - foreach ($clients as $client) { - if ($client == $this->gameServer[$this->currentClientIndex]) continue; - $players = $this->iControl->server->getPlayers($client); - if (!is_array($players)) continue; - foreach ($players as $player) { - $login = $player['Login']; - if (!$client->query('SendOpenLinkToLogin', $login, $joinLink, 1)) { - trigger_error( - "Couldn't redirect player '" . $login . "' to active game server. " . - $this->iControl->getClientErrorText($client)); - } - } - } - } - - /** - * Handle player manialink page answer callback - */ - public function handleManialinkPageAnswer($callback) { - $login = $callback[1][1]; - $action = $callback[1][2]; - switch ($action) { - case self::ML_ADDFAVORITE: - { - // Open manialink to add server logins to favorite - $serverLogins = array(); - $add_all = Tools::toBool($this->config->widgets->addfavorite->add_all); - if ($add_all) { - // Add all server - foreach ($this->gameServer as $serverClient) { - array_push($serverLogins, $this->iControl->server->getLogin($serverClient)); - } - foreach ($this->lobbies as $serverClient) { - array_push($serverLogins, $this->iControl->server->getLogin($serverClient)); - } - } - else { - // Add only current server - array_push($serverLogins, $this->iControl->server->getLogin()); - } - - // Build manialink url - $manialink = 'iControl?favorite'; - foreach ($serverLogins as $serverLogin) { - $manialink .= '&' . $serverLogin; - } - - // Send url to player - if (!$this->iControl->client->query('SendOpenLinkToLogin', $login, $manialink, 1)) { - trigger_error( - "Couldn't open manialink to add server to favorite for '" . $login . "'! " . - $this->iControl->getClientErrorText()); - } - break; - } - } - } - - /** - * Switch to the next server - * - * @param bool $simulateMapEnd - * Simulate end of the map by sending callbacks - */ - private function switchToNextServer($simulateMapEnd) { - $this->finishedBegin = -1; - $oldClient = $this->gameServer[$this->currentClientIndex]; - - $random_order = Tools::toBool($this->config->random_order); - if ($random_order) { - // Random next server - $this->currentClientIndex = rand(0, count($this->gameServer) - 1); - } - else { - // Next server in list - $this->currentClientIndex++; - } - if ($this->currentClientIndex >= count($this->gameServer)) $this->currentClientIndex = 0; - - $newClient = $this->gameServer[$this->currentClientIndex]; - if ($newClient == $oldClient) return; - - // Restart map on next game server - if (!$newClient->query('RestartMap')) { - trigger_error("Couldn't restart map on next game server. " . $this->iControl->getClientErrorText($newClient)); - } - - if ($simulateMapEnd) { - // Simulate EndMap on old client - $this->iControl->callbacks->triggerCallback(Callbacks::CB_IC_ENDMAP, array(Callbacks::CB_IC_ENDMAP)); - } - - // Transfer players to next server - $joinLink = $this->getJoinLink($newClient); - if (!$oldClient->query('GetPlayerList', 255, 0)) { - trigger_error("Couldn't get player list. " . $this->iControl->getClientErrorText($oldClient)); - } - else { - $playerList = $oldClient->getResponse(); - foreach ($playerList as $player) { - $login = $player['Login']; - if (!$oldClient->query('SendOpenLinkToLogin', $login, $joinLink, 1)) { - trigger_error("Couldn't redirect player to next game server. " . $this->iControl->getClientErrorText($oldClient)); - } - } - - $this->iControl->client = $newClient; - } - - // Trigger client updated callback - $this->iControl->callbacks->triggerCallback(Callbacks::CB_IC_CLIENTUPDATED, "Plugin_United.SwitchedServer"); - - if ($simulateMapEnd) { - // Simulate BeginMap on new client - $map = $this->iControl->server->getMap(); - if ($map) { - $this->iControl->callbacks->triggerCallback(Callbacks::CB_IC_BEGINMAP, array(Callbacks::CB_IC_BEGINMAP, array($map))); - } - } - } - - /** - * Handle nextserver command - * - * @param mixed $command - */ - public function handleNextServerCommand($command) { - if (!$command) return; - $login = $command[1][1]; - - if (!$this->iControl->authentication->checkRight($login, 'operator')) { - // Not allowed - $this->iControl->authentication->sendNotAllowed($login); - return; - } - - // Request skip to next server - $this->switchServerRequested = time() + 3; - - // Send chat message - $this->iControl->chat->sendInformation("Switching to next server in 3 seconds..."); - } - - /** - * Handle PlayerConnect callback - */ - public function playerJoinedLobby($client, $callback) { - if (!$client) return; - - $data = $callback[1]; - $login = $data[0]; - - // Redirect player to current game server - $gameserver = $this->gameServer[$this->currentClientIndex]; - $joinLink = $this->getJoinLink($gameserver, !$data[1]); - if (!$client->query('SendOpenLinkToLogin', $login, $joinLink, 1)) { - trigger_error( - "United Plugin: Couldn't redirect player to current game server. " . $this->iControl->getClientErrorText($client)); - } - } - - /** - * Connect to the game server defined in the config - */ - private function loadClients() { - $gameserver = $this->config->xpath('gameserver/server'); - $lobbies = $this->config->xpath('lobbies/server'); - - $clientsConfig = array_merge($gameserver, $lobbies); - foreach ($clientsConfig as $index => $serv) { - $isGameServer = (in_array($serv, $gameserver)); - - $host = $serv->xpath('host'); - $port = $serv->xpath('port'); - if (!$host || !$port) { - trigger_error("Invalid configuration!", E_USER_ERROR); - } - $host = (string) $host[0]; - $port = (string) $port[0]; - - error_log("Connecting to united " . ($isGameServer ? 'game' : 'lobby') . " server at " . $host . ":" . $port . "..."); - $client = new \IXR_ClientMulticall_Gbx(); - - // Connect - if (!$client->InitWithIp($host, $port, $this->settings->timeout)) { - trigger_error( - "Couldn't connect to united " . ($isGameServer ? 'game' : lobby) . " server! " . $client->getErrorMessage() . - "(" . $client->getErrorCode() . ")", E_USER_ERROR); - } - - $login = $serv->xpath('login'); - $pass = $serv->xpath('pass'); - if (!$login || !$pass) { - trigger_error("Invalid configuration!", E_USER_ERROR); - } - $login = (string) $login[0]; - $pass = (string) $pass[0]; - - // Authenticate - if (!$client->query('Authenticate', $login, $pass)) { - trigger_error( - "Couldn't authenticate on united " . ($isGameServer ? 'game' : 'lobby') . " server with user '" . $login . "'! " . - $client->getErrorMessage() . "(" . $client->getErrorCode() . ")", E_USER_ERROR); - } - - // Enable callback system - if (!$client->query('EnableCallbacks', true)) { - trigger_error("Couldn't enable callbacks! " . $client->getErrorMessage() . "(" . $client->getErrorCode() . ")", - E_USER_ERROR); - } - - // Wait for server to be ready - if (!$this->iControl->server->waitForStatus($client, 4)) { - trigger_error("Server couldn't get ready!", E_USER_ERROR); - } - - // Set api version - if (!$client->query('SetApiVersion', ManiaControl::API_VERSION)) { - trigger_error( - "Couldn't set API version '" . ManiaControl::API_VERSION . "'! This might cause problems. " . - $this->iControl->getClientErrorText($client)); - } - - // Set server settings - $password = ($isGameServer ? $this->settings->gamePassword : $this->settings->lobbyPassword); - $hideServer = ($isGameServer && $this->settings->hide_game_server ? 1 : 0); - // Passwords - if (!$client->query('SetServerPassword', $password)) { - trigger_error("Couldn't set server join password. " . $this->iControl->getClientErrorText($client)); - } - if (!$client->query('SetServerPasswordForSpectator', $password)) { - trigger_error("Couldn't set server spec password. " . $this->iControl->getClientErrorText($client)); - } - // Show/Hide server - if (!$client->query('SetHideServer', $hideServer)) { - trigger_error( - "Couldn't set server '" . ($hideServer == 0 ? 'shown' : 'hidden') . "'. " . - $this->iControl->getClientErrorText($client)); - } - - // Enable service announces - if (!$client->query("DisableServiceAnnounces", false)) { - trigger_error("Couldn't enable service announces. " . $this->iControl->getClientErrorText($client)); - } - - // Set game mode - if (!$client->query('SetGameMode', $this->settings->gamemode)) { - trigger_error( - "Couldn't set game mode (" . $this->settings->gamemode . "). " . $this->iControl->getClientErrorText($client)); - } - else if (!$client->query('RestartMap')) { - trigger_error("Couldn't restart map to change game mode. " . $this->iControl->getClientErrorText($client)); - } - - // Save client - $client->index = $index; - if ($isGameServer) { - array_push($this->gameServer, $client); - if (count($this->gameServer) === 1) { - $this->iControl->client = $client; - } - } - else { - array_push($this->lobbies, $client); - } - } - - error_log("United Plugin: Connected to all game and lobby server!"); - } - - /** - * Handle PlayerConnect callback - * - * @param array $callback - */ - public function handlePlayerConnect($callback) { - if ($this->settings->widgets_enabled) { - // Send manialinks to the client - $login = $callback[1][0]; - - if (Tools::toBool($this->config->widgets->addfavorite->enabled)) { - // Send favorite widget - if (!$this->iControl->client->query('SendDisplayManialinkPageToLogin', $login, - $this->manialinks[self::ML_ADDFAVORITE]->asXml(), 0, false)) { - trigger_error("Couldn't send favorite widget to player '" . $login . "'! " . $this->iControl->getClientErrorText()); - } - } - } - } - - /** - * Build join link for the given client - */ - private function getJoinLink(&$client = null, $play = true) { - if (!$client) { - $client = $this->gameServer[$this->currentClientIndex]; - } - if (!$client->query('GetSystemInfo')) { - trigger_error("Couldn't fetch server system info. " . $this->iControl->getClientErrorText($client)); - return null; - } - else { - $systemInfo = $client->getResponse(); - $password = ''; - if (!$client->query('GetServerPassword')) { - trigger_error("Couldn't get server password. " . $this->iControl->getClientErrorText($client)); - } - else { - $password = $client->getResponse(); - } - return '#q' . ($play ? 'join' : 'spectate') . '=' . $systemInfo['ServerLogin'] . - (strlen($password) > 0 ? ':' . $password : '') . '@' . $systemInfo['TitleId']; - } - } - - /** - * Build manialink for addfavorite button - */ - private function buildFavoriteManialink() { - // Load configs - $config = $this->config->widgets->addfavorite; - if (!Tools::toBool($config->enabled)) return; - - $pos_x = (float) $config->pos_x; - $pos_y = (float) $config->pos_y; - $height = (float) $config->height; - $width = (float) $config->width; - $add_all = Tools::toBool($config->add_all); - - // Build manialink - $xml = Tools::newManialinkXml(self::ML_ADDFAVORITE); - - $frameXml = $xml->addChild('frame'); - $frameXml->addAttribute('posn', $pos_x . ' ' . $pos_y); - - // Background - $quadXml = $frameXml->addChild('quad'); - Tools::addAlignment($quadXml); - $quadXml->addAttribute('posn', '0 0 0'); - $quadXml->addAttribute('sizen', $width . ' ' . $height); - $quadXml->addAttribute('style', 'Bgs1InRace'); - $quadXml->addAttribute('substyle', 'BgTitleShadow'); - $quadXml->addAttribute('action', self::ML_ADDFAVORITE); - - // Heart - $quadXml = $frameXml->addChild('quad'); - Tools::addAlignment($quadXml); - $quadXml->addAttribute('id', 'Quad_AddFavorite'); - $quadXml->addAttribute('posn', '0 0 1'); - $quadXml->addAttribute('sizen', ($width - 1.) . ' ' . ($height - 0.8)); - $quadXml->addAttribute('style', 'Icons64x64_1'); - $quadXml->addAttribute('substyle', 'StateFavourite'); - $quadXml->addAttribute('scriptevents', '1'); - - // Tooltip - $tooltipFrameXml = $frameXml->addChild('frame'); - $tooltipFrameXml->addAttribute('id', 'Frame_FavoriteTooltip'); - $tooltipFrameXml->addAttribute('posn', '0 ' . ($pos_y >= 0 ? '-' : '') . '13'); - $tooltipFrameXml->addAttribute('hidden', '1'); - - $quadXml = $tooltipFrameXml->addChild('quad'); - Tools::addAlignment($quadXml); - $quadXml->addAttribute('posn', '0 0 2'); - $quadXml->addAttribute('sizen', '28 16'); - $quadXml->addAttribute('style', 'Bgs1InRace'); - $quadXml->addAttribute('substyle', 'BgTitleShadow'); - - $labelXml = $tooltipFrameXml->addChild('label'); - Tools::addAlignment($labelXml); - Tools::addTranslate($labelXml); - $labelXml->addAttribute('posn', '0 0 3'); - $labelXml->addAttribute('sizen', '26 0'); - $labelXml->addAttribute('style', 'TextTitle1'); - $labelXml->addAttribute('textsize', '2'); - $labelXml->addAttribute('autonewline', '1'); - $countText = ''; - if ($add_all) { - $count = count($this->gameServer) + count($this->lobbies); - $countText = 'all ' . $count . ' '; - } - $labelXml->addAttribute('text', 'Add ' . $countText . 'server to Favorite!'); - - // Script for tooltip - $script = ' -declare Frame_FavoriteTooltip <=> (Page.GetFirstChild("Frame_FavoriteTooltip") as CMlFrame); -while (True) { - yield; - foreach (Event in PendingEvents) { - switch (Event.Type) { - case CMlEvent::Type::MouseOver: { - switch (Event.ControlId) { - case "Quad_AddFavorite": { - Frame_FavoriteTooltip.Visible = True; - } - } - } - case CMlEvent::Type::MouseOut: { - switch (Event.ControlId) { - case "Quad_AddFavorite": { - Frame_FavoriteTooltip.Visible = False; - } - } - } - } - } -}'; - $xml->addChild('script', $script); - - $this->manialinks[self::ML_ADDFAVORITE] = $xml; - } -} - -?> - \ No newline at end of file