// WL804_Tools.cs — 2026-09-07 세션 보조 도구 (#804 검기 3타 · #806 후속 검증) // unity command run_script --file AgentScripts/WL804_Tools.cs --entry WL804_Tools.Refresh (에디트 · AssetDatabase.Refresh + 매핑 Attack3 ShowEffect 값 확인) // unity command run_script --file AgentScripts/WL804_Tools.cs --entry WL804_Tools.FbxEvents (에디트 · Knight@Attack3_S 서브클립 ShowEffect time 확인) // unity command run_script --file AgentScripts/WL804_Tools.cs --entry WL804_Tools.RuntimeCal (Play · WeaponTrailDriver.RuntimeCalibrations 요약) // unity command run_script --file AgentScripts/WL804_Tools.cs --entry WL804_Tools.PetCount (Play · PetActor 인스턴스 · ActorInfo 펫 수) // unity command run_script --file AgentScripts/WL804_Tools.cs --entry WL804_Tools.PopupShow --args "[124]" (Play · 공용 Popup 표시) // unity command run_script --file AgentScripts/WL804_Tools.cs --entry WL804_Tools.PopupClose (Play) using System.Linq; using System.Text; using UnityEditor; using UnityEngine; public static class WL804_Tools { const string MappingPath = "Assets/WL/Combat/CombatAnimMapping.asset"; const string Fbx3 = "Assets/Res_Addr/Animations/Animation/OneHand/Knight@Attack3_S.FBX"; public static object Refresh() { AssetDatabase.Refresh(ImportAssetOptions.ForceSynchronousImport); var so = AssetDatabase.LoadAssetAtPath(MappingPath); if (so == null) return "mapping null"; var sb = new StringBuilder("refreshed · mapping Attack3 ShowEffect:\n"); foreach (var c in so.classes) foreach (var st in c.states) if (st.stateName == "Attack3") foreach (var e in st.events) if (e.functionName == "ShowEffect") sb.AppendLine(" " + c.classId + " " + st.stateName + " norm=" + e.normalizedTime + " useNorm=" + e.useNormalized); return sb.ToString(); } public static object FbxEvents() { var imp = AssetImporter.GetAtPath(Fbx3) as ModelImporter; if (imp == null) return "importer null"; var sb = new StringBuilder(); foreach (var c in imp.clipAnimations) { sb.Append(c.name + " [" + c.firstFrame + "~" + c.lastFrame + "f]:"); foreach (var e in c.events) sb.Append(" " + e.functionName + "@" + e.time.ToString("F4")); sb.AppendLine(); } sb.AppendLine("motionNodeName='" + imp.motionNodeName + "'"); return sb.ToString(); } public static object RuntimeCal() { var rt = WL.Combat.WeaponTrailDriver.RuntimeCalibrations; if (rt == null) return "RuntimeCalibrations null"; var sb = new StringBuilder("runtime calibrations " + rt.Count + "\n"); foreach (var kv in rt) { var c = kv.Value; if (c == null) continue; sb.AppendLine(string.Format(" {0} {1} kind={2} sweep={3:F1} q={4:F2} | {5}", c.classId, c.clipName, c.kind, c.sweepDeg, c.quality, c.source)); } return sb.ToString(); } public static object PetCount() { if (!Application.isPlaying) return "not playing"; var pets = UnityEngine.Object.FindObjectsByType(FindObjectsInactive.Include, FindObjectsSortMode.None); var sb = new StringBuilder("PetActor instances=" + pets.Length + "\n"); foreach (var p in pets) { string path = p.name; var t = p.transform.parent; while (t != null) { path = t.name + "/" + path; t = t.parent; } sb.AppendLine(" " + path + " active=" + p.gameObject.activeInHierarchy + " layer=" + LayerMask.LayerToName(p.gameObject.layer) + " pos=" + p.transform.position); } try { var list = ActorInfo.Ins.Get_Actors(eRole.Pet); sb.AppendLine("ActorInfo eRole.Pet count=" + (list != null ? list.Count : -1)); var my = MyValue.MyPC != null ? MyValue.MyPC.Get_MyPet() : null; sb.AppendLine("MyPC.Get_MyPet()=" + (my != null ? my.name : "null")); } catch (System.Exception ex) { sb.AppendLine("ActorInfo/MyValue err: " + ex.Message); } sb.AppendLine("spawnPlayerPet=" + WL.Settings.WLGameplaySettings.SpawnPlayerPet); return sb.ToString(); } public static object PopupShow(int msgKey) { if (!Application.isPlaying) return "not playing"; var pop = UnityEngine.Object.FindFirstObjectByType(FindObjectsInactive.Include); if (pop == null) return "Popup instance not found"; pop.Set(ePopupType.One, msgKey); var rt = pop.m_popup != null ? pop.m_popup.GetComponentInChildren(true) : null; return "popup shown key=" + msgKey + " text='" + (pop.label_msg != null ? pop.label_msg.text : "") + "' btn=" + (rt != null ? ((RectTransform)rt.transform).rect.size.ToString() : "?") + " scale=" + (rt != null ? rt.transform.lossyScale.x.ToString("F4") : "?"); } public static object PopupClose() { if (!Application.isPlaying) return "not playing"; var pop = UnityEngine.Object.FindFirstObjectByType(FindObjectsInactive.Include); if (pop == null) return "Popup instance not found"; pop.OnClick_OK(); return "popup closed"; } /// 에디트 모드 · SlashTrailSettings.swingCalibrations 에서 clipName 이 suffix 로 끝나는 행 제거 (재베이크 전 · 예: "_3") public static object RemoveCal(string clipSuffix) { var so = AssetDatabase.LoadAssetAtPath("Assets/WL/Settings/Resources/WL/SlashTrailSettings.asset"); if (so == null || so.swingCalibrations == null) return "settings null"; var removed = new StringBuilder(); int n = so.swingCalibrations.RemoveAll(c => { bool r = c != null && c.clipName != null && c.clipName.EndsWith(clipSuffix); if (r) removed.Append(c.classId + "/" + c.clipName + " q=" + c.quality.ToString("F2") + "; "); return r; }); EditorUtility.SetDirty(so); AssetDatabase.SaveAssets(); return "removed " + n + " [" + removed + "] remaining " + so.swingCalibrations.Count; } }