Beim Start des Test-Modus versteckt der Editor die Panels — Godot
klappt dabei die Splitter zusammen (Lage springt z. B. [-320,0] →
[160]), beim Wiedereinblenden baut er die Trenner mit Defaults wieder
auf → die fein gezogenen Seitenbereiche waren weg („riesen groß").
Fix in main.gd (besitzt die UI, überlebt den Playtest-Node): beim
Start alle split_offsets von MainSplit/BottomSplit sichern, im
Exit-Handler deferred UND im nächsten Frame zurücksetzen (das Layout
muss die Panels erst neu vermessen haben). Suite test_playtest 52/52
(mit Splitter-Regression: merken → verbiegen → Exit → unverändert),
test_ui_layout 79, test_gui_smoke 92 grün.
Bug: Die Laufrichtung kam aus transform.basis des Körperknotens — die
Kamera-Drehung steckt aber im look_cam-Kindknoten, der Körper rotiert
nicht → WASD lief stur in eine Himmelsrichtung. Auf der Quest rotiert
der ganze Origin mit dem Kopf, dort trat der Bug nicht auf.
Fix: forward/right aus yaw_deg bauen (identisch zu view_direction(),
identisch zum Kopf-Yaw des Clients). Regression in test_playtest:
yaw 0° + W → -Z, yaw 90° + W → -X. Suite 39/39 grün.
Sly-Befund 20.10.: Im Editor-Testmodus hing man an unsichtbaren Wänden weit
VOR den Gebäuden. Ursache: _collect_obstacles nutzte die Viewport-Metas
pick_radius (Kugel-Näherung = volle Raumdiagonale + Zuschlag) — bei der
Kaserne (17×35 m) blockte das ~40×40 m. Die Trimesh-Fixes aus t_9558038d
wirken nur im Spiel-Client, der Editor-Playtest baut seine Blockierung
selbst (keine Physik-Welt, nur AABBs).
Fix: Hindernis-AABB aus der Registry (collision.size × scale, um rot_y_deg
konservativ gedreht, Y vom Fußpunkt bis Fußpunkt + Höhe — gleiche
Konvention wie der Client-Kollider). Fallback: Kugel-Näherung bleibt für
Objekte ohne Registry-Eintrag.
Regression in test_playtest.gd: gedreht/ungedreht, Scale, Fallback
(20 checks, alle grün). Suiten: playtest_comfort 51, playtest_spawn 56,
resize_dialog 44, terrain 153 — ALL OK.
Befund: der Check funktionierte die ganze Zeit — die Rückmeldung kam aber
NUR in der Statuszeile („Du bist auf dem neusten Stand (…).“) und verblasst
dort schnell → las sich wie „tut nichts“. Probe (echter Menü-Klick): Check
läuft, ls-remote ok, Status korrekt.
Fix: nach dem MANUELLEN Check (report=true) öffnet ein kleines AcceptDialog
„Update-Check“ mit Klartext-Ergebnis (Stil wie Map-Check-Dialog):
- up_to_date: „Du bist auf dem neusten Stand (<sha>).“
- update_available: Zusätzlich zum Banner das Fenster mit local → remote
und Hinweis auf „Jetzt updaten“.
- unreachable / auth_failed / error: gleicher Klartext wie Statuszeile.
Der Still-Start-Check (report=false) zeigt bewusst KEIN Fenster (nur Banner
bei „Update verfügbar“) — Probe belegt: Popup sichtbar=false.
Probe: probe_update_check (echter Menü-Klick → Popup sichtbar + Text).
Suiten: test_updater 75 OK, test_resize_dialog 44 OK, test_theme 35 OK,
test_gui_smoke 92 OK, test_ux 137 OK, test_ui_layout 79 OK.
Ursache (Proben im Container, xvfb): autowrap-Labels OHNE Mindestbreite
melden VOR dem ersten Layout eine explosionsartige Mindesthöhe (Wrap bei
~1 px → jedes Wort eine Zeile). popup_centered() übernimmt genau diesen
Wert als Fensterhöhe: Resize-Dialog 5930 px statt ~470, Neue-Map-Dialog
4781 px statt ~390 — beide waren betroffen. Nach dem Layout fällt der
Mindestwert zurück, die Fenstergröße bleibt aber.
Zusatz-Befund: wächst die Live-Vorschau NACH dem Öffnen (Preset 256 →
Warnband), bleibt das Fenster oben hängen → Buttons bei y≈940 in einem
900-px-Sichtbereich = unerreichbar.
Fix:
- resize_map_dialog + new_map_dialog: autowrap-Labels bekommen
Mindestbreite ~ Dialogbreite → Umbruch rechnet mit echter Breite,
Fenster normal hoch (Probe: 481 px).
- resize_map_dialog: Inhalt in ScrollContainer (horizontal aus), Höhe
dynamisch = min(Inhalt, sichtbarer Platz); nach jeder Vorschau-Änderung
wird das Fenster gedeckelt und neu zentriert (_fit_dialog/
_fit_after_layout) → OK/Abbrechen IMMER erreichbar. unresizable.
- tests: test_resize_dialog prüft jetzt Mindesthöhe VOR dem Popup
(absolut, < 1500 px) für beide Dialoge + echten Menü-Klick;
Preset-Button-Suche robust über find_children.
Proben (xvfb): Dialog 662×481, nach Preset 256 → 662×631, unten 765 < 900,
Buttons sichtbar (Beweisbild work/dialog_beweis/resize_dialog_fix.png).
Suiten: test_resize_dialog 44 OK, test_theme 35 OK, test_gui_smoke 92 OK,
test_ux 137 OK, test_ui_layout 79 OK.
popup.id_pressed.connect(main.call.bind("_on_menu_action")) rief effektiv
call(6, "_on_menu_action") → „Cannot convert argument 1 from int to
StringName“ (map-builder.log 20.10., 2 Treffer) — KEIN Menü-Eintrag tat
etwas (Neue Map/Öffnen/Speichern/Kartengröße/Updates). Alle anderen
.call.bind-Stellen hängen an arg-losen Signalen (pressed/timeout) und
waren unbeeinträchtigt. Fix: Lambda mit expliziter Reihenfolge
(Stil wie grid_btn/contours_btn). Regression: test_resize_dialog stellt
jetzt den echten Klick nach (id_pressed.emit(6) am Datei-Popup) — vorher
rief die Suite _open_resize_dialog() direkt auf und sah den Bruch nicht.
Suiten: test_resize_dialog 42 OK, test_theme 35 OK, test_gui_smoke 92 OK, test_ux 137 OK.
Neu shaders/selection_outline.gdshader: Inverted-Hull-Außenhülle (unshaded,
cull_front, Grow entlang der Normalen; Streifen-Uniform für den Zwilling).
Markierung jetzt über Outline-Kind am Mesh (Auswahl/Hover/Partner); Farben +
Breiten aus theme/editor_theme.tres (selection_outline*, *_width_mm) — eine
Quelle. material_override wird von der Markierung nicht mehr angefasst:
GLB-Texturen bleiben im Auswahl-Zustand voll sichtbar, der Tint bleibt beim
Markieren sichtbar (kein "Orange gewinnt" mehr).
Spawn-Zonen: konstante Disc-Deckkraft + dezenter Kontur-Ring (Torus) statt
Aufhellung/Emission; Label-Farbe aus dem Theme statt hartkodiertem Gelb.
Bau-Teile: Kontur um das Bauteil-Mesh statt halbtransparenter Vollbox.
Neu: set_hover()-API (schwächste Stufe) — Anschluss an die Mausbewegung
liegt in interaction.gd (Grenze dieser Karte) und folgt als eigene Karte.
Suite tests/test_selection_look.gd (41 checks: Theme-Quelle, Grundmaterial
unangetastet, Outline nur bei Markierung, restlos weg bei Abwahl, Zwilling
dünner+gestrichelt, Spawn-Ring, Bau-Teil-Kontur). Altsuiten an die neue
Semantik angepasst (test_glb_view: GLB-Auswahl ohne Override; test_map_tint
T3: Kontur statt Orange-gewinnt; test_object_mirror: Partner per Kontur).
Beweise: 4 Renderproben (fass, echtes GLB — vorher Vollorange / nachher
Kontur, je auf Sand und Fels) in /opt/data/scopedvr/work/u6_auswahl_beweise/.
Voll-Batterie 32/32 grün (EXIT 0) inkl. der drei angepassten Suiten.
Operator-Befund aus dem Eigenstaendigkeits-Beweis auf dem PC (20.10.):
Die App baute den Registry-Pfad nur als <quelle>/<rel-pfad-mit-Praefix
'assets/objekte/'>. Der mitgelieferte models/-Ordner NEBEN der App enthaelt die
Pack-Struktur aber DIREKT (models/military_desert/props/box_010.glb). Ergebnis:
291 von 334 Modellen (alle verschachtelten Pack-Objekte — genau die, mit denen
die Karten gebaut werden) wurden in der eigenstaendigen App nicht gefunden.
Fix: zusaetzlicher Kandidat <quelle>/<rel-pfad OHNE 'assets/objekte/'> — der
flache Alt-Pfad bleibt unveraendert.
Belegt (exportierte App, nacktes Umfeld, frisches HOME):
box_010 -> models/military_desert/props/box_010.glb (vorher: leer)
baum_kiefer_1 -> models/baum_kiefer_1.glb
fehlende_glbs=0 PROBE ERGEBNIS: OK
Suiten: gui_smoke 92 OK, Import 0 Fehler.
Damit lassen sich auch VERSCHACHTELTE Pack-Modelle pruefen
(models/military_desert/<kategorie>/<oid>.glb) — noetig, weil der erste
Eigenstaendigkeits-Beweis nur flache Modelle abdeckte.
Operator-Befund auf dem PC (20.10.): die Original-Texturen liegen NICHT im
Client-Klon, sondern in einem eigenen Pack-Ordner:
~/godot-projects/ithappy_pack_ref/ithappy/military_desert/textures/
Deshalb sucht das Skript jetzt zusaetzlich dort (<clone>/../ithappy_pack_ref/...)
und als letzte Instanz per find -maxdepth 6 unter <clone>/.. und <client>/..
(also neben dem Projekt). Belegt mit einem nachgebauten PC-Aufbau: Palette wird
gefunden, landet FLACH in models/textures/, --check danach Exit 0.
Operator-Nachbesserung nach dem Eigenstaendigkeits-Beweis (exportierte App,
kein Client/Godot im Dateisystem):
- SRC_TEX wird GESUCHT statt fest verdrahtet: SCOPEDVR_TEX_DIR ->
assets/textures/military_desert -> assets/textures -> Ordner der
Demonstration_Textures*.png unter assets/. Findet er nichts, gibt es einen
HINWEIS samt Loesung (SCOPEDVR_TEX_DIR=/pfad).
- Texturen werden FLACH nach models/textures/<name>.png gespiegelt — die App
sucht sie dort; im Client liegen sie verschachtelt.
- Modell-Spiegel schliesst den Unterordner textures/ aus (skip_top): vorher
galt er als 'ueberfluessig' und wurde bei JEDEM Lauf geloescht, der
Textur-Spiegel legte ihn neu an -> Endlosschleife, --check nie sauber.
Belegt: 2. Lauf 0 Aenderungen, --check Exit 0; exportierte App findet
baum_kiefer_1/stein_mittel_1 aus models/, fehlende_glbs=0, ERGEBNIS: OK.
Sly-Befund: der Knopf 'Test-Start' fehlte; tests/test_playtest_spawn.gd brach
mit "Nonexistent function '_test_start_reload'" ab und hing.
- Werkzeug-Modus 'teststart' wieder in _set_tool_mode (+ enter/leave/sync)
- ShortcutPolicy.esc_action: exit_teststart inkl. Test
- Taste T: Editor = Werkzeug umschalten, Lauf-Modus = Punkt setzen + Teleport
aufs Fadenkreuz (playtest.teleport_crosshair)
- Entf im Werkzeug loescht den Punkt; Klartext-Hinweis des Werkzeugs wieder in
der Statuszeile ('auf dem Boden unter dem Objekt')
- Leisten-Knopf '🎯 Test-Start' als Umschalter (registry.gd ACTIONS)
- neues Panel-Modul src/ui/panels/test_start_panel.gd + Registry-Eintrag
- Haken _test_start_apply/_delete/_reload + test_start_point/test_start_panel/
test_start_btn stehen fest auf main (Vertrag der Pruefsuite)
- _test_start_reload() wieder nach Neu/Laden/Speichern; playtest.enter() bekommt
den aufgeloesten Startpunkt (TestStart.resolve_start)
Belegt: test_playtest_spawn 56/56, test_shortcuts 204, gui_smoke 92, ui_layout 71,
Import 0 Fehler.
fit_to_document setzt die Ansicht jetzt auf START_DISTANCE_M = 80 m über der
Kartenmitte (XZ-Mitte der Map-Bounds, Höhe = Gelände dort), yaw 45°, pitch 35°.
Die Regel ist unabhängig von Kartengröße (256/1024/4096) und Inhaltslage;
leeres Dokument ebenfalls 80 m. Statuszeile: „Ansicht: Kartenmitte, Abstand
80 m (Pos1 = ganze Karte).“ Pos1/Home bleibt fit_to_bounds = ganze Karte
(MAP-Bounds werden weiterhin gemerkt, nicht die Content-Bounds).
Ziel-Y bewusst auf der Geländehöhe: die y-Mitte der Bounds liegt bei neuen
Maps 35 m über dem Boden — damit hätte die Ansicht über den Boden gezielt und
die Objekte stünden am unteren Bildrand.
Suite test_orbit_camera auf die neue Regel umgestellt (50 Checks):
Startabstand/Richtung, 80-m-Regel über Größen und Inhaltslagen, leeres
Dokument, „Pos1 ≠ Startansicht“ (80 m → 1215,6 m, alle 8 Map-Ecken).
Dazu Renderprobe tests/probe_k1d_render.gd (2 PNGs).
- BuildOps.place_mirrored / update_mirrored / remove_mirrored /
inside_match_bounds: pure Statics in build_ops.gd, sym-Kopplung aus M1,
gleiche Snap-Regeln (Paritaet bleibt), tiefe Kopien (kein Aliasing).
- V9-Grenzen scharf: laege der Zwilling ausserhalb der Match-Grenzen
(Loader-Regel _inside_bounds ±1 m), wird er NICHT gespeichert und der
Status meldet V9 im Klartext — auch kein halber sym-Link.
- SpawnTool-Spiegelung im GEGNER-Team (Blau West <-> Rot Ost = faire
Gegenstelle, Radius 1:1), Partner-Map in design_notes.spawn_mirror
(Loader-frei, rundtrip-sicher). Auf der Mitte: nicht gedoppelt.
- build_tool.gd: duenne Hooks an den 6 Klick-Mutationen + demo_place —
EIN Undo-Schritt nimmt Original UND Zwilling zurueck.
- spawn_tool.gd: Hooks in setzen/verschieben/loeschen/demo_place/demo_move;
_sym_mode() defensiv ueber main.get() (Mock-Mains ohne sym_mode -> OFF,
statt SCRIPT ERROR — Lektion aus test_shortcuts).
- Neue Suite tests/test_build_spawn_mirror.gd (76 Checks ALL OK) +
Probe tests/probe_m4_mirror_render.gd (2 Beweis-Bilder).
- Regression: 19/20 Suiten gruen; test_glb_view 15/25 FAIL pre-existing
(per git-stash gegen 437f6bf verifiziert, Ursache unabhaengig vom Diff).
git_run mischt stdout+stderr; bei der HTTP-Umleitung der Forgejo-URL schreibt
git zuerst 'warning: Umleitung nach ...'. Die alte Fassung nahm die ERSTE
Zeile und hielt 'warning' fuer den Remote-SHA -> Banner 'Update verfuegbar:
<sha> -> warning' blieb fuer immer, obwohl der Klon auf origin/main stand
(live auf dem PC belegt: STDOUT korrekt, STDERR Warnung).
Jetzt: sha_aus_ls_remote() liest nur echte '<sha>\t<refs/heads/...>'-Zeilen
(Warnungen/hints/fatal uebersprungen, SHA muss Hex sein), Notnagel = erste
hex-artige Zeile; 'kein Commit in der Ausgabe' gilt als unreachable statt
update_available. Regressionstest: 6 neue Checks in test_updater.gd.
aa94bde hat im Live-Pfad die alten Camo-Dateien (desert_multicam_*) verwendet und
zusaetzlich per Inhaltsvergleich auch KORREKTE Texturen wieder durch Camo ersetzt
- das haette die Palette-Arbeit aus t_279df760 im Editor rueckgaengig gemacht.
Jetzt: Zuordnung Materialname -> Pack-Textur (military_base -> Demonstration_Textures1.png,
picture_1/2/3 -> Demonstration_picture_N.png), Pfad ../../../textures/military_desert/
(Client-Repo, dort liegen die Dateien seit 88fded1). Fuer den Inhalt gibt es EINE Quelle:
tools/PACK_TEXTURE_MAPPING.md. Fuer den Inhalt gibt es EINE Quelle: dieselbe Tabelle.
Flaechen mit bereits aufgeloester Textur bleiben unangetastet.
- _camo_tex_setzen -> Pack-Zuordnung je MATERIALNAME (PACK_TEXTURE_MAPPING.md
im Client = Quelle der Wahrheit): military_base -> Demonstration_Textures1,
picture_1/_2 -> Demonstration_picture_1/_2; je Surface ihre Textur
- Thumbs: alle 345 Bibliotheksobjekte neu (Palette-Objekte zeigen Pack-
Farbfelder, Multicam-Objekte echtes Multicam statt der alten Camo-Box-Projektion)
- Beweis-Thumbs: barrier_001 (weiss/rot wie Pack), cactus_001 (Pack-Gruen
27,94,32 per UV-Sampling belegt), tent_001 (Palette + Multicam-Flaechen),
apc_002 (Sand/Multicam)