From 7c7dc385661fa281fd29aab3655889bee61998eb Mon Sep 17 00:00:00 2001 From: "Hermes (scopedvr-dev)" Date: Tue, 20 Oct 2026 09:52:03 +0000 Subject: [PATCH] U-Nachlauf t_efb3d022: assets_panel _library_load_open_states robuster Typ-Check MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit bool(cfg.get_value()) warf SCRIPT ERROR "Nonexistent bool constructor" bei Nicht-Bool-Eintraegen in [library] (Array-Eintraege neben zuletzt_benutzt) — die Klapp-Zustaende luden dann gar nicht (STATES leer). Fix: nur echte Bool-Werte uebernehmen, String/Int/Array auf Fallback true, kein Crash mehr. Beweis-Probe tests/probe_t_efb3d022_repro.gd: vorher: 2x SCRIPT ERROR "Invalid call. Nonexistent 'bool' constructor", STATES leer nachher: 0 Fehler, 3 Zustaende geladen (Array-Eintrag -> Fallback true) Suite test_assets_panel.gd erweitert um Testgruppe 0 "Klapp-Zustaende aus kaputter cfg" (6 neue Checks, 75 -> 81, ALL OK): Array/String/Int-Eintraege + save->load-Rundtrip. test_inspector 47/47, test_gui_smoke 92/92, --import 0 Parse-Errors. --- src/ui/panels/assets_panel.gd | 10 +++++++- tests/probe_t_efb3d022_repro.gd | 36 +++++++++++++++++++++++++++++ tests/probe_t_efb3d022_repro.gd.uid | 1 + tests/test_assets_panel.gd | 29 +++++++++++++++++++++++ 4 files changed, 75 insertions(+), 1 deletion(-) create mode 100644 tests/probe_t_efb3d022_repro.gd create mode 100644 tests/probe_t_efb3d022_repro.gd.uid diff --git a/src/ui/panels/assets_panel.gd b/src/ui/panels/assets_panel.gd index ff73a3e..4492ed7 100644 --- a/src/ui/panels/assets_panel.gd +++ b/src/ui/panels/assets_panel.gd @@ -328,7 +328,15 @@ func _library_load_open_states() -> Dictionary: for key in cfg.get_section_keys(LIBRARY_CFG_SECTION): if str(key) == RECENT_CFG_KEY: continue - out[str(key)] = bool(cfg.get_value(LIBRARY_CFG_SECTION, str(key), true)) + # Robustheit (t_efb3d022): cfg-Einträge dieser Sektion müssen Bool- + # Zustände sein. Ein kaputter Eintrag (String/Array/sonstwas) darf + # KEINEN SCRIPT ERROR werfen (bool() ist kein gültiger + # Konstruktor) — sonst brechen die Klapp-Zustände komplett weg. + var val = cfg.get_value(LIBRARY_CFG_SECTION, str(key), true) + if typeof(val) == TYPE_BOOL: + out[str(key)] = val + else: + out[str(key)] = true return out diff --git a/tests/probe_t_efb3d022_repro.gd b/tests/probe_t_efb3d022_repro.gd new file mode 100644 index 0000000..c01beb0 --- /dev/null +++ b/tests/probe_t_efb3d022_repro.gd @@ -0,0 +1,36 @@ +extends SceneTree +## Beweis-Probe t_efb3d022: `[library]` enthält einen Array-Eintrag. +## Vor dem Fix: SCRIPT ERROR "Invalid call. Nonexistent 'bool' constructor" +## beim Laden der Klapp-Zustände (bool() ist kein gültiger Konstruktor). +## Nach dem Fix: sauberes Laden, Zustände kommen zurück, keine Fehler. +## +## godot4 --headless --path . -s res://tests/probe_t_efb3d022_repro.gd +## +## Grep-Muster für den Gegenbeweis: "SCRIPT ERROR" + "Nonexistent 'bool' constructor" + + +func _initialize() -> void: + _run.call_deferred() + + +func _run() -> void: + # Kaputte cfg simulieren: Array-Eintrag (Nicht-Bool) neben echtem Bool, + # plus zuletzt_benutzt (U4 schreibt das Array in dieselbe Sektion). + var cfg := ConfigFile.new() + cfg.set_value("library", "zuletzt_benutzt", PackedStringArray(["crate_metal", "crate_wood"])) + cfg.set_value("library", "gruppen_kisten", true) + cfg.set_value("library", "gruppen_bauteile", false) + cfg.set_value("library", "array_gruppe", PackedStringArray(["a", "b"])) + cfg.save("user://scopedvr_editor.cfg") + + var scene: PackedScene = load("res://scenes/main.tscn") + var main: Control = scene.instantiate() + root.add_child(main) + await process_frame + await process_frame + var assets = main.assets_mod + var states: Dictionary = assets._library_load_open_states() + print("STATES=", states) + print("PROBE_ENDE states=", states.size(), " kisten=", states.get("gruppen_kisten", "?"), + " bauteile=", states.get("gruppen_bauteile", "?")) + quit(0) diff --git a/tests/probe_t_efb3d022_repro.gd.uid b/tests/probe_t_efb3d022_repro.gd.uid new file mode 100644 index 0000000..3a714f2 --- /dev/null +++ b/tests/probe_t_efb3d022_repro.gd.uid @@ -0,0 +1 @@ +uid://r7meru2u3cn6 diff --git a/tests/test_assets_panel.gd b/tests/test_assets_panel.gd index 885ae45..0b7583e 100644 --- a/tests/test_assets_panel.gd +++ b/tests/test_assets_panel.gd @@ -51,6 +51,7 @@ func _run_all() -> void: assets.object_selected.connect(_on_selected) assets.object_activated.connect(_on_activated) + _test_klapp_zustaende_cfg_robus() _test_kategorien() _test_suche_und_zaehler() _test_kategorie_filter() @@ -98,6 +99,34 @@ func _clear_library_cfg_section() -> void: cfg.save("user://scopedvr_editor.cfg") +# --------------------------------------- 0 Klapp-Zustände aus kaputter cfg ---- + +func _test_klapp_zustaende_cfg_robus() -> void: + print("Testgruppe: Klapp-Zustände laden sauber aus kaputter cfg (t_efb3d022)") + # Kaputte cfg: [library] enthält einen Array-Eintrag (zuletzt_benutzt) und + # einen korrupten Eintrag (String statt Bool) neben einem echten Bool. + var cfg := ConfigFile.new() + cfg.set_value("library", "zuletzt_benutzt", PackedStringArray(["crate_metal", "crate_wood"])) + cfg.set_value("library", "gruppen_kisten", true) + cfg.set_value("library", "gruppen_bauteile", "kaputt") + cfg.set_value("library", "gruppen_spawn", 42) + cfg.save("user://scopedvr_editor.cfg") + # Direkt aufrufen: darf KEINEN SCRIPT ERROR werfen (bool() war der + # alte Crash) und muss die sauberen Bool-Zustände trotzdem liefern. + var states: Dictionary = assets._library_load_open_states() + _check(states.size() == 3, "3 Zustände geladen, Array-Eintrag übersprungen (ist %d)" % states.size()) + _check(states.get("gruppen_kisten") == true, "echter Bool bleibt true") + _check(states.get("gruppen_bauteile") == true, "String-Eintrag auf Fallback true") + _check(states.get("gruppen_spawn") == true, "Int-Eintrag auf Fallback true") + # Und der Persistenz-Weg (save → load) liefert die Zustände unverändert: + assets._library_save_open_state("gruppen_kisten", false) + var states2: Dictionary = assets._library_load_open_states() + _check(states2.get("gruppen_kisten") == false, "save→load Rundtrip: false kommt zurück") + _check(states2.get("gruppen_bauteile") == true, "kaputter Eintrag nach Rundtrip weiter Fallback true") + # Aufräumen: nächste Testgruppen brauchen eine saubere cfg. + _clear_library_cfg_section() + + # ------------------------------------------------------------- 1 Kategorien ---- func _test_kategorien() -> void: