From 9b4073f4566b1a8fbe684f6d75975cfa1a23a137 Mon Sep 17 00:00:00 2001 From: beu Date: Sat, 15 Mar 2025 23:44:25 +0100 Subject: [PATCH] improve custom gamemode settings detection --- MatchManagerSuite/MatchManagerCore.php | 297 +++++++++++++++---------- 1 file changed, 176 insertions(+), 121 deletions(-) diff --git a/MatchManagerSuite/MatchManagerCore.php b/MatchManagerSuite/MatchManagerCore.php index 2ae1e2e..d2bbd51 100644 --- a/MatchManagerSuite/MatchManagerCore.php +++ b/MatchManagerSuite/MatchManagerCore.php @@ -700,6 +700,35 @@ class MatchManagerCore implements CallbackListener, CommandListener, TimerListen * MARK: Internal Functions */ + /** + * Reset match variables + * + * @param Setting $setting + */ + public function resetMatchVariables() { + $this->matchStarted = false; + $this->matchrecover = false; + $this->pauseon = false; + $this->pointstorecover = array(); + $this->currentscore = array(); // TODO CHECK + $this->preendroundscore = null; + $this->settingsloaded = false; + $this->mapsshuffled = false; + $this->mapshidden = false; + $this->hidenextmaps = false; + $this->maps = array(); + $this->postmatch = true; + $this->matchid = ""; + + $this->settings_nbroundsbymap = -1; + $this->settings_nbwinners = 2; + $this->settings_nbmapsbymatch = 0; + $this->settings_pointlimit = 100; + + $this->currentgmbase = ""; + $this->currentcustomgm = ""; + $this->currentsettingmode = ""; + } /** * Add items in AdminUI plugin */ @@ -737,6 +766,28 @@ class MatchManagerCore implements CallbackListener, CommandListener, TimerListen } } + /** + * Function called to list matches + */ + public function getMatchesList(int $limit = 10) { + $mysqli = $this->maniaControl->getDatabase()->getMysqli(); + $stmt = $mysqli->prepare("SELECT `gamemodebase`,`started`,`ended` FROM `" . self::DB_MATCHESINDEX . "` ORDER BY `started` DESC LIMIT ?"); + $stmt->bind_param('i', $limit); + + if (!$stmt->execute()) { + Logger::logError('Error executing MySQL query: '. $stmt->error); + } + + $result = $stmt->get_result(); + while($row = $result->fetch_array()) { + $array[] = $row; + } + return $array; + } + + /* + * MARK: Manage Settings + */ /** * Update Widgets on Setting Changes * @@ -804,79 +855,50 @@ class MatchManagerCore implements CallbackListener, CommandListener, TimerListen } } - if (defined("\ManiaControl\ManiaControl::ISTRACKMANIACONTROL") && $this->maniaControl->getSettingManager()->getSettingValue($this->maniaControl->getSettingManager(), SettingManager::SETTING_ALLOW_UNLINK_SERVER)) { - $deletesettings = !$this->maniaControl->getSettingManager()->getSettingValue($this, self::SETTING_MATCH_DONT_DELETE_SETTINGS); - } else { - $deletesettings = true; - } - $allsettings = $this->maniaControl->getSettingManager()->getSettingsByClass($this); - $settingsmode = $this->maniaControl->getSettingManager()->getSettingValue($this, self::SETTING_MATCH_SETTINGS_MODE); - $modesettings = $this->getModeSettings($settingsmode); - foreach ($allsettings as $key => $value) { - $name = $value->setting; - if (array_key_exists($name,self::SETTINGS_MODE_LIST)) { - if (!isset($modesettings[$name])) { - if ($deletesettings) $this->maniaControl->getSettingManager()->deleteSetting($this, $name); - } + if ($setting === null || $setting->setting === self::SETTING_MATCH_SETTINGS_MODE || $setting->setting === self::SETTING_MATCH_GAMEMODE_BASE || $setting->setting === self::SETTING_MATCH_CUSTOM_GAMEMODE) { + if (defined("\ManiaControl\ManiaControl::ISTRACKMANIACONTROL") && $this->maniaControl->getSettingManager()->getSettingValue($this->maniaControl->getSettingManager(), SettingManager::SETTING_ALLOW_UNLINK_SERVER)) { + $deletesettings = !$this->maniaControl->getSettingManager()->getSettingValue($this, self::SETTING_MATCH_DONT_DELETE_SETTINGS); + } else { + $deletesettings = true; } - } - foreach ($modesettings as $key => $value) { - $this->maniaControl->getSettingManager()->initSetting($this, $key, self::SETTINGS_MODE_LIST[$key]['default'], self::SETTINGS_MODE_LIST[$key]['description'], 50); - } - - if ($settingsmode == 'Maps from file & Settings from plugin' || $settingsmode == 'All from the plugin') { - $gmsettings = $this->getGMSettings($this->maniaControl->getSettingManager()->getSettingValue($this, self::SETTING_MATCH_GAMEMODE_BASE), $this->maniaControl->getSettingManager()->getSettingValue($this, self::SETTING_MATCH_CUSTOM_GAMEMODE)); - + $allsettings = $this->maniaControl->getSettingManager()->getSettingsByClass($this); + $settingsmode = $this->maniaControl->getSettingManager()->getSettingValue($this, self::SETTING_MATCH_SETTINGS_MODE); + $modesettings = $this->getModeSettings($settingsmode); foreach ($allsettings as $key => $value) { $name = $value->setting; - if (substr($name,0, 2) == "S_" && !isset($gmsettings[$name])) { - if ($deletesettings) $this->maniaControl->getSettingManager()->deleteSetting($this, $name); + if (array_key_exists($name,self::SETTINGS_MODE_LIST)) { + if (!isset($modesettings[$name])) { + if ($deletesettings) $this->maniaControl->getSettingManager()->deleteSetting($this, $name); + } } } - foreach ($gmsettings as $key => $value) { - $this->maniaControl->getSettingManager()->initSetting($this, $key, $value['default'], $value['description'], 100); + foreach ($modesettings as $key => $value) { + $this->maniaControl->getSettingManager()->initSetting($this, $key, self::SETTINGS_MODE_LIST[$key]['default'], self::SETTINGS_MODE_LIST[$key]['description'], 50); } - } else { - foreach ($allsettings as $key => $value) { - $name = $value->setting; - if (substr($name,0, 2) == "S_") { - if ($deletesettings) $this->maniaControl->getSettingManager()->deleteSetting($this, $name); + + if ($settingsmode == 'Maps from file & Settings from plugin' || $settingsmode == 'All from the plugin') { + $gmsettings = $this->getGMSettings($this->maniaControl->getSettingManager()->getSettingValue($this, self::SETTING_MATCH_GAMEMODE_BASE), $this->maniaControl->getSettingManager()->getSettingValue($this, self::SETTING_MATCH_CUSTOM_GAMEMODE)); + + foreach ($allsettings as $key => $value) { + $name = $value->setting; + if (substr($name,0, 2) == "S_" && !isset($gmsettings[$name])) { + if ($deletesettings) $this->maniaControl->getSettingManager()->deleteSetting($this, $name); + } + } + foreach ($gmsettings as $key => $value) { + $this->maniaControl->getSettingManager()->initSetting($this, $key, $value['default'], $value['description'], 100); + } + } else { + foreach ($allsettings as $key => $value) { + $name = $value->setting; + if (substr($name,0, 2) == "S_") { + if ($deletesettings) $this->maniaControl->getSettingManager()->deleteSetting($this, $name); + } } } } } - - /** - * Reset match variables - * - * @param Setting $setting - */ - public function resetMatchVariables() { - $this->matchStarted = false; - $this->matchrecover = false; - $this->pauseon = false; - $this->pointstorecover = array(); - $this->currentscore = array(); // TODO CHECK - $this->preendroundscore = null; - $this->settingsloaded = false; - $this->mapsshuffled = false; - $this->mapshidden = false; - $this->hidenextmaps = false; - $this->maps = array(); - $this->postmatch = true; - $this->matchid = ""; - - $this->settings_nbroundsbymap = -1; - $this->settings_nbwinners = 2; - $this->settings_nbmapsbymatch = 0; - $this->settings_pointlimit = 100; - - $this->currentgmbase = ""; - $this->currentcustomgm = ""; - $this->currentsettingmode = ""; - } - /** * Load Gamemode settings excluding not used settings in custom gamemodes * @@ -892,68 +914,120 @@ class MatchManagerCore implements CallbackListener, CommandListener, TimerListen $this->maniaControl->getClient()->setModeScriptSettings($gmsettings); } + /** + * Get recursively Custom gamemodes settings + * @param string $customgamemode + * @return mixed + */ + private function getCustomGMSettings(string $customgamemode) { + $filename = $this->maniaControl->getServer()->getDirectory()->getUserDataFolder() . DIRECTORY_SEPARATOR . "Scripts" . DIRECTORY_SEPARATOR . $customgamemode; + if (!file_exists($filename)) return []; + + $fileContent = file_get_contents($filename); + preg_match('/^\s*\#Extends\s+"(.*)"/m', $fileContent, $matches); + + $gamesettings = []; + + if (count($matches) >= 2) { + $gamesettings = $this->getCustomGMSettings($matches[1]); + } + + // Replace all line breaks and double quote between triple quotes strings. + $fileContent = preg_replace_callback('/"""(.*?)"""/s', function($matches) { + $processedString = str_replace(["\r\n", "\n", "\r"], " ", $matches[1]); + $processedString = str_replace(["\""], "\\\"", $processedString); + return '"' . $processedString . '"'; + }, $fileContent); + + foreach(preg_split("/((\r?\n)|(\r\n?))/", $fileContent) as $line){ + if (preg_match('/^\*\*\*/', $line)) break; + + if (preg_match('/^(\s*)\#Setting\s+(S_\S+)\s+(\S+)\s*(as\s|)(_\(|)("|\'|)([^\'"]*)("\)|\'\)|"|\'| |)/', $line, $matches)) { + $gamesettingname = $matches[2]; + $defaultvalue = $matches[3]; + $description = $matches[7]; + + if (is_numeric($matches[3]) && is_float($matches[3]+0)) { + $type = "float"; + } else if (is_numeric($matches[3])) { + $type = "integer"; + } else if (strtolower($matches[3]) == "true" || strtolower($matches[3]) == "false") { + $type = "boolean"; + if (strtolower($matches[3]) == "false") $defaultvalue = ""; + } else { + // Assuming it's a string, and because it can have spaces, we re-do the regexp + $type = "string"; + preg_match_all('/(? $type, + 'default' => $defaultvalue, + 'description' => $description + ]; + } + } + } + + + return $gamesettings; + } + /** * Get Array with all settings of the Gamemode * * @param String $gamemode */ public function getGMSettings(String $gamemodebase, String $customgamemode) { - $gamesettings = []; + $starttime = hrtime(true); + + $gameSettings = []; foreach (self::GAMEMODES_LIST_SETTINGS as $gamesetting => $info) { if (in_array('Global', $info['gamemode']) || in_array($gamemodebase, $info['gamemode'])) { - $gamesettings = array_merge($gamesettings , array($gamesetting => $info)); + $gameSettings = array_merge($gameSettings , array($gamesetting => $info)); } } - if ($customgamemode != "") { + if ($customgamemode !== "") { // TODO improve detection $filename = $this->maniaControl->getServer()->getDirectory()->getUserDataFolder() . DIRECTORY_SEPARATOR . "Scripts" . DIRECTORY_SEPARATOR . "Modes" . DIRECTORY_SEPARATOR . $customgamemode; if (file_exists($filename)) { - $handle = fopen($filename, "r"); - if ($handle) { - while (($line = fgets($handle)) !== false) { - if (preg_match('/^(\s*)\#Setting\s+(S_\S+)\s+(\S+)\s*(as\s|)(_\(|)("|\'|)([^\'"]*)("\)|\'\)|"|\'| |)/', $line, $matches)) { - $gamesettingname = $matches[2]; - $defaultvalue = $matches[3]; - if (is_numeric($matches[3]) && is_float($matches[3]+0)) { - $type = "float"; - } else if (is_numeric($matches[3])) { - $type = "integer"; - } else if (strtolower($matches[3]) == "true" || strtolower($matches[3]) == "false") { - $type = "boolean"; - if (strtolower($matches[3]) == "false") $defaultvalue = ""; - } else { - $defaultvalue = str_replace(["'", '"'], "" , $matches[3]); - $type = "string"; - } - $description = $matches[7]; - settype($defaultvalue, $type); + $customSettings = $this->getCustomGMSettings("Modes". DIRECTORY_SEPARATOR . $customgamemode); - $gamesettings = array_merge($gamesettings , array($gamesettingname => [ - 'type' => $type, - 'default' => $defaultvalue, - 'description' => $description - ])); - } else if (preg_match('/^\*\*\*/',$line)) { - break; - } + foreach ($customSettings as $settingName => $setting) { + if (array_key_exists($settingName, $gameSettings)) { + $gameSettings[$settingName]['default'] = $setting['default']; + } else { + $gameSettings[$settingName] = $setting; } - fclose($handle); - } else { - Logger::logError("Impossible to read custom gamemode file"); - $this->maniaControl->getChat()->sendErrorToAdmins($this->chatprefix . " Impossible to read custom gamemode file"); } + } else { + Logger::logError("Impossible to read custom gamemode file"); + $this->maniaControl->getChat()->sendErrorToAdmins($this->chatprefix . " Impossible to read custom gamemode file"); } } - foreach ($gamesettings as $settingname => $info) { - $gamesettings[$settingname]['value'] = $this->maniaControl->getSettingManager()->getSettingValue($this, $settingname); - if ($gamesettings[$settingname]['value'] == null) { - $gamesettings[$settingname]['value'] = $info['default']; + foreach ($gameSettings as $settingname => $info) { + $gameSettings[$settingname]['value'] = $this->maniaControl->getSettingManager()->getSettingValue($this, $settingname); + if ($gameSettings[$settingname]['value'] == null) { + $gameSettings[$settingname]['value'] = $info['default']; } - settype($gamesettings[$settingname]['value'], $info['type']); + settype($gameSettings[$settingname]['value'], $info['type']); } - return $gamesettings; + var_dump('getGMSettings '. $customgamemode . ' duration: '. hrtime(true) - $starttime . '(now: '. hrtime(true) .' - starttime: '. $starttime .')'); + + return $gameSettings; } /** @@ -1002,25 +1076,6 @@ class MatchManagerCore implements CallbackListener, CommandListener, TimerListen } } - /** - * Function called to list matches - */ - public function getMatchesList(int $limit = 10) { - $mysqli = $this->maniaControl->getDatabase()->getMysqli(); - $stmt = $mysqli->prepare("SELECT `gamemodebase`,`started`,`ended` FROM `" . self::DB_MATCHESINDEX . "` ORDER BY `started` DESC LIMIT ?"); - $stmt->bind_param('i', $limit); - - if (!$stmt->execute()) { - Logger::logError('Error executing MySQL query: '. $stmt->error); - } - - $result = $stmt->get_result(); - while($row = $result->fetch_array()) { - $array[] = $row; - } - return $array; - } - /* * MARK: Can Start Functions */