222 lines
17 KiB
C#
222 lines
17 KiB
C#
// WL919_Probe.cs — PD 지시 #919 시험(Play 중 · 섬)
|
||
// Bat() : 시험 더미(박쥐) · 섬의 몹 — 콜라이더(종류 · 중심 · 크기 · 트리거 · 레이어 · 월드 높이) · 렌더러 높이 · 위치 함수 높이
|
||
// Bow() : 활 노드(FindBow 규칙) · 무기 소켓 · 활 그림 중심 · 크기 · PC 키
|
||
using System.Text;
|
||
using UnityEngine;
|
||
|
||
public static class WL919_Probe
|
||
{
|
||
static string V(Vector3 v) { return v.ToString("F2"); }
|
||
|
||
public static object Bat()
|
||
{
|
||
var sb = new StringBuilder();
|
||
foreach (var m in Object.FindObjectsByType<MobActor>(FindObjectsInactive.Exclude, FindObjectsSortMode.None))
|
||
{
|
||
if (m == null) continue;
|
||
float gy = m.Get_position().y;
|
||
sb.Append(m.name).Append(" · 위치 y ").Append(gy.ToString("F2")).Append(" · 중심 +").Append((m.Get_Center_position().y - gy).ToString("F2")).Append(" · 머리 +").Append((m.Get_Top_postion().y - gy).ToString("F2"))
|
||
.Append(" · 배율 ").Append(m.transform.localScale.x.ToString("F3")).Append(" · 레이어 ").Append(LayerMask.LayerToName(m.gameObject.layer)).AppendLine();
|
||
var ag = m.GetComponent<UnityEngine.AI.NavMeshAgent>();
|
||
if (ag != null) sb.Append(" agent baseOffset ").Append(ag.baseOffset.ToString("F2")).Append(" 높이 ").Append(ag.height.ToString("F2")).Append(" 반지름 ").Append(ag.radius.ToString("F2")).AppendLine();
|
||
foreach (var c in m.GetComponentsInChildren<Collider>(true))
|
||
{
|
||
sb.Append(" C ").Append(c.GetType().Name).Append(" ").Append(c.transform == m.transform ? "(루트)" : c.transform.name).Append(" 켜짐 ").Append(c.enabled && c.gameObject.activeInHierarchy).Append(" 트리거 ").Append(c.isTrigger)
|
||
.Append(" 레이어 ").Append(LayerMask.LayerToName(c.gameObject.layer)).Append(" 월드 y ").Append((c.bounds.min.y - gy).ToString("F2")).Append("~").Append((c.bounds.max.y - gy).ToString("F2")).Append(" 폭 ").Append(c.bounds.size.x.ToString("F2"));
|
||
var cc = c as CapsuleCollider; if (cc != null) sb.Append(" 캡슐 중심 ").Append(V(cc.center)).Append(" r ").Append(cc.radius.ToString("F2")).Append(" h ").Append(cc.height.ToString("F2")).Append(" 축 ").Append(cc.direction);
|
||
var bc = c as BoxCollider; if (bc != null) sb.Append(" 상자 중심 ").Append(V(bc.center)).Append(" 크기 ").Append(V(bc.size));
|
||
var sc = c as SphereCollider; if (sc != null) sb.Append(" 구 중심 ").Append(V(sc.center)).Append(" r ").Append(sc.radius.ToString("F2"));
|
||
sb.AppendLine();
|
||
}
|
||
Bounds rb = new Bounds(); bool has = false;
|
||
foreach (var r in m.GetComponentsInChildren<Renderer>(false)) { if (!r.enabled || r is ParticleSystemRenderer) continue; if (!has) { rb = r.bounds; has = true; } else rb.Encapsulate(r.bounds); }
|
||
if (has) sb.Append(" 그림 y ").Append((rb.min.y - gy).ToString("F2")).Append("~").Append((rb.max.y - gy).ToString("F2")).AppendLine();
|
||
}
|
||
return sb.Length > 0 ? sb.ToString() : "몹 없음";
|
||
}
|
||
|
||
// ── 판정 상자 높이 · 스킬별 명중 ──
|
||
static readonly System.Collections.Generic.Dictionary<string, int> s_hit = new System.Collections.Generic.Dictionary<string, int>();
|
||
static void OnHit(in WL.Combat.Core.HitConfirmedEvent e)
|
||
{
|
||
if (!(e.victim is MobActor)) return;
|
||
var pd = e.projectile; string k = pd != null && pd.m_SkillListTableData != null ? pd.m_SkillListTableData.e_Skill.ToString() : "기본/기타";
|
||
int n; s_hit.TryGetValue(k, out n); s_hit[k] = n + 1;
|
||
}
|
||
const string Key = "wl919log";
|
||
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(); }
|
||
|
||
/// <summary>seconds 동안 PC 가 낸 판정 투사체(처음 켜진 순간의 콜라이더 높이 · PC 발 기준) · 스킬별 몹 명중 수 · 핫키 slot(0 = 안 누름).</summary>
|
||
public static object Hits(float seconds, int slot)
|
||
{
|
||
var pc = MyValue.MyPC as PCActor; if (pc == null) return "PC 없음";
|
||
var sb = Buf(); sb.Length = 0; s_hit.Clear();
|
||
WL.Combat.Core.CombatEvents.HitConfirmed.Remove(OnHit); WL.Combat.Core.CombatEvents.HitConfirmed.Add(OnHit);
|
||
var seen = new System.Collections.Generic.HashSet<int>(); float t0 = Time.time;
|
||
UnityEngine.Events.UnityAction act = null;
|
||
act = () =>
|
||
{
|
||
float t = Time.time - t0; float gy = pc.Get_position().y;
|
||
foreach (var pb in Object.FindObjectsByType<ProjectileBase>(FindObjectsInactive.Exclude, FindObjectsSortMode.None))
|
||
{
|
||
if (pb == null) continue; var pd = pb.Get_ProjectTileData(); if (pd == null || !ReferenceEquals(pd.shooter, pc)) continue;
|
||
var cols = pb.GetComponentsInChildren<Collider>(false); if (cols.Length == 0) continue;
|
||
bool on = false; Bounds b = new Bounds();
|
||
foreach (var c in cols) { if (!c.enabled) continue; if (!on) { b = c.bounds; on = true; } else b.Encapsulate(c.bounds); }
|
||
if (!on) continue;
|
||
if (!seen.Add(pb.GetInstanceID())) continue;
|
||
sb.AppendFormat("{0:F2} 판정 {1} · y {2:F2}~{3:F2} · 폭 {4:F2}×{5:F2}", t, pb.name.Replace("(Clone)", ""), b.min.y - gy, b.max.y - gy, b.size.x, b.size.z).Append('\n');
|
||
}
|
||
if (t > seconds)
|
||
{
|
||
Application.onBeforeRender -= act; WL.Combat.Core.CombatEvents.HitConfirmed.Remove(OnHit);
|
||
sb.Append("끝 · 명중");
|
||
foreach (var kv in s_hit) sb.Append(' ').Append(kv.Key).Append(' ').Append(kv.Value);
|
||
sb.Append('\n');
|
||
}
|
||
};
|
||
Application.onBeforeRender += act;
|
||
return slot > 0 ? "slot" + slot + ": " + WL.Combat.Weapon.WLSkillHotkey.Fire(slot) : "관찰 " + seconds + " 초";
|
||
}
|
||
|
||
/// <summary>3타 모으기(~WL_BowCharge) — 위치 · 부모 · 파티클별 공간 · 모양 위치 · 살아 있는 입자 중심(월드) vs 활 그림(렌더러 bounds) 중심 · 화면 좌표.</summary>
|
||
public static object Charge()
|
||
{
|
||
var pc = MyValue.MyPC as PCActor; if (pc == null) return "PC 없음";
|
||
var sb = new StringBuilder(); var cam = Camera.main;
|
||
Bounds bow = new Bounds(); bool hasBow = false;
|
||
if (pc.tfs_weapon != null) foreach (var s in pc.tfs_weapon) if (s != null && s.name == "w_archer_l" && s.gameObject.activeInHierarchy)
|
||
foreach (var r in s.GetComponentsInChildren<MeshRenderer>(false)) { if (!r.enabled || r.name == "[WL] Glow") continue; if (!hasBow) { bow = r.bounds; hasBow = true; } else bow.Encapsulate(r.bounds); }
|
||
sb.Append("활 그림 중심 ").Append(hasBow ? V(bow.center - pc.Get_position()) : "-").Append(" · 화면 ").Append(hasBow && cam != null ? cam.WorldToViewportPoint(bow.center).ToString("F3") : "-").AppendLine();
|
||
foreach (var t in Object.FindObjectsByType<Transform>(FindObjectsInactive.Exclude, FindObjectsSortMode.None))
|
||
{
|
||
if (t.name != "~WL_BowCharge") continue;
|
||
sb.Append("모으기 원점 ").Append(V(t.position - pc.Get_position())).Append(" · 부모 ").Append(t.parent != null ? t.parent.name : "-").Append(" · lossy ").Append(t.lossyScale.x.ToString("F3")).Append(" · 활 중심까지 ").Append(hasBow ? Vector3.Distance(t.position, bow.center).ToString("F2") : "-").AppendLine();
|
||
foreach (var ps in t.GetComponentsInChildren<ParticleSystem>(true))
|
||
{
|
||
var m = ps.main; int n = ps.particleCount; Vector3 sum = Vector3.zero;
|
||
var arr = new ParticleSystem.Particle[Mathf.Max(1, n)]; n = ps.GetParticles(arr);
|
||
for (int i = 0; i < n; i++) sum += m.simulationSpace == ParticleSystemSimulationSpace.World ? arr[i].position : ps.transform.TransformPoint(arr[i].position);
|
||
var c = n > 0 ? sum / n : ps.transform.position;
|
||
sb.Append(" ").Append(ps.name).Append(" ").Append(ps.gameObject.activeInHierarchy ? "" : "(꺼짐) ").Append(m.simulationSpace).Append(" · 크기모드 ").Append(m.scalingMode).Append(" · 입자 ").Append(n)
|
||
.Append(" · 입자 중심 → 활 중심 ").Append(hasBow && n > 0 ? Vector3.Distance(c, bow.center).ToString("F2") : "-").Append(" m · 원점 → 활 ").Append(hasBow ? Vector3.Distance(ps.transform.position, bow.center).ToString("F2") : "-")
|
||
.Append(" · 모양 ").Append(ps.shape.enabled ? ps.shape.shapeType + " 위치 " + ps.shape.position.ToString("F2") + " r " + ps.shape.radius.ToString("F2") : "off")
|
||
.Append(" · 화면 ").Append(cam != null && n > 0 ? cam.WorldToViewportPoint(c).ToString("F3") : "-").AppendLine();
|
||
}
|
||
}
|
||
return sb.ToString();
|
||
}
|
||
|
||
// ── 날아가는 화살 붙잡기 · 가까이 찍기 ──
|
||
static ProjectileBase s_arrow;
|
||
/// <summary>mode 0 = 기본 겉모습(~WL_Visual 켜짐) · 1 = 3타(~WL_Charged 켜짐) · 2 = 속사(Projectile_ArcherSkill2Arrow) 화살이 PC 에서 minDist m 넘게 날아간 순간 일시 정지 — 진행 방향과 앞(+Z) 사이 각도.</summary>
|
||
public static object Arrow(int mode, float minDist, float maxSeconds)
|
||
{
|
||
var pc = MyValue.MyPC as PCActor; if (pc == null) return "PC 없음";
|
||
var sb = Buf(); sb.Length = 0; s_arrow = null;
|
||
var prev = new System.Collections.Generic.Dictionary<ProjectileBase, Vector3>(); float t0 = Time.time;
|
||
int ch0 = WL.Combat.Weapon.WLBowChargeReceiver.Charges; float chargeT = -1f;
|
||
UnityEngine.Events.UnityAction act = null;
|
||
act = () =>
|
||
{
|
||
float t = Time.time - t0;
|
||
if (chargeT < 0f && WL.Combat.Weapon.WLBowChargeReceiver.Charges > ch0) { chargeT = t; sb.AppendFormat("{0:F2} 3타 모으기 시작 · {1}", t, WL.Combat.Weapon.WLBowChargeReceiver.LastLog).Append('\n'); }
|
||
foreach (var pb in Object.FindObjectsByType<ProjectileBase>(FindObjectsInactive.Exclude, FindObjectsSortMode.None))
|
||
{
|
||
if (pb == null) continue;
|
||
bool basic = pb.name.StartsWith("Projectile_1040"), rapid = pb.name.StartsWith("Projectile_ArcherSkill2Arrow");
|
||
if (!basic && !rapid) continue;
|
||
var vis = pb.transform.Find("~WL_Visual"); var chg = pb.transform.Find("~WL_Charged");
|
||
bool isCharged = chg != null && chg.gameObject.activeSelf;
|
||
Vector3 p0; bool had = prev.TryGetValue(pb, out p0); prev[pb] = pb.transform.position;
|
||
if (chargeT >= 0f && isCharged && !sb.ToString().Contains("3타 화살 생성")) sb.AppendFormat("{0:F2} 3타 화살 생성 · 모으기부터 {1:F2} 초", t, t - chargeT).Append('\n');
|
||
bool want = mode == 0 ? basic && vis != null && vis.gameObject.activeSelf && !isCharged : mode == 1 ? basic && isCharged : rapid;
|
||
float dpc = Vector3.Distance(pb.transform.position, pc.Get_position());
|
||
if (!want || !had || dpc < minDist || dpc > minDist + 3f) continue; // 멀리 날아가는 옛 관통 화살 제외
|
||
var mv = pb.transform.position - p0; if (mv.sqrMagnitude < 1e-6f) continue;
|
||
Application.onBeforeRender -= act; EditorPause(); s_arrow = pb; System.AppDomain.CurrentDomain.SetData("wl919arrow", pb); // run_script 마다 어셈블리가 새로 — 정적 필드 대신
|
||
sb.AppendFormat("■ 일시 정지 {0:F2} · {1} · 진행-앞 각 {2:F0}° · 진행 높이 변화 {3:F2} · lossy {4:F3} · 기본 {5} · 3타 {6}", t, pb.name, Vector3.Angle(mv, pb.transform.forward), mv.normalized.y, pb.transform.lossyScale.x,
|
||
vis != null && vis.gameObject.activeSelf, isCharged).Append('\n');
|
||
return;
|
||
}
|
||
if (t > maxSeconds) { Application.onBeforeRender -= act; sb.Append("못 찾음\n"); }
|
||
};
|
||
Application.onBeforeRender += act;
|
||
return "화살 관찰 " + mode;
|
||
}
|
||
static void EditorPause()
|
||
{
|
||
#if UNITY_EDITOR
|
||
UnityEditor.EditorApplication.isPaused = true;
|
||
#endif
|
||
}
|
||
|
||
/// <summary>붙잡은 화살을 게임 카메라와 같은 각도로 dist m 앞에서 찍는다(PNG · w×h).</summary>
|
||
public static object Shot(string outFile, float dist, float fov)
|
||
{
|
||
if (s_arrow == null) s_arrow = System.AppDomain.CurrentDomain.GetData("wl919arrow") as ProjectileBase;
|
||
var main = Camera.main; if (main == null || s_arrow == null) return "카메라/화살 없음";
|
||
var go = new GameObject("~WL919_Shot"); var cam = go.AddComponent<Camera>(); cam.enabled = false;
|
||
cam.CopyFrom(main); cam.fieldOfView = fov;
|
||
int ui = LayerMask.NameToLayer("UI"); if (ui >= 0) cam.cullingMask &= ~(1 << ui); // 월드 HUD(HP 바 등) 빼기
|
||
go.transform.rotation = main.transform.rotation; go.transform.position = s_arrow.transform.position - main.transform.forward * dist;
|
||
var rt = new RenderTexture(1200, 800, 24, RenderTextureFormat.ARGB32); cam.targetTexture = rt; cam.aspect = 1.5f; cam.Render();
|
||
var prev = RenderTexture.active; RenderTexture.active = rt;
|
||
var tex = new Texture2D(rt.width, rt.height, TextureFormat.RGB24, false); tex.ReadPixels(new Rect(0, 0, rt.width, rt.height), 0, 0); tex.Apply();
|
||
RenderTexture.active = prev; System.IO.File.WriteAllBytes(outFile, tex.EncodeToPNG());
|
||
Object.Destroy(tex); cam.targetTexture = null; Object.Destroy(rt); Object.Destroy(go);
|
||
var sp = main.WorldToViewportPoint(s_arrow.transform.position + s_arrow.transform.forward * 0.3f) - main.WorldToViewportPoint(s_arrow.transform.position);
|
||
return "저장 " + outFile + " · 화면에서 화살 앞 방향 (" + sp.x.ToString("F3") + "," + sp.y.ToString("F3") + ")";
|
||
}
|
||
|
||
/// <summary>PC → 더미 사이 띠(반경 r m) 안의 켜진 렌더러 — 이름(경로) · 종류 · 재질 · 셰이더 · 파티클 수.</summary>
|
||
public static object Path(float r)
|
||
{
|
||
var pc = MyValue.MyPC as PCActor; var d = WL.IslandMob.WLTrailTest.Dummy; if (pc == null || d == null) return "PC/더미 없음";
|
||
Vector3 a = pc.Get_position(), b = d.Get_position(); a.y = b.y = 0f; var sb = new StringBuilder(); int n = 0;
|
||
foreach (var rd in Object.FindObjectsByType<Renderer>(FindObjectsInactive.Exclude, FindObjectsSortMode.None))
|
||
{
|
||
if (rd == null || !rd.enabled || !rd.isVisible) continue;
|
||
if (rd.transform.IsChildOf(pc.transform) || rd.transform.IsChildOf(d.transform)) continue;
|
||
var c = rd.bounds.center; c.y = 0f; var ab = b - a; float t = Mathf.Clamp01(Vector3.Dot(c - a, ab) / Mathf.Max(1e-4f, ab.sqrMagnitude));
|
||
if (Vector3.Distance(c, a + ab * t) > r || rd.bounds.size.magnitude > 30f) continue;
|
||
var ps = rd.GetComponent<ParticleSystem>(); var m = rd.sharedMaterial;
|
||
string path = rd.name; var tr = rd.transform.parent; for (int k = 0; k < 3 && tr != null; k++, tr = tr.parent) path = tr.name + "/" + path;
|
||
sb.Append(rd.GetType().Name).Append(' ').Append(path).Append(" · 재질 ").Append(m != null ? m.name + " / " + m.shader.name : "-").Append(ps != null ? " · 입자 " + ps.particleCount : "").Append(" · 크기 ").Append(rd.bounds.size.ToString("F2")).AppendLine();
|
||
if (++n > 40) break;
|
||
}
|
||
return n + " 개\n" + sb;
|
||
}
|
||
|
||
public static object Bow()
|
||
{
|
||
var pc = MyValue.MyPC as PCActor; if (pc == null) return "PC 없음";
|
||
var sb = new StringBuilder();
|
||
float gy = pc.Get_position().y;
|
||
sb.Append("PC 키 ").Append((pc.Get_Top_postion().y - gy).ToString("F2")).Append(" · 중심 +").Append((pc.Get_Center_position().y - gy).ToString("F2")).Append(" · 배율 ").Append(pc.transform.localScale.x.ToString("F3")).AppendLine();
|
||
Transform bow = null;
|
||
foreach (var t in pc.GetComponentsInChildren<Transform>(false))
|
||
if (t.gameObject.activeInHierarchy && t.name.IndexOf("Bow", System.StringComparison.OrdinalIgnoreCase) >= 0 && t.name.IndexOf("Elbow", System.StringComparison.OrdinalIgnoreCase) < 0) { bow = t; break; }
|
||
sb.Append("FindBow → ").Append(bow != null ? bow.name + " (부모 " + (bow.parent != null ? bow.parent.name : "-") + ")" : "없음").AppendLine();
|
||
if (pc.tfs_weapon != null)
|
||
foreach (var s in pc.tfs_weapon)
|
||
{
|
||
if (s == null || !s.gameObject.activeInHierarchy) continue;
|
||
var cl = WL.Combat.Weapon.WLWeaponGlowFx.CenterLocal(s); var cw = s.TransformPoint(cl);
|
||
Bounds b = new Bounds(); bool has = false;
|
||
foreach (var r in s.GetComponentsInChildren<MeshRenderer>(false)) { if (!r.enabled || r.name == "[WL] Glow") continue; if (!has) { b = r.bounds; has = true; } else b.Encapsulate(r.bounds); }
|
||
sb.Append("소켓 ").Append(s.name).Append(" · 그림 중심 ").Append(V(cw - pc.Get_position())).Append(" · 소켓 원점 ").Append(V(s.position - pc.Get_position()))
|
||
.Append(" · 원점-중심 ").Append(Vector3.Distance(s.position, cw).ToString("F2")).Append(" m · 그림 크기 ").Append(has ? V(b.size) : "-").Append(" · lossy ").Append(s.lossyScale.x.ToString("F3"));
|
||
if (bow != null) sb.Append(" · FindBow-중심 ").Append(Vector3.Distance(bow.position, cw).ToString("F2")).Append(" m");
|
||
sb.AppendLine();
|
||
}
|
||
return sb.ToString();
|
||
}
|
||
}
|