// WL912_Probe.cs — PD 지시 #912 시험(Play 중 · 섬) // Hammer() : 무기 소켓 · 자식 · 렌더러(종류 · 메시 · 서브메시 · 재질 · 셰이더 · 배율) // Post() : 메인 카메라 후처리 · 켜진 Volume 의 블룸 · 최종 블룸 // TipCurve(state, from, to, step) : 그 상태를 정규화 시간별로 멈춰 망치 끝 높이 · 앞 거리(PC 기준) using System.Text; using UnityEngine; using UnityEngine.Rendering; using UnityEngine.Rendering.Universal; public static class WL912_Probe { const string Key = "wl912log"; static StringBuilder Buf() { var sb = System.AppDomain.CurrentDomain.GetData(Key) as StringBuilder; if (sb == null) { sb = new StringBuilder(); System.AppDomain.CurrentDomain.SetData(Key, sb); } return sb; } public static object Log() { return Buf().ToString(); } static Transform HammerPart(PCActor pc) { foreach (var s in pc.tfs_weapon) if (s != null && s.name == "w_righthand" && s.childCount > 0) return s.GetChild(0); return null; } /// 각성(E) 발동 → 프레임마다 상태 · 속도 · 정규화 시간 · 망치 배율 · 흰 빛 · 점광원 · PC 이동 · 이동 무시 횟수. pauseAt>0 = 그때 일시 정지. /// pushMove=1 이면 멈춤(Holds 증가) 동안부터 1 초간 오른쪽 이동 입력. public static object Trace(float dist, float seconds, float pauseAt, int pushMove) { var pc = MyValue.MyPC as PCActor; if (pc == null) return "PC 없음"; var f = pc.transform.forward; f.y = 0f; f.Normalize(); Actor d = WL.IslandMob.WLTrailTest.Dummy; if (d == null || !d.isActiveAndEnabled) { float bd = float.MaxValue; foreach (var m in Object.FindObjectsByType(FindObjectsInactive.Exclude, FindObjectsSortMode.None)) { if (m == null || m.IsDead()) continue; float dd = Vector3.Distance(pc.Get_position(), m.Get_position()); if (dd < bd) { bd = dd; d = m; } } } if (d != null) { var want = pc.Get_position() + f * dist; UnityEngine.AI.NavMeshHit hit; if (UnityEngine.AI.NavMesh.SamplePosition(want, out hit, 1.5f, UnityEngine.AI.NavMesh.AllAreas)) want = hit.position; d.Stop(true); d.Set_Warp(want); pc.Change_Target(true, d); } var sb = Buf(); sb.Length = 0; float t0 = Time.time; bool paused = false, pushing = false; float pushStart = -1f; int h0 = WL.PartSkill.SkHammerQuake.Holds, mb0 = WL.Combat.Weapon.WLSkillCancel.MoveBlocked; Vector3 p0 = pc.Get_position(); var dir = pc.transform.right; dir.y = 0f; dir.Normalize(); var part = HammerPart(pc); string last = ""; UnityEngine.Events.UnityAction act = null; act = () => { if (pc == null || pc.m_animation == null) { Application.onBeforeRender -= act; return; } float t = Time.time - t0; var a = pc.m_animation; var si = a.GetCurrentAnimatorStateInfo(0); var ci = a.GetCurrentAnimatorClipInfo(0); string clip = ci.Length > 0 && ci[0].clip != null ? ci[0].clip.name : "-"; var glow = part != null ? part.GetComponentInChildren(false) : null; bool glowOn = false; if (part != null) foreach (var r in part.GetComponentsInChildren(false)) if (r.name == "[WL912] Glow" && r.enabled) glowOn = true; var lampGo = GameObject.Find("[WL912] ChargeLight"); var lamp = lampGo != null ? lampGo.GetComponent() : null; // #913 모으기 이펙트 위치(망치 메시 로컬 · 메시 상자 중심 · 크기와 비교) var fxGo = GameObject.Find("WL_Fx_HammerCharge(Clone)"); Transform hm = null; if (part != null) foreach (var r in part.GetComponentsInChildren(false)) if (r.name != "[WL912] Glow") { hm = r.transform; break; } string fxs = fxGo != null && hm != null ? " · 이펙트(망치 로컬) " + hm.InverseTransformPoint(fxGo.transform.position).ToString("F2") : ""; bool holding = WL.PartSkill.SkHammerQuake.Holds > h0; if (pushMove != 0 && holding && !pushing && pushStart < 0f) { pushing = true; pushStart = t; pc.Set_AutoBraking(false); pc.Set_JoystickStatus(1); } if (pushing) { pc.Run_byJoystick(dir); if (t - pushStart > 1.0f) { pushing = false; pc.Set_JoystickStatus(0); pc.Set_AutoBraking(true); } } string key = clip + " " + pc.Get_CurAnim() + " sp" + a.speed.ToString("F1") + " 멈춤" + (holding ? 1 : 0) + " 빛" + (glowOn ? 1 : 0) + (pushing ? " 입력" : ""); if (key != last || Mathf.Repeat(t, 0.1f) < Time.deltaTime) { last = key; sb.AppendFormat("{0:F2} {1} n={2:F2} · 망치 {3:F2} · 광원 {4:F1} · 이동 {5:F2} m · 무시 +{6}{7}", t, key, si.normalizedTime, part != null ? part.localScale.x : -1f, lamp != null && lamp.enabled ? lamp.intensity : 0f, Vector3.Distance(p0, pc.Get_position()), WL.Combat.Weapon.WLSkillCancel.MoveBlocked - mb0, fxs).Append('\n'); } if (!paused && pauseAt > 0f && t >= pauseAt) { paused = true; UnityEditor.EditorApplication.isPaused = true; var cam = Camera.main; var vp = cam != null ? cam.WorldToViewportPoint(pc.Get_position() + Vector3.up * 0.8f) : Vector3.zero; sb.AppendFormat("■ 일시 정지 · PC 화면 {0:F3},{1:F3}", vp.x, 1f - vp.y).Append('\n'); } if (t > seconds) { Application.onBeforeRender -= act; if (pushing) { pc.Set_JoystickStatus(0); pc.Set_AutoBraking(true); } sb.AppendFormat("끝 · 멈춤 +{0} · {1} · 망치 끝 배율 {2:F2}", WL.PartSkill.SkHammerQuake.Holds - h0, WL.PartSkill.SkHammerQuake.LastLog, part != null ? part.localScale.x : -1f).Append('\n'); } }; Application.onBeforeRender += act; var res = "E: " + WL.Combat.Weapon.WLSkillHotkey.Fire(2); BlockAuto(); return res; } /// #914 검 각성(E) — 프레임마다 클립 · 상태 · 이 PC 의 돌진 베기 투사체 켜짐 · 이동 거리 · 동작 끝 횟수 · 타격 창. pushMove=1 이면 처음부터 오른쪽 이동 입력. public static object SwordEnd(float seconds, int pushMove) { var pc = MyValue.MyPC as PCActor; if (pc == null) return "PC 없음"; var sb = Buf(); sb.Length = 0; float t0 = Time.time; Vector3 p0 = pc.Get_position(); var dir = pc.transform.right; dir.y = 0f; dir.Normalize(); int me0 = WL.Combat.Weapon.WLSkillCancel.MotionEnds, w0 = WL.Combat.Weapon.WLSlashFlurry.Windows; string last = ""; bool pushing = false; UnityEngine.Events.UnityAction act = null; act = () => { if (pc == null || pc.m_animation == null) { Application.onBeforeRender -= act; return; } float t = Time.time - t0; if (pushMove != 0 && !pushing) { pushing = true; pc.Set_AutoBraking(false); pc.Set_JoystickStatus(1); } if (pushing) pc.Run_byJoystick(dir); bool eff = false; foreach (var pb in Object.FindObjectsByType(FindObjectsInactive.Exclude, FindObjectsSortMode.None)) { var d = pb.Get_ProjectTileData(); if (d != null && ReferenceEquals(d.shooter, pc)) eff = true; } var ci = pc.m_animation.GetCurrentAnimatorClipInfo(0); string clip = ci.Length > 0 && ci[0].clip != null ? ci[0].clip.name : "-"; string key = clip + " " + pc.Get_CurAnim() + " 이펙트" + (eff ? 1 : 0) + " 동작끝+" + (WL.Combat.Weapon.WLSkillCancel.MotionEnds - me0); if (key != last) { last = key; sb.AppendFormat("{0:F2} {1} · 이동 {2:F2} m · 타격 창 +{3}", t, key, Vector3.Distance(p0, pc.Get_position()), WL.Combat.Weapon.WLSlashFlurry.Windows - w0).Append('\n'); } if (t > seconds) { Application.onBeforeRender -= act; if (pushing) { pc.Set_JoystickStatus(0); pc.Set_AutoBraking(true); } sb.AppendFormat("끝 · 이동 {0:F2} m · 타격 창 +{1} · {2}", Vector3.Distance(p0, pc.Get_position()), WL.Combat.Weapon.WLSlashFlurry.Windows - w0, WL.Combat.Weapon.WLSkillCancel.LastLog).Append('\n'); } }; Application.onBeforeRender += act; return "E: " + WL.Combat.Weapon.WLSkillHotkey.Fire(2); } static int s_hitN; static Actor s_hitDummy; static string s_hitSkills = ""; static void OnHit(in WL.Combat.Core.HitConfirmedEvent e) { if (!ReferenceEquals(e.victim, s_hitDummy)) return; s_hitN++; var pd = e.projectile; var sk = pd != null && pd.m_SkillListTableData != null ? pd.m_SkillListTableData.e_Skill.ToString() : "-"; if (!s_hitSkills.Contains(sk)) s_hitSkills += sk + " "; } static float Flat(Vector3 a, Vector3 b) { a.y = 0f; b.y = 0f; return Vector3.Distance(a, b); } /// #915 검 각성 밀림 — 시험 몹을 PC 정면 dist m 에 세우고 각성 → 몹이 맞을 때마다 PC 와 거리 · 밀린 거리 · 상태 · 경직, 끝에 총 밀림 · 명중 수 · 규칙 적용 수. /// off = 1 이면 스킬별 피격 반응(WLSkillHitFeel)을 끄고 잰다(전후 비교). public static object SwordPush(float dist, float seconds, int off) { var pc = MyValue.MyPC as PCActor; if (pc == null) return "PC 없음"; Actor d = WL.IslandMob.WLTrailTest.Dummy; if (d == null || !d.isActiveAndEnabled) { float bd = float.MaxValue; foreach (var m in Object.FindObjectsByType(FindObjectsInactive.Exclude, FindObjectsSortMode.None)) { if (m == null || m.IsDead()) continue; float dd = Vector3.Distance(pc.Get_position(), m.Get_position()); if (dd < bd) { bd = dd; d = m; } } } if (d == null) return "몹 없음"; var f = pc.transform.forward; f.y = 0f; f.Normalize(); var want = pc.Get_position() + f * dist; UnityEngine.AI.NavMeshHit hit; if (UnityEngine.AI.NavMesh.SamplePosition(want, out hit, 1.5f, UnityEngine.AI.NavMesh.AllAreas)) want = hit.position; d.Stop(true); d.Set_Warp(want); pc.Change_Target(true, d); WL.Combat.Reaction.WLSkillHitFeel.RuntimeDisabled = off != 0; s_hitDummy = d; s_hitN = 0; s_hitSkills = ""; WL.Combat.Core.CombatEvents.HitConfirmed.Remove(OnHit); WL.Combat.Core.CombatEvents.HitConfirmed.Add(OnHit); var sb = Buf(); sb.Length = 0; float t0 = Time.time; Vector3 d0 = d.Get_position(); int lastN = -1; int so0 = WL.Combat.Reaction.MobStagger.SkillOverrides, ks0 = WL.Combat.Reaction.MobKnockbackScale.SkillScaled, w0 = WL.Combat.Weapon.WLSlashFlurry.Windows; UnityEngine.Events.UnityAction act = null; act = () => { if (d == null || pc == null) { Application.onBeforeRender -= act; WL.Combat.Core.CombatEvents.HitConfirmed.Remove(OnHit); return; } float t = Time.time - t0; if (s_hitN != lastN) { lastN = s_hitN; sb.AppendFormat("{0:F2} 명중 {1} · PC 거리 {2:F2} · 몹 밀림 {3:F2} · 상태 {4} · 경직 {5}", t, s_hitN, Flat(pc.Get_position(), d.Get_position()), Flat(d0, d.Get_position()), d.Get_CurAnim(), WL.Combat.Reaction.MobStagger.IsStaggered(d) ? 1 : 0).Append('\n'); } if (t > seconds) { Application.onBeforeRender -= act; WL.Combat.Core.CombatEvents.HitConfirmed.Remove(OnHit); WL.Combat.Reaction.WLSkillHitFeel.RuntimeDisabled = false; sb.AppendFormat("끝({0}) · 시작 거리 {1:F1} m · 총 밀림 {2:F2} m · 명중 {3} · 타격 창 +{4} · 스킬 {5}· 규칙(경직/넉백) +{6}/+{7}", off != 0 ? "규칙 끔" : "규칙 켬", dist, Flat(d0, d.Get_position()), s_hitN, WL.Combat.Weapon.WLSlashFlurry.Windows - w0, s_hitSkills, WL.Combat.Reaction.MobStagger.SkillOverrides - so0, WL.Combat.Reaction.MobKnockbackScale.SkillScaled - ks0).Append('\n'); } }; Application.onBeforeRender += act; return "E: " + WL.Combat.Weapon.WLSkillHotkey.Fire(2); } /// #914 해머 각성 둘레 피해 — 시험 몹을 PC 오른쪽 side m(충격파 갈래 밖)에 세우고 각성 → 1.6 초 뒤 둘레 명중 · 전체 명중 · 몹 높이 · 기절. public static object Area(float side) { var pc = MyValue.MyPC as PCActor; if (pc == null) return "PC 없음"; Actor d = WL.IslandMob.WLTrailTest.Dummy; if (d == null || !d.isActiveAndEnabled) { float bd = float.MaxValue; foreach (var m in Object.FindObjectsByType(FindObjectsInactive.Exclude, FindObjectsSortMode.None)) { if (m == null || m.IsDead()) continue; float dd = Vector3.Distance(pc.Get_position(), m.Get_position()); if (dd < bd) { bd = dd; d = m; } } } if (d == null) return "몹 없음"; var r = pc.transform.right; r.y = 0f; r.Normalize(); var want = pc.Get_position() + r * side; UnityEngine.AI.NavMeshHit hit; if (UnityEngine.AI.NavMesh.SamplePosition(want, out hit, 1.5f, UnityEngine.AI.NavMesh.AllAreas)) want = hit.position; d.Stop(true); d.Set_Warp(want); var sb = Buf(); sb.Length = 0; int a0 = WL.PartSkill.SkHammerQuake.AreaHits, h0 = WL.PartSkill.SkHammerQuake.HitCount; float t0 = Time.time, y0 = d.transform.position.y, maxY = 0f; UnityEngine.Events.UnityAction act = null; act = () => { if (d == null) { Application.onBeforeRender -= act; return; } maxY = Mathf.Max(maxY, d.transform.position.y - y0); if (Time.time - t0 > 1.6f) { Application.onBeforeRender -= act; sb.AppendFormat("몹 PC 오른쪽 {0:F1} m · 둘레 명중 +{1} · 전체 명중 +{2} · 몹 최고 높이 {3:F2} · 기절 {4:F2} · {5}", side, WL.PartSkill.SkHammerQuake.AreaHits - a0, WL.PartSkill.SkHammerQuake.HitCount - h0, maxY, d.Get_CCData(eCC.Stun).CCTime, WL.PartSkill.SkHammerQuake.LastLog).Append('\n'); } }; Application.onBeforeRender += act; var res = "E: " + WL.Combat.Weapon.WLSkillHotkey.Fire(2); BlockAuto(); return res; } /// #914 해머 주력(Q · 강력한 일격) — 발동 뒤 그 스킬 판정 상자 크기 · pauseAt 에 일시 정지. public static object Jump(float pauseAt) { var pc = MyValue.MyPC as PCActor; if (pc == null) return "PC 없음"; var sb = Buf(); sb.Length = 0; float t0 = Time.time; bool paused = false, boxed = false; UnityEngine.Events.UnityAction act = null; act = () => { float t = Time.time - t0; if (!boxed) foreach (var s in Object.FindObjectsByType(FindObjectsInactive.Exclude, FindObjectsSortMode.None)) { var pd = s.Get_ProjectTileData(); if (pd == null || !ReferenceEquals(pd.shooter, pc)) continue; var bc = s.GetComponent(); if (bc == null) continue; boxed = true; sb.AppendFormat("{0:F2} 판정 상자 {1} · 배율 {2}", t, bc.size.ToString("F2"), s.transform.lossyScale.ToString("F2")).Append('\n'); } if (!paused && pauseAt > 0f && t >= pauseAt) { paused = true; UnityEditor.EditorApplication.isPaused = true; var cam = Camera.main; var vp = cam != null ? cam.WorldToViewportPoint(pc.Get_position() + Vector3.up * 0.8f) : Vector3.zero; sb.AppendFormat("■ 일시 정지 · PC 화면 {0:F3},{1:F3}", vp.x, 1f - vp.y).Append('\n'); } if (t > Mathf.Max(1.5f, pauseAt + 0.2f)) Application.onBeforeRender -= act; }; Application.onBeforeRender += act; return "Q: " + WL.Combat.Weapon.WLSkillHotkey.Fire(1); } /// #914 지금 PC 둘레 radius m 안에 입자가 살아 있는 파티클 — 최상위 오브젝트 · 이름 · 입자 수 · 시작색 · 재질(검은 이펙트 출처 찾기). public static object Alive(float radius) { var pc = MyValue.MyPC as PCActor; if (pc == null) return "PC 없음"; var sb = new StringBuilder(); var p = pc.Get_position(); foreach (var ps in Object.FindObjectsByType(FindObjectsInactive.Exclude, FindObjectsSortMode.None)) { if (ps.particleCount == 0 || Vector3.Distance(ps.transform.position, p) > radius) continue; var m = ps.main; var r = ps.GetComponent(); var c = m.startColor; string col = c.mode == ParticleSystemGradientMode.Color ? c.color.ToString("F2") : c.mode == ParticleSystemGradientMode.TwoColors ? c.colorMin.ToString("F2") + "~" + c.colorMax.ToString("F2") : c.mode.ToString(); sb.Append(ps.transform.root.name).Append(" / ").Append(ps.name).Append(" n ").Append(ps.particleCount).Append(" 색 ").Append(col) .Append(" 재질 ").Append(r != null && r.sharedMaterial != null ? r.sharedMaterial.name : "-").Append(" 배율 ").Append(ps.transform.lossyScale.x.ToString("F2")).AppendLine(); } return sb.ToString(); } /// 망치 배율 · 남은 흰 빛 자식 · 점광원 수 · 끊김 · 멈춤 · 마지막 기록 · PC 상태. public static object State() { var pc = MyValue.MyPC as PCActor; var part = pc != null ? HammerPart(pc) : null; int glow = 0, lamp = 0; foreach (var r in Object.FindObjectsByType(FindObjectsInactive.Include, FindObjectsSortMode.None)) if (r.name == "[WL912] Glow") glow++; foreach (var l in Object.FindObjectsByType(FindObjectsInactive.Include, FindObjectsSortMode.None)) if (l.name == "[WL912] ChargeLight") lamp++; return "망치 배율 " + (part != null ? part.localScale.x.ToString("F2") : "-") + " · 흰 빛 자식 " + glow + " · 광원 " + lamp + " · 끊김 " + WL.PartSkill.SkHammerQuake.Aborted + " · 멈춤 " + WL.PartSkill.SkHammerQuake.Holds + " · " + WL.PartSkill.SkHammerQuake.LastLog + " · 상태 " + (pc != null ? pc.Get_CurAnim().ToString() : "-"); } /// 시험 중 실행기 자동 시전 막기 — 대지 분쇄 쿨타임을 크게(핫키 Fire 는 쿨타임 무시). public static object BlockAuto() { var run = WL.PartSkill.WLPartSkillRunner.Instance; if (run == null) return "실행기 없음"; int n = 0; foreach (var sk in run.Skills) if (sk != null && sk.def != null && sk.def.key == "hammer_quake") { sk.cd = 999f; n++; } return "자동 시전 막음 " + n; } static string P(Transform t, Transform root) { var s = t.name; while (t.parent != null && t.parent != root) { t = t.parent; s = t.name + "/" + s; } return s; } public static object Hammer() { var pc = MyValue.MyPC as PCActor; if (pc == null) return "PC 없음"; var ss = pc.tfs_weapon; if (ss == null) return "소켓 없음"; var sb = new StringBuilder(); for (int i = 0; i < ss.Length; i++) { var s = ss[i]; if (s == null) { sb.AppendLine(i + " null"); continue; } sb.AppendLine(i + " " + P(s, pc.transform) + " act " + s.gameObject.activeInHierarchy + " ls " + s.localScale.ToString("F2") + " lossy " + s.lossyScale.ToString("F3")); foreach (Transform c in s) sb.AppendLine(" child " + c.name + " lp " + c.localPosition.ToString("F3") + " lr " + c.localEulerAngles.ToString("F0") + " ls " + c.localScale.ToString("F3") + " act " + c.gameObject.activeSelf + " n " + c.childCount); foreach (var r in s.GetComponentsInChildren(true)) { var mf = r.GetComponent(); var smr = r as SkinnedMeshRenderer; var mesh = mf != null ? mf.sharedMesh : smr != null ? smr.sharedMesh : null; sb.Append(" R ").Append(r.GetType().Name).Append(" ").Append(P(r.transform, s)).Append(" en ").Append(r.enabled).Append(" act ").Append(r.gameObject.activeInHierarchy) .Append(" mesh ").Append(mesh != null ? mesh.name + " sub " + mesh.subMeshCount + " b " + mesh.bounds.size.ToString("F2") + " c " + mesh.bounds.center.ToString("F2") + " rw " + mesh.isReadable : "-") .Append(" lossy ").Append(r.transform.lossyScale.ToString("F3")).Append(" wb ").Append(r.bounds.size.ToString("F2")) .Append(" layer ").Append(r.gameObject.layer).Append(" mpb ").Append(r.HasPropertyBlock()).Append(" mats"); foreach (var m in r.sharedMaterials) sb.Append(" [").Append(m != null ? m.name + " / " + (m.shader != null ? m.shader.name : "-") : "null").Append("]"); sb.AppendLine(); } } return sb.ToString(); } public static object Post() { var sb = new StringBuilder(); var cam = Camera.main; if (cam != null) { var d = cam.GetComponent(); sb.AppendLine("카메라 " + cam.name + " 후처리 " + (d != null && d.renderPostProcessing) + " HDR " + cam.allowHDR); } foreach (var v in Object.FindObjectsByType(FindObjectsInactive.Exclude, FindObjectsSortMode.None)) { var prof = v.sharedProfile; Bloom b = null; bool hb = prof != null && prof.TryGet(out b); sb.AppendLine("볼륨 " + v.name + " 전역 " + v.isGlobal + " 우선 " + v.priority + " 무게 " + v.weight + " 켜짐 " + v.enabled + " 프로필 " + (prof != null ? prof.name : "-") + (hb ? " 블룸 " + b.active + " 세기 " + b.intensity.value.ToString("F2") + " 문턱 " + b.threshold.value.ToString("F2") : " 블룸 없음")); } var stack = VolumeManager.instance.stack; var bl = stack != null ? stack.GetComponent() : null; if (bl != null) sb.AppendLine("최종 블룸 세기 " + bl.intensity.value.ToString("F2") + " 문턱 " + bl.threshold.value.ToString("F2") + " 켜짐 " + bl.IsActive()); return sb.ToString(); } public static object TipCurve(string state, float from, float to, float step) { var pc = MyValue.MyPC as PCActor; if (pc == null || pc.m_animation == null) return "PC 없음"; Transform sock = null; Vector3 tipL = Vector3.zero; float best = 0f; foreach (var s in pc.tfs_weapon) { if (s == null || !s.gameObject.activeInHierarchy) continue; foreach (var r in s.GetComponentsInChildren(false)) { if (r == null || !r.enabled) continue; var mf = r.GetComponent(); var smr = r as SkinnedMeshRenderer; Bounds lb; if (mf != null && mf.sharedMesh != null) lb = mf.sharedMesh.bounds; else if (smr != null) lb = smr.localBounds; else continue; for (int c = 0; c < 8; c++) { var corner = lb.center + new Vector3((c & 1) == 0 ? -lb.extents.x : lb.extents.x, (c & 2) == 0 ? -lb.extents.y : lb.extents.y, (c & 4) == 0 ? -lb.extents.z : lb.extents.z); var local = s.InverseTransformPoint(r.transform.TransformPoint(corner)); if (local.magnitude > best) { best = local.magnitude; sock = s; tipL = local; } } } } if (sock == null) return "망치 없음"; var an = pc.m_animation; var root = pc.transform; var sb = new StringBuilder(); sb.AppendLine("소켓 " + sock.name + " 끝 " + tipL.ToString("F3") + " 길이 " + best.ToString("F3")); bool fe = an.fireEvents; an.fireEvents = false; for (float n = from; n <= to + 1e-4f; n += step) { an.Play(state, 0, n); an.speed = 0f; an.Update(0f); var tip = sock.TransformPoint(tipL); var lp = root.InverseTransformPoint(tip); sb.AppendLine(n.ToString("F2") + " 높이 " + (tip.y - root.position.y).ToString("F2") + " 앞 " + lp.z.ToString("F2") + " 옆 " + lp.x.ToString("F2")); } an.speed = 1f; an.fireEvents = fe; pc.Play_Idle(); return sb.ToString(); } }