extends SceneTree ## Spawn-overlap audit. Every site, every pair of dynamic bodies: do their colliders ## interpenetrate on frame one? ## ## The spawn guard clamps an exploding prop and names it, but only if Jolt happens to ## resolve that pair violently on the frames it's watching — a symmetric overlap can sit ## quietly for a whole run and then launch a filing cabinet the day you change something ## unrelated. This finds them by measurement instead of by luck. ## ## Godot --headless --path game --script dev/probe_overlap.gd const CLEAR := 0.004 ## metres of slop allowed before we call it an overlap func _initialize() -> void: var main: Node = (load("res://main.tscn") as PackedScene).instantiate() get_root().add_child(main) await process_frame var bad := 0 for id in Levels.ORDER: main._load_level(id) await process_frame bad += _audit(id) print("\n%s" % ("CLEAN — nothing interpenetrates at spawn" if bad == 0 else "%d overlapping pairs" % bad)) quit() ## Godot renames duplicates to @RigidBody3D@NNN, which is useless in a report. The GLB ## instance under the body still knows what it is. func _label(b: Node) -> String: for c in b.get_children(): if c is Node3D and not (c is CollisionShape3D): return String(c.name).to_lower() return String(b.name) func _audit(id: String) -> int: var boxes: Array = [] for n in get_nodes_in_group("smashable"): var b := n as RigidBody3D if b == null or b.freeze: continue for c in b.get_children(): var col := c as CollisionShape3D if col == null: continue var half := Vector3.ZERO if col.shape is BoxShape3D: half = (col.shape as BoxShape3D).size * 0.5 elif col.shape is SphereShape3D: # a sphere's AABB over-reports at the corners, so nested round produce # would false-positive; shrink it to the inscribed cube var r: float = (col.shape as SphereShape3D).radius * 0.577 half = Vector3(r, r, r) else: continue boxes.append({"node": b, "name": _label(b), "c": b.global_position + col.position, "h": half}) var hits: Array = [] for i in boxes.size(): for j in range(i + 1, boxes.size()): var a: Dictionary = boxes[i] var b2: Dictionary = boxes[j] var d: Vector3 = (a["c"] as Vector3) - (b2["c"] as Vector3) var need: Vector3 = (a["h"] as Vector3) + (b2["h"] as Vector3) # AABB test: they only overlap if they overlap on ALL THREE axes var pen := Vector3(need.x - absf(d.x), need.y - absf(d.y), need.z - absf(d.z)) if pen.x > CLEAR and pen.y > CLEAR and pen.z > CLEAR: hits.append({"an": a["name"], "bn": b2["name"], "pen": minf(pen.x, minf(pen.y, pen.z)), "at": a["c"]}) hits.sort_custom(func(x, y): return float(x["pen"]) > float(y["pen"])) print("\n=== %-11s %d dynamic boxes, %d overlapping pairs" % [id, boxes.size(), hits.size()]) for k in mini(8, hits.size()): var h: Dictionary = hits[k] print(" %.3f m into %-18s / %-18s at %s" % [h["pen"], h["an"], h["bn"], h["at"]]) return hits.size()