// WL885_Probe.cs — PD 지시 #885 칼날 폭풍 「자동 전투 중에도 가까운 적을 따라가며 돌기」 시험(Play 중) // unity command run_script --file AgentScripts/WL885_Probe.cs --entry WL885_Probe.Run --args '[로그 경로, 조작 시작 s, 조작 길이 s, dx, dz, 슬롯]' // 시험 시전(쿨 · MP 무시) → 조작 구간에는 섬 조이스틱 입력(SimpleInput 축)을 실제로 넣는다(WLIslandAvatar 경로) // → 0.25 s(게임 시간)마다 동작 · 조이스틱 상태 · 위치 · 가까운 적 거리 · 따라가기 상태를 파일에 적는다(run_script 마다 새 어셈블리 · K-DEV-023). using System.Collections; using UnityEngine; using WL.Equip; public static class WL885_Probe { /// 조작 = 힘민지 FloatingJoystick 경로(누름 → 매 프레임 Run_byJoystick = OnDrag 와 같은 호출 → 뗌). public static object RunFloat(string path, float steerAt, float steerFor, float dx, float dz, int slot) { s_float = true; try { return Run(path, steerAt, steerFor, dx, dz, slot); } finally { s_float = false; } } static bool s_float; public static object Run(string path, float steerAt, float steerFor, float dx, float dz, int slot) { var pc = MyValue.MyPC; if (pc == null) return "PC 없음"; var arr = typeof(PCActor).GetField("arr_magicData", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Public).GetValue(pc) as SkillListTableData[]; var data = arr != null && slot >= 0 && slot < arr.Length ? arr[slot] : null; if (data == null) return "슬롯 비어 있음 " + slot; System.IO.File.WriteAllText(path, "skill " + data.n_SkillID + " " + data.e_Skill + " · follow " + WL.Combat.Weapon.WLSkillFollow.LastLog + "\n"); pc.StartCoroutine(Co(pc, data, slot, path, steerAt, steerFor, dx, dz, s_float)); return "started " + data.n_SkillID + (s_float ? " (FloatingJoystick)" : " (섬 조이스틱)"); } static IEnumerator Co(PCActor pc, SkillListTableData data, int slot, string path, float steerAt, float steerFor, float dx, float dz, bool viaFloat) { if (viaFloat) { yield return CoFloat(pc, data, slot, path, steerAt, steerFor, new Vector3(dx, 0f, dz).normalized); yield break; } float moved0 = WL.Combat.Weapon.WLSkillFollow.MovedMeters; int steer0 = WL.Combat.Weapon.WLSkillFollow.SteerFrames; bool ok = pc.Use_Skill(data, true, slot, true); Append(path, "cast=" + ok); SimpleInput.AxisInput h = null, v = null; float t = 0f, next = 0f; while (t < 4.8f && pc != null) { bool steer = t >= steerAt && t < steerAt + steerFor; if (steer && h == null) { h = new SimpleInput.AxisInput("Horizontal") { value = dx }; v = new SimpleInput.AxisInput("Vertical") { value = dz }; h.StartTracking(); v.StartTracking(); Append(path, "입력 시작 t=" + t.ToString("F2")); } if (!steer && h != null) { h.StopTracking(); v.StopTracking(); h = null; v = null; Append(path, "입력 끝 t=" + t.ToString("F2")); } if (t >= next) { next += 0.25f; Append(path, Line(pc, t, moved0, steer0)); } yield return null; t += Time.deltaTime; } if (h != null) { h.StopTracking(); v.StopTracking(); } Append(path, "END " + Line(pc, t, moved0, steer0) + " · " + WL.Combat.Weapon.WLSkillFollow.LastLog); } static IEnumerator CoFloat(PCActor pc, SkillListTableData data, int slot, string path, float steerAt, float steerFor, Vector3 dir) { float moved0 = WL.Combat.Weapon.WLSkillFollow.MovedMeters; int steer0 = WL.Combat.Weapon.WLSkillFollow.SteerFrames; var fj = Object.FindAnyObjectByType(); Append(path, "FloatingJoystick=" + (fj != null) + " PCMove 옵션=" + (OptionInfo.Ins != null && OptionInfo.Ins.Get_PCMove())); var ped = new UnityEngine.EventSystems.PointerEventData(UnityEngine.EventSystems.EventSystem.current); bool ok = pc.Use_Skill(data, true, slot, true); Append(path, "cast=" + ok); bool down = false; float t = 0f, next = 0f; while (t < 4.8f && pc != null) { bool steer = t >= steerAt && t < steerAt + steerFor; if (steer && !down && fj != null) { fj.OnPointerDown(ped); down = true; Append(path, "누름 t=" + t.ToString("F2")); } if (steer && down) pc.Run_byJoystick(dir); if (!steer && down) { fj.OnPointerUp(ped); down = false; Append(path, "뗌 t=" + t.ToString("F2")); } if (t >= next) { next += 0.25f; Append(path, Line(pc, t, moved0, steer0)); } yield return null; t += Time.deltaTime; } if (down && fj != null) fj.OnPointerUp(ped); Append(path, "END " + Line(pc, t, moved0, steer0) + " · " + WL.Combat.Weapon.WLSkillFollow.LastLog); } static string Line(PCActor pc, float t, float moved0, int steer0) { var p = pc.transform.position; var e = ActorInfo.Ins != null ? ActorInfo.Ins.Get_Nearest_EnemyActor_orNull(pc.IsEnemy(), p, 30f) : null; float d = e != null ? Vector3.Distance(new Vector3(p.x, 0f, p.z), new Vector3(e.Get_position().x, 0f, e.Get_position().z)) : -1f; var av = WL.IslandMob.WLIslandAvatar.Instance; string st = "?"; var an = pc.m_animation; if (an != null) { var si = an.GetCurrentAnimatorStateInfo(0); st = si.IsName("twohandskill3_loop") ? "loop" : si.IsName("twohandskill3") ? "start" : si.IsName("idle") ? "idle" : si.IsName("run") ? "run" : "other"; } return "t=" + t.ToString("F2") + " anim=" + pc.Get_CurAnim() + " state=" + st + " js=" + pc.JoystickStatus + " pos=(" + p.x.ToString("F2") + "," + p.z.ToString("F2") + ")" + " enemy=" + (e != null ? e.name.Replace("(Clone)", "") + "@" + d.ToString("F2") : "-") + " follow=" + (WL.Combat.Weapon.WLSkillFollow.Active ? "on" : "off") + " moved+" + (WL.Combat.Weapon.WLSkillFollow.MovedMeters - moved0).ToString("F2") + " steerFr+" + (WL.Combat.Weapon.WLSkillFollow.SteerFrames - steer0) + " canMove=" + pc.CanMove() + " avMoving=" + (av != null && av.PcMoving) + " stop=" + IsStop(pc) + " brake=" + WL.Combat.Weapon.WLSkillFollow.BrakeDeferred + "/" + WL.Combat.Weapon.WLSkillFollow.BrakeApplied + "/" + WL.Combat.Weapon.WLSkillFollow.BrakeDropped; } static string IsStop(PCActor pc) { const System.Reflection.BindingFlags bf = System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Public; for (var t = pc.GetType(); t != null; t = t.BaseType) { var f = t.GetField("IsStop", bf); if (f != null) return f.GetValue(pc).ToString(); var p = t.GetProperty("IsStop", bf); if (p != null) return p.GetValue(pc, null).ToString(); } return "?"; } static void Append(string path, string line) { try { System.IO.File.AppendAllText(path, line + "\n"); } catch { } } /// 인벤토리 무기(목록 순서 · 등급 · 장착) + 치트 · 따라가기 장치 상태. public static object Inv() { if (!WL.Equip.WLInventory.EnsureLoaded()) return "인벤토리 로드 실패"; var sb = new System.Text.StringBuilder(); int n = 0; foreach (var it in WL.Equip.WLInventory.SortedItems()) { if (it.itemJson == null || it.itemJson.EquipmentType != eFREquipmentType.Weapon) continue; n++; sb.Append(n).Append('.').Append(it.itemJson.GroupNo).Append(' ').Append(it.itemJson.Item_name).Append('[').Append(WL.Equip.WLEquipGrades.Label(it.itemJson, false)).Append(']') .Append(WL.Equip.WLInventory.IsEquipped(it.rawItem._id) ? "*" : "").Append(" "); } var rt = System.Type.GetType("WL.Combat.Weapon.WLWeaponGradeCheatRunner, Assembly-CSharp"); int runners = rt != null ? Resources.FindObjectsOfTypeAll(rt).Length : -1; return "무기 " + n + "개: " + sb + "\n 치트 러너=" + runners + " 치트=" + WL.Combat.Weapon.WLWeaponGradeCheat.LastLog + " · 따라가기=" + WL.Combat.Weapon.WLSkillFollow.LastLog + " 시작 " + WL.Combat.Weapon.WLSkillFollow.Started; } /// 숫자 키 치트와 같은 함수 호출(키 입력 대신). public static object Cheat(int tier) { return WL.Combat.Weapon.WLWeaponGradeCheat.Apply(tier); } }