158 lines
11 KiB
C#
158 lines
11 KiB
C#
// WL922_Probe.cs — PD 지시 #922 시험(Play 중 · 섬)
|
|
// PoseClip(fbxPath, timesCsv, outPrefix, side) : FBX 안 첫 애니메이션 클립을 PC 에 입혀(PlayableGraph · 원본 애니메이터 무수정) 시각(초)마다 옆에서 찍는다 — 클립 길이 · 이벤트 없음
|
|
using System.Text;
|
|
using UnityEngine;
|
|
using UnityEngine.Animations;
|
|
using UnityEngine.Playables;
|
|
|
|
public static class WL922_Probe
|
|
{
|
|
const string Key = "wl922log";
|
|
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 float s_t0; static StringBuilder s_sb;
|
|
static void OnStage(in WL.Combat.Core.ComboStageEvent e) { if (s_sb != null) s_sb.AppendFormat("{0:F2} 단계 {1} · 클립 {2}", Time.time - s_t0, e.stage, e.clip).Append('\n'); }
|
|
|
|
/// <summary>#922 속사 모으기 중 이동 — Q 발동 뒤 moveAt 초부터 moveSec 초 동안 이동 입력 · PC 이동 거리(모으기 동안 / 그 뒤) · 이동 막힘 수 · 속사 발 수.</summary>
|
|
public static object RapidMove(float moveAt, float moveSec, float seconds)
|
|
{
|
|
var pc = MyValue.MyPC as PCActor; if (pc == null) return "PC 없음";
|
|
var sb = Buf(); sb.Length = 0; float t0 = Time.time; var p0 = pc.Get_position(); bool moving = false, moved = false; Vector3 pc0 = Vector3.zero;
|
|
int mb0 = WL.Combat.Weapon.WLSkillCancel.MoveBlocked, s0 = WL.Combat.Weapon.WLRapidShot.Shots, ab0 = WL.Combat.Weapon.WLRapidShot.Aborted;
|
|
var dir = Quaternion.Euler(0f, 90f, 0f) * pc.transform.forward; dir.y = 0f; dir.Normalize();
|
|
string res = WL.Combat.Weapon.WLSkillHotkey.Fire(1);
|
|
UnityEngine.Events.UnityAction act = null; float chargeEndDist = -1f;
|
|
act = () =>
|
|
{
|
|
float t = Time.time - t0;
|
|
if (!moved && t >= moveAt)
|
|
{
|
|
if (!moving) { pc.Set_AutoBraking(false); pc.Set_JoystickStatus(1); moving = true; sb.AppendFormat("{0:F2} ▶ 이동 입력 · 상태 {1}", t, pc.Get_CurAnim()).Append('\n'); }
|
|
pc.Run_byJoystick(dir);
|
|
if (t >= moveAt + moveSec) { pc.Set_JoystickStatus(0); pc.Set_AutoBraking(true); moving = false; moved = true; sb.AppendFormat("{0:F2} ■ 이동 끝 · 상태 {1} · 이동 {2:F2} m", t, pc.Get_CurAnim(), Flat(pc.Get_position() - p0)).Append('\n'); }
|
|
}
|
|
if (chargeEndDist < 0f && WL.Combat.Weapon.WLRapidShot.Shots > s0) { chargeEndDist = Flat(pc.Get_position() - p0); sb.AppendFormat("{0:F2} 첫 발(모으기 끝) · 그때까지 이동 {1:F2} m", t, chargeEndDist).Append('\n'); }
|
|
if (t > seconds)
|
|
{
|
|
Application.onBeforeRender -= act; if (moving) { pc.Set_JoystickStatus(0); pc.Set_AutoBraking(true); }
|
|
sb.AppendFormat("끝 · 이동 막힘 +{0} · 속사 발 +{1} · 끊김 +{2} · 총 이동 {3:F2} m · {4}", WL.Combat.Weapon.WLSkillCancel.MoveBlocked - mb0, WL.Combat.Weapon.WLRapidShot.Shots - s0, WL.Combat.Weapon.WLRapidShot.Aborted - ab0, Flat(pc.Get_position() - p0), res).Append('\n');
|
|
}
|
|
};
|
|
Application.onBeforeRender += act;
|
|
return "속사 + 이동 시험";
|
|
}
|
|
static float Flat(Vector3 v) { v.y = 0f; return v.magnitude; }
|
|
|
|
static int s_wantStage; static float s_pauseAt = -1f, s_delay;
|
|
static void OnStagePause(in WL.Combat.Core.ComboStageEvent e) { if (e.stage == s_wantStage && s_pauseAt < 0f) s_pauseAt = Time.time + s_delay; }
|
|
/// <summary>콤보 단계 stage 가 시작되고 delay 초 뒤 일시 정지(호 이펙트 캡처용).</summary>
|
|
public static object PauseStage(int stage, float delay, float maxSeconds)
|
|
{
|
|
var sb = Buf(); sb.Length = 0; s_wantStage = stage; s_delay = delay; s_pauseAt = -1f; float t0 = Time.time;
|
|
WL.Combat.Core.CombatEvents.ComboStage.Remove(OnStagePause); WL.Combat.Core.CombatEvents.ComboStage.Add(OnStagePause);
|
|
UnityEngine.Events.UnityAction act = null;
|
|
act = () =>
|
|
{
|
|
if ((s_pauseAt > 0f && Time.time >= s_pauseAt) || Time.time - t0 > maxSeconds)
|
|
{
|
|
Application.onBeforeRender -= act; WL.Combat.Core.CombatEvents.ComboStage.Remove(OnStagePause);
|
|
if (s_pauseAt > 0f) UnityEditor.EditorApplication.isPaused = true;
|
|
sb.Append(s_pauseAt > 0f ? "■ 일시 정지 단계 " + stage : "못 찾음").Append(" · 호 기울임 ").Append(WL.Combat.WeaponTrailDriver.ArcTilted).Append('\n');
|
|
}
|
|
};
|
|
Application.onBeforeRender += act;
|
|
return "단계 " + stage + " 대기";
|
|
}
|
|
|
|
/// <summary>지면 이펙트(WLImpactFx.GroundShown)가 늘면 delay 초 뒤 일시 정지 · 그때 칼끝(대검 소켓 그림 끝) 위치와 이펙트 위치(LastGround) 기록.</summary>
|
|
public static object PauseGround(float delay, float maxSeconds)
|
|
{
|
|
var pc = MyValue.MyPC as PCActor; if (pc == null) return "PC 없음";
|
|
var sb = Buf(); sb.Length = 0; float t0 = Time.time; int g0 = WL.Combat.Impact.WLImpactFx.GroundShown; float at = -1f;
|
|
UnityEngine.Events.UnityAction act = null;
|
|
act = () =>
|
|
{
|
|
if (at < 0f && WL.Combat.Impact.WLImpactFx.GroundShown > g0) at = Time.time + delay;
|
|
if ((at > 0f && Time.time >= at) || Time.time - t0 > maxSeconds)
|
|
{
|
|
Application.onBeforeRender -= act;
|
|
if (at > 0f) UnityEditor.EditorApplication.isPaused = true;
|
|
Bounds b = new Bounds(); bool has = false;
|
|
if (pc.tfs_weapon != null) foreach (var s in pc.tfs_weapon) if (s != null && s.gameObject.activeInHierarchy) foreach (var r in s.GetComponentsInChildren<MeshRenderer>(false)) { if (!r.enabled) continue; if (!has) { b = r.bounds; has = true; } else b.Encapsulate(r.bounds); }
|
|
var cam = Camera.main; var vp = cam.WorldToViewportPoint(pc.Get_Center_position());
|
|
sb.AppendFormat("{0} · {1} · 무기 그림 {2}~{3} · PC {4} · PC 화면 {5:F3},{6:F3}", at > 0f ? "■ 일시 정지" : "못 찾음", WL.Combat.Impact.WLImpactFx.LastGround, has ? b.min.ToString("F2") : "-", has ? b.max.ToString("F2") : "-", pc.Get_position().ToString("F2"), vp.x, 1f - vp.y).Append('\n');
|
|
}
|
|
};
|
|
Application.onBeforeRender += act;
|
|
return "지면 이펙트 대기";
|
|
}
|
|
|
|
/// <summary>대검 기본 공격 관찰 — 콤보 단계 · 클립 순서 · 지면 충격파(4타) 로그 · 그 순간 칼끝 위치.</summary>
|
|
public static object Combo(float seconds)
|
|
{
|
|
var pc = MyValue.MyPC as PCActor; if (pc == null) return "PC 없음";
|
|
var sb = Buf(); sb.Length = 0; s_sb = sb; s_t0 = Time.time;
|
|
WL.Combat.Core.CombatEvents.ComboStage.Remove(OnStage); WL.Combat.Core.CombatEvents.ComboStage.Add(OnStage);
|
|
int g0 = WL.Combat.Impact.WLImpactFx.GroundShown; string lg = WL.Combat.Impact.WLImpactFx.LastGround;
|
|
UnityEngine.Events.UnityAction act = null;
|
|
act = () =>
|
|
{
|
|
float t = Time.time - s_t0;
|
|
if (WL.Combat.Impact.WLImpactFx.GroundShown != g0 || WL.Combat.Impact.WLImpactFx.LastGround != lg)
|
|
{
|
|
g0 = WL.Combat.Impact.WLImpactFx.GroundShown; lg = WL.Combat.Impact.WLImpactFx.LastGround;
|
|
sb.AppendFormat("{0:F2} 지면 이펙트 #{1} · {2} · PC {3}", t, g0, lg, pc.Get_position().ToString("F2")).Append('\n');
|
|
}
|
|
if (t > seconds) { Application.onBeforeRender -= act; WL.Combat.Core.CombatEvents.ComboStage.Remove(OnStage); s_sb = null; }
|
|
};
|
|
Application.onBeforeRender += act;
|
|
return "대검 콤보 관찰 " + seconds + " 초";
|
|
}
|
|
|
|
public static object PoseClip(string fbxPath, string timesCsv, string outPrefix, float side)
|
|
{
|
|
var pc = MyValue.MyPC as PCActor; if (pc == null) return "PC 없음";
|
|
AnimationClip clip = null; string want = null;
|
|
int hash = fbxPath.IndexOf('#'); if (hash > 0) { want = fbxPath.Substring(hash + 1); fbxPath = fbxPath.Substring(0, hash); } // 경로#클립이름
|
|
foreach (var o in UnityEditor.AssetDatabase.LoadAllAssetsAtPath(fbxPath)) { var c = o as AnimationClip; if (c != null && !c.name.StartsWith("__preview__") && (want == null || c.name == want)) { clip = c; break; } }
|
|
if (clip == null) return "클립 없음 " + fbxPath;
|
|
var an = pc.m_animation; var ci = System.Globalization.CultureInfo.InvariantCulture;
|
|
var graph = PlayableGraph.Create("~WL922_Pose"); graph.SetTimeUpdateMode(DirectorUpdateMode.Manual);
|
|
var output = AnimationPlayableOutput.Create(graph, "pose", an);
|
|
var cp = AnimationClipPlayable.Create(graph, clip); cp.SetApplyFootIK(false); output.SetSourcePlayable(cp);
|
|
var go = new GameObject("~WL922_Cam"); var cam = go.AddComponent<Camera>(); cam.enabled = false; cam.fieldOfView = 35f;
|
|
cam.clearFlags = CameraClearFlags.SolidColor; cam.backgroundColor = new Color(0.12f, 0.14f, 0.18f, 1f);
|
|
int ui = LayerMask.NameToLayer("UI"); if (ui >= 0) cam.cullingMask &= ~(1 << ui); // 시험 더미는 잠깐 멀리 옮긴다(무기는 다른 층이라 층으로 거르지 않음)
|
|
var d = WL.IslandMob.WLTrailTest.Dummy; if (d != null) { d.Stop(true); d.Set_Warp(pc.Get_position() - pc.transform.forward * 25f); }
|
|
var center = pc.Get_position() + Vector3.up * 0.7f + pc.transform.forward * 0.4f;
|
|
go.transform.position = center + pc.transform.right * side + Vector3.up * 0.5f; go.transform.LookAt(center);
|
|
if (Mathf.Approximately(side, 0f) && Camera.main != null) // side 0 = 게임 카메라 각도에서 확대
|
|
{
|
|
var mc = Camera.main; go.transform.rotation = mc.transform.rotation; cam.fieldOfView = 12f;
|
|
go.transform.position = center - mc.transform.forward * Vector3.Distance(mc.transform.position, center);
|
|
}
|
|
var sb = new StringBuilder(clip.name + " " + clip.length.ToString("F2") + "s · ");
|
|
float speed0 = an.speed;
|
|
try
|
|
{
|
|
foreach (var s in timesCsv.Split(','))
|
|
{
|
|
float t = float.Parse(s, ci) * clip.length; // 정규화 시각
|
|
cp.SetTime(t); graph.Evaluate(0f);
|
|
var rt = new RenderTexture(500, 500, 24); cam.targetTexture = rt; cam.Render();
|
|
var prev = RenderTexture.active; RenderTexture.active = rt; var tex = new Texture2D(500, 500, TextureFormat.RGB24, false); tex.ReadPixels(new Rect(0, 0, 500, 500), 0, 0); tex.Apply(); RenderTexture.active = prev;
|
|
System.IO.File.WriteAllBytes(outPrefix + "_" + s + ".png", tex.EncodeToPNG()); Object.Destroy(tex); cam.targetTexture = null; Object.Destroy(rt);
|
|
}
|
|
}
|
|
finally { graph.Destroy(); Object.Destroy(go); an.speed = speed0 <= 0f ? 1f : speed0; pc.Play_Idle(); }
|
|
foreach (var e in clip.events) sb.Append(e.functionName).Append('@').Append((e.time / clip.length).ToString("F2")).Append(' ');
|
|
return sb.ToString();
|
|
}
|
|
}
|