using System.Collections.Generic; using System.IO; using System.Text; using UnityEditor; using UnityEditor.SceneManagement; using UnityEngine; namespace TKS.EditorTools { /// /// 지형 기믹 표(Assets/Data/Gimmicks/{gimmicks,stage_gimmicks,tutorial_tips}.csv · 기획 tables/ 사본 · PD #1097) + 적 AI 가중치(Assets/Data/AI/ai_weights.csv · PD #1098) /// → Resources/Gimmicks/GimmickDb · StageGimmickTable · Resources/AI/AiWeights. 메뉴 TKS/Import Gimmicks 또는 /// CLI: Unity.exe -batchmode -nographics -projectPath <proj> -executeMethod TKS.EditorTools.GimmickImporter.Import -quit /// 형식·참조 오류(정의 id · 스테이지 · 모양 · params · 가중치 키)가 하나라도 있으면 자산을 건드리지 않는다. /// public static class GimmickImporter { public const string AssetFolder = "Assets/Resources/Gimmicks"; public const string AiFolder = "Assets/Resources/AI"; [MenuItem("TKS/Import Gimmicks (기믹 임포트)")] public static void Import() { ImportAll(); } public static string[] ReadFiles() { var dir = Path.Combine(Application.dataPath, GimmickTables.Folder); var texts = new string[GimmickTables.Files.Length]; for (int i = 0; i < texts.Length; i++) { var p = Path.Combine(dir, GimmickTables.Files[i]); texts[i] = File.Exists(p) ? File.ReadAllText(p, Encoding.UTF8) : null; } return texts; } public static bool ImportAll() { var cfg = AssetDatabase.LoadAssetAtPath(ProjectSetup.ConfigPath); System.Func exists = null; if (cfg != null && cfg.stages != null && cfg.stages.Length > 0) { exists = (ch, st) => { foreach (var s in cfg.stages) { if (s.chapter == ch && s.stage == st) return true; } return false; }; } var r = GimmickTables.Parse(ReadFiles(), exists); var aiPath = Path.Combine(Application.dataPath, AiWeights.CsvPath); var aiEntries = AiWeights.Parse(File.Exists(aiPath) ? File.ReadAllText(aiPath, Encoding.UTF8) : null, r.errors); if (r.errors.Count > 0) { foreach (var e in r.errors) Debug.LogError("[TKS] 기믹 표 오류 · " + e); Debug.LogError("[TKS] 기믹 임포트 중단(오류 " + r.errors.Count + ") · 자산 변경 없음"); return false; } EnsureFolder("Assets/Resources"); EnsureFolder(AssetFolder); EnsureFolder(AiFolder); var db = Load(AssetFolder + "/GimmickDb.asset"); db.defs = new List(r.defs); EditorUtility.SetDirty(db); var table = Load(AssetFolder + "/StageGimmickTable.asset"); table.rows = new List(r.rows); table.tips = new List(r.tips); EditorUtility.SetDirty(table); var w = Load(AiFolder + "/AiWeights.asset"); w.entries = aiEntries; EditorUtility.SetDirty(w); AssetDatabase.SaveAssets(); GimmickTables.Invalidate(); AiWeights.Invalidate(); Debug.Log("[TKS] 기믹 임포트 완료 · 정의 " + r.defs.Count + " · 배치 " + r.rows.Count + " · 팁 " + r.tips.Count + " · AI 가중치 " + aiEntries.Count + " · " + AssetFolder); return true; } static T Load(string path) where T : ScriptableObject { var a = AssetDatabase.LoadAssetAtPath(path); if (a != null) return a; a = ScriptableObject.CreateInstance(); AssetDatabase.CreateAsset(a, path); return a; } static void EnsureFolder(string path) { if (AssetDatabase.IsValidFolder(path)) return; var parent = Path.GetDirectoryName(path).Replace('\\', '/'); AssetDatabase.CreateFolder(parent, Path.GetFileName(path)); } /// /// 기믹 검증 캡처(GUI 에디터 · 사본 프로젝트 권장 · 세이브 = 메모리 전용 · PD #1097): /// Unity.exe -projectPath <copy> -executeMethod TKS.EditorTools.GimmickImporter.Capture -gimmickDir <dir> /// 샘플 5 스테이지 1턴씩 + 조준선 반응 2장 + AI 함정 쪽 튕겨내기 1장 PNG + log · 끝나면 스스로 종료. /// -gimmickStages 1-10,2-10,… 을 주면 그 스테이지들의 시작 화면(전장 전체)만 찍는다(145 배치 확인). /// public static void Capture() { string dir = GetArg("-gimmickDir"); if (string.IsNullOrEmpty(dir)) dir = Path.Combine(Directory.GetCurrentDirectory(), "Logs", "gimmick_capture"); ImportAll(); EditorSceneManager.OpenScene(ProjectSetup.ScenePath, OpenSceneMode.Single); SessionState.SetBool(OutGame.SaveStore.MemoryFlagKey, true); SessionState.SetString(GimmickCaptureDriver.DirKey, dir); SessionState.SetString(GimmickCaptureDriver.StagesKey, GetArg("-gimmickStages") ?? ""); Debug.Log("[TKS] 기믹 캡처 시작 → " + dir); EditorApplication.EnterPlaymode(); } static string GetArg(string name) { var args = System.Environment.GetCommandLineArgs(); for (int i = 0; i < args.Length - 1; i++) if (args[i] == name) return args[i + 1]; return null; } } }