OverviewFilesCommitsIssuesDocsReleasesPeers

hyper-tps / scenes / test / gate_level_echo_no_refold.gd

100 lines · gd ref:
extends SceneTree
## Gate: LevelPersistence refolds when the journal CHANGES, not when a record is
## re-delivered.
##
## hyper-games #88 Tier 1 #1 (level half). _on_state_changed set _dirty for ANY
## world:level: key, and a refold rebuilds the whole level from the journal. Every
## level edit arrives twice -- set_state emits it locally, then set_value's
## callback echoes the same value back (state_updated -> state_changed) -- so each
## edit refolded the level twice. Until the poll fix it was also once per 3 s.
##
## A real change must still refold: an undo rewrites the SAME key with a new value
## (a tombstone), and a peer's new record is a new key. Both asserted.

var ok := true
var _started := false
var _done := false


class FakeLevel extends Node:
	var folds: int = 0

	func apply_journal(_recs: Array) -> Dictionary:
		folds += 1
		return {"applied": 0, "skipped": 0, "undone": 0, "records": 0}

	func rebuild() -> void:
		pass


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 not _started:
		_started = true
		_run()
	if _done:
		print("GATE level_echo_no_refold: %s" % ("PASS" if ok else "FAIL"))
		quit(0 if ok else 1)
	return false


func _frames(n: int) -> void:
	for i in n:
		await process_frame


func _run() -> void:
	var gs: Node = root.get_node_or_null("GameState")
	_p(gs != null, "GameState autoload present")
	if gs == null:
		_done = true
		return
	gs.install_routes()
	gs.current_map_id = "gate_level_echo_map"

	# load(), not the class name -- naming it compiles it before GameState exists.
	var lp: Node = (load("res://scenes/maps/level_persistence.gd") as GDScript).new()
	var fake := FakeLevel.new()
	root.add_child(fake)
	root.add_child(lp)
	lp.level = fake
	await _frames(2)
	fake.folds = 0

	# A local edit: one refold.
	var dot: String = lp.record("carve", {"type": "sphere", "pos": [1.0, 2.0, 3.0], "radius": 0.6})
	_p(dot != "", "the record was written (dot %s)" % dot)
	await _frames(2)
	_p(fake.folds == 1, "a new record refolds once (folds %d)" % fake.folds)

	# Its own write confirmation: the same key, the same value.
	var cut: int = dot.rfind(":")
	var key: String = lp._op_key(dot.substr(0, cut), int(dot.substr(cut + 1)))
	gs._on_durable_updated("gate-room", "map:%s:%s" % [gs.current_map_id, key], gs.get_state(key))
	await _frames(2)
	_p(fake.folds == 1, "the echo of an unchanged record does NOT refold (folds %d)" % fake.folds)

	# Undo rewrites the same key with a new value: must refold.
	_p(lp.undo_op(dot), "undo wrote a tombstone")
	await _frames(2)
	_p(fake.folds == 2, "a changed value refolds (folds %d)" % fake.folds)

	# A peer's new record: must refold.
	gs._on_durable_updated("gate-room",
			"map:%s:world:level:zed:op:5" % gs.current_map_id,
			{"v": 2, "kind": "carve", "undone": false, "src": "",
			"type": "sphere", "pos": [0.0, 0.0, 0.0], "radius": 0.6})
	await _frames(2)
	_p(fake.folds == 3, "a peer's new record refolds (folds %d)" % fake.folds)

	# A map change must refold even with no key changing.
	gs.map_changing.emit(gs.current_map_id)
	await _frames(2)
	_p(fake.folds == 4, "a map change refolds (folds %d)" % fake.folds)
	_done = true