extends SceneTree ## Synthetic predicate, memoization, boundary and timing regression for stale ## cached M2 runtime mesh rebuild decisions. const CLASSIFIER_SCRIPT := preload( "res://src/render/m2/m2_runtime_mesh_rebuild_classifier.gd" ) const CLASSIFIER_PATH := "res://src/render/m2/m2_runtime_mesh_rebuild_classifier.gd" const LOADER_PATH := "res://src/scenes/streaming/streaming_world_loader.gd" func _initialize() -> void: var failures: Array[String] = [] _verify_billboard_decisions(failures) _verify_uv_rotation_decisions(failures) _verify_stage_and_index_boundaries(failures) _verify_memoization_clear_and_diagnostics(failures) _verify_ownership_boundaries(failures) var elapsed_milliseconds := _verify_bounded_timing(failures) if not failures.is_empty(): for failure in failures: push_error("M2_RUNTIME_MESH_REBUILD_CLASSIFIER: %s" % failure) quit(1) return print( "M2_RUNTIME_MESH_REBUILD_CLASSIFIER PASS cases=12 iterations=100 elapsed_ms=%.3f" % elapsed_milliseconds ) quit(0) func _verify_billboard_decisions(failures: Array[String]) -> void: _expect_false(_classify("empty", {}), "empty data does not rebuild", failures) _expect_false( _classify("invalid", {"batches": ["invalid", 7, null]}), "non-Dictionary batches skipped", failures ) _expect_true( _classify("flag", {"batches": [{"has_billboard": true}]}), "billboard flag rebuilds", failures ) _expect_true( _classify("vertices", {"batches": [{"billboard_vertex_count": 1}]}), "positive billboard vertex count rebuilds", failures ) _expect_false( _classify("zero_vertices", {"batches": [{"billboard_vertex_count": 0}]}), "zero billboard vertex count does not rebuild", failures ) func _verify_uv_rotation_decisions(failures: Array[String]) -> void: _expect_false( _classify("identity", _uv_data([_rotation_transform()])), "identity UV rotation does not rebuild", failures ) _expect_true( _classify( "rotation", _uv_data([_rotation_transform(Vector4(0.0, 1.0, -1.0, 0.0))]) ), "non-identity UV rotation rebuilds", failures ) _expect_true( _classify("positive_speed", _uv_data([_rotation_transform(Vector4(1, 0, 0, 1), 0.000002)])), "positive UV rotation speed rebuilds", failures ) _expect_true( _classify("negative_speed", _uv_data([_rotation_transform(Vector4(1, 0, 0, 1), -0.000002)])), "negative UV rotation speed rebuilds", failures ) _expect_false( _classify("epsilon", _uv_data([_rotation_transform(Vector4(1, 0, 0, 1), 0.000001)])), "exact UV rotation epsilon does not rebuild", failures ) func _verify_stage_and_index_boundaries(failures: Array[String]) -> void: var fifth_stage_transforms: Array = [ _rotation_transform(), _rotation_transform(), _rotation_transform(), _rotation_transform(), _rotation_transform(Vector4(0.0, 1.0, -1.0, 0.0)), ] _expect_false( _classify( "fifth_stage", _uv_data(fifth_stage_transforms, PackedInt32Array([0, 1, 2, 3, 4]), 5) ), "fifth texture stage remains ignored", failures ) _expect_false( _classify( "invalid_indices", _uv_data([_rotation_transform(Vector4(0, 1, -1, 0))], PackedInt32Array([-1, 9]), 2) ), "invalid transform indices skipped", failures ) _expect_false( _classify( "invalid_transform", _uv_data(["not-a-transform"], PackedInt32Array([0]), 1) ), "non-Dictionary transform uses identity defaults", failures ) func _verify_memoization_clear_and_diagnostics(failures: Array[String]) -> void: var classifier: RefCounted = CLASSIFIER_SCRIPT.new() var billboard_data := {"batches": [{"has_billboard": true}]} _expect_true( classifier.call("needs_runtime_mesh_rebuild", "world/tree.m2", billboard_data), "first true decision", failures ) _expect_true( classifier.call("needs_runtime_mesh_rebuild", "world/tree.m2", {}), "first path decision memoized", failures ) classifier.call("needs_runtime_mesh_rebuild", "world/rock.m2", {}) _expect_equal(int(classifier.call("cached_path_count")), 2, "cached path count", failures) var snapshot: Dictionary = classifier.call("diagnostic_snapshot") snapshot["world/tree.m2"] = false _expect_true( classifier.call("needs_runtime_mesh_rebuild", "world/tree.m2", {}), "diagnostics detached", failures ) classifier.call("clear") _expect_equal(int(classifier.call("cached_path_count")), 0, "clear count", failures) _expect_false( classifier.call("needs_runtime_mesh_rebuild", "world/tree.m2", {}), "clear allows recomputation", failures ) func _verify_ownership_boundaries(failures: Array[String]) -> void: var classifier_source := FileAccess.get_file_as_string(CLASSIFIER_PATH) var loader_source := FileAccess.get_file_as_string(LOADER_PATH) _expect_true( loader_source.contains("M2_RUNTIME_MESH_REBUILD_CLASSIFIER_SCRIPT.new()"), "loader composes classifier", failures ) _expect_equal( loader_source.count("_m2_runtime_mesh_rebuild_classifier.clear()"), 2, "loader retains two classifier clear sites", failures ) _expect_false( loader_source.contains("_m2_runtime_rebuild_required_cache"), "loader removes legacy rebuild cache", failures ) for removed_function in [ "func _m2_raw_data_needs_runtime_mesh_rebuild", "func _m2_raw_data_has_billboards", "func _m2_raw_data_has_uv_rotation", ]: _expect_false(loader_source.contains(removed_function), "loader removes %s" % removed_function, failures) for forbidden_dependency in [ "ResourceLoader.", "WorkerThreadPool.", "M2_BUILDER_SCRIPT", "ClassDB.instantiate", "FileAccess.", ]: _expect_false( classifier_source.contains(forbidden_dependency), "classifier omits %s dependency" % forbidden_dependency, failures ) func _verify_bounded_timing(failures: Array[String]) -> float: var classifier: RefCounted = CLASSIFIER_SCRIPT.new() var ordinary_data := {"batches": [{"has_billboard": false}]} var started_microseconds := Time.get_ticks_usec() for iteration in range(100): for path_index in range(256): classifier.call( "needs_runtime_mesh_rebuild", "world/model_%d.m2" % path_index, ordinary_data ) classifier.call("clear") var elapsed_milliseconds := float(Time.get_ticks_usec() - started_microseconds) / 1000.0 _expect_true(elapsed_milliseconds < 1000.0, "100 by 256 classifications under 1 second", failures) return elapsed_milliseconds func _classify(normalized_path: String, raw_data: Dictionary) -> bool: var classifier: RefCounted = CLASSIFIER_SCRIPT.new() return bool(classifier.call("needs_runtime_mesh_rebuild", normalized_path, raw_data)) func _uv_data( texture_transforms: Array, texture_transform_combos: PackedInt32Array = PackedInt32Array([0]), texture_count: int = 1) -> Dictionary: return { "texture_transforms": texture_transforms, "texture_transform_combos": texture_transform_combos, "batches": [{ "texture_count": texture_count, "texture_transform_combo_index": 0, }], } func _rotation_transform( rotation: Vector4 = Vector4(1.0, 0.0, 0.0, 1.0), rotation_speed: float = 0.0) -> Dictionary: return { "rotation": rotation, "rotation_speed": rotation_speed, } 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_equal(actual: int, expected: int, label: String, failures: Array[String]) -> void: if actual != expected: failures.append("%s expected=%d actual=%d" % [label, expected, actual])