errorHandler = new ErrorHandler($this); $this->log('Loading ManiaControl v' . self::VERSION . '...'); $this->loadConfig(); // Load ManiaControl Modules $this->callbackManager = new CallbackManager($this); $this->timerManager = new TimerManager($this); $this->database = new Database($this); $this->fileReader = new AsynchronousFileReader($this); $this->billManager = new BillManager($this); $this->settingManager = new SettingManager($this); $this->statisticManager = new StatisticManager($this); $this->manialinkManager = new ManialinkManager($this); $this->actionsMenu = new ActionsMenu($this); $this->chat = new Chat($this); $this->commandManager = new CommandManager($this); $this->server = new Server($this); $this->authenticationManager = new AuthenticationManager($this); $this->playerManager = new PlayerManager($this); $this->mapManager = new MapManager($this); $this->configurator = new Configurator($this); $this->pluginManager = new PluginManager($this); $this->updateManager = new UpdateManager($this); // Define Permission Levels $this->authenticationManager->definePermissionLevel(self::SETTING_PERMISSION_SHUTDOWN, AuthenticationManager::AUTH_LEVEL_SUPERADMIN); $this->authenticationManager->definePermissionLevel(self::SETTING_PERMISSION_RESTART, AuthenticationManager::AUTH_LEVEL_SUPERADMIN); // Register for commands $this->commandManager->registerCommandListener('version', $this, 'command_Version', false, 'Shows ManiaControl version.'); $this->commandManager->registerCommandListener('restart', $this, 'command_Restart', true, 'Restarts ManiaControl.'); $this->commandManager->registerCommandListener('shutdown', $this, 'command_Shutdown', true, 'Shuts ManiaControl down.'); // Check connection every 30 seconds $this->timerManager->registerTimerListening($this, 'checkConnection', 1000 * 30); $this->errorHandler->init(); } /** * Load the Config XML-File */ private function loadConfig() { $configId = CommandLineHelper::getParameter('-config'); $configFileName = ($configId ? $configId : 'server.xml'); $this->config = FileUtil::loadConfig($configFileName); if (!$this->config) { trigger_error("Error loading Configuration XML-File! ('{$configFileName}')", E_USER_ERROR); } if (!$this->config->server->port || $this->config->server->port == 'port') { trigger_error("Your Configuration File ('{$configFileName}') doesn't seem to be maintained. Please check it again!", E_USER_ERROR); } } /** * Checks connection every xxx Minutes * * @param $time */ public function checkConnection($time) { if ($this->client->getIdleTime() > 180) { $this->client->getServerName(); } } /** * Print a message to console and log * * @param string $message */ public function log($message, $stripCodes = false) { if ($stripCodes) { $message = Formatter::stripCodes($message); } logMessage($message); } /** * Get the Operating System on which ManiaControl is running * * @param string $compareOS * @return string */ public function getOS($compareOS = null) { $windows = defined('PHP_WINDOWS_VERSION_MAJOR'); if ($compareOS) { // Return bool whether OS equals $compareOS if ($compareOS == self::OS_WIN) { return $windows; } return !$windows; } // Return OS if ($windows) { return self::OS_WIN; } return self::OS_UNIX; } /** * Handle Version Command * * @param array $chatCallback * @param Player $player */ public function command_Version(array $chatCallback, Player $player) { $message = 'This server is using ManiaControl v' . ManiaControl::VERSION . '!'; $this->chat->sendInformation($message, $player->login); } /** * Handle Restart AdminCommand * * @param array $chatCallback * @param Player $player */ public function command_Restart(array $chatCallback, Player $player) { if (!$this->authenticationManager->checkPermission($player, self::SETTING_PERMISSION_RESTART)) { $this->authenticationManager->sendNotAllowed($player); return; } $this->restart("ManiaControl Restart requested by '{$player->login}'!"); } /** * Handle //shutdown command * * @param array $chat * @param Player $player */ public function command_Shutdown(array $chat, Player $player) { if (!$this->authenticationManager->checkPermission($player, self::SETTING_PERMISSION_SHUTDOWN)) { $this->authenticationManager->sendNotAllowed($player); return; } $this->quit("ManiaControl Shutdown requested by '{$player->login}'!"); } /** * Quit ManiaControl and log the given message * * @param string $message */ public function quit($message = null) { if ($message) { $this->log($message); } exit(); } /** * Handle PHP Process Shutdown */ public function handleShutdown() { // OnShutdown callback $this->callbackManager->triggerCallback(CallbackManager::CB_ONSHUTDOWN); // Announce quit $this->chat->sendInformation('ManiaControl shutting down.'); if ($this->client) { try { // Hide manialinks $this->client->sendHideManialinkPage(); // Close the client connection $this->client->delete($this->server->ip, $this->server->port); } catch (TransportException $e) { $this->errorHandler->triggerDebugNotice($e->getMessage() . " File: " . $e->getFile() . " Line: " . $e->getLine()); } } // Check and Trigger Fatal Errors $error = error_get_last(); if ($error && ($error['type'] & E_FATAL)) { $this->errorHandler->errorHandler($error['type'], $error['message'], $error['file'], $error['line']); } // Disable Garbage Collector $this->collectGarbage(); gc_disable(); $this->log('Quitting ManiaControl!'); exit(); } /** * Restart ManiaControl * * @param string $message */ public function restart($message = null) { // Shutdown callback $this->callbackManager->triggerCallback(CallbackManager::CB_ONSHUTDOWN); // Announce restart $this->chat->sendInformation('Restarting ManiaControl...'); if ($message) { $this->log($message); } // Hide widgets $this->client->sendHideManialinkPage(); $this->log('Restarting ManiaControl!'); // Execute start script in background // TODO: restart the .php script itself ($_SERVER['scriptname'] or something + $argv) if ($this->getOS(self::OS_UNIX)) { $command = 'sh ' . escapeshellarg(ManiaControlDir . '/ManiaControl.sh') . ' > /dev/null &'; exec($command); } else { $command = escapeshellarg(ManiaControlDir . "\ManiaControl.bat"); system($command); // TODO, windows stucks here as long controller is running } exit(); } /** * Run ManiaControl */ public function run() { $this->log('Starting ManiaControl v' . self::VERSION . '!'); // Register shutdown handler register_shutdown_function(array($this, 'handleShutdown')); // Connect to server $this->connect(); // Check if the version of the server is high enough $version = $this->client->getVersion(); if ($version->build < self::MIN_DEDIVERSION) { trigger_error("The server has version " . $version->build . ", while at least " . self::MIN_DEDIVERSION . " is required!", E_USER_ERROR); } // OnInit callback $this->callbackManager->triggerCallback(CallbackManager::CB_ONINIT); // Load plugins $this->pluginManager->loadPlugins(); $this->updateManager->checkPluginsUpdate(); // AfterInit callback $this->callbackManager->triggerCallback(CallbackManager::CB_AFTERINIT); // Enable Garbage Collecting gc_enable(); $this->timerManager->registerTimerListening($this, 'collectGarbage', 1000 * 60); // Announce ManiaControl $this->chat->sendInformation('ManiaControl v' . self::VERSION . ' successfully started!'); // Loading finished $this->log('Loading completed!'); $this->log('Link: maniaplanet://#join=' . $this->server->login . '@' . $this->server->titleId); // Main loop while (!$this->shutdownRequested) { $loopStart = microtime(true); // Disable script timeout set_time_limit(self::SCRIPT_TIMEOUT); try { // Manager callbacks $this->callbackManager->manageCallbacks(); } catch (TransportException $e) { $this->log("Connection interrupted!"); // TODO remove if ($this->errorHandler) { $this->errorHandler->exceptionHandler($e, false); } $this->quit($e->getMessage()); } // Manage FileReader $this->fileReader->appendData(); // Yield for next tick $loopEnd = microtime(true); $sleepTime = (int) (2000 - ($loopEnd - $loopStart) * 1000000); if ($sleepTime > 0) { usleep($sleepTime); } } // Shutdown $this->quit(); } /** * Collect Garbage */ public function collectGarbage() { gc_collect_cycles(); } /** * Connect to ManiaPlanet server */ private function connect() { // Load remote client $this->server->loadConfig(); $this->log("Connecting to server at {$this->server->config->host}:{$this->server->config->port}..."); try { $this->client = Connection::factory($this->server->config->host, $this->server->config->port, self::CONNECT_TIMEOUT, $this->server->config->login, $this->server->config->pass); } catch (Exception $e) { trigger_error("Couldn't authenticate on server with user '{$this->server->config->login}'! " . $e->getMessage(), E_USER_ERROR); } // Enable callback system $this->client->enableCallbacks(true); // Wait for server to be ready try { if (!$this->server->waitForStatus(4)) { trigger_error("Server couldn't get ready!", E_USER_ERROR); } } catch (Exception $e) { // TODO remove if ($this->errorHandler) { $this->errorHandler->triggerDebugNotice("Fatal Exception: " . $e->getMessage() . " Trace: " . $e->getTraceAsString()); } $this->quit($e->getMessage()); } // Connect finished $this->log("Server Connection successfully established!"); // Hide old widgets $this->client->sendHideManialinkPage(); // Enable script callbacks if needed if ($this->server->getGameMode() != 0) { return; } try { $scriptSettings = $this->client->getModeScriptSettings(); } catch (NotInScriptModeException $e) { return; } if (!array_key_exists('S_UseScriptCallbacks', $scriptSettings)) { return; } $scriptSettings['S_UseScriptCallbacks'] = true; try { $this->client->setModeScriptSettings($scriptSettings); } catch (Exception $e) { // TODO temp added 19.04.2014 $this->errorHandler->triggerDebugNotice("Exception line 437 ManiaControl.php " . $e->getMessage()); trigger_error("Couldn't set mode script settings to enable script callbacks. " . $e->getMessage()); return; } $this->log('Script Callbacks successfully enabled!'); } }