OverviewFilesCommitsIssuesDocsReleasesPeers

hyper-tps / scenes / test / gate_map_flat_objects.gd

99 lines · gd ref:
extends SceneTree
## Gate: map_flat can be built in.
##
## map_dc_level was the only map that instantiated SceneObjects, so "building"
## and "the Quake brush level" were the same thing by accident of where the
## wiring lived. A builder bot needs a journal, a prefab catalogue and something
## to fold records into nodes; none of those need brushes, and map_flat is the
## map a bot testbed actually runs in.
##
## This instances the REAL map_flat.tscn rather than a stand-in, because what is
## under test is the wiring in that scene's script — a fixture built here would
## be asserting against itself.

var ok := true
var _ran := false


func _p(c: bool, m: String) -> void:
	print(("ok   " if c else "FAIL: ") + m)
	if not c:
		ok = false


func _process(_delta: float) -> bool:
	if _ran:
		return true
	_ran = true
	_run()
	print("GATE map_flat_objects: %s" % ("PASS" if ok else "FAIL"))
	if not ok:
		quit(1)
	return true


func _run() -> void:
	var ps: PackedScene = load("res://scenes/maps/map_flat.tscn")
	_p(ps != null, "map_flat.tscn loads")
	if ps == null:
		return
	var map: Node = ps.instantiate()
	_p(map != null, "and instantiates")
	if map == null:
		return
	root.add_child(map)

	# ---- the wiring exists and was made eagerly ----
	var objs: Node = map.get_node_or_null(^"SceneObjects")
	var persist: Node = map.get_node_or_null(^"LevelPersistence")
	_p(objs != null, "map_flat has a SceneObjects")
	_p(persist != null, "and a LevelPersistence, made in _ready rather than on first use")
	if objs == null or persist == null:
		return
	# CHANGED 2026-10-02 (user decision: brush building on every demo map): map_flat
	# extends map_dc_level with level_import off, so the journal now folds brushes
	# into its DCLevel too. The pair is INHERITED -- there must be exactly one, or
	# two managers would fold one journal.
	var lvl: Node = map.get_node_or_null(^"DCLevel")
	_p(lvl != null and persist.level == lvl, "the journal folds brushes into this map's DCLevel")
	var n_persist := 0
	var n_objs := 0
	for c in map.get_children():
		if String(c.name).begins_with("LevelPersistence"):
			n_persist += 1
		if String(c.name).begins_with("SceneObjects"):
			n_objs += 1
	_p(n_persist == 1 and n_objs == 1, "exactly ONE journal and ONE objects manager (%d / %d)" % [n_persist, n_objs])
	_p(persist.objects == objs, "and the journal is wired to the objects manager")

	# ---- the journal is a control surface a bot can drive ----
	_p(persist.is_in_group("admin_controllable"), "the journal is admin-controllable")
	_p(String(persist.get_meta("admin_name", "")) == "level", "exposed as 'level'")
	var scopes: Dictionary = persist.get_meta("admin_call_scopes", {}) as Dictionary
	_p(String(scopes.get("record", "")) == "authority",
		"record is scope authority — one peer records, or N peers build N blocks")

	# ---- and it can actually build ----
	_p(map.has_method("create_object"), "map_flat exposes create_object()")
	if not map.has_method("create_object"):
		return
	var before: int = objs.count()
	var dot: String = map.create_object("block.bevelled",
		Transform3D(Basis(), Vector3(0.0, 5.0, 0.0)))
	_p(dot != "", "creating a block returns a dot (%s)" % dot)
	_p(objs.count() == before + 1, "and a node exists for it (%d -> %d)" % [before, objs.count()])

	var n: Node = objs.node_for(dot)
	_p(n != null, "the node resolves from its dot")
	if n is Node3D:
		_p((n as Node3D).transform.origin.is_equal_approx(Vector3(0.0, 5.0, 0.0)),
			"and is where it was asked for (%s)" % str((n as Node3D).transform.origin))

	# SELF-CHECK: an unknown prefab must be refused, or create_object would build
	# anything a peer names and the catalogue's allow-list would be decorative.
	var bad: String = map.create_object("definitely.not.a.prefab", Transform3D())
	_p(bad == "", "self-check: an unknown prefab id is refused")
	_p(objs.count() == before + 1, "and nothing was built for it")

	map.free()