OverviewFilesCommitsIssuesDocsReleasesPeers

hyper-tps / scenes / test / gate_object_panel.gd

172 lines · gd ref:
extends SceneTree
## GATE — the Object panel + object.set_prop end to end, on a real map_flat.
##   P1  the panel is in the dock, and says so when nothing is selected;
##   P2  selecting an object builds one widget per catalogue property;
##   P3  a commit writes ONE object.set_prop record, labelled "Set <Label>" in History,
##       and the node changes through the FOLD (not a local poke);
##   P4  an unchanged value writes nothing;
##   P5  a slider DRAG previews without writing and writes once when it ends; a track
##       click / wheel step writes once;
##   P6  one Ctrl+Z (undo_gesture) takes the change back;
##   P7  every kind: colour (block tint), bool, string (teleporter label → its sign),
##       vec3 (teleporter destination);
##   P8  deselecting empties the panel.
##
## Run: CI=true HYPERTPS_DAEMON_TCP=127.0.0.1:1 "$HYPER_TPS_GODOT" --headless --path . --script res://scenes/test/gate_object_panel.gd

var ok := true
var checks := 0
var _frame := 0
var _map: Node
var _persist: Node
var _dock: Node


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


func _process(_d: float) -> bool:
	_frame += 1
	if _frame == 1:
		_dock = root.get_node("/root/BuildDock")
		_map = (load("res://scenes/maps/map_flat.tscn") as PackedScene).instantiate()
		root.add_child(_map)
		return false
	if _frame < 30:
		return false
	_run()
	print("\n%d checks — %s" % [checks, "PASS" if ok else "FAIL"])
	quit(0 if ok else 1)
	return true


func _set_props() -> int:
	var n := 0
	for r: Dictionary in _persist.records():
		if String(r.get("kind", "")) == "object.set_prop":
			n += 1
	return n


func _panel() -> Node:
	return _map.get("_object_panel")


