Project_WL/AgentScripts/WL796_Probe.cs

251 lines
12 KiB
C#
Raw Normal View History

WL 리뉴얼 세션 2026-09-06~07 (#760~#800) — 전투·배경·UI·타격감 (조직 PD 로그 #746~#800 · 대화로그 §14~§24) - 전투: Knight@Attack1~3_S 3콤보(4 컨트롤러·클래스별 서브클립) · 타겟팅 4규칙(정면 우선·재타겟·즉시 공격·어그로 금지 · WLTargetingSettings) · 대쉬 후 공격(Stander@Chase_Start · DashDriver · 5 m · 사정거리+0.8 · 근거리 적 우선) · 공격 이동 FrameTable(발 접지 실측 표 · AttackRootMotion) · 충돌 반경/투사체 0.3 배(WLCollisionTuning) · 무적(임시)·펫 금지(WLGameplaySettings) - 검기: NamuFX Slash_B 배리언트 Effect_WLSwingArc 원 피팅 정합 배치 + 캘리브레이션(SlashArcMeasure · SlashTrailSettings) · 찌르기 Effect_WLStab 대기 · 램프 리본(BladeTrail · WL_BladeRibbon.shader · T_WL_BladeRibbonRamp) 보존(drawRibbon 0) - 타격감: Assets/WL/Feel(WLHitFeel · 히트스톱 0.03 · 셰이크 0.10 m · 몹 펀치 1.12 · Actor.Get_Damage 훅 1줄 · 원본 RealCamera 셰이크 결함 대체) - 배경/맵: LMHPOLY Demo_01~10 → WL_Nature01~10(프리팹·씬·NavMesh·스포너·BattleMapConfig) · 물(ToonWaterU) · 포스트 블룸 0.9/0.3 · 잔디(BruteForce·드레싱) 제거 · 마젠타 머티리얼 URP 변환 - UI: 세로 HUD(WL_HUD · 하단 5메뉴 폭 전체 · 채팅/전투 패드 숨김 · WLIngameUiOverride) · Title/TitleInfo 1080×1920 Expand + 배경 높이 fit(WLBackgroundFit) · 로딩 SortOrder_5(WLRawImageAspectSync · 초점표 8장) · Loading1~8 ASTC 6×6 - 도구: AgentScripts/*(LightProbe · WL_MapSwitch · WL760~WL800 프로브/집행/검증 · 상단 사용법 주석) · 에디터 락 프로토콜 파일(staging) - 제외(별도 커밋 예정): Assets/LMHPOLY(703 MB) · Assets/Feel(422 MB) · Assets/Shinabro(300 MB) — 에셋 스토어/구 WL 팩 원본 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-06 23:24:25 +00:00
// WL796_Probe.cs — PD 지시 #796 (하단 채팅창 숨김 + 하단 메뉴 가득 채우기) 사전 실측 · 읽기 전용
// unity command run_script --file AgentScripts/WL796_Probe.cs --entry WL796_Probe.DumpPrefab
// unity command run_script --file AgentScripts/WL796_Probe.cs --entry WL796_Probe.DumpNode --args '["WL_HUD"]'
// unity command run_script --file AgentScripts/WL796_Probe.cs --entry WL796_Probe.RuntimeRects (Play 중)
// 프리팹을 저장하지 않는다(AssetDatabase.LoadAssetAtPath 로 읽기만).
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEditor;
using UnityEngine;
using UnityEngine.UI;
public static class WL796_Probe
{
const string PrefabPath = "Assets/Res_Addr/MainUI/NewGameUI.prefab";
static GameObject Root()
{
return AssetDatabase.LoadAssetAtPath<GameObject>(PrefabPath);
}
static string Path(Transform t, Transform root)
{
var parts = new List<string>();
while (t != null && t != root) { parts.Add(t.name); t = t.parent; }
parts.Reverse();
return string.Join("/", parts);
}
static string RtLine(RectTransform rt)
{
if (rt == null) return "(no RectTransform)";
return string.Format(
"aMin{0} aMax{1} piv{2} anchoredPos{3} sizeDelta{4} scale{5}",
rt.anchorMin.ToString("F2"), rt.anchorMax.ToString("F2"), rt.pivot.ToString("F2"),
rt.anchoredPosition.ToString("F1"), rt.sizeDelta.ToString("F1"), rt.localScale.ToString("F3"));
}
static string Comps(GameObject go)
{
var names = go.GetComponents<Component>()
.Where(c => c != null)
.Select(c => c.GetType().Name)
.Where(n => n != "RectTransform" && n != "Transform");
return string.Join(",", names.ToArray());
}
static void Walk(Transform t, Transform root, StringBuilder sb, int depth, int maxDepth)
{
string pad = new string(' ', depth * 2);
var rt = t as RectTransform;
sb.Append(pad).Append(t.name)
.Append(t.gameObject.activeSelf ? "" : " [OFF]")
.Append(" ").Append(RtLine(rt));
string c = Comps(t.gameObject);
if (c.Length > 0) sb.Append(" {").Append(c).Append("}");
var btn = t.GetComponent<Button>();
if (btn != null)
{
int n = btn.onClick.GetPersistentEventCount();
var ev = new List<string>();
for (int i = 0; i < n; i++)
{
var tgt = btn.onClick.GetPersistentTarget(i);
ev.Add((tgt != null ? tgt.GetType().Name : "null") + "." + btn.onClick.GetPersistentMethodName(i));
}
sb.Append(" onClick[").Append(string.Join(" | ", ev.ToArray())).Append("]");
}
var txt = t.GetComponent<UnityEngine.UI.Text>();
if (txt != null) sb.Append(" text=\"").Append(txt.text).Append("\"");
var tmp = t.GetComponent<TMPro.TMP_Text>();
if (tmp != null) sb.Append(" tmp=\"").Append(tmp.text).Append("\"");
sb.AppendLine();
if (depth >= maxDepth) { if (t.childCount > 0) sb.Append(pad).Append(" ...(").Append(t.childCount).AppendLine(" children)"); return; }
for (int i = 0; i < t.childCount; i++) Walk(t.GetChild(i), root, sb, depth + 1, maxDepth);
}
static Transform FindDeep(Transform root, string name)
{
if (root.name == name) return root;
for (int i = 0; i < root.childCount; i++)
{
var r = FindDeep(root.GetChild(i), name);
if (r != null) return r;
}
return null;
}
static List<Transform> FindAllDeep(Transform root, string name, List<Transform> acc)
{
if (root.name == name) acc.Add(root);
for (int i = 0; i < root.childCount; i++) FindAllDeep(root.GetChild(i), name, acc);
return acc;
}
/// <summary>프리팹 최상위 자식 목록 + 캔버스/스케일러 설정.</summary>
public static object DumpPrefab()
{
var go = Root();
if (go == null) return "prefab not found: " + PrefabPath;
var sb = new StringBuilder();
var canvas = go.GetComponent<Canvas>();
var scaler = go.GetComponent<CanvasScaler>();
sb.AppendLine("root=" + go.name + " comps={" + Comps(go) + "}");
if (canvas != null) sb.AppendLine("Canvas renderMode=" + canvas.renderMode + " sortOrder=" + canvas.sortingOrder);
if (scaler != null) sb.AppendLine("CanvasScaler mode=" + scaler.uiScaleMode + " ref=" + scaler.referenceResolution +
" match=" + scaler.matchWidthOrHeight + " screenMatch=" + scaler.screenMatchMode);
var rrt = go.transform as RectTransform;
sb.AppendLine("rootRect " + RtLine(rrt));
sb.AppendLine("== top-level children (" + go.transform.childCount + ") ==");
for (int i = 0; i < go.transform.childCount; i++)
{
var c = go.transform.GetChild(i);
sb.AppendLine(" [" + i + "] " + c.name + (c.gameObject.activeSelf ? "" : " [OFF]") + " " + RtLine(c as RectTransform) + " children=" + c.childCount);
}
// 이름 중복 확인
foreach (var n in new[] { "Chat", "WL_HUD", "BotMenu", "HUD", "Common", "IngameUIs" })
{
var all = FindAllDeep(go.transform, n, new List<Transform>());
sb.AppendLine("find '" + n + "' count=" + all.Count + " -> " + string.Join(" ; ", all.Select(t => Path(t, go.transform)).ToArray()));
}
return sb.ToString();
}
/// <summary>하단 메뉴 5버튼의 Image(배경) 스프라이트·색·알파 — 넓히면 늘어나는지 판단용.</summary>
public static object ButtonImages()
{
var go = Root();
if (go == null) return "prefab not found";
var menu = FindDeep(go.transform, "HUD_BottomMenu");
if (menu == null) return "HUD_BottomMenu not found";
var sb = new StringBuilder();
for (int i = 0; i < menu.childCount; i++)
{
var b = menu.GetChild(i);
var img = b.GetComponent<Image>();
sb.Append(b.name).Append(" : ");
if (img == null) sb.AppendLine("(no Image)");
else sb.AppendLine("sprite=" + (img.sprite != null ? img.sprite.name : "(null)") +
" color=" + img.color + " a=" + img.color.a.ToString("F3") +
" type=" + img.type + " raycast=" + img.raycastTarget +
" preserveAspect=" + img.preserveAspect);
// 아이콘도 함께
var icon = b.Find("Icon");
if (icon != null)
{
var ii = icon.GetComponent<Image>();
if (ii != null) sb.AppendLine(" Icon sprite=" + (ii.sprite != null ? ii.sprite.name : "(null)") + " a=" + ii.color.a.ToString("F2"));
}
}
return sb.ToString();
}
/// <summary>이름으로 찾은 노드의 서브트리를 덤프한다(기본 깊이 4).</summary>
public static object DumpNode(string name)
{
return DumpNodeDepth(name, 4);
}
public static object DumpNodeDepth(string name, int maxDepth)
{
var go = Root();
if (go == null) return "prefab not found";
var all = FindAllDeep(go.transform, name, new List<Transform>());
if (all.Count == 0) return "not found: " + name;
var sb = new StringBuilder();
foreach (var t in all)
{
sb.AppendLine("=== " + Path(t, go.transform) + " (parent=" + (t.parent != null ? t.parent.name : "-") + ") ===");
Walk(t, go.transform, sb, 0, maxDepth);
sb.AppendLine();
}
return sb.ToString();
}
/// <summary>경로로 찾은 노드의 서브트리를 덤프한다.</summary>
public static object DumpPath(string path, int maxDepth)
{
var go = Root();
if (go == null) return "prefab not found";
var t = go.transform.Find(path);
if (t == null) return "not found path: " + path;
var sb = new StringBuilder();
sb.AppendLine("=== " + path + " ===");
Walk(t, go.transform, sb, 0, maxDepth);
return sb.ToString();
}
// ── Play 중 실측 ──────────────────────────────────────────────────────────
static Rect ScreenRect(RectTransform rt, Canvas canvas)
{
var corners = new Vector3[4];
rt.GetWorldCorners(corners);
var cam = canvas != null && canvas.renderMode != RenderMode.ScreenSpaceOverlay ? canvas.worldCamera : null;
Vector2 min = new Vector2(float.MaxValue, float.MaxValue), max = new Vector2(float.MinValue, float.MinValue);
for (int i = 0; i < 4; i++)
{
Vector2 p = cam != null ? (Vector2)RectTransformUtility.WorldToScreenPoint(cam, corners[i]) : (Vector2)corners[i];
min = Vector2.Min(min, p); max = Vector2.Max(max, p);
}
return Rect.MinMaxRect(min.x, min.y, max.x, max.y);
}
/// <summary>Play 중: 하단 메뉴 버튼들과 Chat 의 화면 픽셀 사각형 · 활성 상태 · 알파.</summary>
public static object RuntimeRects()
{
if (!Application.isPlaying) return "not playing";
var sb = new StringBuilder();
sb.AppendLine("screen=" + Screen.width + "x" + Screen.height + " safeArea=" + Screen.safeArea.ToString("F0") + " dpi=" + Screen.dpi);
// 런타임 인스턴스 이름은 "NewGameUI(Clone)" 이 될 수 있으므로 컴포넌트 타입으로 찾는다.
var comp = GameObject.FindObjectsByType<NewGameUI>(FindObjectsInactive.Include, FindObjectsSortMode.None).FirstOrDefault();
GameObject uiRoot = comp != null ? comp.gameObject : GameObject.Find("NewGameUI");
if (uiRoot == null) return sb.AppendLine("NewGameUI not found").ToString();
sb.AppendLine("uiRoot=" + uiRoot.name);
var canvas = uiRoot.GetComponent<Canvas>();
var scaler = uiRoot.GetComponent<CanvasScaler>();
if (scaler != null) sb.AppendLine("scaler ref=" + scaler.referenceResolution + " match=" + scaler.matchWidthOrHeight + " scaleFactor=" + (canvas != null ? canvas.scaleFactor : 0f));
foreach (var nm in new[] { "WL_HUD", "Chat" })
{
var t = FindDeep(uiRoot.transform, nm);
if (t == null) { sb.AppendLine("[" + nm + "] not found"); continue; }
var cg = t.GetComponent<CanvasGroup>();
sb.AppendLine("[" + nm + "] activeSelf=" + t.gameObject.activeSelf + " activeInHierarchy=" + t.gameObject.activeInHierarchy +
(cg != null ? " CanvasGroup alpha=" + cg.alpha + " blocksRaycasts=" + cg.blocksRaycasts + " interactable=" + cg.interactable : " (no CanvasGroup)") +
" rect=" + (t is RectTransform ? ScreenRect(t as RectTransform, canvas).ToString("F0") : "-"));
for (int i = 0; i < t.childCount; i++)
{
var c = t.GetChild(i);
var crt = c as RectTransform;
sb.AppendLine(" - " + c.name + (c.gameObject.activeSelf ? "" : " [OFF]") + " rect=" + (crt != null ? ScreenRect(crt, canvas).ToString("F0") : "-"));
if (nm == "WL_HUD" && c.name.IndexOf("Menu", StringComparison.OrdinalIgnoreCase) >= 0)
{
for (int j = 0; j < c.childCount; j++)
{
var b = c.GetChild(j);
var brt = b as RectTransform;
var r = brt != null ? ScreenRect(brt, canvas) : new Rect();
sb.AppendLine(" * " + b.name + " x[" + r.xMin.ToString("F0") + ".." + r.xMax.ToString("F0") + "] y[" +
r.yMin.ToString("F0") + ".." + r.yMax.ToString("F0") + "] w=" + r.width.ToString("F0") + " h=" + r.height.ToString("F0") +
" scale=" + b.localScale.x.ToString("F2") + (b.gameObject.activeSelf ? "" : " [OFF]"));
}
}
}
}
return sb.ToString();
}
}