From 50208b0ee8a909860fc699b479f8055454ca88a2 Mon Sep 17 00:00:00 2001 From: rainer Date: Sat, 7 Jun 2025 14:58:19 +0200 Subject: [PATCH 1/2] updated README with releases-link --- README.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 2bad1cb..917e3c2 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,11 @@ To run this system, the following software packages must be installed on your se ### 1. Clone the Repository -First, clone or copy all project files to a base directory on your server, such as `/opt/luweb/`. +Download the **latest build** from the [Releases-Page](https://git.geigernet.eu/rainer/luanti-web/releases) and save it to your server's base directory, such as `/opt/luweb/`. + +OR + +Clone all project files to a base directory on your server. ``` git clone https://git.geigernet.eu/rainer/luanti-web.git /opt/luweb From 0140e114cdbfc783caaa9aeb0100900bcfcf0d01 Mon Sep 17 00:00:00 2001 From: rainer Date: Sat, 7 Jun 2025 14:58:38 +0200 Subject: [PATCH 2/2] first changes for v0.2 --- generate_map.sh | 55 +-- generate_site.sh | 345 ++++++++++++++---- site_generator/templates/css.template | 91 ++++- site_generator/templates/html_footer.template | 2 +- site_generator/templates/html_header.template | 12 +- .../templates/world_detail_archive.template | 73 +++- .../templates/world_detail_page.template | 305 +++++++++++----- .../templates/worlds_overview_entry.template | 12 +- 8 files changed, 692 insertions(+), 203 deletions(-) diff --git a/generate_map.sh b/generate_map.sh index 4de8461..007d608 100755 --- a/generate_map.sh +++ b/generate_map.sh @@ -33,10 +33,8 @@ MM_CFG_DRAWPLAYERS="$DEFAULT_MM_CFG_DRAWPLAYERS"; MM_CFG_DRAWSCALE="$DEFAULT_MM_ TILES_SUBDIR_NAME="$DEFAULT_TILES_SUBDIR_NAME"; GDAL2TILES_ZOOM_LEVELS="$DEFAULT_GDAL2TILES_ZOOM_LEVELS" WEB_MAP_PNG_FILENAME="$DEFAULT_WEB_MAP_PNG_FILENAME"; RESIZED_MAX_DIMENSION="$DEFAULT_RESIZED_MAX_DIMENSION" ARCHIVE_SUBDIR_NAME="$DEFAULT_ARCHIVE_SUBDIR_NAME" -# RAW_MAP_FILENAME ist global aus config.sh -# RAW_MAP_BASE_SUBDIR ist global aus config.sh (wird für den Output im BASE_SCRIPT_DIR verwendet) -WORLD_WEB_CONFIG_FILE="${CURRENT_MINETEST_WORLD_DATA_PATH}web.conf" # web.conf im Minetest Weltordner +WORLD_WEB_CONFIG_FILE="${CURRENT_MINETEST_WORLD_DATA_PATH}web.conf" if [ -f "$WORLD_WEB_CONFIG_FILE" ]; then echo "$(date '+%Y-%m-%d %H:%M:%S') - [${WORLD_KEY}] - Lade Web-Konfiguration aus ${WORLD_WEB_CONFIG_FILE}" source "$WORLD_WEB_CONFIG_FILE" @@ -50,16 +48,13 @@ MINETESTMAPPER_PATH="${BASE_SCRIPT_DIR}/${MINETESTMAPPER_EXEC_NAME}" LOG_FILE="${LOG_DIR_BASE}/${SCRIPT_BASENAME}_${WORLD_KEY}.log" LOCK_FILE="${LOCK_FILE_BASE_DIR}/${SCRIPT_BASENAME}_${WORLD_KEY}.lock" -# Wichtige Prüfungen für Pfadkomponenten für den Output von minetestmapper if [ -z "$RAW_MAP_BASE_SUBDIR" ]; then echo "FEHLER: RAW_MAP_BASE_SUBDIR ist in config.sh nicht gesetzt oder leer!"; exit 1; fi if [ -z "$RAW_MAP_FILENAME" ]; then echo "FEHLER: RAW_MAP_FILENAME ist in config.sh nicht gesetzt oder leer!"; exit 1; fi -# Ausgabepfade für rohe Kartendaten (im BASE_SCRIPT_DIR) RAW_MAP_OUTPUT_DIR_ABSOLUTE="${BASE_SCRIPT_DIR}/${RAW_MAP_BASE_SUBDIR}/${WORLD_KEY}" RAW_MAP_ABSOLUTE_PATH="${RAW_MAP_OUTPUT_DIR_ABSOLUTE}/${RAW_MAP_FILENAME}" UNKNOWN_NODES_FILE_ABSOLUTE_PATH="${RAW_MAP_OUTPUT_DIR_ABSOLUTE}/unknown_nodes.txt" -# Web-Pfade (nutzen den WORLD_KEY für die Verzeichnisstruktur) WEB_CURRENT_WORLD_DIR="${WEB_ROOT_PATH}/${WEB_MAPS_BASE_SUBDIR}/${WORLD_KEY}" TILES_FULL_OUTPUT_PATH="${WEB_CURRENT_WORLD_DIR}/${TILES_SUBDIR_NAME}" WEB_MAP_PNG_FULL_PATH="${WEB_CURRENT_WORLD_DIR}/${WEB_MAP_PNG_FILENAME}" @@ -101,14 +96,8 @@ flock -n 200 || { echo "$(date '+%Y-%m-%d %H:%M:%S') - [${WORLD_KEY}] Script ${S trap 'rm -f "$LOCK_FILE"; log_message "Skript ${SCRIPT_BASENAME}.sh beendet."' EXIT mkdir -p "$LOG_DIR_BASE"; log_message "Skript ${SCRIPT_BASENAME}.sh gestartet für Welt-Schlüssel: ${WORLD_KEY}" -log_message "DEBUG: MINETESTMAPPER_WORLD_DATA_BASE_PATH = '${MINETESTMAPPER_WORLD_DATA_BASE_PATH}'" # Neuer Debug-Log -log_message "DEBUG: CURRENT_MINETEST_WORLD_DATA_PATH (für -i Option) = '${CURRENT_MINETEST_WORLD_DATA_PATH}'" # Neuer Debug-Log -log_message "DEBUG: RAW_MAP_ABSOLUTE_PATH (für -o Option) = '${RAW_MAP_ABSOLUTE_PATH}'" - mkdir -p "${RAW_MAP_OUTPUT_DIR_ABSOLUTE}" if [ ! -d "${RAW_MAP_OUTPUT_DIR_ABSOLUTE}" ]; then log_message "FEHLER: Rohkarten-Ausgabeverz. (${RAW_MAP_OUTPUT_DIR_ABSOLUTE}) nicht erstellt."; exit 1; fi -log_message "DEBUG: Rohkarten-Ausgabeverzeichnis (${RAW_MAP_OUTPUT_DIR_ABSOLUTE}) existiert." -ls -ld "${RAW_MAP_OUTPUT_DIR_ABSOLUTE}" >> "$LOG_FILE" 2>/dev/null # 1. Generiere die map.png if [ ! -x "$MINETESTMAPPER_PATH" ]; then log_message "FEHLER: minetestmapper (${MINETESTMAPPER_PATH}) nicht ausführbar."; exit 1; fi @@ -119,15 +108,30 @@ if [ "${MM_CFG_DRAWSCALE}" = "true" ]; then MM_ALL_OPTIONS_STR="${MM_ALL_OPTIONS MM_ALL_OPTIONS_STR="${MM_ALL_OPTIONS_STR} --origincolor '${MM_OPT_ORIGINCOLOR}'"; MM_ALL_OPTIONS_STR="${MM_ALL_OPTIONS_STR} --playercolor '${MM_OPT_PLAYERCOLOR}'" MM_ALL_OPTIONS_STR="${MM_ALL_OPTIONS_STR} --scalecolor '${MM_OPT_SCALECOLOR}'"; MM_ALL_OPTIONS_STR="${MM_ALL_OPTIONS_STR} --bgcolor '${MM_OPT_BGCOLOR}'" MM_ALL_OPTIONS_STR="${MM_ALL_OPTIONS_STR} --min-y ${MM_OPT_MIN_Y}" -# Verwendet CURRENT_MINETEST_WORLD_DATA_PATH für -i (korrekt mit / am Ende aus config.sh und WORLD_KEY) + MAP_GENERATION_COMMAND_TO_EVAL="'${MINETESTMAPPER_PATH}' -i '${CURRENT_MINETEST_WORLD_DATA_PATH}' -o '${RAW_MAP_ABSOLUTE_PATH}' ${MM_ALL_OPTIONS_STR}" -log_message "DEBUG: Eval-Befehl: ${MAP_GENERATION_COMMAND_TO_EVAL}" log_message "Starte minetestmapper (Optionen: ${MM_ALL_OPTIONS_STR}). Ausgaben folgen:" MAPPER_RUN_OUTPUT_CAPTURE_FILE=$(mktemp); MAPPER_EXIT_STATUS=0 (set -o pipefail; eval "${MAP_GENERATION_COMMAND_TO_EVAL}" 2>&1 | tee -a "$LOG_FILE" > "$MAPPER_RUN_OUTPUT_CAPTURE_FILE"); MAPPER_EXIT_STATUS=$? if [ ${MAPPER_EXIT_STATUS} -ne 0 ]; then log_message "FEHLER: minetestmapper (Status: ${MAPPER_EXIT_STATUS})."; tail -n 15 "$MAPPER_RUN_OUTPUT_CAPTURE_FILE" | while IFS= read -r line; do log_message " ${line}"; done; rm -f "$MAPPER_RUN_OUTPUT_CAPTURE_FILE"; exit 1; fi if [ ! -f "$RAW_MAP_ABSOLUTE_PATH" ]; then log_message "FEHLER: ${RAW_MAP_ABSOLUTE_PATH} nicht gefunden (minetestmapper Status ${MAPPER_EXIT_STATUS})."; rm -f "$MAPPER_RUN_OUTPUT_CAPTURE_FILE"; exit 1; fi log_message "${RAW_MAP_FILENAME} erfolgreich generiert nach ${RAW_MAP_ABSOLUTE_PATH}." + +# === Karten-Dimensionen auslesen und in map_info.txt speichern === +log_message "Ermittle Dimensionen von ${RAW_MAP_ABSOLUTE_PATH}..." +if ! command -v identify &> /dev/null; then + log_message "WARNUNG: 'identify' (Teil von ImageMagick) nicht gefunden. map_info.txt kann nicht erstellt werden." +else + dimensions=$(identify -format "%wx%h" "$RAW_MAP_ABSOLUTE_PATH" 2>/dev/null) + if [ -n "$dimensions" ]; then + map_info_file="${RAW_MAP_OUTPUT_DIR_ABSOLUTE}/map_info.txt" + echo "$dimensions" > "$map_info_file" + log_message "Dimensionen (${dimensions}) erfolgreich in ${map_info_file} gespeichert." + else + log_message "FEHLER: Konnte Dimensionen von ${RAW_MAP_ABSOLUTE_PATH} nicht ermitteln." + fi +fi + # Unknown Nodes Verarbeitung if [ -f "$MAPPER_RUN_OUTPUT_CAPTURE_FILE" ]; then TEMP_NEW_UNKNOWN_NODES_FILE="${UNKNOWN_NODES_FILE_ABSOLUTE_PATH}.new_found" @@ -137,8 +141,7 @@ if [ -f "$MAPPER_RUN_OUTPUT_CAPTURE_FILE" ]; then else log_message "WARNUNG: minetestmapper-Ausgabe nicht verarbeitbar."; fi rm -f "$MAPPER_RUN_OUTPUT_CAPTURE_FILE" -# 2. Web-Vorschaukarte (verkleinert) erstellen (wie zuvor) -# ... +# 2. Web-Vorschaukarte (verkleinert) erstellen log_message "Erzeuge Web-Version von ${RAW_MAP_FILENAME} (max ${RESIZED_MAX_DIMENSION}px) nach ${WEB_MAP_PNG_FULL_PATH}..." mkdir -p "$(dirname "$WEB_MAP_PNG_FULL_PATH")" if [ ! -f "$RAW_MAP_ABSOLUTE_PATH" ]; then log_message "FEHLER: Quelldatei ${RAW_MAP_ABSOLUTE_PATH} für Web-Vorschau nicht gefunden!"; else @@ -151,8 +154,7 @@ if [ ! -f "$RAW_MAP_ABSOLUTE_PATH" ]; then log_message "FEHLER: Quelldatei ${RAW fi fi -# 3. Tiles generieren (wie zuvor) -# ... +# 3. Tiles generieren log_message "Generiere Kacheln (Zoom: ${GDAL2TILES_ZOOM_LEVELS}) nach ${TILES_FULL_OUTPUT_PATH}..." if [ ! -f "$RAW_MAP_ABSOLUTE_PATH" ]; then log_message "FEHLER: Quelldatei ${RAW_MAP_ABSOLUTE_PATH} für Tiling nicht gefunden!"; else TEMP_TILES_DIR="${TILES_FULL_OUTPUT_PATH}_temp_$(date +%s)"; rm -rf "$TEMP_TILES_DIR"; mkdir -p "$(dirname "$TILES_FULL_OUTPUT_PATH")" @@ -169,8 +171,7 @@ fi # === Archivbereinigung === prune_archives -# 4. Tägliches Archivbild (wie zuvor) -# ... +# 4. Tägliches Archivbild ARCHIVE_YEAR=$(date '+%Y'); ARCHIVE_MONTH=$(date '+%m'); ARCHIVE_DAY=$(date '+%d') ARCHIVE_DAILY_TARGET_DIR="${ARCHIVE_BASE_WEB_PATH}/${ARCHIVE_YEAR}/${ARCHIVE_MONTH}" ARCHIVE_DAILY_FILE_PATH="${ARCHIVE_DAILY_TARGET_DIR}/${ARCHIVE_DAY}.png" @@ -192,8 +193,7 @@ if [ ! -f "$ARCHIVE_DAILY_FILE_PATH" ]; then fi; fi; fi else log_message "Archivbild ${ARCHIVE_DAILY_FILE_PATH} existiert bereits."; fi -# 5. Status- und Info-Dateien im Webverzeichnis (wie zuvor) -# ... +# 5. Status- und Info-Dateien im Webverzeichnis log_message "Erstelle Status- und Info-Dateien im Webverzeichnis ${WEB_CURRENT_WORLD_DIR}..." mkdir -p "$WEB_CURRENT_WORLD_DIR" echo "$(date '+%Y-%m-%d %H:%M:%S %Z')" > "${WEB_CURRENT_WORLD_DIR}/last_update.txt" && log_message "last_update.txt erstellt." || log_message "FEHLER: last_update.txt nicht erstellt." @@ -201,4 +201,15 @@ if [ -f "$UNKNOWN_NODES_FILE_ABSOLUTE_PATH" ]; then if cp "$UNKNOWN_NODES_FILE_ABSOLUTE_PATH" "${WEB_CURRENT_WORLD_DIR}/unknown_nodes.txt"; then log_message "unknown_nodes.txt nach Web kopiert."; else log_message "FEHLER: unknown_nodes.txt nicht nach Web kopiert."; fi else log_message "WARNUNG: ${UNKNOWN_NODES_FILE_ABSOLUTE_PATH} für Web-Kopie nicht gefunden."; fi +# NEU: Kopiere map_info.txt in das Web-Verzeichnis +if [ -f "${RAW_MAP_OUTPUT_DIR_ABSOLUTE}/map_info.txt" ]; then + if cp "${RAW_MAP_OUTPUT_DIR_ABSOLUTE}/map_info.txt" "${WEB_CURRENT_WORLD_DIR}/map_info.txt"; then + log_message "map_info.txt nach Web kopiert." + else + log_message "FEHLER: map_info.txt konnte nicht nach Web kopiert werden." + fi +else + log_message "WARNUNG: Quelldatei map_info.txt für Web-Kopie nicht gefunden." +fi + exit 0 diff --git a/generate_site.sh b/generate_site.sh index cc1d735..7424cea 100755 --- a/generate_site.sh +++ b/generate_site.sh @@ -15,6 +15,7 @@ LOG_FILE="${LOG_DIR_BASE}/${SCRIPT_BASENAME}.log" LOCK_FILE="${LOCK_FILE_BASE_DIR}/${SCRIPT_BASENAME}.lock" WEB_CONTENT_STATIC_PATH="${WEB_CONTENT_BASE_PATH}/${WEB_CONTENT_STATIC_SUBDIR}" CACHE_BUSTER=$(date +%s) +CURRENT_YEAR=$(date '+%Y') ACTUAL_BANNER_IMG_URL_PATH="${FALLBACK_BANNER_IMG_URL}" # === Logging Funktion === @@ -38,22 +39,51 @@ create_placeholder_web_conf() { fi } -# === Template Rendering Funktion === +# === Template Rendering Funktion (FINAL, ROBUST) === render_template() { local template_path="$1" - if [ ! -f "$template_path" ]; then log_message "FEHLER: Template-Datei nicht gefunden: ${template_path}"; return 1; fi - local template_content; template_content=$(<"$template_path") - eval "cat < "$output_path" } # === HTML/CSS Erzeugungsfunktionen === generate_css() { local css_file_path="${WEB_ROOT_PATH}/style.css" log_message "Erzeuge/Aktualisiere ${css_file_path} aus Template..." - local css_banner_image_path="${ACTUAL_BANNER_IMG_URL_PATH}" - render_template "${TEMPLATE_DIR_PATH}/css.template" > "$css_file_path" + render_template "${TEMPLATE_DIR_PATH}/css.template" "$css_file_path" \ + "css_banner_image_path" "$ACTUAL_BANNER_IMG_URL_PATH" \ + "CACHE_BUSTER" "$CACHE_BUSTER" if [ $? -eq 0 ]; then log_message "CSS-Datei erfolgreich erstellt."; else log_message "FEHLER CSS."; fi } @@ -63,48 +93,83 @@ generate_html_header() { local active_page_id="${3:-}" local active_class_home=""; local active_class_worlds=""; local active_class_downloads="" case "$active_page_id" in - home) active_class_home="active" ;; - worlds) active_class_worlds="active" ;; - downloads)active_class_downloads="active" ;; + home) active_class_home="active" ;; + worlds) active_class_worlds="active" ;; + downloads) active_class_downloads="active" ;; esac - render_template "${TEMPLATE_DIR_PATH}/html_header.template" + + local header_file + header_file=$(mktemp) + render_template "${TEMPLATE_DIR_PATH}/html_header.template" "$header_file" \ + "current_page_title" "$current_page_title" \ + "relative_path_prefix" "$relative_path_prefix" \ + "active_class_home" "$active_class_home" \ + "active_class_worlds" "$active_class_worlds" \ + "active_class_downloads" "$active_class_downloads" \ + "CACHE_BUSTER" "$CACHE_BUSTER" \ + "SITE_TITLE" "$SITE_TITLE" + cat "$header_file" + rm "$header_file" } -# --- ANGEPASST: Nutzt jetzt die neue Template-Datei --- generate_html_footer() { - render_template "${TEMPLATE_DIR_PATH}/html_footer.template" + local footer_file + footer_file=$(mktemp) + render_template "${TEMPLATE_DIR_PATH}/html_footer.template" "$footer_file" \ + "CURRENT_YEAR" "$CURRENT_YEAR" \ + "SITE_TITLE" "$SITE_TITLE" \ + "SITE_OWNER_NAME" "$SITE_OWNER_NAME" + cat "$footer_file" + rm "$footer_file" } generate_homepage() { local p="${WEB_ROOT_PATH}/index.html"; local c="${WEB_CONTENT_STATIC_PATH}/startseite_content.html"; log_message "Erzeuge ${p}..."; generate_html_header "Willkommen" "." "home" > "$p"; if [ -f "$c" ]; then cat "$c" >> "$p"; else echo "

