From e57dc8f49887029655613abd8b16279fb4bfad8f Mon Sep 17 00:00:00 2001 From: rainer Date: Mon, 21 Jul 2025 20:40:14 +0200 Subject: [PATCH] Integrate sync_tpads.sh to show Teleporter Pdas in a new created overlay --- .../generators/world_detail_generator.sh | 1 + site_generator/templates/css.template | 31 +++-- .../templates/world_detail_radar.template | 126 +++++++++++++++--- sync_tpads.sh | 117 ++++++++++++++++ 4 files changed, 243 insertions(+), 32 deletions(-) create mode 100755 sync_tpads.sh diff --git a/site_generator/functions/generators/world_detail_generator.sh b/site_generator/functions/generators/world_detail_generator.sh index b54c8a9..f210d2a 100644 --- a/site_generator/functions/generators/world_detail_generator.sh +++ b/site_generator/functions/generators/world_detail_generator.sh @@ -172,6 +172,7 @@ generate_world_detail_page() { "web_tiles_rel_path" "$web_tiles_rel_path" \ "web_map_info_rel_path" "${WEB_MAPS_BASE_SUBDIR}/${current_world_key}/map_info.txt" \ "web_areas_json_rel_path" "${WEB_MAPS_BASE_SUBDIR}/${current_world_key}/areas.json" \ + "web_tpads_txt_rel_path" "${WEB_MAPS_BASE_SUBDIR}/${current_world_key}/tpads.txt" \ "map_background_color" "$map_background_color" \ "DEFAULT_PLAYER_SKIN_URL" "$DEFAULT_PLAYER_SKIN_URL" local WORLD_RADAR_HTML; WORLD_RADAR_HTML=$(<"$temp_radar_file") diff --git a/site_generator/templates/css.template b/site_generator/templates/css.template index cc2624e..c322bb2 100755 --- a/site_generator/templates/css.template +++ b/site_generator/templates/css.template @@ -202,7 +202,7 @@ a.read-more-link { font-size: 0.9em; font-weight: bold; } .scroll-to-top-btn { display: none; position: fixed; bottom: 20px; right: 20px; z-index: 999; background-color: #555; color: #FFA500; border: 1px solid #666; border-radius: 50%; width: 40px; height: 40px; text-align: center; font-size: 24px; line-height: 38px; cursor: pointer; transition: background-color 0.3s, opacity 0.3s; } .scroll-to-top-btn:hover { background-color: #666; text-decoration: none; } .scroll-to-top-btn.show { display: block; } -/* Stile für OpenLayers Popups (Leaflet-Look-and-Feel) */ +/* Stile für OpenLayers Popups */ .ol-popup { position: absolute; background-color: #303030; box-shadow: 0 1px 4px rgba(0,0,0,0.4); padding: 1px; border-radius: 5px; bottom: 12px; left: -50px; min-width: 280px; border: 1px solid #555; color: #ddd; } .ol-popup:after, .ol-popup:before { top: 100%; border: solid transparent; content: " "; height: 0; width: 0; position: absolute; pointer-events: none; } .ol-popup:after { border-top-color: #303030; border-width: 10px; left: 48px; margin-left: -10px; } @@ -236,36 +236,33 @@ a.read-more-link { font-size: 0.9em; font-weight: bold; } .admin-box { flex-basis: 100%; } } -/* KORREKTUR: Stile für OpenLayers Layer Switcher */ - +/* Stile für OpenLayers Layer Switcher (VOM BENUTZER KORRIGIERT) */ .layer-switcher.shown { background-color: #303030 !important; } - .layer-switcher button { font-size: 1.2em !important; + width: 40px !important; + height: 40px !important; } - .layer-switcher button:hover, .layer-switcher button:focus { background-color: #666 !important; } - .layer-switcher .panel { background-color: #303030 !important; border: 1px solid #555 !important; color: #ddd !important; margin: 0; + padding: 5px 10px; } - .layer-switcher ul { padding-left: 1em; } - .layer-switcher label { color: #ddd !important; } -/* NEU: Styling für Checkboxen im Layer-Switcher */ +/* Styling für Checkboxen im Layer-Switcher */ .layer-switcher input[type=checkbox], .layer-switcher input[type=radio] { accent-color: #FFA500; @@ -273,7 +270,7 @@ a.read-more-link { font-size: 0.9em; font-weight: bold; } margin-right: 5px; } -/* NEU: Vergrößerung der Standard-Karten-Buttons */ +/* Vergrößerung der Standard-Karten-Buttons */ .ol-zoom .ol-zoom-in, .ol-zoom .ol-zoom-out, .ol-rotate .ol-rotate-reset, @@ -284,3 +281,17 @@ a.read-more-link { font-size: 0.9em; font-weight: bold; } line-height: 1; padding: 0; } + +/* Styling für die Koordinatenanzeige */ +.ol-mouse-position { + top: auto !important; + right: auto !important; + bottom: 8px !important; + left: 8px !important; +} +.custom-mouse-position { + color: #ffffff; + font-family: monospace; + font-size: 0.9em; + text-shadow: 1px 1px 2px #000, -1px -1px 2px #000, 1px -1px 2px #000, -1px 1px 2px #000; +} diff --git a/site_generator/templates/world_detail_radar.template b/site_generator/templates/world_detail_radar.template index 7e0bf97..0e5cddf 100644 --- a/site_generator/templates/world_detail_radar.template +++ b/site_generator/templates/world_detail_radar.template @@ -28,6 +28,7 @@ window.olMap_%%current_world_key%% = null; window.playerMarkerSource_%%current_world_key%% = new ol.source.Vector(); window.parentAreaLayerSource_%%current_world_key%% = new ol.source.Vector(); window.subAreaLayerSource_%%current_world_key%% = new ol.source.Vector(); +window.tpadMarkerSource_%%current_world_key%% = new ol.source.Vector(); window.mapData_%%current_world_key%% = {}; // Konvertiert Minetest-Koordinaten in OpenLayers-Pixel-Koordinaten @@ -41,6 +42,23 @@ function convertMinetestToOpenLayers_%%current_world_key%%(posX, posZ) { return [pixelX, pixelY]; } +// Konvertiert OpenLayers-Pixel-Koordinaten zurück in Minetest-Koordinaten +function convertOpenLayersToMinetest_%%current_world_key%%(coordinate) { + const mapData = window.mapData_%%current_world_key%%; + if (!mapData || !mapData.mapWidth || !coordinate) return ''; + + const pixelX = coordinate[0]; + const pixelY = coordinate[1]; + + const percentX = pixelX / mapData.mapWidth; + const percentZ = -pixelY / mapData.mapHeight; + + const posX = Math.round((percentX * mapData.extentWidth) + mapData.minX); + const posZ = Math.round((percentZ * mapData.extentHeight) + mapData.minZ); + + return `X: ${posX}, Z: ${posZ}`; +} + function createPolygonFromPos_%%current_world_key%%(pos1, pos2) { const p1 = convertMinetestToOpenLayers_%%current_world_key%%(pos1.x, pos1.z); const p2 = convertMinetestToOpenLayers_%%current_world_key%%(pos2.x, pos2.z); @@ -58,11 +76,13 @@ document.addEventListener('DOMContentLoaded', function() { const mapContainer = document.getElementById('ol-map-container-%%current_world_key%%'); const mapInfoPath = '/%%web_map_info_rel_path%%?v=' + new Date().getTime(); const areasPath = '/%%web_areas_json_rel_path%%?v=' + new Date().getTime(); + const tpadsPath = '/%%web_tpads_txt_rel_path%%?v=' + new Date().getTime(); Promise.all([ fetch(mapInfoPath).then(res => { if (!res.ok) throw new Error('map_info.txt'); return res.text(); }), - fetch(areasPath).then(res => { if (!res.ok) return {}; return res.json(); }) - ]).then(([mapInfoText, areaData]) => { + fetch(areasPath).then(res => { if (!res.ok) return {}; return res.json(); }), + fetch(tpadsPath).then(res => { if (!res.ok) return []; return res.json(); }) + ]).then(([mapInfoText, areaData, tpadData]) => { const mapInfo = (text => { const data = {}; @@ -123,15 +143,22 @@ document.addEventListener('DOMContentLoaded', function() { const parentAreaStyle = new ol.style.Style({ stroke: new ol.style.Stroke({ color: 'rgba(0, 100, 255, 0.8)', width: 2 }), fill: new ol.style.Fill({ color: 'rgba(0, 100, 255, 0.2)' }) }); const subAreaStyle = new ol.style.Style({ stroke: new ol.style.Stroke({ color: 'rgba(0, 100, 255, 0.8)', width: 1.5, lineDash: [6, 6] }), fill: new ol.style.Fill({ color: 'transparent' }) }); - + const tpadStyle = new ol.style.Style({ + image: new ol.style.Icon({ + anchor: [0.5, 1], anchorXUnits: 'fraction', anchorYUnits: 'fraction', + src: 'data:image/svg+xml;utf8,', + scale: 1.5 + }) + }); + const playerLayer = new ol.layer.Vector({ source: window.playerMarkerSource_%%current_world_key%%, style: f => f.get('style'), title: 'Spieler' }); - const parentAreaLayer = new ol.layer.Vector({ source: window.parentAreaLayerSource_%%current_world_key%%, style: parentAreaStyle, title: 'Grundstücke' }); - // KORREKTUR: Die 'title'-Eigenschaft wurde von diesem Layer entfernt + const tpadLayer = new ol.layer.Vector({ source: window.tpadMarkerSource_%%current_world_key%%, style: tpadStyle, title: 'Teleporter' }); + const parentAreaLayer = new ol.layer.Vector({ source: window.parentAreaLayerSource_%%current_world_key%%, style: parentAreaStyle, title: 'Grundstücke', visible: false }); const subAreaLayer = new ol.layer.Vector({ source: window.subAreaLayerSource_%%current_world_key%%, style: subAreaStyle, visible: false }); - const overlayLayers = new ol.layer.Group({ title: 'Overlays', layers: [subAreaLayer, parentAreaLayer, playerLayer] }); + const overlayLayers = new ol.layer.Group({ title: 'Overlays', layers: [subAreaLayer, parentAreaLayer, tpadLayer, playerLayer] }); - const view = new ol.View({ projection: projection, center: ol.extent.getCenter(extent), resolutions: viewResolutions }); + const view = new ol.View({ projection: projection, center: ol.extent.getCenter(extent), resolutions: viewResolutions, maxZoom: viewResolutions.length - 1 }); const popupContainer = document.getElementById('popup-%%current_world_key%%'); const popupContent = document.getElementById('popup-content-%%current_world_key%%'); @@ -139,7 +166,15 @@ document.addEventListener('DOMContentLoaded', function() { const overlay = new ol.Overlay({ element: popupContainer, autoPan: { animation: { duration: 250 } } }); popupCloser.onclick = () => { overlay.setPosition(undefined); popupCloser.blur(); return false; }; - const mapControls = [ new ol.control.Zoom(), new ol.control.Rotate(), new ol.control.Attribution({ collapsible: false }), new ol.control.FullScreen(), new ol.control.LayerSwitcher() ]; + const mousePositionControl = new ol.control.MousePosition({ + className: 'custom-mouse-position', + coordinateFormat: function(coordinate) { + return convertOpenLayersToMinetest_%%current_world_key%%(coordinate); + }, + undefinedHTML: ' ' + }); + + const mapControls = [ new ol.control.Zoom(), new ol.control.Rotate(), new ol.control.Attribution({ collapsible: false }), new ol.control.FullScreen(), new ol.control.LayerSwitcher(), mousePositionControl ]; window.olMap_%%current_world_key%% = new ol.Map({ controls: mapControls, @@ -160,6 +195,14 @@ document.addEventListener('DOMContentLoaded', function() { window.parentAreaLayerSource_%%current_world_key%%.addFeature(feature); } } + + tpadData.forEach(tpad => { + const coords = convertMinetestToOpenLayers_%%current_world_key%%(tpad.posX, tpad.posZ); + if (coords) { + const feature = new ol.Feature({ geometry: new ol.geom.Point(coords), tpadData: tpad }); + window.tpadMarkerSource_%%current_world_key%%.addFeature(feature); + } + }); map.on('click', function(evt) { overlay.setPosition(undefined); @@ -173,17 +216,16 @@ document.addEventListener('DOMContentLoaded', function() { if (playerData) { const statusDotClass = playerFeature.get('statusDotClass'); const lastLoginFormatted = playerFeature.get('lastLoginFormatted'); + // KORREKTUR: Layout des Spieler-Popups const popupHTML = `