extends SceneTree
## Gate: MOVE shows the actual brush moving (proxy mesh), not just its outline
## (docs/editor-texturing-selection-move.md §4; user 2026-10-03).
##
## Activation hides the brush (one rebuild) and puts its own mesh, with the LEVEL
## material, under the level; the drag moves that proxy (and, with texture lock, shifts
## its texture projection by the same delta); confirm unhides + translates; cancel
## unhides and leaves the brush where it was. Measured motivation: _probe_move_cost.
##
## Run: HYPERTPS_DAEMON_TCP=127.0.0.1:1 "$HYPER_TPS_GODOT" --headless --path . --script res://scenes/test/gate_move_proxy.gd
var ok := true
var checks := 0
var _frame := 0
var _map: 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:
_map = (load("res://scenes/maps/map_flat.tscn") as PackedScene).instantiate()
root.add_child(_map)
return false
if _frame < 30:
return false
_run()
if checks < 12:
_p(false, "only %d checks ran" % checks)
print("GATE move_proxy: %s (%d checks)" % ["PASS" if ok else "FAIL", checks])
quit(0 if ok else 1)
return true
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 _proxies(level: Node) -> Array:
var out: Array = []
for c in level.get_children():
if String(c.name).begins_with("MoveProxy_") and not c.is_queued_for_deletion():
out.append(c)
return out
func _run() -> void:
var level: Node = _map.get_node("DCLevel")
var persist: Node = _map.get("_persist")
var keet: Node = root.get_node_or_null("/root/KeetService")
if keet != null:
keet.current_member_id = "gate-author"
var gs: Node = root.get_node_or_null("/root/GameState")
if gs != null:
gs.route("world:level:*", 1, "peer")
var ft: Array = []
for i in 6:
ft.append({"tex": "kenney-prototype/dark_01", "mode": 1})
var dot: String = persist.record("brush.create", {"planes": _box(Vector3(0, 0, 0), Vector3(1, 1, 1)),
"proj": [], "material_id": 1, "level_id": 0, "sky": false, "face_tex": ft})
persist.refold()
var b: int = level.brush_by_key(dot)
var lo0: Vector3 = level.get_brush(b)["aabb_min"]
_p(level.has_method("get_brush_mesh"), "DCLevel exposes get_brush_mesh (rebuilt extension)")
if not level.has_method("get_brush_mesh"):
return
var bm: Mesh = level.get_brush_mesh(b)
_p(bm != null and bm.get_surface_count() == 1 and (bm.surface_get_arrays(0)[Mesh.ARRAY_VERTEX] as PackedVector3Array).size() == 36,
"brush mesh: one surface, 12 triangles for a box")
var stack: Node = _map.call("_ensure_ops")
print("-- activate: the brush is hidden, its proxy stands in --")
_map.select_brushes(PackedInt32Array([b]))
var op := MoveOperator.new()
op.map = _map
op.level = level
_map.add_child(op)
stack.activate(op)
var px := _proxies(level)
_p(px.size() == 1, "one MoveProxy under the level", px.size())
_p(level.is_brush_hidden(b), "the real brush is hidden while moving")
var lm: MeshInstance3D = level.get_node("LevelMesh")
_p(px.size() == 1 and (px[0] as MeshInstance3D).material_override == lm.material_override,
"proxy uses the LEVEL material (same look)")
print("-- drag 3 steps on x --")
op.set("_steps", 3)
op.update_preview()
var d: Vector3 = op.call("_delta")
_p(d.length() > 0.0, "a non-zero drag", d)
if px.size() == 1:
var mi: MeshInstance3D = px[0]
_p(mi.position.is_equal_approx(d), "the proxy moved by the drag", mi.position)
var sh: Variant = mi.get_instance_shader_parameter("tex_lock_shift")
_p(sh is Vector3 and (sh as Vector3).is_equal_approx(d), "texture lock: projection shifted with it", sh)
var ol: Node3D = _map.get("_outline")
_p(ol != null and ol.position.is_equal_approx(d), "the selection outline travels with the proxy",
ol.position if ol != null else "no outline")
print("-- confirm: unhidden, translated, proxy gone --")
stack.confirm()
_p(ol == null or ol.position.is_equal_approx(Vector3.ZERO), "outline back at the origin after the drop")
var lo1: Vector3 = level.get_brush(b)["aabb_min"]
_p(not level.is_brush_hidden(b), "brush visible again")
_p(lo1.is_equal_approx(lo0 + d), "brush translated by the drag", "%s -> %s" % [lo0, lo1])
_p(_proxies(level).is_empty(), "proxy freed")
print("-- cancel: back where it was --")
_map.select_brushes(PackedInt32Array([b]))
var op2 := MoveOperator.new()
op2.map = _map
op2.level = level
_map.add_child(op2)
stack.activate(op2)
op2.set("_steps", 2)
op2.update_preview()
stack.cancel()
_p(not level.is_brush_hidden(b), "cancel: brush visible again")
_p((level.get_brush(b)["aabb_min"] as Vector3).is_equal_approx(lo1), "cancel: not moved")
_p(_proxies(level).is_empty(), "cancel: proxy freed")