OverviewFilesCommitsIssuesDocsReleasesPeers

hyper-tps / scenes / test / gate_walker_acquire.gd

113 lines · gd ref:
extends SceneTree
## Gate: the walker keeps looking for its body, and finds the REAL one.
##
## THE BUG THIS EXISTS FOR. walker.gd looked the player up once in _bot_init,
## warned "no local player to drive", and returned. Nothing ever tried again, so
## a brain registered a moment before the player existed was dead for its whole
## life. hyper-games #77 item 4 reports it failing "against the real tree every
## time" -- which a one-shot lookup produces whatever the underlying timing is:
## an admin command can land before on_game_started spawns anything, and on a
## --dedicated peer nothing spawns until /start.
##
## ⛔ AND ITS GATE PROVED NOTHING. gate_walker_bot.gd builds its own Game and
## Players and attaches scenes/test/stub_local_player.gd -- a script whose
## is_local_player() returns true unconditionally. It asserted against a tree it
## had constructed to satisfy the code under test. #77 says so directly. This
## gate instances the REAL player_procedural.tscn and uses the REAL
## PlayerPosition autoload, so the thing being found is the thing that ships.

var ok := true
var _ran := false

const PLAYER_SCENE := "res://scenes/player/player_procedural.tscn"


func _p(c: bool, m: String) -> void:
	print(("ok   " if c else "FAIL: ") + m)
	if not c:
		ok = false


func _process(_delta: float) -> bool:
	if _ran:
		return true
	_ran = true
	_run()
	print("GATE walker_acquire: %s" % ("PASS" if ok else "FAIL"))
	if not ok:
		quit(1)
	return true


func _run() -> void:
	var pp: Node = root.get_node_or_null("PlayerPosition")
	_p(pp != null, "PlayerPosition autoload present")
	if pp == null:
		return
	_p(pp.has_method("get_local_player"),
		"PlayerPosition exposes get_local_player() -- the maintained handle")
	if not pp.has_method("get_local_player"):
		return
	_p(pp.get_local_player() == null, "with nothing attached it returns null")

	var brain_script: GDScript = load("res://bots/walker.gd")
	_p(brain_script != null, "walker.gd loads")
	if brain_script == null:
		return

	# ---- 1. no body yet: init must NOT be terminal ----
	var w: Object = brain_script.new()
	w.call("_bot_init")
	_p(w.get("_input") == null, "with no player, the walker has not acquired one")
	# A tick before anything exists must not throw and must not acquire.
	w.call("_bot_tick", 2.0)
	_p(w.get("_input") == null, "and a tick with no player still acquires nothing")

	# ---- 2. the REAL player scene appears afterwards ----
	var ps: PackedScene = load(PLAYER_SCENE)
	_p(ps != null, "the real player scene loads")
	if ps == null:
		return
	var player: Node = ps.instantiate()
	player.name = "RealPlayer"
	root.add_child(player)
	_p(player.get_node_or_null(^"InputSync") != null,
		"the real player carries an InputSync (this is what the stub faked)")

	pp.call("attach_local_player", player)
	_p(pp.get_local_player() == player, "PlayerPosition now holds the real player")

	# The walker must pick it up on a later tick -- the whole point of the fix.
	w.call("_bot_tick", 2.0)
	var acquired: Variant = w.get("_input")
	_p(acquired != null, "the walker acquires the player that appeared AFTER _bot_init")
	if acquired != null:
		_p(bool((acquired as Node).get("driven")),
			"and sets driven, so player_input.gd stands down")

	# ---- 3. it drives through the input fields, not a position ----
	var before: Variant = (acquired as Node).get("camera_rotation_y") if acquired != null else null
	w.call("_bot_tick", 1.0)
	if acquired != null:
		_p((acquired as Node).get("camera_rotation_y") != before,
			"ticking steers via camera_rotation_y")
		_p((acquired as Node).get("input_direction") == Vector2(0.0, -1.0),
			"and holds forward on input_direction")

	# ---- 4. releasing hands the player back ----
	w.call("_bot_exit")
	if acquired != null:
		_p(not bool((acquired as Node).get("driven")),
			"_bot_exit clears driven -- a peer is not left unresponsive")

	# SELF-CHECK: the acquisition above must depend on the player actually being
	# there. Detach it and a fresh brain must NOT acquire, or step 2 proved only
	# that _bot_tick runs.
	pp.call("detach_local_player")
	player.queue_free()
	var w2: Object = brain_script.new()
	w2.call("_bot_init")
	w2.call("_bot_tick", 2.0)
	_p(w2.get("_input") == null,
		"self-check: with the player detached, a fresh walker acquires nothing")