OverviewFilesCommitsIssuesDocsReleasesPeers

hyper-tps / scenes / test / gate_editor_grid.gd

125 lines · gd ref:
extends SceneTree
## GATE — the active grid drawn on the aimed surface (#31: TrenchBroom GridRenderer).
##   G1  hidden while playing; shown while building, in the Level editor
##   G2  a patch of (2*RADIUS+2) lines each way, every vertex on the world lattice,
##       lifted off the aimed plane along its normal
##   G3  aiming inside one cell does not rebuild; the next cell, a new step or a new
##       surface axis does
##   G4  a wall hit lays the grid on the wall's plane (x constant)
##   G5  hidden in the Bot editor
##   G6  the toggle key flips the per-player pref and hides it
## Through _update_editor_grid with explicit hits (headless has no crosshair camera).
##
## Run: CI=true HYPERTPS_DAEMON_TCP=127.0.0.1:1 "$HYPER_TPS_GODOT" --headless --path . --script res://scenes/test/gate_editor_grid.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:
		var dock := root.get_node("/root/BuildDock")
		dock.set_pref("snap", true)
		dock.set_pref("grid", 5)
		dock.set_pref("grid_view", true)
		_map = (load("res://scenes/maps/map_flat.tscn") as PackedScene).instantiate()
		root.add_child(_map)
		return false
	if _frame < 30:
		return false
	_run()
	print("\n%d checks — %s" % [checks, "PASS" if ok else "FAIL"])
	quit(0 if ok else 1)
	return true


func _on_lattice(v: float, step: float) -> bool:
	return absf(v / step - roundf(v / step)) < 1.0e-3


func _run() -> void:
	var gm := root.get_node("/root/GameMode")
	var dock := root.get_node("/root/BuildDock")
	var lvl: Node = _map
	var floor_hit := {"position": Vector3(3.3, 0.0, -2.1), "normal": Vector3.UP}
	# ---- G1 ----
	gm.set_mode("play")
	lvl._update_editor_grid(floor_hit)
	var g: EditorGrid = lvl.get("_editor_grid")
	_p(g == null or not g.visible, "G1 no grid while playing")
	gm.set_mode("build")
	dock.set_workspace(dock.WS_LEVEL)
	lvl._update_editor_grid(floor_hit)
	g = lvl.get("_editor_grid")
	_p(g != null and g.visible, "G1 grid shown while building in the Level editor")
	if g == null:
		return
	# ---- G2 ----
	var step: float = lvl._grid_step()
	var want := 2 * (2 * EditorGrid.RADIUS + 2)
	_p(g.line_count() == want, "G2 %d lines" % want, g.line_count())
	var lattice := true
	var lifted := true
	var vs := g.verts()
	for v: Vector3 in vs:
		if not (_on_lattice(v.x, step) and _on_lattice(v.z, step)):
			lattice = false
		if absf(v.y - EditorGrid.LIFT) > 1.0e-5:
			lifted = false
	_p(lattice, "G2 every vertex on the world lattice (step %.4f)" % step)
	_p(lifted, "G2 lifted LIFT above the plane, along the normal")
	var spans_aim := false
	for i in range(0, vs.size(), 2):
		var a: Vector3 = vs[i]
		var b: Vector3 = vs[i + 1]
		if is_equal_approx(a.x, b.x) and minf(a.z, b.z) <= -2.1 and maxf(a.z, b.z) >= -2.1 \
				and absf(a.x - 3.3) < step:
			spans_aim = true
	_p(spans_aim, "G2 the patch is around the aimed point")
	# ---- G3 ----
	var same_cell := floor_hit["position"] as Vector3
	same_cell.x = floorf(same_cell.x / step) * step + step * 0.5
	_p(not g.show_at(same_cell, Vector3.UP, step), "G3 same cell: no rebuild")
	_p(g.show_at(same_cell + Vector3(step, 0, 0), Vector3.UP, step), "G3 next cell: rebuild")
	_p(g.show_at(same_cell + Vector3(step, 0, 0), Vector3.UP, step * 2.0), "G3 new step: rebuild")
	_p(g.show_at(same_cell + Vector3(step, 0, 0), Vector3.RIGHT, step * 2.0), "G3 new axis: rebuild")
	# ---- G4 ----
	lvl._update_editor_grid({"position": Vector3(7.0, 1.2, 0.4), "normal": Vector3(-1, 0.1, 0)})
	var wall := true
	for v: Vector3 in g.verts():
		if absf(v.x - (7.0 - EditorGrid.LIFT)) > 1.0e-5:
			wall = false
	_p(wall and g.line_count() == want, "G4 wall hit: grid on x = 7, lifted toward the viewer")
	# ---- G5 ----
	dock.set_workspace(dock.WS_BOT)
	lvl._update_editor_grid(floor_hit)
	_p(not g.visible, "G5 hidden in the Bot editor")
	dock.set_workspace(dock.WS_LEVEL)
	lvl._update_editor_grid(floor_hit)
	_p(g.visible, "G5 back in the Level editor: shown")
	# ---- G6 ----
	var e := InputEventKey.new()
	var kc: int = int(root.get_node("/root/Keymap").binding_of("builder.grid_view").get("key", 0))
	_p(kc == KEY_APOSTROPHE, "G6 bound to apostrophe", kc)
	e.physical_keycode = kc
	e.keycode = kc
	e.pressed = true
	_map._unhandled_key_input(e)
	_p(dock.pref("grid_view", true) == false, "G6 key turns the pref off")
	lvl._update_editor_grid(floor_hit)
	_p(not g.visible, "G6 grid hidden with the pref off")
	_map._unhandled_key_input(e)
	lvl._update_editor_grid(floor_hit)
	_p(dock.pref("grid_view", false) == true and g.visible, "G6 key turns it back on")
	gm.set_mode("play")