mirror of
https://git.techniverse.net/scriptos/tmserver-docker.git
synced 2026-05-08 07:05:47 +00:00
feat: Forced Mods (Skins) per Umgebungsvariable beim Containerstart setzen
This commit is contained in:
@@ -55,6 +55,20 @@ SERVER_MODE=internet
|
||||
# In einer Produktionsumgebung sollte dieser Wert jedoch auf false belassen werden, um zu verhindern, dass die Konfiguration versehentlich überschrieben wird.
|
||||
FORCE_CONFIG_UPDATE=false
|
||||
|
||||
# --- Forced Mods (Skins) ---
|
||||
# Beim Containerstart kann automatisch ein Mod (Skin) pro Umgebung forciert werden.
|
||||
# Der Wert ist die vollständige URL zu einer Mod-ZIP-Datei, die Spieler beim Betreten des Servers herunterladen.
|
||||
# Verfügbare Skins findest du unter: https://assets.techniverse.net/tm/skins/
|
||||
# Beispiel: FORCE_MOD_STADIUM=https://assets.techniverse.net/tm/skins/Portal.zip
|
||||
# Leer lassen = kein Mod für diese Umgebung.
|
||||
FORCE_MOD_STADIUM=
|
||||
FORCE_MOD_ISLAND=
|
||||
FORCE_MOD_BAY=
|
||||
FORCE_MOD_COAST=
|
||||
FORCE_MOD_SPEED=
|
||||
FORCE_MOD_ALPINE=
|
||||
FORCE_MOD_RALLY=
|
||||
|
||||
# --- MatchSettings ---
|
||||
# Steuert, welche MatchSettings-Datei beim Serverstart geladen wird.
|
||||
# "auto" = die neueste .txt-Datei in data/gamedata/Tracks/MatchSettings/ wird automatisch erkannt.
|
||||
|
||||
+13
@@ -76,6 +76,10 @@ RUN unzip /var/www/html/remoteCP_v4.0.3.5.zip -d /var/www/html \
|
||||
COPY assets/config/remotecp/plugins/CustomPoints/index.php /var/www/html/remotecp/plugins/CustomPoints/index.php
|
||||
RUN chown www-data:www-data /var/www/html/remotecp/plugins/CustomPoints/index.php
|
||||
|
||||
# RemoteCP Mods-Plugin: Vorkonfigurierte Skin-Liste (techniverse.net)
|
||||
COPY assets/config/remotecp/plugins/Mods/settings.xml /var/www/html/remotecp/plugins/Mods/settings.xml
|
||||
RUN chown www-data:www-data /var/www/html/remotecp/plugins/Mods/settings.xml
|
||||
|
||||
# Fix AdminServ MatchSettings-Bugs fuer TmForever:
|
||||
# 1) get_matchset_mapimport.php: Falscher Pfad-Praefix (MatchSettings/ statt
|
||||
# des tatsaechlichen Map-Ordners) beim Erstellen von MatchSettings.
|
||||
@@ -155,6 +159,15 @@ ENV FORCE_CONFIG_UPDATE=false
|
||||
# Spieleinstellungen (MatchSettings)
|
||||
ENV ALLWARMUPDURATION=0
|
||||
|
||||
# Forced Mods (Skins) - URL zu ZIP-Dateien, die beim Start forciert werden
|
||||
ENV FORCE_MOD_STADIUM=""
|
||||
ENV FORCE_MOD_ISLAND=""
|
||||
ENV FORCE_MOD_BAY=""
|
||||
ENV FORCE_MOD_COAST=""
|
||||
ENV FORCE_MOD_SPEED=""
|
||||
ENV FORCE_MOD_ALPINE=""
|
||||
ENV FORCE_MOD_RALLY=""
|
||||
|
||||
# RemoteCP
|
||||
ENV REMOTECP_DB_HOST=mariadb
|
||||
ENV REMOTECP_DB_NAME=remotecp
|
||||
|
||||
@@ -6,6 +6,7 @@ Ein vollständiges Docker-Setup für einen **TrackMania Nations Forever**-Server
|
||||
- **[XAseco](docs/xaseco.md)** – Server-Controller, der lokale Rekorde, Dedimania-Weltrekorde, Karma/Votes und eine Track-Jukebox direkt im Spielchat verwaltet
|
||||
- **[AdminServ](docs/adminserv.md)** – Web-Oberfläche zur komfortablen Verwaltung und Konfiguration des Servers
|
||||
- **[RemoteCP](docs/remotecp.md)** – alternative Web-Verwaltungsoberfläche mit eigenem Login- und Benutzersystem
|
||||
- **[Mods / Skins](docs/remotecp.md#mods--skins)** – über 50 vorkonfigurierte Stadium-Skins (gehostet auf [assets.techniverse.net](https://assets.techniverse.net/tm/skins/)), automatisch beim Start forcierbar
|
||||
|
||||
Alle Komponenten laufen in einem einzigen Container und werden über Umgebungsvariablen konfiguriert.
|
||||
|
||||
|
||||
@@ -397,6 +397,22 @@ if [ -f "$ADMINSERV_CREATEMATCHSET" ] && grep -q "query('GetModeScriptInfo')" "$
|
||||
echo " maps-creatematchset.php erfolgreich gepatcht."
|
||||
fi
|
||||
|
||||
# ============================================================
|
||||
# RemoteCP: Mods-Plugin settings.xml aktualisieren (fuer bestehende Volumes)
|
||||
# ============================================================
|
||||
# Die vorkonfigurierte Skin-Liste aus dem Image wird in das Volume
|
||||
# kopiert, falls die alte Standard-settings.xml noch vorhanden ist
|
||||
# (erkennbar am Beispiel-Eintrag "blacksunonline.com").
|
||||
# ============================================================
|
||||
MODS_SETTINGS_FILE="/var/www/html/remotecp/plugins/Mods/settings.xml"
|
||||
MODS_SETTINGS_DEFAULT="/opt/tmserver/default-controlpanel/remotecp/plugins/Mods/settings.xml"
|
||||
if [ -f "$MODS_SETTINGS_FILE" ] && grep -q 'blacksunonline.com' "$MODS_SETTINGS_FILE"; then
|
||||
echo "==> Aktualisiere RemoteCP Mods-Plugin (Skin-Liste von techniverse.net)..."
|
||||
cp "$MODS_SETTINGS_DEFAULT" "$MODS_SETTINGS_FILE"
|
||||
chown www-data:www-data "$MODS_SETTINGS_FILE"
|
||||
echo " Mods/settings.xml erfolgreich aktualisiert."
|
||||
fi
|
||||
|
||||
echo "Starting apache server"
|
||||
service apache2 start
|
||||
|
||||
@@ -673,35 +689,248 @@ TM_PID=$!
|
||||
echo "TrackmaniaServer gestartet (PID: ${TM_PID})"
|
||||
|
||||
# ============================================================
|
||||
# XAseco starten (nach TrackmaniaServer)
|
||||
# Warte auf XMLRPC-Verfuegbarkeit
|
||||
# ============================================================
|
||||
if [ "${XASECO_ENABLED:-true}" = "true" ] && [ -f "/opt/tmserver/xaseco/aseco.php" ]; then
|
||||
echo "==> Warte auf TrackmaniaServer XMLRPC..."
|
||||
XMLRPC_PORT="${SERVER_XMLRPC_PORT:-5000}"
|
||||
XMLRPC_READY=false
|
||||
for i in $(seq 1 30); do
|
||||
if php -r "@fsockopen('127.0.0.1', ${XMLRPC_PORT}, \$e, \$m, 2) ? exit(0) : exit(1);" 2>/dev/null; then
|
||||
XMLRPC_READY=true
|
||||
# Sowohl XAseco als auch Forced Mods benoetigen eine aktive
|
||||
# XMLRPC-Verbindung zum TrackmaniaServer.
|
||||
# ============================================================
|
||||
echo "==> Warte auf TrackmaniaServer XMLRPC..."
|
||||
XMLRPC_PORT="${SERVER_XMLRPC_PORT:-5000}"
|
||||
XMLRPC_READY=false
|
||||
for i in $(seq 1 30); do
|
||||
if php -r "@fsockopen('127.0.0.1', ${XMLRPC_PORT}, \$e, \$m, 2) ? exit(0) : exit(1);" 2>/dev/null; then
|
||||
XMLRPC_READY=true
|
||||
break
|
||||
fi
|
||||
sleep 2
|
||||
done
|
||||
|
||||
if [ "$XMLRPC_READY" = "true" ]; then
|
||||
echo " XMLRPC-Port ${XMLRPC_PORT} erreichbar."
|
||||
else
|
||||
echo " WARNUNG: XMLRPC-Port ${XMLRPC_PORT} nicht erreichbar nach 60s!"
|
||||
fi
|
||||
|
||||
# ============================================================
|
||||
# Forced Mods (Skins) per XMLRPC setzen
|
||||
# ============================================================
|
||||
# Wenn FORCE_MOD_*-Variablen gesetzt sind, werden die
|
||||
# entsprechenden Mods per SetForcedMods-XMLRPC-Aufruf beim
|
||||
# Serverstart automatisch aktiviert. Dies funktioniert bei
|
||||
# jedem Containerstart und ist unabhaengig von FORCE_CONFIG_UPDATE.
|
||||
# ============================================================
|
||||
|
||||
# Pruefen, ob mindestens ein Mod gesetzt ist (Variable fuer spaeter)
|
||||
HAS_MODS=false
|
||||
if [ "$XMLRPC_READY" = "true" ]; then
|
||||
for ENV_NAME in FORCE_MOD_STADIUM FORCE_MOD_ISLAND FORCE_MOD_BAY FORCE_MOD_COAST FORCE_MOD_SPEED FORCE_MOD_ALPINE FORCE_MOD_RALLY; do
|
||||
eval "MOD_VAL=\${$ENV_NAME:-}"
|
||||
if [ -n "$MOD_VAL" ]; then
|
||||
HAS_MODS=true
|
||||
break
|
||||
fi
|
||||
sleep 2
|
||||
done
|
||||
fi
|
||||
|
||||
if [ "$XMLRPC_READY" = "true" ]; then
|
||||
# ============================================================
|
||||
# XAseco starten (nach TrackmaniaServer, VOR Forced Mods)
|
||||
# ============================================================
|
||||
# XAseco muss zuerst starten und sich initialisieren, damit
|
||||
# es die Forced Mods nicht ueberschreibt oder zuruecksetzt.
|
||||
# ============================================================
|
||||
if [ "$XMLRPC_READY" = "true" ]; then
|
||||
if [ "${XASECO_ENABLED:-true}" = "true" ] && [ -f "/opt/tmserver/xaseco/aseco.php" ]; then
|
||||
echo "==> Starte XAseco..."
|
||||
cd /opt/tmserver/xaseco
|
||||
php aseco.php TMN </dev/null >>aseco.log 2>&1 &
|
||||
XASECO_PID=$!
|
||||
echo " XAseco gestartet (PID: ${XASECO_PID})"
|
||||
cd /opt/tmserver
|
||||
else
|
||||
echo " WARNUNG: XMLRPC-Port ${XMLRPC_PORT} nicht erreichbar nach 60s!"
|
||||
echo " XAseco wurde NICHT gestartet. Bitte manuell starten."
|
||||
fi
|
||||
else
|
||||
if [ "${XASECO_ENABLED:-true}" != "true" ]; then
|
||||
elif [ "${XASECO_ENABLED:-true}" != "true" ]; then
|
||||
echo "==> XAseco ist deaktiviert (XASECO_ENABLED=${XASECO_ENABLED})."
|
||||
fi
|
||||
else
|
||||
echo " WARNUNG: XMLRPC nicht erreichbar - XAseco und Forced Mods wurden NICHT gestartet."
|
||||
fi
|
||||
|
||||
# ============================================================
|
||||
# Forced Mods (Skins) per XMLRPC setzen
|
||||
# ============================================================
|
||||
# Wird NACH XAseco-Start ausgefuehrt, damit XAseco die Mods
|
||||
# nicht bei seiner Initialisierung zuruecksetzt.
|
||||
# ============================================================
|
||||
if [ "$XMLRPC_READY" = "true" ] && [ "$HAS_MODS" = "true" ]; then
|
||||
# Warten, damit XAseco und der TM-Server sich vollstaendig initialisieren
|
||||
echo "==> Forced Mods: Warte 10 Sekunden auf vollstaendige Server-Initialisierung..."
|
||||
sleep 10
|
||||
|
||||
echo "==> Forced Mods: Setze Mods per XMLRPC..."
|
||||
|
||||
# JSON-Array der Mods aufbauen
|
||||
MODS_JSON="["
|
||||
MODS_FIRST=true
|
||||
for PAIR in "FORCE_MOD_STADIUM:Stadium" "FORCE_MOD_ISLAND:Island" "FORCE_MOD_BAY:Bay" "FORCE_MOD_COAST:Coast" "FORCE_MOD_SPEED:Speed" "FORCE_MOD_ALPINE:Alpine" "FORCE_MOD_RALLY:Rally"; do
|
||||
VAR_NAME="${PAIR%%:*}"
|
||||
ENV_NAME="${PAIR##*:}"
|
||||
eval "MOD_URL=\${$VAR_NAME:-}"
|
||||
if [ -n "$MOD_URL" ]; then
|
||||
if [ "$MODS_FIRST" = "true" ]; then
|
||||
MODS_FIRST=false
|
||||
else
|
||||
MODS_JSON="${MODS_JSON},"
|
||||
fi
|
||||
# URL fuer JSON escapen (Backslash und Anfuehrungszeichen)
|
||||
SAFE_URL=$(printf '%s' "$MOD_URL" | sed 's/\\/\\\\/g; s/"/\\"/g')
|
||||
MODS_JSON="${MODS_JSON}{\"Env\":\"${ENV_NAME}\",\"Url\":\"${SAFE_URL}\"}"
|
||||
echo " ${ENV_NAME} => ${MOD_URL}"
|
||||
fi
|
||||
done
|
||||
MODS_JSON="${MODS_JSON}]"
|
||||
|
||||
# GBXRemote2-Protokoll: Authenticate + SetForcedMods
|
||||
SA_PW_MODS="${SERVER_SA_PASSWORD:-SuperAdmin}"
|
||||
php -r '
|
||||
$port = (int)$argv[1];
|
||||
$password = $argv[2];
|
||||
$modsJson = $argv[3];
|
||||
|
||||
$mods = json_decode($modsJson, true);
|
||||
if (empty($mods)) { echo " Keine Mods zu setzen.\n"; exit(0); }
|
||||
|
||||
// GBXRemote2: Verbindung herstellen
|
||||
$fp = @fsockopen("127.0.0.1", $port, $errno, $errstr, 5);
|
||||
if (!$fp) { echo " FEHLER: Verbindung zu XMLRPC fehlgeschlagen ($errno: $errstr).\n"; exit(1); }
|
||||
stream_set_timeout($fp, 10);
|
||||
|
||||
// Handshake lesen (4 Bytes Laenge + Protokollstring)
|
||||
$data = fread($fp, 4);
|
||||
if (strlen($data) < 4) { echo " FEHLER: Handshake fehlgeschlagen.\n"; fclose($fp); exit(1); }
|
||||
$info = unpack("Vsize", $data);
|
||||
$handshake = fread($fp, $info["size"]);
|
||||
if (strpos($handshake, "GBXRemote") === false) {
|
||||
echo " FEHLER: Kein GBXRemote-Protokoll.\n"; fclose($fp); exit(1);
|
||||
}
|
||||
echo " Protokoll: $handshake\n";
|
||||
|
||||
$reqhandle = 0x80000001;
|
||||
|
||||
// XML-RPC-Wert kodieren
|
||||
function encodeVal($v) {
|
||||
if (is_bool($v)) return "<value><boolean>" . ($v ? "1" : "0") . "</boolean></value>";
|
||||
if (is_int($v)) return "<value><int>" . $v . "</int></value>";
|
||||
if (is_string($v)) return "<value><string>" . htmlspecialchars($v, ENT_XML1) . "</string></value>";
|
||||
if (is_array($v)) {
|
||||
if (array_keys($v) !== range(0, count($v) - 1)) {
|
||||
$x = "<value><struct>";
|
||||
foreach ($v as $k => $val) $x .= "<member><name>" . $k . "</name>" . encodeVal($val) . "</member>";
|
||||
return $x . "</struct></value>";
|
||||
} else {
|
||||
$x = "<value><array><data>";
|
||||
foreach ($v as $val) $x .= encodeVal($val);
|
||||
return $x . "</data></array></value>";
|
||||
}
|
||||
}
|
||||
return "<value><string>" . htmlspecialchars((string)$v, ENT_XML1) . "</string></value>";
|
||||
}
|
||||
|
||||
// Ein einzelnes Paket vom Server lesen (Header + Body)
|
||||
function readPacket($fp) {
|
||||
$header = "";
|
||||
while (strlen($header) < 8) {
|
||||
$chunk = @fread($fp, 8 - strlen($header));
|
||||
if ($chunk === false || strlen($chunk) === 0) return false;
|
||||
$header .= $chunk;
|
||||
}
|
||||
$info = unpack("Vsize/Vhandle", $header);
|
||||
$size = $info["size"];
|
||||
$handle = $info["handle"];
|
||||
if ($size > 4194304 || $size == 0) return false;
|
||||
|
||||
$body = "";
|
||||
$remaining = $size;
|
||||
while ($remaining > 0) {
|
||||
$chunk = @fread($fp, min($remaining, 8192));
|
||||
if ($chunk === false || strlen($chunk) === 0) break;
|
||||
$body .= $chunk;
|
||||
$remaining -= strlen($chunk);
|
||||
}
|
||||
return ["handle" => $handle, "body" => $body];
|
||||
}
|
||||
|
||||
// XMLRPC-Request senden und Antwort lesen
|
||||
// Callbacks (handle < 0x80000000) werden uebersprungen
|
||||
function gbxQuery($fp, &$reqhandle, $method, $params) {
|
||||
$xml = "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
|
||||
. "<methodCall><methodName>" . $method . "</methodName><params>";
|
||||
foreach ($params as $p) $xml .= "<param>" . encodeVal($p) . "</param>";
|
||||
$xml .= "</params></methodCall>";
|
||||
|
||||
$myHandle = $reqhandle++;
|
||||
$packet = pack("VV", strlen($xml), $myHandle) . $xml;
|
||||
$written = @fwrite($fp, $packet);
|
||||
if ($written === false || $written === 0) {
|
||||
echo " FEHLER: Konnte Request nicht senden ($method).\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
// Auf Antwort warten, Callbacks ueberspringen
|
||||
for ($attempt = 0; $attempt < 30; $attempt++) {
|
||||
$pkt = readPacket($fp);
|
||||
if ($pkt === false) {
|
||||
echo " FEHLER: Keine Antwort fuer $method.\n";
|
||||
return false;
|
||||
}
|
||||
// Callback? (Handle < 0x80000000) -> ueberspringen
|
||||
if ($pkt["handle"] < 0x80000000) {
|
||||
continue;
|
||||
}
|
||||
// Response gefunden
|
||||
return $pkt["body"];
|
||||
}
|
||||
echo " FEHLER: Zu viele Callbacks, keine Antwort fuer $method.\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
// 1. Authenticate
|
||||
echo " Authentifiziere als SuperAdmin...\n";
|
||||
$resp = gbxQuery($fp, $reqhandle, "Authenticate", ["SuperAdmin", $password]);
|
||||
if ($resp === false || strpos($resp, "<boolean>1</boolean>") === false) {
|
||||
echo " FEHLER: Authentifizierung fehlgeschlagen.\n";
|
||||
if ($resp) echo " Antwort: " . substr(trim($resp), 0, 500) . "\n";
|
||||
fclose($fp); exit(1);
|
||||
}
|
||||
echo " Authentifizierung erfolgreich.\n";
|
||||
|
||||
// 2. EnableCallbacks deaktivieren (weniger Rauschen)
|
||||
gbxQuery($fp, $reqhandle, "EnableCallbacks", [false]);
|
||||
|
||||
// 3. SetForcedMods(override=true, mods=[{Env, Url}, ...])
|
||||
// Debug: Zeige das XML das wir senden
|
||||
$setXml = "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
|
||||
. "<methodCall><methodName>SetForcedMods</methodName><params>"
|
||||
. "<param>" . encodeVal(true) . "</param>"
|
||||
. "<param>" . encodeVal($mods) . "</param>"
|
||||
. "</params></methodCall>";
|
||||
echo " Debug SetForcedMods-XML:\n " . $setXml . "\n";
|
||||
|
||||
echo " Sende SetForcedMods (" . count($mods) . " Mod(s))...\n";
|
||||
$resp = gbxQuery($fp, $reqhandle, "SetForcedMods", [true, $mods]);
|
||||
echo " SetForcedMods-Antwort: " . trim($resp) . "\n";
|
||||
if ($resp !== false && strpos($resp, "<boolean>1</boolean>") !== false) {
|
||||
echo " SetForcedMods: OK\n";
|
||||
} else {
|
||||
echo " FEHLER: SetForcedMods fehlgeschlagen.\n";
|
||||
}
|
||||
|
||||
// 4. GetForcedMods zur Verifikation (vollstaendige Antwort)
|
||||
echo " Verifiziere mit GetForcedMods...\n";
|
||||
$resp = gbxQuery($fp, $reqhandle, "GetForcedMods", []);
|
||||
echo " GetForcedMods-Antwort:\n " . trim($resp) . "\n";
|
||||
|
||||
fclose($fp);
|
||||
' "$XMLRPC_PORT" "$SA_PW_MODS" "$MODS_JSON"
|
||||
elif [ "$XMLRPC_READY" = "true" ]; then
|
||||
echo "==> Forced Mods: Keine FORCE_MOD_*-Variablen gesetzt. Ueberspringe."
|
||||
fi
|
||||
|
||||
# Auf TrackmaniaServer warten (Hauptprozess)
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<settings>
|
||||
<mods>
|
||||
<!-- Mods fuer die Stadium-Umgebung -->
|
||||
<!-- Alle Mods werden von https://assets.techniverse.net/tm/skins/ bereitgestellt -->
|
||||
<Stadium>
|
||||
<item name='A Romanorum Superbia'>https://assets.techniverse.net/tm/skins/ARomanorumSuperbia.zip</item>
|
||||
<item name='Bluemod'>https://assets.techniverse.net/tm/skins/Bluemod.zip</item>
|
||||
<item name='Candy Box II'>https://assets.techniverse.net/tm/skins/CANDY_BOX_II.zip</item>
|
||||
<item name='Egyptian Stadium'>https://assets.techniverse.net/tm/skins/Egyptian_Stadium.zip</item>
|
||||
<item name='FC Mod'>https://assets.techniverse.net/tm/skins/FC-mod.zip</item>
|
||||
<item name='Forest Mod'>https://assets.techniverse.net/tm/skins/FoResT_MoD.zip</item>
|
||||
<item name='Imperial Palace'>https://assets.techniverse.net/tm/skins/ImperialPalace.zip</item>
|
||||
<item name='Inca 3'>https://assets.techniverse.net/tm/skins/Inca3.zip</item>
|
||||
<item name='Jurassic Park'>https://assets.techniverse.net/tm/skins/JurassicPark.zip</item>
|
||||
<item name='LMDS Matrix'>https://assets.techniverse.net/tm/skins/LMDSMatrix.zip</item>
|
||||
<item name='Lego Mod'>https://assets.techniverse.net/tm/skins/LegoMod.zip</item>
|
||||
<item name='Lego Mod v2'>https://assets.techniverse.net/tm/skins/LegoModv2.zip</item>
|
||||
<item name='Lego City'>https://assets.techniverse.net/tm/skins/Lego_City.zip</item>
|
||||
<item name='Mario Mod'>https://assets.techniverse.net/tm/skins/MarioMod.zip</item>
|
||||
<item name='Moon Base'>https://assets.techniverse.net/tm/skins/MoonBase.zip</item>
|
||||
<item name='Portal'>https://assets.techniverse.net/tm/skins/Portal.zip</item>
|
||||
<item name='Quantum Leap'>https://assets.techniverse.net/tm/skins/QuantumLeap.zip</item>
|
||||
<item name='RDV Urban 01'>https://assets.techniverse.net/tm/skins/RDV-Urban01.zip</item>
|
||||
<item name='Rainbow Road'>https://assets.techniverse.net/tm/skins/Rainbow%20Road.zip</item>
|
||||
<item name='Star Wars Mod'>https://assets.techniverse.net/tm/skins/StarWarsMod.zip</item>
|
||||
<item name='The Pirate Bay'>https://assets.techniverse.net/tm/skins/ThePirateBay.zip</item>
|
||||
<item name='Toxic'>https://assets.techniverse.net/tm/skins/Toxic.zip</item>
|
||||
<item name='Transparence V1'>https://assets.techniverse.net/tm/skins/TransparenceV1.zip</item>
|
||||
<item name='Western Fortress'>https://assets.techniverse.net/tm/skins/WesternFortress.zip</item>
|
||||
<item name='Wood Mod'>https://assets.techniverse.net/tm/skins/Wood%20Mod.zip</item>
|
||||
<item name='Wooden Domnann'>https://assets.techniverse.net/tm/skins/Wooden%20Domnann.zip</item>
|
||||
<item name='Xmas'>https://assets.techniverse.net/tm/skins/Xmas.zip</item>
|
||||
<item name='N64 Rainbow Road'>https://assets.techniverse.net/tm/skins/_N64_%20Rainbow%20Road.zip</item>
|
||||
<item name='Blue Light'>https://assets.techniverse.net/tm/skins/bluelight.zip</item>
|
||||
<item name='Blue Water'>https://assets.techniverse.net/tm/skins/bluewater.zip</item>
|
||||
<item name='Construct'>https://assets.techniverse.net/tm/skins/construct.zip</item>
|
||||
<item name='Dark Mirror'>https://assets.techniverse.net/tm/skins/darkmirror.zip</item>
|
||||
<item name='Formel 1'>https://assets.techniverse.net/tm/skins/formel1.zip</item>
|
||||
<item name='Future'>https://assets.techniverse.net/tm/skins/future.zip</item>
|
||||
<item name='Hypercube'>https://assets.techniverse.net/tm/skins/hypercube.zip</item>
|
||||
<item name='Icebreaker'>https://assets.techniverse.net/tm/skins/icebraker.zip</item>
|
||||
<item name='Just Black'>https://assets.techniverse.net/tm/skins/justblack.zip</item>
|
||||
<item name='Lego II'>https://assets.techniverse.net/tm/skins/lego_II.zip</item>
|
||||
<item name='Mars'>https://assets.techniverse.net/tm/skins/mars.zip</item>
|
||||
<item name='Modernizer'>https://assets.techniverse.net/tm/skins/modernizer.zip</item>
|
||||
<item name='Neon Glow'>https://assets.techniverse.net/tm/skins/neonglow.zip</item>
|
||||
<item name='Pioneer'>https://assets.techniverse.net/tm/skins/pioneer.zip</item>
|
||||
<item name='Push'>https://assets.techniverse.net/tm/skins/push.zip</item>
|
||||
<item name='Puzzle'>https://assets.techniverse.net/tm/skins/puzzle.zip</item>
|
||||
<item name='Robot Mod 2'>https://assets.techniverse.net/tm/skins/robotmod2.zip</item>
|
||||
<item name='Rubik'>https://assets.techniverse.net/tm/skins/rubik.zip</item>
|
||||
<item name='Smarties'>https://assets.techniverse.net/tm/skins/smarties.zip</item>
|
||||
<item name='Sonic'>https://assets.techniverse.net/tm/skins/sonic.zip</item>
|
||||
<item name='Stadium 2010'>https://assets.techniverse.net/tm/skins/stadium2010.zip</item>
|
||||
<item name='Stadium Storm'>https://assets.techniverse.net/tm/skins/stadium_storm_mod.zip</item>
|
||||
<item name='Tomb'>https://assets.techniverse.net/tm/skins/tomb.zip</item>
|
||||
<item name='Tron Blue'>https://assets.techniverse.net/tm/skins/tronblue.zip</item>
|
||||
<item name='Tron Green'>https://assets.techniverse.net/tm/skins/trongreen.zip</item>
|
||||
<item name='Tron Red'>https://assets.techniverse.net/tm/skins/tronred.zip</item>
|
||||
<item name='Tron Yellow'>https://assets.techniverse.net/tm/skins/tronyellow.zip</item>
|
||||
<item name='Wipeout'>https://assets.techniverse.net/tm/skins/wipeout.zip</item>
|
||||
</Stadium>
|
||||
|
||||
<!-- Mods fuer die Island-Umgebung -->
|
||||
<Island>
|
||||
</Island>
|
||||
|
||||
<!-- Mods fuer die Bay-Umgebung -->
|
||||
<Bay>
|
||||
</Bay>
|
||||
|
||||
<!-- Mods fuer die Coast-Umgebung -->
|
||||
<Coast>
|
||||
</Coast>
|
||||
|
||||
<!-- Mods fuer die Speed-Umgebung -->
|
||||
<Speed>
|
||||
</Speed>
|
||||
|
||||
<!-- Mods fuer die Alpine-Umgebung -->
|
||||
<Alpine>
|
||||
</Alpine>
|
||||
|
||||
<!-- Mods fuer die Rally-Umgebung -->
|
||||
<Rally>
|
||||
</Rally>
|
||||
</mods>
|
||||
<music>
|
||||
<!-- Musik-URLs hier eintragen -->
|
||||
<!-- <item name='Songname'>https://example.com/song.ogg</item> -->
|
||||
</music>
|
||||
</settings>
|
||||
+5
-3
@@ -13,7 +13,7 @@
|
||||
| [Umgebungsvariablen](umgebungsvariablen.md) | Alle verfügbaren Umgebungsvariablen |
|
||||
| [Server-Modi](server-modi.md) | LAN- und Internet-Dedicated-Modus |
|
||||
| [AdminServ](adminserv.md) | Einrichtung der Server-Verwaltungsoberfläche |
|
||||
| [RemoteCP](remotecp.md) | Alternative Server-Verwaltungsoberfläche |
|
||||
| [RemoteCP](remotecp.md) | Alternative Server-Verwaltungsoberfläche (inkl. Mods/Skins) |
|
||||
| [XAseco](xaseco.md) | Server-Controller für Rekorde, Karma und Jukebox |
|
||||
| [Ports](ports.md) | Freigegebene Ports und deren Verwendung |
|
||||
|
||||
@@ -32,8 +32,10 @@
|
||||
│ │ ├── dedicated_cfg.txt # Server-Config-Template (mit Platzhaltern)
|
||||
│ │ └── remotecp/
|
||||
│ │ └── plugins/
|
||||
│ │ └── CustomPoints/
|
||||
│ │ └── index.php # CustomPoints-Plugin fuer RemoteCP
|
||||
│ │ ├── CustomPoints/
|
||||
│ │ │ └── index.php # CustomPoints-Plugin fuer RemoteCP
|
||||
│ │ └── Mods/
|
||||
│ │ └── settings.xml # Skin-Bibliothek (techniverse.net)
|
||||
│ └── db/
|
||||
│ └── init-xaseco-db.sh # MariaDB Init-Script fuer XAseco-DB
|
||||
├── docs/ # Dokumentation
|
||||
|
||||
@@ -93,6 +93,61 @@ Die Konfigurationsdateien befinden sich unter `./data/controlpanel/remotecp/xml/
|
||||
| `admins.xml` | Benutzer und Zugangsdaten |
|
||||
| `groups.xml` | Berechtigungsgruppen |
|
||||
|
||||
## Mods / Skins
|
||||
|
||||
RemoteCP enthält ein **Mods-Plugin**, mit dem Texturpakete (Skins) pro Spielumgebung auf dem Server forciert werden können. Spieler laden den jeweiligen Mod automatisch beim Betreten des Servers herunter.
|
||||
|
||||
### Wie funktionieren Mods?
|
||||
|
||||
In TrackMania Forever sind Mods ZIP-Archive mit alternativen Texturen für eine Spielumgebung (Stadium, Island, Bay, etc.). Der Ablauf:
|
||||
|
||||
1. Der Mod liegt als `.zip`-Datei auf einem **Webserver**, der für die Spieler erreichbar ist
|
||||
2. Der Serveradmin forciert den Mod über den XML-RPC-Befehl `SetForcedMods` (pro Umgebung eine URL)
|
||||
3. Wenn ein Spieler dem Server beitritt, lädt sein Client den Mod automatisch von der angegebenen URL herunter
|
||||
4. Mods sind **flüchtig** – nach einem Serverneustart müssen sie erneut gesetzt werden (das Startup-Script übernimmt das automatisch, siehe unten)
|
||||
|
||||
### Vorkonfigurierte Skin-Bibliothek
|
||||
|
||||
Das Image wird mit einer vorkonfigurierten Skin-Bibliothek ausgeliefert, die über **50 Skins** für die Stadium-Umgebung enthält. Alle Skins werden von [assets.techniverse.net](https://assets.techniverse.net/tm/skins/) bereitgestellt und sind im RemoteCP-Mods-Plugin als Dropdown-Auswahl verfügbar.
|
||||
|
||||
Die Konfiguration befindet sich unter:
|
||||
|
||||
| Host-Pfad | Container-Pfad | Beschreibung |
|
||||
|-----------|----------------|-------------|
|
||||
| `./data/controlpanel/remotecp/plugins/Mods/settings.xml` | `/var/www/html/remotecp/plugins/Mods/settings.xml` | Mod-Katalog (URLs pro Umgebung) |
|
||||
|
||||
> **Hinweis:** Bei bestehenden Installationen (Volumes) wird die alte Standard-`settings.xml` (mit den Original-Beispiel-URLs von blacksunonline.com) beim nächsten Containerstart automatisch durch die neue Version mit den techniverse.net-Skins ersetzt.
|
||||
|
||||
### Mods über RemoteCP verwalten
|
||||
|
||||
1. RemoteCP öffnen: `http://<host-ip>/remotecp/`
|
||||
2. Mit SuperAdmin-Zugangsdaten einloggen
|
||||
3. Im Seitenmenü das **Mods**-Plugin aufrufen
|
||||
4. Pro Umgebung (Stadium, Island, etc.) einen Skin aus dem Dropdown auswählen
|
||||
5. "Submit" klicken – der Mod wird sofort auf dem Server aktiviert
|
||||
|
||||
### Mods automatisch beim Start forcieren
|
||||
|
||||
Über die Umgebungsvariablen `FORCE_MOD_*` kann ein Mod pro Umgebung automatisch bei **jedem** Containerstart gesetzt werden – unabhängig von `FORCE_CONFIG_UPDATE`. Siehe [Umgebungsvariablen – Forced Mods](umgebungsvariablen.md#forced-mods-skins) für Details.
|
||||
|
||||
**Beispiel** (in der `.env`-Datei):
|
||||
|
||||
```bash
|
||||
FORCE_MOD_STADIUM=https://assets.techniverse.net/tm/skins/Portal.zip
|
||||
```
|
||||
|
||||
### Eigene Skins hinzufügen
|
||||
|
||||
Um eigene Skins in das RemoteCP-Dropdown aufzunehmen, bearbeite die Datei `data/controlpanel/remotecp/plugins/Mods/settings.xml` und füge innerhalb der gewünschten Umgebung einen neuen Eintrag hinzu:
|
||||
|
||||
```xml
|
||||
<Stadium>
|
||||
<item name='Mein Skin'>https://example.com/mods/mein_skin.zip</item>
|
||||
</Stadium>
|
||||
```
|
||||
|
||||
> **Wichtig:** Die ZIP-Datei muss von den Spielern über HTTP/HTTPS erreichbar sein.
|
||||
|
||||
## Sicherheit
|
||||
|
||||
RemoteCP liefert eine `.htaccess`-Datei mit, die den direkten Zugriff auf XML-Konfigurationsdateien über den Browser verhindert. Apache `mod_rewrite` und `AllowOverride` sind im Image aktiviert, damit dieser Schutz funktioniert.
|
||||
|
||||
@@ -103,6 +103,41 @@ RemoteCP verwendet die SuperAdmin-Zugangsdaten (`SERVER_SA_PASSWORD`) des TM-Ser
|
||||
|
||||
> **Hinweis:** Diese Werte werden nur beim ersten Start (leeres Volume) angewendet. Weitere Details unter [RemoteCP](remotecp.md).
|
||||
|
||||
## Forced Mods (Skins)
|
||||
|
||||
Mods sind Texturpakete (Skins), die das Aussehen einer Spielumgebung komplett verändern. Über `FORCE_MOD_*`-Variablen kann beim Containerstart automatisch ein Mod pro Umgebung forciert werden. Spieler laden den Mod dann automatisch beim Betreten des Servers herunter.
|
||||
|
||||
| Variable | Beschreibung | Standard |
|
||||
|----------|-------------|----------|
|
||||
| `FORCE_MOD_STADIUM` | Mod-URL für die Stadium-Umgebung | *(leer)* |
|
||||
| `FORCE_MOD_ISLAND` | Mod-URL für die Island-Umgebung | *(leer)* |
|
||||
| `FORCE_MOD_BAY` | Mod-URL für die Bay-Umgebung | *(leer)* |
|
||||
| `FORCE_MOD_COAST` | Mod-URL für die Coast-Umgebung | *(leer)* |
|
||||
| `FORCE_MOD_SPEED` | Mod-URL für die Speed-Umgebung | *(leer)* |
|
||||
| `FORCE_MOD_ALPINE` | Mod-URL für die Alpine-Umgebung | *(leer)* |
|
||||
| `FORCE_MOD_RALLY` | Mod-URL für die Rally-Umgebung | *(leer)* |
|
||||
|
||||
> **Hinweis:** Die Mods werden per XML-RPC (`SetForcedMods`) bei **jedem** Containerstart gesetzt – unabhängig von `FORCE_CONFIG_UPDATE`. Die URL muss auf eine gültige Mod-ZIP-Datei zeigen, die für die Spieler erreichbar ist.
|
||||
|
||||
### Verfügbare Skins
|
||||
|
||||
Eine Auswahl vorkonfigurierter Skins steht unter `https://assets.techniverse.net/tm/skins/` bereit und ist auch im RemoteCP-Mods-Plugin als Dropdown auswählbar.
|
||||
|
||||
**Beispiel:**
|
||||
|
||||
```bash
|
||||
# Portal-Mod für Stadium forcieren
|
||||
FORCE_MOD_STADIUM=https://assets.techniverse.net/tm/skins/Portal.zip
|
||||
|
||||
# Mehrere Umgebungen gleichzeitig
|
||||
FORCE_MOD_STADIUM=https://assets.techniverse.net/tm/skins/Xmas.zip
|
||||
FORCE_MOD_ISLAND=https://example.com/mods/island_mod.zip
|
||||
```
|
||||
|
||||
### Mods über RemoteCP verwalten
|
||||
|
||||
Zusätzlich zur automatischen Konfiguration per Umgebungsvariable können Mods auch zur Laufzeit über das RemoteCP-Web-Interface (`http://<host-ip>/remotecp/`) im Mods-Plugin per Dropdown ausgewählt und aktiviert werden.
|
||||
|
||||
## MariaDB
|
||||
|
||||
| Variable | Beschreibung | Standard |
|
||||
|
||||
Reference in New Issue
Block a user