extends SceneTree var failures: Array[String] = [] func _init() -> void: _run.call_deferred() func _run() -> void: _check_action_data_schema() _check_chart_schema() _check_effect_schema() _finish() func _check_action_data_schema() -> void: var action_script: Script = load("res://resources/action_data.gd") _expect(action_script != null, "ActionData script should load") if action_script == null: return var action: Resource = action_script.new() _expect(_has_property(action, "input_pattern"), "ActionData should expose input_pattern") _expect(_has_property(action, "startup_beats"), "ActionData should expose startup_beats") _expect(_has_property(action, "active_beats"), "ActionData should expose active_beats") _expect(_has_property(action, "recovery_beats"), "ActionData should expose recovery_beats") _expect(_has_property(action, "knockback_mult_x"), "ActionData should expose knockback_mult_x") _expect(_has_property(action, "knockback_mult_y"), "ActionData should expose knockback_mult_y") _expect_float(float(action.get("knockback_mult_x")), 0.0, "knockback_mult_x should default to zero") _expect_float(float(action.get("knockback_mult_y")), 0.0, "knockback_mult_y should default to zero") _expect(not _has_property(action, "allowed_time_phases"), "ActionData should keep action execution independent from time phase fields") func _check_chart_schema() -> void: var beat_chart_script: Script = load("res://resources/beat_chart.gd") var chart_track_script: Script = load("res://resources/chart_track.gd") var chart_event_script: Script = load("res://resources/chart_event.gd") _expect(beat_chart_script != null, "BeatChart script should load") _expect(chart_track_script != null, "ChartTrack script should load") _expect(chart_event_script != null, "ChartEvent script should load") if beat_chart_script == null or chart_track_script == null or chart_event_script == null: return var chart: Resource = beat_chart_script.new() var track: Resource = chart_track_script.new() var event: Resource = chart_event_script.new() _expect(_has_property(chart, "tracks"), "BeatChart should expose tracks") _expect(_has_property(track, "events"), "ChartTrack should expose events") _expect(_has_property(event, "event_type"), "ChartEvent should expose event_type") _expect(_has_property(event, "payload"), "ChartEvent should expose payload") _expect(_has_property(event, "lead_beats"), "ChartEvent should expose lead_beats") _expect(_has_property(event, "time_phase_mask"), "ChartEvent should expose time_phase_mask") _expect(_has_property(chart, "initial_time_phase"), "BeatChart should expose initial_time_phase") event.set("beat_index", 3) event.set("subdivision", 1) event.set("subdivisions_per_beat", 4) _expect_float(float(event.call("beat_position")), 3.25, "ChartEvent beat_position should include subdivisions") func _check_effect_schema() -> void: for path: String in [ "res://resources/effects/effect_definition.gd", "res://resources/effects/effect_instance.gd", "res://resources/effects/stat_modifier.gd", "res://resources/effects/defense_modifier.gd", "res://resources/effects/action_rule_modifier.gd", ]: _expect(load(path) != null, "%s should load" % path) func _has_property(object: Object, property_name: StringName) -> bool: for property: Dictionary in object.get_property_list(): if StringName(str(property.get("name"))) == property_name: return true return false func _expect(condition: bool, label: String) -> void: if not condition: failures.append(label) func _expect_float(actual: float, expected: float, label: String) -> void: if not is_equal_approx(actual, expected): failures.append("%s: expected %.3f, got %.3f" % [label, expected, actual]) func _finish() -> void: if failures.is_empty(): print("PASS phase 2 schema layer") quit(0) else: for failure: String in failures: push_error(failure) quit(1)