OverviewFilesCommitsIssuesDocsReleasesPeers

hyper-tps / scenes / test / gate_shape_texture.gd

127 lines · gd ref:
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"])