213 lines
8.7 KiB
GDScript
213 lines
8.7 KiB
GDScript
extends SceneTree
|
|
## Editor-Test (headless): Karte t_f72913d4 — Atmosphäre & Skybox.
|
|
## Ausführen: godot --headless --path . --script res://tests/test_skybox.gd
|
|
## Exit 0 = alles grün.
|
|
##
|
|
## T1 svmap-Validierung (V17): weather_sky optional; "sky_panorama"/
|
|
## "prozedural" gültig, Quatsch/nicht-String → V17-Fehler; alte Karte
|
|
## ohne Feld validiert unverändert.
|
|
## T2 Map-Panel „Himmel“: doc-Roundtrip (schreiben = sky_panorama,
|
|
## „Standard“ = Feld ENTFERNEN, Auffüllen aus dem doc).
|
|
## T3 Editor-Vorschau (map_view_builder): weather_sky=sky_panorama →
|
|
## PanoramaSkyMaterial aus dem Client-Nachbar-Klon + ACES-Tonemap +
|
|
## Fog am Skybox-Horizont; ohne Feld → ProceduralSky (alte Maps
|
|
## unverändert).
|
|
|
|
var failures := 0
|
|
var checks := 0
|
|
var main
|
|
var map_panel
|
|
|
|
|
|
func _initialize() -> void:
|
|
_run_all.call_deferred()
|
|
|
|
|
|
func _check(cond: bool, label: String) -> void:
|
|
checks += 1
|
|
print("%s: %s" % ["ok " if cond else "FAIL", label])
|
|
if not cond:
|
|
failures += 1
|
|
|
|
|
|
func _run_all() -> void:
|
|
var scene: PackedScene = load("res://core/scenes/main.tscn")
|
|
_check(scene != null, "scenes/main.tscn laedt")
|
|
if scene == null:
|
|
_finish()
|
|
return
|
|
main = scene.instantiate()
|
|
root.add_child(main)
|
|
await process_frame
|
|
await process_frame
|
|
|
|
map_panel = main.get("map_mod")
|
|
_check(map_panel != null, "Map-Panel ist in main eingebaut")
|
|
if map_panel == null:
|
|
_finish()
|
|
return
|
|
|
|
await _t1_validierung()
|
|
await _t2_panel()
|
|
await _t3_vorschau()
|
|
await _t4_auswahl_undo()
|
|
_finish()
|
|
|
|
|
|
func _t1_validierung() -> void:
|
|
print("== T1: svmap-Validierung weather_sky ==")
|
|
# Alte Karte ohne Feld: unverändert gültig.
|
|
var alte: Dictionary = main.doc.duplicate(true)
|
|
alte.erase("weather_sky")
|
|
SvmapIO.sign_map(alte)
|
|
var f0: PackedStringArray = SvmapIO.validate_map(alte)
|
|
_check(f0.is_empty(), "T1 Karte ohne weather_sky validiert ohne Fehler (%s)" % str(f0))
|
|
# Gültige Werte (mit frischer Prüfsumme — Feld fließt in die Payload).
|
|
for wert in ["sky_panorama", "prozedural", "sky_03", "sky_115"]:
|
|
var d: Dictionary = main.doc.duplicate(true)
|
|
d["weather_sky"] = wert
|
|
SvmapIO.sign_map(d)
|
|
var f: PackedStringArray = SvmapIO.validate_map(d)
|
|
_check(f.is_empty(), "T1 weather_sky='%s' validiert (%s)" % [wert, str(f)])
|
|
# Ungültige Werte → V17 (_validate_core ohne Prüfsumme, wie test_symmetry_core).
|
|
for wert in ["panorama", "sky_999", 42]:
|
|
var d2: Dictionary = main.doc.duplicate(true)
|
|
d2["weather_sky"] = wert
|
|
var f2: PackedStringArray = SvmapIO._validate_core(d2)
|
|
var hat_v17 := false
|
|
for e in f2:
|
|
if str(e).begins_with("V17"):
|
|
hat_v17 = true
|
|
_check(hat_v17, "T1 weather_sky=%s → V17-Fehler (%s)" % [str(wert), str(f2)])
|
|
|
|
|
|
func _t2_panel() -> void:
|
|
print("== T2: Map-Panel Himmel-Option ==")
|
|
var prop_sky: OptionButton = map_panel.get("prop_sky")
|
|
_check(prop_sky != null, "T2 prop_sky existiert")
|
|
if prop_sky == null:
|
|
return
|
|
_check(prop_sky.item_count == 1 + SkyboxKatalog.EINTRAEGE.size(),
|
|
"T2 Himmel-Optionen: Standard + %d Katalog-Einträge (ist %d)" % [SkyboxKatalog.EINTRAEGE.size(), prop_sky.item_count])
|
|
_check(prop_sky.item_count == 15, "T2 15 Einträge (Standard, Wüste, 13 neue)")
|
|
_check(str(prop_sky.get_item_text(1)).contains("Wüste"),
|
|
"T2 Eintrag 2 = Wüste (ist „%s“)" % str(prop_sky.get_item_text(1)))
|
|
# doc mit Panorama → UI zeigt Pack-Skybox.
|
|
main.doc["weather_sky"] = "sky_panorama"
|
|
map_panel.call("refresh_values")
|
|
_check(prop_sky.selected == 1, "T2 doc=sky_panorama → UI Pack-Skybox (ist %d)" % prop_sky.selected)
|
|
# „Prozedural (Standard)“ → Feld ENTFERNEN (kein "prozedural"-Wert im doc).
|
|
map_panel.call("_on_sky_changed", 0)
|
|
_check(not main.doc.has("weather_sky"), "T2 Standard entfernt das Feld")
|
|
_check(bool(main.get("dirty")), "T2 Änderung markiert dirty")
|
|
# „Pack-Skybox“ → Feld = sky_panorama (Client-Vertrag, V17-Wert).
|
|
map_panel.call("_on_sky_changed", 1)
|
|
_check(str(main.doc.get("weather_sky", "")) == "sky_panorama",
|
|
"T2 Pack-Skybox schreibt weather_sky=sky_panorama")
|
|
# UI-Zustand nach externer doc-Änderung korrekt auffüllen.
|
|
map_panel.call("refresh_values")
|
|
_check(prop_sky.selected == 1, "T2 refresh_values liest das Feld (Index 1)")
|
|
# Für T3-Baseline wieder auf Standard.
|
|
map_panel.call("_on_sky_changed", 0)
|
|
_check(not main.doc.has("weather_sky"), "T2 Aufräumen: Feld entfernt")
|
|
|
|
|
|
func _t3_vorschau() -> void:
|
|
print("== T3: Editor-Vorschau (map_view_builder) ==")
|
|
var vb = main.view_builder
|
|
_check(vb != null, "T3 view_builder vorhanden")
|
|
if vb == null:
|
|
return
|
|
var bscript: Script = vb.get_script()
|
|
var sky_pfad: String = bscript.panorama_sky_pfad()
|
|
_check(not sky_pfad.is_empty(), "T3 Client-Nachbar-Klon gefunden (%s)" % sky_pfad)
|
|
if sky_pfad.is_empty() or not FileAccess.file_exists(sky_pfad):
|
|
print(" (Pack-Skybox im Nachbar-Klon nicht erreichbar — Panorama-Checks übersprungen)")
|
|
return
|
|
main.doc["weather_sky"] = "sky_panorama"
|
|
vb.call("rebuild", main.doc, main.manifest)
|
|
await process_frame
|
|
var we := _welt_env(vb)
|
|
_check(we != null, "T3 WorldEnvironment vorhanden")
|
|
if we != null and we.environment != null and we.environment.sky != null:
|
|
_check(we.environment.sky.sky_material is PanoramaSkyMaterial,
|
|
"T3 weather_sky=sky_panorama → PanoramaSkyMaterial in der Vorschau")
|
|
_check(we.environment.tonemap_mode == Environment.TONE_MAPPER_ACES,
|
|
"T3 Vorschau tonemappt ACES")
|
|
var wl: Dictionary = bscript.get_script_constant_map().get("WEATHER_LIGHT", {})
|
|
var preset: Dictionary = wl.get(str(main.doc.get("weather", "mittag")), {})
|
|
if preset.has("panorama_fog_color"):
|
|
_check((we.environment.fog_light_color as Color).is_equal_approx(
|
|
preset["panorama_fog_color"]),
|
|
"T3 Fog am Skybox-Horizont (panorama_fog_color)")
|
|
# Feld entfernen → Procedural (alte Maps laden unverändert).
|
|
main.doc.erase("weather_sky")
|
|
vb.call("rebuild", main.doc, main.manifest)
|
|
await process_frame
|
|
var we2 := _welt_env(vb)
|
|
_check(we2 != null and we2.environment != null and we2.environment.sky != null
|
|
and we2.environment.sky.sky_material is ProceduralSkyMaterial,
|
|
"T3 ohne weather_sky → ProceduralSkyMaterial (alte Maps unverändert)")
|
|
|
|
|
|
## Neue Skyboxen: Auswahl → doc + Vorschau-Bild + Viewport-Sky; Undo/Redo.
|
|
func _t4_auswahl_undo() -> void:
|
|
print("== T4: Skybox-Auswahl mit Undo/Redo ==")
|
|
var prop_sky: OptionButton = map_panel.get("prop_sky")
|
|
var vb = main.view_builder
|
|
main.doc.erase("weather_sky")
|
|
map_panel.call("refresh_values")
|
|
var idx := -1
|
|
for i in SkyboxKatalog.EINTRAEGE.size():
|
|
if SkyboxKatalog.EINTRAEGE[i]["id"] == "sky_98":
|
|
idx = i + 1
|
|
_check(idx > 0, "T4 sky_98 im Katalog")
|
|
var h = main.history
|
|
var n0: int = h.entries.size()
|
|
prop_sky.select(idx)
|
|
map_panel.call("_on_sky_changed", idx)
|
|
_check(str(main.doc.get("weather_sky", "")) == "sky_98", "T4 Auswahl schreibt weather_sky=sky_98")
|
|
_check(h.entries.size() == n0 + 1, "T4 Auswahl landet in der Undo-Historie")
|
|
var prev: TextureRect = map_panel.get("sky_preview")
|
|
var tex_ok := SkyboxKatalog.textur_pfad("sky_98") != "" and FileAccess.file_exists(SkyboxKatalog.textur_pfad("sky_98"))
|
|
if tex_ok:
|
|
_check(prev.texture != null and prev.visible, "T4 Vorschau-Bild sichtbar")
|
|
await process_frame
|
|
var we := _welt_env(vb)
|
|
_check(we != null and we.environment.sky.sky_material is PanoramaSkyMaterial,
|
|
"T4 Viewport zeigt Panorama (sky_98)")
|
|
# Gleiche Auswahl nochmal = kein neuer Historien-Eintrag.
|
|
map_panel.call("_on_sky_changed", idx)
|
|
_check(h.entries.size() == n0 + 1, "T4 gleiche Wahl erzeugt keinen Eintrag")
|
|
# Undo → Feld weg, UI zurück auf Standard.
|
|
main.call("_do_undo")
|
|
_check(not main.doc.has("weather_sky"), "T4 Undo entfernt weather_sky")
|
|
_check(prop_sky.selected == 0, "T4 Undo: Auswahlfeld zeigt Standard")
|
|
main.call("_do_redo")
|
|
_check(str(main.doc.get("weather_sky", "")) == "sky_98", "T4 Redo setzt sky_98 wieder")
|
|
_check(prop_sky.selected == idx, "T4 Redo: Auswahlfeld zeigt sky_98")
|
|
# Wechsel auf anderen Himmel, Undo → zurück auf sky_98 (nicht Standard).
|
|
map_panel.call("_on_sky_changed", 2)
|
|
main.call("_do_undo")
|
|
_check(str(main.doc.get("weather_sky", "")) == "sky_98", "T4 Undo nach Wechsel → vorheriger Himmel")
|
|
# Aufräumen.
|
|
map_panel.call("_on_sky_changed", 0)
|
|
_check(not main.doc.has("weather_sky"), "T4 Aufräumen")
|
|
# Katalog-Vertrag: Server-Feld überlebt Speichern/Laden.
|
|
var d: Dictionary = main.doc.duplicate(true)
|
|
d["weather_sky"] = "sky_14"
|
|
SvmapIO.sign_map(d)
|
|
_check(SvmapIO.validate_map(d).is_empty(), "T4 Map mit sky_14 signiert + valide")
|
|
|
|
|
|
func _welt_env(vb) -> WorldEnvironment:
|
|
for child in vb.get_children():
|
|
if child is WorldEnvironment:
|
|
return child
|
|
return null
|
|
|
|
|
|
func _finish() -> void:
|
|
print("--------------------------------------------------")
|
|
print("CHECKS: %d FAILURES: %d" % [checks, failures])
|
|
quit(0 if failures == 0 else 1)
|