From 676c03847a872c00868ee2d225a6e7113a27d71a Mon Sep 17 00:00:00 2001 From: Beu Date: Fri, 8 Sep 2023 17:39:56 +0200 Subject: [PATCH] add ClimbTheMap plugin --- .gitignore | 9 +- Beu/ClimbTheMap.php | 374 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 379 insertions(+), 4 deletions(-) create mode 100644 Beu/ClimbTheMap.php diff --git a/.gitignore b/.gitignore index ff0927f..973cb8e 100644 --- a/.gitignore +++ b/.gitignore @@ -6,11 +6,12 @@ !MatchManagerSuite/* !Beu !Beu/AFKNotifier.php +!Beu/BeuDonationButton.php !Beu/ChatAdminColorer.php -!Beu/ReloadDevTool.php +!Beu/ClimbTheMap.php +!Beu/GameModeLoader.php !Beu/GuestlistManager.php !Beu/MoreModesTools.php +!Beu/ReloadDevTool.php !Beu/SimpleChatColorer.php -!Beu/SimpleSkinsRemover.php -!Beu/BeuDonationButton.php -!Beu/GameModeLoader.php \ No newline at end of file +!Beu/SimpleSkinsRemover.php \ No newline at end of file diff --git a/Beu/ClimbTheMap.php b/Beu/ClimbTheMap.php new file mode 100644 index 0000000..e90fa1e --- /dev/null +++ b/Beu/ClimbTheMap.php @@ -0,0 +1,374 @@ +maniaControl = $maniaControl; + + $this->initTables(); + + $this->maniaControl->getCallbackManager()->registerCallbackListener(Callbacks::AFTERINIT, $this, 'handleAfterInit'); + $this->maniaControl->getCallbackManager()->registerCallbackListener(Callbacks::MP_STARTROUNDSTART, $this, 'handleStartRound'); + $this->maniaControl->getCallbackManager()->registerCallbackListener(PlayerManager::CB_PLAYERCONNECT, $this, 'handlePlayerConnect'); + + $this->maniaControl->getCallbackManager()->registerScriptCallbackListener(self::CB_UPDATEPBS, $this, 'handleUpdatePBs'); + + $this->maniaControl->getManialinkManager()->registerManialinkPageAnswerListener(self::A_SHOW_ALTITUDE_RECORDS, $this, 'handleShowAltitudeRecords'); + $this->maniaControl->getCommandManager()->registerCommandListener('records', $this, 'handleShowAltitudeRecords', false); + + $this->maniaControl->getTimerManager()->registerTimerListening($this, 'handle1Minute', 60000); + } + + private function initTables() { + $mysqli = $this->maniaControl->getDatabase()->getMysqli(); + + $query = 'CREATE TABLE IF NOT EXISTS `' . self::DB_CLIMBTHEMAP . '` ( + `index` INT UNSIGNED NOT NULL AUTO_INCREMENT, + `mapIndex` INT(11) NOT NULL, + `login` varchar(36) NOT NULL, + `altitude` INT(11) NOT NULL, + `time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (`index`), + UNIQUE KEY `map_player` (`mapIndex`,`login`) + ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;'; + $mysqli->query($query); + if ($mysqli->error) { + trigger_error($mysqli->error, E_USER_ERROR); + } + } + + public function handleAfterInit() { + $this->handleStartRound(); + } + + /** + * Handle when a player connects + * + * @param Player $player + */ + public function handlePlayerConnect(Player $player) { + $mysqli = $this->maniaControl->getDatabase()->getMysqli(); + + } + + public function handleStartRound() { + $map = $this->maniaControl->getMapManager()->getCurrentMap(); + $logins = []; + + foreach ($this->maniaControl->getPlayerManager()->getPlayers() as $player) { + $logins[] = $player->login; + } + + // Send PB + $pbs = $this->getPlayersPB($map->index, $logins); + if (count($pbs) > 0) { + $this->maniaControl->getClient()->triggerModeScriptEvent(self::M_SETPLAYERSPB, [json_encode($pbs)]); + } + + // Send WR + $wr = $this->getWR($map->index); + if ($wr !== null) { + $this->wraltitude = $wr[1]; + $this->maniaControl->getClient()->triggerModeScriptEvent(self::M_SETWR, [$wr[0], strval($wr[1])]); + } else { + $this->wraltitude = 0; + } + } + + public function handleUpdatePBs(array $data) { + $json = json_decode($data[1][0]); + if ($json !== null) { + $map = $this->maniaControl->getMapManager()->getCurrentMap(); + $mapIndex = -1; + if ($map !== null) $mapIndex = $map->index; + + $mysqli = $this->maniaControl->getDatabase()->getMysqli(); + $mysqli->begin_transaction(); + + $stmt = $mysqli->prepare("INSERT INTO `" . self::DB_CLIMBTHEMAP . "` (`mapIndex`, `login`, `altitude`) + VALUES (?, ?, ?) ON DUPLICATE KEY UPDATE + `altitude` = GREATEST(VALUES(`altitude`), `altitude`);"); + $stmt->bind_param('iss', $mapIndex, $login, $altitude); + foreach ($json as $login => $altitude) { + $stmt->execute(); + + if ($this->wraltitude < $altitude) { + $this->wraltitude = $altitude; + } + } + $mysqli->commit(); + + + + // Reset manialink cache + $this->manialink = ""; + } + } + + public function handle1Minute() { + $map = $this->maniaControl->getMapManager()->getCurrentMap(); + if ($map === null) return; + + $wr = $this->getWR($map->index); + + // Update WR if done on an another server + if ($wr !== null && $this->wraltitude < $wr[1]) { + $this->wraltitude = $wr[1]; + $this->maniaControl->getClient()->triggerModeScriptEvent(self::M_SETWR, [$wr[0], strval($wr[1])]); + } + } + + + private function getPlayersPB(int $mapIndex, array $logins) { + if (count($logins) === 0) return; + $return = []; + $mysqli = $this->maniaControl->getDatabase()->getMysqli(); + + $stmt = $mysqli->prepare('SELECT login,altitude FROM `' . self::DB_CLIMBTHEMAP . '` WHERE `mapIndex` = ? and login IN (' . str_repeat('?,', count($logins) - 1) . '?' . ' )'); + $stmt->bind_param('i' . str_repeat('s', count($logins)), $mapIndex, ...$logins); // bind array at once + if (!$stmt->execute()) { + trigger_error('Error executing MySQL query: ' . $stmt->error); + } + $result = $stmt->get_result(); // get the mysqli result + if ($result !== false) { + foreach ($result->fetch_all(MYSQLI_ASSOC) as $data) { + $return[$data["login"]] = $data["altitude"]; + } + } + + return $return; + } + + private function getWR(int $mapIndex) { + $mysqli = $this->maniaControl->getDatabase()->getMysqli(); + + $stmt = $mysqli->prepare('SELECT login,altitude FROM `' . self::DB_CLIMBTHEMAP . '` WHERE `mapIndex` = ? ORDER BY altitude DESC, time ASC LIMIT 1;'); + $stmt->bind_param('i', $mapIndex); + if (!$stmt->execute()) { + trigger_error('Error executing MySQL query: ' . $stmt->error); + } + $result = $stmt->get_result(); + if ($result !== false) { + $data = $result->fetch_assoc(); + if ($data !== null) { + + $player = $this->maniaControl->getPlayerManager()->getPlayer($data["login"]); + if ($player !== null) { + return [$player->nickname, $data["altitude"]]; + } + } + + } + return null; + } + + public function getRecords(Map $map) { + if ($map === null) return []; + + $mapIndex = $map->index; + + $mysqli = $this->maniaControl->getDatabase()->getMysqli(); + + $stmt = $mysqli->prepare('SELECT ctm.index,ctm.login,p.nickname,ctm.altitude,ctm.time FROM `' . self::DB_CLIMBTHEMAP . '` ctm + LEFT JOIN `' . PlayerManager::TABLE_PLAYERS . '` p + ON ctm.login = p.login + WHERE `mapIndex` = ? + ORDER BY altitude DESC, time ASC;'); + $stmt->bind_param('i', $mapIndex); + if (!$stmt->execute()) { + trigger_error('Error executing MySQL query: ' . $stmt->error); + } + $result = $stmt->get_result(); // get the mysqli result + if ($result !== false) { + return $result->fetch_all(MYSQLI_ASSOC); + } + return []; + } + + public function handleShowAltitudeRecords(array $callback, Player $player) { + $this->maniaControl->getManialinkManager()->displayWidget($this->getManialink(), $player, self::MLID_ALTITUDE_RECORDS); + } + + private function getManialink() { + if ($this->manialink !== "") return $this->manialink; + + $width = $this->maniaControl->getManialinkManager()->getStyleManager()->getListWidgetsWidth(); + $height = $this->maniaControl->getManialinkManager()->getStyleManager()->getListWidgetsHeight(); + + // get PlayerList + $records = $this->getRecords($this->maniaControl->getMapManager()->getCurrentMap()); + + // create manialink + $maniaLink = new ManiaLink(ManialinkManager::MAIN_MLID); + $script = $maniaLink->getScript(); + $paging = new Paging(); + $script->addFeature($paging); + + // Main frame + $frame = $this->maniaControl->getManialinkManager()->getStyleManager()->getDefaultListFrame($script, $paging); + $maniaLink->addChild($frame); + + // Start offsets + $posX = -$width / 2; + $posY = $height / 2; + + // Headline + $headFrame = new Frame(); + $frame->addChild($headFrame); + $headFrame->setY($posY - 5); + + $labelLine = new LabelLine($headFrame); + $labelLine->addLabelEntryText('Rank', $posX + 5); + $labelLine->addLabelEntryText('Nickname', $posX + 18); + $labelLine->addLabelEntryText('Altitude', $posX + $width * 0.6); + $labelLine->addLabelEntryText('Date (UTC)', $posX + $width * 0.75); + $labelLine->render(); + + $index = 0; + $posY = $height / 2 - 10; + $pageFrame = null; + + $pageMaxCount = floor(($height - 5 - 10) / 4); + + foreach ($records as $record) { + if ($index % $pageMaxCount === 0) { + $pageFrame = new Frame(); + $frame->addChild($pageFrame); + $posY = $height / 2 - 10; + $paging->addPageControl($pageFrame); + } + + $recordFrame = new Frame(); + $pageFrame->addChild($recordFrame); + + if ($index % 2 === 0) { + $lineQuad = new Quad_BgsPlayerCard(); + $recordFrame->addChild($lineQuad); + $lineQuad->setSize($width, 4); + $lineQuad->setSubStyle($lineQuad::SUBSTYLE_BgPlayerCardBig); + $lineQuad->setZ(-0.001); + } + + $labelLine = new LabelLine($recordFrame); + $labelLine->addLabelEntryText($index + 1, $posX + 5, 13); + $labelLine->addLabelEntryText($record["nickname"], $posX + 18, 52); + $labelLine->addLabelEntryText($record["altitude"], $posX + $width * 0.6, 31); + $labelLine->addLabelEntryText($record["time"], $posX + $width * 0.75, 30); + $labelLine->render(); + + $recordFrame->setY($posY); + + $posY -= 4; + $index++; + } + + $this->manialink = (string) $maniaLink; + return $this->manialink; + } + + /** + * Unload the plugin and its Resources + */ + public function unload() { + } +}