123 lines
5.6 KiB
GDScript
123 lines
5.6 KiB
GDScript
extends SceneTree
|
|
## M5-Beweis (t_60014669): Ein-Klick „Karte symmetrisch machen“ an einer echten
|
|
## Testkarte — VORHER/NACHHER aus der Vogelperspektive mit Symmetrie-Achse.
|
|
## Karte asymmetrisch: Hügel + Sandfleck nur links, Objekte nur links (plus
|
|
## ein widersprüchliches rechts), Bau-Teil nur links, Solo-Spawn links.
|
|
## Nach EINEM Klick (SymmetryOps.apply, Quelle links): beide Seiten decken.
|
|
##
|
|
## xvfb-run -a /opt/data/home/bin/godot4 --rendering-driver opengl3 --path . \
|
|
## --resolution 1600x900 -s res://tests/probe_m5_symmetry_render.gd
|
|
##
|
|
## Ausgabe: /tmp/m5_vorher.png, /tmp/m5_nachher.png + Prüfzeilen.
|
|
|
|
const SpawnToolScript := preload("res://core/editor/spawn_tool.gd")
|
|
const POINT := SymmetryCore.Mode.POINT
|
|
|
|
|
|
func _initialize() -> void:
|
|
var manifest: Dictionary = JSON.parse_string(FileAccess.get_file_as_string("res://library/objects.json"))
|
|
var doc: Dictionary = SvmapDocument.create_new("M5-Symmetrie-Beweis", 256.0, "mittag")
|
|
_fill_asymmetric(doc)
|
|
|
|
# --- VORHER rendern --------------------------------------------------------
|
|
var bauer: Node3D = load("res://core/viewport/map_view_builder.gd").new()
|
|
root.add_child(bauer)
|
|
await process_frame
|
|
bauer.rebuild(doc, manifest)
|
|
await process_frame
|
|
var cam := Camera3D.new()
|
|
cam.fov = 50.0
|
|
root.add_child(cam)
|
|
cam.make_current()
|
|
var achse := MeshInstance3D.new()
|
|
var achse_mesh := BoxMesh.new()
|
|
achse_mesh.size = Vector3(0.4, 3.0, 120.0)
|
|
achse.mesh = achse_mesh
|
|
var achse_mat := StandardMaterial3D.new()
|
|
achse_mat.shading_mode = BaseMaterial3D.SHADING_MODE_UNSHADED
|
|
achse_mat.albedo_color = Color(1.0, 0.95, 0.2, 0.55)
|
|
achse_mat.transparency = BaseMaterial3D.TRANSPARENCY_ALPHA
|
|
achse.material_override = achse_mat
|
|
achse.position = Vector3(0.0, 1.5, 0.0)
|
|
root.add_child(achse)
|
|
await _shot(cam, "/tmp/m5_vorher.png", Vector3(0.0, 95.0, 105.0))
|
|
|
|
# --- Prüfzeilen VORHER (echte Werte) ---------------------------------------
|
|
var rep_v := SymmetryOps.check(doc, POINT)
|
|
print("VORHER-CHECK: %s" % str(rep_v["text"]))
|
|
print("VORHER-BODEN: Hügel Süd-West %.2f m | Spiegelpunkt Nord-Ost %.2f m" % [
|
|
SvmapDocument.terrain_height_at(doc, -90.0, 50.0),
|
|
SvmapDocument.terrain_height_at(doc, 90.0, -50.0)])
|
|
print("VORHER-OBJEKTE: %d | BAU-TEILE: %d" % [
|
|
(doc["objects"] as Array).size(), BuildOps.piece_count(doc)])
|
|
|
|
# --- EIN Klick: ganze Karte angleichen (Quelle links) ----------------------
|
|
var res := SymmetryOps.apply(doc, POINT, false)
|
|
print("APPLY-BERICHT: %s" % str(res["report"]))
|
|
bauer.rebuild(doc, manifest)
|
|
await _shot(cam, "/tmp/m5_nachher.png", Vector3(0.0, 95.0, 105.0))
|
|
|
|
# --- Prüfzeilen NACHHER ----------------------------------------------------
|
|
var rep_n := SymmetryOps.check(doc, POINT)
|
|
print("NACHHER-CHECK: %s" % str(rep_n["text"]))
|
|
print("NACHHER-BODEN: Süd-West %.2f m | Nord-Ost %.2f m" % [
|
|
SvmapDocument.terrain_height_at(doc, -90.0, 50.0),
|
|
SvmapDocument.terrain_height_at(doc, 90.0, -50.0)])
|
|
print("NACHHER-OBJEKTE: %d | BAU-TEILE: %d | Spawn-Partner A9=%s" % [
|
|
(doc["objects"] as Array).size(), BuildOps.piece_count(doc),
|
|
SpawnToolScript.spawn_mirror_partner(doc, "A9")])
|
|
var fehler: Array = []
|
|
_check(bool(rep_n["ok"]), "Check nach dem Klick: 0 Abweichungen", fehler)
|
|
_check(absf(SvmapDocument.terrain_height_at(doc, -90.0, 50.0)
|
|
- SvmapDocument.terrain_height_at(doc, 90.0, -50.0)) < 0.001,
|
|
"Boden: Hügelhöhe am Spiegelpunkt identisch", fehler)
|
|
for f in fehler:
|
|
print(" FEHLER: %s" % f)
|
|
print("PROBE_M5_%s" % ("FAIL" if not fehler.is_empty() else "OK"))
|
|
quit(1 if not fehler.is_empty() else 0)
|
|
|
|
|
|
func _fill_asymmetric(doc: Dictionary) -> void:
|
|
# Layout-Kohärenz: Hügelregion Süd-West (i<60, j 82..96) und ihr
|
|
# Punkt-Spiegel Nord-Ost. Objekte/Bauteil sitzen AUF dem Hügel (y=6) —
|
|
# nach dem Angleichen sitzen ihre Zwillinge exakt (M3-Konvention: y 1:1).
|
|
# Spawns liegen außerhalb der Hügelzone (y 0.2 bleibt sichtbar).
|
|
var terrain: Dictionary = doc["terrain"]
|
|
var res := int(terrain["resolution"])
|
|
var heights := SvmapIO.decode_heights(terrain)
|
|
for j in range(82, 97):
|
|
for i in 60:
|
|
heights[j * res + i] = 6.0 # Hügel nur Süd-West
|
|
terrain["heightmap_r16_b64"] = TerrainField.encode(heights,
|
|
float(terrain["min_height_m"]), float(terrain["max_height_m"]))
|
|
var mats := SvmapIO.decode_materials(terrain)
|
|
for j in range(84, 93):
|
|
for i in range(20, 30):
|
|
mats[j * res + i] = 1 # Sandfleck nur Süd-West
|
|
terrain["materials_r8_b64"] = SvmapIO.encode_materials(mats)
|
|
var objs: Array = doc["objects"]
|
|
objs.append({"id": "barrel_001", "pos": [-90.0, 6.0, 50.0], "scale": 1.0, "rot_y_deg": 30.0}) # Hügel
|
|
objs.append({"id": "barrel_001", "pos": [90.0, 6.0, -50.0], "scale": 1.0, "rot_y_deg": 10.0}) # Widerspruch (Spiegelpunkt)
|
|
objs.append({"id": "barrel_001", "pos": [110.0, 6.0, -60.0], "scale": 1.0, "rot_y_deg": 0.0}) # solo rechts
|
|
var fund := BuildOps.make_piece("fundament", Vector3(-90.0, 6.0, 40.0), 0.0)
|
|
BuildOps.ensure_block(doc).append(fund) # nur links (auf dem Hügel), kein Zwilling
|
|
SpawnOps.remove_point(doc, 1, "B1") # roter Punkt weg → A4 solo
|
|
var zones: Dictionary = doc["spawn_zones"]
|
|
((zones["0"] as Dictionary)["points"] as Array).append({"id": "A9", "pos": [-60.0, 6.0, 40.0]})
|
|
|
|
|
|
func _shot(cam: Camera3D, path: String, pos: Vector3) -> void:
|
|
cam.position = pos
|
|
await process_frame
|
|
cam.look_at(Vector3(0.0, 0.0, -5.0), Vector3(0.0, 0.0, -1.0))
|
|
await process_frame
|
|
await process_frame
|
|
await RenderingServer.frame_post_draw
|
|
root.get_texture().get_image().save_png(path)
|
|
print("BILD: %s" % path)
|
|
|
|
|
|
func _check(cond: bool, label: String, fehler: Array) -> void:
|
|
print(" %s: %s" % ["ok" if cond else "FEHLER", label])
|
|
if not cond:
|
|
fehler.append(label)
|