OverviewFilesCommitsIssuesDocsReleasesPeers

hyper-tps / scenes / test / gate_delete_selection.gd

103 lines · gd ref:
extends Node
## GATE — Delete acts on the SELECTION (2026-10-05: "delete currently works on nothing").
##
## The key went to _delete_aimed(), which never read the selection: it deleted
## whatever was under the cursor AT KEYPRESS, so a brush you clicked was not what
## Delete removed. Now delete_selection(): selected objects, else selected brushes,
## else (nothing selected) the aimed brush.
##
##   1. a selected plain brush is deleted (brush.remove), and Ctrl+Z restores it
##   2. selecting ONE piece of a parametric shape deletes the WHOLE shape
##      (shape.remove — pieces are read-only), and Ctrl+Z restores it
##   3. both are one gesture each
##
## RUN AS A SCENE (level_persistence.gd names GameState at compile time):
##   "$HYPER_TPS_GODOT" --headless res://scenes/test/gate_delete_selection.tscn

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 _box(lo: Vector3, hi: Vector3) -> Array:
	return [1, 0, 0, hi.x, -1, 0, 0, -lo.x, 0, 1, 0, hi.y, 0, -1, 0, -lo.y, 0, 0, 1, hi.z, 0, 0, -1, -lo.z]


func _live(level: Node, id: int) -> bool:
	var b: Dictionary = level.get_brush(id)
	return not b.is_empty() and not bool(b.get("tombstoned", false))


func _live_in_group(level: Node, g: String) -> int:
	var n := 0
	for id: int in (level.get_group_brush_ids(g) as PackedInt32Array):
		if _live(level, id):
			n += 1
	return n


func _ready() -> void:
	var gs: Node = get_tree().root.get_node_or_null("/root/GameState")
	gs.route("world:level:*", 1, "peer")          # 1 == Channel.DURABLE
	var keet: Node = get_tree().root.get_node_or_null("/root/KeetService")
	if keet != null:
		keet.current_member_id = "gate-author"
	var map: Node = (load("res://scenes/maps/map_test.tscn") as PackedScene).instantiate()
	add_child(map)
	for i in 4:
		await get_tree().process_frame
	_run(map)
	if checks < 9:
		print("  **FAIL** only %d checks ran -- setup died before the assertions" % checks)
		fails += 1
	print("\nGATE delete_selection: %s (%d checks, %d failed)" % ["PASS" if fails == 0 else "FAIL", checks, fails])
	get_tree().quit(0 if fails == 0 else 1)


func _run(map: Node) -> void:
	var level: Node = map.get("level")
	var persist: Node = map.get("_persist")
	_ok("map_test has a level and a journal", level != null and persist != null)
	if level == null or persist == null:
		return

	print("-- 1. a selected plain brush --")
	var dot: String = persist.record("brush.create", {"planes": _box(Vector3(200, 0, 200), Vector3(202, 2, 202)),
		"proj": [], "material_id": 0, "level_id": 0, "sky": false})
	persist.refold()
	var id: int = level.brush_by_key(dot)
	_ok("the brush exists", _live(level, id))
	map.select_brushes(PackedInt32Array([id]))
	var g0: String = persist.last_gesture()
	map.delete_selection()
	persist.refold()
	_ok("Delete removed the SELECTED brush (aim is irrelevant)", not _live(level, id))
	_ok("as one new gesture", persist.last_gesture() != g0)
	persist.undo_last()
	persist.refold()
	_ok("Ctrl+Z brings it back", _live(level, level.brush_by_key(dot)))

	print("-- 2. one piece of a parametric shape --")
	var sdot: String = persist.record("shape.create", {"type": "stairs", "gv": 1, "params": {"steps": 5},
		"frame": SceneObjects.xform_to(Transform3D(Basis.IDENTITY, Vector3(300, 0, 300))),
		"size": [5.0, 2.0, 2.0], "material_id": 0, "level_id": 0})
	persist.refold()
	var pieces: PackedInt32Array = level.get_group_brush_ids(sdot)
	_ok("the shape has its pieces", _live_in_group(level, sdot) == 6, "%d" % _live_in_group(level, sdot))
	map.select_brushes(PackedInt32Array([pieces[0]]))
	map.delete_selection()
	persist.refold()
	_ok("Delete on ONE piece removed the WHOLE shape", _live_in_group(level, sdot) == 0, "%d" % _live_in_group(level, sdot))
	var kinds: Array = persist.records().map(func(r: Dictionary) -> String: return String(r["kind"]))
	_ok("via shape.remove (not one brush.remove per piece)", kinds.has("shape.remove") and kinds.count("brush.remove") == 1,
		str(kinds))
	persist.undo_last()
	persist.refold()
	_ok("Ctrl+Z brings the shape back", _live_in_group(level, sdot) == 6, "%d" % _live_in_group(level, sdot))