using System.IO; using System.Text; using UnityEditor; using UnityEditor.SceneManagement; using UnityEngine; namespace TKS.EditorTools { /// /// 스킬 이펙트 작업 도구(2026-11-09 PD 「WL 방식과 동일하게 유닛별 스킬 구현 · 테스트용 씬」). /// ① 스킬 테스트 씬 만들기/열기 ② WL 에서 옮겨 온 이펙트(Assets/VFX) 재질 검사(분홍 · 빠진 스크립트) /// ③ 고른 팩 프리팹 → 스킬 이펙트 사본 Resources/Fx/TKS_Fx_<이름>.prefab(원본 팩 무수정 · WL 의 WL_Fx_* 사본 규칙). /// public static class SkillTestTools { public const string ScenePath = "Assets/Scenes/SkillTest.unity"; public const string FxCopyFolder = "Assets/Resources/Fx"; /// 씬을 새로 만든다(열린 씬은 건드리지 않음 · 추가로 열었다 저장 후 닫음 · 대화 상자 없음). [MenuItem("TKS/Skill Test/Build Scene (스킬 테스트 씬 만들기)")] public static void BuildScene() { var open = EditorSceneManager.GetSceneByPath(ScenePath); if (open.IsValid() && open.isLoaded) { Debug.LogWarning("[TKS] 스킬 테스트 씬이 열려 있어 다시 만들지 않습니다(다른 씬을 연 뒤 다시)."); return; } var scene = EditorSceneManager.NewScene(NewSceneSetup.EmptyScene, NewSceneMode.Additive); var cam = new GameObject("Main Camera"); cam.tag = "MainCamera"; var c = cam.AddComponent(); c.orthographic = true; cam.transform.position = new Vector3(0f, 0f, -10f); EditorSceneManager.MoveGameObjectToScene(cam, scene); var go = new GameObject("SkillTestBootstrap"); var boot = go.AddComponent(); boot.Config = AssetDatabase.LoadAssetAtPath("Assets/Resources/BalanceConfig.asset"); EditorSceneManager.MoveGameObjectToScene(go, scene); Directory.CreateDirectory(Path.GetDirectoryName(ScenePath)); EditorSceneManager.SaveScene(scene, ScenePath); EditorSceneManager.CloseScene(scene, true); AssetDatabase.Refresh(); Debug.Log("[TKS] 스킬 테스트 씬 저장: " + ScenePath); } [MenuItem("TKS/Skill Test/Open Scene (스킬 테스트 씬 열기)")] public static void OpenScene() { if (!File.Exists(ScenePath)) BuildScene(); if (EditorSceneManager.SaveCurrentModifiedScenesIfUserWantsTo()) EditorSceneManager.OpenScene(ScenePath, OpenSceneMode.Single); } /// Assets/VFX 재질(셰이더 없음 · 오류 셰이더 · 미지원 · 컴파일 오류)과 빠진 스크립트 프리팹을 센다. 반환 = 보고 문자열. [MenuItem("TKS/VFX/Check Imported VFX (이펙트 재질 검사)")] public static string CheckVfx() { var sb = new StringBuilder(); int total = 0, bad = 0; foreach (var g in AssetDatabase.FindAssets("t:Material", new[] { SkillTestBootstrap.VfxRoot })) { var p = AssetDatabase.GUIDToAssetPath(g); var m = AssetDatabase.LoadAssetAtPath(p); total++; string why = null; if (m == null) why = "읽기 실패"; else if (m.shader == null) why = "셰이더 없음"; else if (m.shader.name == "Hidden/InternalErrorShader") why = "오류 셰이더"; else if (!m.shader.isSupported) why = "미지원 " + m.shader.name; else if (ShaderUtil.ShaderHasError(m.shader)) why = "컴파일 오류 " + m.shader.name; if (why == null) continue; bad++; if (bad <= 20) sb.AppendLine(" 재질 " + why + " · " + p); } int prefabs = 0, missing = 0; foreach (var g in AssetDatabase.FindAssets("t:Prefab", new[] { SkillTestBootstrap.VfxRoot })) { var p = AssetDatabase.GUIDToAssetPath(g); var go = AssetDatabase.LoadAssetAtPath(p); if (go == null) continue; prefabs++; foreach (var comp in go.GetComponentsInChildren(true)) { if (comp != null) continue; missing++; if (missing <= 20) sb.AppendLine(" 빠진 스크립트 · " + p); break; } } string head = "[TKS] VFX 검사: 재질 " + total + " · 문제 " + bad + " · 프리팹 " + prefabs + " · 빠진 스크립트 " + missing; Debug.Log(head + "\n" + sb); return head + "\n" + sb; } /// Project 창에서 고른 팩 프리팹 → Resources/Fx/TKS_Fx_<이름>.prefab 사본(이미 있으면 건너뜀). 스킬 이펙트 표 s_fx 에 그 이름을 쓴다. [MenuItem("TKS/VFX/Make Skill Fx Copy (선택 프리팹 → 스킬 이펙트 사본)")] public static void CopySelected() { foreach (var o in Selection.objects) { var p = AssetDatabase.GetAssetPath(o); if (!p.EndsWith(".prefab")) continue; MakeCopy(p, null); } } /// 팩 프리팹 사본 만들기(이름 = TKS_Fx_ + name 또는 원본 이름) · 반환 = 사본 경로. public static string MakeCopy(string srcPath, string name) { if (!Directory.Exists(FxCopyFolder)) Directory.CreateDirectory(FxCopyFolder); string n = string.IsNullOrEmpty(name) ? Path.GetFileNameWithoutExtension(srcPath) : name; n = n.Replace(' ', '_'); if (!n.StartsWith("TKS_Fx_")) n = "TKS_Fx_" + n; string dst = FxCopyFolder + "/" + n + ".prefab"; if (File.Exists(dst)) { Debug.Log("[TKS] 사본 이미 있음: " + dst); return dst; } AssetDatabase.Refresh(); if (!AssetDatabase.CopyAsset(srcPath, dst)) { Debug.LogError("[TKS] 사본 실패: " + srcPath + " → " + dst); return null; } Debug.Log("[TKS] 스킬 이펙트 사본: " + srcPath + " → " + dst); return dst; } } }