Willkommen!

" >> "$p"; fi; generate_html_footer >> "$p"; } -generate_impressum() { local p="${WEB_ROOT_PATH}/impressum.html"; local c="${WEB_CONTENT_STATIC_PATH}/impressum_content.html"; log_message "Erzeuge ${p}..."; generate_html_header "Impressum" > "$p"; if [ -f "$c" ]; then cat "$c" >> "$p"; else echo "

Impressum

Betreiber: ${SITE_OWNER_NAME}
Kontakt: ${SITE_OWNER_EMAIL}

" >> "$p"; fi; generate_html_footer >> "$p"; } +generate_impressum() { local p="${WEB_ROOT_PATH}/impressum.html"; local c="${WEB_CONTENT_STATIC_PATH}/impressum_content.html"; log_message "Erzeuge ${p}..."; generate_html_header "Impressum" "" > "$p"; if [ -f "$c" ]; then cat "$c" >> "$p"; else echo "

Impressum

Betreiber: ${SITE_OWNER_NAME}
Kontakt: ${SITE_OWNER_EMAIL}

" >> "$p"; fi; generate_html_footer >> "$p"; } generate_downloads_page() { local p="${WEB_ROOT_PATH}/downloads.html"; local c="${WEB_CONTENT_STATIC_PATH}/downloads_content.html"; log_message "Erzeuge ${p}..."; generate_html_header "Downloads" "." "downloads" > "$p"; if [ -f "$c" ]; then cat "$c" >> "$p"; else cat >>"$p" <Downloads

