diff --git a/src/editor/action_history.gd b/src/editor/action_history.gd index 9e5467b..cd4cf50 100644 --- a/src/editor/action_history.gd +++ b/src/editor/action_history.gd @@ -79,12 +79,15 @@ func commit(desc: String, before: Dictionary, after: Dictionary, merge_tag: Stri ## Letzte Aktion zurücknehmen. Rückgabe: Beschreibung ("" = nichts da). +## Restore läuft IN-PLACE: doc["objects"] etc. behalten ihre Identität (Array/ +## Dict-Objekt wird geleert und neu befüllt) — bezogene Referenzen (Tests, +## Ansichten) werden nicht zu Stale-Schnappschüssen. func undo() -> String: if not can_undo(): return "" var entry: Dictionary = entries[index] for key in entry["before"]: - doc[key] = entry["before"][key].duplicate(true) if entry["before"][key] != null else null + _restore_block(key, entry["before"][key]) index -= 1 return str(entry.get("desc", "")) @@ -96,5 +99,25 @@ func redo() -> String: index += 1 var entry: Dictionary = entries[index] for key in entry["after"]: - doc[key] = entry["after"][key].duplicate(true) if entry["after"][key] != null else null - return str(entry.get("desc", "")) \ No newline at end of file + _restore_block(key, entry["after"][key]) + return str(entry.get("desc", "")) + + +func _restore_block(key: String, value: Variant) -> void: + if value == null: + doc.erase(key) + return + # Ganzen Block (Array/Dict) in-place neu befüllen — Identität bleibt erhalten. + var source: Variant = value.duplicate(true) + if source is Array: + var arr: Array = doc.get(key, []) + arr.clear() + arr.append_array(source) + doc[key] = arr + elif source is Dictionary: + var dict: Dictionary = doc.get(key, {}) + dict.clear() + dict.merge(source) + doc[key] = dict + else: + doc[key] = source \ No newline at end of file diff --git a/tests/test_ux.gd b/tests/test_ux.gd index 045af33..5d39d15 100644 --- a/tests/test_ux.gd +++ b/tests/test_ux.gd @@ -212,10 +212,11 @@ func _test_terrain_height() -> void: "heightmap_r16_b64": Marshalls.raw_to_base64(bytes), } var doc2 := {"terrain": slope} - _check(absf(SvmapDocument.terrain_height_at(doc2, 0.0, 0.0) - 0.0) < 0.5, "Gradient: Nordkante ≈ 0 m") - var mid := SvmapDocument.terrain_height_at(doc2, 0.0, 80.0) - _check(absf(mid - 50.0) < 1.0, "Gradient: Mitte ≈ 50 m (ist %.1f)" % mid) - _check(absf(SvmapDocument.terrain_height_at(doc2, 0.0, 160.0) - 100.0) < 0.5, "Gradient: Südkante ≈ 100 m") + _check(absf(SvmapDocument.terrain_height_at(doc2, 0.0, -80.0) - 0.0) < 0.5, "Gradient: Nordkante (z=-80) ≈ 0 m") + var mid := SvmapDocument.terrain_height_at(doc2, 0.0, 0.0) + _check(absf(mid - 50.0) < 1.0, "Gradient: Mitte (z=0) ≈ 50 m (ist %.1f)" % mid) + _check(absf(SvmapDocument.terrain_height_at(doc2, 0.0, 80.0) - 100.0) < 0.5, "Gradient: Südkante (z=+80) ≈ 100 m") + _check(absf(SvmapDocument.terrain_height_at(doc2, 0.0, 160.0) - 100.0) < 0.5, "Hinter der Kante wird geclampt (100 m)") _check(absf(SvmapDocument.terrain_height_at(doc2, 5000.0, -900.0) - 0.0) < 0.6, "Außerhalb-Query wird geclampt (keine Abstürze)")