diff --git a/application/core/Plugins/PluginManager.php b/application/core/Plugins/PluginManager.php index d12d37be..b45ec937 100644 --- a/application/core/Plugins/PluginManager.php +++ b/application/core/Plugins/PluginManager.php @@ -154,7 +154,7 @@ class PluginManager { } /** - * Check if the plugin is running + * Check if the Plugin is currently running * * @param string $pluginClass * @return bool @@ -165,7 +165,7 @@ class PluginManager { } /** - * Save plugin status in database + * Save Plugin Status in Database * * @param string $className * @param bool $active @@ -203,7 +203,7 @@ class PluginManager { * @return array */ public function loadPlugins() { - $pluginsDirectory = ManiaControlDir . 'plugins'. DIRECTORY_SEPARATOR; + $pluginsDirectory = ManiaControlDir . 'plugins' . DIRECTORY_SEPARATOR; $classesBefore = get_declared_classes(); $this->loadPluginFiles($pluginsDirectory); diff --git a/application/plugins/ChatMessagePlugin.php b/application/plugins/ChatMessagePlugin.php index 99f084f5..e69de29b 100644 --- a/application/plugins/ChatMessagePlugin.php +++ b/application/plugins/ChatMessagePlugin.php @@ -1,452 +0,0 @@ - - * @copyright 2014 ManiaControl Team - * @license http://www.gnu.org/licenses/ GNU General Public License, Version 3 - */ -class ChatMessagePlugin implements CommandListener, Plugin { - /** - * Constants - */ - const PLUGIN_ID = 4; - const PLUGIN_VERSION = 0.1; - const PLUGIN_NAME = 'ChatMessagePlugin'; - const PLUGIN_AUTHOR = 'kremsy'; - const SETTING_AFK_FORCE_SPEC = 'AFK command forces spec'; - - /** - * Private properties - */ - /** - * @var maniaControl $maniaControl - */ - private $maniaControl = null; - - /** - * Prepares the Plugin - * - * @param ManiaControl $maniaControl - * @return mixed - */ - public static function prepare(ManiaControl $maniaControl) { - //do nothing - } - - /** - * Get plugin id - * - * @return int - */ - public static function getId() { - return self::PLUGIN_ID; - } - - /** - * Get Plugin Name - * - * @return string - */ - public static function getName() { - return self::PLUGIN_NAME; - } - - /** - * Get Plugin Version - * - * @return float,, - */ - public static function getVersion() { - return self::PLUGIN_VERSION; - } - - /** - * Get Plugin Author - * - * @return string - */ - public static function getAuthor() { - return self::PLUGIN_AUTHOR; - } - - /** - * Get Plugin Description - * - * @return string - */ - public static function getDescription() { - return "Plugin offers various Chat-Commands like /gg /hi /afk /rq..."; - } - - /** - * Load the plugin - * - * @param \ManiaControl\ManiaControl $maniaControl - * @return bool - */ - public function load(ManiaControl $maniaControl) { - $this->maniaControl = $maniaControl; - - $this->maniaControl->commandManager->registerCommandListener('me', $this, 'chat_me', false, 'Can be used to express your feelings/ideas.'); - $this->maniaControl->commandManager->registerCommandListener('hi', $this, 'chat_hi', false, 'Writes an hello message to the chat.'); - $this->maniaControl->commandManager->registerCommandListener(array('bb', 'bye'), $this, 'chat_bye', false, 'Writes a goodbye message to the chat.'); - $this->maniaControl->commandManager->registerCommandListener('thx', $this, 'chat_thx', false, 'Writes a thanks message to the chat.'); - $this->maniaControl->commandManager->registerCommandListener('gg', $this, 'chat_gg', false, 'Writes a good game message to the chat.'); - $this->maniaControl->commandManager->registerCommandListener('gl', $this, 'chat_gl', false, 'Writes a good luck message to the chat.'); - $this->maniaControl->commandManager->registerCommandListener('hf', $this, 'chat_hf', false, 'Writes an have fun message to the chat.'); - $this->maniaControl->commandManager->registerCommandListener('glhf', $this, 'chat_glhf', false, 'Writes a good luck, have fun message to the chat.'); - $this->maniaControl->commandManager->registerCommandListener('ns', $this, 'chat_ns', false, 'Writes a nice shot message to the chat.'); - $this->maniaControl->commandManager->registerCommandListener('n1', $this, 'chat_n1', false, 'Writes a nice one message to the chat.'); - $this->maniaControl->commandManager->registerCommandListener('lol', $this, 'chat_lol', false, 'Writes a lol message to the chat.'); - $this->maniaControl->commandManager->registerCommandListener('lool', $this, 'chat_lool', false, 'Writes a lool message to the chat.'); - $this->maniaControl->commandManager->registerCommandListener('brb', $this, 'chat_brb', false, 'Writes a be right back message to the chat.'); - $this->maniaControl->commandManager->registerCommandListener('bgm', $this, 'chat_bgm', false, 'Writes a bad game for me message to the chat.'); - $this->maniaControl->commandManager->registerCommandListener('afk', $this, 'chat_afk', false, 'Writes an away from keyboard message to the chat.'); - $this->maniaControl->commandManager->registerCommandListener(array('bm', 'bootme'), $this, 'chat_bootme', false, 'Gets you away from this server quickly!'); - $this->maniaControl->commandManager->registerCommandListener(array('rq', 'ragequit'), $this, 'chat_ragequit', false, 'Gets you away from this server in rage!'); - //TODO block commandlistener for muted people - $this->maniaControl->settingManager->initSetting($this, self::SETTING_AFK_FORCE_SPEC, true); - - return true; - } - - /** - * Unload the plugin and its resources - */ - public function unload() { - $this->maniaControl->commandManager->unregisterCommandListener($this); - unset($this->maniaControl); - } - - /** - * Builds a chat message starting with the player's nickname, can used to express emotions - * - * @param array $chat - * @param Player $player - */ - public function chat_me(array $chat, Player $player) { - $message = substr($chat[1][2], 4); - - $msg = '$<' . $player->nickname . '$>$s$i$fa0 ' . $message; - $this->maniaControl->chat->sendChat($msg, null, false); - } - - /** - * Hello Message - * - * @param array $chat - * @param Player $player - */ - public function chat_hi(array $chat, Player $player) { - $command = explode(" ", $chat[1][2]); - - if (isset($command[1])) { - $msg = '$ff0[$<' . $player->nickname . '$>] $ff0$iHello $z$<' . $this->getTarget($command[1]) . '$>$i!'; - } else { - $msg = '$ff0[$<' . $player->nickname . '$>] $ff0$iHello All!'; - } - $this->maniaControl->chat->sendChat($msg, null, false); - } - - /** - * Checks if a Player is in the PlayerList and returns the nickname if he is, can be called per login, pid or nickname or lj for - * (last joined) - * - * @param $login - * @return mixed - */ - private function getTarget($login) { - /** @var Player $player */ - $player = null; - foreach ($this->maniaControl->playerManager->getPlayers() as $player) { - if ($login == $player->login || $login == $player->pid || $login == $player->nickname) { - return $player->nickname; - } - } - - if ($player && $login == 'lj') { - return $player->nickname; - } - - //returns the text given if nothing matches - return $login; - } - - /** - * Bye Message - * - * @param array $chat - * @param Player $player - */ - public function chat_bye(array $chat, Player $player) { - $command = explode(" ", $chat[1][2]); - - if (isset($command[1])) { - $msg = '$ff0[$<' . $player->nickname . '$>] $ff0$iBye $z$<' . $this->getTarget($command[1]) . '$>$i!'; - } else { - $msg = '$ff0[$<' . $player->nickname . '$>] $ff0$iI have to go... Bye All!'; - } - - $this->maniaControl->chat->sendChat($msg, null, false); - } - - /** - * Thx Message - * - * @param array $chat - * @param Player $player - */ - public function chat_thx(array $chat, Player $player) { - $command = explode(" ", $chat[1][2]); - - if (isset($command[1])) { - $msg = '$ff0[$<' . $player->nickname . '$>] $ff0$iThanks $z$<' . $this->getTarget($command[1]) . '$>$i!'; - } else { - $msg = '$ff0[$<' . $player->nickname . '$>] $ff0$iThanks All!'; - } - - $this->maniaControl->chat->sendChat($msg, null, false); - } - - /** - * Good Game Message - * - * @param array $chat - * @param Player $player - */ - public function chat_gg(array $chat, Player $player) { - $command = explode(" ", $chat[1][2]); - - if (isset($command[1])) { - $msg = '$ff0[$<' . $player->nickname . '$>] $ff0$iGood Game $z$<' . $this->getTarget($command[1]) . '$>$i!'; - } else { - $msg = '$ff0[$<' . $player->nickname . '$>] $ff0$iGood Game All!'; - } - - $this->maniaControl->chat->sendChat($msg, null, false); - } - - /** - * Good Luck Message - * - * @param array $chat - * @param Player $player - */ - public function chat_gl(array $chat, Player $player) { - $command = explode(" ", $chat[1][2]); - - if (isset($command[1])) { - $msg = '$ff0[$<' . $player->nickname . '$>] $ff0$iGood Luck $z$<' . $this->getTarget($command[1]) . '$>$i!'; - } else { - $msg = '$ff0[$<' . $player->nickname . '$>] $ff0$iGood Luck All!'; - } - - $this->maniaControl->chat->sendChat($msg, null, false); - } - - /** - * Have Fun Message - * - * @param array $chat - * @param Player $player - */ - public function chat_hf(array $chat, Player $player) { - $command = explode(" ", $chat[1][2]); - - if (isset($command[1])) { - $msg = '$ff0[$<' . $player->nickname . '$>] $ff0$iHave Fun $z$<' . $this->getTarget($command[1]) . '$>$i!'; - } else { - $msg = '$ff0[$<' . $player->nickname . '$>] $ff0$iHave Fun All!'; - } - - $this->maniaControl->chat->sendChat($msg, null, false); - } - - /** - * Good Luck and Have Fun Message - * - * @param array $chat - * @param Player $player - */ - public function chat_glhf(array $chat, Player $player) { - $command = explode(" ", $chat[1][2]); - - if (isset($command[1])) { - $msg = '$ff0[$<' . $player->nickname . '$>] $ff0$iGood Luck and Have Fun $z$<' . $this->getTarget($command[1]) . '$>$i!'; - } else { - $msg = '$ff0[$<' . $player->nickname . '$>] $ff0$iGood Luck and Have Fun All!'; - } - - $this->maniaControl->chat->sendChat($msg, null, false); - } - - /** - * Nice Shot Message - * - * @param array $chat - * @param Player $player - */ - public function chat_ns(array $chat, Player $player) { - $command = explode(" ", $chat[1][2]); - - if (isset($command[1])) { - $msg = '$ff0[$<' . $player->nickname . '$>] $ff0$iNice Shot $z$<' . $this->getTarget($command[1]) . '$>$i!'; - } else { - $msg = '$ff0[$<' . $player->nickname . '$>] $ff0$iNice Shot!'; - } - - $this->maniaControl->chat->sendChat($msg, null, false); - } - - /** - * Nice one Message - * - * @param array $chat - * @param Player $player - */ - public function chat_n1(array $chat, Player $player) { - $command = explode(" ", $chat[1][2]); - - if (isset($command[1])) { - $msg = '$ff0[$<' . $player->nickname . '$>] $ff0$iNice One $z$<' . $this->getTarget($command[1]) . '$>$i!'; - } else { - $msg = '$ff0[$<' . $player->nickname . '$>] $ff0$iNice One!'; - } - - $this->maniaControl->chat->sendChat($msg, null, false); - } - - /** - * Lol! Message - * - * @param array $chat - * @param Player $player - */ - public function chat_lol(array $chat, Player $player) { - $msg = '$ff0[$<' . $player->nickname . '$>] $ff0$iLoL!'; - $this->maniaControl->chat->sendChat($msg, null, false); - } - - /** - * LooOOooL! Message - * - * @param array $chat - * @param Player $player - */ - public function chat_lool(array $chat, Player $player) { - $msg = '$ff0[$<' . $player->nickname . '$>] $ff0$iLooOOooL!'; - $this->maniaControl->chat->sendChat($msg, null, false); - } - - /** - * Be right back Message - * - * @param array $chat - * @param Player $player - */ - public function chat_brb(array $chat, Player $player) { - $msg = '$ff0[$<' . $player->nickname . '$>] $ff0$iBe Right Back!'; - $this->maniaControl->chat->sendChat($msg, null, false); - } - - /** - * Bad game for me Message - * - * @param array $chat - * @param Player $player - */ - public function chat_bgm(array $chat, Player $player) { - $msg = '$ff0[$<' . $player->nickname . '$>] $ff0$iBad Game for me :('; - $this->maniaControl->chat->sendChat($msg, null, false); - } - - /** - * Leave the server with an Bootme Message - * - * @param array $chat - * @param Player $player - */ - public function chat_bootme(array $chat, Player $player) { - $msg = '$i$ff0 $<' . $player->nickname . '$>$s$39f chooses to boot back to the real world!'; - $this->maniaControl->chat->sendChat($msg, null, true); - - $message = '$39F Thanks for Playing, see you around!$z'; - try { - $this->maniaControl->client->kick($player->login, $message); - } catch (Exception $e) { - $this->maniaControl->errorHandler->triggerDebugNotice("ChatMessagePlugin Debug Line 316: " . $e->getMessage()); - // TODO: only possible valid exception should be "wrong login" - throw others (like connection error) - $this->maniaControl->chat->sendError('Error occurred: ' . $e->getMessage(), $player->login); - return; - } - } - - /** - * Leave the server with an Ragequit - * - * @param array $chat - * @param Player $player - */ - public function chat_ragequit(array $chat, Player $player) { - $msg = '$i$ff0 $<' . $player->nickname . '$>$s$f00 said: "@"#!" and ragequitted!'; - $this->maniaControl->chat->sendChat($msg, null, true); - - $message = '$39F Thanks for Playing, please come back soon!$z '; - try { - $this->maniaControl->client->kick($player->login, $message); - } catch (Exception $e) { - $this->maniaControl->errorHandler->triggerDebugNotice("ChatMessagePlugin Debug Line " . $e->getLine() . ": " . $e->getMessage()); - // TODO: only possible valid exception should be "wrong login" - throw others (like connection error) - $this->maniaControl->chat->sendError('Error occurred: ' . $e->getMessage(), $player->login); - return; - } - } - - /** - * Afk Message and force player to spec - * - * @param array $chat - * @param Player $player - */ - public function chat_afk(array $chat, Player $player) { - $msg = '$ff0[$<' . $player->nickname . '$>] $ff0$iAway From Keyboard!'; - $this->maniaControl->chat->sendChat($msg, null, false); - - if ($this->maniaControl->settingManager->getSetting($this, self::SETTING_AFK_FORCE_SPEC)) { - if ($player->isSpectator) { - return; - } - - // force into spec - try { - $this->maniaControl->client->forceSpectator($player->login, 3); - } catch (Exception $e) { - $this->maniaControl->errorHandler->triggerDebugNotice("ChatMessagePlugin Debug Line " . $e->getLine() . ": " . $e->getMessage()); - // TODO: only possible valid exception should be "wrong login" - throw others (like connection error) - $this->maniaControl->chat->sendError('Error occurred: ' . $e->getMessage(), $player->login); - return; - } - - // free player slot - try { - $this->maniaControl->client->spectatorReleasePlayerSlot($player->login); - } catch (Exception $e) { - if ($e->getMessage() != 'The player is not a spectator') { - $this->maniaControl->errorHandler->triggerDebugNotice("ChatMessagePlugin Debug Line " . $e->getLine() . ": " . $e->getMessage()); - // TODO: only possible valid exception should be "wrong login" - throw others (like connection error) - //to nothing - } - } - } - } -} \ No newline at end of file diff --git a/application/plugins/Chatlog.php b/application/plugins/Chatlog.php new file mode 100644 index 00000000..e69de29b diff --git a/application/plugins/Dedimania/Dedimania.php b/application/plugins/Dedimania/Dedimania.php new file mode 100644 index 00000000..2daff164 --- /dev/null +++ b/application/plugins/Dedimania/Dedimania.php @@ -0,0 +1,1196 @@ +server->getAllServers(); + foreach($servers as $server) { + $maniaControl->settingManager->initSetting(get_class(), self::SETTING_DEDIMANIA_CODE . $server->login . '$l', ''); + } + } + + /** + * Load the plugin + * + * @param \ManiaControl\ManiaControl $maniaControl + * @return bool + */ + public function load(ManiaControl $maniaControl) { + $this->maniaControl = $maniaControl; + + if (!extension_loaded('xmlrpc')) { + throw new \Exception("You need to activate the PHP extension xmlrpc to run this Plugin!"); + } + + $this->maniaControl->settingManager->initSetting($this, self::SETTING_WIDGET_ENABLE, true); + $this->maniaControl->settingManager->initSetting($this, self::SETTING_WIDGET_TITLE, 'Dedimania'); + $this->maniaControl->settingManager->initSetting($this, self::SETTING_WIDGET_POSX, -139); + $this->maniaControl->settingManager->initSetting($this, self::SETTING_WIDGET_POSY, 7); + $this->maniaControl->settingManager->initSetting($this, self::SETTING_WIDGET_WIDTH, 40); + $this->maniaControl->settingManager->initSetting($this, self::SETTING_WIDGET_LINEHEIGHT, 4); + $this->maniaControl->settingManager->initSetting($this, self::SETTING_WIDGET_LINESCOUNT, 12); + + $this->maniaControl->callbackManager->registerCallbackListener(Callbacks::BEGINMAP, $this, 'handleBeginMap'); + $this->maniaControl->callbackManager->registerCallbackListener(Callbacks::ENDMAP, $this, 'handleMapEnd'); + $this->maniaControl->callbackManager->registerCallbackListener(PlayerManager::CB_PLAYERCONNECT, $this, 'handlePlayerConnect'); + $this->maniaControl->callbackManager->registerCallbackListener(PlayerManager::CB_PLAYERDISCONNECT, $this, 'handlePlayerDisconnect'); + $this->maniaControl->callbackManager->registerCallbackListener(CallbackManager::CB_TM_PLAYERCHECKPOINT, $this, 'handlePlayerCheckpoint'); + $this->maniaControl->callbackManager->registerCallbackListener(CallbackManager::CB_TM_PLAYERFINISH, $this, 'handlePlayerFinished'); + $this->maniaControl->callbackManager->registerCallbackListener(CallbackManager::CB_MP_PLAYERMANIALINKPAGEANSWER, $this, 'handleManialinkPageAnswer'); + $this->maniaControl->timerManager->registerTimerListening($this, 'updateEverySecond', 1000); + $this->maniaControl->timerManager->registerTimerListening($this, 'handleEveryMinute', 1000 * 60); + $this->maniaControl->timerManager->registerTimerListening($this, 'updatePlayerList', 1000 * 60 * 3); + $this->maniaControl->commandManager->registerCommandListener(array('dedirecs', 'dedirecords'), $this, 'showDediRecordsList', false, 'Shows a list of Dedimania records of the current map.'); + + // Open session + $serverInfo = $this->maniaControl->server->getInfo(); + $serverVersion = $this->maniaControl->client->getVersion(); + $packMask = $this->maniaControl->server->titleId; + if($packMask != 'Trackmania_2@nadeolabs') { + $packMask = substr($this->maniaControl->server->titleId, 2); + } + + $dedimaniaCode = $this->maniaControl->settingManager->getSetting($this, self::SETTING_DEDIMANIA_CODE . $serverInfo->login . '$l'); + if ($dedimaniaCode == '') { + throw new \Exception("No Dedimania Code Specified, check the settings!"); + } + + $this->dedimaniaData = new DedimaniaData($serverInfo->login, $dedimaniaCode, $serverInfo->path, $packMask, $serverVersion); + + $this->openDedimaniaSession(); + } + + /** + * Opens the Dedimania Session + */ + private function openDedimaniaSession() { + $content = $this->encode_request(self::DEDIMANIA_OPENSESSION, array($this->dedimaniaData->toArray())); + + $self = $this; + $this->maniaControl->fileReader->postData(self::DEDIMANIA_URL, function ($data, $error) use (&$self) { + $self->maniaControl->log("Try to connect on Dedimania"); + + if ($error != '') { + $self->maniaControl->log("Dedimania Error: " . $error); + } + + $data = $self->decode($data); + if (is_array($data)) { + foreach($data as $index => $methodResponse) { + if (xmlrpc_is_fault($methodResponse)) { + $self->handleXmlRpcFault($methodResponse, Dedimania::DEDIMANIA_OPENSESSION); + } else if ($index <= 0) { + $responseData = $methodResponse[0]; + $self->dedimaniaData->sessionId = $responseData['SessionId']; + if ($self->dedimaniaData->sessionId != '') { + $self->maniaControl->log("Dedimania connection successfully established."); + $self->fetchDedimaniaRecords(); + $self->init = true; + } else { + $self->maniaControl->log("Error while opening Dedimania Connection"); + } + } + } + } + }, $content, true); + } + + /** + * Handle 1Second callback + */ + public function updateEverySecond($time) { + if (!$this->updateManialink) { + return; + } + if (!$this->dedimaniaData->records) { + return; + } + + $this->updateManialink = false; + + if ($this->maniaControl->settingManager->getSetting($this, self::SETTING_WIDGET_ENABLE)) { + $manialink = $this->buildManialink(); + $this->maniaControl->manialinkManager->sendManialink($manialink); + } + } + + /** + * Check if the session is alive every minute + * + * @param null $callback + */ + public function handleEveryMinute($callback = null) { + if (!$this->init) { + return; + } + $this->checkDedimaniaSession(); + } + + /** + * Handle PlayerConnect callback + * + * @param \ManiaControl\Players\Player $player + */ + public function handlePlayerConnect(Player $player) { + // Send Dedimania request + $data = array($this->dedimaniaData->sessionId, $player->login, $player->rawNickname, $player->path, $player->isSpectator); + $content = $this->encode_request(self::DEDIMANIA_PLAYERCONNECT, $data); + + $self = $this; + $this->maniaControl->fileReader->postData(self::DEDIMANIA_URL, function ($data, $error) use (&$self, &$player) { + if ($error != '') { + $self->maniaControl->log("Dedimania Error: " . $error); + } + + $data = $self->decode($data); + if (is_array($data)) { + foreach($data as $index => $methodResponse) { + if (xmlrpc_is_fault($methodResponse)) { + $self->handleXmlRpcFault($methodResponse, Dedimania::DEDIMANIA_PLAYERCONNECT); + } else if ($index <= 0) { + $responseData = $methodResponse[0]; + $self->dedimaniaData->addPlayer(new DedimaniaPlayer($responseData)); + + //Fetch records if he is the first who joined the server + if (count($self->maniaControl->playerManager->getPlayers()) == 1) { + $self->fetchDedimaniaRecords(true); + } + } + if ($self->maniaControl->settingManager->getSetting($self, Dedimania::SETTING_WIDGET_ENABLE)) { + $manialink = $self->buildManialink(); + $self->maniaControl->manialinkManager->sendManialink($manialink, $player->login); + } + } + } else { + if (!$data) { + trigger_error('XmlRpc Error.'); + var_dump($data); + } + } + return true; + }, $content, true); + } + + /** + * Handle PlayerDisconnect callback + * + * @param \ManiaControl\Players\Player $player + */ + public function handlePlayerDisconnect(Player $player) { + $this->dedimaniaData->removePlayer($player->login); + + // Send Dedimania request + $data = array($this->dedimaniaData->sessionId, $player->login, ''); + $content = $this->encode_request(self::DEDIMANIA_PLAYERDISCONNECT, $data); + + $self = $this; + $this->maniaControl->fileReader->postData(self::DEDIMANIA_URL, function ($data, $error) use (&$self) { + if ($error != '') { + $self->maniaControl->log("Dedimania Error: " . $error); + } + + $data = $self->decode($data); + if (is_array($data)) { + foreach($data as $methodResponse) { + if (xmlrpc_is_fault($methodResponse)) { + $self->handleXmlRpcFault($methodResponse, Dedimania::DEDIMANIA_PLAYERDISCONNECT); + } + } + } else { + if (!$data) { + trigger_error('XmlRpc Error.'); + var_dump($data); + } + } + return true; + }, $content, true); + } + + /** + * Handle Begin Map + * + * @param $callback + */ + public function handleBeginMap($callback) { + unset($this->dedimaniaData->records); + $this->fetchDedimaniaRecords(true); + } + + + /** + * Handle EndMap callback + * + * @param $callback + */ + public function handleMapEnd($callback) { + if (!$this->dedimaniaData || !$this->dedimaniaData->records) { + return; + } + + // Send dedimania records + $gameMode = $this->getGameModeString(); + $times = array(); + $replays = array(); + foreach($this->dedimaniaData->records as $record) { + /** @var RecordData $record */ + if ($record->rank > $this->dedimaniaData->serverMaxRank) { + break; + } + + if ($record->newRecord == false) { + continue; + } + array_push($times, array('Login' => $record->login, 'Best' => $record->best, 'Checks' => $record->checkpoints)); + if (!isset($replays['VReplay'])) { + $replays['VReplay'] = $record->vReplay; + } + if (!isset($replays['Top1GReplay'])) { + $replays['Top1GReplay'] = $record->top1GReplay; + } + if (!isset($replays['VReplayChecks'])) { + $replays['VReplayChecks'] = ''; + // TODO: VReplayChecks + } + } + + xmlrpc_set_type($replays['VReplay'], 'base64'); + xmlrpc_set_type($replays['Top1GReplay'], 'base64'); + + //var_dump($replays); + $data = array($this->dedimaniaData->sessionId, $this->getMapInfo(), $gameMode, $times, $replays); + //var_dump($data); + $content = $this->encode_request(self::DEDIMANIA_SETCHALLENGETIMES, $data); + + $self = $this; + $maniaControl = $this->maniaControl; + $this->maniaControl->fileReader->postData(self::DEDIMANIA_URL, function ($data, $error) use (&$self, &$maniaControl) { + if ($error != '') { + $maniaControl->log("Dedimania Error: " . $error); + } + + $data = $self->decode($data); + if (is_array($data)) { + foreach($data as $index => $methodResponse) { + if (xmlrpc_is_fault($methodResponse)) { + $self->handleXmlRpcFault($methodResponse, Dedimania::DEDIMANIA_SETCHALLENGETIMES); + } 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) { + $maniaControl->errorHandler->triggerDebugNotice($errors); + // TODO: check if this is sufficient + } + } + } + } + }, $content, false); + } + + /** + * Update the Playerlist every 3 Minutes + * + * @param $callback + */ + public function updatePlayerList($callback) { + $serverInfo = $this->getServerInfo(); + $playerList = $this->getPlayerList(); + $votesInfo = $this->getVotesInfo(); + if (!$serverInfo || !$votesInfo || !$playerList || !isset($this->dedimaniaData) || $this->dedimaniaData->sessionId == '') { + return; + } + + // Send Dedimania request + $data = array($this->dedimaniaData->sessionId, $serverInfo, $votesInfo, $playerList); + $content = $this->encode_request(self::DEDIMANIA_UPDATESERVERPLAYERS, $data); + + $self = $this; + $this->maniaControl->fileReader->postData(self::DEDIMANIA_URL, function ($data, $error) use (&$self) { + if ($error != '') { + $self->maniaControl->log("Dedimania Error: " . $error); + } + + $data = $self->decode($data); + if (is_array($data)) { + foreach($data as $methodResponse) { + if (xmlrpc_is_fault($methodResponse)) { + $self->handleXmlRpcFault($methodResponse, Dedimania::DEDIMANIA_UPDATESERVERPLAYERS); + } + } + } else { + if (!$data) { + trigger_error('XmlRpc Error.'); + var_dump($data); + } + } + return true; + }, $content, true); + } + + /** + * Handle PlayerCheckpoint callback + * + * @param $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; + } + + /** + * Plyer finished callback + * + * @param $callback + */ + public function handlePlayerFinished($callback) { + //var_dump($callback); + $data = $callback[1]; + if ($data[0] <= 0 || $data[2] <= 0) { + return; + } + + $login = $data[1]; + $time = $data[2]; + $map = $this->maniaControl->mapManager->getCurrentMap(); + if (!$map) { + return; + } + + + $oldRecord = $this->getDedimaniaRecord($login); + if ($oldRecord->nullRecord || $oldRecord && $oldRecord->best > $time) { + $player = $this->maniaControl->playerManager->getPlayer($login); + + // Save time + $newRecord = new RecordData(null); + $newRecord->constructNewRecord($login, $player->nickname, $data[2], $this->getCheckpoints($login), true); + if ($this->insertDedimaniaRecord($newRecord, $oldRecord)) { + + // Get newly saved record + foreach($this->dedimaniaData->records as &$record) { + /** @var RecordData $record */ + if ($record->login !== $newRecord->login) { + continue; + } + $newRecord = $record; + break; + } + + $this->maniaControl->callbackManager->triggerCallback(self::CB_DEDIMANIA_CHANGED, $newRecord); + + // Announce record + if ($oldRecord->nullRecord || $newRecord->rank < $oldRecord->rank) { + // Gained rank + $improvement = 'gained the'; + } else { + // Only improved time + $improvement = 'improved his/her'; + } + $message = '$390$<$fff' . $player->nickname . '$> ' . $improvement . ' $<$ff0' . $newRecord->rank . '.$> Dedimania Record: $<$fff' . Formatter::formatTime($newRecord->best) . '$>'; + if (!$oldRecord->nullRecord) { + $message .= ' ($<$ff0' . $oldRecord->rank . '.$> $<$fff-' . Formatter::formatTime(($oldRecord->best - $time)) . '$>)'; + } + $this->maniaControl->chat->sendInformation($message . '!'); + + $this->updateManialink = true; + } + } + } + + /** + * Shows a ManiaLink list with the local records. + * + * @param array $chat + * @param Player $player + */ + public function showDediRecordsList(array $chat, Player $player) { + $width = $this->maniaControl->manialinkManager->styleManager->getListWidgetsWidth(); + $height = $this->maniaControl->manialinkManager->styleManager->getListWidgetsHeight(); + + // get PlayerList + $records = $this->dedimaniaData->records; + if (!$records) { + $this->maniaControl->chat->sendInformation('There are no Dedimania records on this map!'); + return; + } + + $pagesId = ''; + if (count($records) > 15) { + $pagesId = 'DediRecordsListPages'; + } + + //create manialink + $maniaLink = new ManiaLink(ManialinkManager::MAIN_MLID); + $script = $maniaLink->getScript(); + $paging = new Paging(); + $script->addFeature($paging); + + // Main frame + $frame = $this->maniaControl->manialinkManager->styleManager->getDefaultListFrame($script, $paging); + $maniaLink->add($frame); + + // Start offsets + $x = -$width / 2; + $y = $height / 2; + + // Predefine Description Label + $descriptionLabel = $this->maniaControl->manialinkManager->styleManager->getDefaultDescriptionLabel(); + $frame->add($descriptionLabel); + + // Headline + $headFrame = new Frame(); + $frame->add($headFrame); + $headFrame->setY($y - 5); + $array = array("Rank" => $x + 5, "Nickname" => $x + 18, "Login" => $x + 70, "Time" => $x + 101); + $this->maniaControl->manialinkManager->labelLine($headFrame, $array); + + $i = 0; + $y = $height / 2 - 10; + $pageFrames = array(); + foreach($records as $listRecord) { + if (!isset($pageFrame)) { + $pageFrame = new Frame(); + $frame->add($pageFrame); + if (!empty($pageFrames)) { + $pageFrame->setVisible(false); + } + array_push($pageFrames, $pageFrame); + $y = $height / 2 - 10; + $paging->addPage($pageFrame); + } + + $recordFrame = new Frame(); + $pageFrame->add($recordFrame); + + if ($i % 2 != 0) { + $lineQuad = new Quad_BgsPlayerCard(); + $recordFrame->add($lineQuad); + $lineQuad->setSize($width, 4); + $lineQuad->setSubStyle($lineQuad::SUBSTYLE_BgPlayerCardBig); + $lineQuad->setZ(0.001); + } + + if (strlen($listRecord->nickName) < 2) { + $listRecord->nickName = $listRecord->login; + } + $array = array($listRecord->rank => $x + 5, '$fff' . $listRecord->nickName => $x + 18, $listRecord->login => $x + 70, Formatter::formatTime($listRecord->best) => $x + 101); + $this->maniaControl->manialinkManager->labelLine($recordFrame, $array); + + $recordFrame->setY($y); + + $y -= 4; + $i++; + if ($i % 15 == 0) { + unset($pageFrame); + } + } + + // Render and display xml + $this->maniaControl->manialinkManager->displayWidget($maniaLink, $player, 'DediRecordsList'); + } + + /** + * Handle PlayerManialinkPageAnswer callback + * + * @param array $callback + */ + public function handleManialinkPageAnswer(array $callback) { + $actionId = $callback[1][2]; + + $login = $callback[1][1]; + $player = $this->maniaControl->playerManager->getPlayer($login); + + if ($actionId == self::ACTION_SHOW_DEDIRECORDSLIST) { + $this->showDediRecordsList(array(), $player); + } + } + + /** + * Fetch Dedimania Records + * + * @param bool $reset + */ + private function fetchDedimaniaRecords($reset = true) { + if (!$this->dedimaniaData || $this->dedimaniaData->sessionId == '') { + return false; + } + + // Reset records + if ($reset) { + $this->dedimaniaData->records = array(); + } + + + $serverInfo = $this->getServerInfo(); + $playerInfo = $this->getPlayerList(); + $mapInfo = $this->getMapInfo(); + $gameMode = $this->getGameModeString(); + + if (!$serverInfo || !$playerInfo || !$mapInfo || !$gameMode) { + return false; + } + + $data = array($this->dedimaniaData->sessionId, $mapInfo, $gameMode, $serverInfo, $playerInfo); + $content = $this->encode_request(self::DEDIMANIA_GETRECORDS, $data); + + $self = $this; + $this->maniaControl->fileReader->postData(self::DEDIMANIA_URL, function ($data, $error) use (&$self) { + if ($error != '') { + $self->maniaControl->log("Dedimania Error: " . $error); + } + + $data = $self->decode($data); + + if (is_array($data)) { + foreach($data as $index => $methodResponse) { + if (xmlrpc_is_fault($methodResponse)) { + $self->handleXmlRpcFault($methodResponse, Dedimania::DEDIMANIA_GETRECORDS); + return false; + } else if ($index <= 0) { + $responseData = $methodResponse[0]; + $self->dedimaniaData->serverMaxRank = $responseData['ServerMaxRank']; + + foreach($responseData['Players'] as $player) { + $dediPlayer = new DedimaniaPlayer(null); + $dediPlayer->constructNewPlayer($player['Login'], $player['MaxRank']); + $self->dedimaniaData->addPlayer($dediPlayer); + } + foreach($responseData['Records'] as $key => $record) { + $self->dedimaniaData->records[$key] = new RecordData($record); + } + } + } + } + $self->updateManialink = true; + $self->maniaControl->callbackManager->triggerCallback(Dedimania::CB_DEDIMANIA_UPDATED, $self->dedimaniaData->records); + return true; + }, $content, true); + + return true; + } + + /** + * Checks If a Dedimania Session exists, if not create a new oen + */ + private function checkDedimaniaSession() { + if ($this->dedimaniaData->sessionId == '') { + $this->openDedimaniaSession(); + return; + } + + $content = $this->encode_request(self::DEDIMANIA_CHECKSESSION, array($this->dedimaniaData->sessionId)); + + $self = $this; + $this->maniaControl->fileReader->postData(self::DEDIMANIA_URL, function ($data, $error) use (&$self) { + if ($error != '') { + $self->maniaControl->log("Dedimania Error: " . $error); + } + + $data = $self->decode($data); + if (is_array($data)) { + foreach($data as $methodResponse) { + if (xmlrpc_is_fault($methodResponse)) { + $self->handleXmlRpcFault($methodResponse, Dedimania::DEDIMANIA_CHECKSESSION); + } else { + $responseData = $methodResponse[0]; + if (is_bool($responseData)) { + if (!$responseData) { + $self->openDedimaniaSession(); + } + } + } + } + } + }, $content, true); + return; + } + + /** + * Inserts the given new Dedimania record at the proper position + * + * @param array $newRecord + * @return bool + */ + private function insertDedimaniaRecord(RecordData &$newRecord, RecordData $oldRecord) { + if ($newRecord->nullRecord) { + return false; + } + + $insert = false; + + // Get max possible rank + $maxRank = $this->dedimaniaData->getPlayerMaxRank($newRecord->login); + + // Loop through existing records + foreach($this->dedimaniaData->records as $key => &$record) { + /** @var RecordData $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[$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 as $key2 => $record2) { + /** @var RecordData $record2 */ + if ($record2->login !== $oldRecord->login) { + continue; + } + unset($this->dedimaniaData->records[$key2]); + break; + } + } + break; + } + + if (!$insert && count($this->dedimaniaData->records) < $maxRank) { + // Records list not full - Append new record + $insert = true; + } + + if ($insert) { + // Insert new record + array_push($this->dedimaniaData->records, $newRecord); + + // Update ranks + $this->updateDedimaniaRecordRanks(); + + // Save replays + foreach($this->dedimaniaData->records as &$record) { + if ($record->login !== $newRecord->login) { + continue; + } + $this->setRecordReplays($record); + break; + } + // Record inserted + return true; + } + // No new record + return false; + } + + /** + * Update the sorting and the ranks of all dedimania records + */ + private function updateDedimaniaRecordRanks() { + if ($this->dedimaniaData->getRecordCount() == 0) { + $this->maniaControl->callbackManager->triggerCallback(self::CB_DEDIMANIA_UPDATED, $this->dedimaniaData->records); + return; + } + //TODO move into class dedimania data + // Sort records + usort($this->dedimaniaData->records, array($this, 'compareRecords')); + + // Update ranks + $rank = 1; + foreach($this->dedimaniaData->records as &$record) { + /** @var RecordData $record */ + $record->rank = $rank; + $rank++; + } + $this->maniaControl->callbackManager->triggerCallback(self::CB_DEDIMANIA_UPDATED, $this->dedimaniaData->records); + } + + /** + * Compare function for sorting dedimania records + * + * @param \Dedimania\RecordData $first + * @param \Dedimania\RecordData $second + * @return int + */ + private function compareRecords(RecordData $first, RecordData $second) { + //TODO move into class dedimania data + 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; + } + } + } + + /** + * Updates the replay values for the given record + * + * @param array $record + */ + private function setRecordReplays(RecordData &$record) { + // Set validation replay + $validationReplay = $this->maniaControl->server->getValidationReplay($record->login); + if ($validationReplay) { + $record->vReplay = $validationReplay; + } + + // Set ghost replay + if ($record->rank <= 1) { + $dataDirectory = $this->maniaControl->server->getDataDirectory(); + if (!isset($this->dedimaniaData->directoryAccessChecked)) { + $access = $this->maniaControl->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->maniaControl->server->getGhostReplay($record->login); + if ($ghostReplay) { + $record->top1GReplay = $ghostReplay; + } + } + } + } + + /** + * Build server info Structure for callbacks + */ + private function getServerInfo() { + $server = $this->maniaControl->client->getServerOptions(); + if (!$server) { + return null; + } + + if (count($this->maniaControl->playerManager->getPlayers()) == 0) { + return null; + } + + $playerCount = $this->maniaControl->playerManager->getPlayerCount(); + $spectatorCount = $this->maniaControl->playerManager->getSpectatorCount(); + + return array('SrvName' => $server->name, 'Comment' => $server->comment, 'Private' => (strlen($server->password) > 0), 'NumPlayers' => $playerCount, 'MaxPlayers' => $server->currentMaxPlayers, 'NumSpecs' => $spectatorCount, 'MaxSpecs' => $server->currentMaxSpectators); + } + + /** + * Build simple player list for callbacks + */ + private function getPlayerList() { + $players = $this->maniaControl->playerManager->getPlayers(); + + if (count($players) == 0) { + return null; + } + $playerInfo = array(); + foreach($players as $player) { + /** @var Player $player */ + array_push($playerInfo, array('Login' => $player->login, 'IsSpec' => $player->isSpectator)); + } + return $playerInfo; + } + + /** + * Build map info struct for dedimania requests + */ + private function getMapInfo() { + $map = $this->maniaControl->mapManager->getCurrentMap(); + if (!$map) { + return null; + } + $mapInfo = array(); + $mapInfo['UId'] = $map->uid; + $mapInfo['Name'] = $map->rawName; + $mapInfo['Author'] = $map->authorLogin; + $mapInfo['Environment'] = $map->environment; + $mapInfo['NbCheckpoints'] = $map->nbCheckpoints; + $mapInfo['NbLaps'] = $map->nbLaps; + return $mapInfo; + } + + /** + * Build votes info struct for callbacks + */ + private function getVotesInfo() { + $map = $this->maniaControl->mapManager->getCurrentMap(); + if (!$map) { + return null; + } + $gameMode = $this->getGameModeString(); + if (!$gameMode) { + return null; + } + return array('UId' => $map->uid, 'GameMode' => $gameMode); + } + + /** + * Function to retrieve the dedimania records on the current map + * + * @return array|RecordData + */ + public function getDedimaniaRecords() { + if (!$this->dedimaniaData->records) { + return null; + } + $records = $this->dedimaniaData->records; + return $records; + } + + /** + * Get the dedimania record of the given login + * + * @param string $login + * @return RecordData $record + */ + private function getDedimaniaRecord($login) { + if (!$this->dedimaniaData->records) { + return new RecordData(null); + } + $records = $this->dedimaniaData->records; + foreach($records as &$record) { + /** @var RecordData $record */ + if ($record->login === $login) { + return $record; + } + } + + return new RecordData(null); + } + + /** + * Get Dedimania string representation of the current game mode + * + * @return String + */ + private function getGameModeString() { + $gameMode = $this->maniaControl->server->getGameMode(); + $scriptNameResponse = $this->maniaControl->client->getScriptName(); + $scriptName = str_replace('.Script.txt', '', $scriptNameResponse["CurrentValue"]); + if ($gameMode === null) { + trigger_error("Couldn't retrieve game mode. "); + return null; + } + switch($gameMode) { + case 0: + { + if ($scriptName == 'Rounds' || $scriptName == 'Cup' || $scriptName == 'Team') { + return 'Rounds'; + } else if ($scriptName == 'TimeAttack' || $scriptName == 'Laps' || $scriptName == 'TeamAttack' || $scriptName == 'TimeAttackPlus') { + return 'TA'; + } + break; + } + case 1: + case 3: + case 5: + { + return 'Rounds'; + } + case 2: + case 4: + { + return 'TA'; + } + } + return null; + } + + /** + * Get current checkpoint string for dedimania record + * + * @param string $login + * @return string + */ + private function getCheckpoints($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; + } + + /** + * Encode 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')); + } + + /** + * Handle xml rpc fault + * + * @param $fault + * @param $method + */ + private function handleXmlRpcFault($fault, $method) { + trigger_error('XmlRpc Fault on ' . $method . ': ' . $fault['faultString'] . ' (' . $fault['faultCode'] . ')'); + } + + /** + * Build Manialink + * + * @return \FML\ManiaLink + */ + private function buildManialink() { + if (!$this->dedimaniaData->records) { + return null; + } + $records = $this->dedimaniaData->records; + + $title = $this->maniaControl->settingManager->getSetting($this, self::SETTING_WIDGET_TITLE); + $pos_x = $this->maniaControl->settingManager->getSetting($this, self::SETTING_WIDGET_POSX); + $pos_y = $this->maniaControl->settingManager->getSetting($this, self::SETTING_WIDGET_POSY); + $width = $this->maniaControl->settingManager->getSetting($this, self::SETTING_WIDGET_WIDTH); + $lines = $this->maniaControl->settingManager->getSetting($this, self::SETTING_WIDGET_LINESCOUNT); + $lineHeight = $this->maniaControl->settingManager->getSetting($this, self::SETTING_WIDGET_LINEHEIGHT); + $labelStyle = $this->maniaControl->manialinkManager->styleManager->getDefaultLabelStyle(); + $quadStyle = $this->maniaControl->manialinkManager->styleManager->getDefaultQuadStyle(); + $quadSubstyle = $this->maniaControl->manialinkManager->styleManager->getDefaultQuadSubstyle(); + + + $manialink = new ManiaLink(self::MLID_DEDIMANIA); + $frame = new Frame(); + $manialink->add($frame); + $frame->setPosition($pos_x, $pos_y); + + $backgroundQuad = new Quad(); + $frame->add($backgroundQuad); + $backgroundQuad->setVAlign(Control::TOP); + $height = 7. + $lines * $lineHeight; + $backgroundQuad->setSize($width * 1.05, $height); + $backgroundQuad->setStyles($quadStyle, $quadSubstyle); + + $titleLabel = new Label(); + $frame->add($titleLabel); + $titleLabel->setPosition(0, $lineHeight * -0.9); + $titleLabel->setWidth($width); + $titleLabel->setStyle($labelStyle); + $titleLabel->setTextSize(2); + $titleLabel->setText($title); + $titleLabel->setTranslate(true); + + foreach($records as $index => $record) { + /** @var RecordData $record */ + if ($index >= $lines) { + break; + } + + $y = -8. - $index * $lineHeight; + + $recordFrame = new Frame(); + $frame->add($recordFrame); + $recordFrame->setPosition(0, $y); + + /*$backgroundQuad = new Quad(); + $recordFrame->add($backgroundQuad); + $backgroundQuad->setSize($width * 1.04, $lineHeight * 1.4); + $backgroundQuad->setStyles($quadStyle, $quadSubstyle);*/ + + //Rank + $rankLabel = new Label(); + $recordFrame->add($rankLabel); + $rankLabel->setHAlign(Control::LEFT); + $rankLabel->setX($width * -0.47); + $rankLabel->setSize($width * 0.06, $lineHeight); + $rankLabel->setTextSize(1); + $rankLabel->setTextPrefix('$o'); + $rankLabel->setText($record->rank); + $rankLabel->setTextEmboss(true); + + //Name + $nameLabel = new Label(); + $recordFrame->add($nameLabel); + $nameLabel->setHAlign(Control::LEFT); + $nameLabel->setX($width * -0.4); + $nameLabel->setSize($width * 0.6, $lineHeight); + $nameLabel->setTextSize(1); + $nameLabel->setText($record->nickName); + $nameLabel->setTextEmboss(true); + + //Time + $timeLabel = new Label(); + $recordFrame->add($timeLabel); + $timeLabel->setHAlign(Control::RIGHT); + $timeLabel->setX($width * 0.47); + $timeLabel->setSize($width * 0.25, $lineHeight); + $timeLabel->setTextSize(1); + $timeLabel->setText(Formatter::formatTime($record->best)); + $timeLabel->setTextEmboss(true); + } + + return $manialink; + } + + /** + * Decodes xml rpc response + * + * @param string $response + * @return mixed + */ + private function decode($response) { + return xmlrpc_decode($response, 'utf-8'); + } + + /** + * Unload the plugin and its resources + */ + public function unload() { + $this->maniaControl->timerManager->unregisterTimerListenings($this); + $this->maniaControl->callbackManager->unregisterCallbackListener($this); + unset($this->maniaControl); + } + + /** + * Get plugin id + * + * @return int + */ + public static function getId() { + return self::ID; + } + + /** + * Get Plugin Name + * + * @return string + */ + public static function getName() { + return "Dedimania Plugin"; + } + + /** + * Get Plugin Version + * + * @return float + */ + public static function getVersion() { + return self::VERSION; + } + + /** + * Get Plugin Author + * + * @return string + */ + public static function getAuthor() { + return "kremsy and steeffeen"; + } + + /** + * Get Plugin Description + * + * @return string + */ + public static function getDescription() { + return "Dedimania Plugin for Trackmania"; + } +} \ No newline at end of file diff --git a/application/plugins/Dedimania/DedimaniaData.php b/application/plugins/Dedimania/DedimaniaData.php new file mode 100644 index 00000000..16b86ff7 --- /dev/null +++ b/application/plugins/Dedimania/DedimaniaData.php @@ -0,0 +1,95 @@ +game = "TM2"; + $this->login = $serverLogin; + $this->code = $dedimaniaCode; + $this->version = ManiaControl::VERSION; + $this->tool = "ManiaControl"; + $this->path = $path; + $this->packmask = $packmask; + $this->serverVersion = $serverVersion->version; + $this->serverBuild = $serverVersion->build; + } + + public function toArray() { + $array = array(); + foreach(get_object_vars($this) as $key => $value) { + if ($key == 'records' || $key == 'sessionId' || $key == 'directoryAccessChecked' || $key == 'serverMaxRank' || $key == 'players') { + continue; + } + $array[ucfirst($key)] = $value; + } + return $array; + } + + public function getRecordCount() { + return count($this->records); + } + + /** + * Get Max Rank for a certain Player + * + * @param $login + * @return int + */ + public function getPlayerMaxRank($login) { + $maxRank = $this->serverMaxRank; + foreach($this->players as $player) { + /** @var DedimaniaPlayer $player */ + if ($player->login === $login) { + if ($player->maxRank > $maxRank) { + $maxRank = $player->maxRank; + } + break; + } + } + return $maxRank; + } + + /** + * Adds a Player to the Players array + * + * @param DedimaniaPlayer $player + */ + public function addPlayer(DedimaniaPlayer $player) { + /** @var DedimaniaPlayer $player */ + $this->players[$player->login] = $player; + } + + /** + * Removes a Dedimania Player by its login + * + * @param string $player + */ + public function removePlayer($login) { + unset($this->players[$login]); + } +} \ No newline at end of file diff --git a/application/plugins/Dedimania/DedimaniaPlayer.php b/application/plugins/Dedimania/DedimaniaPlayer.php new file mode 100644 index 00000000..33cbfc71 --- /dev/null +++ b/application/plugins/Dedimania/DedimaniaPlayer.php @@ -0,0 +1,38 @@ +login = $player['Login']; + $this->maxRank = $player['MaxRank']; + $this->banned = $player['Banned']; + $this->optionsEnabled = $player['OptionsEnabled']; + $this->options = $player['Options']; + } + + /** + * Construct a new Player by its login and maxRank + * + * @param $login + * @param $maxRank + */ + public function constructNewPlayer($login, $maxRank) { + $this->login = $login; + $this->maxRank = $maxRank; + } +} \ No newline at end of file diff --git a/application/plugins/Dedimania/RecordData.php b/application/plugins/Dedimania/RecordData.php new file mode 100644 index 00000000..2687335b --- /dev/null +++ b/application/plugins/Dedimania/RecordData.php @@ -0,0 +1,61 @@ +nullRecord = true; + return; + } + + $this->login = $record['Login']; + $this->nickName = Formatter::stripDirtyCodes($record['NickName']); + $this->best = $record['Best']; + $this->rank = $record['Rank']; + $this->maxRank = $record['MaxRank']; + $this->checkpoints = $record['Checks']; + } + + /** + * Constructs a new Record via it's properties + * + * @param $login + * @param $nickName + * @param $best + * @param $checkpoints + * @param bool $newRecord + */ + public function constructNewRecord($login, $nickName, $best, $checkpoints, $newRecord = false) { + $this->nullRecord = false; + $this->login = $login; + $this->nickName = $nickName; + $this->best = $best; + $this->checkpoints = $checkpoints; + $this->newRecord = $newRecord; + } +} \ No newline at end of file diff --git a/application/plugins/Donations.php b/application/plugins/Donations.php index 4fe543a8..e69de29b 100644 --- a/application/plugins/Donations.php +++ b/application/plugins/Donations.php @@ -1,556 +0,0 @@ -maniaControl = $maniaControl; - - // Register for commands - $this->maniaControl->commandManager->registerCommandListener('donate', $this, 'command_Donate', false, 'Donate some planets to the server.'); - $this->maniaControl->commandManager->registerCommandListener('pay', $this, 'command_Pay', true, 'Pays planets from the server to a player.'); - $this->maniaControl->commandManager->registerCommandListener('planets', $this, 'command_GetPlanets', true, 'Checks the planets-balance of the server.'); - $this->maniaControl->commandManager->registerCommandListener('topdons', $this, 'command_TopDons', false, 'Provides an overview of who dontated the most planets.'); - - // Register for callbacks - $this->maniaControl->callbackManager->registerCallbackListener(PlayerManager::CB_PLAYERCONNECT, $this, 'handlePlayerConnect'); - $this->maniaControl->callbackManager->registerCallbackListener(CallbackManager::CB_MP_PLAYERMANIALINKPAGEANSWER, $this, 'handleManialinkPageAnswer'); - - // Define player stats - $this->maniaControl->statisticManager->defineStatMetaData(self::STAT_PLAYER_DONATIONS); - - $this->maniaControl->settingManager->initSetting($this, self::SETTING_DONATE_WIDGET_ACTIVATED, true); - $this->maniaControl->settingManager->initSetting($this, self::SETTING_DONATE_WIDGET_POSX, 156.); - $this->maniaControl->settingManager->initSetting($this, self::SETTING_DONATE_WIDGET_POSY, -31.4); - $this->maniaControl->settingManager->initSetting($this, self::SETTING_DONATE_WIDGET_WIDTH, 6); - $this->maniaControl->settingManager->initSetting($this, self::SETTING_DONATE_WIDGET_HEIGHT, 6); - $this->maniaControl->settingManager->initSetting($this, self::SETTING_DONATION_VALUES, "20,50,100,500,1000,2000"); - $this->maniaControl->settingManager->initSetting($this, self::SETTING_MIN_AMOUNT_SHOWN, 100); - - // Register Stat in Simple StatsList - $this->maniaControl->statisticManager->simpleStatsList->registerStat(self::STAT_PLAYER_DONATIONS, 90, "DP", 15); - - $this->displayWidget(); - return true; - } - - /** - * @see \ManiaControl\Plugins\Plugin::unload() - */ - public function unload() { - $emptyManialink = new ManiaLink(self::MLID_DONATE_WIDGET); - $this->maniaControl->manialinkManager->sendManialink($emptyManialink); - - $this->maniaControl->callbackManager->unregisterCallbackListener($this); - $this->maniaControl->commandManager->unregisterCommandListener($this); - unset($this->maniaControl); - } - - /** - * @see \ManiaControl\Plugins\Plugin::getId() - */ - public static function getId() { - return self::ID; - } - - /** - * @see \ManiaControl\Plugins\Plugin::getName() - */ - public static function getName() { - return 'Donations Plugin'; - } - - /** - * @see \ManiaControl\Plugins\Plugin::getVersion() - */ - public static function getVersion() { - return self::VERSION; - } - - /** - * @see \ManiaControl\Plugins\Plugin::getAuthor() - */ - public static function getAuthor() { - return 'steeffeen and kremsy'; - } - - /** - * @see \ManiaControl\Plugins\Plugin::getDescription() - */ - public static function getDescription() { - return 'Plugin offering commands like /donate, /pay and /planets and a donation widget.'; - } - - /** - * Handle ManiaControl OnStartup - * - * @param array $callback - */ - public function displayWidget() { - if ($this->maniaControl->settingManager->getSetting($this, self::SETTING_DONATE_WIDGET_ACTIVATED)) { - $this->displayDonateWidget(); - } - } - - /** - * Handle ManialinkPageAnswer Callback - * - * @param array $callback - */ - public function handleManialinkPageAnswer(array $callback) { - $actionId = $callback[1][2]; - $boolSetting = (strpos($actionId, self::ACTION_DONATE_VALUE) === 0); - if (!$boolSetting) { - return; - } - $login = $callback[1][1]; - $player = $this->maniaControl->playerManager->getPlayer($login); - $actionArray = explode(".", $callback[1][2]); - $this->handleDonation($player, intval($actionArray[2])); - } - - /** - * Handle PlayerConnect callback - * - * @param Player $player - */ - public function handlePlayerConnect(Player $player) { - // Display Map Widget - if ($this->maniaControl->settingManager->getSetting($this, self::SETTING_DONATE_WIDGET_ACTIVATED)) { - $this->displayDonateWidget($player->login); - } - } - - /** - * Displays the Donate Widget - * - * @param bool $login - */ - public function displayDonateWidget($login = false) { - $posX = $this->maniaControl->settingManager->getSetting($this, self::SETTING_DONATE_WIDGET_POSX); - $posY = $this->maniaControl->settingManager->getSetting($this, self::SETTING_DONATE_WIDGET_POSY); - $width = $this->maniaControl->settingManager->getSetting($this, self::SETTING_DONATE_WIDGET_WIDTH); - $height = $this->maniaControl->settingManager->getSetting($this, self::SETTING_DONATE_WIDGET_HEIGHT); - $values = $this->maniaControl->settingManager->getSetting($this, self::SETTING_DONATION_VALUES); - $shootManiaOffset = $this->maniaControl->manialinkManager->styleManager->getDefaultIconOffsetSM(); - $quadStyle = $this->maniaControl->manialinkManager->styleManager->getDefaultQuadStyle(); - $quadSubstyle = $this->maniaControl->manialinkManager->styleManager->getDefaultQuadSubstyle(); - $itemMarginFactorX = 1.3; - $itemMarginFactorY = 1.2; - - //If game is shootmania lower the icons position by 20 - if($this->maniaControl->mapManager->getCurrentMap()->getGame() == 'sm') { - $posY -= $shootManiaOffset; - } - - $itemSize = $width; - - $maniaLink = new ManiaLink(self::MLID_DONATE_WIDGET); - - // Donate Menu Icon Frame - $frame = new Frame(); - $maniaLink->add($frame); - $frame->setPosition($posX, $posY); - - $backgroundQuad = new Quad(); - $frame->add($backgroundQuad); - $backgroundQuad->setSize($width * $itemMarginFactorX, $height * $itemMarginFactorY); - $backgroundQuad->setStyles($quadStyle, $quadSubstyle); - - $iconFrame = new Frame(); - $frame->add($iconFrame); - - $iconFrame->setSize($itemSize, $itemSize); - $itemQuad = new Quad_Icons128x128_1(); - $itemQuad->setSubStyle($itemQuad::SUBSTYLE_Coppers); - $itemQuad->setSize($itemSize, $itemSize); - $iconFrame->add($itemQuad); - - $valueArray = explode(",", $values); - - // Values Menu - $popoutFrame = new Frame(); - $maniaLink->add($popoutFrame); - $popoutFrame->setPosition($posX - $itemSize * 0.5, $posY); - $popoutFrame->setHAlign(Control::RIGHT); - $popoutFrame->setSize(4 * $itemSize * $itemMarginFactorX, $itemSize * $itemMarginFactorY); - $popoutFrame->setVisible(false); - - $quad = new Quad(); - $popoutFrame->add($quad); - $quad->setHAlign(Control::RIGHT); - $quad->setStyles($quadStyle, $quadSubstyle); - $quad->setSize(strlen($values) * 2 + count($valueArray) * 1, $itemSize * $itemMarginFactorY); - - $popoutFrame->add($quad); - $itemQuad->addToggleFeature($popoutFrame); - - // Description Label - $descriptionFrame = new Frame(); - $maniaLink->add($descriptionFrame); - $descriptionFrame->setPosition($posX - 50, $posY - 5); - $descriptionFrame->setHAlign(Control::RIGHT); - - $descriptionLabel = new Label(); - $descriptionFrame->add($descriptionLabel); - $descriptionLabel->setAlign(Control::LEFT, Control::TOP); - $descriptionLabel->setSize(40, 4); - $descriptionLabel->setTextSize(2); - $descriptionLabel->setVisible(true); - $descriptionLabel->setTextColor("0F0"); - - // Add items - $x = -2; - foreach(array_reverse($valueArray) as $value) { - $label = new Label_Button(); - $popoutFrame->add($label); - $label->setX($x); - $label->setHAlign(Control::RIGHT); - $label->setText('$s$FFF' . $value . '$09FP'); - $label->setTextSize(1.2); - $label->setAction(self::ACTION_DONATE_VALUE . "." . $value); - $label->setStyle(Label_Text::STYLE_TextCardSmall); - $description = "Donate {$value} Planets"; - $label->addTooltipLabelFeature($descriptionLabel, $description); - - $x -= strlen($value) * 2 + 1.7; - } - - // Send manialink - $this->maniaControl->manialinkManager->sendManialink($maniaLink, $login); - } - - /** - * Handle /donate command - * - * @param array $chatCallback - * @param Player $player - * @return bool - */ - public function command_Donate(array $chatCallback, Player $player) { - $text = $chatCallback[1][2]; - $params = explode(' ', $text); - if (count($params) < 2) { - $this->sendDonateUsageExample($player); - return false; - } - $amount = (int)$params[1]; - if (!$amount || $amount <= 0) { - $this->sendDonateUsageExample($player); - return false; - } - if (count($params) >= 3) { - $receiver = $params[2]; - $receiverPlayer = $this->maniaControl->playerManager->getPlayer($receiver); - $receiverName = ($receiverPlayer ? $receiverPlayer->nickname : $receiver); - } else { - $receiver = ''; - $receiverName = $this->maniaControl->client->getServerName(); - } - - return $this->handleDonation($player, $amount, $receiver, $receiverName); - } - - /** - * Handles a Player Donate - * - * @param Player $player - * @param $value - */ - private function handleDonation(Player $player, $amount, $receiver = '', $receiverName = false) { - - if (!$receiverName) { - $serverName = $this->maniaControl->client->getServerName(); - $message = 'Donate ' . $amount . ' Planets to $<' . $serverName . '$>?'; - } else { - $message = 'Donate ' . $amount . ' Planets to $<' . $receiverName . '$>?'; - } - - //Send and Handle the Bill - $self = $this; - $this->maniaControl->billManager->sendBill(function ($data, $status) use (&$self, &$player, $amount, $receiver) { - switch($status) { - case BillManager::DONATED_TO_SERVER: - if ($self->maniaControl->settingManager->getSetting($self, DonationPlugin::SETTING_ANNOUNCE_SERVERDONATION, true) && $amount >= $self->maniaControl->settingManager->getSetting($self, DonationPlugin::SETTING_MIN_AMOUNT_SHOWN, true)) { - $login = null; - $message = '$<' . $player->nickname . '$> donated ' . $amount . ' Planets! Thanks.'; - } else { - $login = $player->login; - $message = 'Donation successful! Thanks.'; - } - $self->maniaControl->chat->sendSuccess($message, $login); - $self->maniaControl->statisticManager->insertStat(DonationPlugin::STAT_PLAYER_DONATIONS, $player, $self->maniaControl->server->index, $amount); - break; - case BillManager::DONATED_TO_RECEIVER: - $message = "Successfully donated {$amount} to '{$receiver}'!"; - $self->maniaControl->chat->sendSuccess($message, $player->login); - break; - case BillManager::PLAYER_REFUSED_DONATION: - $message = 'Transaction cancelled.'; - $self->maniaControl->chat->sendError($message, $player->login); - break; - case BillManager::ERROR_WHILE_TRANSACTION: - $message = $data; - $self->maniaControl->chat->sendError($message, $player->login); - break; - } - }, $player, $amount, $message); - - return true; - } - - /** - * Handle //pay command - * - * @param array $chatCallback - * @param Player $player - * @return bool - */ - public function command_Pay(array $chatCallback, Player $player) { - if (!$this->maniaControl->authenticationManager->checkRight($player, AuthenticationManager::AUTH_LEVEL_SUPERADMIN)) { - $this->maniaControl->authenticationManager->sendNotAllowed($player); - return false; - } - $text = $chatCallback[1][2]; - $params = explode(' ', $text); - if (count($params) < 2) { - $this->sendPayUsageExample($player); - return false; - } - $amount = (int)$params[1]; - if (!$amount || $amount <= 0) { - $this->sendPayUsageExample($player); - return false; - } - if (count($params) >= 3) { - $receiver = $params[2]; - } else { - $receiver = $player->login; - } - $message = 'Payout from $<' . $this->maniaControl->client->getServerName() . '$>.'; - - $self = $this; - $this->maniaControl->billManager->sendPlanets(function ($data, $status) use (&$self, &$player, $amount, $receiver) { - switch($status) { - case BillManager::PAYED_FROM_SERVER: - $message = "Successfully payed out {$amount} to '{$receiver}'!"; - $self->maniaControl->chat->sendSuccess($message, $player->login); - break; - case BillManager::PLAYER_REFUSED_DONATION: - $message = 'Transaction cancelled.'; - $self->maniaControl->chat->sendError($message, $player->login); - break; - case BillManager::ERROR_WHILE_TRANSACTION: - $message = $data; - $self->maniaControl->chat->sendError($message, $player->login); - break; - } - }, $receiver, $amount, $message); - - return true; - } - - /** - * Handle //getplanets command - * - * @param array $chatCallback - * @param Player $player - * @return bool - */ - public function command_GetPlanets(array $chatCallback, Player $player) { - if (!$this->maniaControl->authenticationManager->checkRight($player, AuthenticationManager::AUTH_LEVEL_ADMIN)) { - $this->maniaControl->authenticationManager->sendNotAllowed($player); - return false; - } - $planets = $this->maniaControl->client->getServerPlanets(); - $message = "This Server has {$planets} Planets!"; - return $this->maniaControl->chat->sendInformation($message, $player->login); - } - - /** - * Send an usage example for /donate to the player - * - * @param Player $player - * @return boolean - */ - private function sendDonateUsageExample(Player $player) { - $message = "Usage Example: '/donate 100'"; - return $this->maniaControl->chat->sendChat($message, $player->login); - } - - /** - * Send an usage example for /pay to the player - * - * @param Player $player - * @return boolean - */ - private function sendPayUsageExample(Player $player) { - $message = "Usage Example: '/pay 100 login'"; - return $this->maniaControl->chat->sendChat($message, $player->login); - } - - /** - * Handles the /topdons command - * - * @param array $chatCallback - * @param Player $player - */ - public function command_TopDons(array $chatCallback, Player $player) { - $this->showTopDonsList($player); - } - - /** - * Provides a ManiaLink overview with donators. - * - * @param Player $player - * @return null - */ - private function showTopDonsList(Player $player) { - $stats = $this->maniaControl->statisticManager->getStatsRanking(self::STAT_PLAYER_DONATIONS); - - $width = $this->maniaControl->manialinkManager->styleManager->getListWidgetsWidth(); - $height = $this->maniaControl->manialinkManager->styleManager->getListWidgetsHeight(); - - // create manialink - $maniaLink = new ManiaLink(ManialinkManager::MAIN_MLID); - $script = $maniaLink->getScript(); - $paging = new Paging(); - $script->addFeature($paging); - - // Main frame - $frame = $this->maniaControl->manialinkManager->styleManager->getDefaultListFrame($script, $paging); - $maniaLink->add($frame); - - // Start offsets - $x = -$width / 2; - $y = $height / 2; - - //Predefine description Label - $descriptionLabel = $this->maniaControl->manialinkManager->styleManager->getDefaultDescriptionLabel(); - $frame->add($descriptionLabel); - - // Headline - $headFrame = new Frame(); - $frame->add($headFrame); - $headFrame->setY($y - 5); - $array = array('$oId' => $x + 5, '$oNickname' => $x + 18, '$oDonated planets' => $x + 70); - $this->maniaControl->manialinkManager->labelLine($headFrame, $array); - - $i = 1; - $y = $y - 10; - $pageFrames = array(); - foreach($stats as $playerIndex => $donations) { - if (!isset($pageFrame)) { - $pageFrame = new Frame(); - $frame->add($pageFrame); - if (!empty($pageFrames)) { - $pageFrame->setVisible(false); - } - array_push($pageFrames, $pageFrame); - $y = $height / 2 - 10; - $paging->addPage($pageFrame); - } - - - $playerFrame = new Frame(); - $pageFrame->add($playerFrame); - $playerFrame->setY($y); - - if ($i % 2 != 0) { - $lineQuad = new Quad_BgsPlayerCard(); - $playerFrame->add($lineQuad); - $lineQuad->setSize($width, 4); - $lineQuad->setSubStyle($lineQuad::SUBSTYLE_BgPlayerCardBig); - $lineQuad->setZ(0.001); - } - - $donatingPlayer = $this->maniaControl->playerManager->getPlayerByIndex($playerIndex); - $array = array($i => $x + 5, $donatingPlayer->nickname => $x + 18, $donations => $x + 70); - $this->maniaControl->manialinkManager->labelLine($playerFrame, $array); - - $y -= 4; - $i++; - if (($i - 1) % 15 == 0) { - unset($pageFrame); - } - - if($i > 100) { - break; - } - } - - // Render and display xml - $this->maniaControl->manialinkManager->displayWidget($maniaLink, $player, 'TopDons'); - } -} diff --git a/application/plugins/DynamicPointlimitPlugin.php b/application/plugins/DynamicPointlimitPlugin.php new file mode 100644 index 00000000..064be0f6 --- /dev/null +++ b/application/plugins/DynamicPointlimitPlugin.php @@ -0,0 +1,153 @@ +settingManager->initSetting(get_class(), self::ACCEPT_OTHER_MODES, false); + $maniaControl->settingManager->initSetting(get_class(), self::DYNPNT_MULTIPLIER, 10); + $maniaControl->settingManager->initSetting(get_class(), self::DYNPNT_OFFSET, 0); + $maniaControl->settingManager->initSetting(get_class(), self::DYNPNT_MIN, 30); + $maniaControl->settingManager->initSetting(get_class(), self::DYNPNT_MAX, 200); + } + + /** + * Private properties + */ + /** @var ManiaControl $maniaControl */ + private $maniaControl = null; + + /** + * Load the plugin + * + * @param \ManiaControl\ManiaControl $maniaControl + * @throws Exception + * @return bool + */ + public function load(ManiaControl $maniaControl) { + $this->maniaControl = $maniaControl; + + $this->maniaControl->callbackManager->registerCallbackListener(PlayerManager::CB_PLAYERCONNECT, $this, 'changePointlimit'); + $this->maniaControl->callbackManager->registerCallbackListener(PlayerManager::CB_PLAYERDISCONNECT, $this, 'changePointlimit'); + + $allowOthers = $this->maniaControl->settingManager->getSetting($this, self::ACCEPT_OTHER_MODES); + if (!$allowOthers && $this->maniaControl->server->titleId != 'SMStormRoyal@nadeolabs') { + $error = 'This plugin only supports Royal (check Settings)!'; + throw new Exception($error); + } + } + + /** + * Unload the plugin and its resources + */ + public function unload() { + $this->maniaControl->callbackManager->unregisterCallbackListener($this); + + unset($this->maniaControl); + } + + /** + * Get plugin id + * + * @return int + */ + public static function getId() { + return self::ID; + } + + /** + * Get Plugin Name + * + * @return string + */ + public static function getName() { + return 'Dynamic Pointlimit Plugin'; + } + + /** + * Get Plugin Version + * + * @return float + */ + public static function getVersion() { + return self::VERSION; + } + + /** + * Get Plugin Author + * + * @return string + */ + public static function getAuthor() { + return 'TheM'; + } + + /** + * Get Plugin Description + * + * @return string + */ + public static function getDescription() { + return 'Plugin offers a dynamic pointlimit according to the amount of players on the server.'; + } + + /** + * Function called on player connect and disconnect, changing the pointlimit. + * + * @param Player $player + */ + public function changePointlimit(Player $player) { + $numberOfPlayers = 0; + $numberOfSpectators = 0; + + /** @var Player $player */ + foreach($this->maniaControl->playerManager->getPlayers() as $player) { + if ($player->isSpectator) { + $numberOfSpectators++; + } else { + $numberOfPlayers++; + } + } + + $pointlimit = ($numberOfPlayers * $this->maniaControl->settingManager->getSetting($this, self::DYNPNT_MULTIPLIER)) + $this->maniaControl->settingManager->getSetting($this, self::DYNPNT_OFFSET); + + $min_value = $this->maniaControl->settingManager->getSetting($this, self::DYNPNT_MIN); + $max_value = $this->maniaControl->settingManager->getSetting($this, self::DYNPNT_MAX); + if ($pointlimit < $min_value) { + $pointlimit = $min_value; + } + if ($pointlimit > $max_value) { + $pointlimit = $max_value; + } + + $this->maniaControl->client->setModeScriptSettings(array('S_MapPointsLimit' => $pointlimit)); + } +} \ No newline at end of file diff --git a/application/plugins/Endurance.php b/application/plugins/Endurance.php new file mode 100644 index 00000000..e69de29b diff --git a/application/plugins/EndurancePlugin.php b/application/plugins/EndurancePlugin.php new file mode 100644 index 00000000..e69de29b diff --git a/application/plugins/Karma.php b/application/plugins/Karma.php index 188e09c6..e69de29b 100644 --- a/application/plugins/Karma.php +++ b/application/plugins/Karma.php @@ -1,988 +0,0 @@ - - * @copyright 2014 ManiaControl Team - * @license http://www.gnu.org/licenses/ GNU General Public License, Version 3 - */ -class KarmaPlugin implements CallbackListener, TimerListener, Plugin { - /* - * Constants - */ - const ID = 2; - const VERSION = 0.1; - const MLID_KARMA = 'KarmaPlugin.MLID'; - const TABLE_KARMA = 'mc_karma'; - const CB_KARMA_CHANGED = 'KarmaPlugin.Changed'; - const CB_KARMA_MXUPDATED = 'KarmaPlugin.MXUpdated'; - const SETTING_AVAILABLE_VOTES = 'Available Votes (X-Y: Comma separated)'; - const SETTING_WIDGET_ENABLE = 'Enable Karma Widget'; - const SETTING_WIDGET_TITLE = 'Widget-Title'; - const SETTING_WIDGET_POSX = 'Widget-Position: X'; - const SETTING_WIDGET_POSY = 'Widget-Position: Y'; - const SETTING_WIDGET_WIDTH = 'Widget-Size: Width'; - const SETTING_WIDGET_HEIGHT = 'Widget-Size: Height'; - const SETTING_NEWKARMA = 'Enable "new karma" (percentage), disable = RASP karma'; - const STAT_PLAYER_MAPVOTES = 'Voted Maps'; - - /* - * Constants MX Karma - */ - const SETTING_WIDGET_DISPLAY_MX = 'Display MX-Karma in Widget'; - const SETTING_MX_KARMA_ACTIVATED = 'Activate MX-Karma'; - const SETTING_MX_KARMA_IMPORTING = 'Import old MX-Karmas'; - const MX_IMPORT_TABLE = 'mc_karma_mximport'; - const MX_KARMA_URL = 'http://karma.mania-exchange.com/api2/'; - const MX_KARMA_STARTSESSION = 'startSession'; - const MX_KARMA_ACTIVATESESSION = 'activateSession'; - const MX_KARMA_SAVEVOTES = 'saveVotes'; - const MX_KARMA_GETMAPRATING = 'getMapRating'; - - /* - * Private Properties - */ - /** - * @var ManiaControl $maniaControl - */ - private $maniaControl = null; - private $updateManialink = false; - /** - * @var ManiaLink $manialink - */ - private $manialink = null; - private $mxKarma = array(); - - /** - * @see \ManiaControl\Plugins\Plugin - */ - public static function prepare(ManiaControl $maniaControl) { - $maniaControl->settingManager->initSetting(get_class(), self::SETTING_MX_KARMA_ACTIVATED, true); - $maniaControl->settingManager->initSetting(get_class(), self::SETTING_MX_KARMA_IMPORTING, true); - $maniaControl->settingManager->initSetting(get_class(), self::SETTING_WIDGET_DISPLAY_MX, true); - $servers = $maniaControl->server->getAllServers(); - foreach ($servers as $server) { - $maniaControl->settingManager->initSetting(get_class(), '$l[http://karma.mania-exchange.com/auth/getapikey?server=' . $server->login . ']MX Karma Code for ' . $server->login . '$l', ''); - } - } - - /** - * @see \ManiaControl\Plugins\Plugin::getId() - */ - public static function getId() { - return self::ID; - } - - /** - * @see \ManiaControl\Plugins\Plugin::getName() - */ - public static function getName() { - return 'Karma Plugin'; - } - - /** - * @see \ManiaControl\Plugins\Plugin::getVersion() - */ - public static function getVersion() { - return self::VERSION; - } - - /** - * @see \ManiaControl\Plugins\Plugin::getAuthor() - */ - public static function getAuthor() { - return 'steeffeen and kremsy'; - } - - /** - * @see \ManiaControl\Plugins\Plugin::getDescription() - */ - public static function getDescription() { - return 'Plugin offering Karma Voting for Maps.'; - } - - /** - * @see \ManiaControl\Plugins\Plugin::load() - */ - public function load(ManiaControl $maniaControl) { - $this->maniaControl = $maniaControl; - - // Init database - $this->initTables(); - - // Init settings - $this->maniaControl->settingManager->initSetting($this, self::SETTING_AVAILABLE_VOTES, '-2,2'); - $this->maniaControl->settingManager->initSetting($this, self::SETTING_WIDGET_ENABLE, true); - $this->maniaControl->settingManager->initSetting($this, self::SETTING_WIDGET_TITLE, 'Map-Karma'); - $this->maniaControl->settingManager->initSetting($this, self::SETTING_WIDGET_POSX, 160 - 27.5); - $this->maniaControl->settingManager->initSetting($this, self::SETTING_WIDGET_POSY, 90 - 10 - 6); - $this->maniaControl->settingManager->initSetting($this, self::SETTING_WIDGET_WIDTH, 25.); - $this->maniaControl->settingManager->initSetting($this, self::SETTING_WIDGET_HEIGHT, 12.); - $this->maniaControl->settingManager->initSetting($this, self::SETTING_NEWKARMA, true); - - // Register for callbacks - $this->maniaControl->timerManager->registerTimerListening($this, 'handle1Second', 1000); - $this->maniaControl->callbackManager->registerCallbackListener(Callbacks::BEGINMAP, $this, 'handleBeginMap'); - $this->maniaControl->callbackManager->registerCallbackListener(Callbacks::BEGINMAP, $this, 'importMxKarmaVotes'); - $this->maniaControl->callbackManager->registerCallbackListener(Callbacks::ENDMAP, $this, 'sendMxKarmaVotes'); - $this->maniaControl->callbackManager->registerCallbackListener(PlayerManager::CB_PLAYERCONNECT, $this, 'handlePlayerConnect'); - $this->maniaControl->callbackManager->registerCallbackListener(CallbackManager::CB_MP_PLAYERCHAT, $this, 'handlePlayerChat'); - $this->maniaControl->callbackManager->registerCallbackListener(SettingManager::CB_SETTINGS_CHANGED, $this, 'updateSettings'); - - // Define player stats - $this->maniaControl->statisticManager->defineStatMetaData(self::STAT_PLAYER_MAPVOTES); - - // Register Stat in Simple StatsList - $this->maniaControl->statisticManager->simpleStatsList->registerStat(self::STAT_PLAYER_MAPVOTES, 100, "VM"); - - $this->updateManialink = true; - - // Open MX-Karma Session - $this->mxKarmaOpenSession(); - $this->mxKarma['startTime'] = time(); - - return true; - } - - /** - * Create necessary database tables - */ - private function initTables() { - $mysqli = $this->maniaControl->database->mysqli; - - // Create local table - $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` float NOT NULL DEFAULT '-1', - `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;"; - $mysqli->query($query); - if ($mysqli->error) { - trigger_error($mysqli->error, E_USER_ERROR); - } - - // Migrate settings - $this->maniaControl->database->migrationHelper->transferSettings('KarmaPlugin', $this); - - if (!$this->maniaControl->settingManager->getSetting($this, self::SETTING_MX_KARMA_ACTIVATED)) { - return; - } - - // Create mx table - $query = "CREATE TABLE IF NOT EXISTS `" . self::MX_IMPORT_TABLE . "` ( - `index` int(11) NOT NULL AUTO_INCREMENT, - `mapIndex` int(11) NOT NULL, - `mapImported` tinyint(1) NOT NULL, - `time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, - PRIMARY KEY (`index`), - UNIQUE KEY `mapIndex` (`mapIndex`) - ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COMMENT='MX Karma Import Table' AUTO_INCREMENT=1;"; - $mysqli->query($query); - if ($mysqli->error) { - trigger_error($mysqli->error, E_USER_ERROR); - } - } - - /** - * Open a Mx Karma Session - */ - private function mxKarmaOpenSession() { - if (!$this->maniaControl->settingManager->getSetting($this, self::SETTING_MX_KARMA_ACTIVATED)) { - return; - } - - $serverLogin = $this->maniaControl->server->login; - $mxKarmaCode = $this->maniaControl->settingManager->getSetting($this, '$l[http://karma.mania-exchange.com/auth/getapikey?server=' . $serverLogin . ']MX Karma Code for ' . $serverLogin . '$l'); - - if ($mxKarmaCode == '') { - return; - } - - $applicationIdentifier = 'ManiaControl v' . ManiaControl::VERSION; - $testMode = 'true'; - - $query = self::MX_KARMA_URL . self::MX_KARMA_STARTSESSION; - $query .= '?serverLogin=' . $serverLogin; - $query .= '&applicationIdentifier=' . urlencode($applicationIdentifier); - $query .= '&testMode=' . $testMode; - - $this->mxKarma['connectionInProgress'] = true; - - $self = $this; - $this->maniaControl->fileReader->loadFile($query, function ($data, $error) use (&$self, $mxKarmaCode) { - if (!$error) { - $data = json_decode($data); - if ($data->success) { - $self->mxKarma['session'] = $data->data; - $self->activateSession($mxKarmaCode); - } else { - $self->maniaControl->log("Error while authenticating on Mania-Exchange Karma"); - // TODO remove temp trigger - $self->maniaControl->errorHandler->triggerDebugNotice("Error while authenticating on Mania-Exchange Karma " . $data->data->message); - $self->mxKarma['connectionInProgress'] = false; - } - } else { - $self->maniaControl->log($error); - // TODO remove temp trigger - $self->maniaControl->errorHandler->triggerDebugNotice("Error while authenticating on Mania-Exchange Karma " . $error); - $self->mxKarma['connectionInProgress'] = false; - } - }, "application/json", 1000); - } - - /** - * Activates the MX-Karma Session - * - * @param $mxKarmaCode - */ - private function activateSession($mxKarmaCode) { - $hash = $this->buildActivationHash($this->mxKarma['session']->sessionSeed, $mxKarmaCode); - - $query = self::MX_KARMA_URL . self::MX_KARMA_ACTIVATESESSION; - $query .= '?sessionKey=' . urlencode($this->mxKarma['session']->sessionKey); - $query .= '&activationHash=' . urlencode($hash); - - $self = $this; - $this->maniaControl->fileReader->loadFile($query, function ($data, $error) use (&$self, $query) { - if (!$error) { - $data = json_decode($data); - if ($data->success && $data->data->activated) { - $self->maniaControl->log("Successfully authenticated on Mania-Exchange Karma"); - $self->mxKarma['connectionInProgress'] = false; - - // Fetch the Mx Karma Votes - $self->getMxKarmaVotes(); - } else { - $self->maniaControl->log("Error while authenticating on Mania-Exchange Karma " . $data->data->message); - // TODO remove temp trigger - $self->maniaControl->errorHandler->triggerDebugNotice("Error while authenticating on Mania-Exchange Karma " . $data->data->message . " url Query " . $query); - $self->mxKarma['connectionInProgress'] = false; - } - } else { - // TODO remove temp trigger - $self->maniaControl->errorHandler->triggerDebugNotice("Error while authenticating on Mania-Exchange Karma " . $error); - $self->maniaControl->log($error); - $self->mxKarma['connectionInProgress'] = false; - } - }, "application/json", 1000); - } - - /** - * Builds a sha512 activation Hash for the MX-Karma - * - * @param $sessionSeed - * @param $mxKey - * @return string - */ - private function buildActivationHash($sessionSeed, $mxKey) { - return hash('sha512', $mxKey . $sessionSeed); - } - - /** - * Fetch the mxKarmaVotes for the current map - */ - public function getMxKarmaVotes(Player $player = null) { - if (!$this->maniaControl->settingManager->getSetting($this, self::SETTING_MX_KARMA_ACTIVATED)) { - return; - } - - if (!isset($this->mxKarma['session'])) { - if (!isset($this->mxKarma['connectionInProgress']) || !$this->mxKarma['connectionInProgress']) { - $this->mxKarmaOpenSession(); - } - return; - } - - $map = $this->maniaControl->mapManager->getCurrentMap(); - - $properties = array(); - - $gameMode = $this->maniaControl->server->getGameMode(true); - if ($gameMode == 'Script') { - $scriptName = $this->maniaControl->client->getScriptName(); - $properties['gamemode'] = $scriptName["CurrentValue"]; - } else { - $properties['gamemode'] = $gameMode; - } - - $properties['titleid'] = $this->maniaControl->server->titleId; - $properties['mapuid'] = $map->uid; - - if (!$player) { - $properties['getvotesonly'] = false; - $properties['playerlogins'] = array(); - foreach ($this->maniaControl->playerManager->getPlayers() as $plyr) { - /** - * @var Player $player - */ - $properties['playerlogins'][] = $plyr->login; - } - } else { - $properties['getvotesonly'] = true; - $properties['playerlogins'] = array($player->login); - } - - $content = json_encode($properties); - $self = $this; - $this->maniaControl->fileReader->postData(self::MX_KARMA_URL . self::MX_KARMA_GETMAPRATING . "?sessionKey=" . urlencode($this->mxKarma['session']->sessionKey), function ($data, $error) use (&$self, &$player) { - if (!$error) { - $data = json_decode($data); - if ($data->success) { - - // Fetch averages if its for the whole server - if (!$player) { - $self->mxKarma["voteCount"] = $data->data->votecount; - $self->mxKarma["voteAverage"] = $data->data->voteaverage; - $self->mxKarma["modeVoteCount"] = $data->data->modevotecount; - $self->mxKarma["modeVoteAverage"] = $data->data->modevoteaverage; - } - - foreach ($data->data->votes as $votes) { - $self->mxKarma["votes"][$votes->login] = $votes->vote; - } - - $self->updateManialink = true; - $self->maniaControl->callbackManager->triggerCallback($self::CB_KARMA_MXUPDATED, $self->mxKarma); - $self->maniaControl->log("MX-Karma Votes successfully fetched"); - } else { - $self->maniaControl->log("Error while fetching votes: " . $data->data->message); - // TODO remove temp trigger - $self->maniaControl->errorHandler->triggerDebugNotice("Error while fetching votes: " . $data->data->message . " " . KarmaPlugin::MX_KARMA_URL . KarmaPlugin::MX_KARMA_SAVEVOTES . "?sessionKey=" . urlencode($self->mxKarma['session']->sessionKey)); - } - } else { - $self->maniaControl->log($error); - } - }, $content, false, 'application/json'); - } - - /** - * @see \ManiaControl\Plugins\Plugin::unload() - */ - public function unload() { - $this->maniaControl->manialinkManager->hideManialink(self::MLID_KARMA); - $this->maniaControl->callbackManager->unregisterCallbackListener($this); - $this->maniaControl->timerManager->unregisterTimerListenings($this); - unset($this->maniaControl); - } - - /** - * Handle BeginMap ManiaControl callback - * - * @param Map $map - */ - public function handleBeginMap(Map $map) { - // send Map Karma to MX from previous Map - if (isset($this->mxKarma['map'])) { - $votes = array(); - foreach ($this->mxKarma['votes'] as $login => $value) { - $player = $this->maniaControl->playerManager->getPlayer($login); - array_push($votes, array("login" => $login, "nickname" => $player->rawNickname, "vote" => $value)); - } - $this->postKarmaVotes($this->mxKarma['map'], $votes); - unset($this->mxKarma['map']); - } - - unset($this->mxKarma['votes']); - $this->mxKarma['startTime'] = time(); - $this->updateManialink = true; - - // Get Karma votes at begin of map - $this->getMxKarmaVotes(); - } - - /** - * Post the Karma votes to MX-Karma - * - * @param Map $map - * @param array $votes - * @param bool $import - */ - private function postKarmaVotes(Map $map, array $votes, $import = false) { - if (!isset($this->mxKarma['session'])) { - if (!isset($this->mxKarma['connectionInProgress']) || !$this->mxKarma['connectionInProgress']) { - $this->mxKarmaOpenSession(); - } - return; - } - - $gameMode = $this->maniaControl->server->getGameMode(true); - - if (count($votes) == 0) { - return; - } - - $properties = array(); - if ($gameMode == 'Script') { - $scriptName = $this->maniaControl->client->getScriptName(); - $properties['gamemode'] = $scriptName["CurrentValue"]; - } else { - $properties['gamemode'] = $gameMode; - } - - if ($import) { - $properties['maptime'] = 0; - } else { - $properties['maptime'] = time() - $this->mxKarma['startTime']; - } - - $properties['votes'] = $votes; - $properties['titleid'] = $this->maniaControl->server->titleId; - $properties['mapname'] = $map->rawName; - $properties['mapuid'] = $map->uid; - $properties['mapauthor'] = $map->authorLogin; - $properties['isimport'] = $import; - - $content = json_encode($properties); - - $self = $this; - $this->maniaControl->fileReader->postData(self::MX_KARMA_URL . self::MX_KARMA_SAVEVOTES . "?sessionKey=" . urlencode($this->mxKarma['session']->sessionKey), function ($data, $error) use (&$self) { - if (!$error) { - $data = json_decode($data); - if ($data->success) { - $self->maniaControl->log("Votes successfully permitted"); - } else { - $self->maniaControl->log("Error while updating votes: " . $data->data->message); - // TODO remove temp trigger - $self->maniaControl->errorHandler->triggerDebugNotice("Error while updating votes: " . $data->data->message . " " . KarmaPlugin::MX_KARMA_URL . $self::MX_KARMA_SAVEVOTES . "?sessionKey=" . urlencode($self->mxKarma['session']->sessionKey)); - } - } else { - $self->maniaControl->log($error); - } - }, $content, false, 'application/json'); - } - - /** - * Handle PlayerConnect callback - * - * @param \ManiaControl\Players\Player $player - */ - public function handlePlayerConnect(Player $player) { - if (!$player) { - return; - } - $this->queryManialinkUpdateFor($player); - - // Get Mx Karma Vote for Player - $this->getMxKarmaVotes($player); - } - - /** - * Query the player to update the manialink - * - * @param Player $player - */ - private function queryManialinkUpdateFor(Player $player) { - if ($this->updateManialink === true) { - return; - } - if (!is_array($this->updateManialink)) { - $this->updateManialink = array(); - } - $this->updateManialink[$player->login] = $player; - } - - /** - * Handle PlayerChat callback - * - * @param array $chatCallback - */ - public function handlePlayerChat(array $chatCallback) { - $login = $chatCallback[1][1]; - $player = $this->maniaControl->playerManager->getPlayer($login); - if (!$player) { - return; - } - $message = $chatCallback[1][2]; - if ($chatCallback[1][3]) { - $message = substr($message, 1); - } - if (preg_match('/[^+-]/', $message)) { - return; - } - $countPositive = substr_count($message, '+'); - $countNegative = substr_count($message, '-'); - if ($countPositive <= 0 && $countNegative <= 0) { - return; - } - $vote = $countPositive - $countNegative; - $success = $this->handleVote($player, $vote); - if (!$success) { - $this->maniaControl->chat->sendError('Error occurred.', $player->login); - return; - } - $this->maniaControl->chat->sendSuccess('Vote updated!', $player->login); - } - - /** - * Handle a vote done by a player - * - * @param Player $player - * @param int $vote - * @return bool - */ - private function handleVote(Player $player, $vote) { - // Check vote - $votesSetting = $this->maniaControl->settingManager->getSetting($this, self::SETTING_AVAILABLE_VOTES); - $votes = explode(',', $votesSetting); - $voteLow = intval($votes[0]); - $voteHigh = $voteLow + 2; - if (isset($votes[1])) { - $voteHigh = intval($votes[1]); - } - if ($vote < $voteLow || $vote > $voteHigh) { - return false; - } - - // Calculate actual voting - $vote -= $voteLow; - $voteHigh -= $voteLow; - $vote /= $voteHigh; - - // Save vote - $map = $this->maniaControl->mapManager->getCurrentMap(); - - // Update vote in MX karma array - if ($this->maniaControl->settingManager->getSetting($this, self::SETTING_MX_KARMA_ACTIVATED) && isset($this->mxKarma["session"])) { - if (!isset($this->mxKarma["votes"][$player->login])) { - $sum = $this->mxKarma["voteCount"] * $this->mxKarma["voteAverage"] + $vote * 100; - $this->mxKarma["voteCount"]++; - - $modeSum = $this->mxKarma["modeVoteCount"] * $this->mxKarma["modeVoteAverage"] + $vote * 100; - $this->mxKarma["modeVoteCount"]++; - } else { - $oldVote = $this->mxKarma["votes"][$player->login]; - $sum = $this->mxKarma["voteCount"] * $this->mxKarma["voteAverage"] - $oldVote + $vote * 100; - $modeSum = $this->mxKarma["modeVoteCount"] * $this->mxKarma["modeVoteAverage"] - $oldVote + $vote * 100; - } - - $this->mxKarma["voteAverage"] = $sum / $this->mxKarma["voteCount"]; - $this->mxKarma["modeVoteAverage"] = $modeSum / $this->mxKarma["modeVoteCount"]; - $this->mxKarma["votes"][$player->login] = $vote * 100; - } - - $voted = $this->getPlayerVote($player, $map); - if (!$voted) { - $this->maniaControl->statisticManager->incrementStat(self::STAT_PLAYER_MAPVOTES, $player, $this->maniaControl->server->index); - } - - $success = $this->savePlayerVote($player, $map, $vote); - if (!$success) { - return false; - } - $this->maniaControl->callbackManager->triggerCallback(self::CB_KARMA_CHANGED); - $this->updateManialink = true; - return true; - } - - /** - * Get the current vote of the player for the map - * - * @param Player $player - * @param Map $map - * @return int - */ - public function getPlayerVote(Player $player, Map $map) { - $mysqli = $this->maniaControl->database->mysqli; - $query = "SELECT * FROM `" . self::TABLE_KARMA . "` - WHERE `playerIndex` = {$player->index} - AND `mapIndex` = {$map->index} - AND `vote` >= 0;"; - $result = $mysqli->query($query); - if ($mysqli->error) { - trigger_error($mysqli->error); - return false; - } - if ($result->num_rows <= 0) { - $result->free(); - return false; - } - $item = $result->fetch_object(); - $result->free(); - $vote = $item->vote; - return floatval($vote); - } - - /** - * Save the vote of the player for the map - * - * @param Player $player - * @param Map $map - * @param float $vote - * @return bool - */ - private function savePlayerVote(Player $player, Map $map, $vote) { - $mysqli = $this->maniaControl->database->mysqli; - $query = "INSERT INTO `" . self::TABLE_KARMA . "` ( - `mapIndex`, - `playerIndex`, - `vote` - ) VALUES ( - {$map->index}, - {$player->index}, - {$vote} - ) ON DUPLICATE KEY UPDATE - `vote` = VALUES(`vote`);"; - $result = $mysqli->query($query); - if ($mysqli->error) { - trigger_error($mysqli->error); - return false; - } - - return $result; - } - - /** - * Get all players votes - * - * @param Map $map - * @return array - */ - public function getMapPlayerVotes(Map $map) { - $mysqli = $this->maniaControl->database->mysqli; - $query = "SELECT * FROM `" . self::TABLE_KARMA . "` - WHERE `mapIndex` = {$map->index} - AND `vote` >= 0"; - $result = $mysqli->query($query); - if ($mysqli->error) { - trigger_error($mysqli->error); - return false; - } - - $votes = array(); - while ($vote = $result->fetch_object()) { - $player = $this->maniaControl->playerManager->getPlayerByIndex($vote->playerIndex); - $karma = $vote->vote; - $votes[] = array('player' => $player, 'karma' => $karma); - } - - usort($votes, function ($a, $b) { - return $a['karma'] - $b['karma']; - }); - $votes = array_reverse($votes); - - return $votes; - } - - /** - * Update Settings - * - * @param $class - * @param $settingName - * @param $value - */ - public function updateSettings($class, $settingName, $value) { - if (!$class = get_class()) { - return; - } - - $serverLogin = $this->maniaControl->server->login; - if ($settingName == '$l[http://karma.mania-exchange.com/auth/getapikey?server=' . $serverLogin . ']MX Karma Code for ' . $serverLogin . '$l') { - $this->mxKarmaOpenSession(); - } - - if ($settingName == 'Enable Karma Widget' && $value == true) { - $this->updateManialink = true; - $this->handle1Second(time()); - } elseif ($settingName == 'Enable Karma Widget' && $value == false) { - $this->updateManialink = false; - $ml = new ManiaLink(self::MLID_KARMA); - $mltext = $ml->render()->saveXML(); - $this->maniaControl->manialinkManager->sendManialink($mltext); - } - } - - /** - * Handle ManiaControl 1 Second callback - * - * @param $time - */ - public function handle1Second($time) { - if (!$this->updateManialink) { - return; - } - - $displayMxKarma = $this->maniaControl->settingManager->getSetting($this, self::SETTING_WIDGET_DISPLAY_MX); - - // Get players - $players = $this->updateManialink; - if ($players === true) { - $players = $this->maniaControl->playerManager->getPlayers(); - } - $this->updateManialink = false; - - // Get map karma - $map = $this->maniaControl->mapManager->getCurrentMap(); - - // Display the mx Karma if the setting is choosen and the MX session is available - if ($displayMxKarma && isset($this->mxKarma['session']) && isset($this->mxKarma['voteCount'])) { - $karma = $this->mxKarma['modeVoteAverage'] / 100; - $voteCount = $this->mxKarma['modeVoteCount']; - } else { - $karma = $this->getMapKarma($map); - $votes = $this->getMapVotes($map); - $voteCount = $votes['count']; - } - - if ($this->maniaControl->settingManager->getSetting($this, self::SETTING_WIDGET_ENABLE)) { - // Build karma manialink - $this->buildManialink(); - - // Update karma gauge & label - /** - * @var Gauge $karmaGauge - */ - $karmaGauge = $this->manialink->karmaGauge; - /** - * @var Label $karmaLabel - */ - $karmaLabel = $this->manialink->karmaLabel; - if (is_numeric($karma) && $voteCount > 0) { - $karma = floatval($karma); - $karmaGauge->setRatio($karma + 0.15 - $karma * 0.15); - $karmaColor = ColorUtil::floatToStatusColor($karma); - $karmaGauge->setColor($karmaColor . '7'); - $karmaLabel->setText(' ' . round($karma * 100.) . '% (' . $voteCount . ')'); - } else { - $karmaGauge->setRatio(0.); - $karmaGauge->setColor('00fb'); - $karmaLabel->setText('-'); - } - - // Loop players - foreach ($players as $login => $player) { - // Get player vote - // TODO: show the player his own vote in some way - // $vote = $this->getPlayerVote($player, $map); - // $votesFrame = $this->manialink->votesFrame; - // $votesFrame->removeChildren(); - - // Send manialink - $this->maniaControl->manialinkManager->sendManialink($this->manialink, $login); - } - } - } - - /** - * Get the current karma of the map - * - * @param Map $map - * @return float | bool - */ - public function getMapKarma(Map $map) { - $mysqli = $this->maniaControl->database->mysqli; - $query = "SELECT AVG(`vote`) AS `karma` FROM `" . self::TABLE_KARMA . "` - WHERE `mapIndex` = {$map->index} - AND `vote` >= 0;"; - $result = $mysqli->query($query); - if ($mysqli->error) { - trigger_error($mysqli->error); - return false; - } - if ($result->num_rows <= 0) { - $result->free(); - return false; - } - $item = $result->fetch_object(); - $result->free(); - $karma = $item->karma; - if ($karma === null) { - return false; - } - return floatval($karma); - } - - /** - * Get the current Votes for the Map - * - * @param Map $map - * @return array - */ - public function getMapVotes(Map $map) { - $mysqli = $this->maniaControl->database->mysqli; - $query = "SELECT `vote`, COUNT(`vote`) AS `count` FROM `" . self::TABLE_KARMA . "` - WHERE `mapIndex` = {$map->index} - AND `vote` >= 0 - GROUP BY `vote`;"; - $result = $mysqli->query($query); - if ($mysqli->error) { - trigger_error($mysqli->error); - return false; - } - $votes = array(); - $count = 0; - while ($vote = $result->fetch_object()) { - $votes[$vote->vote] = $vote; - $count += $vote->count; - } - $votes['count'] = $count; - $result->free(); - return $votes; - } - - /** - * Build karma voting manialink if necessary - * - * @param bool $forceBuild - */ - private function buildManialink($forceBuild = false) { - if (is_object($this->manialink) && !$forceBuild) { - return; - } - - $title = $this->maniaControl->settingManager->getSetting($this, self::SETTING_WIDGET_TITLE); - $pos_x = $this->maniaControl->settingManager->getSetting($this, self::SETTING_WIDGET_POSX); - $pos_y = $this->maniaControl->settingManager->getSetting($this, self::SETTING_WIDGET_POSY); - $width = $this->maniaControl->settingManager->getSetting($this, self::SETTING_WIDGET_WIDTH); - $height = $this->maniaControl->settingManager->getSetting($this, self::SETTING_WIDGET_HEIGHT); - $labelStyle = $this->maniaControl->manialinkManager->styleManager->getDefaultLabelStyle(); - $quadStyle = $this->maniaControl->manialinkManager->styleManager->getDefaultQuadStyle(); - $quadSubstyle = $this->maniaControl->manialinkManager->styleManager->getDefaultQuadSubstyle(); - - $manialink = new ManiaLink(self::MLID_KARMA); - - $frame = new Frame(); - $manialink->add($frame); - $frame->setPosition($pos_x, $pos_y); - - $backgroundQuad = new Quad(); - $frame->add($backgroundQuad); - $backgroundQuad->setY($height * 0.15); - $backgroundQuad->setSize($width, $height); - $backgroundQuad->setStyles($quadStyle, $quadSubstyle); - - $titleLabel = new Label(); - $frame->add($titleLabel); - $titleLabel->setY($height * 0.36); - $titleLabel->setWidth($width * 0.85); - $titleLabel->setStyle($labelStyle); - $titleLabel->setTranslate(true); - $titleLabel->setTextSize(1); - $titleLabel->setScale(0.90); - $titleLabel->setText($title); - - $karmaGauge = new Gauge(); - $frame->add($karmaGauge); - $karmaGauge->setSize($width * 0.95, $height * 0.92); - $karmaGauge->setDrawBg(false); - $manialink->karmaGauge = $karmaGauge; - - $karmaLabel = new Label(); - $frame->add($karmaLabel); - $karmaLabel->setPosition(0, -0.4, 1); - $karmaLabel->setSize($width * 0.9, $height * 0.9); - $karmaLabel->setStyle($labelStyle); - $karmaLabel->setTextSize(1); - $manialink->karmaLabel = $karmaLabel; - - $votesFrame = new Frame(); - $frame->add($votesFrame); - $manialink->votesFrame = $votesFrame; - - $this->manialink = $manialink; - } - - /** - * Import old Karma votes to Mania-Exchange Karma - * - * @param Map $map - */ - public function importMxKarmaVotes(Map $map) { - if (!$this->maniaControl->settingManager->getSetting($this, self::SETTING_MX_KARMA_ACTIVATED)) { - return; - } - - if (!$this->maniaControl->settingManager->getSetting($this, self::SETTING_MX_KARMA_IMPORTING)) { - return; - } - - if (!isset($this->mxKarma['session'])) { - if (!isset($this->mxKarma['connectionInProgress']) || !$this->mxKarma['connectionInProgress']) { - $this->mxKarmaOpenSession(); - } - return; - } - - $mysqli = $this->maniaControl->database->mysqli; - $query = "SELECT mapImported FROM `" . self::MX_IMPORT_TABLE . "` WHERE `mapIndex` = {$map->index};"; - $result = $mysqli->query($query); - if ($mysqli->error) { - trigger_error($mysqli->error); - return; - } - $vote = $result->fetch_object(); - - if ($result->field_count == 0 || !$vote) { - $query = "SELECT vote, login, nickname FROM `" . self::TABLE_KARMA . "` k LEFT JOIN `" . PlayerManager::TABLE_PLAYERS . "` p ON (k.playerIndex=p.index) WHERE mapIndex = {$map->index}"; - $result2 = $mysqli->query($query); - if ($mysqli->error) { - trigger_error($mysqli->error); - return; - } - - $votes = array(); - while ($row = $result2->fetch_object()) { - array_push($votes, array("login" => $row->login, "nickname" => $row->nickname, "vote" => $row->vote * 100)); - } - - $this->postKarmaVotes($map, $votes, true); - - // Flag Map as Imported in database if it is a import - $query = "INSERT INTO `" . self::MX_IMPORT_TABLE . "` (`mapIndex`,`mapImported`) VALUES ({$map->index},true) ON DUPLICATE KEY UPDATE `mapImported` = true;"; - $mysqli->query($query); - if ($mysqli->error) { - trigger_error($mysqli->error); - } - - $result2->free(); - } - $result->free_result(); - - return; - } - - /** - * Save Mx Karma Votes at Mapend - */ - public function sendMxKarmaVotes(Map $map) { - if (!$this->maniaControl->settingManager->getSetting($this, self::SETTING_MX_KARMA_ACTIVATED)) { - return; - } - - if (!isset($this->mxKarma['session'])) { - if (!isset($this->mxKarma['connectionInProgress']) || !$this->mxKarma['connectionInProgress']) { - $this->mxKarmaOpenSession(); - } - return; - } - - if (!isset($this->mxKarma['votes']) || count($this->mxKarma['votes']) == 0) { - return; - } - - $this->mxKarma['map'] = $map; - } -} diff --git a/application/plugins/LocalRecords.php b/application/plugins/LocalRecords.php new file mode 100644 index 00000000..e69de29b diff --git a/application/plugins/MCTeam/ChatMessagePlugin.php b/application/plugins/MCTeam/ChatMessagePlugin.php new file mode 100644 index 00000000..99f084f5 --- /dev/null +++ b/application/plugins/MCTeam/ChatMessagePlugin.php @@ -0,0 +1,452 @@ + + * @copyright 2014 ManiaControl Team + * @license http://www.gnu.org/licenses/ GNU General Public License, Version 3 + */ +class ChatMessagePlugin implements CommandListener, Plugin { + /** + * Constants + */ + const PLUGIN_ID = 4; + const PLUGIN_VERSION = 0.1; + const PLUGIN_NAME = 'ChatMessagePlugin'; + const PLUGIN_AUTHOR = 'kremsy'; + const SETTING_AFK_FORCE_SPEC = 'AFK command forces spec'; + + /** + * Private properties + */ + /** + * @var maniaControl $maniaControl + */ + private $maniaControl = null; + + /** + * Prepares the Plugin + * + * @param ManiaControl $maniaControl + * @return mixed + */ + public static function prepare(ManiaControl $maniaControl) { + //do nothing + } + + /** + * Get plugin id + * + * @return int + */ + public static function getId() { + return self::PLUGIN_ID; + } + + /** + * Get Plugin Name + * + * @return string + */ + public static function getName() { + return self::PLUGIN_NAME; + } + + /** + * Get Plugin Version + * + * @return float,, + */ + public static function getVersion() { + return self::PLUGIN_VERSION; + } + + /** + * Get Plugin Author + * + * @return string + */ + public static function getAuthor() { + return self::PLUGIN_AUTHOR; + } + + /** + * Get Plugin Description + * + * @return string + */ + public static function getDescription() { + return "Plugin offers various Chat-Commands like /gg /hi /afk /rq..."; + } + + /** + * Load the plugin + * + * @param \ManiaControl\ManiaControl $maniaControl + * @return bool + */ + public function load(ManiaControl $maniaControl) { + $this->maniaControl = $maniaControl; + + $this->maniaControl->commandManager->registerCommandListener('me', $this, 'chat_me', false, 'Can be used to express your feelings/ideas.'); + $this->maniaControl->commandManager->registerCommandListener('hi', $this, 'chat_hi', false, 'Writes an hello message to the chat.'); + $this->maniaControl->commandManager->registerCommandListener(array('bb', 'bye'), $this, 'chat_bye', false, 'Writes a goodbye message to the chat.'); + $this->maniaControl->commandManager->registerCommandListener('thx', $this, 'chat_thx', false, 'Writes a thanks message to the chat.'); + $this->maniaControl->commandManager->registerCommandListener('gg', $this, 'chat_gg', false, 'Writes a good game message to the chat.'); + $this->maniaControl->commandManager->registerCommandListener('gl', $this, 'chat_gl', false, 'Writes a good luck message to the chat.'); + $this->maniaControl->commandManager->registerCommandListener('hf', $this, 'chat_hf', false, 'Writes an have fun message to the chat.'); + $this->maniaControl->commandManager->registerCommandListener('glhf', $this, 'chat_glhf', false, 'Writes a good luck, have fun message to the chat.'); + $this->maniaControl->commandManager->registerCommandListener('ns', $this, 'chat_ns', false, 'Writes a nice shot message to the chat.'); + $this->maniaControl->commandManager->registerCommandListener('n1', $this, 'chat_n1', false, 'Writes a nice one message to the chat.'); + $this->maniaControl->commandManager->registerCommandListener('lol', $this, 'chat_lol', false, 'Writes a lol message to the chat.'); + $this->maniaControl->commandManager->registerCommandListener('lool', $this, 'chat_lool', false, 'Writes a lool message to the chat.'); + $this->maniaControl->commandManager->registerCommandListener('brb', $this, 'chat_brb', false, 'Writes a be right back message to the chat.'); + $this->maniaControl->commandManager->registerCommandListener('bgm', $this, 'chat_bgm', false, 'Writes a bad game for me message to the chat.'); + $this->maniaControl->commandManager->registerCommandListener('afk', $this, 'chat_afk', false, 'Writes an away from keyboard message to the chat.'); + $this->maniaControl->commandManager->registerCommandListener(array('bm', 'bootme'), $this, 'chat_bootme', false, 'Gets you away from this server quickly!'); + $this->maniaControl->commandManager->registerCommandListener(array('rq', 'ragequit'), $this, 'chat_ragequit', false, 'Gets you away from this server in rage!'); + //TODO block commandlistener for muted people + $this->maniaControl->settingManager->initSetting($this, self::SETTING_AFK_FORCE_SPEC, true); + + return true; + } + + /** + * Unload the plugin and its resources + */ + public function unload() { + $this->maniaControl->commandManager->unregisterCommandListener($this); + unset($this->maniaControl); + } + + /** + * Builds a chat message starting with the player's nickname, can used to express emotions + * + * @param array $chat + * @param Player $player + */ + public function chat_me(array $chat, Player $player) { + $message = substr($chat[1][2], 4); + + $msg = '$<' . $player->nickname . '$>$s$i$fa0 ' . $message; + $this->maniaControl->chat->sendChat($msg, null, false); + } + + /** + * Hello Message + * + * @param array $chat + * @param Player $player + */ + public function chat_hi(array $chat, Player $player) { + $command = explode(" ", $chat[1][2]); + + if (isset($command[1])) { + $msg = '$ff0[$<' . $player->nickname . '$>] $ff0$iHello $z$<' . $this->getTarget($command[1]) . '$>$i!'; + } else { + $msg = '$ff0[$<' . $player->nickname . '$>] $ff0$iHello All!'; + } + $this->maniaControl->chat->sendChat($msg, null, false); + } + + /** + * Checks if a Player is in the PlayerList and returns the nickname if he is, can be called per login, pid or nickname or lj for + * (last joined) + * + * @param $login + * @return mixed + */ + private function getTarget($login) { + /** @var Player $player */ + $player = null; + foreach ($this->maniaControl->playerManager->getPlayers() as $player) { + if ($login == $player->login || $login == $player->pid || $login == $player->nickname) { + return $player->nickname; + } + } + + if ($player && $login == 'lj') { + return $player->nickname; + } + + //returns the text given if nothing matches + return $login; + } + + /** + * Bye Message + * + * @param array $chat + * @param Player $player + */ + public function chat_bye(array $chat, Player $player) { + $command = explode(" ", $chat[1][2]); + + if (isset($command[1])) { + $msg = '$ff0[$<' . $player->nickname . '$>] $ff0$iBye $z$<' . $this->getTarget($command[1]) . '$>$i!'; + } else { + $msg = '$ff0[$<' . $player->nickname . '$>] $ff0$iI have to go... Bye All!'; + } + + $this->maniaControl->chat->sendChat($msg, null, false); + } + + /** + * Thx Message + * + * @param array $chat + * @param Player $player + */ + public function chat_thx(array $chat, Player $player) { + $command = explode(" ", $chat[1][2]); + + if (isset($command[1])) { + $msg = '$ff0[$<' . $player->nickname . '$>] $ff0$iThanks $z$<' . $this->getTarget($command[1]) . '$>$i!'; + } else { + $msg = '$ff0[$<' . $player->nickname . '$>] $ff0$iThanks All!'; + } + + $this->maniaControl->chat->sendChat($msg, null, false); + } + + /** + * Good Game Message + * + * @param array $chat + * @param Player $player + */ + public function chat_gg(array $chat, Player $player) { + $command = explode(" ", $chat[1][2]); + + if (isset($command[1])) { + $msg = '$ff0[$<' . $player->nickname . '$>] $ff0$iGood Game $z$<' . $this->getTarget($command[1]) . '$>$i!'; + } else { + $msg = '$ff0[$<' . $player->nickname . '$>] $ff0$iGood Game All!'; + } + + $this->maniaControl->chat->sendChat($msg, null, false); + } + + /** + * Good Luck Message + * + * @param array $chat + * @param Player $player + */ + public function chat_gl(array $chat, Player $player) { + $command = explode(" ", $chat[1][2]); + + if (isset($command[1])) { + $msg = '$ff0[$<' . $player->nickname . '$>] $ff0$iGood Luck $z$<' . $this->getTarget($command[1]) . '$>$i!'; + } else { + $msg = '$ff0[$<' . $player->nickname . '$>] $ff0$iGood Luck All!'; + } + + $this->maniaControl->chat->sendChat($msg, null, false); + } + + /** + * Have Fun Message + * + * @param array $chat + * @param Player $player + */ + public function chat_hf(array $chat, Player $player) { + $command = explode(" ", $chat[1][2]); + + if (isset($command[1])) { + $msg = '$ff0[$<' . $player->nickname . '$>] $ff0$iHave Fun $z$<' . $this->getTarget($command[1]) . '$>$i!'; + } else { + $msg = '$ff0[$<' . $player->nickname . '$>] $ff0$iHave Fun All!'; + } + + $this->maniaControl->chat->sendChat($msg, null, false); + } + + /** + * Good Luck and Have Fun Message + * + * @param array $chat + * @param Player $player + */ + public function chat_glhf(array $chat, Player $player) { + $command = explode(" ", $chat[1][2]); + + if (isset($command[1])) { + $msg = '$ff0[$<' . $player->nickname . '$>] $ff0$iGood Luck and Have Fun $z$<' . $this->getTarget($command[1]) . '$>$i!'; + } else { + $msg = '$ff0[$<' . $player->nickname . '$>] $ff0$iGood Luck and Have Fun All!'; + } + + $this->maniaControl->chat->sendChat($msg, null, false); + } + + /** + * Nice Shot Message + * + * @param array $chat + * @param Player $player + */ + public function chat_ns(array $chat, Player $player) { + $command = explode(" ", $chat[1][2]); + + if (isset($command[1])) { + $msg = '$ff0[$<' . $player->nickname . '$>] $ff0$iNice Shot $z$<' . $this->getTarget($command[1]) . '$>$i!'; + } else { + $msg = '$ff0[$<' . $player->nickname . '$>] $ff0$iNice Shot!'; + } + + $this->maniaControl->chat->sendChat($msg, null, false); + } + + /** + * Nice one Message + * + * @param array $chat + * @param Player $player + */ + public function chat_n1(array $chat, Player $player) { + $command = explode(" ", $chat[1][2]); + + if (isset($command[1])) { + $msg = '$ff0[$<' . $player->nickname . '$>] $ff0$iNice One $z$<' . $this->getTarget($command[1]) . '$>$i!'; + } else { + $msg = '$ff0[$<' . $player->nickname . '$>] $ff0$iNice One!'; + } + + $this->maniaControl->chat->sendChat($msg, null, false); + } + + /** + * Lol! Message + * + * @param array $chat + * @param Player $player + */ + public function chat_lol(array $chat, Player $player) { + $msg = '$ff0[$<' . $player->nickname . '$>] $ff0$iLoL!'; + $this->maniaControl->chat->sendChat($msg, null, false); + } + + /** + * LooOOooL! Message + * + * @param array $chat + * @param Player $player + */ + public function chat_lool(array $chat, Player $player) { + $msg = '$ff0[$<' . $player->nickname . '$>] $ff0$iLooOOooL!'; + $this->maniaControl->chat->sendChat($msg, null, false); + } + + /** + * Be right back Message + * + * @param array $chat + * @param Player $player + */ + public function chat_brb(array $chat, Player $player) { + $msg = '$ff0[$<' . $player->nickname . '$>] $ff0$iBe Right Back!'; + $this->maniaControl->chat->sendChat($msg, null, false); + } + + /** + * Bad game for me Message + * + * @param array $chat + * @param Player $player + */ + public function chat_bgm(array $chat, Player $player) { + $msg = '$ff0[$<' . $player->nickname . '$>] $ff0$iBad Game for me :('; + $this->maniaControl->chat->sendChat($msg, null, false); + } + + /** + * Leave the server with an Bootme Message + * + * @param array $chat + * @param Player $player + */ + public function chat_bootme(array $chat, Player $player) { + $msg = '$i$ff0 $<' . $player->nickname . '$>$s$39f chooses to boot back to the real world!'; + $this->maniaControl->chat->sendChat($msg, null, true); + + $message = '$39F Thanks for Playing, see you around!$z'; + try { + $this->maniaControl->client->kick($player->login, $message); + } catch (Exception $e) { + $this->maniaControl->errorHandler->triggerDebugNotice("ChatMessagePlugin Debug Line 316: " . $e->getMessage()); + // TODO: only possible valid exception should be "wrong login" - throw others (like connection error) + $this->maniaControl->chat->sendError('Error occurred: ' . $e->getMessage(), $player->login); + return; + } + } + + /** + * Leave the server with an Ragequit + * + * @param array $chat + * @param Player $player + */ + public function chat_ragequit(array $chat, Player $player) { + $msg = '$i$ff0 $<' . $player->nickname . '$>$s$f00 said: "@"#!" and ragequitted!'; + $this->maniaControl->chat->sendChat($msg, null, true); + + $message = '$39F Thanks for Playing, please come back soon!$z '; + try { + $this->maniaControl->client->kick($player->login, $message); + } catch (Exception $e) { + $this->maniaControl->errorHandler->triggerDebugNotice("ChatMessagePlugin Debug Line " . $e->getLine() . ": " . $e->getMessage()); + // TODO: only possible valid exception should be "wrong login" - throw others (like connection error) + $this->maniaControl->chat->sendError('Error occurred: ' . $e->getMessage(), $player->login); + return; + } + } + + /** + * Afk Message and force player to spec + * + * @param array $chat + * @param Player $player + */ + public function chat_afk(array $chat, Player $player) { + $msg = '$ff0[$<' . $player->nickname . '$>] $ff0$iAway From Keyboard!'; + $this->maniaControl->chat->sendChat($msg, null, false); + + if ($this->maniaControl->settingManager->getSetting($this, self::SETTING_AFK_FORCE_SPEC)) { + if ($player->isSpectator) { + return; + } + + // force into spec + try { + $this->maniaControl->client->forceSpectator($player->login, 3); + } catch (Exception $e) { + $this->maniaControl->errorHandler->triggerDebugNotice("ChatMessagePlugin Debug Line " . $e->getLine() . ": " . $e->getMessage()); + // TODO: only possible valid exception should be "wrong login" - throw others (like connection error) + $this->maniaControl->chat->sendError('Error occurred: ' . $e->getMessage(), $player->login); + return; + } + + // free player slot + try { + $this->maniaControl->client->spectatorReleasePlayerSlot($player->login); + } catch (Exception $e) { + if ($e->getMessage() != 'The player is not a spectator') { + $this->maniaControl->errorHandler->triggerDebugNotice("ChatMessagePlugin Debug Line " . $e->getLine() . ": " . $e->getMessage()); + // TODO: only possible valid exception should be "wrong login" - throw others (like connection error) + //to nothing + } + } + } + } +} \ No newline at end of file diff --git a/application/plugins/MCTeam/CustomVotesPlugin.php b/application/plugins/MCTeam/CustomVotesPlugin.php new file mode 100644 index 00000000..8d48c789 --- /dev/null +++ b/application/plugins/MCTeam/CustomVotesPlugin.php @@ -0,0 +1,868 @@ +maniaControl = $maniaControl; + + $this->maniaControl->commandManager->registerCommandListener('vote', $this, 'chat_vote', false, 'Starts a new vote.'); + $this->maniaControl->timerManager->registerTimerListening($this, 'handle1Second', 1000); + $this->maniaControl->callbackManager->registerCallbackListener(ServerCommands::CB_VOTE_CANCELED, $this, 'handleVoteCanceled'); + $this->maniaControl->manialinkManager->registerManialinkPageAnswerListener(self::ACTION_POSITIVE_VOTE, $this, 'handlePositiveVote'); + $this->maniaControl->manialinkManager->registerManialinkPageAnswerListener(self::ACTION_NEGATIVE_VOTE, $this, 'handleNegativeVote'); + + $this->maniaControl->callbackManager->registerCallbackListener(CallbackManager::CB_MP_PLAYERMANIALINKPAGEANSWER, $this, 'handleManialinkPageAnswer'); + $this->maniaControl->callbackManager->registerCallbackListener(self::CB_CUSTOM_VOTE_FINISHED, $this, 'handleVoteFinished'); + $this->maniaControl->callbackManager->registerCallbackListener(PlayerManager::CB_PLAYERCONNECT, $this, 'handlePlayerConnect'); + $this->maniaControl->callbackManager->registerCallbackListener(Server::CB_TEAM_MODE_CHANGED, $this, 'constructMenu'); + + //Settings + $this->maniaControl->settingManager->initSetting($this, self::SETTING_VOTE_ICON_POSX, 156.); + $this->maniaControl->settingManager->initSetting($this, self::SETTING_VOTE_ICON_POSY, -38.6); + $this->maniaControl->settingManager->initSetting($this, self::SETTING_VOTE_ICON_WIDTH, 6); + $this->maniaControl->settingManager->initSetting($this, self::SETTING_VOTE_ICON_HEIGHT, 6); + + $this->maniaControl->settingManager->initSetting($this, self::SETTING_WIDGET_POSX, -80); //160 -15 + $this->maniaControl->settingManager->initSetting($this, self::SETTING_WIDGET_POSY, 80); //-15 + $this->maniaControl->settingManager->initSetting($this, self::SETTING_WIDGET_WIDTH, 50); //30 + $this->maniaControl->settingManager->initSetting($this, self::SETTING_WIDGET_HEIGHT, 20); //25 + + $this->maniaControl->settingManager->initSetting($this, self::SETTING_DEFAULT_RATIO, 0.75); + $this->maniaControl->settingManager->initSetting($this, self::SETTING_DEFAULT_PLAYER_RATIO, 0.65); + $this->maniaControl->settingManager->initSetting($this, self::SETTING_SPECTATOR_ALLOW_VOTE, false); + $this->maniaControl->settingManager->initSetting($this, self::SETTING_SPECTATOR_ALLOW_START_VOTE, false); + $this->maniaControl->settingManager->initSetting($this, self::SETTING_VOTE_TIME, 60); + + //Define Votes + $this->defineVote("teambalance", "Vote for Team Balance"); + $this->defineVote("skipmap", "Vote for Skip Map"); + $this->defineVote("nextmap", "Vote for Skip Map"); + $this->defineVote("skip", "Vote for Skip Map"); + $this->defineVote("restartmap", "Vote for Restart Map"); + $this->defineVote("restart", "Vote for Restart Map"); + $this->defineVote("pausegame", "Vote for Pause Game"); + $this->defineVote("replay", "Vote to replay current map"); + + foreach($this->voteCommands as $name => $voteCommand) { + $this->maniaControl->commandManager->registerCommandListener($name, $this, 'handleChatVote', false, $voteCommand->name); + } + + /* Disable Standard Votes */ + $array["Command"] = VoteRatio::COMMAND_BAN; + $array["Param"] = ""; + $array["Ratio"] = (float)-1; + $ratioArray[] = $array; + + $array["Command"] = VoteRatio::COMMAND_KICK; + $ratioArray[] = $array; + + $array["Command"] = VoteRatio::COMMAND_RESTART_MAP; + $ratioArray[] = $array; + + $array["Command"] = VoteRatio::COMMAND_TEAM_BALANCE; + $ratioArray[] = $array; + + $array["Command"] = VoteRatio::COMMAND_NEXT_MAP; + $ratioArray[] = $array; + + $this->maniaControl->client->setCallVoteRatiosEx(false, $ratioArray); + + $this->constructMenu(); + return true; + } + + /** + * Unload the plugin and its resources + */ + public function unload() { + //Enable Standard Votes + $defaultRatio = $this->maniaControl->client->getCallVoteRatio(); + + $array["Command"] = VoteRatio::COMMAND_BAN; + $array["Param"] = ""; + $array["Ratio"] = (float)$defaultRatio; + $ratioArray[] = $array; + $array["Command"] = VoteRatio::COMMAND_KICK; + $ratioArray[] = $array; + $array["Command"] = VoteRatio::COMMAND_RESTART_MAP; + $ratioArray[] = $array; + $array["Command"] = VoteRatio::COMMAND_TEAM_BALANCE; + $ratioArray[] = $array; + $array["Command"] = VoteRatio::COMMAND_NEXT_MAP; + $ratioArray[] = $array; + + $this->maniaControl->client->setCallVoteRatiosEx(false, $ratioArray); + + $this->destroyVote(); + $emptyManialink = new ManiaLink(self::MLID_ICON); + $this->maniaControl->manialinkManager->sendManialink($emptyManialink); + $this->maniaControl->commandManager->unregisterCommandListener($this); + $this->maniaControl->callbackManager->unregisterCallbackListener($this); + $this->maniaControl->manialinkManager->unregisterManialinkPageAnswerListener($this); + $this->maniaControl->timerManager->unregisterTimerListenings($this); + unset($this->maniaControl); + } + + /** + * Handle PlayerConnect callback + * + * @param Player $player + */ + public function handlePlayerConnect(Player $player) { + $this->showIcon($player->login); + } + + /** + * Add a new Vote Menu Item + * + * @param Control $control + * @param int $order + * @param string $description + */ + public function addVoteMenuItem(Control $control, $order = 0, $description = null) { + if (!isset($this->voteMenuItems[$order])) { + $this->voteMenuItems[$order] = array(); + array_push($this->voteMenuItems[$order], array($control, $description)); + krsort($this->voteMenuItems); + } + } + + /** + * Chat Vote + * + * @param array $chat + * @param Player $player + */ + public function chat_vote(array $chat, Player $player) { + $command = explode(" ", $chat[1][2]); + if (isset($command[1])) { + if (isset($this->voteCommands[$command[1]])) { + $this->startVote($player, strtolower($command[1])); + } + } + } + + /** + * Handle ManiaControl OnInit callback + * + * @internal param array $callback + */ + public function constructMenu() { + // Menu RestartMap + $itemQuad = new Quad_UIConstruction_Buttons(); + $itemQuad->setSubStyle($itemQuad::SUBSTYLE_Reload); + $itemQuad->setAction(self::ACTION_START_VOTE . 'restartmap'); + $this->addVoteMenuItem($itemQuad, 5, 'Vote for Restart-Map'); + + //Check if Pause exists in current GameMode + try { + $scriptInfos = $this->maniaControl->client->getModeScriptInfo(); + + $pauseExists = false; + foreach($scriptInfos->commandDescs as $param) { + if ($param->name == "Command_ForceWarmUp") { + $pauseExists = true; + break; + } + } + + // Menu Pause + if ($pauseExists) { + $itemQuad = new Quad_Icons128x32_1(); + $itemQuad->setSubStyle($itemQuad::SUBSTYLE_ManiaLinkSwitch); + $itemQuad->setAction(self::ACTION_START_VOTE . 'pausegame'); + $this->addVoteMenuItem($itemQuad, 10, 'Vote for a pause of Current Game'); + } + } catch(NotInScriptModeException $e) { + } + + //Menu SkipMap + $itemQuad = new Quad_Icons64x64_1(); + $itemQuad->setSubStyle($itemQuad::SUBSTYLE_ArrowFastNext); + $itemQuad->setAction(self::ACTION_START_VOTE . 'skipmap'); + $this->addVoteMenuItem($itemQuad, 15, 'Vote for a Mapskip'); + + if ($this->maniaControl->server->isTeamMode()) { + //Menu TeamBalance + $itemQuad = new Quad_Icons128x32_1(); + $itemQuad->setSubStyle($itemQuad::SUBSTYLE_RT_Team); + $itemQuad->setAction(self::ACTION_START_VOTE . 'teambalance'); + $this->addVoteMenuItem($itemQuad, 20, 'Vote for Team-Balance'); + } + //Show the Menu's icon + $this->showIcon(); + } + + /** + * Destroy the Vote on Canceled Callback + * + * @param Player $player + */ + public function handleVoteCanceled(Player $player) { + //reset vote + $this->destroyVote(); + } + + /** + * Handle Standard Votes + * + * @param $voteName + * @param $voteResult + */ + public function handleVoteFinished($voteName, $voteResult) { + if ($voteResult >= $this->currentVote->neededRatio) { + // Call Closure if one exists + if (is_callable($this->currentVote->function)) { + call_user_func($this->currentVote->function, $voteResult); + return; + } + + switch($voteName) { + case 'teambalance': + $this->maniaControl->client->autoTeamBalance(); + $this->maniaControl->chat->sendInformation('$f8fVote to $fffbalance the teams$f8f has been successfull!'); + break; + case 'skipmap': + case 'skip': + case 'nextmap': + $this->maniaControl->client->nextMap(); + $this->maniaControl->chat->sendInformation('$f8fVote to $fffskip the map$f8f has been successfull!'); + break; + case 'restartmap': + $this->maniaControl->client->restartMap(); + $this->maniaControl->chat->sendInformation('$f8fVote to $fffrestart the map$f8f has been successfull!'); + break; + case 'pausegame': + $this->maniaControl->client->sendModeScriptCommands(array('Command_ForceWarmUp' => True)); + $this->maniaControl->chat->sendInformation('$f8fVote to $fffpause the current game$f8f has been successfull!'); + break; + case 'replay': + $this->maniaControl->mapManager->mapQueue->addFirstMapToMapQueue($this->currentVote->voter, $this->maniaControl->mapManager->getCurrentMap()); + $this->maniaControl->chat->sendInformation('$f8fVote to $fffreplay the map$f8f has been successfull!'); + break; + } + } else { + $this->maniaControl->chat->sendError('Vote Failed!'); + } + } + + /** + * Handles the ManialinkPageAnswers and start a vote if a button in the panel got clicked + * + * @param array $callback + */ + public function handleManialinkPageAnswer(array $callback) { + $actionId = $callback[1][2]; + $actionArray = explode('.', $actionId); + if (count($actionArray) <= 2) { + return; + } + + $voteIndex = $actionArray[2]; + if (isset($this->voteCommands[$voteIndex])) { + $login = $callback[1][1]; + $player = $this->maniaControl->playerManager->getPlayer($login); + $this->startVote($player, $voteIndex); + } + } + + public function handleChatVote(array $chat, Player $player) { + $chatCommand = explode(' ', $chat[1][2]); + $chatCommand = $chatCommand[0]; + $chatCommand = str_replace('/', '', $chatCommand); + + if (isset($this->voteCommands[$chatCommand])) { + $this->startVote($player, $chatCommand); + } + } + + /** + * Defines a Vote + * + * @param $voteIndex + * @param $voteName + * @param bool $idBased + * @param $neededRatio + */ + public function defineVote($voteIndex, $voteName, $idBased = false, $startText = '', $neededRatio = -1) { + if ($neededRatio == -1) { + $neededRatio = $this->maniaControl->settingManager->getSetting($this, self::SETTING_DEFAULT_RATIO); + } + $voteCommand = new VoteCommand($voteIndex, $voteName, $idBased, $neededRatio); + $voteCommand->startText = $startText; + $this->voteCommands[$voteIndex] = $voteCommand; + } + + /** + * Undefines a Vote + * + * @param $voteIndex + */ + public function undefineVote($voteIndex) { + unset($this->voteCommands[$voteIndex]); + } + + + /** + * Starts a vote + * + * @param \ManiaControl\Players\Player $player + * @param $voteIndex + * @param $action + */ + public function startVote(Player $player, $voteIndex, $function = null) { + //Player is muted + if ($this->maniaControl->playerManager->playerActions->isPlayerMuted($player)) { + $this->maniaControl->chat->sendError('Muted Players are not allowed to start a vote.', $player->login); + return; + } + + //Specators are not allowed to start a vote + if ($player->isSpectator && !$this->maniaControl->settingManager->getSetting($this, self::SETTING_SPECTATOR_ALLOW_START_VOTE)) { + $this->maniaControl->chat->sendError('Spectators are not allowed to start a vote.', $player->login); + return; + } + + //Vote does not exist + if (!isset($this->voteCommands[$voteIndex])) { + $this->maniaControl->chat->sendError('Undefined vote.', $player->login); + return; + } + + //A vote is currently running + if (isset($this->currentVote)) { + $this->maniaControl->chat->sendError('There is currently another vote running.', $player->login); + return; + } + + $maxTime = $this->maniaControl->settingManager->getSetting($this, self::SETTING_VOTE_TIME); + + $this->currentVote = $this->voteCommands[$voteIndex]; + + $this->currentVote = new CurrentVote($this->voteCommands[$voteIndex], $player, time() + $maxTime); + $this->currentVote->neededRatio = floatval($this->maniaControl->settingManager->getSetting($this, self::SETTING_DEFAULT_RATIO)); + $this->currentVote->neededPlayerRatio = floatval($this->maniaControl->settingManager->getSetting($this, self::SETTING_DEFAULT_PLAYER_RATIO)); + $this->currentVote->function = $function; + + if ($this->currentVote->voteCommand->startText != '') { + $message = $this->currentVote->voteCommand->startText; + } else { + $message = '$fff$<' . $player->nickname . '$>$s$f8f started a $fff$<' . $this->currentVote->voteCommand->name . '$>$f8f!'; + } + + $this->maniaControl->chat->sendSuccess($message); + } + + /** + * Handles a Positive Vote + * + * @param array $callback + * @param Player $player + */ + public function handlePositiveVote(array $callback, Player $player) { + if (!isset($this->currentVote) || $player->isSpectator && !$this->maniaControl->settingManager->getSetting($this, self::SETTING_SPECTATOR_ALLOW_VOTE)) { + return; + } + + $this->currentVote->votePositive($player->login); + } + + /** + * Handles a negative Vote + * + * @param array $callback + * @param Player $player + */ + public function handleNegativeVote(array $callback, Player $player) { + if (!isset($this->currentVote) || $player->isSpectator && !$this->maniaControl->settingManager->getSetting($this, self::SETTING_SPECTATOR_ALLOW_VOTE)) { + return; + } + + $this->currentVote->voteNegative($player->login); + } + + /** + * Handle ManiaControl 1 Second callback + * + * @param $time + */ + public function handle1Second($time) { + if (!isset($this->currentVote)) { + return; + } + + $votePercentage = $this->currentVote->positiveVotes / $this->currentVote->getVoteCount(); + + $timeUntilExpire = $this->currentVote->expireTime - time(); + $this->showVoteWidget($timeUntilExpire, $votePercentage); + + $playerCount = $this->maniaControl->playerManager->getPlayerCount(); + $playersVoteRatio = (100 / $playerCount * $this->currentVote->getVoteCount()) / 100; + + //Check if vote is over + if ($timeUntilExpire <= 0 || (($playersVoteRatio >= $this->currentVote->neededPlayerRatio) && (($votePercentage >= $this->currentVote->neededRatio) || ($votePercentage <= 1 - $this->currentVote->neededRatio)))) { + // Trigger callback + $this->maniaControl->callbackManager->triggerCallback(self::CB_CUSTOM_VOTE_FINISHED, $this->currentVote->voteCommand->index, $votePercentage); + + //reset vote + $this->destroyVote(); + } + } + + /** + * Destroys the current Vote + */ + private function destroyVote() { + $emptyManialink = new ManiaLink(self::MLID_WIDGET); + $this->maniaControl->manialinkManager->sendManialink($emptyManialink); + + unset($this->currentVote); + } + + /** + * Shows the vote widget + * + * @param $timeUntilExpire + * @param $votePercentage + */ + private function showVoteWidget($timeUntilExpire, $votePercentage) { + $pos_x = $this->maniaControl->settingManager->getSetting($this, self::SETTING_WIDGET_POSX); + $pos_y = $this->maniaControl->settingManager->getSetting($this, self::SETTING_WIDGET_POSY); + $width = $this->maniaControl->settingManager->getSetting($this, self::SETTING_WIDGET_WIDTH); + $height = $this->maniaControl->settingManager->getSetting($this, self::SETTING_WIDGET_HEIGHT); + $maxTime = $this->maniaControl->settingManager->getSetting($this, self::SETTING_VOTE_TIME); + + $quadStyle = $this->maniaControl->manialinkManager->styleManager->getDefaultQuadStyle(); + $quadSubstyle = $this->maniaControl->manialinkManager->styleManager->getDefaultQuadSubstyle(); + $labelStyle = $this->maniaControl->manialinkManager->styleManager->getDefaultLabelStyle(); + + $maniaLink = new ManiaLink(self::MLID_WIDGET); + + // mainframe + $frame = new Frame(); + $maniaLink->add($frame); + $frame->setSize($width, $height); + $frame->setPosition($pos_x, $pos_y, 30); + + // Background Quad + $backgroundQuad = new Quad(); + $frame->add($backgroundQuad); + $backgroundQuad->setSize($width, $height); + $backgroundQuad->setStyles($quadStyle, $quadSubstyle); + + //Vote for label + $label = new Label_Text(); + $frame->add($label); + $label->setY($height / 2 - 3); + $label->setAlign(Control::CENTER, Control::CENTER); + $label->setSize($width - 5, $height); + $label->setTextSize(1.3); + $label->setText('$s ' . $this->currentVote->voteCommand->name); + + //Started by nick + $label = new Label_Text(); + $frame->add($label); + $label->setY($height / 2 - 6); + $label->setAlign(Control::CENTER, Control::CENTER); + $label->setSize($width - 5, 2); + $label->setTextSize(1); + $label->setTextColor("F80"); + $label->setText('$sStarted by ' . $this->currentVote->voter->nickname); + + //Time Gauge + $timeGauge = new Gauge(); + $frame->add($timeGauge); + $timeGauge->setY(1.5); + $timeGauge->setSize($width * 0.95, 6); + $timeGauge->setDrawBg(false); + if (!$timeUntilExpire) $timeUntilExpire = 1; + $timeGaugeRatio = (100 / $maxTime * $timeUntilExpire) / 100; + $timeGauge->setRatio($timeGaugeRatio + 0.15 - $timeGaugeRatio * 0.15); + $gaugeColor = ColorUtil::floatToStatusColor($timeGaugeRatio); + $timeGauge->setColor($gaugeColor . '9'); + + //Time Left + $label = new Label_Text(); + $frame->add($label); + $label->setY(0); + $label->setAlign(Control::CENTER, Control::CENTER); + $label->setSize($width - 5, $height); + $label->setTextSize(1.1); + $label->setText('$sTime left: ' . $timeUntilExpire . "s"); + $label->setTextColor("FFF"); + + //Vote Gauge + $voteGauge = new Gauge(); + $frame->add($voteGauge); + $voteGauge->setY(-4); + $voteGauge->setSize($width * 0.65, 12); + $voteGauge->setDrawBg(false); + $voteGauge->setRatio($votePercentage + 0.10 - $votePercentage * 0.10); + $gaugeColor = ColorUtil::floatToStatusColor($votePercentage); + $voteGauge->setColor($gaugeColor . '6'); + + $y = -4.4; + $voteLabel = new Label(); + $frame->add($voteLabel); + $voteLabel->setY($y); + $voteLabel->setSize($width * 0.65, 12); + $voteLabel->setStyle($labelStyle); + $voteLabel->setTextSize(1); + $voteLabel->setText(' ' . round($votePercentage * 100.) . '% (' . $this->currentVote->getVoteCount() . ')'); + + + $positiveQuad = new Quad_BgsPlayerCard(); + $frame->add($positiveQuad); + $positiveQuad->setPosition(-$width / 2 + 6, $y); + $positiveQuad->setSubStyle($positiveQuad::SUBSTYLE_BgPlayerCardBig); + $positiveQuad->setSize(5, 5); + + $positiveLabel = new Label_Button(); + $frame->add($positiveLabel); + $positiveLabel->setPosition(-$width / 2 + 6, $y); + $positiveLabel->setStyle($labelStyle); + $positiveLabel->setTextSize(1); + $positiveLabel->setSize(3, 3); + $positiveLabel->setTextColor("0F0"); + $positiveLabel->setText("F1"); + + $negativeQuad = clone $positiveQuad; + $frame->add($negativeQuad); + $negativeQuad->setX($width / 2 - 6); + + $negativeLabel = clone $positiveLabel; + $frame->add($negativeLabel); + $negativeLabel->setX($width / 2 - 6); + $negativeLabel->setTextColor("F00"); + $negativeLabel->setText("F2"); + + // Voting Actions + $positiveQuad->addActionTriggerFeature(self::ACTION_POSITIVE_VOTE); + $negativeQuad->addActionTriggerFeature(self::ACTION_NEGATIVE_VOTE); + + $script = $maniaLink->getScript(); + $keyActionPositive = new KeyAction(self::ACTION_POSITIVE_VOTE, 'F1'); + $script->addFeature($keyActionPositive); + $keyActionNegative = new KeyAction(self::ACTION_NEGATIVE_VOTE, 'F2'); + $script->addFeature($keyActionNegative); + + // Send manialink + $this->maniaControl->manialinkManager->sendManialink($maniaLink); + } + + /** + * Shows the Icon Widget + * + * @param bool $login + */ + private function showIcon($login = false) { + $posX = $this->maniaControl->settingManager->getSetting($this, self::SETTING_VOTE_ICON_POSX); + $posY = $this->maniaControl->settingManager->getSetting($this, self::SETTING_VOTE_ICON_POSY); + $width = $this->maniaControl->settingManager->getSetting($this, self::SETTING_VOTE_ICON_WIDTH); + $height = $this->maniaControl->settingManager->getSetting($this, self::SETTING_VOTE_ICON_HEIGHT); + $shootManiaOffset = $this->maniaControl->manialinkManager->styleManager->getDefaultIconOffsetSM(); + $quadStyle = $this->maniaControl->manialinkManager->styleManager->getDefaultQuadStyle(); + $quadSubstyle = $this->maniaControl->manialinkManager->styleManager->getDefaultQuadSubstyle(); + $itemMarginFactorX = 1.3; + $itemMarginFactorY = 1.2; + + //If game is shootmania lower the icons position by 20 + if($this->maniaControl->mapManager->getCurrentMap()->getGame() == 'sm') { + $posY -= $shootManiaOffset; + } + + $itemSize = $width; + + $maniaLink = new ManiaLink(self::MLID_ICON); + + //Custom Vote Menu Iconsframe + $frame = new Frame(); + $maniaLink->add($frame); + $frame->setPosition($posX, $posY); + + $backgroundQuad = new Quad(); + $frame->add($backgroundQuad); + $backgroundQuad->setSize($width * $itemMarginFactorX, $height * $itemMarginFactorY); + $backgroundQuad->setStyles($quadStyle, $quadSubstyle); + + $iconFrame = new Frame(); + $frame->add($iconFrame); + + $iconFrame->setSize($itemSize, $itemSize); + $itemQuad = new Quad_UIConstruction_Buttons(); + $itemQuad->setSubStyle($itemQuad::SUBSTYLE_Add); + $itemQuad->setSize($itemSize, $itemSize); + $iconFrame->add($itemQuad); + + //Define Description Label + $menuEntries = count($this->voteMenuItems); + $descriptionFrame = new Frame(); + $maniaLink->add($descriptionFrame); + $descriptionFrame->setPosition($posX - $menuEntries * $itemSize * 1.15 - 6, $posY); + + $descriptionLabel = new Label(); + $descriptionFrame->add($descriptionLabel); + $descriptionLabel->setAlign(Control::RIGHT, Control::TOP); + $descriptionLabel->setSize(40, 4); + $descriptionLabel->setTextSize(1.4); + $descriptionLabel->setTextColor('fff'); + + //Popout Frame + $popoutFrame = new Frame(); + $maniaLink->add($popoutFrame); + $popoutFrame->setPosition($posX - $itemSize * 0.5, $posY); + $popoutFrame->setHAlign(Control::RIGHT); + $popoutFrame->setSize(4 * $itemSize * $itemMarginFactorX, $itemSize * $itemMarginFactorY); + $popoutFrame->setVisible(false); + + $backgroundQuad = new Quad(); + $popoutFrame->add($backgroundQuad); + $backgroundQuad->setHAlign(Control::RIGHT); + $backgroundQuad->setStyles($quadStyle, $quadSubstyle); + $backgroundQuad->setSize($menuEntries * $itemSize * 1.15 + 2, $itemSize * $itemMarginFactorY); + + $itemQuad->addToggleFeature($popoutFrame); + + // Add items + $x = -1; + foreach($this->voteMenuItems as $menuItems) { + foreach($menuItems as $menuItem) { + $menuQuad = $menuItem[0]; + /** + * @var Quad $menuQuad + */ + $popoutFrame->add($menuQuad); + $menuQuad->setSize($itemSize, $itemSize); + $menuQuad->setX($x); + $menuQuad->setHAlign(Control::RIGHT); + $x -= $itemSize * 1.05; + + if ($menuItem[1]) { + $menuQuad->removeScriptFeatures(); + $description = '$s' . $menuItem[1]; + $menuQuad->addTooltipLabelFeature($descriptionLabel, $description); + } + } + } + + + // Send manialink + $this->maniaControl->manialinkManager->sendManialink($maniaLink, $login); + } + + + /** + * Get plugin id + * + * @return int + */ + public static function getId() { + return self::PLUGIN_ID; + } + + /** + * Get Plugin Name + * + * @return string + */ + public static function getName() { + return self::PLUGIN_NAME; + } + + /** + * Get Plugin Version + * + * @return float,, + */ + public static function getVersion() { + return self::PLUGIN_VERSION; + } + + /** + * Get Plugin Author + * + * @return string + */ + public static function getAuthor() { + return self::PLUGIN_AUTHOR; + } + + /** + * Get Plugin Description + * + * @return string + */ + public static function getDescription() { + return 'Plugin offers your Custom Votes like Restart, Skip, Balance...'; + } +} + +/** + * Vote Command Structure + */ +class VoteCommand { + public $index = ''; + public $name = ''; + public $neededRatio = 0; + public $idBased = false; + public $startText = ''; + + public function __construct($index, $name, $idBased, $neededRatio) { + $this->index = $index; + $this->name = $name; + $this->idBased = $idBased; + $this->neededRatio = $neededRatio; + } +} + +/** + * Current Vote Structure + */ +class CurrentVote { + const VOTE_FOR_ACTION = '1'; + const VOTE_AGAINST_ACTION = '-1'; + + public $voteCommand = null; + public $expireTime = 0; + public $positiveVotes = 0; + public $neededRatio = 0; + public $neededPlayerRatio = 0; + public $voter = null; + public $map = null; + public $player = null; + public $function = null; + + private $playersVoted = array(); + + public function __construct(VoteCommand $voteCommand, Player $voter, $expireTime) { + $this->expireTime = $expireTime; + $this->voteCommand = $voteCommand; + $this->voter = $voter; + $this->votePositive($voter->login); + } + + public function votePositive($login) { + if (isset($this->playersVoted[$login])) { + if ($this->playersVoted[$login] == self::VOTE_AGAINST_ACTION) { + $this->playersVoted[$login] = self::VOTE_FOR_ACTION; + $this->positiveVotes++; + } + } else { + $this->playersVoted[$login] = self::VOTE_FOR_ACTION; + $this->positiveVotes++; + } + } + + public function voteNegative($login) { + if (isset($this->playersVoted[$login])) { + if ($this->playersVoted[$login] == self::VOTE_FOR_ACTION) { + $this->playersVoted[$login] = self::VOTE_AGAINST_ACTION; + $this->positiveVotes--; + } + } else { + $this->playersVoted[$login] = self::VOTE_AGAINST_ACTION; + } + } + + public function getVoteCount() { + return count($this->playersVoted); + } + +} \ No newline at end of file diff --git a/application/plugins/MCTeam/DonationPlugin.php b/application/plugins/MCTeam/DonationPlugin.php new file mode 100644 index 00000000..4fe543a8 --- /dev/null +++ b/application/plugins/MCTeam/DonationPlugin.php @@ -0,0 +1,556 @@ +maniaControl = $maniaControl; + + // Register for commands + $this->maniaControl->commandManager->registerCommandListener('donate', $this, 'command_Donate', false, 'Donate some planets to the server.'); + $this->maniaControl->commandManager->registerCommandListener('pay', $this, 'command_Pay', true, 'Pays planets from the server to a player.'); + $this->maniaControl->commandManager->registerCommandListener('planets', $this, 'command_GetPlanets', true, 'Checks the planets-balance of the server.'); + $this->maniaControl->commandManager->registerCommandListener('topdons', $this, 'command_TopDons', false, 'Provides an overview of who dontated the most planets.'); + + // Register for callbacks + $this->maniaControl->callbackManager->registerCallbackListener(PlayerManager::CB_PLAYERCONNECT, $this, 'handlePlayerConnect'); + $this->maniaControl->callbackManager->registerCallbackListener(CallbackManager::CB_MP_PLAYERMANIALINKPAGEANSWER, $this, 'handleManialinkPageAnswer'); + + // Define player stats + $this->maniaControl->statisticManager->defineStatMetaData(self::STAT_PLAYER_DONATIONS); + + $this->maniaControl->settingManager->initSetting($this, self::SETTING_DONATE_WIDGET_ACTIVATED, true); + $this->maniaControl->settingManager->initSetting($this, self::SETTING_DONATE_WIDGET_POSX, 156.); + $this->maniaControl->settingManager->initSetting($this, self::SETTING_DONATE_WIDGET_POSY, -31.4); + $this->maniaControl->settingManager->initSetting($this, self::SETTING_DONATE_WIDGET_WIDTH, 6); + $this->maniaControl->settingManager->initSetting($this, self::SETTING_DONATE_WIDGET_HEIGHT, 6); + $this->maniaControl->settingManager->initSetting($this, self::SETTING_DONATION_VALUES, "20,50,100,500,1000,2000"); + $this->maniaControl->settingManager->initSetting($this, self::SETTING_MIN_AMOUNT_SHOWN, 100); + + // Register Stat in Simple StatsList + $this->maniaControl->statisticManager->simpleStatsList->registerStat(self::STAT_PLAYER_DONATIONS, 90, "DP", 15); + + $this->displayWidget(); + return true; + } + + /** + * @see \ManiaControl\Plugins\Plugin::unload() + */ + public function unload() { + $emptyManialink = new ManiaLink(self::MLID_DONATE_WIDGET); + $this->maniaControl->manialinkManager->sendManialink($emptyManialink); + + $this->maniaControl->callbackManager->unregisterCallbackListener($this); + $this->maniaControl->commandManager->unregisterCommandListener($this); + unset($this->maniaControl); + } + + /** + * @see \ManiaControl\Plugins\Plugin::getId() + */ + public static function getId() { + return self::ID; + } + + /** + * @see \ManiaControl\Plugins\Plugin::getName() + */ + public static function getName() { + return 'Donations Plugin'; + } + + /** + * @see \ManiaControl\Plugins\Plugin::getVersion() + */ + public static function getVersion() { + return self::VERSION; + } + + /** + * @see \ManiaControl\Plugins\Plugin::getAuthor() + */ + public static function getAuthor() { + return 'steeffeen and kremsy'; + } + + /** + * @see \ManiaControl\Plugins\Plugin::getDescription() + */ + public static function getDescription() { + return 'Plugin offering commands like /donate, /pay and /planets and a donation widget.'; + } + + /** + * Handle ManiaControl OnStartup + * + * @param array $callback + */ + public function displayWidget() { + if ($this->maniaControl->settingManager->getSetting($this, self::SETTING_DONATE_WIDGET_ACTIVATED)) { + $this->displayDonateWidget(); + } + } + + /** + * Handle ManialinkPageAnswer Callback + * + * @param array $callback + */ + public function handleManialinkPageAnswer(array $callback) { + $actionId = $callback[1][2]; + $boolSetting = (strpos($actionId, self::ACTION_DONATE_VALUE) === 0); + if (!$boolSetting) { + return; + } + $login = $callback[1][1]; + $player = $this->maniaControl->playerManager->getPlayer($login); + $actionArray = explode(".", $callback[1][2]); + $this->handleDonation($player, intval($actionArray[2])); + } + + /** + * Handle PlayerConnect callback + * + * @param Player $player + */ + public function handlePlayerConnect(Player $player) { + // Display Map Widget + if ($this->maniaControl->settingManager->getSetting($this, self::SETTING_DONATE_WIDGET_ACTIVATED)) { + $this->displayDonateWidget($player->login); + } + } + + /** + * Displays the Donate Widget + * + * @param bool $login + */ + public function displayDonateWidget($login = false) { + $posX = $this->maniaControl->settingManager->getSetting($this, self::SETTING_DONATE_WIDGET_POSX); + $posY = $this->maniaControl->settingManager->getSetting($this, self::SETTING_DONATE_WIDGET_POSY); + $width = $this->maniaControl->settingManager->getSetting($this, self::SETTING_DONATE_WIDGET_WIDTH); + $height = $this->maniaControl->settingManager->getSetting($this, self::SETTING_DONATE_WIDGET_HEIGHT); + $values = $this->maniaControl->settingManager->getSetting($this, self::SETTING_DONATION_VALUES); + $shootManiaOffset = $this->maniaControl->manialinkManager->styleManager->getDefaultIconOffsetSM(); + $quadStyle = $this->maniaControl->manialinkManager->styleManager->getDefaultQuadStyle(); + $quadSubstyle = $this->maniaControl->manialinkManager->styleManager->getDefaultQuadSubstyle(); + $itemMarginFactorX = 1.3; + $itemMarginFactorY = 1.2; + + //If game is shootmania lower the icons position by 20 + if($this->maniaControl->mapManager->getCurrentMap()->getGame() == 'sm') { + $posY -= $shootManiaOffset; + } + + $itemSize = $width; + + $maniaLink = new ManiaLink(self::MLID_DONATE_WIDGET); + + // Donate Menu Icon Frame + $frame = new Frame(); + $maniaLink->add($frame); + $frame->setPosition($posX, $posY); + + $backgroundQuad = new Quad(); + $frame->add($backgroundQuad); + $backgroundQuad->setSize($width * $itemMarginFactorX, $height * $itemMarginFactorY); + $backgroundQuad->setStyles($quadStyle, $quadSubstyle); + + $iconFrame = new Frame(); + $frame->add($iconFrame); + + $iconFrame->setSize($itemSize, $itemSize); + $itemQuad = new Quad_Icons128x128_1(); + $itemQuad->setSubStyle($itemQuad::SUBSTYLE_Coppers); + $itemQuad->setSize($itemSize, $itemSize); + $iconFrame->add($itemQuad); + + $valueArray = explode(",", $values); + + // Values Menu + $popoutFrame = new Frame(); + $maniaLink->add($popoutFrame); + $popoutFrame->setPosition($posX - $itemSize * 0.5, $posY); + $popoutFrame->setHAlign(Control::RIGHT); + $popoutFrame->setSize(4 * $itemSize * $itemMarginFactorX, $itemSize * $itemMarginFactorY); + $popoutFrame->setVisible(false); + + $quad = new Quad(); + $popoutFrame->add($quad); + $quad->setHAlign(Control::RIGHT); + $quad->setStyles($quadStyle, $quadSubstyle); + $quad->setSize(strlen($values) * 2 + count($valueArray) * 1, $itemSize * $itemMarginFactorY); + + $popoutFrame->add($quad); + $itemQuad->addToggleFeature($popoutFrame); + + // Description Label + $descriptionFrame = new Frame(); + $maniaLink->add($descriptionFrame); + $descriptionFrame->setPosition($posX - 50, $posY - 5); + $descriptionFrame->setHAlign(Control::RIGHT); + + $descriptionLabel = new Label(); + $descriptionFrame->add($descriptionLabel); + $descriptionLabel->setAlign(Control::LEFT, Control::TOP); + $descriptionLabel->setSize(40, 4); + $descriptionLabel->setTextSize(2); + $descriptionLabel->setVisible(true); + $descriptionLabel->setTextColor("0F0"); + + // Add items + $x = -2; + foreach(array_reverse($valueArray) as $value) { + $label = new Label_Button(); + $popoutFrame->add($label); + $label->setX($x); + $label->setHAlign(Control::RIGHT); + $label->setText('$s$FFF' . $value . '$09FP'); + $label->setTextSize(1.2); + $label->setAction(self::ACTION_DONATE_VALUE . "." . $value); + $label->setStyle(Label_Text::STYLE_TextCardSmall); + $description = "Donate {$value} Planets"; + $label->addTooltipLabelFeature($descriptionLabel, $description); + + $x -= strlen($value) * 2 + 1.7; + } + + // Send manialink + $this->maniaControl->manialinkManager->sendManialink($maniaLink, $login); + } + + /** + * Handle /donate command + * + * @param array $chatCallback + * @param Player $player + * @return bool + */ + public function command_Donate(array $chatCallback, Player $player) { + $text = $chatCallback[1][2]; + $params = explode(' ', $text); + if (count($params) < 2) { + $this->sendDonateUsageExample($player); + return false; + } + $amount = (int)$params[1]; + if (!$amount || $amount <= 0) { + $this->sendDonateUsageExample($player); + return false; + } + if (count($params) >= 3) { + $receiver = $params[2]; + $receiverPlayer = $this->maniaControl->playerManager->getPlayer($receiver); + $receiverName = ($receiverPlayer ? $receiverPlayer->nickname : $receiver); + } else { + $receiver = ''; + $receiverName = $this->maniaControl->client->getServerName(); + } + + return $this->handleDonation($player, $amount, $receiver, $receiverName); + } + + /** + * Handles a Player Donate + * + * @param Player $player + * @param $value + */ + private function handleDonation(Player $player, $amount, $receiver = '', $receiverName = false) { + + if (!$receiverName) { + $serverName = $this->maniaControl->client->getServerName(); + $message = 'Donate ' . $amount . ' Planets to $<' . $serverName . '$>?'; + } else { + $message = 'Donate ' . $amount . ' Planets to $<' . $receiverName . '$>?'; + } + + //Send and Handle the Bill + $self = $this; + $this->maniaControl->billManager->sendBill(function ($data, $status) use (&$self, &$player, $amount, $receiver) { + switch($status) { + case BillManager::DONATED_TO_SERVER: + if ($self->maniaControl->settingManager->getSetting($self, DonationPlugin::SETTING_ANNOUNCE_SERVERDONATION, true) && $amount >= $self->maniaControl->settingManager->getSetting($self, DonationPlugin::SETTING_MIN_AMOUNT_SHOWN, true)) { + $login = null; + $message = '$<' . $player->nickname . '$> donated ' . $amount . ' Planets! Thanks.'; + } else { + $login = $player->login; + $message = 'Donation successful! Thanks.'; + } + $self->maniaControl->chat->sendSuccess($message, $login); + $self->maniaControl->statisticManager->insertStat(DonationPlugin::STAT_PLAYER_DONATIONS, $player, $self->maniaControl->server->index, $amount); + break; + case BillManager::DONATED_TO_RECEIVER: + $message = "Successfully donated {$amount} to '{$receiver}'!"; + $self->maniaControl->chat->sendSuccess($message, $player->login); + break; + case BillManager::PLAYER_REFUSED_DONATION: + $message = 'Transaction cancelled.'; + $self->maniaControl->chat->sendError($message, $player->login); + break; + case BillManager::ERROR_WHILE_TRANSACTION: + $message = $data; + $self->maniaControl->chat->sendError($message, $player->login); + break; + } + }, $player, $amount, $message); + + return true; + } + + /** + * Handle //pay command + * + * @param array $chatCallback + * @param Player $player + * @return bool + */ + public function command_Pay(array $chatCallback, Player $player) { + if (!$this->maniaControl->authenticationManager->checkRight($player, AuthenticationManager::AUTH_LEVEL_SUPERADMIN)) { + $this->maniaControl->authenticationManager->sendNotAllowed($player); + return false; + } + $text = $chatCallback[1][2]; + $params = explode(' ', $text); + if (count($params) < 2) { + $this->sendPayUsageExample($player); + return false; + } + $amount = (int)$params[1]; + if (!$amount || $amount <= 0) { + $this->sendPayUsageExample($player); + return false; + } + if (count($params) >= 3) { + $receiver = $params[2]; + } else { + $receiver = $player->login; + } + $message = 'Payout from $<' . $this->maniaControl->client->getServerName() . '$>.'; + + $self = $this; + $this->maniaControl->billManager->sendPlanets(function ($data, $status) use (&$self, &$player, $amount, $receiver) { + switch($status) { + case BillManager::PAYED_FROM_SERVER: + $message = "Successfully payed out {$amount} to '{$receiver}'!"; + $self->maniaControl->chat->sendSuccess($message, $player->login); + break; + case BillManager::PLAYER_REFUSED_DONATION: + $message = 'Transaction cancelled.'; + $self->maniaControl->chat->sendError($message, $player->login); + break; + case BillManager::ERROR_WHILE_TRANSACTION: + $message = $data; + $self->maniaControl->chat->sendError($message, $player->login); + break; + } + }, $receiver, $amount, $message); + + return true; + } + + /** + * Handle //getplanets command + * + * @param array $chatCallback + * @param Player $player + * @return bool + */ + public function command_GetPlanets(array $chatCallback, Player $player) { + if (!$this->maniaControl->authenticationManager->checkRight($player, AuthenticationManager::AUTH_LEVEL_ADMIN)) { + $this->maniaControl->authenticationManager->sendNotAllowed($player); + return false; + } + $planets = $this->maniaControl->client->getServerPlanets(); + $message = "This Server has {$planets} Planets!"; + return $this->maniaControl->chat->sendInformation($message, $player->login); + } + + /** + * Send an usage example for /donate to the player + * + * @param Player $player + * @return boolean + */ + private function sendDonateUsageExample(Player $player) { + $message = "Usage Example: '/donate 100'"; + return $this->maniaControl->chat->sendChat($message, $player->login); + } + + /** + * Send an usage example for /pay to the player + * + * @param Player $player + * @return boolean + */ + private function sendPayUsageExample(Player $player) { + $message = "Usage Example: '/pay 100 login'"; + return $this->maniaControl->chat->sendChat($message, $player->login); + } + + /** + * Handles the /topdons command + * + * @param array $chatCallback + * @param Player $player + */ + public function command_TopDons(array $chatCallback, Player $player) { + $this->showTopDonsList($player); + } + + /** + * Provides a ManiaLink overview with donators. + * + * @param Player $player + * @return null + */ + private function showTopDonsList(Player $player) { + $stats = $this->maniaControl->statisticManager->getStatsRanking(self::STAT_PLAYER_DONATIONS); + + $width = $this->maniaControl->manialinkManager->styleManager->getListWidgetsWidth(); + $height = $this->maniaControl->manialinkManager->styleManager->getListWidgetsHeight(); + + // create manialink + $maniaLink = new ManiaLink(ManialinkManager::MAIN_MLID); + $script = $maniaLink->getScript(); + $paging = new Paging(); + $script->addFeature($paging); + + // Main frame + $frame = $this->maniaControl->manialinkManager->styleManager->getDefaultListFrame($script, $paging); + $maniaLink->add($frame); + + // Start offsets + $x = -$width / 2; + $y = $height / 2; + + //Predefine description Label + $descriptionLabel = $this->maniaControl->manialinkManager->styleManager->getDefaultDescriptionLabel(); + $frame->add($descriptionLabel); + + // Headline + $headFrame = new Frame(); + $frame->add($headFrame); + $headFrame->setY($y - 5); + $array = array('$oId' => $x + 5, '$oNickname' => $x + 18, '$oDonated planets' => $x + 70); + $this->maniaControl->manialinkManager->labelLine($headFrame, $array); + + $i = 1; + $y = $y - 10; + $pageFrames = array(); + foreach($stats as $playerIndex => $donations) { + if (!isset($pageFrame)) { + $pageFrame = new Frame(); + $frame->add($pageFrame); + if (!empty($pageFrames)) { + $pageFrame->setVisible(false); + } + array_push($pageFrames, $pageFrame); + $y = $height / 2 - 10; + $paging->addPage($pageFrame); + } + + + $playerFrame = new Frame(); + $pageFrame->add($playerFrame); + $playerFrame->setY($y); + + if ($i % 2 != 0) { + $lineQuad = new Quad_BgsPlayerCard(); + $playerFrame->add($lineQuad); + $lineQuad->setSize($width, 4); + $lineQuad->setSubStyle($lineQuad::SUBSTYLE_BgPlayerCardBig); + $lineQuad->setZ(0.001); + } + + $donatingPlayer = $this->maniaControl->playerManager->getPlayerByIndex($playerIndex); + $array = array($i => $x + 5, $donatingPlayer->nickname => $x + 18, $donations => $x + 70); + $this->maniaControl->manialinkManager->labelLine($playerFrame, $array); + + $y -= 4; + $i++; + if (($i - 1) % 15 == 0) { + unset($pageFrame); + } + + if($i > 100) { + break; + } + } + + // Render and display xml + $this->maniaControl->manialinkManager->displayWidget($maniaLink, $player, 'TopDons'); + } +} diff --git a/application/plugins/MCTeam/KarmaPlugin.php b/application/plugins/MCTeam/KarmaPlugin.php new file mode 100644 index 00000000..188e09c6 --- /dev/null +++ b/application/plugins/MCTeam/KarmaPlugin.php @@ -0,0 +1,988 @@ + + * @copyright 2014 ManiaControl Team + * @license http://www.gnu.org/licenses/ GNU General Public License, Version 3 + */ +class KarmaPlugin implements CallbackListener, TimerListener, Plugin { + /* + * Constants + */ + const ID = 2; + const VERSION = 0.1; + const MLID_KARMA = 'KarmaPlugin.MLID'; + const TABLE_KARMA = 'mc_karma'; + const CB_KARMA_CHANGED = 'KarmaPlugin.Changed'; + const CB_KARMA_MXUPDATED = 'KarmaPlugin.MXUpdated'; + const SETTING_AVAILABLE_VOTES = 'Available Votes (X-Y: Comma separated)'; + const SETTING_WIDGET_ENABLE = 'Enable Karma Widget'; + const SETTING_WIDGET_TITLE = 'Widget-Title'; + const SETTING_WIDGET_POSX = 'Widget-Position: X'; + const SETTING_WIDGET_POSY = 'Widget-Position: Y'; + const SETTING_WIDGET_WIDTH = 'Widget-Size: Width'; + const SETTING_WIDGET_HEIGHT = 'Widget-Size: Height'; + const SETTING_NEWKARMA = 'Enable "new karma" (percentage), disable = RASP karma'; + const STAT_PLAYER_MAPVOTES = 'Voted Maps'; + + /* + * Constants MX Karma + */ + const SETTING_WIDGET_DISPLAY_MX = 'Display MX-Karma in Widget'; + const SETTING_MX_KARMA_ACTIVATED = 'Activate MX-Karma'; + const SETTING_MX_KARMA_IMPORTING = 'Import old MX-Karmas'; + const MX_IMPORT_TABLE = 'mc_karma_mximport'; + const MX_KARMA_URL = 'http://karma.mania-exchange.com/api2/'; + const MX_KARMA_STARTSESSION = 'startSession'; + const MX_KARMA_ACTIVATESESSION = 'activateSession'; + const MX_KARMA_SAVEVOTES = 'saveVotes'; + const MX_KARMA_GETMAPRATING = 'getMapRating'; + + /* + * Private Properties + */ + /** + * @var ManiaControl $maniaControl + */ + private $maniaControl = null; + private $updateManialink = false; + /** + * @var ManiaLink $manialink + */ + private $manialink = null; + private $mxKarma = array(); + + /** + * @see \ManiaControl\Plugins\Plugin + */ + public static function prepare(ManiaControl $maniaControl) { + $maniaControl->settingManager->initSetting(get_class(), self::SETTING_MX_KARMA_ACTIVATED, true); + $maniaControl->settingManager->initSetting(get_class(), self::SETTING_MX_KARMA_IMPORTING, true); + $maniaControl->settingManager->initSetting(get_class(), self::SETTING_WIDGET_DISPLAY_MX, true); + $servers = $maniaControl->server->getAllServers(); + foreach ($servers as $server) { + $maniaControl->settingManager->initSetting(get_class(), '$l[http://karma.mania-exchange.com/auth/getapikey?server=' . $server->login . ']MX Karma Code for ' . $server->login . '$l', ''); + } + } + + /** + * @see \ManiaControl\Plugins\Plugin::getId() + */ + public static function getId() { + return self::ID; + } + + /** + * @see \ManiaControl\Plugins\Plugin::getName() + */ + public static function getName() { + return 'Karma Plugin'; + } + + /** + * @see \ManiaControl\Plugins\Plugin::getVersion() + */ + public static function getVersion() { + return self::VERSION; + } + + /** + * @see \ManiaControl\Plugins\Plugin::getAuthor() + */ + public static function getAuthor() { + return 'steeffeen and kremsy'; + } + + /** + * @see \ManiaControl\Plugins\Plugin::getDescription() + */ + public static function getDescription() { + return 'Plugin offering Karma Voting for Maps.'; + } + + /** + * @see \ManiaControl\Plugins\Plugin::load() + */ + public function load(ManiaControl $maniaControl) { + $this->maniaControl = $maniaControl; + + // Init database + $this->initTables(); + + // Init settings + $this->maniaControl->settingManager->initSetting($this, self::SETTING_AVAILABLE_VOTES, '-2,2'); + $this->maniaControl->settingManager->initSetting($this, self::SETTING_WIDGET_ENABLE, true); + $this->maniaControl->settingManager->initSetting($this, self::SETTING_WIDGET_TITLE, 'Map-Karma'); + $this->maniaControl->settingManager->initSetting($this, self::SETTING_WIDGET_POSX, 160 - 27.5); + $this->maniaControl->settingManager->initSetting($this, self::SETTING_WIDGET_POSY, 90 - 10 - 6); + $this->maniaControl->settingManager->initSetting($this, self::SETTING_WIDGET_WIDTH, 25.); + $this->maniaControl->settingManager->initSetting($this, self::SETTING_WIDGET_HEIGHT, 12.); + $this->maniaControl->settingManager->initSetting($this, self::SETTING_NEWKARMA, true); + + // Register for callbacks + $this->maniaControl->timerManager->registerTimerListening($this, 'handle1Second', 1000); + $this->maniaControl->callbackManager->registerCallbackListener(Callbacks::BEGINMAP, $this, 'handleBeginMap'); + $this->maniaControl->callbackManager->registerCallbackListener(Callbacks::BEGINMAP, $this, 'importMxKarmaVotes'); + $this->maniaControl->callbackManager->registerCallbackListener(Callbacks::ENDMAP, $this, 'sendMxKarmaVotes'); + $this->maniaControl->callbackManager->registerCallbackListener(PlayerManager::CB_PLAYERCONNECT, $this, 'handlePlayerConnect'); + $this->maniaControl->callbackManager->registerCallbackListener(CallbackManager::CB_MP_PLAYERCHAT, $this, 'handlePlayerChat'); + $this->maniaControl->callbackManager->registerCallbackListener(SettingManager::CB_SETTINGS_CHANGED, $this, 'updateSettings'); + + // Define player stats + $this->maniaControl->statisticManager->defineStatMetaData(self::STAT_PLAYER_MAPVOTES); + + // Register Stat in Simple StatsList + $this->maniaControl->statisticManager->simpleStatsList->registerStat(self::STAT_PLAYER_MAPVOTES, 100, "VM"); + + $this->updateManialink = true; + + // Open MX-Karma Session + $this->mxKarmaOpenSession(); + $this->mxKarma['startTime'] = time(); + + return true; + } + + /** + * Create necessary database tables + */ + private function initTables() { + $mysqli = $this->maniaControl->database->mysqli; + + // Create local table + $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` float NOT NULL DEFAULT '-1', + `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;"; + $mysqli->query($query); + if ($mysqli->error) { + trigger_error($mysqli->error, E_USER_ERROR); + } + + // Migrate settings + $this->maniaControl->database->migrationHelper->transferSettings('KarmaPlugin', $this); + + if (!$this->maniaControl->settingManager->getSetting($this, self::SETTING_MX_KARMA_ACTIVATED)) { + return; + } + + // Create mx table + $query = "CREATE TABLE IF NOT EXISTS `" . self::MX_IMPORT_TABLE . "` ( + `index` int(11) NOT NULL AUTO_INCREMENT, + `mapIndex` int(11) NOT NULL, + `mapImported` tinyint(1) NOT NULL, + `time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (`index`), + UNIQUE KEY `mapIndex` (`mapIndex`) + ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COMMENT='MX Karma Import Table' AUTO_INCREMENT=1;"; + $mysqli->query($query); + if ($mysqli->error) { + trigger_error($mysqli->error, E_USER_ERROR); + } + } + + /** + * Open a Mx Karma Session + */ + private function mxKarmaOpenSession() { + if (!$this->maniaControl->settingManager->getSetting($this, self::SETTING_MX_KARMA_ACTIVATED)) { + return; + } + + $serverLogin = $this->maniaControl->server->login; + $mxKarmaCode = $this->maniaControl->settingManager->getSetting($this, '$l[http://karma.mania-exchange.com/auth/getapikey?server=' . $serverLogin . ']MX Karma Code for ' . $serverLogin . '$l'); + + if ($mxKarmaCode == '') { + return; + } + + $applicationIdentifier = 'ManiaControl v' . ManiaControl::VERSION; + $testMode = 'true'; + + $query = self::MX_KARMA_URL . self::MX_KARMA_STARTSESSION; + $query .= '?serverLogin=' . $serverLogin; + $query .= '&applicationIdentifier=' . urlencode($applicationIdentifier); + $query .= '&testMode=' . $testMode; + + $this->mxKarma['connectionInProgress'] = true; + + $self = $this; + $this->maniaControl->fileReader->loadFile($query, function ($data, $error) use (&$self, $mxKarmaCode) { + if (!$error) { + $data = json_decode($data); + if ($data->success) { + $self->mxKarma['session'] = $data->data; + $self->activateSession($mxKarmaCode); + } else { + $self->maniaControl->log("Error while authenticating on Mania-Exchange Karma"); + // TODO remove temp trigger + $self->maniaControl->errorHandler->triggerDebugNotice("Error while authenticating on Mania-Exchange Karma " . $data->data->message); + $self->mxKarma['connectionInProgress'] = false; + } + } else { + $self->maniaControl->log($error); + // TODO remove temp trigger + $self->maniaControl->errorHandler->triggerDebugNotice("Error while authenticating on Mania-Exchange Karma " . $error); + $self->mxKarma['connectionInProgress'] = false; + } + }, "application/json", 1000); + } + + /** + * Activates the MX-Karma Session + * + * @param $mxKarmaCode + */ + private function activateSession($mxKarmaCode) { + $hash = $this->buildActivationHash($this->mxKarma['session']->sessionSeed, $mxKarmaCode); + + $query = self::MX_KARMA_URL . self::MX_KARMA_ACTIVATESESSION; + $query .= '?sessionKey=' . urlencode($this->mxKarma['session']->sessionKey); + $query .= '&activationHash=' . urlencode($hash); + + $self = $this; + $this->maniaControl->fileReader->loadFile($query, function ($data, $error) use (&$self, $query) { + if (!$error) { + $data = json_decode($data); + if ($data->success && $data->data->activated) { + $self->maniaControl->log("Successfully authenticated on Mania-Exchange Karma"); + $self->mxKarma['connectionInProgress'] = false; + + // Fetch the Mx Karma Votes + $self->getMxKarmaVotes(); + } else { + $self->maniaControl->log("Error while authenticating on Mania-Exchange Karma " . $data->data->message); + // TODO remove temp trigger + $self->maniaControl->errorHandler->triggerDebugNotice("Error while authenticating on Mania-Exchange Karma " . $data->data->message . " url Query " . $query); + $self->mxKarma['connectionInProgress'] = false; + } + } else { + // TODO remove temp trigger + $self->maniaControl->errorHandler->triggerDebugNotice("Error while authenticating on Mania-Exchange Karma " . $error); + $self->maniaControl->log($error); + $self->mxKarma['connectionInProgress'] = false; + } + }, "application/json", 1000); + } + + /** + * Builds a sha512 activation Hash for the MX-Karma + * + * @param $sessionSeed + * @param $mxKey + * @return string + */ + private function buildActivationHash($sessionSeed, $mxKey) { + return hash('sha512', $mxKey . $sessionSeed); + } + + /** + * Fetch the mxKarmaVotes for the current map + */ + public function getMxKarmaVotes(Player $player = null) { + if (!$this->maniaControl->settingManager->getSetting($this, self::SETTING_MX_KARMA_ACTIVATED)) { + return; + } + + if (!isset($this->mxKarma['session'])) { + if (!isset($this->mxKarma['connectionInProgress']) || !$this->mxKarma['connectionInProgress']) { + $this->mxKarmaOpenSession(); + } + return; + } + + $map = $this->maniaControl->mapManager->getCurrentMap(); + + $properties = array(); + + $gameMode = $this->maniaControl->server->getGameMode(true); + if ($gameMode == 'Script') { + $scriptName = $this->maniaControl->client->getScriptName(); + $properties['gamemode'] = $scriptName["CurrentValue"]; + } else { + $properties['gamemode'] = $gameMode; + } + + $properties['titleid'] = $this->maniaControl->server->titleId; + $properties['mapuid'] = $map->uid; + + if (!$player) { + $properties['getvotesonly'] = false; + $properties['playerlogins'] = array(); + foreach ($this->maniaControl->playerManager->getPlayers() as $plyr) { + /** + * @var Player $player + */ + $properties['playerlogins'][] = $plyr->login; + } + } else { + $properties['getvotesonly'] = true; + $properties['playerlogins'] = array($player->login); + } + + $content = json_encode($properties); + $self = $this; + $this->maniaControl->fileReader->postData(self::MX_KARMA_URL . self::MX_KARMA_GETMAPRATING . "?sessionKey=" . urlencode($this->mxKarma['session']->sessionKey), function ($data, $error) use (&$self, &$player) { + if (!$error) { + $data = json_decode($data); + if ($data->success) { + + // Fetch averages if its for the whole server + if (!$player) { + $self->mxKarma["voteCount"] = $data->data->votecount; + $self->mxKarma["voteAverage"] = $data->data->voteaverage; + $self->mxKarma["modeVoteCount"] = $data->data->modevotecount; + $self->mxKarma["modeVoteAverage"] = $data->data->modevoteaverage; + } + + foreach ($data->data->votes as $votes) { + $self->mxKarma["votes"][$votes->login] = $votes->vote; + } + + $self->updateManialink = true; + $self->maniaControl->callbackManager->triggerCallback($self::CB_KARMA_MXUPDATED, $self->mxKarma); + $self->maniaControl->log("MX-Karma Votes successfully fetched"); + } else { + $self->maniaControl->log("Error while fetching votes: " . $data->data->message); + // TODO remove temp trigger + $self->maniaControl->errorHandler->triggerDebugNotice("Error while fetching votes: " . $data->data->message . " " . KarmaPlugin::MX_KARMA_URL . KarmaPlugin::MX_KARMA_SAVEVOTES . "?sessionKey=" . urlencode($self->mxKarma['session']->sessionKey)); + } + } else { + $self->maniaControl->log($error); + } + }, $content, false, 'application/json'); + } + + /** + * @see \ManiaControl\Plugins\Plugin::unload() + */ + public function unload() { + $this->maniaControl->manialinkManager->hideManialink(self::MLID_KARMA); + $this->maniaControl->callbackManager->unregisterCallbackListener($this); + $this->maniaControl->timerManager->unregisterTimerListenings($this); + unset($this->maniaControl); + } + + /** + * Handle BeginMap ManiaControl callback + * + * @param Map $map + */ + public function handleBeginMap(Map $map) { + // send Map Karma to MX from previous Map + if (isset($this->mxKarma['map'])) { + $votes = array(); + foreach ($this->mxKarma['votes'] as $login => $value) { + $player = $this->maniaControl->playerManager->getPlayer($login); + array_push($votes, array("login" => $login, "nickname" => $player->rawNickname, "vote" => $value)); + } + $this->postKarmaVotes($this->mxKarma['map'], $votes); + unset($this->mxKarma['map']); + } + + unset($this->mxKarma['votes']); + $this->mxKarma['startTime'] = time(); + $this->updateManialink = true; + + // Get Karma votes at begin of map + $this->getMxKarmaVotes(); + } + + /** + * Post the Karma votes to MX-Karma + * + * @param Map $map + * @param array $votes + * @param bool $import + */ + private function postKarmaVotes(Map $map, array $votes, $import = false) { + if (!isset($this->mxKarma['session'])) { + if (!isset($this->mxKarma['connectionInProgress']) || !$this->mxKarma['connectionInProgress']) { + $this->mxKarmaOpenSession(); + } + return; + } + + $gameMode = $this->maniaControl->server->getGameMode(true); + + if (count($votes) == 0) { + return; + } + + $properties = array(); + if ($gameMode == 'Script') { + $scriptName = $this->maniaControl->client->getScriptName(); + $properties['gamemode'] = $scriptName["CurrentValue"]; + } else { + $properties['gamemode'] = $gameMode; + } + + if ($import) { + $properties['maptime'] = 0; + } else { + $properties['maptime'] = time() - $this->mxKarma['startTime']; + } + + $properties['votes'] = $votes; + $properties['titleid'] = $this->maniaControl->server->titleId; + $properties['mapname'] = $map->rawName; + $properties['mapuid'] = $map->uid; + $properties['mapauthor'] = $map->authorLogin; + $properties['isimport'] = $import; + + $content = json_encode($properties); + + $self = $this; + $this->maniaControl->fileReader->postData(self::MX_KARMA_URL . self::MX_KARMA_SAVEVOTES . "?sessionKey=" . urlencode($this->mxKarma['session']->sessionKey), function ($data, $error) use (&$self) { + if (!$error) { + $data = json_decode($data); + if ($data->success) { + $self->maniaControl->log("Votes successfully permitted"); + } else { + $self->maniaControl->log("Error while updating votes: " . $data->data->message); + // TODO remove temp trigger + $self->maniaControl->errorHandler->triggerDebugNotice("Error while updating votes: " . $data->data->message . " " . KarmaPlugin::MX_KARMA_URL . $self::MX_KARMA_SAVEVOTES . "?sessionKey=" . urlencode($self->mxKarma['session']->sessionKey)); + } + } else { + $self->maniaControl->log($error); + } + }, $content, false, 'application/json'); + } + + /** + * Handle PlayerConnect callback + * + * @param \ManiaControl\Players\Player $player + */ + public function handlePlayerConnect(Player $player) { + if (!$player) { + return; + } + $this->queryManialinkUpdateFor($player); + + // Get Mx Karma Vote for Player + $this->getMxKarmaVotes($player); + } + + /** + * Query the player to update the manialink + * + * @param Player $player + */ + private function queryManialinkUpdateFor(Player $player) { + if ($this->updateManialink === true) { + return; + } + if (!is_array($this->updateManialink)) { + $this->updateManialink = array(); + } + $this->updateManialink[$player->login] = $player; + } + + /** + * Handle PlayerChat callback + * + * @param array $chatCallback + */ + public function handlePlayerChat(array $chatCallback) { + $login = $chatCallback[1][1]; + $player = $this->maniaControl->playerManager->getPlayer($login); + if (!$player) { + return; + } + $message = $chatCallback[1][2]; + if ($chatCallback[1][3]) { + $message = substr($message, 1); + } + if (preg_match('/[^+-]/', $message)) { + return; + } + $countPositive = substr_count($message, '+'); + $countNegative = substr_count($message, '-'); + if ($countPositive <= 0 && $countNegative <= 0) { + return; + } + $vote = $countPositive - $countNegative; + $success = $this->handleVote($player, $vote); + if (!$success) { + $this->maniaControl->chat->sendError('Error occurred.', $player->login); + return; + } + $this->maniaControl->chat->sendSuccess('Vote updated!', $player->login); + } + + /** + * Handle a vote done by a player + * + * @param Player $player + * @param int $vote + * @return bool + */ + private function handleVote(Player $player, $vote) { + // Check vote + $votesSetting = $this->maniaControl->settingManager->getSetting($this, self::SETTING_AVAILABLE_VOTES); + $votes = explode(',', $votesSetting); + $voteLow = intval($votes[0]); + $voteHigh = $voteLow + 2; + if (isset($votes[1])) { + $voteHigh = intval($votes[1]); + } + if ($vote < $voteLow || $vote > $voteHigh) { + return false; + } + + // Calculate actual voting + $vote -= $voteLow; + $voteHigh -= $voteLow; + $vote /= $voteHigh; + + // Save vote + $map = $this->maniaControl->mapManager->getCurrentMap(); + + // Update vote in MX karma array + if ($this->maniaControl->settingManager->getSetting($this, self::SETTING_MX_KARMA_ACTIVATED) && isset($this->mxKarma["session"])) { + if (!isset($this->mxKarma["votes"][$player->login])) { + $sum = $this->mxKarma["voteCount"] * $this->mxKarma["voteAverage"] + $vote * 100; + $this->mxKarma["voteCount"]++; + + $modeSum = $this->mxKarma["modeVoteCount"] * $this->mxKarma["modeVoteAverage"] + $vote * 100; + $this->mxKarma["modeVoteCount"]++; + } else { + $oldVote = $this->mxKarma["votes"][$player->login]; + $sum = $this->mxKarma["voteCount"] * $this->mxKarma["voteAverage"] - $oldVote + $vote * 100; + $modeSum = $this->mxKarma["modeVoteCount"] * $this->mxKarma["modeVoteAverage"] - $oldVote + $vote * 100; + } + + $this->mxKarma["voteAverage"] = $sum / $this->mxKarma["voteCount"]; + $this->mxKarma["modeVoteAverage"] = $modeSum / $this->mxKarma["modeVoteCount"]; + $this->mxKarma["votes"][$player->login] = $vote * 100; + } + + $voted = $this->getPlayerVote($player, $map); + if (!$voted) { + $this->maniaControl->statisticManager->incrementStat(self::STAT_PLAYER_MAPVOTES, $player, $this->maniaControl->server->index); + } + + $success = $this->savePlayerVote($player, $map, $vote); + if (!$success) { + return false; + } + $this->maniaControl->callbackManager->triggerCallback(self::CB_KARMA_CHANGED); + $this->updateManialink = true; + return true; + } + + /** + * Get the current vote of the player for the map + * + * @param Player $player + * @param Map $map + * @return int + */ + public function getPlayerVote(Player $player, Map $map) { + $mysqli = $this->maniaControl->database->mysqli; + $query = "SELECT * FROM `" . self::TABLE_KARMA . "` + WHERE `playerIndex` = {$player->index} + AND `mapIndex` = {$map->index} + AND `vote` >= 0;"; + $result = $mysqli->query($query); + if ($mysqli->error) { + trigger_error($mysqli->error); + return false; + } + if ($result->num_rows <= 0) { + $result->free(); + return false; + } + $item = $result->fetch_object(); + $result->free(); + $vote = $item->vote; + return floatval($vote); + } + + /** + * Save the vote of the player for the map + * + * @param Player $player + * @param Map $map + * @param float $vote + * @return bool + */ + private function savePlayerVote(Player $player, Map $map, $vote) { + $mysqli = $this->maniaControl->database->mysqli; + $query = "INSERT INTO `" . self::TABLE_KARMA . "` ( + `mapIndex`, + `playerIndex`, + `vote` + ) VALUES ( + {$map->index}, + {$player->index}, + {$vote} + ) ON DUPLICATE KEY UPDATE + `vote` = VALUES(`vote`);"; + $result = $mysqli->query($query); + if ($mysqli->error) { + trigger_error($mysqli->error); + return false; + } + + return $result; + } + + /** + * Get all players votes + * + * @param Map $map + * @return array + */ + public function getMapPlayerVotes(Map $map) { + $mysqli = $this->maniaControl->database->mysqli; + $query = "SELECT * FROM `" . self::TABLE_KARMA . "` + WHERE `mapIndex` = {$map->index} + AND `vote` >= 0"; + $result = $mysqli->query($query); + if ($mysqli->error) { + trigger_error($mysqli->error); + return false; + } + + $votes = array(); + while ($vote = $result->fetch_object()) { + $player = $this->maniaControl->playerManager->getPlayerByIndex($vote->playerIndex); + $karma = $vote->vote; + $votes[] = array('player' => $player, 'karma' => $karma); + } + + usort($votes, function ($a, $b) { + return $a['karma'] - $b['karma']; + }); + $votes = array_reverse($votes); + + return $votes; + } + + /** + * Update Settings + * + * @param $class + * @param $settingName + * @param $value + */ + public function updateSettings($class, $settingName, $value) { + if (!$class = get_class()) { + return; + } + + $serverLogin = $this->maniaControl->server->login; + if ($settingName == '$l[http://karma.mania-exchange.com/auth/getapikey?server=' . $serverLogin . ']MX Karma Code for ' . $serverLogin . '$l') { + $this->mxKarmaOpenSession(); + } + + if ($settingName == 'Enable Karma Widget' && $value == true) { + $this->updateManialink = true; + $this->handle1Second(time()); + } elseif ($settingName == 'Enable Karma Widget' && $value == false) { + $this->updateManialink = false; + $ml = new ManiaLink(self::MLID_KARMA); + $mltext = $ml->render()->saveXML(); + $this->maniaControl->manialinkManager->sendManialink($mltext); + } + } + + /** + * Handle ManiaControl 1 Second callback + * + * @param $time + */ + public function handle1Second($time) { + if (!$this->updateManialink) { + return; + } + + $displayMxKarma = $this->maniaControl->settingManager->getSetting($this, self::SETTING_WIDGET_DISPLAY_MX); + + // Get players + $players = $this->updateManialink; + if ($players === true) { + $players = $this->maniaControl->playerManager->getPlayers(); + } + $this->updateManialink = false; + + // Get map karma + $map = $this->maniaControl->mapManager->getCurrentMap(); + + // Display the mx Karma if the setting is choosen and the MX session is available + if ($displayMxKarma && isset($this->mxKarma['session']) && isset($this->mxKarma['voteCount'])) { + $karma = $this->mxKarma['modeVoteAverage'] / 100; + $voteCount = $this->mxKarma['modeVoteCount']; + } else { + $karma = $this->getMapKarma($map); + $votes = $this->getMapVotes($map); + $voteCount = $votes['count']; + } + + if ($this->maniaControl->settingManager->getSetting($this, self::SETTING_WIDGET_ENABLE)) { + // Build karma manialink + $this->buildManialink(); + + // Update karma gauge & label + /** + * @var Gauge $karmaGauge + */ + $karmaGauge = $this->manialink->karmaGauge; + /** + * @var Label $karmaLabel + */ + $karmaLabel = $this->manialink->karmaLabel; + if (is_numeric($karma) && $voteCount > 0) { + $karma = floatval($karma); + $karmaGauge->setRatio($karma + 0.15 - $karma * 0.15); + $karmaColor = ColorUtil::floatToStatusColor($karma); + $karmaGauge->setColor($karmaColor . '7'); + $karmaLabel->setText(' ' . round($karma * 100.) . '% (' . $voteCount . ')'); + } else { + $karmaGauge->setRatio(0.); + $karmaGauge->setColor('00fb'); + $karmaLabel->setText('-'); + } + + // Loop players + foreach ($players as $login => $player) { + // Get player vote + // TODO: show the player his own vote in some way + // $vote = $this->getPlayerVote($player, $map); + // $votesFrame = $this->manialink->votesFrame; + // $votesFrame->removeChildren(); + + // Send manialink + $this->maniaControl->manialinkManager->sendManialink($this->manialink, $login); + } + } + } + + /** + * Get the current karma of the map + * + * @param Map $map + * @return float | bool + */ + public function getMapKarma(Map $map) { + $mysqli = $this->maniaControl->database->mysqli; + $query = "SELECT AVG(`vote`) AS `karma` FROM `" . self::TABLE_KARMA . "` + WHERE `mapIndex` = {$map->index} + AND `vote` >= 0;"; + $result = $mysqli->query($query); + if ($mysqli->error) { + trigger_error($mysqli->error); + return false; + } + if ($result->num_rows <= 0) { + $result->free(); + return false; + } + $item = $result->fetch_object(); + $result->free(); + $karma = $item->karma; + if ($karma === null) { + return false; + } + return floatval($karma); + } + + /** + * Get the current Votes for the Map + * + * @param Map $map + * @return array + */ + public function getMapVotes(Map $map) { + $mysqli = $this->maniaControl->database->mysqli; + $query = "SELECT `vote`, COUNT(`vote`) AS `count` FROM `" . self::TABLE_KARMA . "` + WHERE `mapIndex` = {$map->index} + AND `vote` >= 0 + GROUP BY `vote`;"; + $result = $mysqli->query($query); + if ($mysqli->error) { + trigger_error($mysqli->error); + return false; + } + $votes = array(); + $count = 0; + while ($vote = $result->fetch_object()) { + $votes[$vote->vote] = $vote; + $count += $vote->count; + } + $votes['count'] = $count; + $result->free(); + return $votes; + } + + /** + * Build karma voting manialink if necessary + * + * @param bool $forceBuild + */ + private function buildManialink($forceBuild = false) { + if (is_object($this->manialink) && !$forceBuild) { + return; + } + + $title = $this->maniaControl->settingManager->getSetting($this, self::SETTING_WIDGET_TITLE); + $pos_x = $this->maniaControl->settingManager->getSetting($this, self::SETTING_WIDGET_POSX); + $pos_y = $this->maniaControl->settingManager->getSetting($this, self::SETTING_WIDGET_POSY); + $width = $this->maniaControl->settingManager->getSetting($this, self::SETTING_WIDGET_WIDTH); + $height = $this->maniaControl->settingManager->getSetting($this, self::SETTING_WIDGET_HEIGHT); + $labelStyle = $this->maniaControl->manialinkManager->styleManager->getDefaultLabelStyle(); + $quadStyle = $this->maniaControl->manialinkManager->styleManager->getDefaultQuadStyle(); + $quadSubstyle = $this->maniaControl->manialinkManager->styleManager->getDefaultQuadSubstyle(); + + $manialink = new ManiaLink(self::MLID_KARMA); + + $frame = new Frame(); + $manialink->add($frame); + $frame->setPosition($pos_x, $pos_y); + + $backgroundQuad = new Quad(); + $frame->add($backgroundQuad); + $backgroundQuad->setY($height * 0.15); + $backgroundQuad->setSize($width, $height); + $backgroundQuad->setStyles($quadStyle, $quadSubstyle); + + $titleLabel = new Label(); + $frame->add($titleLabel); + $titleLabel->setY($height * 0.36); + $titleLabel->setWidth($width * 0.85); + $titleLabel->setStyle($labelStyle); + $titleLabel->setTranslate(true); + $titleLabel->setTextSize(1); + $titleLabel->setScale(0.90); + $titleLabel->setText($title); + + $karmaGauge = new Gauge(); + $frame->add($karmaGauge); + $karmaGauge->setSize($width * 0.95, $height * 0.92); + $karmaGauge->setDrawBg(false); + $manialink->karmaGauge = $karmaGauge; + + $karmaLabel = new Label(); + $frame->add($karmaLabel); + $karmaLabel->setPosition(0, -0.4, 1); + $karmaLabel->setSize($width * 0.9, $height * 0.9); + $karmaLabel->setStyle($labelStyle); + $karmaLabel->setTextSize(1); + $manialink->karmaLabel = $karmaLabel; + + $votesFrame = new Frame(); + $frame->add($votesFrame); + $manialink->votesFrame = $votesFrame; + + $this->manialink = $manialink; + } + + /** + * Import old Karma votes to Mania-Exchange Karma + * + * @param Map $map + */ + public function importMxKarmaVotes(Map $map) { + if (!$this->maniaControl->settingManager->getSetting($this, self::SETTING_MX_KARMA_ACTIVATED)) { + return; + } + + if (!$this->maniaControl->settingManager->getSetting($this, self::SETTING_MX_KARMA_IMPORTING)) { + return; + } + + if (!isset($this->mxKarma['session'])) { + if (!isset($this->mxKarma['connectionInProgress']) || !$this->mxKarma['connectionInProgress']) { + $this->mxKarmaOpenSession(); + } + return; + } + + $mysqli = $this->maniaControl->database->mysqli; + $query = "SELECT mapImported FROM `" . self::MX_IMPORT_TABLE . "` WHERE `mapIndex` = {$map->index};"; + $result = $mysqli->query($query); + if ($mysqli->error) { + trigger_error($mysqli->error); + return; + } + $vote = $result->fetch_object(); + + if ($result->field_count == 0 || !$vote) { + $query = "SELECT vote, login, nickname FROM `" . self::TABLE_KARMA . "` k LEFT JOIN `" . PlayerManager::TABLE_PLAYERS . "` p ON (k.playerIndex=p.index) WHERE mapIndex = {$map->index}"; + $result2 = $mysqli->query($query); + if ($mysqli->error) { + trigger_error($mysqli->error); + return; + } + + $votes = array(); + while ($row = $result2->fetch_object()) { + array_push($votes, array("login" => $row->login, "nickname" => $row->nickname, "vote" => $row->vote * 100)); + } + + $this->postKarmaVotes($map, $votes, true); + + // Flag Map as Imported in database if it is a import + $query = "INSERT INTO `" . self::MX_IMPORT_TABLE . "` (`mapIndex`,`mapImported`) VALUES ({$map->index},true) ON DUPLICATE KEY UPDATE `mapImported` = true;"; + $mysqli->query($query); + if ($mysqli->error) { + trigger_error($mysqli->error); + } + + $result2->free(); + } + $result->free_result(); + + return; + } + + /** + * Save Mx Karma Votes at Mapend + */ + public function sendMxKarmaVotes(Map $map) { + if (!$this->maniaControl->settingManager->getSetting($this, self::SETTING_MX_KARMA_ACTIVATED)) { + return; + } + + if (!isset($this->mxKarma['session'])) { + if (!isset($this->mxKarma['connectionInProgress']) || !$this->mxKarma['connectionInProgress']) { + $this->mxKarmaOpenSession(); + } + return; + } + + if (!isset($this->mxKarma['votes']) || count($this->mxKarma['votes']) == 0) { + return; + } + + $this->mxKarma['map'] = $map; + } +} diff --git a/application/plugins/MCTeam/LocalRecordsPlugin.php b/application/plugins/MCTeam/LocalRecordsPlugin.php new file mode 100644 index 00000000..7d01322c --- /dev/null +++ b/application/plugins/MCTeam/LocalRecordsPlugin.php @@ -0,0 +1,660 @@ +maniaControl = $maniaControl; + $this->initTables(); + + // Init settings + $this->maniaControl->settingManager->initSetting($this, self::SETTING_WIDGET_TITLE, 'Local Records'); + $this->maniaControl->settingManager->initSetting($this, self::SETTING_WIDGET_POSX, -139.); + $this->maniaControl->settingManager->initSetting($this, self::SETTING_WIDGET_POSY, 75); + $this->maniaControl->settingManager->initSetting($this, self::SETTING_WIDGET_WIDTH, 40.); + $this->maniaControl->settingManager->initSetting($this, self::SETTING_WIDGET_LINESCOUNT, 15); + $this->maniaControl->settingManager->initSetting($this, self::SETTING_WIDGET_LINEHEIGHT, 4.); + $this->maniaControl->settingManager->initSetting($this, self::SETTING_WIDGET_ENABLE, true); + $this->maniaControl->settingManager->initSetting($this, self::SETTING_NOTIFY_ONLY_DRIVER, false); + $this->maniaControl->settingManager->initSetting($this, self::SETTING_NOTIFY_BEST_RECORDS, -1); + $this->maniaControl->settingManager->initSetting($this, self::SETTING_ADJUST_OUTER_BORDER, false); + + // Register for callbacks + $this->maniaControl->timerManager->registerTimerListening($this, 'handle1Second', 1000); + $this->maniaControl->callbackManager->registerCallbackListener(CallbackManager::CB_AFTERINIT, $this, 'handleAfterInit'); + $this->maniaControl->callbackManager->registerCallbackListener(Callbacks::BEGINMAP, $this, 'handleMapBegin'); + $this->maniaControl->callbackManager->registerCallbackListener(CallbackManager::CB_TM_PLAYERFINISH, $this, 'handlePlayerFinish'); + $this->maniaControl->callbackManager->registerCallbackListener(PlayerManager::CB_PLAYERCONNECT, $this, 'handlePlayerConnect'); + $this->maniaControl->callbackManager->registerCallbackListener(CallbackManager::CB_TM_PLAYERCHECKPOINT, $this, 'handlePlayerCheckpoint'); + $this->maniaControl->callbackManager->registerCallbackListener(SettingManager::CB_SETTINGS_CHANGED, $this, 'handleSettingsChanged'); + $this->maniaControl->callbackManager->registerCallbackListener(CallbackManager::CB_MP_PLAYERMANIALINKPAGEANSWER, $this, 'handleManialinkPageAnswer'); + $this->maniaControl->commandManager->registerCommandListener(array('recs', 'records'), $this, 'showRecordsList', false, 'Shows a list of Local Records on the current map.'); + $this->maniaControl->commandManager->registerCommandListener('delrec', $this, 'deleteRecord', true, 'Removes a record from the database.'); + + $this->updateManialink = true; + + return true; + } + + /** + * + * @see \ManiaControl\Plugins\Plugin::unload() + */ + public function unload() { + $this->maniaControl->callbackManager->unregisterCallbackListener($this); + $this->maniaControl->timerManager->unregisterTimerListenings($this); + } + + /** + * Initialize needed database tables + */ + private function initTables() { + $mysqli = $this->maniaControl->database->mysqli; + $query = "CREATE TABLE IF NOT EXISTS `" . self::TABLE_RECORDS . "` ( + `index` int(11) NOT NULL AUTO_INCREMENT, + `mapIndex` int(11) NOT NULL, + `playerIndex` int(11) 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` (`mapIndex`,`playerIndex`) + ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=1;"; + $mysqli->query($query); + if ($mysqli->error) { + trigger_error($mysqli->error, E_USER_ERROR); + } + + $mysqli->query("ALTER TABLE `" . self::TABLE_RECORDS . "` ADD `checkpoints` TEXT CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL"); + if ($mysqli->error) { + if (!strstr($mysqli->error, 'Duplicate')) { + trigger_error($mysqli->error, E_USER_ERROR); + } + } + } + + /** + * + * @see \ManiaControl\Plugins\Plugin::getId() + */ + public static function getId() { + return self::ID; + } + + /** + * + * @see \ManiaControl\Plugins\Plugin::getName() + */ + public static function getName() { + return 'Local Records Plugin'; + } + + /** + * + * @see \ManiaControl\Plugins\Plugin::getVersion() + */ + public static function getVersion() { + return self::VERSION; + } + + /** + * + * @see \ManiaControl\Plugins\Plugin::getAuthor() + */ + public static function getAuthor() { + return 'steeffeen'; + } + + /** + * + * @see \ManiaControl\Plugins\Plugin::getDescription() + */ + public static function getDescription() { + return 'Plugin offering tracking of local records and manialinks to display them.'; + } + + /** + * Handle ManiaControl After Init + */ + public function handleAfterInit() { + $this->updateManialink = true; + } + + /** + * Handle 1Second callback + * + * @param $time + */ + public function handle1Second($time) { + if (!$this->updateManialink) { + return; + } + + $this->updateManialink = false; + if ($this->maniaControl->settingManager->getSetting($this, self::SETTING_WIDGET_ENABLE)) { + $manialink = $this->buildManialink(); + $this->maniaControl->manialinkManager->sendManialink($manialink); + } + } + + public function handleSettingsChanged($class, $settingName, $value) { + if (!$class = get_class()) { + return; + } + if ($settingName == 'Enable Local Records Widget' && $value == true) { + $this->updateManialink = true; + } + elseif ($settingName == 'Enable Local Records Widget' && $value == false) { + $ml = new ManiaLink(self::MLID_RECORDS); + $mltext = $ml->render()->saveXML(); + $this->maniaControl->manialinkManager->sendManialink($mltext); + } + } + + /** + * Handle PlayerCheckpoint callback + * + * @param $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 PlayerConnect callback + * + * @param Player $player + */ + public function handlePlayerConnect(Player $player) { + $this->updateManialink = true; + } + + /** + * Handle BeginMap callback + * + * @param Map $map + */ + public function handleMapBegin(Map $map) { + $this->updateManialink = true; + } + + /** + * Handle PlayerFinish callback + * + * @param array $callback + */ + public function handlePlayerFinish(array $callback) { + $data = $callback[1]; + if ($data[0] <= 0 || $data[2] <= 0) { + // Invalid player or time + return; + } + + $login = $data[1]; + $player = $this->maniaControl->playerManager->getPlayer($login); + if (!$player) { + // Invalid player + return; + } + + $time = $data[2]; + $map = $this->maniaControl->mapManager->getCurrentMap(); + + // Check old record of the player + $oldRecord = $this->getLocalRecord($map, $player); + $oldRank = -1; + if ($oldRecord) { + $oldRank = $oldRecord->rank; + if ($oldRecord->time < $time) { + // Not improved + return; + } + if ($oldRecord->time == $time) { + // Same time + $message = '$<$fff' . $player->nickname . '$> equalized his/her $<$ff0' . $oldRecord->rank . '.$> Local Record: $<$fff' . Formatter::formatTime($oldRecord->time) . '$>!'; + $this->maniaControl->chat->sendInformation('$3c0' . $message); + return; + } + } + + // Save time + $mysqli = $this->maniaControl->database->mysqli; + $query = "INSERT INTO `" . self::TABLE_RECORDS . "` ( + `mapIndex`, + `playerIndex`, + `time`, + `checkpoints` + ) VALUES ( + {$map->index}, + {$player->index}, + {$time}, + '{$this->getCheckpoints($player->login)}' + ) ON DUPLICATE KEY UPDATE + `time` = VALUES(`time`), + `checkpoints` = VALUES(`checkpoints`);"; + $mysqli->query($query); + if ($mysqli->error) { + trigger_error($mysqli->error); + return; + } + $this->updateManialink = true; + + // Announce record + $newRecord = $this->getLocalRecord($map, $player); + + $notifyOnlyDriver = $this->maniaControl->settingManager->getSetting($this, self::SETTING_NOTIFY_ONLY_DRIVER); + $notifyOnlyBestRecords = $this->maniaControl->settingManager->getSetting($this, self::SETTING_NOTIFY_BEST_RECORDS); + if ($notifyOnlyDriver || $notifyOnlyBestRecords > 0 && $newRecord->rank > $notifyOnlyBestRecords) { + $improvement = ((!$oldRecord || $newRecord->rank < $oldRecord->rank) ? 'gained the' : 'improved your'); + $message = 'You ' . $improvement . ' $<$ff0' . $newRecord->rank . '.$> Local Record: $<$fff' . Formatter::formatTime($newRecord->time) . '$>'; + if ($oldRecord) $oldRank = ($improvement == 'improved your') ? '' : $oldRecord->rank . '. '; + if ($oldRecord) $message .= ' ($<$ff0' . $oldRank . '$>$<$fff-' . Formatter::formatTime(($oldRecord->time - $newRecord->time)) . '$>!'; + $this->maniaControl->chat->sendInformation('$3c0' . $message.'!', $player->login); + } else { + $improvement = ((!$oldRecord || $newRecord->rank < $oldRecord->rank) ? 'gained the' : 'improved the'); + $message = '$<$fff' . $player->nickname . '$> ' . $improvement . ' $<$ff0' . $newRecord->rank . '.$> Local Record: $<$fff' . Formatter::formatTime($newRecord->time) . '$>'; + if ($oldRecord) $oldRank = ($improvement == 'improved the') ? '' : $oldRecord->rank . '. '; + if ($oldRecord) $message .= ' ($<$ff0' . $oldRank . '$>$<$fff-' . Formatter::formatTime(($oldRecord->time - $newRecord->time)) . '$>)'; + $this->maniaControl->chat->sendInformation('$3c0' . $message.'!'); + } + + $this->maniaControl->callbackManager->triggerCallback(self::CB_LOCALRECORDS_CHANGED, $newRecord); + } + + /** + * Handle PlayerManialinkPageAnswer callback + * + * @param array $callback + */ + public function handleManialinkPageAnswer(array $callback) { + $actionId = $callback[1][2]; + + $login = $callback[1][1]; + $player = $this->maniaControl->playerManager->getPlayer($login); + + if ($actionId == self::ACTION_SHOW_RECORDSLIST) { + $this->showRecordsList(array(), $player); + } + } + + /** + * Delete a Player's record + * + * @param array $chat + * @param Player $player + */ + public function deleteRecord(array $chat, Player $player) { + if (!$this->maniaControl->authenticationManager->checkRight($player, AuthenticationManager::AUTH_LEVEL_MASTERADMIN)) { + $this->maniaControl->authenticationManager->sendNotAllowed($player); + return; + } + + $chatCommand = explode(' ', $chat[1][2]); + $recordId = (int) $chatCommand[1]; + if (is_integer($recordId)) { + $currentMap = $this->maniaControl->mapManager->getCurrentMap(); + $records = $this->getLocalRecords($currentMap); + if (count($records) < $recordId) { + $this->maniaControl->chat->sendError('Cannot remove record $<$fff' . $recordId . '$>!', $player); + return; + } + + $mysqli = $this->maniaControl->database->mysqli; + $query = "DELETE FROM `" . self::TABLE_RECORDS . "` WHERE `mapIndex` = " . $currentMap->index . " AND `playerIndex` = " . $player->index . ""; + $mysqli->query($query); + if ($mysqli->error) { + trigger_error($mysqli->error); + return; + } + + $this->maniaControl->callbackManager->triggerCallback(self::CB_LOCALRECORDS_CHANGED, null); + $this->maniaControl->chat->sendInformation('Record no. $<$fff' . $recordId . '$> has been removed!'); + } + else { + $this->maniaControl->chat->sendError('Cannot remove record $<$fff' . $recordId . '$>, because it\'s not an integer!', $player); + } + } + + /** + * Shows a ManiaLink list with the local records. + * + * @param array $chat + * @param Player $player + */ + public function showRecordsList(array $chat, Player $player) { + $width = $this->maniaControl->manialinkManager->styleManager->getListWidgetsWidth(); + $height = $this->maniaControl->manialinkManager->styleManager->getListWidgetsHeight(); + + // get PlayerList + $records = $this->getLocalRecords($this->maniaControl->mapManager->getCurrentMap()); + + $pagesId = ''; + if (count($records) > 15) { + $pagesId = 'RecordsListPages'; + } + + // create manialink + $maniaLink = new ManiaLink(ManialinkManager::MAIN_MLID); + $script = $maniaLink->getScript(); + $paging = new Paging(); + $script->addFeature($paging); + + // Main frame + $frame = $this->maniaControl->manialinkManager->styleManager->getDefaultListFrame($script, $paging); + $maniaLink->add($frame); + + // Start offsets + $x = -$width / 2; + $y = $height / 2; + + // Predefine Description Label + $descriptionLabel = $this->maniaControl->manialinkManager->styleManager->getDefaultDescriptionLabel(); + $frame->add($descriptionLabel); + + // Headline + $headFrame = new Frame(); + $frame->add($headFrame); + $headFrame->setY($y - 5); + $array = array("Rank" => $x + 5, "Nickname" => $x + 18, "Login" => $x + 70, "Time" => $x + 101); + $this->maniaControl->manialinkManager->labelLine($headFrame, $array); + + $i = 0; + $y = $height / 2 - 10; + $pageFrames = array(); + foreach ($records as $listRecord) { + if (!isset($pageFrame)) { + $pageFrame = new Frame(); + $frame->add($pageFrame); + if (!empty($pageFrames)) { + $pageFrame->setVisible(false); + } + array_push($pageFrames, $pageFrame); + $y = $height / 2 - 10; + + $paging->addPage($pageFrame); + } + + $recordFrame = new Frame(); + $pageFrame->add($recordFrame); + + if ($i % 2 != 0) { + $lineQuad = new Quad_BgsPlayerCard(); + $recordFrame->add($lineQuad); + $lineQuad->setSize($width, 4); + $lineQuad->setSubStyle($lineQuad::SUBSTYLE_BgPlayerCardBig); + $lineQuad->setZ(0.001); + } + + if (strlen($listRecord->nickname) < 2) $listRecord->nickname = $listRecord->login; + $array = array($listRecord->rank => $x + 5, '$fff' . $listRecord->nickname => $x + 18, $listRecord->login => $x + 70, + Formatter::formatTime($listRecord->time) => $x + 101); + $this->maniaControl->manialinkManager->labelLine($recordFrame, $array); + + $recordFrame->setY($y); + + $y -= 4; + $i++; + if ($i % 15 == 0) { + unset($pageFrame); + } + } + + // Render and display xml + $this->maniaControl->manialinkManager->displayWidget($maniaLink, $player, 'PlayerList'); + } + + /** + * Get current checkpoint string for dedimania record + * + * @param string $login + * @return string + */ + private function getCheckpoints($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 the local records manialink + * + * @return string + */ + private function buildManialink() { + $map = $this->maniaControl->mapManager->getCurrentMap(); + if (!$map) { + return null; + } + + $title = $this->maniaControl->settingManager->getSetting($this, self::SETTING_WIDGET_TITLE); + $pos_x = $this->maniaControl->settingManager->getSetting($this, self::SETTING_WIDGET_POSX); + $pos_y = $this->maniaControl->settingManager->getSetting($this, self::SETTING_WIDGET_POSY); + $width = $this->maniaControl->settingManager->getSetting($this, self::SETTING_WIDGET_WIDTH); + $lines = $this->maniaControl->settingManager->getSetting($this, self::SETTING_WIDGET_LINESCOUNT); + $lineHeight = $this->maniaControl->settingManager->getSetting($this, self::SETTING_WIDGET_LINEHEIGHT); + $labelStyle = $this->maniaControl->manialinkManager->styleManager->getDefaultLabelStyle(); + $quadStyle = $this->maniaControl->manialinkManager->styleManager->getDefaultQuadStyle(); + $quadSubstyle = $this->maniaControl->manialinkManager->styleManager->getDefaultQuadSubstyle(); + + $records = $this->getLocalRecords($map); + if (!is_array($records)) { + trigger_error("Couldn't fetch player records."); + return null; + } + + $manialink = new ManiaLink(self::MLID_RECORDS); + $frame = new Frame(); + $manialink->add($frame); + $frame->setPosition($pos_x, $pos_y); + + $backgroundQuad = new Quad(); + $frame->add($backgroundQuad); + $backgroundQuad->setVAlign(Control::TOP); + $adjustOuterBorder = $this->maniaControl->settingManager->getSetting($this, self::SETTING_ADJUST_OUTER_BORDER); + $height = 7. + ($adjustOuterBorder ? count($records) : $lines) * $lineHeight; + $backgroundQuad->setSize($width * 1.05, $height); + $backgroundQuad->setStyles($quadStyle, $quadSubstyle); + $backgroundQuad->setAction(self::ACTION_SHOW_RECORDSLIST); + + $titleLabel = new Label(); + $frame->add($titleLabel); + $titleLabel->setPosition(0, $lineHeight * -0.9); + $titleLabel->setWidth($width); + $titleLabel->setStyle($labelStyle); + $titleLabel->setTextSize(2); + $titleLabel->setText($title); + $titleLabel->setTranslate(true); + + // Times + foreach ($records as $index => $record) { + if ($index >= $lines) { + break; + } + + $y = -8. - $index * $lineHeight; + + $recordFrame = new Frame(); + $frame->add($recordFrame); + $recordFrame->setPosition(0, $y); + + /* + * $backgroundQuad = new Quad(); $recordFrame->add($backgroundQuad); $backgroundQuad->setSize($width * 1.04, $lineHeight * 1.4); $backgroundQuad->setStyles($quadStyle, $quadSubstyle); + */ + + $rankLabel = new Label(); + $recordFrame->add($rankLabel); + $rankLabel->setHAlign(Control::LEFT); + $rankLabel->setX($width * -0.47); + $rankLabel->setSize($width * 0.06, $lineHeight); + $rankLabel->setTextSize(1); + $rankLabel->setTextPrefix('$o'); + $rankLabel->setText($record->rank); + $rankLabel->setTextEmboss(true); + + $nameLabel = new Label(); + $recordFrame->add($nameLabel); + $nameLabel->setHAlign(Control::LEFT); + $nameLabel->setX($width * -0.4); + $nameLabel->setSize($width * 0.6, $lineHeight); + $nameLabel->setTextSize(1); + $nameLabel->setText($record->nickname); + $nameLabel->setTextEmboss(true); + + $timeLabel = new Label(); + $recordFrame->add($timeLabel); + $timeLabel->setHAlign(Control::RIGHT); + $timeLabel->setX($width * 0.47); + $timeLabel->setSize($width * 0.25, $lineHeight); + $timeLabel->setTextSize(1); + $timeLabel->setText(Formatter::formatTime($record->time)); + $timeLabel->setTextEmboss(true); + } + + return $manialink; + } + + /** + * Fetch local records for the given map + * + * @param Map $map + * @param int $limit + * @return array + */ + public function getLocalRecords(Map $map, $limit = -1) { + $mysqli = $this->maniaControl->database->mysqli; + $limit = ($limit > 0 ? "LIMIT " . $limit : ""); + $query = "SELECT * FROM ( + SELECT recs.*, @rank := @rank + 1 as `rank` FROM `" . self::TABLE_RECORDS . "` recs, (SELECT @rank := 0) ra + WHERE recs.`mapIndex` = {$map->index} + ORDER BY recs.`time` ASC + {$limit}) records + LEFT JOIN `" . PlayerManager::TABLE_PLAYERS . "` players + ON records.`playerIndex` = players.`index`;"; + $result = $mysqli->query($query); + if ($mysqli->error) { + trigger_error($mysqli->error); + return null; + } + $records = array(); + while ($record = $result->fetch_object()) { + array_push($records, $record); + } + $result->free(); + return $records; + } + + /** + * Retrieve the local record for the given map and login + * + * @param Map $map + * @param Player $player + * @return mixed + */ + private function getLocalRecord(Map $map, Player $player) { + $mysqli = $this->maniaControl->database->mysqli; + $query = "SELECT records.* FROM ( + SELECT recs.*, @rank := @rank + 1 as `rank` FROM `" . self::TABLE_RECORDS . "` recs, (SELECT @rank := 0) ra + WHERE recs.`mapIndex` = {$map->index} + ORDER BY recs.`time` ASC) records + WHERE records.`playerIndex` = {$player->index};"; + $result = $mysqli->query($query); + if ($mysqli->error) { + trigger_error("Couldn't retrieve player record for '{$player->login}'." . $mysqli->error); + return null; + } + $record = $result->fetch_object(); + $result->free(); + return $record; + } +} diff --git a/application/plugins/MCTeam/ServerRankingPlugin.php b/application/plugins/MCTeam/ServerRankingPlugin.php new file mode 100644 index 00000000..ad30c0cc --- /dev/null +++ b/application/plugins/MCTeam/ServerRankingPlugin.php @@ -0,0 +1,563 @@ +maniaControl = $maniaControl; + + $this->initTables(); + + $maniaControl->settingManager->initSetting($this, self::SETTING_MIN_HITS_RATIO_RANKING, 100); + $maniaControl->settingManager->initSetting($this, self::SETTING_MIN_HITS_POINTS_RANKING, 15); + + $maniaControl->settingManager->initSetting($this, self::SETTING_MIN_REQUIRED_RECORDS, 3); + $maniaControl->settingManager->initSetting($this, self::SETTING_MAX_STORED_RECORDS, 50); + + $script = $this->maniaControl->client->getScriptName(); + + if ($this->maniaControl->mapManager->getCurrentMap()->getGame() == 'tm') { + //TODO also add obstacle here as default + $maniaControl->settingManager->initSetting($this, self::SETTING_MIN_RANKING_TYPE, self::RANKING_TYPE_RECORDS); + } else if ($script["CurrentValue"] == "InstaDM.Script.txt") { + $maniaControl->settingManager->initSetting($this, self::SETTING_MIN_RANKING_TYPE, self::RANKING_TYPE_RATIOS); + } else { + $maniaControl->settingManager->initSetting($this, self::SETTING_MIN_RANKING_TYPE, self::RANKING_TYPE_POINTS); + } + + //Check if the type is Correct + $type = $this->maniaControl->settingManager->getSetting($this, self::SETTING_MIN_RANKING_TYPE); + if ($type != self::RANKING_TYPE_RECORDS && $type != self::RANKING_TYPE_POINTS && $type != self::RANKING_TYPE_RATIOS) { + $error = 'Ranking Type is not correct, possible values(' . self::RANKING_TYPE_RATIOS . ', ' . self::RANKING_TYPE_POINTS . ', ' . self::RANKING_TYPE_POINTS . ')'; + throw new Exception($error); + } + + //Register CallbackListeners + $this->maniaControl->callbackManager->registerCallbackListener(PlayerManager::CB_PLAYERCONNECT, $this, 'handlePlayerConnect'); + $this->maniaControl->callbackManager->registerCallbackListener(Callbacks::ENDMAP, $this, 'handleEndMap'); + + //Register CommandListener + $this->maniaControl->commandManager->registerCommandListener('rank', $this, 'command_showRank', false, 'Shows your current serverrank.'); + $this->maniaControl->commandManager->registerCommandListener('nextrank', $this, 'command_nextRank', false, 'Shows the person in front of you in the serverranking.'); + $this->maniaControl->commandManager->registerCommandListener(array('topranks', 'top100'), $this, 'command_topRanks', false, 'Shows an overview of the best-ranked 100 players.'); + + $this->resetRanks(); //TODO only update records count + } + + /** + * Unload the plugin and its resources + */ + public function unload() { + $this->maniaControl->callbackManager->unregisterCallbackListener($this); + $this->maniaControl->commandManager->unregisterCommandListener($this); + } + + /** + * Get plugin id + * + * @return int + */ + public static function getId() { + return self::PLUGIN_ID; + } + + /** + * Get Plugin Name + * + * @return string + */ + public static function getName() { + return self::PLUGIN_NAME; + } + + /** + * Get Plugin Version + * + * @return float + */ + public static function getVersion() { + return self::PLUGIN_VERSION; + } + + /** + * Get Plugin Author + * + * @return string + */ + public static function getAuthor() { + return self::PLUGIN_AUTHOR; + } + + /** + * Get Plugin Description + * + * @return string + */ + public static function getDescription() { + return "ServerRanking Plugin, ServerRanking by an avg build from the records, per count of points, or by a multiplication from Kill/Death Ratio and Laser accuracy"; + } + + /** + * Create necessary database tables + */ + private function initTables() { + $mysqli = $this->maniaControl->database->mysqli; + $query = "CREATE TABLE IF NOT EXISTS `" . self::TABLE_RANK . "` ( + `PlayerIndex` mediumint(9) NOT NULL default 0, + `Rank` mediumint(9) NOT NULL default 0, + `Avg` float NOT NULL default 0, + KEY `PlayerIndex` (`PlayerIndex`), + UNIQUE `Rank` (`Rank`) + ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COMMENT='Mania Control Serverranking';"; + $mysqli->query($query); + if ($mysqli->error) { + trigger_error($mysqli->error, E_USER_ERROR); + } + } + + /** + * Resets and rebuilds the Ranking + */ + private function resetRanks() { + $mysqli = $this->maniaControl->database->mysqli; + + // Erase old Average Data + $mysqli->query('TRUNCATE TABLE ' . self::TABLE_RANK); + $type = $this->maniaControl->settingManager->getSetting($this, self::SETTING_MIN_RANKING_TYPE); + + switch($type) { + case self::RANKING_TYPE_RATIOS: + $minHits = $this->maniaControl->settingManager->getSetting($this, self::SETTING_MIN_HITS_RATIO_RANKING); + + $hits = $this->maniaControl->statisticManager->getStatsRanking(StatisticCollector::STAT_ON_HIT, -1, $minHits); + $killDeathRatios = $this->maniaControl->statisticManager->getStatsRanking(StatisticManager::SPECIAL_STAT_KD_RATIO); + $accuracies = $this->maniaControl->statisticManager->getStatsRanking(StatisticManager::SPECIAL_STAT_LASER_ACC); + + $ranks = array(); + foreach($hits as $player => $hitCount) { + if (!isset($killDeathRatios[$player]) || !isset($accuracies[$player])) { + continue; + } + $ranks[$player] = $killDeathRatios[$player] * $accuracies[$player] * 1000; + + } + + arsort($ranks); + + + break; + case self::RANKING_TYPE_POINTS: + $minHits = $this->maniaControl->settingManager->getSetting($this, self::SETTING_MIN_HITS_POINTS_RANKING); + + $ranks = $this->maniaControl->statisticManager->getStatsRanking(StatisticCollector::STAT_ON_HIT, -1, $minHits); + + break; + case self::RANKING_TYPE_RECORDS: //TODO verify workable status + if (!$this->maniaControl->pluginManager->isPluginActive('MCTeam\LocalRecordsPlugin')) { + return; + } + + $requiredRecords = $this->maniaControl->settingManager->getSetting($this, self::SETTING_MIN_REQUIRED_RECORDS); + $maxRecords = $this->maniaControl->settingManager->getSetting($this, self::SETTING_MAX_STORED_RECORDS); + + $query = 'SELECT playerIndex, COUNT(*) AS Cnt + FROM ' . \MCTeam\LocalRecordsPlugin::TABLE_RECORDS . ' + GROUP BY PlayerIndex + HAVING Cnt >=' . $requiredRecords; + + $result = $mysqli->query($query); + $players = array(); + while($row = $result->fetch_object()) { + $players[$row->playerIndex] = array(0, 0); //sum, count + } + $result->free_result(); + + /** @var \MCTeam\LocalRecordsPlugin $localRecordsPlugin */ + $localRecordsPlugin = $this->maniaControl->pluginManager->getPlugin('MCTeam\LocalRecordsPlugin'); + $maps = $this->maniaControl->mapManager->getMaps(); + foreach($maps as $map) { + $records = $localRecordsPlugin->getLocalRecords($map, $maxRecords); + + $i = 1; + foreach($records as $record) { + if (isset($players[$record->playerIndex])) { + $players[$record->playerIndex][0] += $i; + $players[$record->playerIndex][1]++; + } + $i++; + } + } + + $mapCount = count($maps); + + //compute each players new average score + $ranks = array(); + foreach($players as $player => $val) { + $sum = $val[0]; + $cnt = $val[1]; + // ranked maps sum + $maxRecs rank for all remaining maps + $ranks[$player] = ($sum + ($mapCount - $cnt) * $maxRecords) / $mapCount; + } + + asort($ranks); + break; + } + + if (empty($ranks)) { + return; + } + + $this->recordCount = count($ranks); + + //Compute each player's new average score + $query = "INSERT INTO " . self::TABLE_RANK . " VALUES "; + $i = 1; + + foreach($ranks as $player => $rankValue) { + $query .= '(' . $player . ',' . $i . ',' . $rankValue . '),'; + $i++; + } + $query = substr($query, 0, strlen($query) - 1); // strip trailing ',' + + $mysqli->query($query); + } + + /** + * Handle PlayerConnect callback + * + * @param Player $player + */ + public function handlePlayerConnect(Player $player) { + $this->showRank($player); + $this->showNextRank($player); + } + + /** + * Shows Ranks on endMap + * + * @param Map $map + */ + public function handleEndMap(Map $map) { + $this->resetRanks(); + + foreach($this->maniaControl->playerManager->getPlayers() as $player) { + /** @var Player $player */ + if ($player->isFakePlayer()) { + continue; + } + $this->showRank($player); + $this->showNextRank($player); + } + + // Trigger callback + $this->maniaControl->callbackManager->triggerCallback(self::CB_RANK_BUILT); + } + + /** + * Shows the serverRank to a certain Player + * + * @param Player $player + */ + public function showRank(Player $player) { + $rankObj = $this->getRank($player); + + $type = $this->maniaControl->settingManager->getSetting($this, self::SETTING_MIN_RANKING_TYPE); + + $message = ''; + if ($rankObj) { + switch($type) { + case self::RANKING_TYPE_RATIOS: + $kd = $this->maniaControl->statisticManager->getStatisticData(StatisticManager::SPECIAL_STAT_KD_RATIO, $player->index); + $acc = $this->maniaControl->statisticManager->getStatisticData(StatisticManager::SPECIAL_STAT_LASER_ACC, $player->index); + $message = '$0f3Your Server rank is $<$ff3' . $rankObj->rank . '$> / $<$fff' . $this->recordCount . '$> (K/D: $<$fff' . round($kd, 2) . '$> Acc: $<$fff' . round($acc * 100) . '%$>)'; + break; + case self::RANKING_TYPE_POINTS: + $message = '$0f3Your Server rank is $<$ff3' . $rankObj->rank . '$> / $<$fff' . $this->recordCount . '$> Points: $fff' . $rankObj->avg; + break; + case self::RANKING_TYPE_RECORDS: + $message = '$0f3Your Server rank is $<$ff3' . $rankObj->rank . '$> / $<$fff' . $this->recordCount . '$> Avg: $fff' . round($rankObj->avg, 2); + } + } else { + switch($type) { + case self::RANKING_TYPE_RATIOS: + $minHits = $this->maniaControl->settingManager->getSetting($this, self::SETTING_MIN_HITS_RATIO_RANKING); + $message = '$0f3 You must make $<$fff' . $minHits . '$> Hits on this server before receiving a rank...'; + break; + case self::RANKING_TYPE_POINTS: + $minHits = $this->maniaControl->settingManager->getSetting($this, self::SETTING_MIN_HITS_POINTS_RANKING); + $message = '$0f3 You must make $<$fff' . $minHits . '$> Hits on this server before receiving a rank...'; + break; + case self::RANKING_TYPE_RECORDS: + $minHits = $this->maniaControl->settingManager->getSetting($this, self::SETTING_MIN_REQUIRED_RECORDS); + $message = '$0f3 You need $<$fff' . $minHits . '$> Records on this server before receiving a rank...'; + } + } + $this->maniaControl->chat->sendChat($message, $player->login); + } + + /** + * Gets A Rank As Object with properties Avg PlayerIndex and Rank + * + * @param Player $player + * @return Rank $rank + */ + private function getRank(Player $player) { + //TODO setting global from db or local + $mysqli = $this->maniaControl->database->mysqli; + + $result = $mysqli->query('SELECT * FROM ' . self::TABLE_RANK . ' WHERE PlayerIndex=' . $player->index); + if ($mysqli->error) { + trigger_error($mysqli->error); + return null; + } + if ($result->num_rows <= 0) { + $result->free_result(); + return null; + } + + $row = $result->fetch_array(); + $result->free_result(); + return Rank::fromArray($row); + } + + /** + * Get the Next Ranked Player + * + * @param Player $player + * @return Rank + */ + private function getNextRank(Player $player) { + $mysqli = $this->maniaControl->database->mysqli; + $rankObject = $this->getRank($player); + $nextRank = $rankObject->rank - 1; + + $result = $mysqli->query('SELECT * FROM ' . self::TABLE_RANK . ' WHERE Rank=' . $nextRank); + if ($result->num_rows > 0) { + $row = $result->fetch_array(); + $result->free_result(); + return Rank::fromArray($row); + } else { + $result->free_result(); + return null; + } + } + + + /** + * Shows the current Server-Rank + * + * @param array $chatCallback + * @param Player $player + */ + public function command_showRank(array $chatCallback, Player $player) { + $this->showRank($player); + } + + /** + * Show the next better ranked player + * + * @param array $chatCallback + * @param Player $player + */ + public function command_nextRank(array $chatCallback, Player $player) { + if (!$this->showNextRank($player)) { + $message = '$0f3You need to have a ServerRank first!'; + $this->maniaControl->chat->sendChat($message, $player->login); + } + } + + + /** + * Shows which Player is next ranked to you + * + * @param Player $player + */ + public function showNextRank(Player $player) { + $rankObject = $this->getRank($player); + + if ($rankObject) { + if ($rankObject->rank > 1) { + $nextRank = $this->getNextRank($player); + $nextPlayer = $this->maniaControl->playerManager->getPlayerByIndex($nextRank->playerIndex); + $message = '$0f3The next better ranked player is $fff' . $nextPlayer->nickname; + } else { + $message = '$0f3No better ranked player :-)'; + } + $this->maniaControl->chat->sendChat($message, $player->login); + + return true; + } + return false; + } + + /** + * Handles /topranks|top100 command + * + * @param array $chatCallback + * @param Player $player + */ + public function command_topRanks(array $chatCallback, Player $player) { + $this->showTopRanksList($player); + } + + /** + * Provides a ManiaLink window with the top ranks to the player + * + * @param Player $player + */ + private function showTopRanksList(Player $player) { + $query = "SELECT * FROM `".self::TABLE_RANK."` ORDER BY `Rank` ASC LIMIT 0, 100"; + $mysqli = $this->maniaControl->database->mysqli; + $result = $mysqli->query($query); + if ($mysqli->error) { + trigger_error($mysqli->error); + return null; + } + + $width = $this->maniaControl->manialinkManager->styleManager->getListWidgetsWidth(); + $height = $this->maniaControl->manialinkManager->styleManager->getListWidgetsHeight(); + + // create manialink + $maniaLink = new ManiaLink(ManialinkManager::MAIN_MLID); + $script = $maniaLink->getScript(); + $paging = new Paging(); + $script->addFeature($paging); + + // Main frame + $frame = $this->maniaControl->manialinkManager->styleManager->getDefaultListFrame($script, $paging); + $maniaLink->add($frame); + + // Start offsets + $x = -$width / 2; + $y = $height / 2; + + //Predefine description Label + $descriptionLabel = $this->maniaControl->manialinkManager->styleManager->getDefaultDescriptionLabel(); + $frame->add($descriptionLabel); + + // Headline + $headFrame = new Frame(); + $frame->add($headFrame); + $headFrame->setY($y - 5); + $array = array('$oRank' => $x + 5, '$oNickname' => $x + 18, '$oAverage' => $x + 70); + $this->maniaControl->manialinkManager->labelLine($headFrame, $array); + + $i = 1; + $y = $y - 10; + $pageFrames = array(); + while($rankedPlayer = $result->fetch_object()) { + if (!isset($pageFrame)) { + $pageFrame = new Frame(); + $frame->add($pageFrame); + if (!empty($pageFrames)) { + $pageFrame->setVisible(false); + } + array_push($pageFrames, $pageFrame); + $y = $height / 2 - 10; + $paging->addPage($pageFrame); + } + + + $playerFrame = new Frame(); + $pageFrame->add($playerFrame); + $playerFrame->setY($y); + + if ($i % 2 != 0) { + $lineQuad = new Quad_BgsPlayerCard(); + $playerFrame->add($lineQuad); + $lineQuad->setSize($width, 4); + $lineQuad->setSubStyle($lineQuad::SUBSTYLE_BgPlayerCardBig); + $lineQuad->setZ(0.001); + } + + $playerObject = $this->maniaControl->playerManager->getPlayerByIndex($rankedPlayer->PlayerIndex); + $array = array($rankedPlayer->Rank => $x + 5, $playerObject->nickname => $x + 18, (string)round($rankedPlayer->Avg, 2) => $x + 70); + $this->maniaControl->manialinkManager->labelLine($playerFrame, $array); + + $y -= 4; + $i++; + if (($i - 1) % 15 == 0) { + unset($pageFrame); + } + } + + // Render and display xml + $this->maniaControl->manialinkManager->displayWidget($maniaLink, $player, 'TopRanks'); + } +} + +/** + * Rank Structure + */ +class Rank extends AbstractStructure { + public $playerIndex; + public $rank; + public $avg; +} \ No newline at end of file diff --git a/application/plugins/MCTeam/WidgetPlugin.php b/application/plugins/MCTeam/WidgetPlugin.php new file mode 100644 index 00000000..79187138 --- /dev/null +++ b/application/plugins/MCTeam/WidgetPlugin.php @@ -0,0 +1,592 @@ + + * @copyright 2014 ManiaControl Team + * @license http://www.gnu.org/licenses/ GNU General Public License, Version 3 + */ +class WidgetPlugin implements CallbackListener, TimerListener, Plugin { + + /** + * Constants + */ + const PLUGIN_ID = 1; + const PLUGIN_VERSION = 0.1; + const PLUGIN_NAME = 'WidgetPlugin'; + const PLUGIN_AUTHOR = 'kremsy'; + + // MapWidget Properties + const MLID_MAPWIDGET = 'WidgetPlugin.MapWidget'; + const SETTING_MAP_WIDGET_ACTIVATED = 'Map-Widget Activated'; + const SETTING_MAP_WIDGET_POSX = 'Map-Widget-Position: X'; + const SETTING_MAP_WIDGET_POSY = 'Map-Widget-Position: Y'; + const SETTING_MAP_WIDGET_WIDTH = 'Map-Widget-Size: Width'; + const SETTING_MAP_WIDGET_HEIGHT = 'Map-Widget-Size: Height'; + + // ClockWidget Properties + const MLID_CLOCKWIDGET = 'WidgetPlugin.ClockWidget'; + const SETTING_CLOCK_WIDGET_ACTIVATED = 'Clock-Widget Activated'; + const SETTING_CLOCK_WIDGET_POSX = 'Clock-Widget-Position: X'; + const SETTING_CLOCK_WIDGET_POSY = 'Clock-Widget-Position: Y'; + const SETTING_CLOCK_WIDGET_WIDTH = 'Clock-Widget-Size: Width'; + const SETTING_CLOCK_WIDGET_HEIGHT = 'Clock-Widget-Size: Height'; + + // NextMapWidget Properties + const MLID_NEXTMAPWIDGET = 'WidgetPlugin.NextMapWidget'; + const SETTING_NEXTMAP_WIDGET_ACTIVATED = 'Nextmap-Widget Activated'; + const SETTING_NEXTMAP_WIDGET_POSX = 'Nextmap-Widget-Position: X'; + const SETTING_NEXTMAP_WIDGET_POSY = 'Nextmap-Widget-Position: Y'; + const SETTING_NEXTMAP_WIDGET_WIDTH = 'Nextmap-Widget-Size: Width'; + const SETTING_NEXTMAP_WIDGET_HEIGHT = 'Nextmap-Widget-Size: Height'; + + // ServerInfoWidget Properties + const MLID_SERVERINFOWIDGET = 'WidgetPlugin.ServerInfoWidget'; + const SETTING_SERVERINFO_WIDGET_ACTIVATED = 'ServerInfo-Widget Activated'; + const SETTING_SERVERINFO_WIDGET_POSX = 'ServerInfo-Widget-Position: X'; + const SETTING_SERVERINFO_WIDGET_POSY = 'ServerInfo-Widget-Position: Y'; + const SETTING_SERVERINFO_WIDGET_WIDTH = 'ServerInfo-Widget-Size: Width'; + const SETTING_SERVERINFO_WIDGET_HEIGHT = 'ServerInfo-Widget-Size: Height'; + + /** + * Private Properties + */ + /** + * @var maniaControl $maniaControl + */ + private $maniaControl = null; + + /** + * Prepares the Plugin + * + * @param ManiaControl $maniaControl + * @return mixed + */ + public static function prepare(ManiaControl $maniaControl) { + //do nothing + } + + /** + * Get plugin id + * + * @return int + */ + public static function getId() { + return self::PLUGIN_ID; + } + + /** + * Get Plugin Name + * + * @return string + */ + public static function getName() { + return self::PLUGIN_NAME; + } + + /** + * Get Plugin Version + * + * @return float,, + */ + public static function getVersion() { + return self::PLUGIN_VERSION; + } + + /** + * Get Plugin Author + * + * @return string + */ + public static function getAuthor() { + return self::PLUGIN_AUTHOR; + } + + /** + * Get Plugin Description + * + * @return string + */ + public static function getDescription() { + return 'Plugin offers some Widgets'; + } + + /** + * Load the plugin + * + * @param ManiaControl $maniaControl + * @return bool + */ + public function load(ManiaControl $maniaControl) { + $this->maniaControl = $maniaControl; + + // Set CustomUI Setting + $this->maniaControl->manialinkManager->customUIManager->setChallengeInfoVisible(false); + + // Register for callbacks + $this->maniaControl->callbackManager->registerCallbackListener(Callbacks::BEGINMAP, $this, 'handleOnBeginMap'); + $this->maniaControl->callbackManager->registerCallbackListener(Callbacks::ENDMAP, $this, 'handleOnEndMap'); + $this->maniaControl->callbackManager->registerCallbackListener(PlayerManager::CB_PLAYERCONNECT, $this, 'handlePlayerConnect'); + $this->maniaControl->callbackManager->registerCallbackListener(PlayerManager::CB_PLAYERDISCONNECT, $this, 'handlePlayerDisconnect'); + + $this->maniaControl->settingManager->initSetting($this, self::SETTING_MAP_WIDGET_ACTIVATED, true); + $this->maniaControl->settingManager->initSetting($this, self::SETTING_MAP_WIDGET_POSX, 160 - 20); + $this->maniaControl->settingManager->initSetting($this, self::SETTING_MAP_WIDGET_POSY, 90 - 4.5); + $this->maniaControl->settingManager->initSetting($this, self::SETTING_MAP_WIDGET_WIDTH, 40); + $this->maniaControl->settingManager->initSetting($this, self::SETTING_MAP_WIDGET_HEIGHT, 9.); + + $this->maniaControl->settingManager->initSetting($this, self::SETTING_SERVERINFO_WIDGET_ACTIVATED, true); + $this->maniaControl->settingManager->initSetting($this, self::SETTING_SERVERINFO_WIDGET_POSX, -160 + 17.5); + $this->maniaControl->settingManager->initSetting($this, self::SETTING_SERVERINFO_WIDGET_POSY, 90 - 4.5); + $this->maniaControl->settingManager->initSetting($this, self::SETTING_SERVERINFO_WIDGET_WIDTH, 35); + $this->maniaControl->settingManager->initSetting($this, self::SETTING_SERVERINFO_WIDGET_HEIGHT, 9.); + + $this->maniaControl->settingManager->initSetting($this, self::SETTING_NEXTMAP_WIDGET_ACTIVATED, true); + $this->maniaControl->settingManager->initSetting($this, self::SETTING_NEXTMAP_WIDGET_POSX, 160 - 20); + $this->maniaControl->settingManager->initSetting($this, self::SETTING_NEXTMAP_WIDGET_POSY, 90 - 25.5); + $this->maniaControl->settingManager->initSetting($this, self::SETTING_NEXTMAP_WIDGET_WIDTH, 40); + $this->maniaControl->settingManager->initSetting($this, self::SETTING_NEXTMAP_WIDGET_HEIGHT, 12.); + + $this->maniaControl->settingManager->initSetting($this, self::SETTING_CLOCK_WIDGET_ACTIVATED, true); + $this->maniaControl->settingManager->initSetting($this, self::SETTING_CLOCK_WIDGET_POSX, 160 - 5); + $this->maniaControl->settingManager->initSetting($this, self::SETTING_CLOCK_WIDGET_POSY, 90 - 11); + $this->maniaControl->settingManager->initSetting($this, self::SETTING_CLOCK_WIDGET_WIDTH, 10); + $this->maniaControl->settingManager->initSetting($this, self::SETTING_CLOCK_WIDGET_HEIGHT, 5.5); + + $this->displayWidgets(); + + return true; + } + + /** + * Display the Widgets + */ + private function displayWidgets() { + // Display Map Widget + if ($this->maniaControl->settingManager->getSetting($this, self::SETTING_MAP_WIDGET_ACTIVATED)) { + $this->maniaControl->client->triggerModeScriptEventArray("Siege_SetProgressionLayerPosition", array("160.", "-67.", "0.")); + $this->displayMapWidget(); + } + if ($this->maniaControl->settingManager->getSetting($this, self::SETTING_CLOCK_WIDGET_ACTIVATED)) { + $this->displayClockWidget(); + } + if ($this->maniaControl->settingManager->getSetting($this, self::SETTING_SERVERINFO_WIDGET_ACTIVATED)) { + $this->displayServerInfoWidget(); + } + } + + /** + * Display the Map Widget + * + * @param string $login + */ + public function displayMapWidget($login = null) { + $pos_x = $this->maniaControl->settingManager->getSetting($this, self::SETTING_MAP_WIDGET_POSX); + $pos_y = $this->maniaControl->settingManager->getSetting($this, self::SETTING_MAP_WIDGET_POSY); + $width = $this->maniaControl->settingManager->getSetting($this, self::SETTING_MAP_WIDGET_WIDTH); + $height = $this->maniaControl->settingManager->getSetting($this, self::SETTING_MAP_WIDGET_HEIGHT); + $quadStyle = $this->maniaControl->manialinkManager->styleManager->getDefaultQuadStyle(); + $quadSubstyle = $this->maniaControl->manialinkManager->styleManager->getDefaultQuadSubstyle(); + + $maniaLink = new ManiaLink(self::MLID_MAPWIDGET); + $script = new Script(); + $maniaLink->setScript($script); + + // mainframe + $frame = new Frame(); + $maniaLink->add($frame); + $frame->setSize($width, $height); + $frame->setPosition($pos_x, $pos_y); + + // Background Quad + $backgroundQuad = new Quad(); + $frame->add($backgroundQuad); + $backgroundQuad->setSize($width, $height); + $backgroundQuad->setStyles($quadStyle, $quadSubstyle); + $backgroundQuad->addMapInfoFeature(); + + $map = $this->maniaControl->mapManager->getCurrentMap(); + + $label = new Label_Text(); + $frame->add($label); + $label->setY(1.5); + $label->setX(0); + $label->setAlign(Control::CENTER, Control::CENTER); + $label->setZ(0.2); + $label->setTextSize(1.3); + $label->setText(Formatter::stripDirtyCodes($map->name)); + $label->setTextColor("FFF"); + $label->setSize($width - 5, $height); + + $label = new Label_Text(); + $frame->add($label); + $label->setX(0); + $label->setY(-1.4); + + $label->setAlign(Control::CENTER, Control::CENTER); + $label->setZ(0.2); + $label->setTextSize(1); + $label->setScale(0.8); + $label->setText($map->authorLogin); + $label->setTextColor("FFF"); + $label->setSize($width - 5, $height); + + if (isset($map->mx->pageurl)) { + $quad = new Quad(); + $frame->add($quad); + $quad->setImageFocus($this->maniaControl->manialinkManager->iconManager->getIcon(IconManager::MX_ICON_MOVER)); + $quad->setImage($this->maniaControl->manialinkManager->iconManager->getIcon(IconManager::MX_ICON)); + $quad->setPosition(-$width / 2 + 4, -1.5, -0.5); + $quad->setSize(4, 4); + $quad->setHAlign(Control::CENTER); + $quad->setUrl($map->mx->pageurl); + } + + // Send manialink + $this->maniaControl->manialinkManager->sendManialink($maniaLink, $login); + } + + /** + * Displays the Clock Widget + * + * @param bool $login + */ + public function displayClockWidget($login = false) { + $pos_x = $this->maniaControl->settingManager->getSetting($this, self::SETTING_CLOCK_WIDGET_POSX); + $pos_y = $this->maniaControl->settingManager->getSetting($this, self::SETTING_CLOCK_WIDGET_POSY); + $width = $this->maniaControl->settingManager->getSetting($this, self::SETTING_CLOCK_WIDGET_WIDTH); + $height = $this->maniaControl->settingManager->getSetting($this, self::SETTING_CLOCK_WIDGET_HEIGHT); + $quadStyle = $this->maniaControl->manialinkManager->styleManager->getDefaultQuadStyle(); + $quadSubstyle = $this->maniaControl->manialinkManager->styleManager->getDefaultQuadSubstyle(); + + $maniaLink = new ManiaLink(self::MLID_CLOCKWIDGET); + + // mainframe + $frame = new Frame(); + $maniaLink->add($frame); + $frame->setSize($width, $height); + $frame->setPosition($pos_x, $pos_y); + + // Background Quad + $backgroundQuad = new Quad(); + $frame->add($backgroundQuad); + $backgroundQuad->setSize($width, $height); + $backgroundQuad->setStyles($quadStyle, $quadSubstyle); + + $label = new Label_Text(); + $frame->add($label); + $label->setY(1.5); + $label->setX(0); + $label->setAlign(Control::CENTER, Control::TOP); + $label->setZ(0.2); + $label->setTextSize(1); + $label->setTextColor("FFF"); + $label->addClockFeature(false); + + // Send manialink + $this->maniaControl->manialinkManager->sendManialink($maniaLink, $login); + } + + /** + * Display the Server Info Widget + * + * @param string $login + */ + public function displayServerInfoWidget($login = null) { + $pos_x = $this->maniaControl->settingManager->getSetting($this, self::SETTING_SERVERINFO_WIDGET_POSX); + $pos_y = $this->maniaControl->settingManager->getSetting($this, self::SETTING_SERVERINFO_WIDGET_POSY); + $width = $this->maniaControl->settingManager->getSetting($this, self::SETTING_SERVERINFO_WIDGET_WIDTH); + $height = $this->maniaControl->settingManager->getSetting($this, self::SETTING_SERVERINFO_WIDGET_HEIGHT); + $quadStyle = $this->maniaControl->manialinkManager->styleManager->getDefaultQuadStyle(); + $quadSubstyle = $this->maniaControl->manialinkManager->styleManager->getDefaultQuadSubstyle(); + + $maniaLink = new ManiaLink(self::MLID_SERVERINFOWIDGET); + + // mainframe + $frame = new Frame(); + $maniaLink->add($frame); + $frame->setSize($width, $height); + $frame->setPosition($pos_x, $pos_y); + + // Background Quad + $backgroundQuad = new Quad(); + $frame->add($backgroundQuad); + $backgroundQuad->setSize($width, $height); + $backgroundQuad->setStyles($quadStyle, $quadSubstyle); + + $maxPlayers = $this->maniaControl->client->getMaxPlayers(); + + $maxSpectators = $this->maniaControl->client->getMaxSpectators(); + + $serverName = $this->maniaControl->client->getServerName(); + + $players = $this->maniaControl->playerManager->getPlayers(); + $playerCount = 0; + $spectatorCount = 0; + /** + * @var Player $player + */ + foreach ($players as $player) { + if ($player->isSpectator) { + $spectatorCount++; + } else { + $playerCount++; + } + } + + $label = new Label_Text(); + $frame->add($label); + $label->setPosition(0, 1.5, 0.2); + $label->setAlign(Control::CENTER, Control::CENTER); + $label->setSize($width - 5, $height); + $label->setTextSize(1.3); + $label->setText(Formatter::stripDirtyCodes($serverName)); + $label->setTextColor("FFF"); + //$label->setAutoNewLine(true); + // Player Quad / Label + $label = new Label_Text(); + $frame->add($label); + $label->setPosition(-$width / 2 + 9, -1.5, 0.2); + $label->setAlign(Control::LEFT, Control::CENTER); + $label->setTextSize(1); + $label->setScale(0.8); + $label->setText($playerCount . " / " . $maxPlayers['NextValue']); + $label->setTextColor("FFF"); + + $quad = new Quad_Icons128x128_1(); + $frame->add($quad); + $quad->setSubStyle($quad::SUBSTYLE_Multiplayer); + $quad->setPosition(-$width / 2 + 7, -1.6, 0.2); + $quad->setSize(2.5, 2.5); + $quad->setHAlign(Control::CENTER); + + // Spectator Quad / Label + $label = new Label_Text(); + $frame->add($label); + $label->setPosition(2, -1.5, 0.2); + $label->setAlign(Control::LEFT, Control::CENTER); + $label->setTextSize(1); + $label->setScale(0.8); + $label->setText($spectatorCount . " / " . $maxSpectators['NextValue']); + $label->setTextColor("FFF"); + + $quad = new Quad_Icons64x64_1(); + $frame->add($quad); + $quad->setSubStyle($quad::SUBSTYLE_Camera); + $quad->setPosition(0, -1.6, 0.2); + $quad->setSize(3.3, 2.5); + $quad->setHAlign(Control::CENTER); + + // Favorite quad + $quad = new Quad_Icons64x64_1(); + $frame->add($quad); + $quad->setSubStyle($quad::SUBSTYLE_StateFavourite); + $quad->setPosition($width / 2 - 4, -1.5, -0.5); + $quad->setSize(3, 3); + $quad->setHAlign(Control::CENTER); + $quad->setManialink('mcontrol?favorite=' . urlencode($this->maniaControl->server->login)); + + // Send manialink + $this->maniaControl->manialinkManager->sendManialink($maniaLink, $login); + } + + /** + * Unload the plugin and its resources + */ + public function unload() { + //Restore Siege Progression Layer + $this->maniaControl->client->triggerModeScriptEventArray("Siege_SetProgressionLayerPosition", array("160.", "90.", "0.")); + + $this->closeWidget(self::MLID_CLOCKWIDGET); + $this->closeWidget(self::MLID_SERVERINFOWIDGET); + $this->closeWidget(self::MLID_MAPWIDGET); + $this->closeWidget(self::MLID_NEXTMAPWIDGET); + $this->maniaControl->callbackManager->unregisterCallbackListener($this); + $this->maniaControl->timerManager->unregisterTimerListenings($this); + unset($this->maniaControl); + } + + /** + * Closes a Widget + * + * @param $widgetId + */ + public function closeWidget($widgetId) { + $emptyManialink = new ManiaLink($widgetId); + $this->maniaControl->manialinkManager->sendManialink($emptyManialink); + } + + /** + * Handle on Begin Map + * + * @param Map $map + */ + public function handleOnBeginMap(Map $map) { + // Display Map Widget + if ($this->maniaControl->settingManager->getSetting($this, self::SETTING_MAP_WIDGET_ACTIVATED)) { + $this->displayMapWidget(); + } + $this->closeWidget(self::MLID_NEXTMAPWIDGET); + } + + /** + * Handle on End Map + * + * @param Map $map + */ + public function handleOnEndMap(Map $map) { + // Display Map Widget + if ($this->maniaControl->settingManager->getSetting($this, self::SETTING_NEXTMAP_WIDGET_ACTIVATED)) { + $this->displayNextMapWidget(); + } + } + + /** + * Displays the Next Map (Only at the end of the Map) + * + * @param bool $login + */ + public function displayNextMapWidget($login = false) { + $pos_x = $this->maniaControl->settingManager->getSetting($this, self::SETTING_NEXTMAP_WIDGET_POSX); + $pos_y = $this->maniaControl->settingManager->getSetting($this, self::SETTING_NEXTMAP_WIDGET_POSY); + $width = $this->maniaControl->settingManager->getSetting($this, self::SETTING_NEXTMAP_WIDGET_WIDTH); + $height = $this->maniaControl->settingManager->getSetting($this, self::SETTING_NEXTMAP_WIDGET_HEIGHT); + $quadStyle = $this->maniaControl->manialinkManager->styleManager->getDefaultQuadStyle(); + $quadSubstyle = $this->maniaControl->manialinkManager->styleManager->getDefaultQuadSubstyle(); + $labelStyle = $this->maniaControl->manialinkManager->styleManager->getDefaultLabelStyle(); + + $maniaLink = new ManiaLink(self::MLID_NEXTMAPWIDGET); + + // mainframe + $frame = new Frame(); + $maniaLink->add($frame); + $frame->setSize($width, $height); + $frame->setPosition($pos_x, $pos_y); + + // Background Quad + $backgroundQuad = new Quad(); + $frame->add($backgroundQuad); + $backgroundQuad->setSize($width, $height); + $backgroundQuad->setStyles($quadStyle, $quadSubstyle); + + // Check if the Next Map is a queued Map + $queuedMap = $this->maniaControl->mapManager->mapQueue->getNextMap(); + + /** + * @var Player $requester + */ + $requester = null; + // if the nextmap is not a queued map, get it from map info + if (!$queuedMap) { + $map = $this->maniaControl->client->getNextMapInfo(); + $name = Formatter::stripDirtyCodes($map->name); + $author = $map->author; + } else { + $requester = $queuedMap[0]; + $map = $queuedMap[1]; + $name = $map->name; + $author = $map->authorLogin; + } + + $label = new Label_Text(); + $frame->add($label); + $label->setY($height / 2 - 2.3); + $label->setX(0); + $label->setAlign(Control::CENTER, Control::CENTER); + $label->setZ(0.2); + $label->setTextSize(1); + $label->setText("Next Map"); + $label->setTextColor("FFF"); + $label->setStyle($labelStyle); + + $label = new Label_Text(); + $frame->add($label); + $label->setY($height / 2 - 5.5); + $label->setX(0); + $label->setAlign(Control::CENTER, Control::CENTER); + $label->setZ(0.2); + $label->setTextSize(1.3); + $label->setText($name); + $label->setTextColor("FFF"); + + $label = new Label_Text(); + $frame->add($label); + $label->setX(0); + $label->setY(-$height / 2 + 4); + + $label->setAlign(Control::CENTER, Control::CENTER); + $label->setZ(0.2); + $label->setTextSize(1); + $label->setScale(0.8); + $label->setText($author); + $label->setTextColor("FFF"); + + if ($requester) { + $label = new Label_Text(); + $frame->add($label); + $label->setX(0); + $label->setY(-$height / 2 + 2); + $label->setAlign(Control::CENTER, Control::CENTER); + $label->setZ(0.2); + $label->setTextSize(1); + $label->setScale(0.7); + $label->setText($author); + $label->setTextColor("F80"); + $label->setText("Requested by " . $requester->nickname); + } + + // Send manialink + $this->maniaControl->manialinkManager->sendManialink($maniaLink, $login); + } + + /** + * Handle PlayerConnect callback + * + * @param Player $player + */ + public function handlePlayerConnect(Player $player) { + // Display Map Widget + if ($this->maniaControl->settingManager->getSetting($this, self::SETTING_MAP_WIDGET_ACTIVATED)) { + $this->displayMapWidget($player->login); + } + if ($this->maniaControl->settingManager->getSetting($this, self::SETTING_CLOCK_WIDGET_ACTIVATED)) { + $this->displayClockWidget($player->login); + } + if ($this->maniaControl->settingManager->getSetting($this, self::SETTING_SERVERINFO_WIDGET_ACTIVATED)) { + $this->displayServerInfoWidget(); + } + } + + /** + * Handle PlayerConnect callback + * + * @param Player $player + */ + public function handlePlayerDisconnect(Player $player) { + if ($this->maniaControl->settingManager->getSetting($this, self::SETTING_SERVERINFO_WIDGET_ACTIVATED)) { + $this->displayServerInfoWidget(); + } + } +} \ No newline at end of file diff --git a/application/plugins/Obstacle.php b/application/plugins/Obstacle.php new file mode 100644 index 00000000..e69de29b diff --git a/application/plugins/QueuePlugin.php b/application/plugins/QueuePlugin.php new file mode 100644 index 00000000..91806859 --- /dev/null +++ b/application/plugins/QueuePlugin.php @@ -0,0 +1,570 @@ +maniaControl = $maniaControl; + + $this->maniaControl->timerManager->registerTimerListening($this, 'handleEverySecond', 1000); + $this->maniaControl->callbackManager->registerCallbackListener(PlayerManager::CB_PLAYERCONNECT, $this, 'handlePlayerConnect'); + $this->maniaControl->callbackManager->registerCallbackListener(PlayerManager::CB_PLAYERDISCONNECT, $this, 'handlePlayerDisconnect'); + $this->maniaControl->callbackManager->registerCallbackListener(CallbackManager::CB_MP_PLAYERINFOCHANGED, $this, 'handlePlayerInfoChanged'); + $this->maniaControl->callbackManager->registerCallbackListener(Callbacks::BEGINMAP, $this, 'handleBeginMap'); + $this->maniaControl->manialinkManager->registerManialinkPageAnswerListener(self::ML_ADDTOQUEUE, $this, 'handleManiaLinkAnswerAdd'); + $this->maniaControl->manialinkManager->registerManialinkPageAnswerListener(self::ML_REMOVEFROMQUEUE, $this, 'handleManiaLinkAnswerRemove'); + + $this->maniaControl->settingManager->initSetting($this, self::QUEUE_MAX, 8); + $this->maniaControl->settingManager->initSetting($this, self::QUEUE_WIDGET_POS_X, 0); + $this->maniaControl->settingManager->initSetting($this, self::QUEUE_WIDGET_POS_Y, -46); + $this->maniaControl->settingManager->initSetting($this, self::QUEUE_ACTIVE_ON_PASS, false); + $this->maniaControl->settingManager->initSetting($this, self::QUEUE_CHATMESSAGES, true); + + $maxPlayers = $this->maniaControl->client->getMaxPlayers(); + $this->maxPlayers = $maxPlayers['CurrentValue']; + + foreach($this->maniaControl->playerManager->getPlayers() as $player) { + if ($player->isSpectator) { + $this->spectators[$player->login] = $player->login; + $this->maniaControl->client->forceSpectator($player->login, 1); + $this->showJoinQueueWidget($player); + } + } + } + + /** + * Unload the plugin and its resources + */ + public function unload() { + $this->maniaControl->manialinkManager->unregisterManialinkPageAnswerListener($this); + $this->maniaControl->callbackManager->unregisterCallbackListener($this); + $this->maniaControl->timerManager->unregisterTimerListenings($this); + + foreach($this->spectators as $spectator) { + $this->maniaControl->client->forceSpectator($spectator, 3); + $this->maniaControl->client->forceSpectator($spectator, 0); + } + + foreach($this->maniaControl->playerManager->getPlayers() as $player) { + $this->hideQueueWidget($player); + } + + $this->queue = array(); + $this->spectators = array(); + $this->showPlay = array(); + unset($this->maniaControl); + } + + /** + * Get plugin id + * + * @return int + */ + public static function getId() { + return self::ID; + } + + /** + * Get Plugin Name + * + * @return string + */ + public static function getName() { + return 'Queue Plugin'; + } + + /** + * Get Plugin Version + * + * @return float + */ + public static function getVersion() { + return self::VERSION; + } + + /** + * Get Plugin Author + * + * @return string + */ + public static function getAuthor() { + return 'TheM'; + } + + /** + * Get Plugin Description + * + * @return string + */ + public static function getDescription() { + return 'Plugin offers the known AutoQueue/SpecJam options.'; + } + + /** + * Function handling on the connection of a player. + * + * @param Player $player + */ + public function handlePlayerConnect(Player $player) { + $maxPlayers = $this->maniaControl->client->getMaxPlayers(); + $this->maxPlayers = $maxPlayers['CurrentValue']; + + if ($player->isSpectator) { + $this->spectators[$player->login] = $player->login; + $this->maniaControl->client->forceSpectator($player->login, 1); + $this->showJoinQueueWidget($player); + } else { + if (count($this->queue) != 0) { + $this->maniaControl->client->forceSpectator($player->login, 1); + $this->spectators[$player->login] = $player->login; + $this->showJoinQueueWidget($player); + } + } + } + + /** + * Function handling on the disconnection of a player. + * + * @param Player $player + */ + public function handlePlayerDisconnect(Player $player) { + $maxPlayers = $this->maniaControl->client->getMaxPlayers(); + $this->maxPlayers = $maxPlayers['CurrentValue']; + + if (isset($this->spectators[$player->login])) { + unset($this->spectators[$player->login]); + } + $this->removePlayerFromQueue($player->login); + $this->moveFirstPlayerToPlay(); + } + + /** + * Function handling the change of player information. + * + * @param array $callback + */ + public function handlePlayerInfoChanged(array $callback) { + $login = $callback[1][0]['Login']; + $player = $this->maniaControl->playerManager->getPlayer($login); + + if (!is_null($player)) { + if ($player->isSpectator) { + if (!isset($this->spectators[$player->login])) { + $this->maniaControl->client->forceSpectator($player->login, 1); + $this->spectators[$player->login] = $player->login; + $this->showJoinQueueWidget($player); + $this->showQueueWidgetSpectators(); + } + } else { + $this->removePlayerFromQueue($player->login); + if (isset($this->spectators[$player->login])) { + unset($this->spectators[$player->login]); + } + + $found = false; + foreach($this->showPlay as $showPlay) { + if ($showPlay['player']->login == $player->login) { + $found = true; + } + } + + if (!$found) { + $this->hideQueueWidget($player); + } + } + } + } + + public function showQueueWidgetSpectators() { + foreach($this->spectators as $login) { + $player = $this->maniaControl->playerManager->getPlayer($login); + $this->showJoinQueueWidget($player); + } + } + + /** + * Function called on every second. + */ + public function handleEverySecond() { + if ($this->maxPlayers > (count($this->maniaControl->playerManager->players) - count($this->spectators))) { + $this->moveFirstPlayerToPlay(); + $this->showQueueWidgetSpectators(); + } + + foreach($this->showPlay as $showPlay) { + if (($showPlay['time'] + 5) < time()) { + $this->hideQueueWidget($showPlay['player']); + unset($this->showPlay[$showPlay['player']->login]); + } + } + } + + /** + * Checks for being of new map to retrieve maximum number of players. + * + * @param $currentMap + */ + public function handleBeginMap($currentMap) { + $maxPlayers = $this->maniaControl->client->getMaxPlayers(); + $this->maxPlayers = $maxPlayers['CurrentValue']; + } + + /** + * Function handling the click of the widget to add them to the queue. + * + * @param array $chatCallback + * @param Player $player + */ + public function handleManiaLinkAnswerAdd(array $chatCallback, Player $player) { + $this->addPlayerToQueue($player); + } + + /** + * Function handling the click of the widget to remove them from the queue. + * + * @param array $chatCallback + * @param Player $player + */ + public function handleManiaLinkAnswerRemove(array $chatCallback, Player $player) { + $this->removePlayerFromQueue($player->login); + $this->showJoinQueueWidget($player); + $this->sendChatMessage('$<$fff' . $player->nickname . '$> has left the queue!'); + } + + /** + * Function used to move the first queued player to the + */ + private function moveFirstPlayerToPlay() { + if (count($this->queue) > 0) { + $firstPlayer = $this->maniaControl->playerManager->getPlayer($this->queue[0]->login); + $this->forcePlayerToPlay($firstPlayer); + $this->showQueueWidgetSpectators(); + } + } + + /** + * Function to force a player to play status. + * + * @param Player $player + */ + private function forcePlayerToPlay(Player $player) { + if ($this->maniaControl->client->getServerPassword() != false && $this->maniaControl->settingManager->getSetting($this, self::QUEUE_ACTIVE_ON_PASS) == false) { + return; + } + + if ($this->maxPlayers > (count($this->maniaControl->playerManager->players) - count($this->spectators))) { + try { + $this->maniaControl->client->forceSpectator($player->login, 2); + } catch(Exception $e) { + // TODO: only possible valid exception should be "wrong login" - throw others (like connection error) + $this->maniaControl->chat->sendError("Error while leaving the Queue", $player->login); + return; + } + + try { + $this->maniaControl->client->forceSpectator($player->login, 0); + } catch(Exception $e) { + // TODO: only possible valid exception should be "wrong login" - throw others (like connection error) + } + + $teams = array(); + /** @var Player $playerObj */ + foreach($this->maniaControl->playerManager->players as $playerObj) { + if (!isset($teams[$playerObj->teamId])) { + $teams[$playerObj->teamId] = 1; + } else { + $teams[$playerObj->teamId]++; + } + } + + $smallestTeam = null; + $smallestSize = 999; + foreach($teams as $team => $size) { + if ($size < $smallestSize) { + $smallestTeam = $team; + $smallestSize = $size; + } + } + + try { + if ($smallestTeam != -1) { + $this->maniaControl->client->forcePlayerTeam($player->login, $smallestTeam); + } + } catch(Exception $e) { + // TODO: only possible valid exceptions should be "wrong login" or "not in team mode" - throw others (like connection error) + } + + if (isset($this->spectators[$player->login])) { + unset($this->spectators[$player->login]); + } + $this->removePlayerFromQueue($player->login); + $this->showPlayWidget($player); + $this->sendChatMessage('$<$fff' . $player->nickname . '$> has a free spot and is now playing!'); + } + + } + + /** + * Function adds a player to the queue. + * + * @param Player $player + * @return bool + */ + private function addPlayerToQueue(Player $player) { + if ($this->maniaControl->client->getServerPassword() != false && $this->maniaControl->settingManager->getSetting($this, self::QUEUE_ACTIVE_ON_PASS) == false) { + return false; + } + + foreach($this->queue as $queuedPlayer) { + if ($queuedPlayer->login == $player->login) { + $this->maniaControl->chat->sendError('You\'re already in the queue!', $player->login); + return false; + } + } + + if ($this->maniaControl->settingManager->getSetting($this, self::QUEUE_MAX) > count($this->queue)) { + $this->queue[count($this->queue)] = $player; + $this->sendChatMessage('$<$fff' . $player->nickname . '$> just joined the queue!'); + } + + $this->showQueueWidgetSpectators(); + + return true; + } + + /** + * Function removes a player from the queue. + * + * @param $login + */ + private function removePlayerFromQueue($login) { + $count = 0; + $newQueue = array(); + foreach($this->queue as $queuePlayer) { + if ($queuePlayer->login != $login) { + $newQueue[$count] = $queuePlayer; + $count++; + } + } + + $this->queue = $newQueue; + $this->showQueueWidgetSpectators(); + } + + /** + * Function sends (or not depending on setting) chatmessages for the queue. + * + * @param $message + */ + private function sendChatMessage($message) { + if ($this->maniaControl->settingManager->getSetting($this, self::QUEUE_CHATMESSAGES)) { + $this->maniaControl->chat->sendChat('$090[Queue] ' . $message); + } + } + + /** + * Function shows the join queue widget to a player. + * + * @param Player $player + */ + private function showJoinQueueWidget(Player $player) { + $maniaLink = new ManiaLink(self::ML_ID); + + $quadStyle = $this->maniaControl->manialinkManager->styleManager->getDefaultMainWindowStyle(); + $quadSubstyle = $this->maniaControl->manialinkManager->styleManager->getDefaultMainWindowSubStyle(); + $max_queue = $this->maniaControl->settingManager->getSetting($this, self::QUEUE_MAX); + + // Main frame + $frame = new Frame(); + $maniaLink->add($frame); + $frame->setSize(60, 6); + $frame->setPosition($this->maniaControl->settingManager->getSetting($this, self::QUEUE_WIDGET_POS_X), $this->maniaControl->settingManager->getSetting($this, self::QUEUE_WIDGET_POS_Y), 0); + + // Background + $backgroundQuad = new Quad(); + $frame->add($backgroundQuad); + $backgroundQuad->setPosition(0, 0, 0); + $backgroundQuad->setSize(70, 10); + $backgroundQuad->setStyles($quadStyle, $quadSubstyle); + + $cameraQuad = new Quad_Icons64x64_1(); + $frame->add($cameraQuad); + $cameraQuad->setPosition(-29, 0.4, 2); + $cameraQuad->setSize(9, 9); + $cameraQuad->setSubStyle(Quad_Icons64x64_1::SUBSTYLE_Camera); + + $statusLabel = new Label_Text(); + $frame->add($statusLabel); + $statusLabel->setPosition(4.5, 2.8, 1); + $statusLabel->setSize(66, 4); + $statusLabel->setAlign('center', 'center'); + $statusLabel->setScale(0.8); + $statusLabel->setStyle(Label_Text::STYLE_TextStaticSmall); + + $messageLabel = new Label_Button(); + $frame->add($messageLabel); + $messageLabel->setPosition(4.5, -1.6, 1); + $messageLabel->setSize(56, 4); + $messageLabel->setAlign('center', 'center'); + $messageLabel->setScale(1.0); + + $inQueue = false; + foreach($this->queue as $queuedPlayer) { + if ($queuedPlayer->login == $player->login) { + $inQueue = true; + } + } + + if ($inQueue) { + $message = '$fff$sYou\'re in the queue (click to unqueue).'; + + $position = 0; + foreach(array_values($this->queue) as $i => $queuePlayer) { + if ($player->login == $queuePlayer->login) { + $position = ($i + 1); + } + } + + $statusLabel->setText('$aaaStatus: In queue (' . $position . '/' . count($this->queue) . ') Waiting: ' . count($this->queue) . '/' . $max_queue . ''); + $messageLabel->setAction(self::ML_REMOVEFROMQUEUE); + $backgroundQuad->setAction(self::ML_REMOVEFROMQUEUE); + $statusLabel->setAction(self::ML_REMOVEFROMQUEUE); + $cameraQuad->setAction(self::ML_REMOVEFROMQUEUE); + } else { + if (count($this->queue) < $max_queue) { + $message = '$0ff$sClick to join spectator waiting list.'; + $messageLabel->setAction(self::ML_ADDTOQUEUE); + $backgroundQuad->setAction(self::ML_ADDTOQUEUE); + $statusLabel->setAction(self::ML_ADDTOQUEUE); + $cameraQuad->setAction(self::ML_ADDTOQUEUE); + } else { + $message = '$f00The waiting list is full!'; + } + + $statusLabel->setText('$aaaStatus: Not queued spectator Waiting: ' . count($this->queue) . '/' . $max_queue . ''); + } + + $messageLabel->setText($message); + $messageLabel->setStyle(Label_Text::STYLE_TextStaticSmall); + + $this->maniaControl->manialinkManager->sendManialink($maniaLink, $player->login); + } + + /** + * Function shows the "You got a free spot, enjoy playing!" widget. + * + * @param Player $player + */ + private function showPlayWidget(Player $player) { + $maniaLink = new ManiaLink(self::ML_ID); + + $quadStyle = $this->maniaControl->manialinkManager->styleManager->getDefaultMainWindowStyle(); + $quadSubstyle = $this->maniaControl->manialinkManager->styleManager->getDefaultMainWindowSubStyle(); + + // Main frame + $frame = new Frame(); + $maniaLink->add($frame); + $frame->setSize(60, 6); + $frame->setPosition($this->maniaControl->settingManager->getSetting($this, self::QUEUE_WIDGET_POS_X), $this->maniaControl->settingManager->getSetting($this, self::QUEUE_WIDGET_POS_Y), 0); + + // Background + $backgroundQuad = new Quad(); + $frame->add($backgroundQuad); + $backgroundQuad->setPosition(0, 0, 0); + $backgroundQuad->setSize(70, 10); + $backgroundQuad->setStyles($quadStyle, $quadSubstyle); + + $cameraQuad = new Quad_Icons64x64_1(); + $frame->add($cameraQuad); + $cameraQuad->setPosition(-29, 0.4, 2); + $cameraQuad->setSize(9, 9); + $cameraQuad->setSubStyle(Quad_Icons64x64_1::SUBSTYLE_Camera); + + $messageLabel = new Label_Button(); + $frame->add($messageLabel); + $messageLabel->setPosition(4.5, 0.6, 1); + $messageLabel->setSize(56, 4); + $messageLabel->setAlign('center', 'center'); + $messageLabel->setScale(1.0); + $messageLabel->setText('$090You got a free spot, enjoy playing!'); + $messageLabel->setStyle(Label_Text::STYLE_TextStaticSmall); + + $this->maniaControl->manialinkManager->sendManialink($maniaLink, $player->login); + $this->showPlay[$player->login] = array('time' => time(), 'player' => $player); + } + + /** + * Function hides the queue widget from the player. + * + * @param Player $player + */ + private function hideQueueWidget(Player $player) { + $maniaLink = new ManiaLink(self::ML_ID); + $this->maniaControl->manialinkManager->sendManialink($maniaLink, $player->login); + } +} \ No newline at end of file diff --git a/application/plugins/ServerRanking.php b/application/plugins/ServerRanking.php new file mode 100644 index 00000000..e69de29b diff --git a/application/plugins/TeamSpeakPlugin.php b/application/plugins/TeamSpeakPlugin.php new file mode 100644 index 00000000..8c9db17b --- /dev/null +++ b/application/plugins/TeamSpeakPlugin.php @@ -0,0 +1,514 @@ +settingManager->initSetting(get_class(), self::TEAMSPEAK_SID, 1); + $maniaControl->settingManager->initSetting(get_class(), self::TEAMSPEAK_SERVERHOST, 'ts3.somehoster.com'); + $maniaControl->settingManager->initSetting(get_class(), self::TEAMSPEAK_SERVERPORT, 9987); + $maniaControl->settingManager->initSetting(get_class(), self::TEAMSPEAK_QUERYHOST, ''); + $maniaControl->settingManager->initSetting(get_class(), self::TEAMSPEAK_QUERYPORT, 10011); + $maniaControl->settingManager->initSetting(get_class(), self::TEAMSPEAK_QUERYUSER, ''); + $maniaControl->settingManager->initSetting(get_class(), self::TEAMSPEAK_QUERYPASS, ''); + } + + /** + * Load the plugin + * + * @param \ManiaControl\ManiaControl $maniaControl + * @return bool + */ + public function load(ManiaControl $maniaControl) { + $this->maniaControl = $maniaControl; + $this->checkConfig(); + + $this->refreshTime = time(); + + $this->maniaControl->manialinkManager->iconManager->addIcon(self::TS_ICON); + $this->maniaControl->manialinkManager->iconManager->addIcon(self::TS_ICON_MOVER); + + $this->maniaControl->timerManager->registerTimerListening($this, 'ts3_queryServer', 1000); + + $this->addToMenu(); + } + + + /** + * Function used to check certain configuration options to check if they can be used. + * + * @throws Exception + */ + private function checkConfig() { + if ($this->maniaControl->settingManager->getSetting($this, self::TEAMSPEAK_SERVERHOST) == 'ts3.somehoster.com') { + $error = 'Missing the required serverhost, please set it up before enabling the TeamSpeak plugin!'; + throw new Exception($error); + } + + $this->ts3_queryServer(); // Get latest information from the TeamSpeak server + if (!isset($this->serverData['channels']) || count($this->serverData['channels']) == 0) { + $error = 'Could not make proper connections with the server!'; + throw new Exception($error); + } + } + + /** + * Function used insert the icon into the menu. + */ + private function addToMenu() { + $this->maniaControl->manialinkManager->registerManialinkPageAnswerListener(self::ACTION_OPEN_TSVIEWER, $this, 'command_tsViewer'); + $itemQuad = new Quad(); + $itemQuad->setImage($this->maniaControl->manialinkManager->iconManager->getIcon(self::TS_ICON)); + $itemQuad->setImageFocus($this->maniaControl->manialinkManager->iconManager->getIcon(self::TS_ICON_MOVER)); + $itemQuad->setAction(self::ACTION_OPEN_TSVIEWER); + $this->maniaControl->actionsMenu->addMenuItem($itemQuad, true, 1, 'Open TeamSpeak Viewer'); + } + + /** + * Unload the plugin and its resources + */ + public function unload() { + $this->serverData = array(); + + $this->maniaControl->actionsMenu->removeMenuItem(1, true); + $this->maniaControl->manialinkManager->unregisterManialinkPageAnswerListener($this); + $this->maniaControl->callbackManager->unregisterCallbackListener($this); + $this->maniaControl->commandManager->unregisterCommandListener($this); + $this->maniaControl->timerManager->unregisterTimerListenings($this); + unset($this->maniaControl); + } + + /** + * Get plugin id + * + * @return int + */ + public static function getId() { + return self::ID; + } + + /** + * Get Plugin Name + * + * @return string + */ + public static function getName() { + return 'TeamSpeak Plugin'; + } + + /** + * Get Plugin Version + * + * @return float + */ + public static function getVersion() { + return self::VERSION; + } + + /** + * Get Plugin Author + * + * @return string + */ + public static function getAuthor() { + return 'TheM'; + } + + /** + * Get Plugin Description + * + * @return string + */ + public static function getDescription() { + return 'Plugin offers a connection with a TeamSpeak server (via widgets).'; + } + + /** + * Function handling the pressing of the icon. + * + * @param array $chatCallback + * @param Player $player + */ + public function command_tsViewer(array $chatCallback, Player $player) { + $this->showWidget($player); + } + + /** + * Function showing the TeamSpeak widget to the player. + * + * @param $player + */ + private function showWidget($player) { + $width = $this->maniaControl->manialinkManager->styleManager->getListWidgetsWidth(); + $height = $this->maniaControl->manialinkManager->styleManager->getListWidgetsHeight(); + $quadStyle = $this->maniaControl->manialinkManager->styleManager->getDefaultMainWindowStyle(); + $quadSubstyle = $this->maniaControl->manialinkManager->styleManager->getDefaultMainWindowSubStyle(); + + $maniaLink = new ManiaLink(ManialinkManager::MAIN_MLID); + + // Main frame + $frame = new Frame(); + $maniaLink->add($frame); + $frame->setSize($width, $height); + $frame->setPosition(0, 0, 10); + + // Background + $backgroundQuad = new Quad(); + $frame->add($backgroundQuad); + $backgroundQuad->setSize($width, $height); + $backgroundQuad->setStyles($quadStyle, $quadSubstyle); + + // Close Quad (X) + $closeQuad = new Quad_Icons64x64_1(); + $frame->add($closeQuad); + $closeQuad->setPosition($width * 0.483, $height * 0.467, 3); + $closeQuad->setSize(6, 6); + $closeQuad->setSubStyle(Quad_Icons64x64_1::SUBSTYLE_QuitRace); + $closeQuad->setAction(ManialinkManager::ACTION_CLOSEWIDGET); + + $servername = new Label_Text(); + $frame->add($servername); + $servername->setY($height / 2 - 4); + $servername->setX(-70); + $servername->setStyle($servername::STYLE_TextCardMedium); + $servername->setHAlign('left'); + $servername->setTextSize(1); + $servername->setText('$oServername:$o ' . $this->serverData['server']['virtualserver_name']); + $servername->setTextColor('fff'); + + $serverversion = new Label_Text(); + $frame->add($serverversion); + $serverversion->setY($height / 2 - 4); + $serverversion->setX(2); + $serverversion->setStyle($serverversion::STYLE_TextCardMedium); + $serverversion->setHAlign('left'); + $serverversion->setTextSize(1); + $serverversion->setText('$oServerversion:$o ' . $this->serverData['server']['virtualserver_version']); + $serverversion->setTextColor('fff'); + + $clients = new Label_Text(); + $frame->add($clients); + $clients->setY($height / 2 - 7); + $clients->setX(-70); + $clients->setStyle($clients::STYLE_TextCardMedium); + $clients->setHAlign('left'); + $clients->setTextSize(1); + $clients->setText('$oConnected clients:$o ' . $this->serverData['server']['virtualserver_clientsonline'] . '/' . $this->serverData['server']['virtualserver_maxclients']); + $clients->setTextColor('fff'); + + $channels = new Label_Text(); + $frame->add($channels); + $channels->setY($height / 2 - 7); + $channels->setX(2); + $channels->setStyle($channels::STYLE_TextCardMedium); + $channels->setHAlign('left'); + $channels->setTextSize(1); + $nochannels = 0; + foreach($this->serverData['channels'] as $channel) { + if ($channel['channel_maxclients'] == 0 || strpos($channel['channel_name'], 'spacer') > 0) { + continue; + } + $nochannels++; + } + $channels->setText('$oChannels:$o ' . $nochannels); + $channels->setTextColor('fff'); + + // Join button + $joinbutton = new Label_Button(); + $frame->add($joinbutton); + $joinbutton->setWidth(150); + $joinbutton->setY($height / 2 - 11.5); + $joinbutton->setStyle($joinbutton::STYLE_CardButtonSmallWide); + $joinbutton->setText('Join TeamSpeak: ' . $this->maniaControl->settingManager->getSetting($this, self::TEAMSPEAK_SERVERHOST) . ':' . $this->maniaControl->settingManager->getSetting($this, self::TEAMSPEAK_SERVERPORT)); + $joinbutton->setTextColor('fff'); + $url = 'ts3server://' . $this->maniaControl->settingManager->getSetting($this, self::TEAMSPEAK_SERVERHOST) . '/?port=' . $this->maniaControl->settingManager->getSetting($this, self::TEAMSPEAK_SERVERPORT) . '&nickname=' . rawurlencode(\ManiaControl\Formatter::stripCodes($player->nickname)); + $joinbutton->setUrl($url); + + $leftlistQuad = new Quad(); + $frame->add($leftlistQuad); + $leftlistQuad->setSize((($width / 2) - 5), ($height - 18)); + $leftlistQuad->setX(-36); + $leftlistQuad->setY($height / 2 - 46); + $leftlistQuad->setStyles($quadStyle, $quadSubstyle); + + $channels = array(); + $users = array(); + $userid = 0; + $i = 0; + $startx = -69.5; + foreach($this->serverData['channels'] as $channel) { + if ($channel['channel_maxclients'] == 0 || strpos($channel['channel_name'], 'spacer') > 0) { + continue; + } + $channelLabel = new Label_Text(); + $frame->add($channelLabel); + $y = 17.5 + ($i * 2.5); + $channelLabel->setY($height / 2 - $y); + $x = $startx; + if ($channel['pid'] != 0) { + $x = $startx + 5; + } + $channelLabel->setX($x); + $channelLabel->setStyle($channelLabel::STYLE_TextCardMedium); + $channelLabel->setHAlign('left'); + $channelLabel->setTextSize(1); + $channelLabel->setScale(0.9); + if ($channel['channel_flag_default'] == 1) { + $channel['total_clients'] = ($channel['total_clients'] - 1); + } // remove query client + $channelLabel->setText('$o' . $channel['channel_name'] . '$o (' . $channel['total_clients'] . ')'); + $channelLabel->setTextColor('fff'); + + $channels[$i] = $channelLabel; + + $i++; + foreach($this->serverData['users'] as $user) { + if ($user['cid'] == $channel['cid']) { + $userLabel = new Label_Text(); + $frame->add($userLabel); + $y = 17.5 + ($i * 2.5); + $userLabel->setY($height / 2 - $y); + if ($channel['pid'] != 0) { + $x = $startx + 7; + } else { + $x = $startx + 2; + } + $userLabel->setX($x); + $userLabel->setStyle($userLabel::STYLE_TextCardMedium); + $userLabel->setHAlign('left'); + $userLabel->setTextSize(1); + $userLabel->setScale(0.9); + $userLabel->setText($user['client_nickname']); + $userLabel->setTextColor('fff'); + $users[$userid] = $userLabel; + + $userid++; + $i++; + + if ($i > 22) { + $i = 0; + $startx = 2.5; + } + } + } + + if ($i > 22) { + $i = 0; + $startx = 2.5; + } + } + + $rightlistQuad = new Quad(); + $frame->add($rightlistQuad); + $rightlistQuad->setSize((($width / 2) - 5), ($height - 18)); + $rightlistQuad->setX(36); + $rightlistQuad->setY($height / 2 - 46); + $rightlistQuad->setStyles($quadStyle, $quadSubstyle); + + $this->maniaControl->manialinkManager->displayWidget($maniaLink, $player, 'TSViewer'); + } + + /** + * TeamSpeak related functions + * The functions are based upon tsstatus.php from http://tsstatus.sebastien.me/ + * and were optimized by SilentStorm. + * Functions originally from the TeamSpeakInfo plugin made by undef.de for XAseco(2) and MPAseco. + */ + + public function ts3_queryServer() { + if (time() >= $this->refreshTime) { + $this->refreshTime = (time() + $this->refreshInterval); + + $queryhost = $this->maniaControl->settingManager->getSetting($this, self::TEAMSPEAK_QUERYHOST); + $host = $this->maniaControl->settingManager->getSetting($this, self::TEAMSPEAK_SERVERHOST); + + $host = ($queryhost != '') ? $queryhost : $host; + + $socket = fsockopen(@$host, $this->maniaControl->settingManager->getSetting($this, self::TEAMSPEAK_QUERYPORT), $errno, $errstr, 2); + if ($socket) { + socket_set_timeout($socket, 2); + $is_ts3 = trim(fgets($socket)) == 'TS3'; + if (!$is_ts3) { + trigger_error('[TeamSpeakPlugin] Server at "' . $host . '" is not a Teamspeak3-Server or you have setup a bad query-port!', E_USER_WARNING); + } + + $queryuser = $this->maniaControl->settingManager->getSetting($this, self::TEAMSPEAK_QUERYUSER); + $querypass = $this->maniaControl->settingManager->getSetting($this, self::TEAMSPEAK_QUERYPASS); + if (($queryuser != '') && !is_numeric($queryuser) && $queryuser != false && ($querypass != '') && !is_numeric($querypass) && $querypass != false) { + $ret = $this->ts3_sendCommand($socket, 'login client_login_name=' . $this->ts3_escape($queryuser) . ' client_login_password=' . $this->ts3_escape($querypass)); + if (stripos($ret, "error id=0") === false) { + trigger_error("[TeamSpeakPlugin] Failed to authenticate with TS3 Server! Make sure you put the correct username & password in teamspeak.xml", E_USER_WARNING); + return; + } + } + + $response = ''; + $response .= $this->ts3_sendCommand($socket, 'use sid=' . $this->maniaControl->settingManager->getSetting($this, self::TEAMSPEAK_SID)); + $this->ts3_sendCommand($socket, 'clientupdate client_nickname=' . $this->ts3_escape('ManiaControl Viewer')); + $response .= $this->ts3_sendCommand($socket, 'serverinfo'); + $response .= $this->ts3_sendCommand($socket, 'channellist -topic -flags -voice -limits'); + $response .= $this->ts3_sendCommand($socket, 'clientlist -uid -away -voice -groups'); + + fputs($socket, "quit\n"); + fclose($socket); + + $lines = explode("error id=0 msg=ok\n\r", $response); + if (count($lines) == 5) { + $serverdata = $this->ts3_parseLine($lines[1]); + $this->serverData['server'] = $serverdata[0]; + $this->serverData['channels'] = $this->ts3_parseLine($lines[2]); + + $users = $this->ts3_parseLine($lines[3]); + $this->serverData['users'] = array(); // reset userslist + foreach($users as $user) { + if ($user['client_nickname'] != 'ManiaControl Viewer') { + $this->serverData['users'][] = $user; + } + } + + // Subtract reserved slots + $this->serverData['server']['virtualserver_maxclients'] -= $this->serverData['server']['virtualserver_reserved_slots']; + + // Make ping value int + $this->serverData['server']['virtualserver_total_ping'] = intval($this->serverData['server']['virtualserver_total_ping']); + + // Format the Date of server startup + $this->serverData['server']['virtualserver_uptime'] = date('Y-m-d H:i:s', (time() - $this->serverData['server']['virtualserver_uptime'])); + + // Always subtract all Query Clients + $this->serverData['server']['virtualserver_clientsonline'] -= $this->serverData['server']['virtualserver_queryclientsonline']; + } + } else { + trigger_error("[TeamSpeakPlugin] Failed to connect with TS3 server; socket error: " . $errstr . " [" . $errno . "]", E_USER_WARNING); + } + } + } + + /** + * TS Function to send a command to the TeamSpeak server. + * + * @param $socket + * @param $cmd + * @return string + */ + private function ts3_sendCommand($socket, $cmd) { + + fputs($socket, "$cmd\n"); + + $response = ''; + /*while(strpos($response, 'error id=') === false) { + $response .= fread($socket, 8096); + }*/ + + /*while (!feof($socket)) { + $response .= fread($socket, 8192); + }*/ + + $info = array('timed_out' => false); + while(!feof($socket) && !$info['timed_out'] && strpos($response, 'error id=') === false) { + $response .= fread($socket, 1024); + $info = stream_get_meta_data($socket); + } + + return $response; + } + + /** + * TS Function used to parse lines in the serverresponse. + * + * @param $rawLine + * @return array + */ + private function ts3_parseLine($rawLine) { + + $datas = array(); + $rawItems = explode('|', $rawLine); + + foreach($rawItems as &$rawItem) { + $rawDatas = explode(' ', $rawItem); + $tempDatas = array(); + foreach($rawDatas as &$rawData) { + $ar = explode("=", $rawData, 2); + $tempDatas[$ar[0]] = isset($ar[1]) ? $this->ts3_unescape($ar[1]) : ''; + } + $datas[] = $tempDatas; + } + unset($rawItem, $rawData); + + return $datas; + } + + /** + * TS Function used to escape characters in channelnames. + * + * @param $str + * @return mixed + */ + private function ts3_escape($str) { + return str_replace(array(chr(92), chr(47), chr(32), chr(124), chr(7), chr(8), chr(12), chr(10), chr(3), chr(9), chr(11)), array('\\\\', "\/", "\s", "\p", "\a", "\b", "\f", "\n", "\r", "\t", "\v"), $str); + } + + /** + * TS Function used to unescape characters in channelnames. + * + * @param $str + * @return mixed + */ + private function ts3_unescape($str) { + return str_replace(array('\\\\', "\/", "\s", "\p", "\a", "\b", "\f", "\n", "\r", "\t", "\v"), array(chr(92), chr(47), chr(32), chr(124), chr(7), chr(8), chr(12), chr(10), chr(3), chr(9), chr(11)), $str); + } + +} \ No newline at end of file diff --git a/application/plugins/steeffeen/ChatlogPlugin.php b/application/plugins/steeffeen/ChatlogPlugin.php new file mode 100644 index 00000000..599a9d63 --- /dev/null +++ b/application/plugins/steeffeen/ChatlogPlugin.php @@ -0,0 +1,160 @@ +maniaControl = $maniaControl; + + // Init settings + $this->maniaControl->settingManager->initSetting($this, self::SETTING_FOLDERNAME, 'logs'); + $this->maniaControl->settingManager->initSetting($this, self::SETTING_FILENAME, 'ChatLog.log'); + $this->maniaControl->settingManager->initSetting($this, self::SETTING_USEPID, false); + $this->maniaControl->settingManager->initSetting($this, self::SETTING_LOGSERVERMESSAGES, true); + + // Get settings + $folderName = $this->maniaControl->settingManager->getSetting($this, self::SETTING_FOLDERNAME); + $folderName = FileUtil::getClearedFileName($folderName); + $folderDir = ManiaControlDir . $folderName; + if (!is_dir($folderDir)) { + $success = mkdir($folderDir); + if (!$success) { + trigger_error("Couldn't create chat log folder '{$folderName}'."); + } + } + $fileName = $this->maniaControl->settingManager->getSetting($this, self::SETTING_FILENAME); + $fileName = FileUtil::getClearedFileName($fileName); + $usePId = $this->maniaControl->settingManager->getSetting($this, self::SETTING_USEPID); + if ($usePId) { + $dotIndex = strripos($fileName, '.'); + $pIdPart = '_' . getmypid(); + if ($dotIndex !== false && $dotIndex >= 0) { + $fileName = substr($fileName, 0, $dotIndex) . $pIdPart . substr($fileName, $dotIndex); + } else { + $fileName .= $pIdPart; + } + } + $this->fileName = $folderDir . DIRECTORY_SEPARATOR . $fileName; + $this->logServerMessages = $this->maniaControl->settingManager->getSetting($this, self::SETTING_LOGSERVERMESSAGES); + + // Register for callbacks + $this->maniaControl->callbackManager->registerCallbackListener(CallbackManager::CB_MP_PLAYERCHAT, $this, 'handlePlayerChatCallback'); + + return true; + } + + /** + * @see \ManiaControl\Plugins\Plugin::unload() + */ + public function unload() { + $this->maniaControl->callbackManager->unregisterCallbackListener($this); + unset($this->maniaControl); + } + + /** + * @see \ManiaControl\Plugins\Plugin::getId() + */ + public static function getId() { + return self::ID; + } + + /** + * @see \ManiaControl\Plugins\Plugin::getName() + */ + public static function getName() { + return 'Chatlog Plugin'; + } + + /** + * @see \ManiaControl\Plugins\Plugin::getVersion() + */ + public static function getVersion() { + return self::VERSION; + } + + /** + * @see \ManiaControl\Plugins\Plugin::getAuthor() + */ + public static function getAuthor() { + return 'steeffeen'; + } + + /** + * @see \ManiaControl\Plugins\Plugin::getDescription() + */ + public static function getDescription() { + return 'Plugin logging the Chat Messages of the Server for later Checks and Controlling.'; + } + + /** + * Handle PlayerChat callback + * + * @param array $chatCallback + */ + public function handlePlayerChatCallback(array $chatCallback) { + $data = $chatCallback[1]; + if ($data[0] <= 0 && !$this->logServerMessages) { + // Skip server message + return; + } + $this->logText($data[2], $data[1]); + } + + /** + * Log the given message + * + * @param string $text + * @param string $login + */ + private function logText($text, $login = null) { + if (!$login) { + $login = ''; + } + $message = date(self::DATE) . " >> {$login}: {$text}" . PHP_EOL; + file_put_contents($this->fileName, $message, FILE_APPEND); + } +} diff --git a/application/plugins/steeffeen/EndurancePlugin.php b/application/plugins/steeffeen/EndurancePlugin.php new file mode 100644 index 00000000..5e342a43 --- /dev/null +++ b/application/plugins/steeffeen/EndurancePlugin.php @@ -0,0 +1,157 @@ +maniaControl = $maniaControl; + + // Register for callbacks + $this->maniaControl->callbackManager->registerCallbackListener(CallbackManager::CB_ONINIT, $this, 'callback_OnInit'); + $this->maniaControl->callbackManager->registerCallbackListener(Callbacks::BEGINMAP, $this, 'callback_BeginMap'); + $this->maniaControl->callbackManager->registerScriptCallbackListener(self::CB_CHECKPOINT, $this, 'callback_Checkpoint'); + + return true; + } + + /** + * + * @see \ManiaControl\Plugins\Plugin::unload() + */ + public function unload() { + $this->maniaControl->callbackManager->unregisterCallbackListener($this); + $this->maniaControl->callbackManager->unregisterScriptCallbackListener($this); + unset($this->maniaControl); + } + + /** + * + * @see \ManiaControl\Plugins\Plugin::getId() + */ + public static function getId() { + return self::ID; + } + + /** + * + * @see \ManiaControl\Plugins\Plugin::getName() + */ + public static function getName() { + return 'Endurance Plugin'; + } + + /** + * + * @see \ManiaControl\Plugins\Plugin::getVersion() + */ + public static function getVersion() { + return self::VERSION; + } + + /** + * + * @see \ManiaControl\Plugins\Plugin::getAuthor() + */ + public static function getAuthor() { + return 'steeffeen'; + } + + /** + * + * @see \ManiaControl\Plugins\Plugin::getDescription() + */ + public static function getDescription() { + return "Plugin enabling Support for the TM Game Mode 'Endurance' by TGYoshi."; + } + + /** + * Handle ManiaControl OnInit callback + * + * @param array $callback + */ + public function callback_OnInit(array $callback) { + $this->currentMap = $this->maniaControl->mapManager->getCurrentMap(); + $this->playerLapTimes = array(); + } + + /** + * Handle BeginMap callback + * + * @param Map $map + */ + public function callback_BeginMap(Map $map) { + $this->currentMap = $map; + $this->playerLapTimes = array(); + } + + /** + * Handle Endurance Checkpoint callback + * + * @param array $callback + */ + public function callback_Checkpoint(array $callback) { + $callbackData = json_decode($callback[1]); + if (!$this->currentMap->nbCheckpoints || $callbackData->Checkpoint % $this->currentMap->nbCheckpoints != 0) { + return; + } + $player = $this->maniaControl->playerManager->getPlayer($callbackData->Login); + if (!$player) { + return; + } + $time = $callbackData->Time; + if ($time <= 0) { + return; + } + if (isset($this->playerLapTimes[$player->login])) { + $time -= $this->playerLapTimes[$player->login]; + } + $this->playerLapTimes[$player->login] = $callbackData->Time; + // Trigger trackmania player finish callback + $finishCallback = array($player->pid, $player->login, $time); + $finishCallback = array(CallbackManager::CB_TM_PLAYERFINISH, $finishCallback); + $this->maniaControl->callbackManager->triggerCallback(CallbackManager::CB_TM_PLAYERFINISH, $finishCallback); + } +} diff --git a/application/plugins/steeffeen/ObstaclePlugin.php b/application/plugins/steeffeen/ObstaclePlugin.php new file mode 100644 index 00000000..f78f3390 --- /dev/null +++ b/application/plugins/steeffeen/ObstaclePlugin.php @@ -0,0 +1,181 @@ +maniaControl = $maniaControl; + + // Init settings + $this->maniaControl->settingManager->initSetting($this, self::SETTING_JUMPTOAUTHLEVEL, AuthenticationManager::AUTH_LEVEL_MODERATOR); + + // Register for commands + $this->maniaControl->commandManager->registerCommandListener('jumpto', $this, 'command_JumpTo'); + + // Register for callbacks + $this->maniaControl->callbackManager->registerScriptCallbackListener(self::SCB_ONFINISH, $this, 'callback_OnFinish'); + $this->maniaControl->callbackManager->registerScriptCallbackListener(self::SCB_ONCHECKPOINT, $this, 'callback_OnCheckpoint'); + + return true; + } + + /** + * + * @see \ManiaControl\Plugins\Plugin::unload() + */ + public function unload() { + $this->maniaControl->commandManager->unregisterCommandListener($this); + $this->maniaControl->callbackManager->unregisterScriptCallbackListener($this); + unset($this->maniaControl); + } + + /** + * + * @see \ManiaControl\Plugins\Plugin::getId() + */ + public static function getId() { + return self::ID; + } + + /** + * + * @see \ManiaControl\Plugins\Plugin::getName() + */ + public static function getName() { + return 'Obstacle Plugin'; + } + + /** + * + * @see \ManiaControl\Plugins\Plugin::getVersion() + */ + public static function getVersion() { + return self::VERSION; + } + + /** + * + * @see \ManiaControl\Plugins\Plugin::getAuthor() + */ + public static function getAuthor() { + return 'steeffeen'; + } + + /** + * + * @see \ManiaControl\Plugins\Plugin::getDescription() + */ + public static function getDescription() { + return "Plugin offering CP Jumping and Local Records Support for the ShootManie Gamemode 'Obstacle'."; + } + + /** + * Handle JumpTo command + * + * @param array $chatCallback + * @param Player $player + * @return bool + */ + public function command_JumpTo(array $chatCallback, Player $player) { + $authLevel = $this->maniaControl->settingManager->getSetting($this, self::SETTING_JUMPTOAUTHLEVEL); + if (!$this->maniaControl->authenticationManager->checkRight($player, $authLevel)) { + $this->maniaControl->authenticationManager->sendNotAllowed($player); + return; + } + // Send jump callback + $params = explode(' ', $chatCallback[1][2], 2); + $param = $player->login . ";" . $params[1] . ";"; + try { + $this->maniaControl->client->triggerModeScriptEvent(self::CB_JUMPTO, $param); + } + catch (Exception $e) { + if ($e->getMessage() == 'Not in script mode.') { + trigger_error("Couldn't send jump callback for '{$player->login}'. " . $e->getMessage()); + return; + } + throw $e; + } + } + + /** + * Handle OnFinish script callback + * + * @param array $callback + */ + public function callback_OnFinish(array $callback) { + $data = json_decode($callback[1]); + $player = $this->maniaControl->playerManager->getPlayer($data->Player->Login); + if (!$player) { + return; + } + $time = $data->Run->Time; + // Trigger trackmania player finish callback + $finishCallback = array($player->pid, $player->login, $time); + $this->maniaControl->callbackManager->triggerCallback(CallbackManager::CB_TM_PLAYERFINISH, + array(CallbackManager::CB_TM_PLAYERFINISH, $finishCallback)); + } + + /** + * Handle OnCheckpoint script callback + * + * @param array $callback + */ + public function callback_OnCheckpoint(array $callback) { + $data = json_decode($callback[1]); + $player = $this->maniaControl->playerManager->getPlayer($data->Player->Login); + $time = $data->Run->Time; + if (!$player || $time <= 0) { + return; + } + // Trigger Trackmania player checkpoint callback + $checkpointCallback = array($player->pid, $player->login, $time, 0, 0); + $this->maniaControl->callbackManager->triggerCallback(CallbackManager::CB_TM_PLAYERCHECKPOINT, + array(CallbackManager::CB_TM_PLAYERCHECKPOINT, $checkpointCallback)); + } +}