extends Node
## GATE — G AND SHIFT+D ON A UNION SELECTION, 5c (#120 §17.10).
## V1 G on a box + an object + a curve moves all three by the same delta, ONE gesture
## V2 Esc puts all three back and writes nothing
## V3 Shift+D copies all three in ONE gesture; the copies are selected and Move is up
## V4 ... confirming that Move moves the copies; the originals stay
##
## RUN AS A SCENE: "$HYPER_TPS_GODOT" --headless res://scenes/test/gate_union_move.tscn
var fails := 0
var checks := 0
var map: Node3D
var persist: Node
func _ok(what: String, cond: bool, note: Variant = "") -> void:
checks += 1
if not cond:
fails += 1
print(" %-64s %s %s" % [what, "OK" if cond else "**FAIL**", str(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"
get_tree().root.get_node("/root/GameMode").set_mode("build")
map = (load("res://scenes/maps/map_dev_test.tscn") as PackedScene).instantiate()
add_child(map)
for i in 6:
await get_tree().process_frame
await _run()
get_tree().root.get_node("/root/GameMode").set_mode("play")
if checks < 9:
print(" **FAIL** only %d checks ran -- setup died before the assertions" % checks)
fails += 1
print("\nGATE union_move: %s (%d checks, %d failed)" % ["PASS" if fails == 0 else "FAIL", checks, fails])
get_tree().quit(0 if fails == 0 else 1)
func _gestures() -> int:
return (persist.gestures(true) as Array).size()
func _box_at(d: String) -> Vector3:
return (persist.shape_state(d)["frame"] as Transform3D).origin
func _obj_at(d: String) -> Vector3:
return (map.object_node(d) as Node3D).global_position
func _curve_at(d: String) -> Vector3:
return (map.curve_states()[d]["points"] as Array)[0]["p"]
func _select_three(box: String, obj: String, c: String) -> void:
map.select_shape(box)
map.select_object(obj, true)
map.select_curve(c, true)
func _run() -> void:
persist = map.get("_persist")
var ops: Node = map.call("_ensure_ops")
var mv: Node = map.get("_move")
var P := Vector3(500.1, 1.0, 500.3)
persist.begin_gesture("box")
var box: String = persist.record("shape.create", {"type": "box", "gv": 1, "params": {},
"frame": SceneObjects.xform_to(Transform3D(Basis.IDENTITY, P)), "size": [1, 1, 1],
"material_id": 2, "level_id": 0})
persist.end_gesture()
persist.refold()
var obj: String = map.create_object(PrefabCatalogue.ids()[0], Transform3D(Basis.IDENTITY, P + Vector3(3, 0, 0)))
var c: String = map.create_curve([CurveMath.point(P + Vector3(0, 0, 4)), CurveMath.point(P + Vector3(2.1, 0, 4))], false, "V")
_ok("setup", box != "" and obj != "" and c != "")
var b0 := _box_at(box)
var o0 := _obj_at(obj)
var c0 := _curve_at(c)
# ---- V1 ----
_select_three(box, obj, c)
var g0 := _gestures()
_ok("V1 G starts on the union", ops.activate(mv))
mv.set_tool_setting("axis", 0)
mv.set_tool_setting("distance", 4)
ops.confirm()
persist.refold()
var db := _box_at(box) - b0
var do := _obj_at(obj) - o0
var dc := _curve_at(c) - c0
_ok("V1 all three moved by the same +x", db.x > 0.0 and db.is_equal_approx(do) and db.is_equal_approx(dc), [db, do, dc])
_ok("V1 ... in ONE gesture", _gestures() == g0 + 1, _gestures() - g0)
# ---- V2 ----
var b1 := _box_at(box)
var o1 := _obj_at(obj)
var c1 := _curve_at(c)
_select_three(box, obj, c)
var g1 := _gestures()
ops.activate(mv)
mv.set_tool_setting("distance", 3)
await get_tree().process_frame
ops.cancel()
persist.refold()
_ok("V2 Esc: all three back, nothing written", _box_at(box).is_equal_approx(b1) and _obj_at(obj).is_equal_approx(o1)
and _curve_at(c).is_equal_approx(c1) and _gestures() == g1)
# ---- V3 / V4 ----
_select_three(box, obj, c)
var shapes0: Array = (persist.live_shapes() as Dictionary).keys()
var curves0: Array = map.curve_states().keys()
var objs0: Array = (map.get_node("SceneObjects").entries() as Array).map(func(e: Dictionary) -> String: return String(e["dot"]))
var g2 := _gestures()
map.duplicate_selection()
var new_shapes: Array = (persist.live_shapes() as Dictionary).keys().filter(func(d: String) -> bool: return not shapes0.has(d))
var new_curves: Array = map.curve_states().keys().filter(func(d: String) -> bool: return not curves0.has(d))
var new_objs: Array = (map.get_node("SceneObjects").entries() as Array).map(func(e: Dictionary) -> String: return String(e["dot"])) \
.filter(func(d: String) -> bool: return not objs0.has(d))
_ok("V3 Shift+D copies all three", new_shapes.size() == 1 and new_curves.size() == 1 and new_objs.size() == 1,
[new_shapes, new_curves, new_objs])
_ok("V3 ... in ONE gesture", _gestures() == g2 + 1, _gestures() - g2)
_ok("V3 ... the copies are selected and Move is up", ops.get("active") == mv and map.selected_objects() == new_objs
and map.selected_curves() == new_curves and new_shapes.size() == 1 and map.selected_shape() == String(new_shapes[0]),
[ops.get("active"), map.selected_objects(), map.selected_curves()])
if new_shapes.size() == 1 and new_curves.size() == 1 and new_objs.size() == 1:
mv.set_tool_setting("axis", 2)
mv.set_tool_setting("distance", 5)
ops.confirm()
persist.refold()
_ok("V4 the copies moved, the originals stayed", _box_at(String(new_shapes[0])).z > _box_at(box).z + 0.5
and _obj_at(String(new_objs[0])).z > _obj_at(obj).z + 0.5 and _curve_at(String(new_curves[0])).z > _curve_at(c).z + 0.5
and _box_at(box).is_equal_approx(b1))