Project_WL/AgentScripts/WL912_Probe.cs

363 lines
24 KiB
C#

// 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;
}
/// <summary>각성(E) 발동 → 프레임마다 상태 · 속도 · 정규화 시간 · 망치 배율 · 흰 빛 · 점광원 · PC 이동 · 이동 무시 횟수. pauseAt>0 = 그때 일시 정지.
/// pushMove=1 이면 멈춤(Holds 증가) 동안부터 1 초간 오른쪽 이동 입력.</summary>
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<MobActor>(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<MeshRenderer>(false) : null; bool glowOn = false;
if (part != null) foreach (var r in part.GetComponentsInChildren<MeshRenderer>(false)) if (r.name == "[WL912] Glow" && r.enabled) glowOn = true;
var lampGo = GameObject.Find("[WL912] ChargeLight"); var lamp = lampGo != null ? lampGo.GetComponent<Light>() : null;
// #913 모으기 이펙트 위치(망치 메시 로컬 · 메시 상자 중심 · 크기와 비교)
var fxGo = GameObject.Find("WL_Fx_HammerCharge(Clone)"); Transform hm = null;
if (part != null) foreach (var r in part.GetComponentsInChildren<MeshRenderer>(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;
}
/// <summary>#914 검 각성(E) — 프레임마다 클립 · 상태 · 이 PC 의 돌진 베기 투사체 켜짐 · 이동 거리 · 동작 끝 횟수 · 타격 창. pushMove=1 이면 처음부터 오른쪽 이동 입력.</summary>
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<Skill_DashSlash>(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); }
/// <summary>#915 검 각성 밀림 — 시험 몹을 PC 정면 dist m 에 세우고 각성 → 몹이 맞을 때마다 PC 와 거리 · 밀린 거리 · 상태 · 경직, 끝에 총 밀림 · 명중 수 · 규칙 적용 수.
/// off = 1 이면 스킬별 피격 반응(WLSkillHitFeel)을 끄고 잰다(전후 비교).</summary>
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<MobActor>(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);
}
/// <summary>#914 해머 각성 둘레 피해 — 시험 몹을 PC 오른쪽 side m(충격파 갈래 밖)에 세우고 각성 → 1.6 초 뒤 둘레 명중 · 전체 명중 · 몹 높이 · 기절.</summary>
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<MobActor>(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;
}
/// <summary>#914 해머 주력(Q · 강력한 일격) — 발동 뒤 그 스킬 판정 상자 크기 · pauseAt 에 일시 정지.</summary>
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<Skill_JumpAttack>(FindObjectsInactive.Exclude, FindObjectsSortMode.None))
{
var pd = s.Get_ProjectTileData(); if (pd == null || !ReferenceEquals(pd.shooter, pc)) continue;
var bc = s.GetComponent<BoxCollider>(); 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);
}
/// <summary>#914 지금 PC 둘레 radius m 안에 입자가 살아 있는 파티클 — 최상위 오브젝트 · 이름 · 입자 수 · 시작색 · 재질(검은 이펙트 출처 찾기).</summary>
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<ParticleSystem>(FindObjectsInactive.Exclude, FindObjectsSortMode.None))
{
if (ps.particleCount == 0 || Vector3.Distance(ps.transform.position, p) > radius) continue;
var m = ps.main; var r = ps.GetComponent<ParticleSystemRenderer>(); 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();
}
/// <summary>망치 배율 · 남은 흰 빛 자식 · 점광원 수 · 끊김 · 멈춤 · 마지막 기록 · PC 상태.</summary>
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<MeshRenderer>(FindObjectsInactive.Include, FindObjectsSortMode.None)) if (r.name == "[WL912] Glow") glow++;
foreach (var l in Object.FindObjectsByType<Light>(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() : "-");
}
/// <summary>시험 중 실행기 자동 시전 막기 — 대지 분쇄 쿨타임을 크게(핫키 Fire 는 쿨타임 무시).</summary>
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<Renderer>(true))
{
var mf = r.GetComponent<MeshFilter>(); 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<UniversalAdditionalCameraData>(); sb.AppendLine("카메라 " + cam.name + " 후처리 " + (d != null && d.renderPostProcessing) + " HDR " + cam.allowHDR); }
foreach (var v in Object.FindObjectsByType<Volume>(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<Bloom>() : 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<Renderer>(false))
{
if (r == null || !r.enabled) continue;
var mf = r.GetComponent<MeshFilter>(); 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();
}
}