extends SceneTree ## CBT-01 技能矩阵检查:读取 test/playable/skill-cases.json(或 --matrix 指定的本地副本), ## 按职业校验并输出可直接放入场景配置的 skill_cases。只读数据,不连网络、不读凭据。 ## ## godot --headless --path project --script playable_skill_matrix.gd -- --job WARRIOR [--matrix PATH] ## ## stdout: 一行 "SKILL_MATRIX {json}"。exit 0 = READY,1 = 矩阵错误,2 = 存在未确认条目(BLOCKED)。 const Config = preload("res://testing/playable_config.gd") const SkillTable = preload("res://ui/skill_table.gd") func _init() -> void: var args := OS.get_cmdline_user_args() var job := "" var matrix_path := ProjectSettings.globalize_path("res://").path_join("../test/playable/skill-cases.json").simplify_path() var i := 0 while i < args.size(): match args[i]: "--job": i += 1 job = String(args[i]).to_upper() if i < args.size() else "" "--matrix": i += 1 matrix_path = args[i] if i < args.size() else "" "--help": print("usage: playable_skill_matrix.gd -- --job WARRIOR|ASSASSIN|SURA|SHAMAN [--matrix PATH]") quit(0) return _: printerr("SKILL_MATRIX: unknown argument %s" % args[i]) quit(1) return i += 1 var result := check(matrix_path, job) print("SKILL_MATRIX " + JSON.stringify(result)) quit({"READY": 0, "BLOCKED": 2}.get(result.status, 1)) static func check(matrix_path: String, job: String) -> Dictionary: var out := {"status": "FAIL", "job": job, "errors": [], "blocked": [], "not_applicable": [], "skill_cases": []} var file := FileAccess.open(matrix_path, FileAccess.READ) if file == null: out.errors.append("skill matrix cannot be opened") return out var parsed: Variant = JSON.parse_string(file.get_as_text()) if not (parsed is Dictionary): out.errors.append("skill matrix is not a JSON object") return out var table := SkillTable.new() var loaded := false for lang in ["en", "common"]: if table.load_file(AssetRoot.path().path_join("locale/locale/%s/skilldesc.txt" % lang)): loaded = true break var resolved := Config.skill_matrix_cases(parsed, job, table if loaded else null) out.errors = resolved.errors if not loaded: out.errors.append("skilldesc.txt is unavailable; skill ownership cannot be checked") out.blocked = resolved.blocked out.not_applicable = resolved.not_applicable out.skill_cases = resolved.cases if out.errors.is_empty(): out.status = "BLOCKED" if not out.blocked.is_empty() else "READY" return out