Offizielle Seite: luanti.org

EOF fi; generate_html_footer >> "$p"; } -generate_datenschutz_page() { local p="${WEB_ROOT_PATH}/datenschutz.html"; local c="${WEB_CONTENT_STATIC_PATH}/datenschutz_content.html"; log_message "Erzeuge ${p}..."; generate_html_header "Datenschutz" > "$p"; if [ -f "$c" ]; then cat "$c" >> "$p"; else echo "

Datenschutzerklärung

Platzhalter.

" >> "$p"; fi; generate_html_footer >> "$p"; } +generate_datenschutz_page() { local p="${WEB_ROOT_PATH}/datenschutz.html"; local c="${WEB_CONTENT_STATIC_PATH}/datenschutz_content.html"; log_message "Erzeuge ${p}..."; generate_html_header "Datenschutz" "" > "$p"; if [ -f "$c" ]; then cat "$c" >> "$p"; else echo "

Datenschutzerklärung

Platzhalter.

" >> "$p"; fi; generate_html_footer >> "$p"; } generate_worlds_overview() { - local overview_file="${WEB_ROOT_PATH}/worlds.html"; log_message "Erzeuge Weltenübersicht: ${overview_file}..." - generate_html_header "Weltenübersicht" "." "worlds" > "$overview_file"; echo "

Unsere Welten

" >> "$overview_file" + local overview_file="${WEB_ROOT_PATH}/worlds.html" + log_message "Erzeuge Weltenübersicht: ${overview_file}..." + generate_html_header "Weltenübersicht" "." "worlds" > "$overview_file" + echo "

Unsere Welten

" >> "$overview_file" + local discovered_worlds_count=0; shopt -s nullglob local world_key_dirs=("${MINETESTMAPPER_WORLD_DATA_BASE_PATH}"/*/) shopt -u nullglob - if [ ${#world_key_dirs[@]} -eq 0 ]; then log_message "WARNUNG: Keine Welt-Verzeichnisse in ${MINETESTMAPPER_WORLD_DATA_BASE_PATH}."; echo "

Keine Welten verfügbar.

" >> "$overview_file"; + + if [ ${#world_key_dirs[@]} -eq 0 ]; then + log_message "WARNUNG: Keine Welt-Verzeichnisse in ${MINETESTMAPPER_WORLD_DATA_BASE_PATH}." + echo "

Keine Welten verfügbar.

" >> "$overview_file" else + local overview_entry_template_path="${TEMPLATE_DIR_PATH}/worlds_overview_entry.template" for world_data_dir_loop_overview in "${world_key_dirs[@]}"; do - local current_world_key=$(basename "$world_data_dir_loop_overview"); local world_mt_file="${world_data_dir_loop_overview}world.mt"; local web_conf_file="${world_data_dir_loop_overview}web.conf" + local current_world_key + current_world_key=$(basename "$world_data_dir_loop_overview") + local world_mt_file="${world_data_dir_loop_overview}world.mt" + local web_conf_file="${world_data_dir_loop_overview}web.conf" if [ ! -f "$world_mt_file" ] || [ ! -f "$web_conf_file" ]; then continue; fi - local world_display_name_ov; world_display_name_ov=$(get_config_value_from_file "$web_conf_file" "WORLD_DISPLAY_NAME") - local world_short_desc_ov; world_short_desc_ov=$(get_config_value_from_file "$web_conf_file" "WORLD_SHORT_DESCRIPTION" "$DEFAULT_WORLD_SHORT_DESCRIPTION") + local world_display_name_ov + world_display_name_ov=$(get_config_value_from_file "$web_conf_file" "WORLD_DISPLAY_NAME") + local world_short_desc_ov + world_short_desc_ov=$(get_config_value_from_file "$web_conf_file" "WORLD_SHORT_DESCRIPTION" "$DEFAULT_WORLD_SHORT_DESCRIPTION") - local admin_name_ov; unset ADMIN_NAME; source "$web_conf_file" &>/dev/null; if [ ${#ADMIN_NAME[@]} -gt 0 ]; then admin_name_ov=$(IFS=', '; echo "${ADMIN_NAME[*]}"); else admin_name_ov="$SITE_OWNER_NAME"; fi - local current_map_png_filename_for_preview_ov; current_map_png_filename_for_preview_ov=$(get_config_value_from_file "$web_conf_file" "WEB_MAP_PNG_FILENAME" "$DEFAULT_WEB_MAP_PNG_FILENAME") + unset ADMIN_NAME; source "$web_conf_file" &>/dev/null + local admin_name_ov + if [ ${#ADMIN_NAME[@]} -gt 0 ]; then admin_name_ov=$(IFS=', '; echo "${ADMIN_NAME[*]}"); else admin_name_ov="$SITE_OWNER_NAME"; fi + + local current_map_png_filename_for_preview_ov + current_map_png_filename_for_preview_ov=$(get_config_value_from_file "$web_conf_file" "WEB_MAP_PNG_FILENAME" "$DEFAULT_WEB_MAP_PNG_FILENAME") if [ -z "$world_display_name_ov" ]; then - local mt_world_name_from_mt_ov; mt_world_name_from_mt_ov=$(grep -E "^\s*world_name\s*=" "$world_mt_file" | tail -n 1 | cut -d'=' -f2 | xargs) + local mt_world_name_from_mt_ov + mt_world_name_from_mt_ov=$(grep -E "^\s*world_name\s*=" "$world_mt_file" | tail -n 1 | cut -d'=' -f2 | xargs) if [ -n "$mt_world_name_from_mt_ov" ]; then world_display_name_ov="$mt_world_name_from_mt_ov"; - else world_display_name_ov="${DEFAULT_SERVER_DISPLAY_NAME_PREFIX}${current_world_key}"; if [[ "$world_display_name_ov" == "${DEFAULT_SERVER_DISPLAY_NAME_PREFIX}"* && "$DEFAULT_SERVER_DISPLAY_NAME_PREFIX" == "n/a" ]]; then world_display_name_ov="Welt ${current_world_key}"; fi; fi + else world_display_name_ov="Welt ${current_world_key}"; fi fi local detail_page_filename="world_${current_world_key}.html" @@ -112,18 +177,38 @@ generate_worlds_overview() { local preview_img_abs_path="${WEB_ROOT_PATH}/${preview_img_rel_path}" local online_status_text="offline"; local online_status_class="offline" local status_file_for_overview="${WEB_ROOT_PATH}/${WEB_MAPS_BASE_SUBDIR}/${current_world_key}/online_status.txt" - if [ -f "$status_file_for_overview" ]; then local status_line_overview; status_line_overview=$(cat "$status_file_for_overview"); if [[ "$status_line_overview" == "online"* ]]; then online_status_text="online"; online_status_class="online"; fi; fi + if [ -f "$status_file_for_overview" ]; then + local status_line_overview + status_line_overview=$(cat "$status_file_for_overview") + if [[ "$status_line_overview" == "online"* ]]; then online_status_text="online"; online_status_class="online"; fi + fi local preview_img_html - if [ -f "$preview_img_abs_path" ]; then preview_img_html="Vorschau ${world_display_name_ov}"; - else preview_img_html="Keine Vorschau für ${world_display_name_ov}"; fi + if [ -f "$preview_img_abs_path" ]; then + preview_img_html="Vorschau ${world_display_name_ov}" + else + preview_img_html="Keine Vorschau für ${world_display_name_ov}" + fi + + local temp_overview_entry_file + temp_overview_entry_file=$(mktemp) + render_template "$overview_entry_template_path" "$temp_overview_entry_file" \ + "detail_page_filename" "$detail_page_filename" \ + "preview_img_html" "$preview_img_html" \ + "world_display_name_ov" "$world_display_name_ov" \ + "online_status_class" "$online_status_class" \ + "online_status_text" "$online_status_text" \ + "admin_name_ov" "$admin_name_ov" \ + "world_short_desc_ov" "$world_short_desc_ov" + cat "$temp_overview_entry_file" >> "$overview_file" + rm "$temp_overview_entry_file" discovered_worlds_count=$((discovered_worlds_count + 1)) - render_template "${TEMPLATE_DIR_PATH}/worlds_overview_entry.template" >> "$overview_file" done if [ "$discovered_worlds_count" -eq 0 ]; then echo "

Keine Welten mit gültiger Konfiguration gefunden.

" >> "$overview_file"; fi fi - generate_html_footer >> "$overview_file"; if [ $? -eq 0 ]; then log_message "Weltenübersicht erstellt."; else log_message "FEHLER Weltenübersicht."; fi + generate_html_footer >> "$overview_file" + if [ $? -eq 0 ]; then log_message "Weltenübersicht erstellt."; else log_message "FEHLER Weltenübersicht."; fi } generate_world_detail_page() { @@ -132,10 +217,35 @@ generate_world_detail_page() { local world_mt_file="${current_minetest_world_path}/world.mt"; local web_conf_file="${current_minetest_world_path}/web.conf" if [ ! -f "$world_mt_file" ] || [ ! -f "$web_conf_file" ]; then log_message "FEHLER: world.mt oder web.conf für ${current_world_key} fehlt."; return 1; fi - local WORLD_DISPLAY_NAME_PAGE=$(get_config_value_from_file "$web_conf_file" "WORLD_DISPLAY_NAME") - local SERVER_ADDRESS_PAGE=$(get_config_value_from_file "$web_conf_file" "SERVER_ADDRESS" "$DEFAULT_SERVER_ADDRESS") - local SERVER_PORT_PAGE=$(get_config_value_from_file "$web_conf_file" "SERVER_PORT" "$DEFAULT_SERVER_PORT") - local SERVER_ACCESS_INFO_PAGE=$(get_config_value_from_file "$web_conf_file" "SERVER_ACCESS_INFO" "$DEFAULT_SERVER_ACCESS_INFO") + local map_info_file="${BASE_SCRIPT_DIR}/${RAW_MAP_BASE_SUBDIR}/${current_world_key}/map_info.txt" + local MAP_WIDTH=0; local MAP_HEIGHT=0; local MAP_EXTENT_MIN_X=0; local MAP_EXTENT_MIN_Z=0; local MAP_EXTENT_WIDTH=0; local MAP_EXTENT_HEIGHT=0 + if [ -f "$map_info_file" ]; then + local map_dim_val; map_dim_val=$(get_config_value_from_file "$map_info_file" "map_dimension") + if [[ "$map_dim_val" == *"x"* ]]; then + MAP_WIDTH=$(echo "$map_dim_val" | cut -d'x' -f1) + MAP_HEIGHT=$(echo "$map_dim_val" | cut -d'x' -f2) + fi + local map_ext_val; map_ext_val=$(get_config_value_from_file "$map_info_file" "map_extent") + if [[ "$map_ext_val" == *":"* && "$map_ext_val" == *"+"* ]]; then + local min_coords; min_coords=$(echo "$map_ext_val" | cut -d'+' -f1) + local extent_dims; extent_dims=$(echo "$map_ext_val" | cut -d'+' -f2,3) + MAP_EXTENT_MIN_X=$(echo "$min_coords" | cut -d':' -f1) + MAP_EXTENT_MIN_Z=$(echo "$min_coords" | cut -d':' -f2) + MAP_EXTENT_WIDTH=$(echo "$extent_dims" | cut -d'+' -f1) + MAP_EXTENT_HEIGHT=$(echo "$extent_dims" | cut -d'+' -f2) + fi + else + log_message "WARNUNG: ${map_info_file} für '${current_world_key}' nicht gefunden." + fi + + local WORLD_DISPLAY_NAME_PAGE; WORLD_DISPLAY_NAME_PAGE=$(get_config_value_from_file "$web_conf_file" "WORLD_DISPLAY_NAME") + if [ -z "$WORLD_DISPLAY_NAME_PAGE" ]; then + WORLD_DISPLAY_NAME_PAGE=$(get_config_value_from_file "$world_mt_file" "world_name" "Welt ${current_world_key}") + fi + + local SERVER_ADDRESS_PAGE; SERVER_ADDRESS_PAGE=$(get_config_value_from_file "$web_conf_file" "SERVER_ADDRESS" "$DEFAULT_SERVER_ADDRESS") + local SERVER_PORT_PAGE; SERVER_PORT_PAGE=$(get_config_value_from_file "$web_conf_file" "SERVER_PORT" "$DEFAULT_SERVER_PORT") + local SERVER_ACCESS_INFO_PAGE; SERVER_ACCESS_INFO_PAGE=$(get_config_value_from_file "$web_conf_file" "SERVER_ACCESS_INFO" "$DEFAULT_SERVER_ACCESS_INFO") unset ADMIN_NAME ADMIN_SKIN_URL ADMIN_EMAIL ADMIN_DISCORD ADMIN_MATRIX ADMIN_STEAM ADMIN_TEAMSPEAK ADMIN_MUMBLE WORLD_LONG_DESCRIPTION WORLD_GAME_RULES source "$web_conf_file" @@ -143,40 +253,102 @@ generate_world_detail_page() { local WORLD_GAME_RULES_PAGE="${WORLD_GAME_RULES:-}" local STATUS_TEXT_FALLBACK_PAGE="$DEFAULT_SERVER_STATUS_TEXT_FALLBACK" - local CURRENT_TILES_SUBDIR_NAME=$(get_config_value_from_file "$web_conf_file" "TILES_SUBDIR_NAME" "$DEFAULT_TILES_SUBDIR_NAME") - local CURRENT_GDAL2TILES_ZOOM_LEVELS=$(get_config_value_from_file "$web_conf_file" "GDAL2TILES_ZOOM_LEVELS" "$DEFAULT_GDAL2TILES_ZOOM_LEVELS") - local CURRENT_WEB_MAP_PNG_FILENAME=$(get_config_value_from_file "$web_conf_file" "WEB_MAP_PNG_FILENAME" "$DEFAULT_WEB_MAP_PNG_FILENAME") - local CURRENT_ARCHIVE_SUBDIR_NAME=$(get_config_value_from_file "$web_conf_file" "ARCHIVE_SUBDIR_NAME" "$DEFAULT_ARCHIVE_SUBDIR_NAME") - local LEAFLET_BOUNDS_SOUTH=$(get_config_value_from_file "$web_conf_file" "LEAFLET_BOUNDS_SOUTH" "$DEFAULT_LEAFLET_BOUNDS_SOUTH") - local LEAFLET_BOUNDS_WEST=$(get_config_value_from_file "$web_conf_file" "LEAFLET_BOUNDS_WEST" "$DEFAULT_LEAFLET_BOUNDS_WEST") - local LEAFLET_BOUNDS_NORTH=$(get_config_value_from_file "$web_conf_file" "LEAFLET_BOUNDS_NORTH" "$DEFAULT_LEAFLET_BOUNDS_NORTH") - local LEAFLET_BOUNDS_EAST=$(get_config_value_from_file "$web_conf_file" "LEAFLET_BOUNDS_EAST" "$DEFAULT_LEAFLET_BOUNDS_EAST") - local LEAFLET_ZOOM_AFTER_FIT=$(get_config_value_from_file "$web_conf_file" "LEAFLET_ZOOM_AFTER_FIT" "$DEFAULT_LEAFLET_ZOOM_AFTER_FIT") + local CURRENT_WEB_MAP_PNG_FILENAME; CURRENT_WEB_MAP_PNG_FILENAME=$(get_config_value_from_file "$web_conf_file" "WEB_MAP_PNG_FILENAME" "$DEFAULT_WEB_MAP_PNG_FILENAME") + local CURRENT_ARCHIVE_SUBDIR_NAME; CURRENT_ARCHIVE_SUBDIR_NAME=$(get_config_value_from_file "$web_conf_file" "ARCHIVE_SUBDIR_NAME" "$DEFAULT_ARCHIVE_SUBDIR_NAME") - local MT_WORLD_NAME_FROM_MT="$current_world_key"; local MT_GAMEID="$DEFAULT_GAMEID"; local MT_ENABLE_DAMAGE="false"; local MT_CREATIVE_MODE="false" - declare -A parsed_mod_packs; declare -a parsed_standalone_mods + local MT_GAMEID="$DEFAULT_GAMEID"; local MT_ENABLE_DAMAGE="false"; local MT_CREATIVE_MODE="false" + declare -A parsed_mod_packs; declare -a parsed_standalone_mods while IFS='=' read -r key value || [ -n "$key" ]; do key=$(echo "$key"|xargs); value=$(echo "$value"|xargs) case "$key" in - world_name) MT_WORLD_NAME_FROM_MT="$value" ;; gameid) MT_GAMEID="$value" ;; - enable_damage) MT_ENABLE_DAMAGE="$value" ;; creative_mode) MT_CREATIVE_MODE="$value" ;; + gameid) MT_GAMEID="$value" ;; + enable_damage) MT_ENABLE_DAMAGE="$value" ;; + creative_mode) MT_CREATIVE_MODE="$value" ;; load_mod_*) local mod_id="${key#load_mod_}"; mod_id=$(echo "$mod_id"|xargs) if [[ "$value" =~ ^mods/([^/]+)/.+ ]]; then local pack_n="${BASH_REMATCH[1]}"; parsed_mod_packs["$pack_n"]="${parsed_mod_packs[$pack_n]} ${mod_id}"; elif [[ "$value" =~ ^mods/([^/]+)$ ]]; then parsed_standalone_mods+=("$mod_id"); elif [ -n "$value" ]; then parsed_standalone_mods+=("$mod_id"); fi ;; - esac; done < "$world_mt_file" - if [ -z "$WORLD_DISPLAY_NAME_PAGE" ]; then if [ -n "$MT_WORLD_NAME_FROM_MT" ] && [ "$MT_WORLD_NAME_FROM_MT" != "$current_world_key" ]; then WORLD_DISPLAY_NAME_PAGE="$MT_WORLD_NAME_FROM_MT"; else WORLD_DISPLAY_NAME_PAGE="${DEFAULT_SERVER_DISPLAY_NAME_PREFIX}${current_world_key}"; if [[ "$WORLD_DISPLAY_NAME_PAGE" == "${DEFAULT_SERVER_DISPLAY_NAME_PREFIX}"* && "$DEFAULT_SERVER_DISPLAY_NAME_PREFIX" == "n/a" ]]; then WORLD_DISPLAY_NAME_PAGE="Welt ${current_world_key}"; fi;fi;fi + esac; + done < "$world_mt_file" + local MODS_HTML="" + if [ ${#parsed_mod_packs[@]} -gt 0 ] || [ ${#parsed_standalone_mods[@]} -gt 0 ]; then + MODS_HTML+="
    " + local sorted_pack_names=(); if [ ${#parsed_mod_packs[@]} -gt 0 ]; then mapfile -t sorted_pack_names < <(printf '%s\n' "${!parsed_mod_packs[@]}" | sort); fi + for pack_name in "${sorted_pack_names[@]}"; do + MODS_HTML+="
  • + ${pack_name}
      " + local mods_in_pack_str="${parsed_mod_packs[$pack_name]}" + local sorted_mods_in_pack=(); if [ -n "$mods_in_pack_str" ]; then mapfile -t sorted_mods_in_pack < <(echo "$mods_in_pack_str" | tr ' ' '\n' | grep -v '^\s*$' | sort); fi + for mod_in_pack in "${sorted_mods_in_pack[@]}"; do + [ -n "$mod_in_pack" ] && MODS_HTML+="
    • - ${mod_in_pack}
    • " + done + MODS_HTML+="
  • " + done + local sorted_standalone_mods=(); if [ ${#parsed_standalone_mods[@]} -gt 0 ]; then mapfile -t sorted_standalone_mods < <(printf '%s\n' "${parsed_standalone_mods[@]}" | sort); fi + for solo_mod in "${sorted_standalone_mods[@]}"; do + [ -n "$solo_mod" ] && MODS_HTML+="
  • - ${solo_mod}
  • " + done + MODS_HTML+="
" + else + MODS_HTML="

Keine Mod-Informationen in world.mt gefunden.

" + fi + + # KORREKTUR: Logik zur Archiv-Suche wiederhergestellt (wie im Original-Skript) + local ARCHIVE_HTML=""; local available_archive_dates_js_array="[]"; local -a available_archive_dates_bash=(); + local archive_scan_base_path="${WEB_ROOT_PATH}/${WEB_MAPS_BASE_SUBDIR}/${current_world_key}/${CURRENT_ARCHIVE_SUBDIR_NAME}"; + if [ -d "$archive_scan_base_path" ]; then + shopt -s nullglob; + for y_d in "${archive_scan_base_path}"/*/; do + if [ -d "$y_d" ]; then + local y=$(basename "$y_d"); + for m_d in "${y_d}"*/; do + if [ -d "$m_d" ]; then + local m=$(basename "$m_d"); + for d_f in "${m_d}"*.png; do + if [ -f "$d_f" ]; then + local d=$(basename "$d_f" .png); + if [[ "$y" =~ ^[0-9]{4}$ && "$m" =~ ^[0-9]{2}$ && "$d" =~ ^[0-9]{2}$ ]]; then + available_archive_dates_bash+=("${y}-${m}-${d}"); + fi; + fi; + done; + fi; + done; + fi; + done; + shopt -u nullglob; + fi; + if [ ${#available_archive_dates_bash[@]} -gt 0 ]; then + local sorted_dates_str; sorted_dates_str=$(printf '%s\n' "${available_archive_dates_bash[@]}" | sort -r); + local js_dates_temp_array=(); if [ -n "$sorted_dates_str" ]; then mapfile -t js_dates_temp_array < <(echo "$sorted_dates_str"); fi; + local js_array_content=""; + if [ ${#js_dates_temp_array[@]} -gt 0 ]; then + for date_str_loop in "${js_dates_temp_array[@]}"; do + if [ -n "$date_str_loop" ]; then js_array_content+="\"${date_str_loop}\","; fi; + done; + js_array_content=${js_array_content%,}; + fi; + available_archive_dates_js_array="[${js_array_content}]"; + local temp_archive_html_file; temp_archive_html_file=$(mktemp) + local archive_world_rel_to_webroot="/${WEB_MAPS_BASE_SUBDIR}/${current_world_key}/${CURRENT_ARCHIVE_SUBDIR_NAME}" + render_template "${TEMPLATE_DIR_PATH}/world_detail_archive.template" "$temp_archive_html_file" \ + "current_world_key" "$current_world_key" \ + "available_archive_dates_js_array" "$available_archive_dates_js_array" \ + "archive_world_rel_to_webroot" "$archive_world_rel_to_webroot" \ + "CACHE_BUSTER" "$CACHE_BUSTER" + ARCHIVE_HTML=$(<"$temp_archive_html_file") + rm "$temp_archive_html_file" + else + ARCHIVE_HTML="

Keine Archivbilder für diese Welt verfügbar.

"; + fi + local web_map_preview_rel_path="${WEB_MAPS_BASE_SUBDIR}/${current_world_key}/${CURRENT_WEB_MAP_PNG_FILENAME}" - local web_tiles_rel_path="${WEB_MAPS_BASE_SUBDIR}/${current_world_key}/${CURRENT_TILES_SUBDIR_NAME}" - local web_last_update_rel_path="${WEB_MAPS_BASE_SUBDIR}/${current_world_key}/last_update.txt" - local web_unknown_nodes_rel_path="${WEB_MAPS_BASE_SUBDIR}/${current_world_key}/unknown_nodes.txt" local web_online_status_rel_path="${WEB_MAPS_BASE_SUBDIR}/${current_world_key}/online_status.txt" + local web_last_update_rel_path="${WEB_MAPS_BASE_SUBDIR}/${current_world_key}/last_update.txt" local web_players_txt_rel_path="${WEB_MAPS_BASE_SUBDIR}/${current_world_key}/players.txt" local web_weather_txt_rel_path="${WEB_MAPS_BASE_SUBDIR}/${current_world_key}/weather.txt" - local archive_world_rel_to_webroot="/${WEB_MAPS_BASE_SUBDIR}/${current_world_key}/${CURRENT_ARCHIVE_SUBDIR_NAME}" - local map_preview_abs_path="${WEB_ROOT_PATH}/${web_map_preview_rel_path}"; local last_update_abs_path="${WEB_ROOT_PATH}/${web_last_update_rel_path}" - local unknown_nodes_abs_path="${WEB_ROOT_PATH}/${web_unknown_nodes_rel_path}"; local min_zoom="${CURRENT_GDAL2TILES_ZOOM_LEVELS%%-*}"; local max_zoom="${CURRENT_GDAL2TILES_ZOOM_LEVELS##*-}" + local web_unknown_nodes_rel_path="${WEB_MAPS_BASE_SUBDIR}/${current_world_key}/unknown_nodes.txt" + local unknown_nodes_abs_path="${WEB_ROOT_PATH}/${web_unknown_nodes_rel_path}" local creative_text="Aus"; local creative_text_class="offline"; if [ "$MT_CREATIVE_MODE" = "true" ]; then creative_text="An"; creative_text_class="online"; fi local damage_text="Aus"; local damage_text_class="online"; if [ "$MT_ENABLE_DAMAGE" = "true" ]; then damage_text="An"; damage_text_class="offline"; fi @@ -184,7 +356,7 @@ generate_world_detail_page() { local ADMIN_BOXES_HTML="" local num_admins=${#ADMIN_NAME[@]} if [ $num_admins -eq 0 ]; then - ADMIN_BOXES_HTML="
Admin Skin

${SITE_OWNER_NAME}

" + ADMIN_BOXES_HTML="
Admin Skin

${SITE_OWNER_NAME}

" else for i in "${!ADMIN_NAME[@]}"; do local name="${ADMIN_NAME[$i]}"; local skin_url="${ADMIN_SKIN_URL[$i]:-$DEFAULT_PLAYER_SKIN_URL}"; local email="${ADMIN_EMAIL[$i]}"; local discord="${ADMIN_DISCORD[$i]}"; local matrix="${ADMIN_MATRIX[$i]}"; local steam="${ADMIN_STEAM[$i]}"; local teamspeak="${ADMIN_TEAMSPEAK[$i]}"; local mumble="${ADMIN_MUMBLE[$i]}" @@ -198,14 +370,56 @@ generate_world_detail_page() { ADMIN_BOXES_HTML+="
Admin Skin ${name}

${name}

"; if [ -n "$contact_links_html" ]; then ADMIN_BOXES_HTML+=""; fi; ADMIN_BOXES_HTML+="
" done fi + + local map_sub_info_link="" + if [ -f "$unknown_nodes_abs_path" ]; then + map_sub_info_link="Fehlende Map-Nodes" + else + map_sub_info_link=" " + fi - local MAP_HTML=""; if [ -d "${WEB_ROOT_PATH}/${web_tiles_rel_path}" ]; then local map_sub_info_link=""; if [ -f "$unknown_nodes_abs_path" ]; then map_sub_info_link="Fehlende Map-Nodes"; else map_sub_info_link=" "; fi; MAP_HTML=$(render_template "${TEMPLATE_DIR_PATH}/world_detail_map.template"); else MAP_HTML="

Kartenkacheln nicht verfügbar.

"; [ -f "$map_preview_abs_path" ] && MAP_HTML+="

Statische Vorschau:

Vorschau ${WORLD_DISPLAY_NAME_PAGE}"; fi - local ARCHIVE_HTML=""; local available_archive_dates_js_array="[]"; local -a available_archive_dates_bash=(); local archive_scan_base_path="${WEB_ROOT_PATH}/${WEB_MAPS_BASE_SUBDIR}/${current_world_key}/${CURRENT_ARCHIVE_SUBDIR_NAME}"; if [ -d "$archive_scan_base_path" ]; then shopt -s nullglob; for y_d in "${archive_scan_base_path}"/*/; do if [ -d "$y_d" ]; then local y=$(basename "$y_d"); for m_d in "${y_d}"*/; do if [ -d "$m_d" ]; then local m=$(basename "$m_d"); for d_f in "${m_d}"*.png; do if [ -f "$d_f" ]; then local d=$(basename "$d_f" .png); if [[ "$y" =~ ^[0-9]{4}$ && "$m" =~ ^[0-9]{2}$ && "$d" =~ ^[0-9]{2}$ ]]; then available_archive_dates_bash+=("${y}-${m}-${d}");fi;fi;done;fi;done;fi;done; shopt -u nullglob;fi; if [ ${#available_archive_dates_bash[@]} -gt 0 ]; then local sorted_dates_str; sorted_dates_str=$(printf '%s\n' "${available_archive_dates_bash[@]}" | sort -r); local js_dates_temp_array=(); if [ -n "$sorted_dates_str" ]; then mapfile -t js_dates_temp_array < <(echo "$sorted_dates_str"); fi; local js_array_content=""; if [ ${#js_dates_temp_array[@]} -gt 0 ]; then for date_str_loop in "${js_dates_temp_array[@]}"; do if [ -n "$date_str_loop" ]; then js_array_content+="\"${date_str_loop}\","; fi; done; js_array_content=${js_array_content%,}; fi; available_archive_dates_js_array="[${js_array_content}]"; ARCHIVE_HTML=$(render_template "${TEMPLATE_DIR_PATH}/world_detail_archive.template"); else ARCHIVE_HTML="

Keine Archivbilder für diese Welt verfügbar.

"; fi - local MODS_HTML=""; if [ ${#parsed_mod_packs[@]} -gt 0 ] || [ ${#parsed_standalone_mods[@]} -gt 0 ]; then MODS_HTML+="
    "; local sorted_pack_names=(); if [ ${#parsed_mod_packs[@]} -gt 0 ]; then mapfile -t sorted_pack_names < <(printf '%s\n' "${!parsed_mod_packs[@]}" | sort); fi; for pack_name in "${sorted_pack_names[@]}"; do MODS_HTML+="
  • + ${pack_name}
      "; local mods_in_pack_str="${parsed_mod_packs[$pack_name]}"; local sorted_mods_in_pack=(); if [ -n "$mods_in_pack_str" ]; then mapfile -t sorted_mods_in_pack < <(echo "$mods_in_pack_str" | tr ' ' '\n' | grep -v '^\s*$' | sort); fi; for mod_in_pack in "${sorted_mods_in_pack[@]}"; do [ -n "$mod_in_pack" ] && MODS_HTML+="
    • - ${mod_in_pack}
    • "; done; MODS_HTML+="
  • "; done; local sorted_standalone_mods=(); if [ ${#parsed_standalone_mods[@]} -gt 0 ]; then mapfile -t sorted_standalone_mods < <(printf '%s\n' "${parsed_standalone_mods[@]}" | sort); fi; for solo_mod in "${sorted_standalone_mods[@]}"; do [ -n "$solo_mod" ] && MODS_HTML+="
  • - ${solo_mod}
  • "; done; MODS_HTML+="
"; else MODS_HTML="

Keine Mod-Informationen in world.mt gefunden.

"; fi + { + generate_html_header "Welt: ${WORLD_DISPLAY_NAME_PAGE}" "" + + local temp_body_file + temp_body_file=$(mktemp) + render_template "${TEMPLATE_DIR_PATH}/world_detail_page.template" "$temp_body_file" \ + "WORLD_DISPLAY_NAME_PAGE" "$WORLD_DISPLAY_NAME_PAGE" \ + "current_world_key" "$current_world_key" \ + "STATUS_TEXT_FALLBACK_PAGE" "$STATUS_TEXT_FALLBACK_PAGE" \ + "MT_GAMEID" "$MT_GAMEID" \ + "creative_text_class" "$creative_text_class" \ + "creative_text" "$creative_text" \ + "damage_text_class" "$damage_text_class" \ + "damage_text" "$damage_text" \ + "SERVER_ADDRESS_PAGE" "$SERVER_ADDRESS_PAGE" \ + "SERVER_PORT_PAGE" "$SERVER_PORT_PAGE" \ + "SERVER_ACCESS_INFO_PAGE" "$SERVER_ACCESS_INFO_PAGE" \ + "ADMIN_BOXES_HTML" "$ADMIN_BOXES_HTML" \ + "web_online_status_rel_path" "$web_online_status_rel_path" \ + "web_last_update_rel_path" "$web_last_update_rel_path" \ + "CACHE_BUSTER" "$CACHE_BUSTER" \ + "web_players_txt_rel_path" "$web_players_txt_rel_path" \ + "MAP_WIDTH" "$MAP_WIDTH" \ + "MAP_HEIGHT" "$MAP_HEIGHT" \ + "MAP_EXTENT_MIN_X" "$MAP_EXTENT_MIN_X" \ + "MAP_EXTENT_MIN_Z" "$MAP_EXTENT_MIN_Z" \ + "MAP_EXTENT_WIDTH" "$MAP_EXTENT_WIDTH" \ + "MAP_EXTENT_HEIGHT" "$MAP_EXTENT_HEIGHT" \ + "DEFAULT_PLAYER_SKIN_URL" "$DEFAULT_PLAYER_SKIN_URL" \ + "web_map_preview_rel_path" "$web_map_preview_rel_path" \ + "web_weather_txt_rel_path" "$web_weather_txt_rel_path" \ + "WORLD_LONG_DESCRIPTION_PAGE" "$WORLD_LONG_DESCRIPTION_PAGE" \ + "WORLD_GAME_RULES_PAGE" "$WORLD_GAME_RULES_PAGE" \ + "web_unknown_nodes_rel_path" "$web_unknown_nodes_rel_path" \ + "ARCHIVE_HTML" "$ARCHIVE_HTML" \ + "MODS_HTML" "$MODS_HTML" \ + "map_sub_info_link" "$map_sub_info_link" + cat "$temp_body_file" + rm "$temp_body_file" - generate_html_header "Welt: ${WORLD_DISPLAY_NAME_PAGE}" "" "" > "$detail_page_file" - render_template "${TEMPLATE_DIR_PATH}/world_detail_page.template" >> "$detail_page_file" - generate_html_footer >> "$detail_page_file" + generate_html_footer + } > "$detail_page_file" if [ $? -eq 0 ]; then log_message "Detailseite ${WORLD_DISPLAY_NAME_PAGE} erstellt."; else log_message "FEHLER Detailseite ${WORLD_DISPLAY_NAME_PAGE}."; fi } @@ -217,6 +431,7 @@ flock -n 200 || { echo "$(date '+%Y-%m-%d %H:%M:%S') - Script ${SCRIPT_BASENAME} trap 'rm -f "$LOCK_FILE"; log_message "Script ${SCRIPT_BASENAME}.sh beendet."' EXIT mkdir -p "$LOG_DIR_BASE"; mkdir -p "${WEB_ROOT_PATH}" log_message "Script ${SCRIPT_BASENAME}.sh gestartet." + log_message "Prüfe und erstelle Webseiten-Inhaltsverzeichnisse und Platzhalter..." mkdir -p "${WEB_CONTENT_BASE_PATH}"; mkdir -p "${WEB_CONTENT_STATIC_PATH}"; mkdir -p "${TEMPLATE_DIR_PATH}"; mkdir -p "${EXAMPLE_TEMPLATE_DIR_PATH}" @@ -229,18 +444,16 @@ create_placeholder_file "${WEB_CONTENT_STATIC_PATH}/downloads_content.html" "

Datenschutzerklärung

Hier deinen Datenschutztext einfügen.

" log_message "Starte Generierung der statischen Webseiten-Dateien..." -# --- Asset Copying --- log_message "Kopiere Webseiten-Assets (Bilder, Icons)..." WEB_IMAGES_TARGET_DIR="${WEB_ROOT_PATH}/images" WEB_PLAYER_IMAGES_TARGET_DIR="${WEB_IMAGES_TARGET_DIR}/players" SOURCE_IMAGES_DIR="${WEB_CONTENT_BASE_PATH}/${WEB_CONTENT_IMAGES_SOURCE_SUBDIR:-images_source}" -SOURCE_PLAYER_IMAGES_DIR="${SOURCE_IMAGES_DIR}/players" +SOURCE_PLAYER_IMAGES_TARGET_DIR="${SOURCE_IMAGES_DIR}/players" mkdir -p "$WEB_IMAGES_TARGET_DIR"; mkdir -p "$WEB_PLAYER_IMAGES_TARGET_DIR" if [ -d "$SOURCE_IMAGES_DIR" ]; then shopt -s nullglob; for src_file in "$SOURCE_IMAGES_DIR"/* ; do [ -f "$src_file" ] && cp -u "$src_file" "$WEB_IMAGES_TARGET_DIR/"; done; shopt -u nullglob; log_message "Allgemeine Bilder kopiert/aktualisiert."; else log_message "WARNUNG: Quellverz. allgemeine Bilder nicht gefunden: ${SOURCE_IMAGES_DIR}"; fi if [ -d "$SOURCE_PLAYER_IMAGES_DIR" ]; then shopt -s nullglob; for src_file in "$SOURCE_PLAYER_IMAGES_DIR"/*.png ; do [ -f "$src_file" ] && cp -u "$src_file" "$WEB_PLAYER_IMAGES_TARGET_DIR/"; done; shopt -u nullglob; log_message "Spieler-Skins kopiert/aktualisiert."; else log_message "WARNUNG: Quellverz. Spieler-Skins nicht gefunden: ${SOURCE_PLAYER_IMAGES_DIR}"; fi -# --- Ende Asset Copying --- if [ -n "$STATIC_BANNER_FILENAME" ]; then ACTUAL_BANNER_IMG_URL_PATH="/images/${STATIC_BANNER_FILENAME}"; if [ ! -f "${WEB_ROOT_PATH}${ACTUAL_BANNER_IMG_URL_PATH}" ]; then log_message "WARNUNG: Statisches Banner '${STATIC_BANNER_FILENAME}' nicht in '${WEB_ROOT_PATH}/images/' gefunden. Fallback: ${FALLBACK_BANNER_IMG_URL}"; ACTUAL_BANNER_IMG_URL_PATH="${FALLBACK_BANNER_IMG_URL}"; else log_message "Verwende statisches Banner: ${ACTUAL_BANNER_IMG_URL_PATH}"; fi else log_message "Kein STATIC_BANNER_FILENAME, verwende Fallback: ${FALLBACK_BANNER_IMG_URL}"; ACTUAL_BANNER_IMG_URL_PATH="${FALLBACK_BANNER_IMG_URL}"; fi diff --git a/site_generator/templates/css.template b/site_generator/templates/css.template index 6d43183..4c3f45c 100755 --- a/site_generator/templates/css.template +++ b/site_generator/templates/css.template @@ -53,7 +53,7 @@ a:hover { text-decoration: underline; color: #FFC500; } .header-banner { width: 100%; height: 240px; - background-image: url('${css_banner_image_path}?v=${CACHE_BUSTER}'); + background-image: url('%%css_banner_image_path%%?v=%%CACHE_BUSTER%%'); background-size: cover; background-position: center 45%; border-bottom: 2px solid #4A2E0A; @@ -100,11 +100,13 @@ a.world-preview:hover { .page-nav-buttons { text-align: right; margin-top: 10px; margin-bottom: 15px; } .page-nav-buttons .button { background-color: #555; color: #FFA500; border: 1px solid #666; padding: 5px 10px; margin-left: 5px; margin-bottom: 5px; border-radius: 3px; text-decoration: none; font-size: 0.9em; display: inline-block; } .page-nav-buttons .button:hover { background-color: #666; color: #FFC500; } -.leaflet-map { width: 100%; height: 500px; border: 1px solid #666; margin-bottom: 5px; border-radius: 3px;} +.leaflet-map { width: 100%; height: 600px; border: 1px solid #666; margin-bottom: 5px; border-radius: 3px; background-color: #111;} .map-sub-info { display: flex; justify-content: space-between; align-items: center; font-size: 0.9em; color: #aaa; margin-bottom: 20px; padding: 5px 0; } -.map-sub-info .map-file-link { text-align: left; } .map-sub-info .map-last-update { text-align: right; } +.map-sub-info .map-file-link { text-align: left; } +.map-sub-info .map-last-update { text-align: right; } .info-box { background-color: #3a3a3a; border: 1px solid #555; padding: 15px; margin-bottom: 20px; border-left: 5px solid #FFD700; border-radius: 3px;} .info-box h3 { margin-top: 0; border-bottom: none; padding-bottom: 0.2em; } + /* Admin Sektion */ .admin-section h3 { margin-top: 2.5em !important; } .admin-grid { @@ -117,7 +119,10 @@ a.world-preview:hover { padding: 15px; border-radius: 5px; border: 1px solid #4a4a4a; - flex: 1; + flex-grow: 0; /* KORREKTUR: Verhindert das Strecken der letzten Box */ + flex-shrink: 1; + flex-basis: calc(50% - 8px); + box-sizing: border-box; min-width: 280px; } .admin-contact-block { display: flex; align-items: center; } @@ -171,7 +176,16 @@ a.world-preview:hover { .copy-button:hover { background: #666; } .player-list-container { margin-top: 1em; } .player-list-grid { display: flex; flex-wrap: wrap; gap: 15px; box-sizing: border-box; } -.player-box { background-color: #303030; border: 1px solid #555; border-radius: 5px; padding: 10px; width: calc(33.333% - 10px); box-sizing: border-box; display: flex; flex-direction: column;} +.player-box { + background-color: #303030; + border: 1px solid #555; + border-radius: 5px; + padding: 10px; + width: calc((100% - 30px) / 3); /* KORREKTUR: Max 3 Boxen pro Zeile */ + box-sizing: border-box; + display: flex; + flex-direction: column; +} .player-box.has-server-priv { border-left: 5px solid #FFD700; } .player-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 8px; } .player-identity { display: flex; align-items: center; } @@ -415,8 +429,56 @@ a.read-more-link { display: block; } -.leaflet-control-fullscreen a { background:#fff url('data:image/svg+xml;charset=utf8,%3Csvg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32"%3E%3Cpath d="M4 14h6v6h4v-4h6v-4h-6v-4h-4v4H4zm17 2h12v-2H21zm0 4h12v-2H21zm5 1h7v-2h-7zM10 23h12v4h-4v-4h-4v4H10zm15 0h7v-2h-7z"/%3E%3C/svg%3E') no-repeat 0 0 !important; background-size: 16px 16px !important; } -.leaflet-control-fullscreen a.leaflet-fullscreen-on { background-image: url('data:image/svg+xml;charset=utf8,%3Csvg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32"%3E%3Cpath d="M7 13h2V7h6V5H7zm11-2h7v7h-2v-5h-5z"/%3E%3C/svg%3E') no-repeat 0 0 !important; background-size: 16px 16px !important; } +/* KORREKTUR: Leaflet Fullscreen Button Icon */ +.leaflet-control-fullscreen a { + background: #fff url('data:image/svg+xml;charset=utf8,%3Csvg viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"%3E%3Cpath d="M2 9H0v7h7v-2H2V9zM0 7h2V2h5V0H0v7zm14 2v5h-5v2h7V9h-2zm0-2V0h-7v2h5v5h2z" fill="%23333"/%3E%3C/svg%3E') no-repeat center center; + background-size: 16px 16px; + font-size: 0; /* Versteckt fehlerhafte Text-Icons */ +} +.leaflet-control-fullscreen a.leaflet-fullscreen-on { + background-image: url('data:image/svg+xml;charset=utf8,%3Csvg viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"%3E%3Cpath d="M0 11h5v5h2V9H0v2zm11 5h5V9h-2v5h-3v2zM5 0H0v7h2V2h3V0zm9 2V0h-2v7h7V5h-5z" fill="%23333"/%3E%3C/svg%3E'); +} + +/* KORREKTUR: Stile für Marker-Popup */ +.leaflet-popup-content-wrapper, .leaflet-popup-content { + background-color: #303030 !important; + color: #ddd !important; + border-radius: 5px; +} +.leaflet-popup-content { + margin: 0 !important; + padding: 0 !important; + line-height: 1.5; +} +.leaflet-container a.leaflet-popup-close-button { + color: #ddd; + padding: 8px 8px 0 0; +} +.leaflet-container a.leaflet-popup-close-button:hover { + color: #fff; + background-color: transparent; +} +.popup-player-box { + padding: 10px; +} +.popup-player-box .player-name { + font-size: 1.2em; /* Schriftgröße für Namen im Popup erhöht */ +} +.popup-player-vitals { + display: flex; + justify-content: space-around; + gap: 10px; + align-items: center; + margin-top: 8px; +} +.popup-player-vitals .vital { + display: flex; + align-items: center; + gap: 5px; +} +.popup-player-vitals .icon { + font-size: 1.2em; +} @media (max-width: 768px) { /* Responsive Stile für Burger-Menü */ @@ -449,7 +511,7 @@ a.read-more-link { margin: 5px; width: auto; } - .player-box { width: calc(50% - 10px); } + .player-box { width: calc((100% - 15px) / 2); } /* 2 Spalten auf Tablets */ .page-nav-buttons .button { margin-top: 5px;} /* Responsive Stile für Welt-Vorschau */ @@ -463,12 +525,13 @@ a.read-more-link { margin-right: 0; margin-bottom: 15px; } - - /* NEU: Responsive Höhe für Leaflet-Karte */ .leaflet-map { - height: auto; /* Deaktiviert die feste Höhe von 500px */ - aspect-ratio: 1 / 1; /* Erzwingt ein quadratisches Seitenverhältnis */ - max-height: 70vh; /* Stellt sicher, dass die Karte nicht den ganzen Bildschirm füllt */ + height: auto; + aspect-ratio: 4 / 3; + max-height: 70vh; } } -@media (max-width: 480px) { .player-box { width: 100%; } } +@media (max-width: 480px) { + .player-box { width: 100%; } /* 1 Spalte auf Handys */ + .admin-box { flex-basis: 100%; } /* 1 Spalte auf Handys */ +} diff --git a/site_generator/templates/html_footer.template b/site_generator/templates/html_footer.template index 2699a3b..2bea999 100755 --- a/site_generator/templates/html_footer.template +++ b/site_generator/templates/html_footer.template @@ -1,6 +1,6 @@ diff --git a/site_generator/templates/html_header.template b/site_generator/templates/html_header.template index 067b15d..8cc4f1b 100755 --- a/site_generator/templates/html_header.template +++ b/site_generator/templates/html_header.template @@ -3,8 +3,8 @@ - ${current_page_title} - ${SITE_TITLE} - + %%current_page_title%% - %%SITE_TITLE%% + @@ -40,13 +40,13 @@
-

${SITE_TITLE}

+

%%SITE_TITLE%%

diff --git a/site_generator/templates/world_detail_archive.template b/site_generator/templates/world_detail_archive.template index af96c9c..0061929 100755 --- a/site_generator/templates/world_detail_archive.template +++ b/site_generator/templates/world_detail_archive.template @@ -1,3 +1,70 @@ -
-
- +
+ + + +
+ +
+ +

Bitte ein Datum auswählen, um die Karte anzuzeigen.

+
+ + diff --git a/site_generator/templates/world_detail_page.template b/site_generator/templates/world_detail_page.template index 1dda627..63f6245 100755 --- a/site_generator/templates/world_detail_page.template +++ b/site_generator/templates/world_detail_page.template @@ -1,5 +1,5 @@
-

${WORLD_DISPLAY_NAME_PAGE}

+

%%WORLD_DISPLAY_NAME_PAGE%%

@@ -13,7 +13,7 @@ -