Project_WL/AgentScripts/WL793_Probe.cs

199 lines
11 KiB
C#
Raw Permalink 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
// WL793_Probe.cs — PD 지시 #793·#794·#795 타이틀 해상도 대응 실측 (에디트 모드 · 읽기 전용)
// unity command run_script --file AgentScripts/WL793_Probe.cs --entry WL793_Probe.Dump
// unity command run_script --file AgentScripts/WL793_Probe.cs --entry WL793_Probe.Textures
//
// 왜 스크립트인가: Title.unity 51KB YAML 을 눈으로 읽어 앵커·피벗·sizeDelta 를 계산하면 오독이 난다.
// CanvasScaler 의 실제 scaleFactor 는 런타임 계산식이라 YAML 만 봐서는 버튼의 "화면 픽셀 크기"가 안 나온다.
// → 공개 API 로 씬을 걸어 실측한다. 쓰기 없음(SetDirty/Save 호출 없음).
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEditor;
using UnityEngine;
using UnityEngine.UI;
public static class WL793_Probe
{
const string Out = "Screenshots_WL/title/probe_wl793.txt";
static string Rt(RectTransform r)
{
if (r == null) return "(RectTransform 없음)";
return string.Format(
"aMin({0:F2},{1:F2}) aMax({2:F2},{3:F2}) piv({4:F2},{5:F2}) anchPos({6:F1},{7:F1}) sizeDelta({8:F1},{9:F1}) rect({10:F1}x{11:F1}) scale({12:F2},{13:F2})",
r.anchorMin.x, r.anchorMin.y, r.anchorMax.x, r.anchorMax.y, r.pivot.x, r.pivot.y,
r.anchoredPosition.x, r.anchoredPosition.y, r.sizeDelta.x, r.sizeDelta.y,
r.rect.width, r.rect.height, r.localScale.x, r.localScale.y);
}
static void Walk(Transform t, int depth, StringBuilder sb)
{
var pad = new string(' ', depth * 2);
var rt = t as RectTransform;
var comps = t.GetComponents<Component>()
.Where(c => c != null && !(c is Transform))
.Select(c => c.GetType().Name).ToArray();
sb.AppendLine(string.Format("{0}{1} [{2}] active={3}", pad, t.name,
comps.Length == 0 ? "-" : string.Join(",", comps), t.gameObject.activeSelf));
if (rt != null) sb.AppendLine(pad + " " + Rt(rt));
var img = t.GetComponent<Image>();
if (img != null)
sb.AppendLine(string.Format("{0} Image sprite={1} type={2} preserveAspect={3} raycast={4} color={5}",
pad, img.sprite != null ? img.sprite.name : "(null)", img.type, img.preserveAspect,
img.raycastTarget, img.color));
var raw = t.GetComponent<RawImage>();
if (raw != null)
sb.AppendLine(string.Format("{0} RawImage tex={1} uvRect={2} raycast={3} color={4}",
pad, raw.texture != null ? raw.texture.name : "(null)", raw.uvRect, raw.raycastTarget, raw.color));
var btn = t.GetComponent<Button>();
if (btn != null)
{
int n = btn.onClick.GetPersistentEventCount();
var calls = new List<string>();
for (int i = 0; i < n; i++)
calls.Add((btn.onClick.GetPersistentTarget(i) != null ? btn.onClick.GetPersistentTarget(i).name : "?")
+ "." + btn.onClick.GetPersistentMethodName(i));
sb.AppendLine(string.Format("{0} Button interactable={1} onClick=[{2}]", pad, btn.interactable, string.Join(" ", calls)));
}
var txt = t.GetComponent<Text>();
if (txt != null)
sb.AppendLine(string.Format("{0} Text size={1} font={2} text=\"{3}\"", pad, txt.fontSize,
txt.font != null ? txt.font.name : "(null)",
(txt.text ?? "").Replace("\n", "\\n")));
var tmp = t.GetComponent("TMPro.TextMeshProUGUI");
if (tmp != null) sb.AppendLine(pad + " TMP present");
for (int i = 0; i < t.childCount; i++) Walk(t.GetChild(i), depth + 1, sb);
}
public static object Dump()
{
if (EditorApplication.isPlaying) return "ABORT: Play 중";
var sb = new StringBuilder();
var scene = UnityEngine.SceneManagement.SceneManager.GetActiveScene();
sb.AppendLine("=== 씬: " + scene.name + " (" + scene.path + ") isDirty=" + scene.isDirty + " ===");
sb.AppendLine("Screen(에디터 게임뷰) = " + Screen.width + "x" + Screen.height);
sb.AppendLine();
foreach (var cv in Object.FindObjectsByType<Canvas>(FindObjectsInactive.Include, FindObjectsSortMode.None))
{
var cs = cv.GetComponent<CanvasScaler>();
sb.AppendLine("[Canvas] " + cv.name + " renderMode=" + cv.renderMode
+ " scaleFactor=" + cv.scaleFactor.ToString("F4")
+ " sortOrder=" + cv.sortingOrder
+ " pixelRect=" + cv.pixelRect);
if (cs != null)
sb.AppendLine(" CanvasScaler mode=" + cs.uiScaleMode
+ " ref=" + cs.referenceResolution
+ " screenMatch=" + cs.screenMatchMode
+ " match=" + cs.matchWidthOrHeight.ToString("F2")
+ " refPPU=" + cs.referencePixelsPerUnit);
var crt = cv.GetComponent<RectTransform>();
if (crt != null) sb.AppendLine(" Canvas rect=" + crt.rect.width.ToString("F1") + "x" + crt.rect.height.ToString("F1"));
}
sb.AppendLine();
foreach (var cam in Object.FindObjectsByType<Camera>(FindObjectsInactive.Include, FindObjectsSortMode.None))
sb.AppendLine("[Camera] " + cam.name + " clearFlags=" + cam.clearFlags + " bg=" + cam.backgroundColor
+ " ortho=" + cam.orthographic + " depth=" + cam.depth);
sb.AppendLine();
sb.AppendLine("=== 하이라키 ===");
foreach (var go in scene.GetRootGameObjects()) Walk(go.transform, 0, sb);
System.IO.Directory.CreateDirectory(System.IO.Path.GetDirectoryName(Out));
System.IO.File.WriteAllText(Out, sb.ToString());
return "OK -> " + Out + " (" + sb.Length + " chars)";
}
// 런타임 로드되는 타이틀 UI 프리팹(TitleInfo 등) 실측
// unity command run_script --file AgentScripts/WL793_Probe.cs --entry WL793_Probe.Prefab --args '["Assets/ResWork/UIPrefabs/Title/TitleInfo.prefab"]'
public static object Prefab(string path)
{
if (EditorApplication.isPlaying) return "ABORT: Play 중";
var go = AssetDatabase.LoadAssetAtPath<GameObject>(path);
if (go == null) return "ABORT: 로드 실패 " + path;
var sb = new StringBuilder();
sb.AppendLine("=== 프리팹: " + path + " ===");
foreach (var cv in go.GetComponentsInChildren<Canvas>(true))
{
var cs = cv.GetComponent<CanvasScaler>();
sb.AppendLine("[Canvas] " + cv.name + " renderMode=" + cv.renderMode + " sortOrder=" + cv.sortingOrder);
if (cs != null)
sb.AppendLine(" CanvasScaler mode=" + cs.uiScaleMode + " ref=" + cs.referenceResolution
+ " screenMatch=" + cs.screenMatchMode + " match=" + cs.matchWidthOrHeight.ToString("F2"));
}
sb.AppendLine();
Walk(go.transform, 0, sb);
var outp = "Screenshots_WL/title/probe_" + System.IO.Path.GetFileNameWithoutExtension(path) + ".txt";
System.IO.Directory.CreateDirectory("Screenshots_WL/title");
System.IO.File.WriteAllText(outp, sb.ToString());
return "OK -> " + outp + " (" + sb.Length + " chars)";
}
// 타이틀 씬이 참조하는 모든 텍스처의 임포트 설정 실측
public static object Textures()
{
if (EditorApplication.isPlaying) return "ABORT: Play 중";
var sb = new StringBuilder();
var seen = new HashSet<string>();
var scene = UnityEngine.SceneManagement.SceneManager.GetActiveScene();
var texs = new List<Texture>();
foreach (var go in scene.GetRootGameObjects())
{
foreach (var g in go.GetComponentsInChildren<Graphic>(true))
{
var im = g as Image;
if (im != null && im.sprite != null && im.sprite.texture != null) texs.Add(im.sprite.texture);
var rw = g as RawImage;
if (rw != null && rw.texture != null) texs.Add(rw.texture);
}
}
foreach (var t in texs)
{
var path = AssetDatabase.GetAssetPath(t);
if (string.IsNullOrEmpty(path) || !seen.Add(path)) continue;
var ti = AssetImporter.GetAtPath(path) as TextureImporter;
sb.AppendLine("--- " + path);
sb.AppendLine(" 로드된 텍스처 = " + t.width + "x" + t.height + " format=" + (t is Texture2D ? ((Texture2D)t).format.ToString() : "?")
+ " mip=" + t.mipmapCount + " filter=" + t.filterMode);
if (ti == null) { sb.AppendLine(" (TextureImporter 없음)"); continue; }
int ow = 0, oh = 0;
ti.GetSourceTextureWidthAndHeight(out ow, out oh);
sb.AppendLine(" 원본 소스 = " + ow + "x" + oh);
sb.AppendLine(" type=" + ti.textureType + " shape=" + ti.textureShape + " npot=" + ti.npotScale
+ " mipmap=" + ti.mipmapEnabled + " filter=" + ti.filterMode + " wrap=" + ti.wrapMode
+ " aniso=" + ti.anisoLevel + " sRGB=" + ti.sRGBTexture + " alphaIsTransparency=" + ti.alphaIsTransparency
+ " readable=" + ti.isReadable + " compressionQuality=" + ti.compressionQuality);
var def = ti.GetDefaultPlatformTextureSettings();
sb.AppendLine(" [Default] maxSize=" + def.maxTextureSize + " format=" + def.format + " compression=" + def.textureCompression
+ " crunched=" + def.crunchedCompression);
foreach (var plat in new[] { "Android", "iPhone" })
{
var ps = ti.GetPlatformTextureSettings(plat);
sb.AppendLine(" [" + plat + "] override=" + ps.overridden + " maxSize=" + ps.maxTextureSize + " format=" + ps.format
+ " compression=" + ps.textureCompression + " quality=" + ps.compressionQuality
+ " crunched=" + ps.crunchedCompression);
}
if (ti.textureType == TextureImporterType.Sprite)
sb.AppendLine(" [Sprite] mode=" + ti.spriteImportMode + " ppu=" + ti.spritePixelsPerUnit
+ " border=" + ti.spriteBorder);
var fi = new System.IO.FileInfo(path);
if (fi.Exists) sb.AppendLine(" 파일 크기 = " + (fi.Length / 1024) + " KB");
}
System.IO.Directory.CreateDirectory("Screenshots_WL/title");
System.IO.File.WriteAllText("Screenshots_WL/title/probe_wl793_tex.txt", sb.ToString());
return "OK -> Screenshots_WL/title/probe_wl793_tex.txt (" + sb.Length + " chars)";
}
}