extends SceneTree
## GATE — a parametric shape is TEXTURED (docs/parametric-shapes-design.md §13.3).
## The baked tool put the current texture on every solid plane at birth; a shape.create
## generated `face_tex: []`, so making the create tool parametric would have turned
## every new shape grey.
##
## T1 at birth: every plane of every SOLID piece carries the current texture; the
## clearance (air) carries none
## T2 a texture applied with the shape selected writes ONE shape.set {tex}, no
## face.tex (piece names change on every regeneration — a face.tex on one is lost)
## T3 a param edit regenerates the pieces and keeps the texture
## T4 one Ctrl+Z puts the previous texture back
##
## RUN: CI=true HYPERTPS_DAEMON_TCP=127.0.0.1:1 "$GODOT" --headless --path . --script res://scenes/test/gate_shape_texture.gd
var _frame := 0
var _map: Node = null
var fails := 0
var checks := 0
func _p(c: bool, m: String, got: Variant = "") -> void:
checks += 1
if not c:
fails += 1
print(" %-66s %s %s" % [m, "OK" if c else "**FAIL**", str(got)])
func _process(_d: float) -> bool:
_frame += 1
if _frame == 1:
root.get_node("/root/GameMode").set_mode("build")
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")
_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 < 6:
print(" **FAIL** only %d checks ran -- setup died before the assertions" % checks)
fails += 1
print("\nGATE shape_texture: %s (%d checks, %d failed)" % ["PASS" if fails == 0 else "FAIL", checks, fails])
quit(0 if fails == 0 else 1)
return true
func _count(kind: String) -> int:
var n := 0
for r: Dictionary in (_map.get("_persist").records() as Array):
if String(r.get("kind", "")) == kind and not bool(r.get("undone", false)):
n += 1
return n
## {solid: [tex ids seen], clearance: [tex ids seen], planes: total solid planes}
func _textures(dot: String) -> Dictionary:
var solid: Dictionary = {}
var air: Dictionary = {}
var planes := 0
var bare := 0
for b: int in (_map.level.get_group_brush_ids(dot) as PackedInt32Array):
var br: Dictionary = _map.level.get_brush(b)
var fts: Array = br.get("face_tex", [])
var np: int = (br.get("planes", PackedFloat32Array()) as PackedFloat32Array).size() / 4
if bool(br.get("clearance", false)):
for ft: Variant in fts:
if ft is Dictionary and String((ft as Dictionary).get("tex", "")) != "":
air[String(ft["tex"])] = true
continue
planes += np
for i in np:
var ft2: Variant = fts[i] if i < fts.size() else null
if ft2 is Dictionary and String((ft2 as Dictionary).get("tex", "")) != "":
solid[String(ft2["tex"])] = true
else:
bare += 1
return {"solid": solid.keys(), "air": air.keys(), "planes": planes, "bare": bare}
func _run() -> void:
var packs: PackedStringArray = TexturePacks.ids()
var tex_a := String(_map.current_face_tex()["tex"])
var tex_b := ""
for id: Variant in packs:
if String(id) != tex_a:
tex_b = String(id)
break
_p(tex_b != "", "setup: two textures to tell apart", "%s / %s" % [tex_a, tex_b])
var bx: CreateBoxOperator = _map.get("_box")
bx.set_tool_setting("shape", CreateBoxOperator.Shape.STAIRS)
bx.set_tool_setting("size", 4)
bx.adjust_restore({"origin": Vector3.ZERO, "normal": Vector3.UP, "axis": 1,
"view": Vector3(1, 0, 0.01), "material": 0, "level_id": 0})
bx.confirm()
var dot: String = _map.selected_shape()
var t0 := _textures(dot)
_p(t0["bare"] == 0 and t0["solid"] == [tex_a], "T1 every solid plane carries the current texture",
"%d of %d bare, %s" % [t0["bare"], t0["planes"], t0["solid"]])
_p((t0["air"] as Array).is_empty(), "T1 the clearance carries none", t0["air"])
# ---- T2 ----
_map.set_current_tex(tex_b)
var nft := _count("face.tex")
var nset := _count("shape.set")
_map.select_shape(dot)
_map.apply_texture_to_selection()
var t1 := _textures(dot)
_p(_count("shape.set") == nset + 1 and _count("face.tex") == nft, "T2 one shape.set, no face.tex",
"+%d shape.set +%d face.tex" % [_count("shape.set") - nset, _count("face.tex") - nft])
_p(t1["bare"] == 0 and t1["solid"] == [tex_b], "T2 every solid plane now carries the new texture", t1["solid"])
# ---- T3 ----
_map.set_shape_params(dot, {"steps": 3})
var t2 := _textures(dot)
_p(t2["solid"] == [tex_b] and t2["bare"] == 0, "T3 a param edit keeps the texture", t2["solid"])
# ---- T4 ----
var persist: Node = _map.get("_persist")
persist.undo_last() # the steps edit
persist.undo_last() # the texture
persist.refold()
var t3 := _textures(dot)
_p(t3["solid"] == [tex_a], "T4 undo puts the first texture back", t3["solid"])