# ScopedVR Map Editor Standalone-PC-App zum Bauen von ScopedVR-Maps. Technisches Fundament: Godot 4.x (MIT-Lizenz, lizenzfrei, keine Fremd-Abhängigkeit). Creator sehen/brauchen Godot NIE — die App ist das Produkt (PLAN.md, Entscheidung 14). ## ⭐ Chef-Grundsatz (Sly, 15.10.): MAXIMALE NUTZERFREUNDLICHKEIT > „Der soll auf jeden Fall so nutzerfreundlich sein, wie es nur geht, damit > echt richtig easy ist Maps zu bauen und es auch Spaß macht!" Konkret heißt das für JEDE Editor-Karte: - Deutsch, große Buttons, Klartext-Beschriftungen — kein Fachchinesisch. - Klick statt Konsole: gewünschte Aktion per Maus erreichbar (ziehen, drehen, klicken), ohne Tastenkürzel auswendig zu lernen (Kürzel dürfen optional sein). - Sofortiges visuelles Feedback (Objekt leuchtet beim Anfassen, Vorschau vor dem Platzieren, Undo mit STRG+Z). - Die App hilft: ungültige Aktionen erklären WARUM („Spawn-Zone fehlt noch für Team Rot — klicke auf den Boden, um sie zu setzen"). - Test-Benchmark: Sly baut ohne Anleitung in < 10 Minuten eine kleine Map. ## Philosophie (Entscheidung 20 — GESCHLOSSENER Baukasten) - Objekte kommen ausschließlich aus der Spiel-Asset-Bibliothek (geprüfte Poly-Budgets). - KEINE freien Mesh-Imports. Konsistenz + Performance statt unbegrenzter Freiheit. - Performance-Prüfung ist eingebaut (Objekt-Count-/Poly-Limits), nicht optional. ## MVP-Werkzeuge (Reihenfolge = Karten-Kette) 1. **Terrain** — Höhenfeld bearbeiten (heben/senken/glätten), Sniper-Distanzen 100–800 m (Entscheidung 7). 2. **Objekt-Platzierung** — Bibliothek-Browser, platzieren/drehen/verschieben. 3. **Spawn-Zonen** — pro Team (TDM), Validierung gegen Regeln. 4. **Map-Metadaten** — Name, Autor, Version, Wetter-Preset (mittag/abend/regen/nacht, siehe Weather-System 9ebe8ef/a296986). 5. **Performance-Check** — Objekt-Count/Poly-Budget gegen die FPS-Baseline. 6. **Export** — `.svmap`-Paket (Format: docs/map_format.md im scopedvr-match-server Repo, Karte t_74976e9f). ## Architektur (MVP) - Godot 4.x Desktop-App (die Editor-UI IST Godot-Control-UI — pragmatisches MVP). - Map-Datenmodell = 1:1 das svmap-Format (kein internes Zwischenformat → kein Konverter). - Speichern/Laden direkt auf .svmap; Export = Kopie + Validierung. ## Milestone-Zuordnung M2 (siehe PLAN.md §6): Map-Paket-Format → Editor-MVP → erste offizielle Map (offenes Gelände) → Map-Repo/Release-Workflow über Forgejo (M3). ## Status (M2, Karte t_40d855d0 — UX-Fundament FERTIG) UX-Fundament auf dem App-Skelett (t_5badf371), nach dem Chef-Grundsatz gebaut: *(Unverändert darunter: svmap laden/speichern V1–V14 mit Prüfsummen-Interop, Neue-Map-Dialog mit 4 Pflicht-Spawns pro Team, Orbit-Viewport mit Gitter/ Boden/Wetter-Stimmung — siehe Commit 84bc081 und `svmap_io.gd`.)* - **Undo/Redo (`src/editor/action_history.gd`):** zentrale ActionHistory über die svmap-Ober-Blöcke (`objects`/`terrain`/`spawn_zones` — tiefe Kopien vor und nach jeder Änderung, merge_tags gegen Mausrad-Tick-Fluten, Max-Stufe 100). Strg+Z / Strg+Y UND große Buttons „↩ Rückgängig / ↪ Wiederholen" oben. Spätere Werkzeuge melden sich mit `snapshot(keys)` vor und `commit(desc, before, after)` nach der Änderung an — Terrain-Strokes und Spawn-Zonen landen damit automatisch in derselben History. - **Objekt-Platzierung mit Ghost-Preview (`src/editor/interaction.gd`):** Bibliothek links (deutsche Namen + Poly-Zahl), Klick startet den Platzier-Modus — eine transparente Vorschau schwebt am Cursor auf dem Boden (Höhe kommt aus dem Terrain), Klick setzt, Rechtsklick/ESC bricht ab, Mausrad dreht die Vorschau VOR dem Setzen (15°-Raster). Modus bleibt an für schnelles Mehrfachsetzen. Poly-Budget wird VOR dem Platzieren geprüft. - **Auswahl-Anfassen:** Klick wählt ein Objekt (orange + Emission), Ziehen verschiebt es (auf Terrain-Höhe geclampt in der Map), R-Taste ODER Mausrad dreht (15°-Raster, Shift+R zurück), Entf löscht. Auch über den Objekt-Baum wählbar (beide Wege bleiben synchron). Panel „Auswahl“ rechts zeigt Position/ Richtung + Bedienhinweise. - **Helfende Meldungen:** Statusleiste unten erklärt nach jeder Aktion den NÄCHSTEN Schritt („Klicke in die Karte“, „Strg+Z holt es zurück“, Budget-Warnung ab 80 %). Fehler-Dialoge bleiben Klartext, keine Godot-Texte im sichtbaren UI. - **Deutsche, große UI:** Schrift 16 px Basis (≥ 14 px überall), Buttons/ Klickflächen ≥ 40 px Höhe, Mausrad-Konflikt gelöst: Rad dreht Objekt/ Vorschau, wenn eines aktiv ist — sonst zoomt es die Kamera. - **Tests:** `tests/test_ux.gd` (History-Roundtrips setzen/löschen/verschieben/ drehen, Merge-Tag-Verhalten, Alias-Sicherheit der Snapshots, Kapazität, Terrain-Höhen-Abfrage, Platzhalter-Meshes). Lauf: `godot --headless --path . --script res://tests/test_ux.gd` **Bekannte Falle (15.10. live passiert):** Nach `git pull` mit NEUEN `class_name`-Skripten (z. B. `action_history.gd`) muss einmal `godot --headless --import` laufen, bevor die GUI gestartet wird — sonst ist der globale Klassen-Cache (`.godot/`) alt, `main.gd` wirft „Identifier not declared" und das Fenster startet ohne UI. Symptom: Parse-Errors im App-Log trotz grünem Test-Lauf (der ja selbst mit importiertem Cache lief). **Bibliothek:** `library/objects.json` ist die Editor-Kopie der offiziellen Registry aus dem Match-Server-Repo — neue Objekte DORT registrieren und hier synchron ziehen (IDs sind der Vertrag, Entscheidung 20). ## Status (M2, Karte t_3a998ae4 — Objekt-Bibliothek FERTIG) Auf dem Terrain-Werkzeug (t_9aba04f1) aufgebaut, nach dem Chef-Grundsatz: - **Bibliothek-Browser mit Gruppen (`src/editor/library_browser.gd`):** Die 11 etablierten Objekte aus `library/objects.json`, sortiert in deutsche Klapp-Gruppen (Kisten & Barrieren / Bauwerke / Natur + automatisch „Sonstiges" für neue, noch ungruppierte IDs). Jeder Button zeigt ein 128-px-Thumbnail (`library/thumbs/*.png` — einmalig mit `xvfb-run -a godot4 --rendering-driver opengl3 --path . --script res://tools/gen_thumbs.gd` gerendert und committed; fehlt ein PNG, fällt der Button sauber aufs Text-Layout zurück). Deutsche Namen wohnen jetzt in `LibraryBrowser` (ohne UI → headless testbar). - **Snap to Ground (`src/editor/object_ops.gd`):** Ein Klick auf „⚡ Alles auf den Boden setzen" holt ALLE schwebenden Objekte auf die Terrain-Höhe (z. B. nach dem Terrain-Formen) — EIN Undo-Eintrag für die ganze Aktion. Objekte, die schon auf dem Boden stehen, bleiben unangetastet. - **Raster-Snap (1 m):** CheckButton in den Objekt-Werkzeugen — beim Platzieren UND Ziehen rasten X/Z auf ganze Meter (Höhe folgt weiter dem Terrain). AUS = freies Platzieren wie bisher. - **svmap-Roundtrip:** Objekte (Bibliotheks-ID + Pos/Rot/Scale) überleben Speichern/Laden identisch, save→load→save bleibt byte-identisch (`tests/test_library.gd`). - **Tests:** `tests/test_library.gd` (Bibliothek laden, Gruppen komplett/ überschneidungsfrei, Thumbnails 128×128, Raster-Snap, Snap-to-Ground + je Undo für setzen/drehen/verschieben/löschen über ALLE 11 Objekte, svmap-Roundtrip mit Objekten + Poly-Budget aus dem Katalog). - **Desktop-Smoke:** `godot … -- --library-demo [ordner] [--library-demo-quit]` fährt Bibliothek/Platzierung/Schweben/Snap programmatisch durch und speichert Screenshots. **Noch offen (folgende Karten der MVP-Kette):** Performance-Check-UI, Export-Workflow. ## Status (M2, Karte t_c4162c5d — Spawn-Zonen FERTIG) Auf der Objekt-Bibliothek (t_3a998ae4) aufgebaut, nach dem Chef-Grundsatz: - **Spawn-Zonen malen (`src/editor/spawn_tool.gd`):** Werkzeug „🚩 Spawn-Zonen malen“ — Team Blau 🔵 / Team Rot 🔴 (TDM-Konvention: IDs A…/B…, mapformat § spawn_zones), Klick setzt eine farbige flache Kreis-Zone auf dem Terrain (Vorschau-Kreis folgt der Maus), Radius 2–30 m per Regler. Zone anklicken → auswählen + ziehen (Terrain-Höhe bleibt), Entf löscht, Strg+Z nimmt JEDE Operation zurück (jede Zone = EIN History-Eintrag, Radius-Slider-Ticks sind merge-gekoppelt). - **Live-Validierung (`src/editor/spawn_ops.gd`):** Block „Spawn-Check“ rechts bleibt STÄNDIG sichtbar und spiegelt exakt die Loader-Regeln (V11: ≥ 4 Spawn-Punkte pro Team · V7: Objekt-IDs in der Bibliothek) — z. B. „✅ Spawns Team Blau: 4 · ❌ Spawns Team Rot: 2 (mindestens 4 nötig)“ + Klartext-Hinweis, WIE die Zone ergänzt wird. Fehler zeigt der Editor VOR dem Export, nicht erst beim Speichern. - **Map-Fertig-Check:** Button „✅ Karte prüfen“ oben — Klartext-Liste ✅/❌ (Name, Autor, beide Teams, Objekt-IDs, Poly-Budget) in einem Fenster; fehlt etwas, wackelt (Shake-Tween) der Button und die Statusleiste sagt „Map ist noch nicht bereit — siehe Warnungen“. Der harte Gate bleibt das Speichern (`SvmapIO.save_to_file` — dieselbe `_validate_core`-Funktion, EINE Implementierung, kein Drift). - **Export-Signierung:** unverändert der eine Code-Pfad — Editor-Speichern ruft `SvmapIO.sign_map` (SHA-256 über kanonisierte Payload). Abnahme mit ECHTEM Server-Loader: Editor-Export durch `SvmapLoader.parse_and_validate` aus scopedvr-match-server gejagt → ok=true inkl. V13-Prüfsummen-Check (kein Copy-Paste-Drift, Interop bewiesen). - **Radius-Persistenz:** Der Zonen-Radius ist KEIN Formatfeld (spawn_zones speichert Punkte) — er wohnt als `design_notes.spawn_radius_m` in der Map (Loader prüft design_notes nicht → rundtrip-sicher). Zonen sitzen AUF dem Terrain (`terrain_height_at`), egal wie hügelig die Map ist. - **Tests:** `tests/test_spawns.gd` (52 Checks: setzen/ändern/löschen + je Undo/Redo mit Radius, Merge-Tags, Live-Status ✅/❌, ready_report grün/rot, Export→Re-Import identisch + byte-identischer Roundtrip, Zone auf Terrain-Höhe). Parse-Check: 23 Scripts, 0 Fehler. - **Desktop-Smoke:** `godot … -- --spawns-demo [ordner] [--spawns-demo-quit]` fährt Zonen-Übersicht → Live-Check-Alarm → Undo → „Karte prüfen“ programmatisch durch und speichert Screenshots.