From f35dab8542878d5f90b7b70e2055c3f9b3764358 Mon Sep 17 00:00:00 2001 From: swrring Date: Tue, 15 Sep 2026 09:37:12 +0900 Subject: [PATCH] =?UTF-8?q?[WL-816t]=20=EA=B2=80=EA=B8=B0=20=ED=81=AC?= =?UTF-8?q?=EA=B8=B0=20=3D=20=EA=B3=B5=EA=B2=A9=20=EB=B2=94=EC=9C=84=20?= =?UTF-8?q?=C2=B7=20=EB=AC=B4=EA=B8=B0=20=EC=9C=84=EC=B9=98=20=EC=A0=95?= =?UTF-8?q?=ED=95=A9=20(#816)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 원인(실측): 검기 캘리브레이션 8행이 교체 전 캐릭터 Ai01(root scale 1 · 무기 원본 크기) 기준으로 구워져 있고, 런타임 캐릭터는 814n/814p 로 LH_M05(root scale 1.0527 = f_Scale 0.70 x heightComp 1.5038) + 무기 x0.54~0.66 로 바뀌었다. 로컬 프레임이 달라 호 중심이 0.36~0.88 m, 평면 법선이 6.9~61.0 deg 어긋난 채 고정돼 있었고, 이 오차 벡터가 캐릭터와 함께 돌아 화면에서는 가로 -0.50~+0.59 m / 세로 -0.46~+0.86 m 로 방향마다 다르게 보였다. - WL816t_Bake: 런타임과 같은 PC(swap resolve) x 같은 스케일 x 같은 무기 보정(WLWeaponFitter.Fit)으로 1/2/3 타 클립을 60 Hz 샘플 -> 런타임 ToLocalPos 규약(회전만)으로 12행 재베이크 (구 8행 대체) - SlashTrailSettings: arcFitAttackRange / arcRangeScale 신설 (기본 off = 무동작 · C8 롤백) - WeaponTrailDriver.PlaceArc: 스위치 on 이면 호 바깥 반지름 = 공격 범위 (stoppingDistance 양수 최솟값 + AttackRange_Up + immediateAttackMargin · WLRangeRing 과 같은 SOT · 상수 0개) - 8방향 x 3타 편차 0.525/0.361/0.864 m -> 0.000 m · 법선 61.0/20.5/23.5 deg -> 0.0 deg Co-Authored-By: Claude Opus 5 (1M context) --- AgentScripts/WL816t_Bake.cs | 305 +++++++++++++++++ Assets/WL/Combat/SlashTrailSettings.cs | 9 + Assets/WL/Combat/WeaponTrailDriver.cs | 35 ++ .../Resources/WL/SlashTrailSettings.asset | 313 +++++++++++------- 4 files changed, 540 insertions(+), 122 deletions(-) create mode 100644 AgentScripts/WL816t_Bake.cs diff --git a/AgentScripts/WL816t_Bake.cs b/AgentScripts/WL816t_Bake.cs new file mode 100644 index 000000000..cfce72a08 --- /dev/null +++ b/AgentScripts/WL816t_Bake.cs @@ -0,0 +1,305 @@ +// WL816t_Bake.cs — 검기 호 ↔ 무기 정합 실측·재베이크 (PD #816t) +// unity command run_script --file AgentScripts/WL816t_Bake.cs --entry WL816t_Bake.Probe --args "[10101, false]" +// unity command run_script --file AgentScripts/WL816t_Bake.cs --entry WL816t_Bake.Probe --args "[10101, true]" (SO 기록) +// +// WL804_Bake 와 같은 수식(SlashArcMeasure)·같은 프리뷰 샘플링을 쓰되 **런타임과 같은 캐릭터**로 잰다. +// · WL804_Bake : Assets/Res_Addr/PC/Ai01.prefab · root scale 1 · 무기 localScale 1 · root.InverseTransformPoint(스케일 포함) +// · 런타임 : WLCharacterSwapSettings.Resolve("Ai01") = LH_M05 · root scale = f_Scale × heightCompensation +// · 무기 = WLWeaponFitter.Fit(targetRatio 0.6) · ToLocalPos = 회전만(스케일 제외) +// 두 좌표계가 달라서 베이크 행이 현재 캐릭터의 칼끝 원과 어긋난다 — 그 편차를 재고 새 행을 만든다. +using System.Collections.Generic; +using System.Linq; +using System.Text; +using UnityEditor; +using UnityEditor.SceneManagement; +using UnityEngine; +using WL.Combat; + +public static class WL816t_Bake +{ + const string SettingsPath = "Assets/WL/Settings/Resources/WL/SlashTrailSettings.asset"; + const string ClassConfigJson = "Assets/ResWork/Table/Export/ClassConfig.json"; + const string AnimDir = "Assets/Res_Addr/Animations/Animation/OneHand/Knight@Attack{0}_S.FBX"; + const float BakedQuality = 50f; + + class Row + { + public int stage; public string clipName; + public Vector3 pivot, normal, bisector, startDir; public float tipR, hiltR, sweep, path, fitQ, q; + public Vector3 tipMid; // 스윙 중간 프레임의 칼끝(런타임 로컬) + public string src; + } + + static readonly int[] Classes = { 10101, 10102, 10501, 10502 }; + + public static object Probe(int classId, bool apply) { return Run(classId, apply, true); } + public static object ProbeAll() + { + var sb = new StringBuilder(); + foreach (var c in Classes) sb.AppendLine(Run(c, false, false)); + return sb.ToString(); + } + public static object ApplyAll() + { + var sb = new StringBuilder(); + foreach (var c in Classes) sb.AppendLine(Run(c, true, false)); + return sb.ToString(); + } + + /// 공격 범위 정합 스위치 on/off + 배수. 되돌리기 = Set(false, 1) + public static object SetRangeFit(bool on, float rangeScale) + { + var s = AssetDatabase.LoadAssetAtPath(SettingsPath); + if (s == null) return "설정 에셋 없음"; + string before = string.Format("before: arcFitAttackRange={0} arcRangeScale={1:F2} arcSizeScale={2:F2}", s.arcFitAttackRange, s.arcRangeScale, s.arcSizeScale); + s.arcFitAttackRange = on; s.arcRangeScale = rangeScale; + EditorUtility.SetDirty(s); AssetDatabase.SaveAssets(); + return before + string.Format(" → after: arcFitAttackRange={0} arcRangeScale={1:F2} arcSizeScale={2:F2}", s.arcFitAttackRange, s.arcRangeScale, s.arcSizeScale); + } + + /// 공격 범위(사거리) 정적 검산 — 런타임 ResolveAttackReach 와 같은 SOT. + public static object Reach(int classId) + { + float atk = 0f; + var arr = Newtonsoft.Json.Linq.JArray.Parse(System.IO.File.ReadAllText(ClassConfigJson)); + foreach (var row in arr) { if ((string)row["n_ClassID"] == classId.ToString()) { float.TryParse((string)row["f_AttackRange"], out atk); break; } } + float margin = WL.Settings.WLTargetingSettings.ImmediateAttackMargin; + return string.Format("class {0} · f_AttackRange={1:F2} + AttackRange_Up(평시 0) + immediateAttackMargin={2:F2} = reach {3:F2} m", classId, atk, margin, atk + margin); + } + + static string Run(int classId, bool apply, bool table) + { + var sb = new StringBuilder(); + var settings = AssetDatabase.LoadAssetAtPath(SettingsPath); + if (settings == null) return "설정 에셋 없음"; + + // ── ClassConfig (C45 · 상수 금지) ──────────────────────────────────── + string weaponName = null; int socketIndex = -1; float fScale = 1f, atkRange = 0f; + try + { + var arr = Newtonsoft.Json.Linq.JArray.Parse(System.IO.File.ReadAllText(ClassConfigJson)); + foreach (var row in arr) + { + if ((string)row["n_ClassID"] != classId.ToString()) continue; + weaponName = (string)row["s_WeaponRHPrefab"]; socketIndex = int.Parse((string)row["n_WeaponRHIndex"]); + if (string.IsNullOrEmpty(weaponName)) { weaponName = (string)row["s_WeaponLHPrefab"]; socketIndex = int.Parse((string)row["n_WeaponLHIndex"]); } + float.TryParse((string)row["f_Scale"], out fScale); + float.TryParse((string)row["f_AttackRange"], out atkRange); + break; + } + } + catch (System.Exception ex) { return "ClassConfig parse fail: " + ex.Message; } + if (string.IsNullOrEmpty(weaponName) || socketIndex < 0) return "class " + classId + " weapon not found"; + + // ── 런타임과 같은 PC 프리팹·스케일 ────────────────────────────────── + string pcName = WL.Character.WLCharacterSwapSettings.Resolve("Ai01"); + float heightComp = WL.Character.WLCharacterSwapSettings.HeightCompensation; + string pcPath = "Assets/Res_Addr/PC/" + pcName + ".prefab"; + var model = AssetDatabase.LoadAssetAtPath(pcPath); + var weaponPrefab = AssetDatabase.LoadAssetAtPath("Assets/Res_Addr/Weapon/" + weaponName + ".prefab"); + if (model == null || weaponPrefab == null) return "load fail pc=" + pcPath + " weapon=" + weaponName; + + float rootScale = Mathf.Max(fScale, 0.01f) * Mathf.Max(heightComp, 0.01f); + sb.AppendLine(string.Format("== class {0} · PC {1}(swap:{2}) rootScale={3:F4}(f_Scale {4:F2} × heightComp {5:F4}) · weapon {6}@{7} · f_AttackRange={8:F2}", + classId, pcName, pcName != "Ai01", rootScale, fScale, heightComp, weaponName, socketIndex, atkRange)); + + var scene = EditorSceneManager.NewPreviewScene(); + bool animMode = false; + var rows = new List(); + try + { + var go = (GameObject)PrefabUtility.InstantiatePrefab(model, scene); + go.transform.position = Vector3.zero; go.transform.rotation = Quaternion.identity; + go.transform.localScale = Vector3.one * rootScale; + + var pc = go.GetComponentInChildren(true); + if (pc == null || pc.tfs_weapon == null || socketIndex >= pc.tfs_weapon.Length) return sb + "\ntfs_weapon missing"; + var socket = pc.tfs_weapon[socketIndex]; + + var w = (GameObject)PrefabUtility.InstantiatePrefab(weaponPrefab, scene); + w.transform.SetParent(socket, false); + w.transform.localPosition = Vector3.zero; w.transform.localRotation = Quaternion.identity; w.transform.localScale = Vector3.one; + + // ── 814p 무기 축소(런타임과 동일 경로) ────────────────────────── + var fitter = go.GetComponent(); + if (fitter == null) fitter = go.AddComponent(); + float wk = fitter.Fit(w.transform, socket); + sb.AppendLine(string.Format(" 무기 보정 ×{0:F4} (WLWeaponFitter.Fit · targetRatio={1:F2})", wk, WL.Character.WLWeaponFitSettings.ResolveRatio(w.name))); + + // ── 칼자루/칼끝 로컬(WL804_Bake·MeasureSlot 과 같은 규칙) ──────── + Renderer best = null; Mesh bestMesh = null; float bestExtent = 0f; + foreach (var r in socket.GetComponentsInChildren(true)) + { + var mf2 = r.GetComponent(); var smr = r as SkinnedMeshRenderer; + var mesh = smr != null ? smr.sharedMesh : (mf2 != null ? mf2.sharedMesh : null); + if (mesh == null) continue; + var ws = Vector3.Scale(mesh.bounds.size, Abs(r.transform.lossyScale)); + float longest = Mathf.Max(ws.x, Mathf.Max(ws.y, ws.z)); + if (longest > bestExtent) { bestExtent = longest; best = r; bestMesh = mesh; } + } + if (best == null) return sb + "\nno renderer under socket"; + var b = bestMesh.bounds; var size = Vector3.Scale(b.size, Abs(best.transform.lossyScale)); + int axis = size.x >= size.y && size.x >= size.z ? 0 : (size.y >= size.z ? 1 : 2); + Vector3 axisDir = Vector3.zero; axisDir[axis] = 1f; + Vector3 eA = best.transform.TransformPoint(b.center - axisDir * b.extents[axis]); + Vector3 eB = best.transform.TransformPoint(b.center + axisDir * b.extents[axis]); + bool aIsHilt = (eA - socket.position).sqrMagnitude <= (eB - socket.position).sqrMagnitude; + Vector3 hiltLocal = socket.InverseTransformPoint(aIsHilt ? eA : eB); + Vector3 tipLocal = socket.InverseTransformPoint(aIsHilt ? eB : eA); + sb.AppendLine(string.Format(" 무기 월드 길이 {0:F3} m · 칼끝-자루 {1:F3} m", bestExtent, + Vector3.Distance(socket.TransformPoint(tipLocal), socket.TransformPoint(hiltLocal)))); + + var anim = go.GetComponentInChildren(); + var animGo = anim.gameObject; anim.applyRootMotion = false; + var root = go.transform; + + AnimationMode.StartAnimationMode(); animMode = true; + for (int stage = 1; stage <= 3; stage++) + { + var fbx = string.Format(AnimDir, stage); + var clips = AssetDatabase.LoadAllAssetsAtPath(fbx).OfType().Where(c => !c.name.StartsWith("__preview")).ToArray(); + var clip = clips.FirstOrDefault(c => c.name == "Attack" + stage + "_S_" + classId) ?? clips.FirstOrDefault(c => c.name.StartsWith("Attack" + stage)); + if (clip == null) { sb.AppendLine(" [" + stage + "타] 클립 없음 " + fbx); continue; } + + // 클립 전체를 60 Hz 로 훑고 런타임과 같은 속도 트림으로 스윙 구간만 남긴다 + int n0 = Mathf.Max(8, Mathf.RoundToInt(clip.length * 60f) + 1); + var tAll = new Vector3[n0]; var hAll = new Vector3[n0]; + for (int i = 0; i < n0; i++) + { + float t = clip.length * i / (n0 - 1); + AnimationMode.BeginSampling(); + AnimationMode.SampleAnimationClip(animGo, clip, t); + AnimationMode.EndSampling(); + // 🔴 런타임 ToLocalPos 와 동일 = 회전만(스케일 제외) + tAll[i] = Quaternion.Inverse(root.rotation) * (socket.TransformPoint(tipLocal) - root.position); + hAll[i] = Quaternion.Inverse(root.rotation) * (socket.TransformPoint(hiltLocal) - root.position); + } + int lo = 0, hi = n0 - 1; + float ratio = settings.swingTrimSpeedRatio; + if (ratio > 0f) + { + float maxStep = 0f; var step = new float[n0]; + for (int i = 1; i < n0; i++) { step[i] = Vector3.Distance(tAll[i], tAll[i - 1]); if (step[i] > maxStep) maxStep = step[i]; } + float th = maxStep * ratio; int f = -1, l = -1; + for (int i = 1; i < n0; i++) if (step[i] >= th) { if (f < 0) f = i - 1; l = i; } + if (f >= 0 && l > f) { lo = f; hi = l; } + } + int n = hi - lo + 1; + if (n < 3) { lo = 0; hi = n0 - 1; n = n0; } + var tips = new Vector3[n]; var hilts = new Vector3[n]; + for (int i = 0; i < n; i++) { tips[i] = tAll[lo + i]; hilts[i] = hAll[lo + i]; } + + float fullPath = 0f; Vector3 pd = (tips[0] - hilts[0]).normalized; float bladeAng = 0f; + for (int i = 1; i < n; i++) + { + fullPath += Vector3.Distance(tips[i], tips[i - 1]); + var d = (tips[i] - hilts[i]).normalized; bladeAng += Vector3.Angle(pd, d); pd = d; + } + + var fit = SlashArcMeasure.FitArcOrdered(tips, n); + if (!fit.valid) { sb.AppendLine(" [" + stage + "타] 원 피팅 실패 (n=" + n + ")"); continue; } + Vector3 nrm = fit.normal, pivot = fit.center; + float tipR = SlashArcMeasure.MeanRadius(tips, n, pivot, nrm); + float hiltR = SlashArcMeasure.MeanRadius(hilts, n, pivot, nrm); + float dev = SlashArcMeasure.RadiusDeviation(tips, n, pivot, nrm, tipR); + string pivotSrc = "칼끝원"; + if (tipR < 1e-3f || tipR <= hiltR * 1.15f || dev > tipR * 0.25f) + { + Vector3 tc = SlashArcMeasure.CentroidOnPlane(tips, n, nrm, tips[0]); + pivot = SlashArcMeasure.CentroidOnPlane(hilts, n, nrm, tc); + tipR = SlashArcMeasure.MeanRadius(tips, n, pivot, nrm); + hiltR = SlashArcMeasure.MeanRadius(hilts, n, pivot, nrm); + pivotSrc = "손잡이중심"; + } + Vector3 sd2, bis; float sweep; + if (!SlashArcMeasure.RecomputeAboutPivot(tips, n, pivot, ref nrm, out sd2, out bis, out sweep)) + { sb.AppendLine(" [" + stage + "타] RecomputeAboutPivot 실패"); continue; } + float fitQ = Mathf.Clamp01(1f - (dev / Mathf.Max(tipR, 1e-3f)) * 2f); + + rows.Add(new Row + { + stage = stage, clipName = "Effect_Slash_" + classId + "_" + stage, + pivot = pivot, normal = nrm, bisector = bis, startDir = sd2, + tipR = tipR, hiltR = hiltR, sweep = sweep, path = fullPath, fitQ = fitQ, + q = fullPath * Mathf.Max(fitQ, 0.05f), tipMid = tips[n / 2], + src = string.Format("wl816t {0:yyyy-MM-dd HH:mm} {1} f{2}~f{3}/{4}@60Hz n={5} PC={6} rootScale={7:F4} weaponK={8:F4} path={9:F2} bladeAng={10:F0}° sweep={11:F1}° pivot={12} tipR={13:F3} hiltR={14:F3} dev={15:F3} fitQ={16:F2} (런타임 로컬=회전만)", + System.DateTime.Now, clip.name, lo, hi, n0 - 1, n, pcName, rootScale, wk, fullPath, bladeAng, sweep, pivotSrc, tipR, hiltR, dev, fitQ) + }); + } + AnimationMode.StopAnimationMode(); animMode = false; + + // ── 비교 + 8방향 편차 ─────────────────────────────────────────── + sb.AppendLine(""); + sb.AppendLine("clip | old pivot(로컬) tipR | new pivot(로컬) tipR | Δpivot(m) ΔtipR(m) Δnormal(°)"); + var cams = CamBasis(); + var devTable = new StringBuilder(); + foreach (var r in rows) + { + var old = settings.FindCalibration(classId, r.clipName); + if (old == null) { sb.AppendLine(string.Format("{0,-23} | (없음) | {1} {2:F3} | -", r.clipName, V(r.pivot), r.tipR)); continue; } + float dPiv = Vector3.Distance(old.pivot, r.pivot); + float dTip = r.tipR - old.tipRadius; + float dNrm = Vector3.Angle(old.planeNormal, r.normal); + sb.AppendLine(string.Format("{0,-23} | {1} {2:F3} | {3} {4:F3} | {5:F3} {6:+0.000;-0.000} {7:F1}", + r.clipName, V(old.pivot), old.tipRadius, V(r.pivot), r.tipR, dPiv, dTip, dNrm)); + + // 8방향: 구 행으로 배치한 호의 중심/테두리 vs 실제 칼끝 + if (!table) continue; + devTable.AppendLine(" " + r.clipName); + devTable.AppendLine(" yaw | Δ중심(m) 화면Δ가로(m) 화면Δ세로(m) | 칼끝-호테두리 반경차(m)"); + for (int k = 0; k < 8; k++) + { + float yaw = k * 45f; + var rot = Quaternion.Euler(0f, yaw, 0f); + Vector3 oldPivW = rot * old.pivot; // root at origin + Vector3 newPivW = rot * r.pivot; + Vector3 tipW = rot * r.tipMid; + Vector3 d = oldPivW - newPivW; + float radialGap = Vector3.Distance(tipW, oldPivW) - old.tipRadius * Mathf.Max(settings.arcSizeScale, 0.01f); + devTable.AppendLine(string.Format(" {0,3:F0} | {1:F3} {2,8:+0.000;-0.000} {3,8:+0.000;-0.000} | {4,8:+0.000;-0.000}", + yaw, d.magnitude, Vector3.Dot(d, cams[0]), Vector3.Dot(d, cams[1]), radialGap)); + } + } + sb.AppendLine(""); + sb.AppendLine("8방향 편차(카메라 기준 · PD 구도 yaw45 내려보기 45°)"); + sb.Append(devTable); + + if (apply) + { + int removed = 0; + foreach (var r in rows) + { + removed += settings.swingCalibrations.RemoveAll(c => c != null && c.classId == classId && c.clipName == r.clipName); + settings.swingCalibrations.Add(new SwingCalibration + { + classId = classId, clipName = r.clipName, kind = SwingKind.Swing, + planeNormal = r.normal, bisector = r.bisector, startDir = r.startDir, + pivot = r.pivot, tipRadius = r.tipR, hiltRadius = r.hiltR, sweepDeg = r.sweep, + stabAxis = Vector3.forward, stabStart = r.pivot, stabLength = Mathf.Max(r.tipR, 1e-3f), + quality = Mathf.Max(BakedQuality, r.q), source = r.src + }); + } + EditorUtility.SetDirty(settings); + AssetDatabase.SaveAssets(); + sb.AppendLine(string.Format("APPLIED {0}행 (기존 {1}행 교체 · 총 {2}행)", rows.Count, removed, settings.swingCalibrations.Count)); + } + else sb.AppendLine("(dry)"); + } + finally + { + if (animMode) AnimationMode.StopAnimationMode(); + EditorSceneManager.ClosePreviewScene(scene); + } + return sb.ToString(); + } + + /// PD 구도(비스듬히 내려보는 카메라)의 화면 가로·세로 축(월드). + static Vector3[] CamBasis() + { + var rot = Quaternion.Euler(45f, 45f, 0f); + return new[] { rot * Vector3.right, rot * Vector3.up }; + } + + static string V(Vector3 v) { return string.Format("({0,6:F3},{1,6:F3},{2,6:F3})", v.x, v.y, v.z); } + static Vector3 Abs(Vector3 v) { return new Vector3(Mathf.Abs(v.x), Mathf.Abs(v.y), Mathf.Abs(v.z)); } +} diff --git a/Assets/WL/Combat/SlashTrailSettings.cs b/Assets/WL/Combat/SlashTrailSettings.cs index e8589120a..8003fcba7 100644 --- a/Assets/WL/Combat/SlashTrailSettings.cs +++ b/Assets/WL/Combat/SlashTrailSettings.cs @@ -788,6 +788,15 @@ namespace WL.Combat [Tooltip("정합한 크기에 곱하는 배수. 1 = 칼끝 반경과 정확히 일치(기본 · C3-5)")] [Range(0.4f, 2.5f)] public float arcSizeScale = 1f; + [Tooltip("■ #816t — 호 바깥 반지름을 칼끝 반경 대신 **플레이어 공격 범위**(사거리)에 맞춘다. " + + "출처 = NavMeshAgent.stoppingDistance 양수 최솟값(= ClassConfig f_AttackRange · PCActor.cs:381) " + + "+ eStat.AttackRange_Up + WLTargetingSettings.immediateAttackMargin — WLRangeRing 과 같은 SOT(상수 0개 · C45). " + + "끄면 즉시 이전(칼끝 반경 정합) 동작으로 돌아간다(C8 롤백)")] + public bool arcFitAttackRange = false; + + [Tooltip("공격 범위에 곱하는 배수. 1 = 사거리와 정확히 일치")] + [Range(0.3f, 2f)] public float arcRangeScale = 1f; + [Tooltip("호를 스윙 평면에서 법선 방향으로 이만큼(m) 띄운다. 0 = 평면 위. " + "무기 메시와 Z-파이팅이 보이면 아주 작은 값을 준다")] public float arcPlaneOffset = 0f; diff --git a/Assets/WL/Combat/WeaponTrailDriver.cs b/Assets/WL/Combat/WeaponTrailDriver.cs index ce2f844c4..07f2b4ace 100644 --- a/Assets/WL/Combat/WeaponTrailDriver.cs +++ b/Assets/WL/Combat/WeaponTrailDriver.cs @@ -1602,6 +1602,13 @@ namespace WL.Combat s = cal.tipRadius / mf.radiusOuter; break; } + // ── #816t 공격 범위 정합 — 호 바깥 반지름을 플레이어 사거리에 맞춘다(PD 지시) ── + // 출처는 WLRangeRing 과 같은 SOT(테이블 f_AttackRange + 버프 + 즉시공격 여유). 상수 0 개(C45). + // 사거리를 못 읽으면(로비·스탯 미초기화) 0 → 위의 칼끝 반경 정합을 그대로 쓴다. + float reach = settings.arcFitAttackRange ? ResolveAttackReach() : 0f; + if (reach > 0.01f && mf.radiusOuter > 1e-4f) + s = reach * Mathf.Max(settings.arcRangeScale, 0.01f) / mf.radiusOuter; + s *= Mathf.Max(settings.arcSizeScale, 0.01f); // ── 회전 · 위치 ──────────────────────────────────────────────── @@ -1740,6 +1747,34 @@ namespace WL.Combat private Vector3 ToLocalPos(Vector3 world) { return Quaternion.Inverse(transform.rotation) * (world - transform.position); } private Vector3 ToWorldPos(Vector3 local) { return transform.position + transform.rotation * local; } + // ── #816t 공격 범위(사거리) 해석 — WLRangeRing.Poll 과 같은 출처·같은 수식 ────── + // stoppingDistance 는 타겟 반경·크기 보정으로 커질 수 있어(MyActor.cs:207·212·213) + // **양수 최솟값**을 기억한다 = 보정 없는 평시 값 = ClassConfig f_AttackRange(PCActor.cs:381). + private float _baseStop; + + /// 마지막으로 해석한 공격 범위(m). 0 = 아직 못 읽음(검증용 읽기 전용 · 게임 로직은 쓰지 않는다). + public static float LastAttackReach; + + private float ResolveAttackReach() + { + if (_pc == null) return 0f; + var agent = _pc.Get_Agent(); + if (agent != null) + { + float sd = agent.stoppingDistance; + if (sd > 0.01f && (_baseStop <= 0f || sd < _baseStop)) _baseStop = sd; + } + if (_baseStop <= 0f) return 0f; + + float up = 0f; + var stat = _pc.Get_StatInfo(); + if (stat != null) up = (float)stat.Get_Stat(eStat.AttackRange_Up); + + float reach = _baseStop + up + WL.Settings.WLTargetingSettings.ImmediateAttackMargin; + LastAttackReach = reach; + return reach; + } + // ───────────────────────────────────────────────────────────────────────── // 수명 관리 // ───────────────────────────────────────────────────────────────────────── diff --git a/Assets/WL/Settings/Resources/WL/SlashTrailSettings.asset b/Assets/WL/Settings/Resources/WL/SlashTrailSettings.asset index d0a146097..9c268f420 100644 --- a/Assets/WL/Settings/Resources/WL/SlashTrailSettings.asset +++ b/Assets/WL/Settings/Resources/WL/SlashTrailSettings.asset @@ -407,150 +407,217 @@ MonoBehaviour: flipAxis: 0 bakedAt: 2026-09-07 01:52:52 swingCalibrations: - - classId: 10501 - clipName: Effect_Slash_10501_2 - kind: 1 - planeNormal: {x: 0.15228733, y: 0.9881525, z: -0.01905872} - pivot: {x: -0.01862258, y: 0.8349972, z: 0.039082136} - bisector: {x: 0.9480554, y: -0.14060435, z: 0.28534392} - startDir: {x: -0.9755819, y: 0.15338214, z: 0.15720595} - tipRadius: 0.7859197 - hiltRadius: 0.2289177 - sweepDeg: 308.74216 - stabAxis: {x: 0.9878676, y: -0.07309146, z: -0.13702233} - stabStart: {x: -0.84236026, y: 0.7775105, z: 0.17080714} - stabLength: 1.5588787 - quality: 6.4799576 - source: "runtime 02:40:00 samples=30/33(trim 0~29) path=8.43 \uCE7C\uB0A0\uD68C\uC804=604\xB0 - \uCE7C\uB05D/\uC190\uC7A1\uC774=3.36 sweep=308.7\xB0 straight=0.60 fwd=-0.14 - chord=1.56 pivot=\uCE7C\uB05D\uC6D0 tipR=0.786 hiltR=0.229 dev=0.091 fitQ=0.77 - q=6.48" - - classId: 10501 - clipName: Effect_Slash_10501_1 - kind: 1 - planeNormal: {x: 0.09609319, y: -0.69287807, z: 0.7146231} - pivot: {x: 0.013419926, y: 0.6920113, z: -0.017135125} - bisector: {x: -0.46833384, y: 0.6020381, z: 0.64669436} - startDir: {x: 0.7837881, y: 0.49521428, z: 0.374752} - tipRadius: 0.8682612 - hiltRadius: 0.19870256 - sweepDeg: 160.0273 - stabAxis: {x: -0.7661477, y: -0.63733035, z: -0.0826303} - stabStart: {x: 0.65847033, y: 1.292506, z: 0.12008436} - stabLength: 1.8009284 - quality: 5.0141697 - source: "runtime 02:26:58 samples=28/28(trim 0~27) path=5.21 \uCE7C\uB0A0\uD68C\uC804=366\xB0 - \uCE7C\uB05D/\uC190\uC7A1\uC774=4.43 sweep=160.0\xB0 straight=0.36 fwd=-0.08 - chord=1.80 pivot=\uCE7C\uB05D\uC6D0 tipR=0.868 hiltR=0.199 dev=0.016 fitQ=0.96 - q=5.01" - classId: 10101 clipName: Effect_Slash_10101_1 kind: 1 - planeNormal: {x: 0.3078961, y: -0.636374, z: -0.70726806} - pivot: {x: -0.056650292, y: 0.74904346, z: 0.17702837} - bisector: {x: 0.897873, y: -0.05152121, z: 0.43722925} - startDir: {x: -0.6402187, y: 0.41131842, z: -0.6487967} - tipRadius: 1.0059098 - hiltRadius: 0.20204122 - sweepDeg: 303.2123 - stabAxis: {x: 0.7060405, y: -0.4063584, z: 0.5799824} - stabStart: {x: -0.7590293, y: 1.3011718, z: -0.30031368} - stabLength: 1.9881575 - quality: 5.966149 - source: "runtime 02:41:31 samples=28/28(trim 0~27) path=6.15 \uCE7C\uB0A0\uD68C\uC804=363\xB0 - \uCE7C\uB05D/\uC190\uC7A1\uC774=4.65 sweep=303.2\xB0 straight=0.65 fwd=0.58 - chord=1.99 pivot=\uCE7C\uB05D\uC6D0 tipR=1.006 hiltR=0.202 dev=0.015 fitQ=0.97 - q=5.97" + planeNormal: {x: 0.6155671, y: -0.7459609, z: 0.2542036} + pivot: {x: -0.44185022, y: 0.90176433, z: -0.14577419} + bisector: {x: -0.18893999, y: -0.452843, z: -0.8713409} + startDir: {x: 0.4323041, y: 0.5893181, z: 0.6825082} + tipRadius: 0.71769434 + hiltRadius: 0.2310255 + sweepDeg: 398.79218 + stabAxis: {x: 0, y: 0, z: 1} + stabStart: {x: -0.44185022, y: 0.90176433, z: -0.14577419} + stabLength: 0.71769434 + quality: 50 + source: "wl816t 2026-09-15 09:35 Attack1_S_10101 f12~f35/50@60Hz n=24 PC=LH_M05 + rootScale=1.0527 weaponK=0.5369 path=6.88 bladeAng=544\xB0 sweep=398.8\xB0 + pivot=\uC190\uC7A1\uC774\uC911\uC2EC tipR=0.718 hiltR=0.231 dev=0.195 fitQ=0.46 + (\uB7F0\uD0C0\uC784 \uB85C\uCEEC=\uD68C\uC804\uB9CC)" - classId: 10101 clipName: Effect_Slash_10101_2 kind: 1 - planeNormal: {x: 0.09728308, y: 0.9890535, z: -0.11094675} - pivot: {x: -0.071887866, y: 0.80780745, z: 0.034430865} - bisector: {x: 0.9841305, y: -0.078973934, z: 0.15890326} - startDir: {x: -0.76585925, y: 0.14558588, z: 0.6263101} - tipRadius: 0.9324841 - hiltRadius: 0.2528293 - sweepDeg: 263.46906 - stabAxis: {x: 0.8400051, y: -0.09362712, z: -0.5344393} - stabStart: {x: -0.7618986, y: 0.83268386, z: 0.60202444} - stabLength: 1.7789476 - quality: 5.7660966 - source: "runtime 02:28:34 samples=29/31(trim 0~28) path=6.25 \uCE7C\uB0A0\uD68C\uC804=385\xB0 - \uCE7C\uB05D/\uC190\uC7A1\uC774=3.35 sweep=263.5\xB0 straight=0.65 fwd=-0.53 - chord=1.78 pivot=\uCE7C\uB05D\uC6D0 tipR=0.932 hiltR=0.253 dev=0.036 fitQ=0.92 - q=5.77" + planeNormal: {x: 0.04436424, y: 0.9695876, z: 0.24068981} + pivot: {x: -0.07215572, y: 0.45991144, z: -0.0608187} + bisector: {x: -0.8473422, y: -0.09110173, z: 0.52317464} + startDir: {x: -0.20181037, y: 0.24465796, z: -0.9483749} + tipRadius: 0.65453726 + hiltRadius: 0.3102 + sweepDeg: 220.66309 + stabAxis: {x: 0, y: 0, z: 1} + stabStart: {x: -0.07215572, y: 0.45991144, z: -0.0608187} + stabLength: 0.65453726 + quality: 50 + source: "wl816t 2026-09-15 09:35 Attack2_S_10101 f14~f44/52@60Hz n=31 PC=LH_M05 + rootScale=1.0527 weaponK=0.5369 path=7.36 bladeAng=614\xB0 sweep=220.7\xB0 + pivot=\uCE7C\uB05D\uC6D0 tipR=0.655 hiltR=0.310 dev=0.089 fitQ=0.73 (\uB7F0\uD0C0\uC784 + \uB85C\uCEEC=\uD68C\uC804\uB9CC)" - classId: 10101 clipName: Effect_Slash_10101_3 kind: 1 - planeNormal: {x: 0.16853563, y: -0.9836209, z: -0.06391966} - pivot: {x: 0.09357196, y: 1.2423787, z: -0.1380892} - bisector: {x: 0.94817513, y: 0.14405777, z: 0.28321597} - startDir: {x: 0.25327274, y: 0.10588382, z: -0.9615829} - tipRadius: 0.95663345 - hiltRadius: 0.40691212 - sweepDeg: 181.94073 - stabAxis: {x: -0.12657256, y: -0.108728364, z: 0.9859805} - stabStart: {x: 0.3463071, y: 1.37269, z: -1.1111009} - stabLength: 2.0542197 + planeNormal: {x: -0.23372532, y: -0.96444863, z: -0.12333438} + pivot: {x: -0.37444147, y: 0.6109033, z: 0.22184418} + bisector: {x: 0.95191514, y: -0.20113623, z: -0.2310883} + startDir: {x: 0.61234134, y: -0.04747615, z: -0.7891667} + tipRadius: 0.71797794 + hiltRadius: 0.51229453 + sweepDeg: 78.42377 + stabAxis: {x: 0, y: 0, z: 1} + stabStart: {x: -0.37444147, y: 0.6109033, z: 0.22184418} + stabLength: 0.71797794 quality: 50 - source: "editbake 2026-09-07 09:58 Attack3_S_10101 f7~f11@60Hz n=9 path=3.03 - bladeAng=154\xB0 sweep=181.9\xB0 pivot=\uCE7C\uB05D\uC6D0 tipR=0.957 hiltR=0.407 - dev=0.071 fitQ=0.85 q=2.58 (WL804_Bake \xB7 \uB7F0\uD0C0\uC784 \uC7AC\uC2E4\uCE21\uC774 - \uB36E\uC9C0 \uC54A\uB3C4\uB85D quality \uACE0\uC815)" + source: "wl816t 2026-09-15 09:35 Attack3_S_10101 f16~f54/64@60Hz n=39 PC=LH_M05 + rootScale=1.0527 weaponK=0.5369 path=3.97 bladeAng=257\xB0 sweep=78.4\xB0 pivot=\uCE7C\uB05D\uC6D0 + tipR=0.718 hiltR=0.512 dev=0.120 fitQ=0.66 (\uB7F0\uD0C0\uC784 \uB85C\uCEEC=\uD68C\uC804\uB9CC)" + - classId: 10102 + clipName: Effect_Slash_10102_1 + kind: 1 + planeNormal: {x: 0.6155671, y: -0.7459609, z: 0.2542036} + pivot: {x: -0.44185022, y: 0.90176433, z: -0.14577419} + bisector: {x: -0.18893999, y: -0.452843, z: -0.8713409} + startDir: {x: 0.4323041, y: 0.5893181, z: 0.6825082} + tipRadius: 0.71769434 + hiltRadius: 0.2310255 + sweepDeg: 398.79218 + stabAxis: {x: 0, y: 0, z: 1} + stabStart: {x: -0.44185022, y: 0.90176433, z: -0.14577419} + stabLength: 0.71769434 + quality: 50 + source: "wl816t 2026-09-15 09:35 Attack1_S_10102 f12~f35/50@60Hz n=24 PC=LH_M05 + rootScale=1.0527 weaponK=0.5369 path=6.88 bladeAng=544\xB0 sweep=398.8\xB0 + pivot=\uC190\uC7A1\uC774\uC911\uC2EC tipR=0.718 hiltR=0.231 dev=0.195 fitQ=0.46 + (\uB7F0\uD0C0\uC784 \uB85C\uCEEC=\uD68C\uC804\uB9CC)" + - classId: 10102 + clipName: Effect_Slash_10102_2 + kind: 1 + planeNormal: {x: 0.04436424, y: 0.9695876, z: 0.24068981} + pivot: {x: -0.07215572, y: 0.45991144, z: -0.0608187} + bisector: {x: -0.8473422, y: -0.09110173, z: 0.52317464} + startDir: {x: -0.20181037, y: 0.24465796, z: -0.9483749} + tipRadius: 0.65453726 + hiltRadius: 0.3102 + sweepDeg: 220.66309 + stabAxis: {x: 0, y: 0, z: 1} + stabStart: {x: -0.07215572, y: 0.45991144, z: -0.0608187} + stabLength: 0.65453726 + quality: 50 + source: "wl816t 2026-09-15 09:35 Attack2_S_10102 f14~f44/52@60Hz n=31 PC=LH_M05 + rootScale=1.0527 weaponK=0.5369 path=7.36 bladeAng=614\xB0 sweep=220.7\xB0 + pivot=\uCE7C\uB05D\uC6D0 tipR=0.655 hiltR=0.310 dev=0.089 fitQ=0.73 (\uB7F0\uD0C0\uC784 + \uB85C\uCEEC=\uD68C\uC804\uB9CC)" - classId: 10102 clipName: Effect_Slash_10102_3 kind: 1 - planeNormal: {x: 0.16853563, y: -0.9836209, z: -0.06391966} - pivot: {x: 0.09357196, y: 1.2423787, z: -0.1380892} - bisector: {x: 0.94817513, y: 0.14405777, z: 0.28321597} - startDir: {x: 0.25327274, y: 0.10588382, z: -0.9615829} - tipRadius: 0.95663345 - hiltRadius: 0.40691212 - sweepDeg: 181.94073 - stabAxis: {x: -0.12657256, y: -0.108728364, z: 0.9859805} - stabStart: {x: 0.3463071, y: 1.37269, z: -1.1111009} - stabLength: 2.0542197 + planeNormal: {x: -0.23372532, y: -0.96444863, z: -0.12333438} + pivot: {x: -0.37444147, y: 0.6109033, z: 0.22184418} + bisector: {x: 0.95191514, y: -0.20113623, z: -0.2310883} + startDir: {x: 0.61234134, y: -0.04747615, z: -0.7891667} + tipRadius: 0.71797794 + hiltRadius: 0.51229453 + sweepDeg: 78.42377 + stabAxis: {x: 0, y: 0, z: 1} + stabStart: {x: -0.37444147, y: 0.6109033, z: 0.22184418} + stabLength: 0.71797794 quality: 50 - source: "editbake 2026-09-07 09:58 Attack3_S_10102 f7~f11@60Hz n=9 path=3.03 - bladeAng=154\xB0 sweep=181.9\xB0 pivot=\uCE7C\uB05D\uC6D0 tipR=0.957 hiltR=0.407 - dev=0.071 fitQ=0.85 q=2.58 (WL804_Bake \xB7 \uB7F0\uD0C0\uC784 \uC7AC\uC2E4\uCE21\uC774 - \uB36E\uC9C0 \uC54A\uB3C4\uB85D quality \uACE0\uC815)" + source: "wl816t 2026-09-15 09:35 Attack3_S_10102 f16~f54/64@60Hz n=39 PC=LH_M05 + rootScale=1.0527 weaponK=0.5369 path=3.97 bladeAng=257\xB0 sweep=78.4\xB0 pivot=\uCE7C\uB05D\uC6D0 + tipR=0.718 hiltR=0.512 dev=0.120 fitQ=0.66 (\uB7F0\uD0C0\uC784 \uB85C\uCEEC=\uD68C\uC804\uB9CC)" + - classId: 10501 + clipName: Effect_Slash_10501_1 + kind: 1 + planeNormal: {x: 0.6043122, y: -0.7630855, z: 0.22914462} + pivot: {x: -0.5143255, y: 0.99384046, z: -0.13518894} + bisector: {x: -0.2910512, y: -0.47915196, z: -0.8280716} + startDir: {x: 0.60951185, y: 0.6279901, z: 0.48386335} + tipRadius: 0.7389534 + hiltRadius: 0.23210584 + sweepDeg: 416.96194 + stabAxis: {x: 0, y: 0, z: 1} + stabStart: {x: -0.5143255, y: 0.99384046, z: -0.13518894} + stabLength: 0.7389534 + quality: 50 + source: "wl816t 2026-09-15 09:35 Attack1_S_10501 f12~f35/50@60Hz n=24 PC=LH_M05 + rootScale=1.0527 weaponK=0.6587 path=7.35 bladeAng=545\xB0 sweep=417.0\xB0 + pivot=\uC190\uC7A1\uC774\uC911\uC2EC tipR=0.739 hiltR=0.232 dev=0.204 fitQ=0.45 + (\uB7F0\uD0C0\uC784 \uB85C\uCEEC=\uD68C\uC804\uB9CC)" + - classId: 10501 + clipName: Effect_Slash_10501_2 + kind: 1 + planeNormal: {x: 0.04244417, y: 0.97287947, z: 0.2273852} + pivot: {x: -0.077203944, y: 0.43669456, z: -0.052627534} + bisector: {x: -0.81407905, y: -0.098262936, z: 0.5723808} + startDir: {x: -0.2501254, y: 0.23068981, z: -0.9403295} + tipRadius: 0.7294197 + hiltRadius: 0.2821212 + sweepDeg: 221.86562 + stabAxis: {x: 0, y: 0, z: 1} + stabStart: {x: -0.077203944, y: 0.43669456, z: -0.052627534} + stabLength: 0.7294197 + quality: 50 + source: "wl816t 2026-09-15 09:35 Attack2_S_10501 f14~f44/52@60Hz n=31 PC=LH_M05 + rootScale=1.0527 weaponK=0.6587 path=8.04 bladeAng=616\xB0 sweep=221.9\xB0 + pivot=\uCE7C\uB05D\uC6D0 tipR=0.729 hiltR=0.282 dev=0.083 fitQ=0.77 (\uB7F0\uD0C0\uC784 + \uB85C\uCEEC=\uD68C\uC804\uB9CC)" - classId: 10501 clipName: Effect_Slash_10501_3 kind: 1 - planeNormal: {x: 0.16179384, y: -0.98433506, z: -0.070051745} - pivot: {x: 0.06956807, y: 1.2031016, z: -0.17662044} - bisector: {x: 0.98678565, y: 0.16074902, z: 0.020341488} - startDir: {x: 0.019124245, y: 0.074101284, z: -0.99706733} - tipRadius: 0.797171 - hiltRadius: 0.35618255 - sweepDeg: 178.7966 - stabAxis: {x: 0.11699972, y: -0.072316095, z: 0.99049556} - stabStart: {x: 0.08246852, y: 1.288136, z: -1.0311682} - stabLength: 1.7564142 + planeNormal: {x: 0.043638147, y: -0.9978227, z: -0.049451575} + pivot: {x: -0.32562953, y: 0.5273627, z: 0.22276048} + bisector: {x: 0.96429247, y: 0.05501082, z: -0.25906354} + startDir: {x: 0.53950334, y: 0.06519729, z: -0.8394555} + tipRadius: 0.80060536 + hiltRadius: 0.42106363 + sweepDeg: 84.31582 + stabAxis: {x: 0, y: 0, z: 1} + stabStart: {x: -0.32562953, y: 0.5273627, z: 0.22276048} + stabLength: 0.80060536 quality: 50 - source: "editbake 2026-09-07 09:59 Attack3_S_10501 f7~f11@60Hz n=9 path=2.56 - bladeAng=153\xB0 sweep=178.8\xB0 pivot=\uCE7C\uB05D\uC6D0 tipR=0.797 hiltR=0.356 - dev=0.082 fitQ=0.79 q=2.03 (WL804_Bake \xB7 \uB7F0\uD0C0\uC784 \uC7AC\uC2E4\uCE21\uC774 - \uB36E\uC9C0 \uC54A\uB3C4\uB85D quality \uACE0\uC815)" + source: "wl816t 2026-09-15 09:35 Attack3_S_10501 f16~f54/64@60Hz n=39 PC=LH_M05 + rootScale=1.0527 weaponK=0.6587 path=4.20 bladeAng=254\xB0 sweep=84.3\xB0 pivot=\uCE7C\uB05D\uC6D0 + tipR=0.801 hiltR=0.421 dev=0.120 fitQ=0.70 (\uB7F0\uD0C0\uC784 \uB85C\uCEEC=\uD68C\uC804\uB9CC)" + - classId: 10502 + clipName: Effect_Slash_10502_1 + kind: 1 + planeNormal: {x: 0.6255864, y: -0.7492798, z: 0.21730489} + pivot: {x: -0.4383909, y: 0.96184254, z: -0.13046789} + bisector: {x: 0.32277644, y: 0.5021659, z: 0.80227476} + startDir: {x: 0.6897078, y: 0.6613513, z: 0.29481786} + tipRadius: 0.6846314 + hiltRadius: 0.21322028 + sweepDeg: 75.39421 + stabAxis: {x: 0, y: 0, z: 1} + stabStart: {x: -0.4383909, y: 0.96184254, z: -0.13046789} + stabLength: 0.6846314 + quality: 50 + source: "wl816t 2026-09-15 09:35 Attack1_S_10502 f12~f35/50@60Hz n=24 PC=LH_M05 + rootScale=1.0527 weaponK=0.5632 path=6.42 bladeAng=545\xB0 sweep=75.4\xB0 pivot=\uC190\uC7A1\uC774\uC911\uC2EC + tipR=0.685 hiltR=0.213 dev=0.167 fitQ=0.51 (\uB7F0\uD0C0\uC784 \uB85C\uCEEC=\uD68C\uC804\uB9CC)" + - classId: 10502 + clipName: Effect_Slash_10502_2 + kind: 1 + planeNormal: {x: 0.047004227, y: 0.97822416, z: 0.20215859} + pivot: {x: -0.07373327, y: 0.44671315, z: -0.044609603} + bisector: {x: -0.7875351, y: -0.08820486, z: 0.609925} + startDir: {x: -0.28951094, y: 0.20703694, z: -0.9345154} + tipRadius: 0.6426512 + hiltRadius: 0.30169082 + sweepDeg: 222.2306 + stabAxis: {x: 0, y: 0, z: 1} + stabStart: {x: -0.07373327, y: 0.44671315, z: -0.044609603} + stabLength: 0.6426512 + quality: 50 + source: "wl816t 2026-09-15 09:35 Attack2_S_10502 f14~f44/52@60Hz n=31 PC=LH_M05 + rootScale=1.0527 weaponK=0.5632 path=7.04 bladeAng=616\xB0 sweep=222.2\xB0 + pivot=\uCE7C\uB05D\uC6D0 tipR=0.643 hiltR=0.302 dev=0.076 fitQ=0.76 (\uB7F0\uD0C0\uC784 + \uB85C\uCEEC=\uD68C\uC804\uB9CC)" - classId: 10502 clipName: Effect_Slash_10502_3 kind: 1 - planeNormal: {x: 0.16322699, y: -0.9838918, z: -0.07289651} - pivot: {x: 0.06879786, y: 1.1890548, z: -0.17932634} - bisector: {x: 0.9864896, y: 0.16381113, z: -0.0020673866} - startDir: {x: -0.012327602, y: 0.0718477, z: -0.9973394} - tipRadius: 0.74294686 - hiltRadius: 0.5402583 - sweepDeg: 179.8086 - stabAxis: {x: 0.14303008, y: -0.07050567, z: 0.98720384} - stabStart: {x: 0.055376478, y: 1.2679739, z: -0.98118037} - stabLength: 1.6514131 + planeNormal: {x: 0.035052184, y: -0.99825996, z: -0.047418203} + pivot: {x: -0.28646088, y: 0.51465774, z: 0.23871267} + bisector: {x: 0.9424084, y: 0.04880832, z: -0.330884} + startDir: {x: 0.4772259, y: 0.058407497, z: -0.8768375} + tipRadius: 0.70055455 + hiltRadius: 0.39948177 + sweepDeg: 84.072044 + stabAxis: {x: 0, y: 0, z: 1} + stabStart: {x: -0.28646088, y: 0.51465774, z: 0.23871267} + stabLength: 0.70055455 quality: 50 - source: "editbake 2026-09-07 09:59 Attack3_S_10502 f7~f11@60Hz n=9 path=2.41 - bladeAng=153\xB0 sweep=179.8\xB0 pivot=\uCE7C\uB05D\uC6D0 tipR=0.743 hiltR=0.540 - dev=0.083 fitQ=0.78 q=1.87 (WL804_Bake \xB7 \uB7F0\uD0C0\uC784 \uC7AC\uC2E4\uCE21\uC774 - \uB36E\uC9C0 \uC54A\uB3C4\uB85D quality \uACE0\uC815)" + source: "wl816t 2026-09-15 09:35 Attack3_S_10502 f16~f54/64@60Hz n=39 PC=LH_M05 + rootScale=1.0527 weaponK=0.5632 path=3.83 bladeAng=254\xB0 sweep=84.1\xB0 pivot=\uCE7C\uB05D\uC6D0 + tipR=0.701 hiltR=0.399 dev=0.110 fitQ=0.69 (\uB7F0\uD0C0\uC784 \uB85C\uCEEC=\uD68C\uC804\uB9CC)" swingMinSweepDegrees: 150 swingMinTipHiltRatio: 3 stabMinStraightness: 0.86 @@ -559,6 +626,8 @@ MonoBehaviour: swingTrimSpeedRatio: 0.2 arcRadiusFit: 0 arcSizeScale: 1 + arcFitAttackRange: 1 + arcRangeScale: 1 arcPlaneOffset: 0 arcRadialOffset: 0 arcLifetimeSeconds: 0