maniaControl->getChat()->sendErrorToAdmins('MatchManager Core is required to use MatchManagerPickAndBan plugin. Install it and restart Maniacontrol'); Logger::logError('MatchManager Core is required to use MatchManagerPickAndBan plugin. Install it and restart Maniacontrol'); return false; } /** * MatchManager Pick and Ban * * @author Beu * @license http://www.gnu.org/licenses/ GNU General Public License, Version 3 */ class MatchManagerPickAndBan implements ManialinkPageAnswerListener, CallbackListener, TimerListener, Plugin { /* * Constants */ const PLUGIN_ID = 223; const PLUGIN_VERSION = 0.1; const PLUGIN_NAME = 'MatchManager Pick & Ban'; const PLUGIN_AUTHOR = 'Beu'; const LOG_PREFIX = '[MatchManagerPickAndBan] '; // Settings const SETTING_ENABLE = 'Enable pick & ban'; const SETTING_STEPCONFIG = 'Step config'; const SETTING_STEPDURATION = 'Step duration'; // Other MatchManager plugin const MATCHMANAGERCORE_PLUGIN = 'MatchManagerSuite\MatchManagerCore'; const MATCHMANAGERADMINUI_PLUGIN = 'MatchManagerSuite\MatchManagerAdminUI'; // Steps const ML_STEP_OPENSETTINGS = 'MatchManagerSuite\MatchManagerPickAndBan.OpenSettings'; const ML_STEP_MAPCHOOSENREGEX = '/^MatchManagerPickAndBan_MapChoosen:.*/'; /* * Private properties */ private ManiaControl $maniaControl; private MatchManagerCore $MatchManagerCore; private MatchManagerPickAndBan_State $state; /** * @param \ManiaControl\ManiaControl $maniaControl * @see \ManiaControl\Plugins\Plugin::prepare() */ public static function prepare(ManiaControl $maniaControl) { } /** * @see \ManiaControl\Plugins\Plugin::getId() */ public static function getId() { return self::PLUGIN_ID; } /** * @see \ManiaControl\Plugins\Plugin::getName() */ public static function getName() { return self::PLUGIN_NAME; } /** * @see \ManiaControl\Plugins\Plugin::getVersion() */ public static function getVersion() { return self::PLUGIN_VERSION; } /** * @see \ManiaControl\Plugins\Plugin::getAuthor() */ public static function getAuthor() { return self::PLUGIN_AUTHOR; } /** * @see \ManiaControl\Plugins\Plugin::getDescription() */ public static function getDescription() { return 'Pick & Ban plugin for MatchManager'; } /** * @param \ManiaControl\ManiaControl $maniaControl * @return bool * @see \ManiaControl\Plugins\Plugin::load() */ public function load(ManiaControl $maniaControl) { $this->maniaControl = $maniaControl; $this->clearManialinks(); $this->MatchManagerCore = $this->maniaControl->getPluginManager()->getPlugin(self::MATCHMANAGERCORE_PLUGIN); if ($this->MatchManagerCore == Null) { throw new \Exception('MatchManager Core is needed to use ' . self::PLUGIN_NAME); } $this->state = new MatchManagerPickAndBan_State; // Settings $this->maniaControl->getSettingManager()->initSetting($this, self::SETTING_ENABLE, true, '', 0); $this->maniaControl->getSettingManager()->initSetting($this, self::SETTING_STEPCONFIG, '', '', 0); $this->maniaControl->getSettingManager()->initSetting($this, self::SETTING_STEPDURATION, 60, '', 0); // Callbacks $this->maniaControl->getManialinkManager()->registerManialinkPageAnswerListener(self::ML_STEP_OPENSETTINGS, $this, 'handleStepOpenSettings'); $this->maniaControl->getManialinkManager()->registerManialinkPageAnswerRegexListener(self::ML_STEP_MAPCHOOSENREGEX, $this, 'handleStepMapChoosen'); $this->maniaControl->getCallbackManager()->registerCallbackListener(Callbacks::AFTERINIT, $this, 'handleAfterInit'); $this->maniaControl->getCallbackManager()->registerCallbackListener(PluginManager::CB_PLUGIN_LOADED, $this, 'handlePluginLoaded'); $this->maniaControl->getCallbackManager()->registerCallbackListener($this->MatchManagerCore::CB_MATCHMANAGER_ENDMATCH, $this, 'handleEndMatch'); $this->maniaControl->getCallbackManager()->registerCallbackListener($this->MatchManagerCore::CB_MATCHMANAGER_STOPMATCH, $this, 'handleEndMatch'); $this->MatchManagerCore->addCanStartFunction($this, 'handleCanStartMatch'); $this->updateAdminUIMenuItems(); $this->sendStateToPlayers(); } /** * @see \ManiaControl\Plugins\Plugin::unload() */ public function unload() { /** @var \MatchManagerSuite\MatchManagerAdminUI|null */ $adminUIPlugin = $this->maniaControl->getPluginManager()->getPlugin(self::MATCHMANAGERADMINUI_PLUGIN); if ($adminUIPlugin !== null) { $adminUIPlugin->removeMenuItem(self::ML_STEP_OPENSETTINGS); } $this->clearManialinks(); } /** * Custom log function to add prefix * * @param mixed $message */ private function log(mixed $message) { Logger::log(self::LOG_PREFIX . $message); } /** * Custom logError function to add prefix * * @param mixed $message */ private function logError(mixed $message) { Logger::logError(self::LOG_PREFIX . $message); } /** * handle Plugin Loaded */ public function handleAfterInit() { $this->updateAdminUIMenuItems(); } /** * handle Plugin Loaded * * @param string $pluginClass */ public function handlePluginLoaded(string $pluginClass) { if ($pluginClass === self::MATCHMANAGERADMINUI_PLUGIN) { $this->updateAdminUIMenuItems(); } } /** * Add items in AdminUI plugin */ public function updateAdminUIMenuItems() { /** @var \MatchManagerSuite\MatchManagerAdminUI|null */ $adminUIPlugin = $this->maniaControl->getPluginManager()->getPlugin(self::MATCHMANAGERADMINUI_PLUGIN); if ($adminUIPlugin === null) return; $adminUIPlugin->removeMenuItem(self::ML_STEP_OPENSETTINGS); $menuItem = new \MatchManagerSuite\MatchManagerAdminUI_MenuItem(); $menuItem->setActionId(self::ML_STEP_OPENSETTINGS) ->setOrder(40) ->setStyle('MeshModelerIcons') ->setSubStyle('LayersFocused') ->setDescription('Open Pick & Ban Settings'); $adminUIPlugin->addMenuItem($menuItem); } /** * manage Step */ public function manageStep() { // Do random pick while ( array_key_exists($this->state->stepIndex, $this->state->steps) && $this->state->steps[$this->state->stepIndex]->login === "" ) { $availableMaps = array_filter($this->state->maps, function($map) { return !$map->picked && !$map->banned; }); $mapUid = array_rand($availableMaps); $this->state->maps[$mapUid]->banned = ($this->state->steps[$this->state->stepIndex]->type === MatchManagerPickAndBan_Step::STEP_BAN); $this->state->maps[$mapUid]->picked = ($this->state->steps[$this->state->stepIndex]->type === MatchManagerPickAndBan_Step::STEP_PICK); $this->state->steps[$this->state->stepIndex]->mapUid = $mapUid; $this->state->stepIndex++; } $this->state->startTimestamp = time(); $this->state->endTimestamp = time() + $this->maniaControl->getSettingManager()->getSettingValue($this, self::SETTING_STEPDURATION); $this->sendStateToPlayers(); } /** * handle timer * @return void */ public function handleTimer() { if ($this->state->status !== MatchManagerPickAndBan_State::STATUS_INPROGRESS) { $this->maniaControl->getTimerManager()->unregisterTimerListening($this, 'handleTimer'); return; } if ($this->state->endTimestamp < time()) { if (array_key_exists($this->state->stepIndex, $this->state->steps)) { $this->state->steps[$this->state->stepIndex]->login = ""; $this->manageStep(); } else { $this->log("Start match"); $this->state->status = MatchManagerPickAndBan_State::STATUS_COMPLETED; $this->MatchManagerCore->MatchStart(); $this->clearManialinks(); } } } /** * handle Open settings manialink step * * @param array $callback * @param Player $player */ public function handleStepOpenSettings(array $callback, Player $player) { if ($player->authLevel <= 0) return; $pluginMenu = $this->maniaControl->getPluginManager()->getPluginMenu(); if (defined("\ManiaControl\ManiaControl::ISTRACKMANIACONTROL")) { $player->setCache($pluginMenu, PluginMenu::CACHE_SETTING_CLASS, "PluginMenu.Settings." . self::class); } else { $player->setCache($pluginMenu, PluginMenu::CACHE_SETTING_CLASS, self::class); } $this->maniaControl->getConfigurator()->showMenu($player, $pluginMenu); } /** * handle Map Choosen * * @param array $callback * @param Player $player */ public function handleStepMapChoosen(array $callback, Player $player) { if ($this->state->status !== MatchManagerPickAndBan_State::STATUS_INPROGRESS) return; if (!array_key_exists($this->state->stepIndex, $this->state->steps)) return; if ($this->state->steps[$this->state->stepIndex]->login !== $player->login) return; $step = $callback[1][2]; $stepArray = explode(':', $step); if (count($stepArray) !== 2) return; $mapUid = $stepArray[1]; if (!array_key_exists($mapUid, $this->state->maps)) return; $this->state->maps[$mapUid]->banned = ($this->state->steps[$this->state->stepIndex]->type === MatchManagerPickAndBan_Step::STEP_BAN); $this->state->maps[$mapUid]->picked = ($this->state->steps[$this->state->stepIndex]->type === MatchManagerPickAndBan_Step::STEP_PICK); $this->state->steps[$this->state->stepIndex]->mapUid = $mapUid; $this->state->stepIndex++; $this->manageStep(); } /** * handle MatchManagerCore Can Start Match callback */ public function handleCanStartMatch() { if (!$this->maniaControl->getSettingManager()->getSettingValue($this, self::SETTING_ENABLE)) return true; if ($this->state->status === MatchManagerPickAndBan_State::STATUS_COMPLETED) { $maplist = []; foreach ($this->state->steps as $step) { if ($step->type !== MatchManagerPickAndBan_Step::STEP_PICK) continue; if (!array_key_exists($step->mapUid, $this->state->maps)) { $this->logError("Picked map doesn't exist in map list, should never happen."); $this->maniaControl->getChat()->sendErrorToAdmins($this->MatchManagerCore->getChatPrefix() . "Picked map doesn't exist in map list, should never happen."); $this->state = new MatchManagerPickAndBan_State; return false; } $maplist[] = $this->state->maps[$step->mapUid]->filePath; } $setting = $this->maniaControl->getSettingManager()->getSettingObject($this->MatchManagerCore, $this->MatchManagerCore::SETTING_MODE_MAPS); $setting->value = implode(',', $maplist); $this->log('Starting match with maps "'. $setting->value .'"'); return true; } if ($this->state->status === MatchManagerPickAndBan_State::STATUS_INPROGRESS) { $this->maniaControl->getChat()->sendErrorToAdmins($this->MatchManagerCore->getChatPrefix() . "Pick and Ban in progress"); return false; } $stepConfig = $this->maniaControl->getSettingManager()->getSettingValue($this, self::SETTING_STEPCONFIG); if ($stepConfig === '') { $this->maniaControl->getChat()->sendErrorToAdmins($this->MatchManagerCore->getChatPrefix() . "'Step config' setting must be set"); return false; } if ($this->maniaControl->getSettingManager()->getSettingValue($this->MatchManagerCore, $this->MatchManagerCore::SETTING_MATCH_SETTINGS_MODE) !== 'All from the plugin') { $this->maniaControl->getChat()->sendErrorToAdmins($this->MatchManagerCore->getChatPrefix() . "Setting mode must be in 'All from the plugin' to use Pick & Ban"); return false; } $mapFiles = $this->maniaControl->getSettingManager()->getSettingValue($this->MatchManagerCore, $this->MatchManagerCore::SETTING_MODE_MAPS); if ($mapFiles === '') { $this->maniaControl->getChat()->sendErrorToAdmins($this->MatchManagerCore->getChatPrefix() . "Maps must be defined to use Pick & Ban"); return false; } if (count(explode(',', $mapFiles)) < count(explode(',', $stepConfig))) { $this->maniaControl->getChat()->sendErrorToAdmins($this->MatchManagerCore->getChatPrefix() . "You must have at least same number of maps than steps"); return false; } $this->log('Building Pick & Ban config'); $this->state = new MatchManagerPickAndBan_State; $this->state->status = MatchManagerPickAndBan_State::STATUS_INPROGRESS; $this->state->originalMapList = $mapFiles; // build map config $maps = []; foreach (explode(',', $mapFiles) as $mapPath) { try { $mapInfo = $this->maniaControl->getClient()->getMapInfo($mapPath); $mapObject = new MatchManagerPickAndBan_Map(); $mapObject->mapUid = $mapInfo->uId; $mapObject->filePath = $mapPath; $mapObject->name = $mapInfo->name; $maps[$mapInfo->uId] = $mapObject; } catch (Exception $e) { $this->maniaControl->getChat()->sendErrorToAdmins($this->MatchManagerCore->getChatPrefix() . 'Error with the Map to play "' . $mapPath . '": ' . $e->getMessage()); return false; } } uasort($maps, function ($a, $b) { return strnatcasecmp($a->name, $b->name); }); $this->state->maps = $maps; $this->log(count($this->state->maps) . ' maps loaded for Pick & Ban'); // build steps $steps = []; foreach (explode(',', $stepConfig) as $index => $stepRaw) { $stepArray = explode(':', $stepRaw); if (count($stepArray) !== 2) { $this->maniaControl->getChat()->sendErrorToAdmins($this->MatchManagerCore->getChatPrefix() . 'Invalid step ' . $index . 'config: ' . $stepRaw); return false; } $step = new MatchManagerPickAndBan_Step; if ($stepArray[0] === 'p') { $step->type = MatchManagerPickAndBan_Step::STEP_PICK; } else if ($stepArray[0] === 'b') { $step->type = MatchManagerPickAndBan_Step::STEP_BAN; } if ($stepArray[1] === 'r') { $step->login = ""; } else { $step->login = $stepArray[1]; } $steps[] = $step; } $this->state->steps = $steps; $this->log(count($this->state->steps) . ' steps loaded for Pick & Ban'); $this->maniaControl->getChat()->sendSuccess('Starting Pick & Ban phase'); $this->log('Starting Pick & Ban phase'); $this->sendManialink(); $this->manageStep(); $this->maniaControl->getTimerManager()->registerTimerListening($this, 'handleTimer', 1000); return false; } public function handleEndMatch() { if ($this->state->status === MatchManagerPickAndBan_State::STATUS_COMPLETED) { $setting = $this->maniaControl->getSettingManager()->getSettingObject($this->MatchManagerCore, $this->MatchManagerCore::SETTING_MODE_MAPS); $setting->value = $this->state->originalMapList; $this->state = new MatchManagerPickAndBan_State; } } private function sendManialink(): void { $manialink = '