func _run() -> void:
	_persist = _map.get("_persist")
	var panel: Node = _panel()
	# ---- P1 ----
	_p(_dock._panels.has("object"), "P1 the Object panel is registered in the dock")
	_p(panel != null, "P1 the map holds it")
	if panel == null:
		return
	panel.refresh()
	_p(String(panel._title.text).begins_with("Select an object"), "P1 empty selection says so", panel._title.text)

	# ---- P2 ----
	var at := Transform3D(Basis(), Vector3(3, 2, 3))
	var light: String = _map.create_object("light.point", at)
	_p(light != "", "P2 a light is created", light)
	_map.select_object(light)
	panel.refresh()
	_p(String(panel._title.text).begins_with("light.point"), "P2 the panel shows the selected light", panel._title.text)
	var ids: Array = panel._widgets.keys()
	_p(ids == ["color", "energy", "range", "shadows"], "P2 one widget per catalogue prop", ids)
	var node := _map.object_node(light) as OmniLight3D

	# ---- P3 ----
	var before := _set_props()
	_p(panel.commit("energy", 6.0), "P3 commit returns true")
	_p(_set_props() == before + 1, "P3 exactly one object.set_prop record", _set_props() - before)
	_p(is_equal_approx(node.light_energy, 6.0), "P3 the light changed (via the fold)", node.light_energy)
	var newest: Dictionary = _persist.gestures()[0]
	_p(String(newest["label"]) == "Set Brightness", "P3 History names it", newest["label"])
	_p(int(newest["count"]) == 1, "P3 one record in the gesture", newest["count"])

	# ---- P4 ----
	before = _set_props()
	_p(not panel.commit("energy", 6.0), "P4 an unchanged value is not a write")
	_p(_set_props() == before, "P4 and no record", _set_props() - before)

	# ---- P5 ----
	panel.refresh()
	var sl := panel.widget("range") as HSlider
	before = _set_props()
	panel._on_drag_started("range")
	sl.value = 20.0
	sl.value = 30.0
	_p(_set_props() == before, "P5 mid-drag writes nothing", _set_props() - before)
	_p(is_equal_approx(node.omni_range, 30.0), "P5 but previews on the node", node.omni_range)
	panel._on_drag_ended(true, "range")
	_p(_set_props() == before + 1, "P5 the drag's end writes once", _set_props() - before)
	_p(is_equal_approx(float(_map.object_props(light)["range"]), 30.0), "P5 with the final value",
		_map.object_props(light)["range"])
	before = _set_props()
	sl.value = 40.0                      # a track click / wheel step: not dragging
	_p(_set_props() == before + 1, "P5 a click on the track writes once", _set_props() - before)

	# ---- P6 ----
	_persist.undo_gesture(_persist.newest_live_gesture())
	_persist.refold()
	_p(is_equal_approx(node.omni_range, 30.0), "P6 one undo takes the last change back", node.omni_range)
	_persist.undo_gesture(_persist.newest_live_gesture())
	_persist.refold()
	_p(is_equal_approx(node.omni_range, 8.0), "P6 and the one before, to the default", node.omni_range)

	# ---- P7 ----
	_p(panel.commit("shadows", false), "P7 bool commit")
	_p(not node.shadow_enabled, "P7 shadows off", node.shadow_enabled)
	_p(panel.commit("color", [0.2, 0.5, 1.0]), "P7 colour commit")
	_p(node.light_color.is_equal_approx(Color(0.2, 0.5, 1.0)), "P7 light colour", node.light_color)

	var block: String = _map.create_object("block.bevelled", Transform3D(Basis(), Vector3(20, 5, 0)))
	_map.select_object(block)
	panel.refresh()
	_p(panel._widgets.keys() == ["tint"], "P7 the block shows its colour only", panel._widgets.keys())
	panel.commit("tint", [0.9, 0.1, 0.1])
	var mi := _map.object_node(block).get_node("Mesh") as MeshInstance3D
	_p((mi.material_override as StandardMaterial3D).albedo_color.is_equal_approx(Color(0.9, 0.1, 0.1)),
		"P7 block tinted", (mi.material_override as StandardMaterial3D).albedo_color)

	var tp: String = _map.create_object("teleporter", Transform3D(Basis(), Vector3(0, 0, 30)))
	_map.select_object(tp)
	panel.refresh()
	var le := panel.widget("label") as LineEdit
	le.text = "Roof"
	le.text_submitted.emit("Roof")
	var tnode: Node = _map.object_node(tp)
	_p(String((tnode.get_node("Label3D") as Label3D).text) == "Roof", "P7 the label reaches the sign",
		(tnode.get_node("Label3D") as Label3D).text)
	_p(String(_persist.gestures()[0]["label"]) == "Set Label", "P7 History: Set Label", _persist.gestures()[0]["label"])
	var boxes: Array = panel.widget("destination")
	(boxes[1] as SpinBox).value = 12.5
	_p((tnode.get("destination") as Vector3).is_equal_approx(Vector3(0, 12.5, 0)), "P7 destination from the number boxes",
		tnode.get("destination"))
	_p(panel._widgets["destination"].has("here"), "P7 vec3 has a Use my position button")

	# ---- P9: a model's panel — name / collision / scale, never the hash ----
	var md: String = _map.create_object("model", Transform3D(Basis(), Vector3(0, 0, -20)))
	_map.select_object(md)
	panel.refresh()
	_p(panel._widgets.keys() == ["name", "collision", "scale"], "P9 model: name, collision, scale (asset hidden)",
		panel._widgets.keys())
	var ob := panel.widget("collision") as OptionButton
	_p(ob != null and ob.item_count == 6 and ob.get_item_text(ob.selected) == "Automatic",
		"P9 collision is a dropdown, showing the default", ob.get_item_text(ob.selected) if ob != null else "?")
	ob.select(5)
	ob.item_selected.emit(5)
	_p(String(_map.object_props(md)["collision"]) == "none", "P9 choosing None writes collision=none",
		_map.object_props(md)["collision"])
	_p(String(_persist.gestures()[0]["label"]) == "Set Collision", "P9 History: Set Collision")
	_p((panel.widget("scale") as HSlider).exp_edit, "P9 scale slider is exponential (0.01–100)")

	# ---- P8 ----
	_map.select_object("")
	panel.refresh()
	_p(String(panel._title.text).begins_with("Select an object") and panel._widgets.is_empty(),
		"P8 deselecting empties the panel", panel._title.text)