extends Node
## GATE — a level map's SCENE BOXES become BASE BRUSHES at load (2026-10-05: "the
## editor cannot select the created elements in the tscn starter map").
##
## map_test's geometry was StaticBody3D + BoxShape3D + CSGBox3D nodes: no journal
## identity, so a click logged "not level geometry" and nothing could select, move or
## delete them. Now each becomes a base brush in the DCLevel (key "i:1:<n>", level 1,
## in node-NAME order so the keys are stable), and the node goes. Edits are ordinary
## journal records against those keys; the rewind keeps base brushes live.
##
## 1. no box StaticBody3D left under the map; 8 base brushes, keys in name order
## 2. Platform1's brush is where Platform1 was; the rotated Ramp keeps its rotation
## 3. a child that is not collision (HubLabel) survives the conversion
## 4. a real ray onto Platform2 picks its brush (level body)
## 5. brush.remove on a base key deletes it; Ctrl+Z restores it
##
## RUN AS A SCENE: "$HYPER_TPS_GODOT" --headless res://scenes/test/gate_scene_boxes_base.tscn
const NAMES := ["Ground", "NorthBridge", "NorthHub", "Platform1", "Platform2", "Platform3", "Ramp", "Wall1"]
var fails := 0
var checks := 0
func _ok(what: String, cond: bool, note: String = "") -> void:
checks += 1
if not cond:
fails += 1
print(" %-62s %s %s" % [what, "OK" if cond else "**FAIL**", note])
func _ready() -> void:
var gs: Node = get_tree().root.get_node_or_null("/root/GameState")
gs.route("world:level:*", 1, "peer")
var keet: Node = get_tree().root.get_node_or_null("/root/KeetService")
if keet != null:
keet.current_member_id = "gate-author"
var map: Node3D = (load("res://scenes/maps/map_dev_test.tscn") as PackedScene).instantiate()
add_child(map)
for i in 6:
await get_tree().physics_frame
_run(map)
if checks < 12:
print(" **FAIL** only %d checks ran -- setup died before the assertions" % checks)
fails += 1
print("\nGATE scene_boxes_base: %s (%d checks, %d failed)" % ["PASS" if fails == 0 else "FAIL", checks, fails])
get_tree().quit(0 if fails == 0 else 1)
func _live(level: Node, key: String) -> bool:
var id: int = level.brush_by_key(key)
var b: Dictionary = level.get_brush(id) if id > 0 else {}
return not b.is_empty() and not bool(b.get("tombstoned", false))
func _run(map: Node3D) -> void:
var level: Node = map.get("level")
var persist: Node = map.get("_persist")
_ok("map_test has its level and journal", level != null and persist != null)
if level == null or persist == null:
return
var left: Array = []
for c in map.get_children():
if c is StaticBody3D:
left.append(c.name)
_ok("no scene box StaticBody3D left under the map", left.is_empty(), str(left))
var keys_ok := true
for i in NAMES.size():
if not _live(level, "i:1:%d" % i):
keys_ok = false
_ok("8 live base brushes i:1:0..7", keys_ok and not _live(level, "i:1:8"))
var p1: Dictionary = level.get_brush(level.brush_by_key("i:1:%d" % NAMES.find("Platform1")))
var mn: Vector3 = p1.get("aabb_min", Vector3.INF)
var mx: Vector3 = p1.get("aabb_max", Vector3.INF)
# Platform1: origin (-10, 3, -5), BoxShape3D 8 x 0.5 x 8.
_ok("Platform1's brush is where Platform1 was", mn.is_equal_approx(Vector3(-14, 2.75, -9))
and mx.is_equal_approx(Vector3(-6, 3.25, -1)), "%s .. %s" % [mn, mx])
var ramp: Dictionary = level.get_brush(level.brush_by_key("i:1:%d" % NAMES.find("Ramp")))
var pl: PackedFloat32Array = ramp.get("planes", PackedFloat32Array())
var tilted := false
for k in range(0, pl.size(), 4):
var n := Vector3(pl[k], pl[k + 1], pl[k + 2])
if absf(n.y) > 0.05 and absf(n.y) < 0.995:
tilted = true
_ok("the rotated Ramp keeps its rotation (tilted planes)", pl.size() == 24 and tilted, "%d floats" % pl.size())
var label: Node = map.find_child("HubLabel", true, false)
_ok("HubLabel (not collision) survived the conversion", label != null and label.is_inside_tree())
_ok("and kept its place above the hub", label != null and (label as Node3D).global_position.y > 0.4,
str((label as Node3D).global_position) if label != null else "")
# Platform2: origin (10, 6, 5), 6 x 0.5 x 6 -> top at y = 6.25.
var q := PhysicsRayQueryParameters3D.create(Vector3(10, 20, 5), Vector3(10, -20, 5))
var hit: Dictionary = map.get_world_3d().direct_space_state.intersect_ray(q)
var p2id: int = level.brush_by_key("i:1:%d" % NAMES.find("Platform2"))
_ok("a real ray onto Platform2 hits the LEVEL body", not hit.is_empty() and hit.get("collider") == level,
str(hit.get("collider")))
_ok("and picks Platform2's brush", map._brush_from_hit(hit) == p2id, "%d vs %d" % [map._brush_from_hit(hit), p2id])
var key2 := "i:1:%d" % NAMES.find("Platform2")
_ok("Platform2 is live before the delete", _live(level, key2))
map.select_brushes(PackedInt32Array([p2id]))
map.delete_selection()
persist.refold()
_ok("Delete removes a base brush (Platform2)", not _live(level, key2))
_ok("via brush.remove on its base key", persist.records().any(func(r: Dictionary) -> bool:
return String(r["kind"]) == "brush.remove" and String(r.get("brush_key", "")) == key2))
persist.undo_last()
persist.refold()
_ok("Ctrl+Z restores it", _live(level, key2))