extends SceneTree const Scene = preload("res://game_scene.gd") const View = preload("res://ui/player_view.gd") class Client extends Node: var main := 0 var rows := {} func get_main_vid() -> int: return main func get_entity(vid: int) -> Dictionary: return rows.get(vid, {}) class StubView extends Node3D: var anim: Node var succeeds := true var during_build := Callable() func build(_assets: String, _race: int, _pump: Callable) -> bool: if during_build.is_valid(): during_build.call() return succeeds func set_audio(_node: Node) -> void: pass class Harness extends Scene: var builds := 0 var succeeds := true var during_build := Callable() func _create_main_view() -> Node3D: builds += 1 var view := StubView.new() view.succeeds = succeeds view.during_build = during_build return view class Controller extends Node: signal anim_state(state: String) var player: Node3D class Camera extends Camera3D: var target: Node3D var failures := 0 func check(value: bool, label: String) -> void: if not value: failures += 1 printerr("FAIL: " + label) func _initialize() -> void: call_deferred("run") func run() -> void: var client := Client.new() var scene := Harness.new() root.add_child(client) root.add_child(scene) scene.set_process(false) scene.client = client scene._assets = "synthetic-assets" scene.player = Node3D.new() scene.add_child(scene.player) scene.pc = Controller.new() scene.add_child(scene.pc) scene.cam = Camera.new() scene.add_child(scene.cam) scene._sync_main_character() check(scene.builds == 0, "setup incomplete does not build") scene._main_sync_ready = true client.main = 10 scene._sync_main_character() check(scene.builds == 0, "late entity is awaited") client.rows[10] = {"pos": Vector3(20, 0, -30)} scene._sync_main_character() check(scene.builds == 0, "missing race does not build") check(scene.player.position == Vector3(20, 0, 30), "late row places placeholder") client.rows[10].race = 0 scene.during_build = func(): scene._on_main_set(10) scene._sync_main_character() check(scene.builds == 1 and scene._model_built, "reentrant network event creates one view") check(scene.cam.target == scene.player and scene.pc.player == scene.player, "replacement updates consumers") scene.player.position = Vector3(25, 0, 35) for i in 5: scene._sync_main_character() scene._on_main_set(10) check(scene.builds == 1, "duplicate main events are idempotent") check(scene.player.position == Vector3(25, 0, 35), "polling does not undo movement") client.main = 20 client.rows[20] = {"race": 1, "pos": Vector3(40, 0, -50)} scene.during_build = Callable() scene.succeeds = false scene._sync_main_character() check(scene.builds == 2 and not scene._model_built, "failed replacement is not marked ready") for i in 5: scene._sync_main_character() check(scene.builds == 2, "failure does not retry every frame") scene._main_retry_at = 0 scene.succeeds = true scene._sync_main_character() check(scene.builds == 3 and scene._model_built, "transient failure recovers") check(scene.pc.anim_state.get_connections().size() == 1, "replacement does not duplicate animation subscriptions") var previous = scene.player client.main = 30 client.rows[30] = {"race": 0, "pos": Vector3.ZERO} scene.during_build = func(): client.main = 40 scene._sync_main_character() check(scene.player == previous, "obsolete build is discarded") client.rows[40] = {"race": 0, "pos": Vector3.ZERO} scene.during_build = Callable() scene.succeeds = false for i in 5: scene._main_retry_at = 0 scene._sync_main_character() check(scene._main_attempts == 3, "permanent failure has bounded attempts") var view := View.new() check(not view.build("missing-assets", 8), "unsupported race rejected") view.free() scene.queue_free() client.queue_free() await process_frame print("main_character_sync_test: failures=", failures) quit(1 if failures else 0)