// WL-814k 이름 규약 표 — 「굽기 SO 의 상태 이름 후보」가 어떤 캐릭터에 얼마나 걸리는지 실측 (읽기만 · 굽기 0) // run: unity command run_script --file AgentScripts/WL814k_Naming.cs --entry WL814k_Naming.Run // 🔴 여기서도 굽지 않는다 — 1차 시범은 PC 1종 + 잡몹 1종(발주서). 이 표는 「확장하면 뭐가 걸리나」의 근거다. using System; using System.Collections.Generic; using System.IO; using System.Text; using UnityEditor; using UnityEngine; using WL.Look.SpriteBake; public static class WL814k_Naming { const string kTxt = "AgentScripts/WL814k_NAMING.txt"; static StringBuilder s_sb; static void L(string s) { s_sb.AppendLine(s); Debug.Log("[WL814k] " + s); } public static void Run() { s_sb = new StringBuilder(); L("WL-814k 이름 규약 표 · " + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")); var cfg = AssetDatabase.LoadAssetAtPath("Assets/WL/Look/Sprite/Resources/WL/WLSpriteBakeSettings.asset"); if (cfg == null) { L("FAIL — 굽기 SO 없음"); File.WriteAllText(kTxt, s_sb.ToString(), new UTF8Encoding(false)); return; } foreach (var a in cfg.actions) L(" 후보 " + a.key.PadRight(7) + " = [" + string.Join(" / ", a.stateNames) + "] (+보기만: " + string.Join(" / ", a.alsoMapStateNames) + ")"); // ── ① 시범 2종 + PD 가 방금 임포트한 치비 팩(Little Heroes) ───────────── L(""); L("== 개별 프리팹 =="); foreach (var p in new[] { "Assets/Res_Addr/PC/Ai01.prefab", "Assets/Res_Addr/Mobs/Mob/Batty_A.prefab", "Assets/Suriyun/Characters/Nana/Prefab/F06.prefab", "Assets/Suriyun/Characters/RedKnight/Prefab/M05/M05.prefab", }) One(p, cfg); // ── ② 몹 전수 — 확장했을 때 몇 %가 그냥 걸리는지 ─────────────────────── L(""); L("== Res_Addr/Mobs 전수 (확장 견적 근거) =="); var guids = AssetDatabase.FindAssets("t:Prefab", new[] { "Assets/Res_Addr/Mobs" }); int total = 0, full = 0; var hist = new Dictionary(); var missing = new Dictionary(); foreach (var g in guids) { var path = AssetDatabase.GUIDToAssetPath(g); var go = AssetDatabase.LoadAssetAtPath(path); if (go == null) continue; var anim = go.GetComponentInChildren(true); if (anim == null || anim.runtimeAnimatorController == null) continue; total++; var states = States(anim); int hit = 0; foreach (var a in cfg.actions) { if (Match(a, states) != null) hit++; else { int c; missing.TryGetValue(a.key, out c); missing[a.key] = c + 1; } } if (hit == cfg.actions.Length) full++; int n; hist.TryGetValue(hit, out n); hist[hit] = n + 1; } L(" Animator+Controller 보유 프리팹 = " + total + " · 동작 5종 전부 매칭 = " + full + " (" + (100f * full / Mathf.Max(1, total)).ToString("0.0") + " %)"); var keys = new List(hist.Keys); keys.Sort(); foreach (var k in keys) L(" 매칭 " + k + "/5 동작 = " + hist[k] + "종"); foreach (var kv in missing) L(" 못 찾은 동작 '" + kv.Key + "' = " + kv.Value + "종"); File.WriteAllText(kTxt, s_sb.ToString(), new UTF8Encoding(false)); Debug.Log("[WL814k] → " + kTxt); } static void One(string path, WLSpriteBakeSettings cfg) { var go = AssetDatabase.LoadAssetAtPath(path); if (go == null) { L(" " + path + " → 없음"); return; } var anim = go.GetComponentInChildren(true); if (anim == null || anim.runtimeAnimatorController == null) { L(" " + path + " → Animator/Controller 없음"); return; } var states = States(anim); var sb = new StringBuilder(); int hit = 0; foreach (var a in cfg.actions) { var m = Match(a, states); if (m != null) hit++; sb.Append(a.key + "→" + (m ?? "✗") + " "); } L(string.Format(" {0,-56} 컨트롤러 {1,-24} 상태 {2,2}개 · 매칭 {3}/{4} · {5}", Path.GetFileName(path), anim.runtimeAnimatorController.name, states.Count, hit, cfg.actions.Length, sb.ToString().Trim())); } static Dictionary States(Animator anim) { var d = new Dictionary(StringComparer.OrdinalIgnoreCase); var ac = anim.runtimeAnimatorController as UnityEditor.Animations.AnimatorController; if (ac != null && ac.layers.Length > 0 && ac.layers[0].stateMachine != null) foreach (var ch in ac.layers[0].stateMachine.states) if (ch.state.motion != null && !d.ContainsKey(ch.state.name)) d[ch.state.name] = ch.state.name; return d; } static string Match(WLSpriteBakeAction a, Dictionary states) { foreach (var n in a.stateNames) { string real; if (states.TryGetValue(n, out real)) return real; } return null; } }