449 lines
29 KiB
C#
449 lines
29 KiB
C#
|
|
// WL899_Probe.cs — PD 지시 #899 시험(Play 중 · 섬)
|
|||
|
|
// Cast(dist, sec) : 시험 몹을 PC 정면 dist(m)에 세우고 주력 스킬(Q 경로 = WLSkillHotkey.Fire)을 쏜 뒤 sec 초 동안 매 프레임 기록(상태 · 정규화 시간 · 재생 배속 · 몹 거리)
|
|||
|
|
// Move(sec) : 검기 호 이펙트가 떠 있는 프레임을 기다렸다가 조이스틱 이동(상태 1 + Run_byJoystick)을 sec 초 넣고 호 이펙트가 꺼지는지 기록
|
|||
|
|
// Log() : 위 기록 · Hammer() : 강력한 일격 이펙트 크기 노드 배율 · 판정 상자
|
|||
|
|
using System.Text;
|
|||
|
|
using UnityEngine;
|
|||
|
|
|
|||
|
|
public static class WL899_Probe
|
|||
|
|
{
|
|||
|
|
const string Key = "wl899log";
|
|||
|
|
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;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
static Actor Dummy()
|
|||
|
|
{
|
|||
|
|
var d = WL.IslandMob.WLTrailTest.Dummy;
|
|||
|
|
if (d != null && d.isActiveAndEnabled) return d;
|
|||
|
|
var pc = MyValue.MyPC; Actor best = null; float bd = float.MaxValue;
|
|||
|
|
foreach (var m in Object.FindObjectsByType<MobActor>(FindObjectsInactive.Exclude, FindObjectsSortMode.None))
|
|||
|
|
{
|
|||
|
|
if (m == null || m.IsDead()) continue;
|
|||
|
|
float dd = pc != null ? Vector3.Distance(pc.Get_position(), m.Get_position()) : 0f;
|
|||
|
|
if (dd < bd) { bd = dd; best = m; }
|
|||
|
|
}
|
|||
|
|
return best;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
static string StateName(Animator a, AnimatorStateInfo st)
|
|||
|
|
{
|
|||
|
|
foreach (var n in new[] { "shieldattack", "shieldbash", "idle", "run", "jump", "attack", "Attack2", "Attack3", "dash" })
|
|||
|
|
if (st.IsName(n)) return n;
|
|||
|
|
return "#" + st.shortNameHash;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public static object Cast(float dist, float seconds)
|
|||
|
|
{
|
|||
|
|
var pc = MyValue.MyPC; var d = Dummy();
|
|||
|
|
if (pc == null || d == null) return "PC/몹 없음";
|
|||
|
|
if (dist > 0f)
|
|||
|
|
{
|
|||
|
|
var f = pc.transform.forward; f.y = 0f; if (f.sqrMagnitude < 1e-4f) f = Vector3.forward; 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);
|
|||
|
|
}
|
|||
|
|
var sb = Buf(); sb.Length = 0;
|
|||
|
|
float t0 = Time.time, acc0 = WL.Combat.AttackRootMotion.SwingAccum;
|
|||
|
|
Vector3 p0 = pc.Get_position();
|
|||
|
|
sb.Append("시작 거리 ").Append(Vector3.Distance(pc.Get_position(), d.Get_position()).ToString("F2")).Append('\n');
|
|||
|
|
UnityEngine.Events.UnityAction act = null;
|
|||
|
|
act = () =>
|
|||
|
|
{
|
|||
|
|
if (pc == null || pc.m_animation == null || d == null) { Application.onBeforeRender -= act; return; }
|
|||
|
|
var a = pc.m_animation; var st = a.GetCurrentAnimatorStateInfo(0);
|
|||
|
|
sb.AppendFormat("{0:F2} {1} n={2:F2} sp={3:F2} d={4:F2} tr={5} {6}\n", Time.time - t0, StateName(a, st), st.normalizedTime, a.speed,
|
|||
|
|
Vector3.Distance(pc.Get_position(), d.Get_position()), a.IsInTransition(0) ? 1 : 0, pc.Get_CurAnim());
|
|||
|
|
if (Time.time - t0 > seconds)
|
|||
|
|
{
|
|||
|
|
Application.onBeforeRender -= act;
|
|||
|
|
sb.Append("끝 · PC 이동 ").Append(Vector3.Distance(p0, pc.Get_position()).ToString("F2")).Append(" m · 표 전진 합 ")
|
|||
|
|
.Append((WL.Combat.AttackRootMotion.SwingAccum - acc0).ToString("F2")).Append(" m\n");
|
|||
|
|
}
|
|||
|
|
};
|
|||
|
|
Application.onBeforeRender += act;
|
|||
|
|
string r = WL.Combat.Weapon.WLSkillHotkey.Fire();
|
|||
|
|
return "발동: " + r + " · 거리 " + Vector3.Distance(pc.Get_position(), d.Get_position()).ToString("F2");
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public static object Move(float seconds)
|
|||
|
|
{
|
|||
|
|
var pc = MyValue.MyPC as PCActor;
|
|||
|
|
if (pc == null) return "PC 없음";
|
|||
|
|
var sb = Buf(); sb.Length = 0;
|
|||
|
|
int k0 = WL.Combat.SlashArcFollower.KillOnMoveCount;
|
|||
|
|
float t0 = Time.time, moveStart = -1f; int arcAtStart = -1;
|
|||
|
|
var dir = pc.transform.right; dir.y = 0f; dir.Normalize();
|
|||
|
|
UnityEngine.Events.UnityAction act = null;
|
|||
|
|
act = () =>
|
|||
|
|
{
|
|||
|
|
if (pc == null) { Application.onBeforeRender -= act; return; }
|
|||
|
|
int arcs = 0;
|
|||
|
|
foreach (var f in Object.FindObjectsByType<WL.Combat.SlashArcFollower>(FindObjectsInactive.Exclude, FindObjectsSortMode.None)) if (f.isActiveAndEnabled) arcs++;
|
|||
|
|
if (moveStart < 0f)
|
|||
|
|
{
|
|||
|
|
if (arcs > 0) { moveStart = Time.time; arcAtStart = arcs; pc.Set_JoystickStatus(1); sb.Append("호 이펙트 ").Append(arcs).Append("개 떠 있을 때 이동 시작 · ").Append(pc.Get_CurAnim()).Append('\n'); }
|
|||
|
|
else if (Time.time - t0 > 6f) { Application.onBeforeRender -= act; sb.Append("6초 안에 호 이펙트가 안 떠서 중단\n"); }
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
pc.Run_byJoystick(dir);
|
|||
|
|
sb.AppendFormat("{0:F2} 이동 중 · 호 {1} · 소멸 누적 +{2} · 상태 {3}\n", Time.time - moveStart, arcs, WL.Combat.SlashArcFollower.KillOnMoveCount - k0, pc.JoystickStatus);
|
|||
|
|
if (Time.time - moveStart > seconds) { pc.Set_JoystickStatus(3); pc.Set_AutoBraking(true); Application.onBeforeRender -= act; sb.Append("이동 끝(상태 ").Append(pc.JoystickStatus).Append(")\n"); }
|
|||
|
|
};
|
|||
|
|
Application.onBeforeRender += act;
|
|||
|
|
return "이동 시험 대기 시작";
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>휘두르는 도중(WeaponTrailDriver 스윙 창 열림)에 이동을 넣고 스윙 창이 바로 닫히는지 · 그 뒤 호 이펙트가 새로 안 뜨는지 기록.</summary>
|
|||
|
|
public static object MoveInSwing(float seconds)
|
|||
|
|
{
|
|||
|
|
var pc = MyValue.MyPC as PCActor;
|
|||
|
|
if (pc == null) return "PC 없음";
|
|||
|
|
var drv = pc.GetComponentInChildren<WL.Combat.WeaponTrailDriver>(true);
|
|||
|
|
var fSwing = typeof(WL.Combat.WeaponTrailDriver).GetField("_swingActive", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);
|
|||
|
|
if (drv == null || fSwing == null) return "궤적 드라이버/필드 없음 drv=" + (drv != null);
|
|||
|
|
var sb = Buf(); sb.Length = 0;
|
|||
|
|
float t0 = Time.time, moveStart = -1f;
|
|||
|
|
var dir = pc.transform.right; dir.y = 0f; dir.Normalize();
|
|||
|
|
UnityEngine.Events.UnityAction act = null;
|
|||
|
|
act = () =>
|
|||
|
|
{
|
|||
|
|
if (pc == null || drv == null) { Application.onBeforeRender -= act; return; }
|
|||
|
|
bool swing = (bool)fSwing.GetValue(drv);
|
|||
|
|
int arcs = 0;
|
|||
|
|
foreach (var f in Object.FindObjectsByType<WL.Combat.SlashArcFollower>(FindObjectsInactive.Exclude, FindObjectsSortMode.None)) if (f.isActiveAndEnabled) arcs++;
|
|||
|
|
if (moveStart < 0f)
|
|||
|
|
{
|
|||
|
|
if (swing) { moveStart = Time.time; pc.Set_JoystickStatus(1); sb.Append("스윙 중(호 ").Append(arcs).Append("개) 이동 시작 · ").Append(pc.Get_CurAnim()).Append('\n'); }
|
|||
|
|
else if (Time.time - t0 > 6f) { Application.onBeforeRender -= act; sb.Append("6초 안에 스윙 창을 못 잡아 중단\n"); }
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
pc.Run_byJoystick(dir);
|
|||
|
|
sb.AppendFormat("{0:F2} 이동 중 · 스윙 창 {1} · 호 {2}\n", Time.time - moveStart, swing ? "열림" : "닫힘", arcs);
|
|||
|
|
if (Time.time - moveStart > seconds) { pc.Set_JoystickStatus(3); pc.Set_AutoBraking(true); Application.onBeforeRender -= act; sb.Append("이동 끝\n"); }
|
|||
|
|
};
|
|||
|
|
Application.onBeforeRender += act;
|
|||
|
|
return "스윙 중 이동 시험 대기 시작";
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>주력 스킬을 쏘고 sec 초 동안 켜진 파티클 렌더러를 최상위 이펙트 이름별로 모아 가장 컸던 지름(월드 bounds XZ)을 기록.</summary>
|
|||
|
|
public static object CastFx(float dist, float seconds)
|
|||
|
|
{
|
|||
|
|
var pc = MyValue.MyPC; var d = Dummy();
|
|||
|
|
if (pc == null || d == null) return "PC/몹 없음";
|
|||
|
|
if (dist > 0f)
|
|||
|
|
{
|
|||
|
|
var f = pc.transform.forward; f.y = 0f; if (f.sqrMagnitude < 1e-4f) f = Vector3.forward; 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);
|
|||
|
|
}
|
|||
|
|
var sb = Buf(); sb.Length = 0;
|
|||
|
|
var maxSize = new System.Collections.Generic.Dictionary<string, float>();
|
|||
|
|
var firstAt = new System.Collections.Generic.Dictionary<string, float>();
|
|||
|
|
float t0 = Time.time;
|
|||
|
|
UnityEngine.Events.UnityAction act = null;
|
|||
|
|
act = () =>
|
|||
|
|
{
|
|||
|
|
foreach (var r in Object.FindObjectsByType<ParticleSystemRenderer>(FindObjectsInactive.Exclude, FindObjectsSortMode.None))
|
|||
|
|
{
|
|||
|
|
if (r == null || !r.enabled) continue;
|
|||
|
|
var ps = r.GetComponent<ParticleSystem>(); if (ps == null || ps.particleCount == 0) continue;
|
|||
|
|
var root = r.transform.root; string key = root.name + "/" + r.name;
|
|||
|
|
if (pc != null && root == pc.transform.root) key = "(PC)/" + r.name;
|
|||
|
|
var b = r.bounds; float sz = Mathf.Max(b.size.x, b.size.z);
|
|||
|
|
if (Vector3.Distance(new Vector3(b.center.x, 0, b.center.z), new Vector3(pc.Get_position().x, 0, pc.Get_position().z)) > 6f) continue;
|
|||
|
|
float cur; if (!maxSize.TryGetValue(key, out cur) || sz > cur) maxSize[key] = sz;
|
|||
|
|
if (!firstAt.ContainsKey(key)) firstAt[key] = Time.time - t0;
|
|||
|
|
}
|
|||
|
|
if (Time.time - t0 > seconds)
|
|||
|
|
{
|
|||
|
|
Application.onBeforeRender -= act;
|
|||
|
|
var list = new System.Collections.Generic.List<System.Collections.Generic.KeyValuePair<string, float>>(maxSize);
|
|||
|
|
list.Sort((a, b) => b.Value.CompareTo(a.Value));
|
|||
|
|
foreach (var kv in list) sb.Append(kv.Value.ToString("F1")).Append(" m @").Append(firstAt[kv.Key].ToString("F2")).Append("s ").Append(kv.Key).Append('\n');
|
|||
|
|
}
|
|||
|
|
};
|
|||
|
|
Application.onBeforeRender += act;
|
|||
|
|
return "발동: " + WL.Combat.Weapon.WLSkillHotkey.Fire();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ── #900 ──────────────────────────────────────────────────────────────
|
|||
|
|
static int StageOf(PCActor pc) { var ct = pc != null ? pc.GetComponent<WL.Combat.Core.ComboTracker>() : null; return ct != null ? ct.LastStage : -1; }
|
|||
|
|
|
|||
|
|
/// <summary>검기(호 · 찌르기) 배치마다 PC 중심에서 가장 먼 수평 거리 · 정면 투영 거리를 기록(sec 초).</summary>
|
|||
|
|
public static object Slash(float seconds)
|
|||
|
|
{
|
|||
|
|
var pc = MyValue.MyPC as PCActor; if (pc == null) return "PC 없음";
|
|||
|
|
var sb = Buf(); sb.Length = 0;
|
|||
|
|
int last = WL.Combat.WeaponTrailDriver.MappedSpawnCount; float t0 = Time.time;
|
|||
|
|
UnityEngine.Events.UnityAction act = null;
|
|||
|
|
act = () =>
|
|||
|
|
{
|
|||
|
|
if (pc == null) { Application.onBeforeRender -= act; return; }
|
|||
|
|
int n = WL.Combat.WeaponTrailDriver.MappedSpawnCount;
|
|||
|
|
if (n != last)
|
|||
|
|
{
|
|||
|
|
last = n;
|
|||
|
|
var p = WL.Combat.WeaponTrailDriver.LastPlacement;
|
|||
|
|
Vector3 c = pc.Get_position(); var f = pc.transform.forward; f.y = 0f; f.Normalize();
|
|||
|
|
float maxD = 0f, maxF = 0f;
|
|||
|
|
if (p.kind == WL.Combat.SwingKind.Stab)
|
|||
|
|
{
|
|||
|
|
var e = p.stabStartPlaced + p.stabAxisPlaced.normalized * p.stabLenPlaced;
|
|||
|
|
foreach (var q in new[] { p.stabStartPlaced, e }) { var v = q - c; v.y = 0f; maxD = Mathf.Max(maxD, v.magnitude); maxF = Mathf.Max(maxF, Vector3.Dot(v, f)); }
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
var b = p.arcBisector.normalized; var side = Vector3.Cross(p.arcNormal.normalized, b).normalized;
|
|||
|
|
for (int k = -20; k <= 20; k++)
|
|||
|
|
{
|
|||
|
|
float th = k / 20f * p.sweepMesh * 0.5f * Mathf.Deg2Rad;
|
|||
|
|
var q = p.arcCenter + p.arcRadius * (Mathf.Cos(th) * b + Mathf.Sin(th) * side);
|
|||
|
|
var v = q - c; v.y = 0f; maxD = Mathf.Max(maxD, v.magnitude); maxF = Mathf.Max(maxF, Vector3.Dot(v, f));
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
var tg = pc.Get_Target();
|
|||
|
|
sb.AppendFormat("{0:F2}s 단계 {1} {2} {3} · 가장 먼 거리 {4:F2} · 정면 {5:F2} · 반지름 {6:F2} · 적 {7}\n", Time.time - t0, StageOf(pc), p.kind, p.effect, maxD, maxF, p.arcRadius,
|
|||
|
|
tg != null ? Vector3.Distance(c, tg.Get_position()).ToString("F2") : "-");
|
|||
|
|
}
|
|||
|
|
if (Time.time - t0 > seconds) { Application.onBeforeRender -= act; sb.Append("끝 · 원 반지름 ").Append(WL.Combat.RangeRing.WLRangeRing.AttackReach(pc).ToString("F2")).Append('\n'); }
|
|||
|
|
};
|
|||
|
|
Application.onBeforeRender += act;
|
|||
|
|
return "검기 기록 시작";
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>해머 — 콤보 1단계 시작 때 적 거리 · 지면 충격파 자리(PC 중심에서 수평 · 정면) 기록(sec 초).</summary>
|
|||
|
|
public static object Ground(float seconds)
|
|||
|
|
{
|
|||
|
|
var pc = MyValue.MyPC as PCActor; if (pc == null) return "PC 없음";
|
|||
|
|
var sb = Buf(); sb.Length = 0;
|
|||
|
|
int g0 = WL.Combat.Impact.WLImpactFx.GroundShown, lastStage = StageOf(pc); float t0 = Time.time;
|
|||
|
|
UnityEngine.Events.UnityAction act = null;
|
|||
|
|
act = () =>
|
|||
|
|
{
|
|||
|
|
if (pc == null) { Application.onBeforeRender -= act; return; }
|
|||
|
|
int st = StageOf(pc); var tg = pc.Get_Target(); Vector3 c = pc.Get_position();
|
|||
|
|
if (st != lastStage) { lastStage = st; sb.AppendFormat("{0:F2}s 단계 {1} 시작 · 적 {2}\n", Time.time - t0, st, tg != null ? Vector3.Distance(c, tg.Get_position()).ToString("F2") : "-"); }
|
|||
|
|
int g = WL.Combat.Impact.WLImpactFx.GroundShown;
|
|||
|
|
if (g != g0)
|
|||
|
|
{
|
|||
|
|
g0 = g; string s = WL.Combat.Impact.WLImpactFx.LastGround; int i = s.LastIndexOf('@');
|
|||
|
|
var parts = i >= 0 ? s.Substring(i + 2).TrimEnd(')').Split(',') : new string[0];
|
|||
|
|
if (parts.Length == 3)
|
|||
|
|
{
|
|||
|
|
var q = new Vector3(float.Parse(parts[0]), float.Parse(parts[1]), float.Parse(parts[2]));
|
|||
|
|
var v = q - c; v.y = 0f; var f = pc.transform.forward; f.y = 0f; f.Normalize();
|
|||
|
|
var td = tg != null ? tg.Get_position() - c : f; td.y = 0f; td.Normalize();
|
|||
|
|
var mf = pc.m_animation != null ? pc.m_animation.transform.forward : f; mf.y = 0f; mf.Normalize();
|
|||
|
|
sb.AppendFormat("{0:F2}s 충격파 · 수평 {1:F2} · 적 방향 {2:F2} · 루트 정면 {3:F2} · 모델 정면 {4:F2} · 적 {5} · 충격파-적 {6}\n", Time.time - t0, v.magnitude, Vector3.Dot(v, td), Vector3.Dot(v, f), Vector3.Dot(v, mf),
|
|||
|
|
tg != null ? Vector3.Distance(c, tg.Get_position()).ToString("F2") : "-", tg != null ? Vector3.Distance(new Vector3(q.x, 0, q.z), new Vector3(tg.Get_position().x, 0, tg.Get_position().z)).ToString("F2") : "-");
|
|||
|
|
}
|
|||
|
|
else sb.Append(s).Append('\n');
|
|||
|
|
}
|
|||
|
|
if (Time.time - t0 > seconds) { Application.onBeforeRender -= act; sb.Append("끝 · 원 ").Append(WL.Combat.RangeRing.WLRangeRing.AttackReach(pc).ToString("F2")).Append(" · 정지 ").Append(WL.Combat.WLCombatMotionSettings.ApproachStop(pc, -1f).ToString("F2")).Append('\n'); }
|
|||
|
|
};
|
|||
|
|
Application.onBeforeRender += act;
|
|||
|
|
return "해머 기록 시작";
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>몹을 dist 에 세우고 주력 스킬 쿨 · 자동 간격을 0 으로 만든 뒤 sec 초 동안 상태 · 거리 · 대쉬 · 대쉬 시전 수를 기록(대쉬 후 방패 치기 확인).</summary>
|
|||
|
|
public static object Watch(float dist, float seconds)
|
|||
|
|
{
|
|||
|
|
var pc = MyValue.MyPC as PCActor; var d = Dummy();
|
|||
|
|
if (pc == null || d == null) return "PC/몹 없음";
|
|||
|
|
var f = pc.transform.forward; f.y = 0f; if (f.sqrMagnitude < 1e-4f) f = Vector3.forward; 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.Set_MagicCoolTime(0f, 0);
|
|||
|
|
var fa = typeof(PCActor).GetField("t_autoskill", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Public);
|
|||
|
|
if (fa != null) fa.SetValue(pc, 0f);
|
|||
|
|
var sb = Buf(); sb.Length = 0;
|
|||
|
|
int dc0 = WL.Combat.Weapon.WLWeaponSkillSlots.DashCasts; float t0 = Time.time; string lastState = "";
|
|||
|
|
UnityEngine.Events.UnityAction act = null;
|
|||
|
|
act = () =>
|
|||
|
|
{
|
|||
|
|
if (pc == null || d == null) { Application.onBeforeRender -= act; return; }
|
|||
|
|
var a = pc.m_animation; var st = a.GetCurrentAnimatorStateInfo(0); string sn = StateName(a, st);
|
|||
|
|
bool dash = WL.Combat.DashDriver.IsDashingNow(pc);
|
|||
|
|
string key = sn + (dash ? "+대쉬" : "");
|
|||
|
|
if (key != lastState)
|
|||
|
|
{
|
|||
|
|
lastState = key;
|
|||
|
|
sb.AppendFormat("{0:F2}s {1} · 거리 {2:F2} · 대쉬 시전 +{3} · {4}\n", Time.time - t0, key, Vector3.Distance(pc.Get_position(), d.Get_position()),
|
|||
|
|
WL.Combat.Weapon.WLWeaponSkillSlots.DashCasts - dc0, pc.Get_CurAnim());
|
|||
|
|
}
|
|||
|
|
if (Time.time - t0 > seconds) { Application.onBeforeRender -= act; sb.Append("끝 · 거리 ").Append(Vector3.Distance(pc.Get_position(), d.Get_position()).ToString("F2")).Append(" · 마지막 대쉬 시전 ").Append(WL.Combat.Weapon.WLWeaponSkillSlots.LastDashCast).Append(" · ").Append(WL.Combat.DashDriver.LastInfo).Append('\n'); }
|
|||
|
|
};
|
|||
|
|
Application.onBeforeRender += act;
|
|||
|
|
return "관찰 시작 · 몹 " + Vector3.Distance(pc.Get_position(), d.Get_position()).ToString("F2") + " m";
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ── #902 ──
|
|||
|
|
/// <summary>해머 기본 공격 판정 상자(Projectile_10501)의 PC 정면 최대 도달 · 3타 넉백/기절 · 점프 스킬 카운터를 sec 초 기록.</summary>
|
|||
|
|
public static object Hammer902(float seconds)
|
|||
|
|
{
|
|||
|
|
var pc = MyValue.MyPC as PCActor; if (pc == null) return "PC 없음";
|
|||
|
|
var sb = Buf(); sb.Length = 0;
|
|||
|
|
float t0 = Time.time, maxF = 0f, maxD = 0f; int boxes = 0;
|
|||
|
|
int st0 = WL.Combat.Weapon.WLStageHitReaction.Applied, fc0 = WL.Combat.Weapon.WLWeaponSkillSlots.FirstCasts, la0 = WL.Combat.Weapon.WLLaunch.Launches, kb0 = WL.Combat.Weapon.WLLaunch.Knockbacks;
|
|||
|
|
var seen = new System.Collections.Generic.HashSet<int>();
|
|||
|
|
UnityEngine.Events.UnityAction act = null;
|
|||
|
|
act = () =>
|
|||
|
|
{
|
|||
|
|
if (pc == null) { Application.onBeforeRender -= act; return; }
|
|||
|
|
Vector3 c = pc.Get_position(); var f = pc.transform.forward; f.y = 0f; f.Normalize();
|
|||
|
|
foreach (var pb in Object.FindObjectsByType<ProjectileBase>(FindObjectsInactive.Exclude, FindObjectsSortMode.None))
|
|||
|
|
{
|
|||
|
|
if (pb == null || !pb.name.StartsWith("Projectile_1050")) continue;
|
|||
|
|
var bc = pb.GetComponent<BoxCollider>(); if (bc == null || !bc.enabled) continue;
|
|||
|
|
if (seen.Add(pb.GetInstanceID() ^ Time.frameCount)) { }
|
|||
|
|
boxes++;
|
|||
|
|
var b = bc.bounds;
|
|||
|
|
for (int k = 0; k < 8; k++)
|
|||
|
|
{
|
|||
|
|
var q = b.center + new Vector3((k & 1) == 0 ? -b.extents.x : b.extents.x, 0f, (k & 4) == 0 ? -b.extents.z : b.extents.z);
|
|||
|
|
var v = q - c; v.y = 0f; maxF = Mathf.Max(maxF, Vector3.Dot(v, f)); maxD = Mathf.Max(maxD, v.magnitude);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
if (Time.time - t0 > seconds)
|
|||
|
|
{
|
|||
|
|
Application.onBeforeRender -= act;
|
|||
|
|
sb.AppendFormat("판정 상자 프레임 {0} · 정면 최대 {1:F2} m · 모서리 최대 {2:F2} m\n", boxes, maxF, maxD);
|
|||
|
|
sb.Append("3타 반응 +").Append(WL.Combat.Weapon.WLStageHitReaction.Applied - st0).Append(" · 넉백 +").Append(WL.Combat.Weapon.WLLaunch.Knockbacks - kb0).Append(" · ").Append(WL.Combat.Weapon.WLStageHitReaction.LastLog).Append('\n');
|
|||
|
|
sb.Append("우선 시전 +").Append(WL.Combat.Weapon.WLWeaponSkillSlots.FirstCasts - fc0).Append(" · 띄우기 +").Append(WL.Combat.Weapon.WLLaunch.Launches - la0)
|
|||
|
|
.Append(" · 가운데 ").Append(WL.Combat.Weapon.WLSkillVfx.Centers).Append(" · 8방향 ").Append(WL.Combat.Weapon.WLSkillVfx.Radials).Append(" · 원 ").Append(WL.Combat.RangeRing.WLRangeRing.LastRadius.ToString("F2")).Append('\n');
|
|||
|
|
}
|
|||
|
|
};
|
|||
|
|
Application.onBeforeRender += act;
|
|||
|
|
return "해머 #902 기록 시작";
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ── #903 몹 AI 관찰 ──
|
|||
|
|
static readonly System.Reflection.BindingFlags BF = System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Public;
|
|||
|
|
static object F(object o, string n) { for (var t = o.GetType(); t != null; t = t.BaseType) { var f = t.GetField(n, BF); if (f != null) return f.GetValue(o); } return null; }
|
|||
|
|
static void SetF(object o, string n, object v) { for (var t = o.GetType(); t != null; t = t.BaseType) { var f = t.GetField(n, BF); if (f != null) { f.SetValue(o, v); return; } } }
|
|||
|
|
|
|||
|
|
/// <summary>PC 를 멈추게(stopPc) 하고 시험 몹의 상태 · 거리 · 정지 거리 · 루트모션을 상태가 바뀔 때마다 기록(sec 초).</summary>
|
|||
|
|
public static object MobWatch(float dist, float seconds, bool stopPc)
|
|||
|
|
{
|
|||
|
|
var pc = MyValue.MyPC as PCActor; var d = (s_pick != null && s_pick.isActiveAndEnabled ? s_pick : Dummy() as MobActor); s_pick = null;
|
|||
|
|
if (pc == null || d == null) return "PC/몹 없음";
|
|||
|
|
if (stopPc) SetF(pc, "IsStop", true);
|
|||
|
|
if (dist > 0f) { var f = pc.transform.forward; f.y = 0f; f.Normalize(); d.Set_Warp(pc.Get_position() + f * dist); }
|
|||
|
|
var sb = Buf(); sb.Length = 0; float t0 = Time.time; string last = "";
|
|||
|
|
var ag = d.Get_Agent();
|
|||
|
|
sb.Append(d.name).Append(" 공격거리(표)=").Append(F(d, "m_NavStopDistance")).Append(" 선공=").Append(F(d, "b_IsFirstAttack")).Append(" 추적=").Append(F(d, "f_BaseChaseRange"))
|
|||
|
|
.Append(" 크기=").Append(d.transform.localScale.x.ToString("F2")).Append(" 루트모션=").Append(d.m_animation != null && d.m_animation.applyRootMotion).Append('\n');
|
|||
|
|
UnityEngine.Events.UnityAction act = null;
|
|||
|
|
act = () =>
|
|||
|
|
{
|
|||
|
|
if (pc == null || d == null) { Application.onBeforeRender -= act; return; }
|
|||
|
|
string key = F(d, "MobStatus") + "/" + d.Get_CurAnim();
|
|||
|
|
float dd = Vector3.Distance(pc.Get_position(), d.Get_position());
|
|||
|
|
if (key != last)
|
|||
|
|
{
|
|||
|
|
last = key;
|
|||
|
|
sb.AppendFormat("{0:F2}s {1} · 거리 {2:F2} · 정지 {3:F2} · 속도 {4:F2} · hitT {5}\n", Time.time - t0, key, dd, ag != null ? ag.stoppingDistance : -1f, ag != null ? ag.velocity.magnitude : -1f, F(d, "m_HitTime"));
|
|||
|
|
}
|
|||
|
|
if (Time.time - t0 > seconds) { Application.onBeforeRender -= act; if (stopPc) SetF(pc, "IsStop", false); sb.AppendFormat("끝 · 거리 {0:F2}\n", dd); }
|
|||
|
|
};
|
|||
|
|
Application.onBeforeRender += act;
|
|||
|
|
return "몹 관찰 시작 · 거리 " + Vector3.Distance(pc.Get_position(), d.Get_position()).ToString("F2");
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>몹 ID(표 n_MonsterID)로 골라 MobWatch 와 같은 기록(없으면 섬 시험 몹 규칙을 끄고 꺼진 몹을 깨운다).</summary>
|
|||
|
|
public static object MobWatchId(int id, float dist, float seconds, bool stopPc)
|
|||
|
|
{
|
|||
|
|
MobActor pick = null;
|
|||
|
|
System.Func<MobActor, int> idOf = m => { var tab = F(m, "m_MonsterTableData") as MonsterTableData; return tab != null ? tab.n_MonsterID : 0; };
|
|||
|
|
foreach (var m in Object.FindObjectsByType<MobActor>(FindObjectsInactive.Include, FindObjectsSortMode.None))
|
|||
|
|
if (m != null && idOf(m) == id) { pick = m; if (m.isActiveAndEnabled && !m.IsDead()) break; }
|
|||
|
|
if (pick == null) return "몹 ID " + id + " 없음";
|
|||
|
|
if (!pick.isActiveAndEnabled) { int prev = WL.IslandMob.WLTrailTest.Override; WL.IslandMob.WLTrailTest.Override = 0; try { pick.On_Regen(); } finally { WL.IslandMob.WLTrailTest.Override = prev; } }
|
|||
|
|
s_pick = pick;
|
|||
|
|
return MobWatch(dist, seconds, stopPc);
|
|||
|
|
}
|
|||
|
|
static MobActor s_pick;
|
|||
|
|
|
|||
|
|
/// <summary>#904 콤보 단계마다 PC 전진(위치 변화) · 표 전진 합(AttackRootMotion.SwingAccum) · 적 거리 · 지금 클립 이름 기록.</summary>
|
|||
|
|
public static object StageMove(float dist, float seconds)
|
|||
|
|
{
|
|||
|
|
var pc = MyValue.MyPC as PCActor; var d = Dummy();
|
|||
|
|
if (pc == null || d == null) return "PC/몹 없음";
|
|||
|
|
if (dist > 0f) { var f = pc.transform.forward; f.y = 0f; f.Normalize(); d.Stop(true); d.Set_Warp(pc.Get_position() + f * dist); }
|
|||
|
|
var sb = Buf(); sb.Length = 0; float t0 = Time.time; int last = -1; Vector3 p0 = pc.Get_position(); float a0 = WL.Combat.AttackRootMotion.SwingAccum;
|
|||
|
|
UnityEngine.Events.UnityAction act = null;
|
|||
|
|
act = () =>
|
|||
|
|
{
|
|||
|
|
if (pc == null || d == null) { Application.onBeforeRender -= act; return; }
|
|||
|
|
int st = StageOf(pc);
|
|||
|
|
if (st != last)
|
|||
|
|
{
|
|||
|
|
var ci = pc.m_animation.GetCurrentAnimatorClipInfo(0); string clip = ci.Length > 0 && ci[0].clip != null ? ci[0].clip.name : "-";
|
|||
|
|
sb.AppendFormat("{0:F2}s 단계 {1} 시작 · 적 {2:F2} · 직전 단계 PC 이동 {3:F2} · 표 전진 {4:F2} · 클립 {5}\n", Time.time - t0, st, Vector3.Distance(pc.Get_position(), d.Get_position()),
|
|||
|
|
Vector3.Distance(p0, pc.Get_position()), WL.Combat.AttackRootMotion.SwingAccum - a0, clip);
|
|||
|
|
last = st; p0 = pc.Get_position(); a0 = WL.Combat.AttackRootMotion.SwingAccum;
|
|||
|
|
}
|
|||
|
|
if (Time.time - t0 > seconds) { Application.onBeforeRender -= act; d.Stop(false); }
|
|||
|
|
};
|
|||
|
|
Application.onBeforeRender += act;
|
|||
|
|
return "단계 전진 기록 시작";
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>#906 해머 3타 넉백 — 반응이 걸린 순간의 몹 위치와 0.6 초 뒤 위치 차이 · 모델 최대 높이.</summary>
|
|||
|
|
public static object KnockWatch(float seconds)
|
|||
|
|
{
|
|||
|
|
var pc = MyValue.MyPC as PCActor; var d = Dummy();
|
|||
|
|
if (pc == null || d == null) return "PC/몹 없음";
|
|||
|
|
var sb = Buf(); sb.Length = 0; float t0 = Time.time; int a0 = WL.Combat.Weapon.WLStageHitReaction.Applied;
|
|||
|
|
Vector3 hitPos = Vector3.zero; float hitAt = -1f, maxY = 0f; float baseY = d.m_animation != null ? d.m_animation.transform.localPosition.y : 0f;
|
|||
|
|
UnityEngine.Events.UnityAction act = null;
|
|||
|
|
act = () =>
|
|||
|
|
{
|
|||
|
|
if (pc == null || d == null) { Application.onBeforeRender -= act; return; }
|
|||
|
|
int a = WL.Combat.Weapon.WLStageHitReaction.Applied;
|
|||
|
|
if (a != a0)
|
|||
|
|
{
|
|||
|
|
a0 = a;
|
|||
|
|
if (WL.Combat.Weapon.WLStageHitReaction.LastLog.StartsWith("stage 3")) { hitPos = d.Get_position(); hitAt = Time.time; maxY = 0f; }
|
|||
|
|
}
|
|||
|
|
if (hitAt > 0f)
|
|||
|
|
{
|
|||
|
|
if (d.m_animation != null) maxY = Mathf.Max(maxY, d.m_animation.transform.position.y - d.Get_position().y);
|
|||
|
|
if (Time.time - hitAt >= 0.6f)
|
|||
|
|
{
|
|||
|
|
var v = d.Get_position() - hitPos; v.y = 0f;
|
|||
|
|
sb.AppendFormat("3타 넉백 · 몹 이동 {0:F2} m · 모델 최대 높이(발 기준) {1:F2} · PC 와 거리 {2:F2}\n", v.magnitude, maxY, Vector3.Distance(pc.Get_position(), d.Get_position()));
|
|||
|
|
hitAt = -1f;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
if (Time.time - t0 > seconds) Application.onBeforeRender -= act;
|
|||
|
|
};
|
|||
|
|
Application.onBeforeRender += act;
|
|||
|
|
return "넉백 관찰 시작";
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public static object Log() { return Buf().ToString(); }
|
|||
|
|
|
|||
|
|
public static object Hammer()
|
|||
|
|
{
|
|||
|
|
var sb = new StringBuilder();
|
|||
|
|
sb.Append("크기 조절 ").Append(WL.Combat.Weapon.WLSkillVfx.Scaled).Append(" · ").Append(WL.Combat.Weapon.WLSkillVfx.LastLog).Append('\n');
|
|||
|
|
foreach (var s in Object.FindObjectsByType<Skill_JumpAttack>(FindObjectsInactive.Include, FindObjectsSortMode.None))
|
|||
|
|
sb.Append(s.name).Append(" 켜짐=").Append(s.gameObject.activeInHierarchy).Append(" 크기 노드 ").Append(s.tf_size != null ? s.tf_size.localScale.ToString("F2") : "-")
|
|||
|
|
.Append(" · 판정 상자 ").Append(s.m_boxcollider != null ? s.m_boxcollider.size.ToString("F1") : "-").Append(" × 루트 ").Append(s.transform.localScale.ToString("F2")).Append('\n');
|
|||
|
|
var slots = WL.Combat.Weapon.WLWeaponSkillSlots.LastSlots;
|
|||
|
|
sb.Append("무기 스킬 칸 [").Append(slots != null ? string.Join(",", System.Array.ConvertAll(slots, x => x.ToString())) : "-").Append("] 등급 ").Append(WL.Combat.Weapon.WLWeaponSkillSlots.LastTier);
|
|||
|
|
return sb.ToString();
|
|||
|
|
}
|
|||
|
|
}
|