#!/bin/bash # Lade globale Konfiguration CONFIG_FILE_PATH="$(dirname "$0")/config.sh" if [ -f "$CONFIG_FILE_PATH" ]; then source "$CONFIG_FILE_PATH" else echo "FEHLER: Globale config.sh nicht unter ${CONFIG_FILE_PATH} gefunden!" exit 1 fi # === Logging Funktion (früh definieren für Wrapper-Logik) === LOG_FILE_BASE="${LOG_DIR_BASE}/$(basename "$0" .sh)" log_message() { local key="${1:-main}" local msg="$2" local log_target="${LOG_FILE_BASE}.log" [ "$key" != "main" ] && log_target="${LOG_FILE_BASE}_${key}.log" local message_to_log; message_to_log="$(date '+%Y-%m-%d %H:%M:%S') - [${key}] - ${msg}" echo "${message_to_log}" | tee -a "$log_target" } # --- Wrapper-Logik zur Verarbeitung aller Welten, wenn kein Argument übergeben wird --- if [ -z "$1" ]; then log_message "main" "Kein spezifischer Welt-Schlüssel angegeben. Verarbeite alle Welten mit web.conf..." shopt -s nullglob for world_dir in "${MINETESTMAPPER_WORLD_DATA_BASE_PATH}"/*/; do if [ -f "${world_dir}web.conf" ]; then world_key_to_process=$(basename "$world_dir") log_message "main" "--- Starte Durchlauf für '${world_key_to_process}' ---" bash "$0" "$world_key_to_process" fi done shopt -u nullglob log_message "main" "Alle Welten verarbeitet." exit 0 fi # ############################################################################# # Ab hier beginnt die Logik für eine EINZELNE Welt # ############################################################################# /opt/luweb/check_dependencies.sh || exit 1 WORLD_KEY=$1 CURRENT_MINETEST_WORLD_DATA_PATH="${MINETESTMAPPER_WORLD_DATA_BASE_PATH}${WORLD_KEY}/" # === Abgeleitete Variablen === SCRIPT_BASENAME=$(basename "$0" .sh) LOG_FILE="${LOG_DIR_BASE}/${SCRIPT_BASENAME}_${WORLD_KEY}.log" LOCK_FILE="${LOCK_FILE_BASE_DIR}/${SCRIPT_BASENAME}_${WORLD_KEY}.lock" # Pfade zu den Quell- und Zieldateien MOD_STORAGE_DB_PATH="${CURRENT_MINETEST_WORLD_DATA_PATH}mod_storage.sqlite" TPADS_JSON_TARGET_DIR="${WEB_ROOT_PATH}/${WEB_MAPS_BASE_SUBDIR}/${WORLD_KEY}" TPADS_JSON_FILE_PATH="${TPADS_JSON_TARGET_DIR}/tpads.txt" TPADS_JSON_TMP_FILE_PATH="${TPADS_JSON_FILE_PATH}.tmp" # SQLite-Befehl SQLITE_CMD="sqlite3 -readonly" # === Hauptlogik für eine einzelne Welt === exec 200>"$LOCK_FILE" flock -n 200 || { log_message "${WORLD_KEY}" "Script ${SCRIPT_BASENAME}.sh ist bereits für diese Welt aktiv. Beende."; exit 1; } trap 'rm -f "$LOCK_FILE"; log_message "${WORLD_KEY}" "Skript beendet."' EXIT log_message "${WORLD_KEY}" "Script gestartet." if [ ! -f "$MOD_STORAGE_DB_PATH" ]; then log_message "${WORLD_KEY}" "INFO: mod_storage.sqlite nicht gefunden. Erstelle leere tpads.txt." mkdir -p "$TPADS_JSON_TARGET_DIR" echo "[]" > "$TPADS_JSON_FILE_PATH" exit 0 fi log_message "${WORLD_KEY}" "Lese ${MOD_STORAGE_DB_PATH} und extrahiere öffentliche TPADs (type=4)..." # KORREKTUR: Die 'trim'-Funktion wird durch 'sub' ersetzt für höhere Kompatibilität. $SQLITE_CMD "$MOD_STORAGE_DB_PATH" "SELECT key, value FROM entries WHERE modname = 'tpad' AND INSTR(key, 'pads:') = 1;" | \ jq -Rs ' # Definiere eine eigene trimm-Funktion für ältere jq-Versionen def trim: sub("^\\s+"; "") | sub("\\s+$"; ""); split("\n") | map(select(length > 0)) | map( split("|") | {key: .[0], value: .[1]} | (.key | split(":")[1]) as $owner | (.value | [capture("\\[\"\\((?[^,]*),(?[^,]*),(?[^)]*)\\)\"\\]=\\{(?[^\\}]*)\\}"; "g")]) as $entries | $entries | map( (.props | split(",") | map(split("=")) | map({(.[0]|trim): .[1]|trim}) | add) as $prop_obj | select($prop_obj.type == "4") | { owner: $owner, name: ($prop_obj.name | gsub("\""; "")), posX: (.posX | tonumber), posY: (.posY | tonumber), posZ: (.posZ | tonumber) } ) ) | flatten ' > "$TPADS_JSON_TMP_FILE_PATH" if [ $? -ne 0 ]; then log_message "${WORLD_KEY}" "FEHLER: jq-Transformation fehlgeschlagen." rm -f "$TPADS_JSON_TMP_FILE_PATH" exit 1 fi # Temporäre Datei an den Zielort verschieben mkdir -p "$TPADS_JSON_TARGET_DIR" mv "$TPADS_JSON_TMP_FILE_PATH" "$TPADS_JSON_FILE_PATH" log_message "${WORLD_KEY}" "tpads.txt erfolgreich synchronisiert nach ${TPADS_JSON_FILE_PATH}" exit 0