extends SceneTree ## M4-Beweis (t_ffa207b1): Bau-Teile + Spawn-Zonen werden im Symmetrie-Modus ## gespiegelt. Ein Blick von oben auf eine 256-m-Karte: links Original ## (Fundament + Wand, blaue Zone), rechts der Zwilling (gleiche kind_id, ## gespiegelte Drehung; rote Zone im Gegner-Team). ## ## xvfb-run -a /opt/data/home/bin/godot4 --rendering-driver opengl3 --path . \ ## --resolution 1600x900 -s res://tests/probe_m4_mirror_render.gd ## ## Ausgabe: /tmp/m4_mirror_beweis.png + Prüfzeilen (Zwillinge vorhanden, ## Positionen gespiegelt). Nur DER Beweis-Lauf nutzt die echte Code-Kette ## (BuildOps.place_mirrored / SpawnTool.spawn_mirror_add) — genau wie die Suite. const SpawnTool := preload("res://src/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("M4-Symmetrie-Beweis", 256.0, "mittag") # --- Bau-Teile: Original West, Zwilling Ost (echte M4-Code-Kette) -------- var fund := BuildOps.make_piece("fundament", Vector3(-21.0, 0.0, 3.0), 0.0) BuildOps.ensure_block(doc).append(fund) var fund_msg: String = BuildOps.place_mirrored(doc, fund, POINT) var wand := BuildOps.make_piece("wand", Vector3(-20.0, 0.2, -2.0), 90.0) BuildOps.ensure_block(doc).append(wand) var wand_msg: String = BuildOps.place_mirrored(doc, wand, POINT) # --- Spawn: blaue Zone West → rote Zwilling-Zone Ost --------------------- var point := SpawnOps.add_zone(doc, 0, -100.0, 30.0) var spawn_res: Dictionary = SpawnTool.spawn_mirror_add(doc, 0, str(point["id"]), POINT) # --- Prüfzeilen (echte Werte, keine Behauptungen) ------------------------- var fehler: Array = [] _check(BuildOps.piece_count(doc) == 4, "4 Bauteile (2 Paare)", fehler) _check(fund_msg == "" and wand_msg == "", "beide Bau-Teile still gespiegelt", fehler) var twin_fund := _piece_at_pos(doc, 21.0) _check(not twin_fund.is_empty(), "Fundament-Zwilling bei +21", fehler) var twin_wand := _wand_twin(doc) _check(not twin_wand.is_empty(), "Wand-Zwilling vorhanden", fehler) if not twin_wand.is_empty(): var rot: float = float(twin_wand.get("rot", 0.0)) _check(SymmetryCore.sym_of(wand) == SymmetryCore.sym_of(twin_wand), "Wand-Paar via sym gekoppelt", fehler) print("WAND-ZWILLING: pos=%.1f/%.1f rot=%.0f (Original 90° → gespiegelt %.0f)" % [ (float(twin_wand["pos"][0])), float(twin_wand["pos"][2]), rot, rot]) _check(bool(spawn_res["ok"]), "Spawn gespiegelt: %s" % str(spawn_res["status"]), fehler) _check(SpawnOps.count_points(doc, 1) == 5, "Team Rot: 4 Default + 1 Zwilling", fehler) print("BAU-TEILE: %d | SPAWN-STATUS: %s" % [BuildOps.piece_count(doc), str(spawn_res["status"])]) # --- Render --------------------------------------------------------------- var bauer: Node3D = load("res://src/viewport/map_view_builder.gd").new() root.add_child(bauer) await process_frame bauer.rebuild(doc, manifest) await process_frame # Symmetrie-Achse sichtbar machen (dünne halbtransparente Linie bei x = 0). var achse := MeshInstance3D.new() var achse_mesh := BoxMesh.new() achse_mesh.size = Vector3(0.3, 3.0, 90.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) var cam := Camera3D.new() cam.fov = 55.0 root.add_child(cam) cam.current = true cam.make_current() # Bild 1: TOTAL — gespiegelte Spawn-Zonen (blau links, rot rechts). cam.position = Vector3(0.0, 120.0, 130.0) await process_frame cam.look_at(Vector3(0.0, 0.0, -10.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("/tmp/m4_beweis_spawns.png") # Bild 2: NAH — Bauteil-Paar links/rechts der Achse (beide voll im Rahmen). cam.position = Vector3(0.0, 14.0, 36.0) await process_frame cam.look_at(Vector3(0.0, 0.0, 0.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("/tmp/m4_beweis_bauteile.png") for f in fehler: print(" FEHLER: %s" % f) print("PROBE_M4_MIRROR_%s" % ("FAIL" if not fehler.is_empty() else "OK")) quit(1 if not fehler.is_empty() else 0) func _check(cond: bool, label: String, fehler: Array) -> void: print(" %s: %s" % ["ok" if cond else "FEHLER", label]) if not cond: fehler.append(label) func _piece_at_pos(doc: Dictionary, x: float) -> Dictionary: for t in BuildOps.pieces(doc): if not (t is Dictionary): continue var pos: Array = (t as Dictionary).get("pos", [0.0, 0.0, 0.0]) if absf(float(pos[0]) - x) < 0.01 and str((t as Dictionary).get("id", "")) == "fundament": return t as Dictionary return {} func _wand_twin(doc: Dictionary) -> Dictionary: for t in BuildOps.pieces(doc): if not (t is Dictionary): continue var pos: Array = (t as Dictionary).get("pos", [0.0, 0.0, 0.0]) if str((t as Dictionary).get("id", "")) == "wand" and float(pos[0]) > 0.0: return t as Dictionary return {}