Project_WL/AgentScripts/WL890_Probe.cs

160 lines
9.8 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// WL890_Probe.cs — PD 지시 #890 · #891 시험(Play 중)
// ShieldInfo : 방패(왼손 소켓 0) · 팔(Elbow_L → Wrist_L) · 몸 중심(Chest_M) 기하 — 팔 바깥쪽 방향 · 방패 면 방향 · 그림자 설정
// ShieldOutward : 방패 래퍼 자식을 「팔 바깥쪽」으로 dist(월드 m) 만큼 옮긴다(실행 중만 · 파일 무수정) → 래퍼 루트 기준 로컬 값을 돌려준다(JSON 에 넣을 값)
// ShieldShadow : 방패 렌더러 그림자 받기 켬/끔(실행 중만)
// Q / Chain : Q 키와 같은 함수 호출 · 연결 상태
using System.Text;
using UnityEngine;
public static class WL890_Probe
{
static Transform Bone(PCActor pc, string name)
{
foreach (var t in pc.GetComponentsInChildren<Transform>(true)) if (t.name == name) return t;
return null;
}
static Transform ShieldChild(PCActor pc, out Transform root)
{
root = null;
var s = pc.tfs_weapon[0]; if (s == null || s.childCount == 0) return null;
root = s.GetChild(0);
return root.childCount > 0 ? root.GetChild(0) : root;
}
static Vector3 Outward(PCActor pc)
{
var elbow = Bone(pc, "Elbow_L"); var wrist = Bone(pc, "Wrist_L"); var chest = Bone(pc, "Chest_M");
if (elbow == null || wrist == null || chest == null) return Vector3.zero;
var arm = (wrist.position - elbow.position).normalized;
var o = wrist.position - chest.position;
o -= Vector3.Dot(o, arm) * arm; // 팔 방향 성분 제거 = 팔에 수직인 「몸 → 팔」 방향
return o.sqrMagnitude > 1e-8f ? o.normalized : Vector3.zero;
}
public static object ShieldInfo()
{
var pc = MyValue.MyPC; if (pc == null) return "PC 없음";
Transform root; var ch = ShieldChild(pc, out root); if (ch == null) return "방패 없음";
var wrist = Bone(pc, "Wrist_L"); var chest = Bone(pc, "Chest_M");
var outw = Outward(pc);
var sb = new StringBuilder();
var ci = pc.m_animation.GetCurrentAnimatorClipInfo(0);
sb.Append("clip=").Append(ci.Length > 0 ? ci[0].clip.name : "?").Append(" root=").Append(root.name).Append(" child=").Append(ch.name).Append(" childLocal=").Append(ch.localPosition.ToString("F3"));
sb.Append("\n 팔 바깥쪽(월드)=").Append(outw.ToString("F2")).Append(" · 방패 두께축(Z) · 바깥쪽 = ").Append(Vector3.Dot(ch.forward, outw).ToString("F2"));
var rends = ch.GetComponentsInChildren<Renderer>(true);
var b = rends.Length > 0 ? rends[0].bounds : new Bounds(ch.position, Vector3.zero); foreach (var r in rends) b.Encapsulate(r.bounds);
sb.Append("\n 방패 중심 − 손목 = ").Append((b.center - wrist.position).ToString("F3")).Append(" · 바깥쪽 성분 ").Append(Vector3.Dot(b.center - wrist.position, outw).ToString("F3"))
.Append(" m · 방패 크기 ").Append(b.size.ToString("F2")).Append(" · 손목 − 가슴 ").Append(Vector3.Distance(wrist.position, chest.position).ToString("F2"));
foreach (var r in rends) sb.Append("\n renderer ").Append(r.name).Append(" receive=").Append(r.receiveShadows).Append(" cast=").Append(r.shadowCastingMode).Append(" mat=").Append(r.sharedMaterial != null ? r.sharedMaterial.shader.name : "-");
return sb.ToString();
}
public static object ShieldOutward(float dist)
{
var pc = MyValue.MyPC; if (pc == null) return "PC 없음";
Transform root; var ch = ShieldChild(pc, out root); if (ch == null || ch == root) return "방패 자식 없음";
var outw = Outward(pc); if (outw == Vector3.zero) return "뼈 없음";
var local = root.InverseTransformVector(outw * dist);
ch.localPosition = local;
return "자식 localPosition = (" + local.x.ToString("F3") + ", " + local.y.ToString("F3") + ", " + local.z.ToString("F3") + ") · 월드 " + dist + " m";
}
public static object ShieldLocal(float x, float y, float z)
{
var pc = MyValue.MyPC; if (pc == null) return "PC 없음";
Transform root; var ch = ShieldChild(pc, out root); if (ch == null || ch == root) return "방패 자식 없음";
ch.localPosition = new Vector3(x, y, z);
return "자식 localPosition = " + ch.localPosition.ToString("F3");
}
/// <summary>자식 회전(로컬 오일러) + 「팔 바깥쪽」 dist(m) 위치를 한 번에(실행 중만). 돌려준 값 = JSON 에 넣을 로컬 위치 · 회전.</summary>
public static object ShieldPose(float ex, float ey, float ez, float dist)
{
var pc = MyValue.MyPC; if (pc == null) return "PC 없음";
Transform root; var ch = ShieldChild(pc, out root); if (ch == null || ch == root) return "방패 자식 없음";
ch.localRotation = Quaternion.Euler(ex, ey, ez);
ch.localPosition = Vector3.zero;
// 회전 뒤 방패 중심이 손목보다 바깥쪽 dist 가 되게(중심 기준)
var wrist = Bone(pc, "Wrist_L"); var outw = Outward(pc);
var rends = ch.GetComponentsInChildren<Renderer>(true);
var b = rends[0].bounds; foreach (var r in rends) b.Encapsulate(r.bounds);
float now = Vector3.Dot(b.center - wrist.position, outw);
var local = root.InverseTransformVector(outw * (dist - now));
ch.localPosition = local;
return "euler(" + ex + "," + ey + "," + ez + ") 바깥 " + dist + " m(이전 " + now.ToString("F3") + ") · 로컬 위치 (" + local.x.ToString("F3") + ", " + local.y.ToString("F3") + ", " + local.z.ToString("F3") + ") · 장식면(-Z)·바깥쪽 " + Vector3.Dot(-ch.forward, outw).ToString("F2");
}
/// <summary>방패 재질(실행 중 인스턴스)의 어두운 면 색 · 그림자 받기를 바꾼다(파일 무수정).</summary>
public static object ShieldMat(float dark, int receive)
{
var pc = MyValue.MyPC; if (pc == null) return "PC 없음";
Transform root; var ch = ShieldChild(pc, out root); if (ch == null) return "방패 없음";
var sb = new StringBuilder();
foreach (var r in ch.GetComponentsInChildren<Renderer>(true))
{
var m = r.material; // 인스턴스
if (m.HasProperty("_GoochDarkColor")) m.SetColor("_GoochDarkColor", new Color(dark, dark, dark, 1f));
if (m.HasProperty("_ReceiveShadows")) m.SetFloat("_ReceiveShadows", receive);
if (receive == 0) { m.DisableKeyword("_MK_RECEIVE_SHADOWS"); m.DisableKeyword("_RECEIVESHADOWS_ON"); } else { m.EnableKeyword("_MK_RECEIVE_SHADOWS"); m.EnableKeyword("_RECEIVESHADOWS_ON"); }
r.receiveShadows = receive != 0;
sb.Append(r.name).Append(" dark=").Append(dark).Append(" receive=").Append(receive).Append(' ');
}
return sb.ToString();
}
public static object ShieldShadow(bool receive)
{
var pc = MyValue.MyPC; if (pc == null) return "PC 없음";
Transform root; var ch = ShieldChild(pc, out root); if (ch == null) return "방패 없음";
int n = 0; foreach (var r in ch.GetComponentsInChildren<Renderer>(true)) { r.receiveShadows = receive; n++; }
return "receiveShadows=" + receive + " · " + n + "개";
}
public static object Q() { return WL.Combat.Weapon.WLSkillHotkey.Fire(); }
static readonly string[] States = { "shieldattack", "dashslash", "slashflurry_b1", "slashflurry_a1", "slashflurry_b2", "idle", "run", "dodge", "attack", "Attack2", "Attack3", "hit" };
/// <summary>Q 와 같은 함수로 주력 스킬 발동 → 0.1 s(게임 시간)마다 상태 · 방패 치기/연속 베기 타격 수를 파일에.</summary>
public static object QTimeline(string path, float seconds)
{
var pc = MyValue.MyPC; if (pc == null) return "PC 없음";
System.IO.File.WriteAllText(path, "Q → " + WL.Combat.Weapon.WLSkillHotkey.Fire() + "\n");
pc.StartCoroutine(Co(pc, path, seconds));
return "started";
}
static System.Collections.IEnumerator Co(PCActor pc, string path, float seconds)
{
int bash = 0, flurry = 0;
WL.Combat.Core.CombatHandler<WL.Combat.Core.HitConfirmedEvent> hh = (in WL.Combat.Core.HitConfirmedEvent e) =>
{
var s = e.projectile != null ? e.projectile.m_SkillListTableData : null; if (s == null) return;
if (s.n_SkillID == 703502) bash++; else if (s.n_SkillID == 703103) flurry++;
};
WL.Combat.Core.CombatEvents.HitConfirmed.Add(hh);
float t = 0f, next = 0f;
while (t < seconds && pc != null)
{
if (t >= next)
{
next += 0.1f;
var an = pc.m_animation; string st = "?";
var si = an.GetCurrentAnimatorStateInfo(0); foreach (var n in States) if (si.IsName(n)) { st = n; break; }
if (an.IsInTransition(0)) { var ni = an.GetNextAnimatorStateInfo(0); foreach (var n in States) if (ni.IsName(n)) { st += ">" + n; break; } }
System.IO.File.AppendAllText(path, "t=" + t.ToString("F2") + " anim=" + pc.Get_CurAnim() + " state=" + st + " 방패치기타격=" + bash + " 연속베기타격=" + flurry + "\n");
}
yield return null; t += Time.deltaTime;
}
WL.Combat.Core.CombatEvents.HitConfirmed.Remove(hh);
System.IO.File.AppendAllText(path, "END " + Chain() + " · dust " + WL.Combat.WLDoubleTapDodge.DustScaled + "\n");
}
public static object Chain()
{
return "chain 예약 " + WL.Combat.Weapon.WLSkillChain.Triggered + " 발동 " + WL.Combat.Weapon.WLSkillChain.Cast + " 실패 " + WL.Combat.Weapon.WLSkillChain.Failed + " · " + WL.Combat.Weapon.WLSkillChain.LastLog
+ " | hotkey " + WL.Combat.Weapon.WLSkillHotkey.Fired + "/" + WL.Combat.Weapon.WLSkillHotkey.Failed + " · " + WL.Combat.Weapon.WLSkillHotkey.LastLog
+ " | flurry " + WL.Combat.Weapon.WLSlashFlurry.Taken + " · vfx swings " + WL.Combat.Weapon.WLSkillVfx.Swings;
}
}