From d989efd9cde11e9bbc5ec474b220106d5f47c89b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Steffen=20Schro=CC=88der?= Date: Sun, 4 May 2014 00:36:20 +0200 Subject: [PATCH] updated dedimania plugin namespace to MCTeam --- .../plugins/Dedimania/DedimaniaData.php | 108 -- .../plugins/Dedimania/DedimaniaPlayer.php | 48 - .../plugins/Dedimania/DedimaniaPlugin.php | 1181 ---------------- application/plugins/Dedimania/RecordData.php | 65 - .../plugins/MCTeam/Dedimania/Dedimania.php | 0 .../MCTeam/Dedimania/DedimaniaData.php | 108 ++ .../MCTeam/Dedimania/DedimaniaPlayer.php | 48 + .../MCTeam/Dedimania/DedimaniaPlugin.php | 1182 +++++++++++++++++ .../plugins/MCTeam/Dedimania/RecordData.php | 65 + 9 files changed, 1403 insertions(+), 1402 deletions(-) create mode 100644 application/plugins/MCTeam/Dedimania/Dedimania.php create mode 100644 application/plugins/MCTeam/Dedimania/DedimaniaData.php create mode 100644 application/plugins/MCTeam/Dedimania/DedimaniaPlayer.php create mode 100644 application/plugins/MCTeam/Dedimania/DedimaniaPlugin.php create mode 100644 application/plugins/MCTeam/Dedimania/RecordData.php diff --git a/application/plugins/Dedimania/DedimaniaData.php b/application/plugins/Dedimania/DedimaniaData.php index 704ea39b..e69de29b 100644 --- a/application/plugins/Dedimania/DedimaniaData.php +++ b/application/plugins/Dedimania/DedimaniaData.php @@ -1,108 +0,0 @@ - - * @copyright 2014 ManiaControl Team - * @license http://www.gnu.org/licenses/ GNU General Public License, Version 3 - */ -class DedimaniaData { - /* - * Constants - */ - public $game; - public $path; - public $packmask; - public $serverVersion; - public $serverBuild; - public $tool; - public $version; - public $login; - public $code; - public $sessionId = ''; - public $records = array(); - public $players = array(); - public $directoryAccessChecked = false; - public $serverMaxRank = 30; - - /** - * Construct a new Dedimania Data Model - * - * @param string $serverLogin - * @param string $dedimaniaCode - * @param string $path - * @param string $packmask - * @param Version $serverVersion - */ - public function __construct($serverLogin, $dedimaniaCode, $path, $packmask, Version $serverVersion) { - $this->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 index fbd187b5..e69de29b 100644 --- a/application/plugins/Dedimania/DedimaniaPlayer.php +++ b/application/plugins/Dedimania/DedimaniaPlayer.php @@ -1,48 +0,0 @@ - - * @copyright 2014 ManiaControl Team - * @license http://www.gnu.org/licenses/ GNU General Public License, Version 3 - */ -class DedimaniaPlayer { - /* - * Public Properties - */ - public $login = ''; - public $maxRank = -1; - public $banned = false; - public $optionsEnabled = false; - public $options = ''; - - /** - * Construct a new Dedimania Player Model - * @param mixed$player - */ - public function __construct($player) { - if (!$player) { - return; - } - - $this->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 string $login - * @param int $maxRank - */ - public function constructNewPlayer($login, $maxRank) { - $this->login = $login; - $this->maxRank = $maxRank; - } -} \ No newline at end of file diff --git a/application/plugins/Dedimania/DedimaniaPlugin.php b/application/plugins/Dedimania/DedimaniaPlugin.php index 017ce57f..e69de29b 100644 --- a/application/plugins/Dedimania/DedimaniaPlugin.php +++ b/application/plugins/Dedimania/DedimaniaPlugin.php @@ -1,1181 +0,0 @@ - - * @copyright 2014 ManiaControl Team - * @license http://www.gnu.org/licenses/ GNU General Public License, Version 3 - */ -class DedimaniaPlugin implements CallbackListener, CommandListener, TimerListener, Plugin { - /* - * Constants - */ - const ID = 8; - const VERSION = 0.1; - const AUTHOR = 'MCTeam'; - const NAME = 'Dedimania Plugin'; - const MLID_DEDIMANIA = 'Dedimania.ManialinkId'; - const XMLRPC_MULTICALL = 'system.multicall'; - const DEDIMANIA_URL = 'http://dedimania.net:8081/Dedimania'; - const DEDIMANIA_OPENSESSION = 'dedimania.OpenSession'; - const DEDIMANIA_CHECKSESSION = 'dedimania.CheckSession'; - const DEDIMANIA_GETRECORDS = 'dedimania.GetChallengeRecords'; - const DEDIMANIA_PLAYERCONNECT = 'dedimania.PlayerConnect'; - const DEDIMANIA_PLAYERDISCONNECT = 'dedimania.PlayerDisconnect'; - const DEDIMANIA_UPDATESERVERPLAYERS = 'dedimania.UpdateServerPlayers'; - const DEDIMANIA_SETCHALLENGETIMES = 'dedimania.SetChallengeTimes'; - const DEDIMANIA_WARNINGSANDTTR2 = 'dedimania.WarningsAndTTR2'; - const SETTING_WIDGET_ENABLE = 'Enable Dedimania 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 Width'; - const SETTING_WIDGET_LINESCOUNT = 'Widget Displayed Lines Count'; - const SETTING_WIDGET_LINEHEIGHT = 'Widget Line Height'; - const SETTING_DEDIMANIA_CODE = '$l[http://dedimania.net/tm2stats/?do=register]Dedimania Code for '; - const CB_DEDIMANIA_CHANGED = 'Dedimania.Changed'; - const CB_DEDIMANIA_UPDATED = 'Dedimania.Updated'; - const ACTION_SHOW_DEDIRECORDSLIST = 'Dedimania.ShowDediRecordsList'; - - /* - * Private Properties - */ - /** @var ManiaControl $maniaControl */ - private $maniaControl = null; - /** @var DedimaniaData $dedimaniaData */ - private $dedimaniaData = null; - private $updateManialink = false; - private $checkpoints = array(); - private $init = false; - - /** - * @see \ManiaControl\Plugins\Plugin::prepare() - */ - public static function prepare(ManiaControl $maniaControl) { - $maniaControl->database->migrationHelper->transferSettings('Dedimania\Dedimania', get_class()); - - $servers = $maniaControl->server->getAllServers(); - foreach ($servers as $server) { - $maniaControl->settingManager->initSetting(get_class(), self::SETTING_DEDIMANIA_CODE . $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 self::NAME; - } - - /** - * @see \ManiaControl\Plugins\Plugin::getVersion() - */ - public static function getVersion() { - return self::VERSION; - } - - /** - * @see \ManiaControl\Plugins\Plugin::getAuthor() - */ - public static function getAuthor() { - return self::AUTHOR; - } - - /** - * @see \ManiaControl\Plugins\Plugin::getDescription() - */ - public static function getDescription() { - return "Dedimania Plugin for Trackmania"; - } - - /** - * @see \ManiaControl\Plugins\Plugin::load() - */ - 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); - } - - /** - * 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')); - } - - /** - * Decodes xml rpc response - * - * @param string $response - * @return mixed - */ - private function decode($response) { - return xmlrpc_decode($response, 'utf-8'); - } - - /** - * Handle xml rpc fault - * - * @param $fault - * @param $method - */ - private function handleXmlRpcFault($fault, $method) { - trigger_error('XmlRpc Fault on ' . $method . ': ' . $fault['faultString'] . ' (' . $fault['faultCode'] . ')'); - } - - /** - * 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; - } - - /** - * 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; - } - - /** - * 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; - } - - /** - * 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); - } - } - - /** - * 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; - } - - /** - * Check if the session is alive every minute - * - * @param null $callback - */ - public function handleEveryMinute($callback = null) { - if (!$this->init) { - return; - } - $this->checkDedimaniaSession(); - } - - /** - * 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; - } - - /** - * 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); - } - - /** - * 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); - } - - /** - * 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; - } - } - } - - /** - * 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 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; - } - - /** - * 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); - } - - /** - * 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; - } - } - } - } - - /** - * 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); - } - } - - /** - * 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'); - } - - /** - * 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; - } - - /** - * @see \ManiaControl\Plugins\Plugin::unload() - */ - public function unload() { - } - - /** - * 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; - } - } - } -} \ No newline at end of file diff --git a/application/plugins/Dedimania/RecordData.php b/application/plugins/Dedimania/RecordData.php index 1ae40d89..e69de29b 100644 --- a/application/plugins/Dedimania/RecordData.php +++ b/application/plugins/Dedimania/RecordData.php @@ -1,65 +0,0 @@ - - * @copyright 2014 ManiaControl Team - * @license http://www.gnu.org/licenses/ GNU General Public License, Version 3 - */ -class RecordData { - /* - * Public Properties - */ - public $nullRecord = false; - public $login = ''; - public $nickName = ''; - public $best = -1; - public $rank = -1; - public $maxRank = -1; - public $checkpoints = ''; - public $newRecord = false; - public $vReplay = ''; - public $top1GReplay = ''; - - /** - * Construct a Record by a given Record Array - * - * @param array $record - */ - public function __construct($record) { - if (!$record) { - $this->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']; - } - - /** - * Construct a new Record via its Properties - * - * @param string $login - * @param string $nickName - * @param float $best - * @param int $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; - } -} diff --git a/application/plugins/MCTeam/Dedimania/Dedimania.php b/application/plugins/MCTeam/Dedimania/Dedimania.php new file mode 100644 index 00000000..e69de29b diff --git a/application/plugins/MCTeam/Dedimania/DedimaniaData.php b/application/plugins/MCTeam/Dedimania/DedimaniaData.php new file mode 100644 index 00000000..bd4d936f --- /dev/null +++ b/application/plugins/MCTeam/Dedimania/DedimaniaData.php @@ -0,0 +1,108 @@ + + * @copyright 2014 ManiaControl Team + * @license http://www.gnu.org/licenses/ GNU General Public License, Version 3 + */ +class DedimaniaData { + /* + * Constants + */ + public $game; + public $path; + public $packmask; + public $serverVersion; + public $serverBuild; + public $tool; + public $version; + public $login; + public $code; + public $sessionId = ''; + public $records = array(); + public $players = array(); + public $directoryAccessChecked = false; + public $serverMaxRank = 30; + + /** + * Construct a new Dedimania Data Model + * + * @param string $serverLogin + * @param string $dedimaniaCode + * @param string $path + * @param string $packmask + * @param Version $serverVersion + */ + public function __construct($serverLogin, $dedimaniaCode, $path, $packmask, Version $serverVersion) { + $this->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/MCTeam/Dedimania/DedimaniaPlayer.php b/application/plugins/MCTeam/Dedimania/DedimaniaPlayer.php new file mode 100644 index 00000000..9046527d --- /dev/null +++ b/application/plugins/MCTeam/Dedimania/DedimaniaPlayer.php @@ -0,0 +1,48 @@ + + * @copyright 2014 ManiaControl Team + * @license http://www.gnu.org/licenses/ GNU General Public License, Version 3 + */ +class DedimaniaPlayer { + /* + * Public Properties + */ + public $login = ''; + public $maxRank = -1; + public $banned = false; + public $optionsEnabled = false; + public $options = ''; + + /** + * Construct a new Dedimania Player Model + * @param mixed$player + */ + public function __construct($player) { + if (!$player) { + return; + } + + $this->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 string $login + * @param int $maxRank + */ + public function constructNewPlayer($login, $maxRank) { + $this->login = $login; + $this->maxRank = $maxRank; + } +} \ No newline at end of file diff --git a/application/plugins/MCTeam/Dedimania/DedimaniaPlugin.php b/application/plugins/MCTeam/Dedimania/DedimaniaPlugin.php new file mode 100644 index 00000000..28bb05bf --- /dev/null +++ b/application/plugins/MCTeam/Dedimania/DedimaniaPlugin.php @@ -0,0 +1,1182 @@ + + * @copyright 2014 ManiaControl Team + * @license http://www.gnu.org/licenses/ GNU General Public License, Version 3 + */ +class DedimaniaPlugin implements CallbackListener, CommandListener, TimerListener, Plugin { + /* + * Constants + */ + const ID = 8; + const VERSION = 0.1; + const AUTHOR = 'MCTeam'; + const NAME = 'Dedimania Plugin'; + const MLID_DEDIMANIA = 'Dedimania.ManialinkId'; + const XMLRPC_MULTICALL = 'system.multicall'; + const DEDIMANIA_URL = 'http://dedimania.net:8081/Dedimania'; + const DEDIMANIA_OPENSESSION = 'dedimania.OpenSession'; + const DEDIMANIA_CHECKSESSION = 'dedimania.CheckSession'; + const DEDIMANIA_GETRECORDS = 'dedimania.GetChallengeRecords'; + const DEDIMANIA_PLAYERCONNECT = 'dedimania.PlayerConnect'; + const DEDIMANIA_PLAYERDISCONNECT = 'dedimania.PlayerDisconnect'; + const DEDIMANIA_UPDATESERVERPLAYERS = 'dedimania.UpdateServerPlayers'; + const DEDIMANIA_SETCHALLENGETIMES = 'dedimania.SetChallengeTimes'; + const DEDIMANIA_WARNINGSANDTTR2 = 'dedimania.WarningsAndTTR2'; + const SETTING_WIDGET_ENABLE = 'Enable Dedimania 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 Width'; + const SETTING_WIDGET_LINESCOUNT = 'Widget Displayed Lines Count'; + const SETTING_WIDGET_LINEHEIGHT = 'Widget Line Height'; + const SETTING_DEDIMANIA_CODE = '$l[http://dedimania.net/tm2stats/?do=register]Dedimania Code for '; + const CB_DEDIMANIA_CHANGED = 'Dedimania.Changed'; + const CB_DEDIMANIA_UPDATED = 'Dedimania.Updated'; + const ACTION_SHOW_DEDIRECORDSLIST = 'Dedimania.ShowDediRecordsList'; + + /* + * Private Properties + */ + /** @var ManiaControl $maniaControl */ + private $maniaControl = null; + /** @var DedimaniaData $dedimaniaData */ + private $dedimaniaData = null; + private $updateManialink = false; + private $checkpoints = array(); + private $init = false; + + /** + * @see \ManiaControl\Plugins\Plugin::prepare() + */ + public static function prepare(ManiaControl $maniaControl) { + $maniaControl->database->migrationHelper->transferSettings('Dedimania\Dedimania', get_class()); + $maniaControl->database->migrationHelper->transferSettings('Dedimania\DedimaniaPlugin', get_class()); + + $servers = $maniaControl->server->getAllServers(); + foreach ($servers as $server) { + $maniaControl->settingManager->initSetting(get_class(), self::SETTING_DEDIMANIA_CODE . $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 self::NAME; + } + + /** + * @see \ManiaControl\Plugins\Plugin::getVersion() + */ + public static function getVersion() { + return self::VERSION; + } + + /** + * @see \ManiaControl\Plugins\Plugin::getAuthor() + */ + public static function getAuthor() { + return self::AUTHOR; + } + + /** + * @see \ManiaControl\Plugins\Plugin::getDescription() + */ + public static function getDescription() { + return "Dedimania Plugin for Trackmania"; + } + + /** + * @see \ManiaControl\Plugins\Plugin::load() + */ + 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); + } + + /** + * 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')); + } + + /** + * Decodes xml rpc response + * + * @param string $response + * @return mixed + */ + private function decode($response) { + return xmlrpc_decode($response, 'utf-8'); + } + + /** + * Handle xml rpc fault + * + * @param $fault + * @param $method + */ + private function handleXmlRpcFault($fault, $method) { + trigger_error('XmlRpc Fault on ' . $method . ': ' . $fault['faultString'] . ' (' . $fault['faultCode'] . ')'); + } + + /** + * 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; + } + + /** + * 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; + } + + /** + * 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; + } + + /** + * 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); + } + } + + /** + * 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; + } + + /** + * Check if the session is alive every minute + * + * @param null $callback + */ + public function handleEveryMinute($callback = null) { + if (!$this->init) { + return; + } + $this->checkDedimaniaSession(); + } + + /** + * 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; + } + + /** + * 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); + } + + /** + * 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); + } + + /** + * 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; + } + } + } + + /** + * 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 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; + } + + /** + * 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); + } + + /** + * 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; + } + } + } + } + + /** + * 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); + } + } + + /** + * 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'); + } + + /** + * 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; + } + + /** + * @see \ManiaControl\Plugins\Plugin::unload() + */ + public function unload() { + } + + /** + * 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; + } + } + } +} \ No newline at end of file diff --git a/application/plugins/MCTeam/Dedimania/RecordData.php b/application/plugins/MCTeam/Dedimania/RecordData.php new file mode 100644 index 00000000..b5628f9f --- /dev/null +++ b/application/plugins/MCTeam/Dedimania/RecordData.php @@ -0,0 +1,65 @@ + + * @copyright 2014 ManiaControl Team + * @license http://www.gnu.org/licenses/ GNU General Public License, Version 3 + */ +class RecordData { + /* + * Public Properties + */ + public $nullRecord = false; + public $login = ''; + public $nickName = ''; + public $best = -1; + public $rank = -1; + public $maxRank = -1; + public $checkpoints = ''; + public $newRecord = false; + public $vReplay = ''; + public $top1GReplay = ''; + + /** + * Construct a Record by a given Record Array + * + * @param array $record + */ + public function __construct($record) { + if (!$record) { + $this->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']; + } + + /** + * Construct a new Record via its Properties + * + * @param string $login + * @param string $nickName + * @param float $best + * @param int $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; + } +}