// WL-814k 실측 조사 (게임 코드 아님 · 에디트 모드 전용 · 에셋 수정 0 · 읽기만) // run: unity command run_script --file AgentScripts/WL814k_Survey.cs --entry WL814k_Survey.Run // 🔴 원본 프리팹/머티리얼/애니메이션 수정 0. AssetDatabase.SaveAssets 호출 0. using System; using System.Collections.Generic; using System.IO; using System.Text; using UnityEditor; using UnityEngine; public static class WL814k_Survey { const string kTxt = "AgentScripts/WL814k_SURVEY.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") + " · Unity " + Application.unityVersion); try { Cam(); Prefab("Assets/Res_Addr/PC/Ai01.prefab"); Prefab("Assets/Res_Addr/Mobs/Mob/Batty_A.prefab"); Counts(); ToonMats(); } catch (Exception ex) { L("EXCEPTION " + ex); } File.WriteAllText(kTxt, s_sb.ToString(), new UTF8Encoding(false)); Debug.Log("[WL814k] → " + kTxt); } // ── ① 카메라 각 (811o 수식 그대로 · 814d 프리셋 값) ────────────────────── static void Cam() { L(""); L("== ① 카메라 각 (WLLookModeSettings 프리셋 실측) =="); var so = Resources.Load("WL/WLLookModeSettings"); if (so == null) { L(" WLLookModeSettings 없음"); return; } for (int i = 0; i < so.presets.Length; i++) { var p = so.presets[i]; float down = WL.CameraFraming.CameraFramingOverride.DownAngleDeg(p.cameraHeight, p.distance, p.distanceUp); float above = WL.CameraFraming.CameraFramingOverride.CamHeightAbove(p.cameraHeight, p.distance, p.distanceUp); float horiz = WL.CameraFraming.CameraFramingOverride.CamHorizontal(p.cameraHeight, p.distance); L(string.Format(" [{0}] {1} pixelRig={2} h={3} d={4} up={5} ortho={6} pxH={7} → 내림각 {8:0.000}° · 높이 {9:0.000} m · 수평 {10:0.000} m", i, p.name, p.pixelRig ? 1 : 0, p.cameraHeight, p.distance, p.distanceUp, p.orthoSize, p.pixelHeight, down, above, horiz)); } // 도트A 프리셋 기준 캐릭터 픽셀 var d = so.presets.Length > 1 ? so.presets[1] : null; if (d != null) L(string.Format(" 도트A: orthoSize {0} · pixelHeight {1} → 월드 1 m = {2:0.000} px · 픽셀 1개 = {3:0.00000} m", d.orthoSize, d.pixelHeight, d.pixelHeight / (2f * d.orthoSize), (2f * d.orthoSize) / d.pixelHeight)); } // ── ② 프리팹 전수 ──────────────────────────────────────────────────────── static void Prefab(string path) { L(""); L("== ② 프리팹 " + path + " =="); var go = AssetDatabase.LoadAssetAtPath(path); if (go == null) { L(" 로드 실패"); return; } var anim = go.GetComponentInChildren(true); L(" Animator = " + (anim == null ? "없음" : anim.gameObject.name)); if (anim != null) { L(" avatar = " + (anim.avatar == null ? "null" : anim.avatar.name + " · isHuman=" + anim.avatar.isHuman + " · isValid=" + anim.avatar.isValid)); L(" applyRootMotion = " + anim.applyRootMotion + " · cullingMode = " + anim.cullingMode); var rac = anim.runtimeAnimatorController; L(" controller = " + (rac == null ? "null" : rac.name + " (" + AssetDatabase.GetAssetPath(rac) + ")")); if (rac != null) { var clips = rac.animationClips; L(" clips = " + clips.Length); var seen = new HashSet(); foreach (var c in clips) { if (c == null || !seen.Add(c.name)) continue; L(string.Format(" · {0,-28} len {1,6:0.000}s fps {2,5:0.#} frames {3,4} loop {4} legacy {5} hasMotion {6} hasRoot {7} empty {8}", c.name, c.length, c.frameRate, Mathf.RoundToInt(c.length * c.frameRate), c.isLooping, c.legacy, c.hasMotionCurves, c.hasRootCurves, c.empty)); } var ac = rac as UnityEditor.Animations.AnimatorController; if (ac != null) { L(" layers = " + ac.layers.Length); for (int li = 0; li < ac.layers.Length; li++) { var lay = ac.layers[li]; var sm = lay.stateMachine; if (sm == null) { L(" layer[" + li + "] " + lay.name + " (stateMachine null)"); continue; } var names = new List(); foreach (var st in sm.states) names.Add(st.state.name + "|" + (st.state.motion == null ? "-" : st.state.motion.name) + "|hash " + Animator.StringToHash(st.state.name) + "|full " + Animator.StringToHash(lay.name + "." + st.state.name)); L(" layer[" + li + "] " + lay.name + " · states " + names.Count + " · default=" + (sm.defaultState == null ? "-" : sm.defaultState.name)); foreach (var n in names) L(" " + n); } } } } var smrs = go.GetComponentsInChildren(true); var mrs = go.GetComponentsInChildren(true); L(" SkinnedMeshRenderer = " + smrs.Length + " · MeshRenderer = " + mrs.Length); int tri = 0; var mats = new HashSet(); foreach (var r in smrs) { if (r.sharedMesh != null) tri += r.sharedMesh.triangles.Length / 3; foreach (var m in r.sharedMaterials) if (m != null) mats.Add(m.name + " [" + (m.shader == null ? "-" : m.shader.name) + "]"); } foreach (var r in mrs) { var mf = r.GetComponent(); if (mf != null && mf.sharedMesh != null) tri += mf.sharedMesh.triangles.Length / 3; foreach (var m in r.sharedMaterials) if (m != null) mats.Add(m.name + " [" + (m.shader == null ? "-" : m.shader.name) + "]"); } L(" 삼각형 합계 = " + tri + " · 머티리얼 " + mats.Count + "종"); foreach (var m in mats) L(" " + m); // 본 수 if (smrs.Length > 0 && smrs[0].bones != null) L(" bones[0] = " + smrs[0].bones.Length); var allT = go.GetComponentsInChildren(true); L(" transform 노드 = " + allT.Length); // 스케일·ClassConfig L(" root localScale = " + go.transform.localScale.ToString("F4")); foreach (var c in go.GetComponents()) if (c != null) L(" root comp: " + c.GetType().FullName); // 인스턴스를 임시로 만들어 바운드 실측(씬 저장 0) var inst = (GameObject)PrefabUtility.InstantiatePrefab(go); try { inst.transform.position = Vector3.zero; inst.transform.rotation = Quaternion.identity; var b = WorldBounds(inst); L(string.Format(" 바운드(스케일 1) center {0} size {1} · 높이 {2:0.0000} m", b.center.ToString("F4"), b.size.ToString("F4"), b.size.y)); inst.transform.localScale = Vector3.one * 0.7f; var b7 = WorldBounds(inst); L(string.Format(" 바운드(스케일 0.7) 높이 {0:0.0000} m · 폭 {1:0.0000} m · 깊이 {2:0.0000} m", b7.size.y, b7.size.x, b7.size.z)); } finally { UnityEngine.Object.DestroyImmediate(inst); } } static Bounds WorldBounds(GameObject root) { var rs = root.GetComponentsInChildren(true); bool any = false; var b = new Bounds(); foreach (var r in rs) { if (r == null || r is ParticleSystemRenderer) continue; if (!any) { b = r.bounds; any = true; } else b.Encapsulate(r.bounds); } return b; } // ── ③ 전 캐릭터 수 (확장 견적용) ──────────────────────────────────────── static void Counts() { L(""); L("== ③ 캐릭터 프리팹 수 (확장 견적 근거) =="); var pc = AssetDatabase.FindAssets("t:Prefab", new[] { "Assets/Res_Addr/PC" }); var mob = AssetDatabase.FindAssets("t:Prefab", new[] { "Assets/Res_Addr/Mobs" }); L(" Res_Addr/PC 프리팹 = " + pc.Length); L(" Res_Addr/Mobs 프리팹 = " + mob.Length); int mobWithAnim = 0; var ctrls = new HashSet(); foreach (var g in mob) { var p = AssetDatabase.GUIDToAssetPath(g); var go = AssetDatabase.LoadAssetAtPath(p); if (go == null) continue; var a = go.GetComponentInChildren(true); if (a != null && a.runtimeAnimatorController != null) { mobWithAnim++; ctrls.Add(a.runtimeAnimatorController.name); } } L(" 그중 Animator+Controller 보유 = " + mobWithAnim + " · 서로 다른 컨트롤러 " + ctrls.Count + "종"); } // ── ④ Toon 머티리얼 (814c) ────────────────────────────────────────────── static void ToonMats() { L(""); L("== ④ 814c Toon 머티리얼 =="); string dir = "Assets/WL/Look/Env/Materials"; var all = AssetDatabase.FindAssets("t:Material", new[] { dir }); L(" " + dir + " = " + all.Length + "개"); foreach (var key in new[] { "Ai_", "Batty" }) { var hits = new List(); foreach (var g in all) { var p = AssetDatabase.GUIDToAssetPath(g); if (Path.GetFileName(p).StartsWith(key, StringComparison.OrdinalIgnoreCase)) hits.Add(Path.GetFileName(p)); } L(" '" + key + "*' → " + hits.Count + "개: " + string.Join(", ", hits.ToArray())); } var envSo = Resources.Load("WL/WLEnvLookSettings"); L(" WLEnvLookSettings = " + (envSo == null ? "없음" : "있음")); } }