extends SceneTree ## Parent-runner precondition gate. Runs headless before the packaged client ## starts; it never opens a network connection or reads credentials. ## ## env: ## MT_PLAYABLE_VALIDATE_CONFIG scenario JSON (required) ## MT_PLAYABLE_SUITE playable|full|soak (default playable) ## MT_PLAYABLE_ASSETS asset root used for map/waypoint checks ## MT_PLAYABLE_SERVERLIST test-mode serverlist override (same value is ## handed to the client, so both resolve alike) ## MT_PLAYABLE_GATE_OUTPUT directory for required-cases.json / server-address.json ## exit: 0 = ready, 2 = configuration/precondition blocked. const Config = preload("res://testing/playable_config.gd") const ServerInfoRes = preload("res://net/serverinfo.gd") func _init() -> void: var path := OS.get_environment("MT_PLAYABLE_VALIDATE_CONFIG") var suite := OS.get_environment("MT_PLAYABLE_SUITE").strip_edges() if suite.is_empty(): suite = "playable" var errors: Array = [] if not (suite in Config.SUITES): errors.append("unknown suite: %s" % suite) var result := Config.load_file(path) errors.append_array(result.errors) # A present soak block is validated for every suite: its confirmed fault proxy also # fronts the playable exit runs that share the scenario. if result.ok and (suite == "soak" or result.config.has("soak")): errors.append_array(Config.validate_soak(result.config, suite == "soak").errors) var address := {} var bounds := {} if result.ok: var serverinfo := ServerInfoRes.new() var override := OS.get_environment("MT_PLAYABLE_SERVERLIST").strip_edges() if not override.is_empty(): if not serverinfo.load_file(override): errors.append("MT_PLAYABLE_SERVERLIST cannot be loaded") else: serverinfo.load_file("res://serverlist.txt") var resolved := Config.resolve_server(result.config, serverinfo) errors.append_array(resolved.errors) address = resolved.address var assets := OS.get_environment("MT_PLAYABLE_ASSETS").strip_edges() if assets.is_empty(): errors.append("MT_PLAYABLE_ASSETS is not set; resource preconditions cannot be checked") else: var resources := Config.check_resources(result.config, assets) errors.append_array(resources.errors) bounds = resources.bounds if not errors.is_empty(): for error in errors: printerr("CONFIG: " + String(error)) quit(2) return var out_dir := OS.get_environment("MT_PLAYABLE_GATE_OUTPUT").strip_edges() if not out_dir.is_empty(): var cases := Config.required_cases(result.config, suite) if not _write_json(out_dir.path_join("required-cases.json"), {"schema_version": 1, "suite": suite, "cases": cases}) \ or not _write_json(out_dir.path_join("server-address.json"), address) \ or not _write_json(out_dir.path_join("map-bounds.json"), bounds): printerr("CONFIG: cannot write gate output") quit(2) return print("PLAYABLE CONFIG: PASS") quit(0) func _write_json(path: String, value: Variant) -> bool: var file := FileAccess.open(path, FileAccess.WRITE) if file == null: return false file.store_string(JSON.stringify(value, " ") + "\n") file.close() return true