From 75ae777f1ed9d23bebfbda019227fb9117834dde Mon Sep 17 00:00:00 2001 From: "Patrick Asmus (scriptos)" Date: Sun, 22 Mar 2026 15:22:19 +0100 Subject: [PATCH] feat: Auto-Import von AdminServ ServerOptions beim Containerstart --- assets/bin/RunTrackmaniaServer.sh | 123 ++++++++++++++++++++++++++++++ docs/konfiguration.md | 33 ++++++++ 2 files changed, 156 insertions(+) diff --git a/assets/bin/RunTrackmaniaServer.sh b/assets/bin/RunTrackmaniaServer.sh index d2ef431..42872da 100644 --- a/assets/bin/RunTrackmaniaServer.sh +++ b/assets/bin/RunTrackmaniaServer.sh @@ -453,6 +453,129 @@ if [ "$APPLY_ENV" = "true" ]; then echo "Platzhalter erfolgreich ersetzt." fi +# ============================================================ +# AdminServ ServerOptions: Exportierte Einstellungen anwenden +# ============================================================ +# Falls ein AdminServ-Export in GameData/Config/AdminServ/ServerOptions/ +# vorhanden ist, werden die darin enthaltenen Werte (z.B. Servername, +# Beschreibung, Spielerzahl) in die dedicated_cfg.txt uebernommen. +# So bleiben Aenderungen, die ueber AdminServ vorgenommen und exportiert +# wurden, auch nach einem Container-Neustart erhalten. +# ============================================================ +ADMINSERV_OPTIONS_DIR="$GAMEDATA_DIR/Config/AdminServ/ServerOptions" +if [ -d "$ADMINSERV_OPTIONS_DIR" ]; then + LATEST_EXPORT=$(ls -t "$ADMINSERV_OPTIONS_DIR"/*.txt "$ADMINSERV_OPTIONS_DIR"/*.xml 2>/dev/null | head -1) + if [ -n "$LATEST_EXPORT" ] && [ -f "$LATEST_EXPORT" ]; then + echo "==> AdminServ ServerOptions-Export gefunden: $(basename "$LATEST_EXPORT")" + echo " Uebernehme exportierte Einstellungen in dedicated_cfg.txt..." + php -r ' + $xmlFile = $argv[1]; + $cfgFile = $argv[2]; + + // AdminServ-Export parsen + $dom = new DOMDocument(); + if (!@$dom->load($xmlFile)) { + echo " WARNUNG: AdminServ-Export konnte nicht gelesen werden.\n"; + exit(0); + } + $root = $dom->documentElement; + $exportValues = []; + foreach ($root->childNodes as $node) { + if ($node->nodeType === XML_ELEMENT_NODE) { + $exportValues[$node->nodeName] = $node->nodeValue; + } + } + + // Mapping: AdminServ-XML-Feld => dedicated_cfg.txt-Feld + $mapping = [ + "Name" => "name", + "Comment" => "comment", + "HideServer" => "hide_server", + "NextMaxPlayers" => "max_players", + "Password" => "password", + "PasswordForSpectator" => "password_spectator", + "NextMaxSpectators" => "max_spectators", + "NextLadderMode" => "ladder_mode", + "NextCallVoteTimeOut" => "callvote_timeout", + "CallVoteRatio" => "callvote_ratio", + "AllowChallengeDownload" => "allow_challenge_download", + "AutoSaveReplays" => "autosave_replays", + "IsP2PUpload" => "enable_p2p_upload", + "IsP2PDownload" => "enable_p2p_download", + ]; + + // Bool-Felder: 1/0 => True/False (dedicated_cfg.txt-Format) + $boolFields = [ + "allow_challenge_download", "autosave_replays", + "enable_p2p_upload", "enable_p2p_download", + ]; + + // Ladder-Modus: 0 => inactive, 1 => forced + $ladderMap = ["0" => "inactive", "1" => "forced"]; + + // Zu ersetzende Werte aufbauen + $replacements = []; + foreach ($mapping as $xmlField => $cfgField) { + if (isset($exportValues[$xmlField])) { + $value = $exportValues[$xmlField]; + if (in_array($cfgField, $boolFields)) { + $value = ($value == "1" || strtolower($value) === "true") ? "True" : "False"; + } + if ($cfgField === "ladder_mode" && isset($ladderMap[$value])) { + $value = $ladderMap[$value]; + } + $replacements[$cfgField] = $value; + } + } + + if (empty($replacements)) { + echo " Keine anwendbaren Einstellungen im Export gefunden.\n"; + exit(0); + } + + // dedicated_cfg.txt zeilenweise verarbeiten + // Nur Tags innerhalb von werden ersetzt, + // damit und in unangetastet bleiben. + $lines = file($cfgFile); + $inServerOptions = false; + $updated = 0; + + foreach ($lines as $i => $line) { + if (strpos($line, "") !== false) { + $inServerOptions = true; + } + if (strpos($line, "") !== false) { + $inServerOptions = false; + } + if ($inServerOptions) { + foreach ($replacements as $field => $value) { + $pattern = "/(<" . preg_quote($field, "/") . ">)[^<]*(<\/" . preg_quote($field, "/") . ">)/"; + if (preg_match($pattern, $line)) { + $safeValue = htmlspecialchars($value, ENT_XML1 | ENT_QUOTES, "UTF-8"); + // $ und \ im Replacement escapen, damit preg_replace + // sie nicht als Backreferences interpretiert (wichtig + // fuer TM-Farbcodes wie $03F, $z, $s etc.) + $escapedValue = str_replace(["\\", "$"], ["\\\\", "\\$"], $safeValue); + $lines[$i] = preg_replace($pattern, "\${1}" . $escapedValue . "\${2}", $line, 1); + echo " " . $field . " => " . $value . "\n"; + $updated++; + unset($replacements[$field]); + break; + } + } + } + } + + if ($updated > 0) { + file_put_contents($cfgFile, implode("", $lines)); + echo " " . $updated . " Einstellung(en) aus AdminServ-Export uebernommen.\n"; + } + ' "$LATEST_EXPORT" "$CONFIG" + fi +else + echo "==> Kein AdminServ ServerOptions-Verzeichnis gefunden. Ueberspringe Import." +fi + # Bestimme Server-Modus (Standard: internet) SERVER_MODE="${SERVER_MODE:-internet}" diff --git a/docs/konfiguration.md b/docs/konfiguration.md index 0781602..f9ae1ee 100644 --- a/docs/konfiguration.md +++ b/docs/konfiguration.md @@ -103,6 +103,39 @@ Der Ordner `GameData/Config/` enthält: | `blacklist.txt` | Liste gesperrter Spieler | | `guestlist.txt` | Liste erlaubter Spieler | | `Default.SystemConfig.Gbx` | System-Konfiguration | +| `AdminServ/ServerOptions/` | Von AdminServ exportierte Server-Einstellungen | + +## AdminServ ServerOptions-Import + +Wenn über AdminServ Änderungen an den Server-Optionen vorgenommen und als Export gespeichert werden (z.B. Servername, Beschreibung, Spielerzahl), werden diese beim nächsten Container-Start **automatisch** in die `dedicated_cfg.txt` übernommen. + +**Ablauf:** + +1. In AdminServ unter „Server Options" die gewünschten Einstellungen ändern und „Export" klicken +2. Die exportierte Datei wird in `GameData/Config/AdminServ/ServerOptions/` gespeichert +3. Beim nächsten Start des Containers wird die **neueste** Export-Datei erkannt +4. Die darin enthaltenen Werte werden in die `dedicated_cfg.txt` geschrieben + +**Unterstützte Felder:** + +| AdminServ-Feld | dedicated_cfg.txt-Feld | +|----------------|----------------------| +| `Name` | `` | +| `Comment` | `` | +| `HideServer` | `` | +| `NextMaxPlayers` | `` | +| `Password` | `` | +| `PasswordForSpectator` | `` | +| `NextMaxSpectators` | `` | +| `NextLadderMode` | `` | +| `NextCallVoteTimeOut` | `` | +| `CallVoteRatio` | `` | +| `AllowChallengeDownload` | `` | +| `AutoSaveReplays` | `` | +| `IsP2PUpload` | `` | +| `IsP2PDownload` | `` | + +> **Hinweis:** Die AdminServ-Exports haben **Vorrang** vor den Werten aus den Umgebungsvariablen. Beim ersten Start werden zunächst die Umgebungsvariablen angewendet, danach die AdminServ-Exports (falls vorhanden). Bei weiteren Starts werden nur die AdminServ-Exports angewendet. ## Wichtige Parameter in der dedicated_cfg.txt