extends SceneTree const FINALIZER_SCRIPT := preload( "res://src/render/m2/m2_animation_resource_finalizer.gd" ) const PIPELINE_SCRIPT := preload( "res://src/render/m2/m2_animation_load_pipeline_state.gd" ) const PROTOTYPE_CACHE_SCRIPT := preload( "res://src/render/m2/m2_prototype_cache_state.gd" ) const FINALIZER_PATH := "res://src/render/m2/m2_animation_resource_finalizer.gd" const LOADER_PATH := "res://src/scenes/streaming/streaming_world_loader.gd" class FakeResourceLoaderAdapter extends RefCounted: var statuses: Dictionary = {} var resources: Dictionary = {} var status_paths: Array[String] = [] var load_paths: Array[String] = [] func load_threaded_get_status(resource_path: String) -> int: status_paths.append(resource_path) return int(statuses.get( resource_path, ResourceLoader.THREAD_LOAD_IN_PROGRESS )) func load_threaded_get(resource_path: String) -> Resource: load_paths.append(resource_path) return resources.get(resource_path, null) as Resource class FakeAnimatedSceneFinalizer extends RefCounted: var candidate_by_resource: Dictionary = {} var finalization_by_candidate: Dictionary = {} var instantiated_resources: Array[Resource] = [] var repaired_candidates: Array[Node3D] = [] var repaired_material_sources: Array[Node3D] = [] func instantiate_candidate(resource: Resource) -> Node3D: instantiated_resources.append(resource) return candidate_by_resource.get(resource, null) as Node3D func repair_materials(candidate: Node3D, material_source: Node3D) -> void: repaired_candidates.append(candidate) repaired_material_sources.append(material_source) func finalize_candidate(candidate: Node3D) -> Dictionary: return finalization_by_candidate.get(candidate, {}) as Dictionary class EmptyPathPipeline extends RefCounted: var discarded_path: String = "" func request_records_snapshot() -> Array[Dictionary]: return [{"normalized": "world/empty.m2", "path": ""}] func discard_request(normalized_relative_path: String) -> bool: discarded_path = normalized_relative_path return true func _initialize() -> void: var failures: Array[String] = [] _verify_polling(failures) _verify_empty_path_polling(failures) _verify_terminal_rejections(failures) _verify_preparation_and_adoption(failures) _verify_finalize_rejection(failures) _verify_source_boundaries(failures) var elapsed_milliseconds := _verify_bounded_timing(failures) if not failures.is_empty(): for failure in failures: push_error("M2_ANIMATION_RESOURCE_FINALIZER: %s" % failure) quit(1) return print( "M2_ANIMATION_RESOURCE_FINALIZER PASS " + "cases=28 iterations=1000 elapsed_ms=%.3f" % elapsed_milliseconds ) quit(0) func _verify_polling(failures: Array[String]) -> void: var resource_loader := FakeResourceLoaderAdapter.new() var scene_finalizer := FakeAnimatedSceneFinalizer.new() var service: RefCounted = FINALIZER_SCRIPT.new(scene_finalizer, resource_loader) var pipeline: RefCounted = PIPELINE_SCRIPT.new() var prototype_cache: RefCounted = PROTOTYPE_CACHE_SCRIPT.new() for request in [ ["world/pending.m2", "res://pending.tscn"], ["world/loaded.m2", "res://loaded.tscn"], ["world/failed.m2", "res://failed.tscn"], ]: pipeline.call("remember_request", request[0], request[1]) resource_loader.statuses = { "res://pending.tscn": ResourceLoader.THREAD_LOAD_IN_PROGRESS, "res://loaded.tscn": ResourceLoader.THREAD_LOAD_LOADED, "res://failed.tscn": ResourceLoader.THREAD_LOAD_FAILED, } _expect_equal( int(service.call("poll_terminal_requests", pipeline, prototype_cache)), 2, "two terminal requests completed", failures ) _expect_equal( int(pipeline.call("pending_request_count")), 1, "pending request retained", failures ) _expect_equal( int(pipeline.call("finalize_record_count")), 2, "terminal FIFO receives two records", failures ) _expect_string_array( resource_loader.status_paths, ["res://pending.tscn", "res://loaded.tscn", "res://failed.tscn"], "status polling insertion order", failures ) prototype_cache.call("clear_and_release") func _verify_empty_path_polling(failures: Array[String]) -> void: var resource_loader := FakeResourceLoaderAdapter.new() var service: RefCounted = FINALIZER_SCRIPT.new( FakeAnimatedSceneFinalizer.new(), resource_loader ) var pipeline := EmptyPathPipeline.new() var prototype_cache: RefCounted = PROTOTYPE_CACHE_SCRIPT.new() _expect_equal( int(service.call("poll_terminal_requests", pipeline, prototype_cache)), 1, "empty resource path completed", failures ) _expect_string_equal( pipeline.discarded_path, "world/empty.m2", "empty resource path discarded", failures ) _expect_true( bool(prototype_cache.call("is_animation_static", "world/empty.m2")), "empty resource path marks static", failures ) _expect_equal(resource_loader.status_paths.size(), 0, "empty path skips I/O", failures) prototype_cache.call("clear_and_release") func _verify_terminal_rejections(failures: Array[String]) -> void: var resource_loader := FakeResourceLoaderAdapter.new() var scene_finalizer := FakeAnimatedSceneFinalizer.new() var service: RefCounted = FINALIZER_SCRIPT.new(scene_finalizer, resource_loader) var pipeline: RefCounted = PIPELINE_SCRIPT.new() var prototype_cache: RefCounted = PROTOTYPE_CACHE_SCRIPT.new() _expect_dictionary_empty( service.call("prepare_next_candidate", pipeline, prototype_cache), "empty finalize FIFO", failures ) _enqueue_terminal( pipeline, "world/failed.m2", "res://failed.tscn", ResourceLoader.THREAD_LOAD_FAILED ) _expect_dictionary_empty( service.call("prepare_next_candidate", pipeline, prototype_cache), "failed terminal record rejects", failures ) _expect_true( bool(prototype_cache.call("is_animation_static", "world/failed.m2")), "failed terminal record marks static", failures ) var cached := Node3D.new() prototype_cache.call("adopt_animated_prototype", "world/cached.m2", cached) _enqueue_terminal( pipeline, "world/cached.m2", "res://cached.tscn", ResourceLoader.THREAD_LOAD_LOADED ) _expect_dictionary_empty( service.call("prepare_next_candidate", pipeline, prototype_cache), "cached terminal record skipped", failures ) prototype_cache.call("mark_animation_static", "world/static.m2") _enqueue_terminal( pipeline, "world/static.m2", "res://static.tscn", ResourceLoader.THREAD_LOAD_LOADED ) _expect_dictionary_empty( service.call("prepare_next_candidate", pipeline, prototype_cache), "static terminal record skipped", failures ) _enqueue_terminal(pipeline, "world/null.m2", "res://null.tscn", ResourceLoader.THREAD_LOAD_LOADED) _expect_dictionary_empty( service.call("prepare_next_candidate", pipeline, prototype_cache), "null Resource candidate rejects", failures ) _expect_true( bool(prototype_cache.call("is_animation_static", "world/null.m2")), "null Resource candidate marks static", failures ) _expect_string_array( resource_loader.load_paths, ["res://null.tscn"], "only uncached loaded record performs terminal get", failures ) prototype_cache.call("clear_and_release") func _verify_preparation_and_adoption(failures: Array[String]) -> void: var resource_loader := FakeResourceLoaderAdapter.new() var scene_finalizer := FakeAnimatedSceneFinalizer.new() var service: RefCounted = FINALIZER_SCRIPT.new(scene_finalizer, resource_loader) var pipeline: RefCounted = PIPELINE_SCRIPT.new() var prototype_cache: RefCounted = PROTOTYPE_CACHE_SCRIPT.new() var packed_scene := PackedScene.new() var candidate := Node3D.new() var prototype := Node3D.new() var material_source := Node3D.new() resource_loader.resources["res://animated.tscn"] = packed_scene scene_finalizer.candidate_by_resource[packed_scene] = candidate scene_finalizer.finalization_by_candidate[candidate] = { "prototype": prototype, "animation_player_count": 3, } _enqueue_terminal( pipeline, "world/animated.m2", "res://animated.tscn", ResourceLoader.THREAD_LOAD_LOADED ) var preparation: Dictionary = service.call( "prepare_next_candidate", pipeline, prototype_cache ) _expect_same(preparation.get("candidate"), candidate, "candidate identity", failures) _expect_string_equal( String(preparation.get("normalized", "")), "world/animated.m2", "prepared normalized path", failures ) _expect_string_equal( String(preparation.get("path", "")), "res://animated.tscn", "prepared Resource path", failures ) var adopted: Node3D = service.call( "finalize_prepared_candidate", preparation, material_source, prototype_cache, false ) _expect_same(adopted, prototype, "adopted prototype identity", failures) _expect_same( prototype_cache.call("find_animated_prototype", "world/animated.m2"), prototype, "prototype cache adoption", failures ) _expect_same(scene_finalizer.repaired_candidates[0], candidate, "repair candidate", failures) _expect_same( scene_finalizer.repaired_material_sources[0], material_source, "repair material source", failures ) prototype_cache.call("clear_and_release") material_source.free() candidate.free() func _verify_finalize_rejection(failures: Array[String]) -> void: var scene_finalizer := FakeAnimatedSceneFinalizer.new() var service: RefCounted = FINALIZER_SCRIPT.new( scene_finalizer, FakeResourceLoaderAdapter.new() ) var prototype_cache: RefCounted = PROTOTYPE_CACHE_SCRIPT.new() var candidate := Node3D.new() _expect_null( service.call( "finalize_prepared_candidate", {"normalized": "world/rejected.m2", "candidate": candidate}, null, prototype_cache ), "rejected finalization returns null", failures ) _expect_true( bool(prototype_cache.call("is_animation_static", "world/rejected.m2")), "rejected finalization marks static", failures ) candidate.free() prototype_cache.call("clear_and_release") func _verify_source_boundaries(failures: Array[String]) -> void: var loader_source := FileAccess.get_file_as_string(LOADER_PATH) var service_source := FileAccess.get_file_as_string(FINALIZER_PATH) var drain_start := loader_source.find("func _drain_m2_animation_loads()") var drain_end := loader_source.find("func _drain_m2_mesh_loads()", drain_start) var drain_source := loader_source.substr(drain_start, drain_end - drain_start) _expect_true( drain_source.contains("_m2_animation_resource_finalizer.poll_terminal_requests("), "loader delegates polling", failures ) _expect_true( drain_source.contains("_m2_animation_resource_finalizer.prepare_next_candidate("), "loader delegates candidate preparation", failures ) _expect_true( drain_source.contains("_m2_animation_resource_finalizer.finalize_prepared_candidate("), "loader delegates finalization", failures ) for removed_token in [ "ResourceLoader.load_threaded_get_status", "ResourceLoader.load_threaded_get(", "_m2_animated_scene_finalizer.instantiate_candidate", "_m2_animated_scene_finalizer.repair_materials", "_m2_animated_scene_finalizer.finalize_candidate", "M2_ANIM_CACHE path=", ]: _expect_false(drain_source.contains(removed_token), "loader omits %s" % removed_token, failures) for required_token in [ "ResourceLoader.load_threaded_get_status", "ResourceLoader.load_threaded_get(", "\"instantiate_candidate\"", "\"repair_materials\"", "\"finalize_candidate\"", "M2_ANIM_CACHE path=%s cache=%s players=%d", ]: _expect_true( service_source.contains(required_token), "service owns %s" % required_token, failures ) func _verify_bounded_timing(failures: Array[String]) -> float: var service: RefCounted = FINALIZER_SCRIPT.new( FakeAnimatedSceneFinalizer.new(), FakeResourceLoaderAdapter.new() ) var pipeline: RefCounted = PIPELINE_SCRIPT.new() var prototype_cache: RefCounted = PROTOTYPE_CACHE_SCRIPT.new() var started_microseconds := Time.get_ticks_usec() for iteration in range(1000): service.call("poll_terminal_requests", pipeline, prototype_cache) var elapsed_milliseconds := float( Time.get_ticks_usec() - started_microseconds ) / 1000.0 _expect_true(elapsed_milliseconds < 1000.0, "empty polling remains bounded", failures) prototype_cache.call("clear_and_release") return elapsed_milliseconds func _enqueue_terminal( pipeline: RefCounted, normalized_relative_path: String, resource_path: String, status: int ) -> void: pipeline.call("remember_request", normalized_relative_path, resource_path) pipeline.call("complete_request", normalized_relative_path, status) func _expect_true(condition: bool, label: String, failures: Array[String]) -> void: if not condition: failures.append(label) func _expect_false(condition: bool, label: String, failures: Array[String]) -> void: _expect_true(not condition, label, failures) func _expect_null(actual: Variant, label: String, failures: Array[String]) -> void: _expect_true(actual == null, label, failures) func _expect_same( actual: Variant, expected: Variant, label: String, failures: Array[String] ) -> void: _expect_true(is_same(actual, expected), label, failures) func _expect_dictionary_empty( actual: Variant, label: String, failures: Array[String] ) -> void: _expect_true(actual is Dictionary and (actual as Dictionary).is_empty(), label, failures) func _expect_equal(actual: int, expected: int, label: String, failures: Array[String]) -> void: if actual != expected: failures.append("%s expected=%d actual=%d" % [label, expected, actual]) func _expect_string_equal( actual: String, expected: String, label: String, failures: Array[String] ) -> void: if actual != expected: failures.append("%s expected=%s actual=%s" % [label, expected, actual]) func _expect_string_array( actual: Array[String], expected: Array[String], label: String, failures: Array[String] ) -> void: if actual != expected: failures.append("%s expected=%s actual=%s" % [label, expected, actual])