637 lines
36 KiB
C#
637 lines
36 KiB
C#
|
|
// WL-813y 프로브 — UI 핫픽스 묶음 실측(에디트 모드 · Play 0).
|
|||
|
|
// run_script --file AgentScripts/WL813y_Probe.cs --entry WL813y_Probe.<Entry>
|
|||
|
|
// Nodes · Bridge · Stat · Text · BossLate · Hud
|
|||
|
|
// 로그는 <worktree>/Logs/WL813y_*.txt (Assets 밖 · 미추적).
|
|||
|
|
// 🔴 프리팹은 LoadPrefabContents 로 열고 **저장하지 않는다**. 구독·임시 노드는 전부 되돌린다.
|
|||
|
|
|
|||
|
|
using System;
|
|||
|
|
using System.Collections.Generic;
|
|||
|
|
using System.IO;
|
|||
|
|
using System.Reflection;
|
|||
|
|
using System.Text;
|
|||
|
|
using UnityEngine;
|
|||
|
|
using UnityEngine.UI;
|
|||
|
|
using TMPro;
|
|||
|
|
using UnityEditor;
|
|||
|
|
using WL.UI;
|
|||
|
|
|
|||
|
|
public static class WL813y_Probe
|
|||
|
|
{
|
|||
|
|
const string kPrefab = "Assets/Res_Addr/MainUI/NewGameUI.prefab";
|
|||
|
|
const string kHud = "IngameUIs/WL_HUD";
|
|||
|
|
const string kPad = "IngameUIs/BattleUI";
|
|||
|
|
const BindingFlags NP = BindingFlags.Instance | BindingFlags.NonPublic;
|
|||
|
|
|
|||
|
|
static string LogDir
|
|||
|
|
{
|
|||
|
|
get
|
|||
|
|
{
|
|||
|
|
string d = Path.Combine(Directory.GetParent(Application.dataPath).FullName, "Logs");
|
|||
|
|
if (!Directory.Exists(d)) Directory.CreateDirectory(d);
|
|||
|
|
return d;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
static string Write(string name, string body)
|
|||
|
|
{
|
|||
|
|
string p = Path.Combine(LogDir, name);
|
|||
|
|
File.WriteAllText(p, body, new UTF8Encoding(false));
|
|||
|
|
return p;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
static Transform Find(Transform root, string path)
|
|||
|
|
{
|
|||
|
|
var cur = root;
|
|||
|
|
foreach (var part in path.Split('/'))
|
|||
|
|
{
|
|||
|
|
Transform next = null;
|
|||
|
|
for (int i = 0; i < cur.childCount; i++)
|
|||
|
|
if (cur.GetChild(i).name == part) { next = cur.GetChild(i); break; }
|
|||
|
|
if (next == null) return null;
|
|||
|
|
cur = next;
|
|||
|
|
}
|
|||
|
|
return cur;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
static string PathOf(Transform t, Transform root)
|
|||
|
|
{
|
|||
|
|
var sb = new StringBuilder(t.name);
|
|||
|
|
var c = t.parent;
|
|||
|
|
while (c != null && c != root) { sb.Insert(0, c.name + "/"); c = c.parent; }
|
|||
|
|
return sb.ToString();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ── ① 프리팹 노드 탐색 — HUD_BottomMenu 경로 · WL_HUD 자식 · 패드 좌표 ──────
|
|||
|
|
public static string Nodes()
|
|||
|
|
{
|
|||
|
|
var sb = new StringBuilder();
|
|||
|
|
var root = PrefabUtility.LoadPrefabContents(kPrefab);
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
var rt = root.transform;
|
|||
|
|
sb.AppendLine("[1] 루트 자식 " + rt.childCount + "개");
|
|||
|
|
foreach (Transform c in rt) sb.AppendLine(" - " + c.name + " active=" + c.gameObject.activeSelf);
|
|||
|
|
|
|||
|
|
sb.AppendLine();
|
|||
|
|
sb.AppendLine("[2] 이름에 'Bottom' / 'Menu' 가 든 노드 (전수 탐색)");
|
|||
|
|
var all = root.GetComponentsInChildren<Transform>(true);
|
|||
|
|
sb.AppendLine(" 총 Transform = " + all.Length);
|
|||
|
|
foreach (var t in all)
|
|||
|
|
{
|
|||
|
|
if (t.name.IndexOf("Bottom", StringComparison.OrdinalIgnoreCase) < 0 &&
|
|||
|
|
t.name.IndexOf("Menu", StringComparison.OrdinalIgnoreCase) < 0) continue;
|
|||
|
|
var r = t as RectTransform;
|
|||
|
|
sb.AppendLine(" - " + PathOf(t, rt) + " active=" + t.gameObject.activeSelf +
|
|||
|
|
" children=" + t.childCount +
|
|||
|
|
(r != null ? " pos" + r.anchoredPosition + " size" + r.sizeDelta +
|
|||
|
|
" aMin" + r.anchorMin + " aMax" + r.anchorMax + " pivot" + r.pivot : ""));
|
|||
|
|
foreach (Transform cc in t) sb.AppendLine(" · " + cc.name + " active=" + cc.gameObject.activeSelf);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
sb.AppendLine();
|
|||
|
|
sb.AppendLine("[3] IngameUIs 아래 1단계");
|
|||
|
|
var ing = WLVignetteUtil.FindUiPath(rt, "IngameUIs");
|
|||
|
|
if (ing == null) sb.AppendLine(" IngameUIs 없음");
|
|||
|
|
else foreach (Transform c in ing) sb.AppendLine(" - " + c.name + " active=" + c.gameObject.activeSelf + " children=" + c.childCount);
|
|||
|
|
|
|||
|
|
sb.AppendLine();
|
|||
|
|
sb.AppendLine("[4] WL_HUD 자식");
|
|||
|
|
var hud = WLVignetteUtil.FindUiPath(rt, kHud);
|
|||
|
|
if (hud == null) sb.AppendLine(" WL_HUD 없음");
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
sb.AppendLine(" WL_HUD SafeAreaFitter=" + (hud.GetComponent<SafeAreaFitter>() != null));
|
|||
|
|
foreach (Transform c in hud)
|
|||
|
|
{
|
|||
|
|
var comps = c.GetComponents<Component>();
|
|||
|
|
var names = new List<string>();
|
|||
|
|
foreach (var cp in comps) names.Add(cp == null ? "(missing)" : cp.GetType().Name);
|
|||
|
|
sb.AppendLine(" - " + c.name + " [" + string.Join(", ", names.ToArray()) + "] children=" + c.childCount);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
sb.AppendLine();
|
|||
|
|
sb.AppendLine("[5] BattleUI 자식");
|
|||
|
|
var bui = WLVignetteUtil.FindUiPath(rt, kPad);
|
|||
|
|
if (bui == null) sb.AppendLine(" BattleUI 없음");
|
|||
|
|
else foreach (Transform c in bui)
|
|||
|
|
{
|
|||
|
|
var r = c as RectTransform;
|
|||
|
|
sb.AppendLine(" - " + c.name + " active=" + c.gameObject.activeSelf +
|
|||
|
|
(r != null ? " pos" + r.anchoredPosition + " size" + r.sizeDelta + " aMin" + r.anchorMin : ""));
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
finally { PrefabUtility.UnloadPrefabContents(root); }
|
|||
|
|
|
|||
|
|
string p = Write("WL813y_nodes.txt", sb.ToString());
|
|||
|
|
return sb.ToString() + "\n→ " + p;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ═══ ⓑ ① 813i 연결 6줄 (발주서 §1-1) ═══════════════════════════════════
|
|||
|
|
public static string Bridge()
|
|||
|
|
{
|
|||
|
|
var sb = new StringBuilder();
|
|||
|
|
var root = PrefabUtility.LoadPrefabContents(kPrefab);
|
|||
|
|
int ov0 = WL.Combat.Survival.WLSurvivalSettings.RuntimeOverride;
|
|||
|
|
float ts0 = Time.timeScale;
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
var hud = Find(root.transform, kHud);
|
|||
|
|
var pad = Find(root.transform, kPad);
|
|||
|
|
var dlgT = hud != null ? hud.Find("WL_ReviveDialog") : null;
|
|||
|
|
var dlg = dlgT != null ? dlgT.GetComponent<ReviveDialog>() : null;
|
|||
|
|
var potion = pad != null ? pad.GetComponentInChildren<PotionButton>(true) : null;
|
|||
|
|
if (dlg == null) return "🔴 WL_ReviveDialog 없음";
|
|||
|
|
if (potion == null) return "🔴 WL_PotionButton 없음";
|
|||
|
|
dlg.Initialize();
|
|||
|
|
potion.Initialize();
|
|||
|
|
|
|||
|
|
sb.AppendLine("[0] 연결 전 (813tj 상태)");
|
|||
|
|
WLSurvivalUiBridge.Uninstall();
|
|||
|
|
WLSurvivalUiBridge.ResetDiagnostics();
|
|||
|
|
sb.AppendLine(" " + WLSurvivalUiBridge.Dump().TrimEnd());
|
|||
|
|
|
|||
|
|
sb.AppendLine();
|
|||
|
|
sb.AppendLine("[1] Install() — 6줄 연결");
|
|||
|
|
sb.AppendLine(" " + WLSurvivalUiBridge.Install());
|
|||
|
|
sb.Append(WLSurvivalUiBridge.Dump());
|
|||
|
|
|
|||
|
|
sb.AppendLine();
|
|||
|
|
sb.AppendLine("[2] 물약 4줄 — 스위치 off(에셋 enabled=false · 병합 전) → 813tj 표시용 폴백");
|
|||
|
|
WL.Combat.Survival.WLSurvivalSettings.RuntimeOverride = -1;
|
|||
|
|
sb.AppendLine(" survivalEnabled=" + WL.Combat.Survival.WLSurvivalSettings.Enabled +
|
|||
|
|
" · UI 가 읽는 count=" + PotionButton.CountProvider() +
|
|||
|
|
" cdRemain=" + PotionButton.CooldownRemainProvider().ToString("F2") +
|
|||
|
|
" cdTotal=" + PotionButton.CooldownTotalProvider().ToString("F2") +
|
|||
|
|
" · 버튼 ReadCount=" + potion.ReadCount() + " fill=" + potion.ReadCooldownFill().ToString("F3"));
|
|||
|
|
sb.AppendLine(" 클릭 → " + potion.OnClickPotion());
|
|||
|
|
|
|||
|
|
sb.AppendLine();
|
|||
|
|
sb.AppendLine("[3] 물약 4줄 — 스위치 on(RuntimeOverride=1 · Lead 가 병합 시 켜는 상태) → 813i PotionUse");
|
|||
|
|
WL.Combat.Survival.WLSurvivalSettings.RuntimeOverride = 1;
|
|||
|
|
WL.Combat.Survival.PotionUse.ResetRun("probe");
|
|||
|
|
WL.Combat.Survival.PotionUse.ResetDiagnostics();
|
|||
|
|
sb.AppendLine(" survivalEnabled=" + WL.Combat.Survival.WLSurvivalSettings.Enabled +
|
|||
|
|
" · 813i Remaining=" + WL.Combat.Survival.PotionUse.Remaining + "/" + WL.Combat.Survival.PotionUse.Max +
|
|||
|
|
" cdTotal=" + WL.Combat.Survival.PotionUse.CooldownTotal.ToString("F2") + "s");
|
|||
|
|
sb.AppendLine(" UI 가 읽는 count=" + PotionButton.CountProvider() +
|
|||
|
|
" cdRemain=" + PotionButton.CooldownRemainProvider().ToString("F2") +
|
|||
|
|
" cdTotal=" + PotionButton.CooldownTotalProvider().ToString("F2") +
|
|||
|
|
" ← ① ② ③ 이 813i 값을 그대로 읽는다");
|
|||
|
|
int chg0 = WLSurvivalUiBridge.PotionChangedSeen;
|
|||
|
|
sb.AppendLine(" ④ UseHandler() → " + PotionButton.UseHandler() +
|
|||
|
|
" (PC 없는 에디트 모드라 813i 가 " + WL.Combat.Survival.PotionUse.LastResult +
|
|||
|
|
" 로 거절 · 호출은 도달) · Changed 수신 " + chg0 + "→" + WLSurvivalUiBridge.PotionChangedSeen);
|
|||
|
|
sb.AppendLine(" 버튼 클릭 경로 → " + potion.OnClickPotion());
|
|||
|
|
|
|||
|
|
sb.AppendLine();
|
|||
|
|
sb.AppendLine("[4] 부활 2줄 — 813i DeathFlow 왕복(가짜 메인 PC · ReviveOverride 로 원본 회복 경로 차단)");
|
|||
|
|
var deathFlowOverride = WL.Combat.Survival.DeathFlow.ReviveOverride;
|
|||
|
|
int overrideCalls = 0;
|
|||
|
|
WL.Combat.Survival.DeathFlow.ReviveOverride = (p, r) => { overrideCalls++; };
|
|||
|
|
var pc = MakePC();
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
WL.Combat.Survival.DeathFlow.ResetDiagnostics();
|
|||
|
|
WLSurvivalUiBridge.ResetDiagnostics();
|
|||
|
|
dlg.HideNow();
|
|||
|
|
float t = 100f;
|
|||
|
|
WL.Combat.Survival.DeathFlow.Tick(t);
|
|||
|
|
sb.AppendLine(" ⑤ OnPCDied → " + "state=" + WL.Combat.Survival.DeathFlow.State);
|
|||
|
|
WL.Combat.Survival.DeathFlow.OnPCDied(pc);
|
|||
|
|
sb.AppendLine(" Died 수신=" + WLSurvivalUiBridge.DiedSeen + " state=" + WL.Combat.Survival.DeathFlow.State +
|
|||
|
|
" · 팝업 표시=" + dlg.FallbackVisible + "(사망 연출 대기 · 예약=" + dlg.Pending + ")");
|
|||
|
|
var st = WL.Combat.Survival.WLSurvivalSettings.Instance;
|
|||
|
|
float disp = st != null ? st.deathDisplaySeconds : 2f;
|
|||
|
|
WL.Combat.Survival.DeathFlow.Tick(t + disp + 0.01f);
|
|||
|
|
sb.AppendLine(" +" + disp.ToString("F2") + "s → ReviveRequested 수신=" + WLSurvivalUiBridge.ReviveRequestedSeen +
|
|||
|
|
" state=" + WL.Combat.Survival.DeathFlow.State +
|
|||
|
|
" · 팝업 표시=" + dlg.FallbackVisible + " shows=" + dlg.ShownCount +
|
|||
|
|
" 본문=\"" + dlg.LastMessage.Replace("\n", " / ") + "\"");
|
|||
|
|
sb.AppendLine(" autoReviveWhenNoListener 무력화 = ReviveRequested 구독자 " +
|
|||
|
|
WL.Combat.Survival.DeathFlow.ReviveRequested.Count + "(0 이면 813i 가 자동 부활한다)");
|
|||
|
|
sb.AppendLine(" ⑥ 팝업 확인 버튼 → " + dlg.OnConfirm());
|
|||
|
|
sb.AppendLine(" DeathFlow.Revive() 호출=" + WLSurvivalUiBridge.ReviveCalls +
|
|||
|
|
" state=" + WL.Combat.Survival.DeathFlow.State +
|
|||
|
|
" reviveCount=" + WL.Combat.Survival.DeathFlow.ReviveCount +
|
|||
|
|
" (ReviveOverride 호출 " + overrideCalls + ")");
|
|||
|
|
sb.AppendLine(" Revived 수신=" + WLSurvivalUiBridge.RevivedSeen + " → 팝업 닫힘=" + !dlg.FallbackVisible);
|
|||
|
|
sb.AppendLine(" 최종 " + WLSurvivalUiBridge.Dump().Split('\n')[0].Trim());
|
|||
|
|
}
|
|||
|
|
finally
|
|||
|
|
{
|
|||
|
|
WL.Combat.Survival.DeathFlow.ReviveOverride = deathFlowOverride;
|
|||
|
|
if (pc != null) UnityEngine.Object.DestroyImmediate(pc.gameObject);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
finally
|
|||
|
|
{
|
|||
|
|
WLSurvivalUiBridge.Uninstall();
|
|||
|
|
WL.Combat.Survival.WLSurvivalSettings.RuntimeOverride = ov0;
|
|||
|
|
WL.Combat.Survival.DeathFlow.ResetDiagnostics();
|
|||
|
|
Time.timeScale = ts0;
|
|||
|
|
KillRunners();
|
|||
|
|
PrefabUtility.UnloadPrefabContents(root);
|
|||
|
|
}
|
|||
|
|
sb.AppendLine();
|
|||
|
|
sb.AppendLine("정리: 브리지 해제=" + !WLSurvivalUiBridge.Installed +
|
|||
|
|
" · DeathFlow 구독(Died/Req/Revived)=" + WL.Combat.Survival.DeathFlow.Died.Count + "/" +
|
|||
|
|
WL.Combat.Survival.DeathFlow.ReviveRequested.Count + "/" + WL.Combat.Survival.DeathFlow.Revived.Count +
|
|||
|
|
" · PotionButton.HasProvider=" + PotionButton.HasProvider +
|
|||
|
|
" · timeScale=" + Time.timeScale + " · SurvivalRunner=" + WL.Combat.Survival.SurvivalRunner.Exists);
|
|||
|
|
var body = sb.ToString();
|
|||
|
|
return body + "\n→ " + Write("WL813y_bridge.txt", body);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
static PCActor MakePC()
|
|||
|
|
{
|
|||
|
|
var go = new GameObject("__WL813y_PC");
|
|||
|
|
var pc = go.AddComponent<PCActor>();
|
|||
|
|
pc.m_Role = eRole.PC; pc.m_SubRole = eSubRol.None;
|
|||
|
|
var stat = new ActorStatInfo(eRole.PC);
|
|||
|
|
stat.Set_Stat(eStat.MaxHP, 1000d); stat.Set_Stat(eStat.HP, 0d);
|
|||
|
|
typeof(Actor).GetField("m_Stat", NP).SetValue(pc, stat);
|
|||
|
|
typeof(Actor).GetField("m_Enemy", NP).SetValue(pc, false);
|
|||
|
|
typeof(Actor).GetField("DeadStatus", NP).SetValue(pc, true);
|
|||
|
|
return pc;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
static void KillRunners()
|
|||
|
|
{
|
|||
|
|
var all = UnityEngine.Object.FindObjectsByType<MonoBehaviour>(FindObjectsInactive.Include, FindObjectsSortMode.None);
|
|||
|
|
foreach (var m in all)
|
|||
|
|
{
|
|||
|
|
if (m == null) continue;
|
|||
|
|
string n = m.GetType().Name;
|
|||
|
|
if (n == "SurvivalRunner" || n == "HudCombatVisibilityRunner")
|
|||
|
|
UnityEngine.Object.DestroyImmediate(m.gameObject);
|
|||
|
|
}
|
|||
|
|
var leftovers = UnityEngine.Object.FindObjectsByType<Actor>(FindObjectsInactive.Include, FindObjectsSortMode.None);
|
|||
|
|
foreach (var a in leftovers)
|
|||
|
|
if (a != null && a.name.StartsWith("__WL813y_")) UnityEngine.Object.DestroyImmediate(a.gameObject);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ═══ ⓑ ② 스탯 팝업 3줄 (발주서 §1-2) ═══════════════════════════════════
|
|||
|
|
public static string Stat()
|
|||
|
|
{
|
|||
|
|
var sb = new StringBuilder();
|
|||
|
|
var root = PrefabUtility.LoadPrefabContents(kPrefab);
|
|||
|
|
StatPopup sp = null;
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
var hud = Find(root.transform, kHud);
|
|||
|
|
var node = hud != null ? hud.Find("WL_StatPopup") : null;
|
|||
|
|
sp = node != null ? node.GetComponent<StatPopup>() : null;
|
|||
|
|
if (sp == null) return "🔴 WL_StatPopup 없음";
|
|||
|
|
var s = WLCombatTextSettings.Instance;
|
|||
|
|
if (s == null) return "🔴 WLCombatTextSettings 에셋 없음";
|
|||
|
|
|
|||
|
|
sb.AppendLine("[0] 구독 축 선택 (statPopupUseGrowthEvents=" + s.statPopupUseGrowthEvents + ")");
|
|||
|
|
sb.AppendLine(" 구독 전 growth=" + WL.Combat.Growth.GrowthEvents.LevelUp.Count +
|
|||
|
|
" core=" + WL.Combat.Core.CombatEvents.LevelUp.Count);
|
|||
|
|
sb.AppendLine(" " + sp.Initialize());
|
|||
|
|
sb.AppendLine(" 구독 후 growth=" + WL.Combat.Growth.GrowthEvents.LevelUp.Count +
|
|||
|
|
" core=" + WL.Combat.Core.CombatEvents.LevelUp.Count +
|
|||
|
|
" · UsingGrowthEvents=" + sp.UsingGrowthEvents +
|
|||
|
|
" ← 813k 축 하나만 문다(이중 팝업 방지)");
|
|||
|
|
|
|||
|
|
sb.AppendLine();
|
|||
|
|
sb.AppendLine("[1] 813k 실제 Dispatch — 스탯이 오른 경우(statDelta=+12) → 3줄");
|
|||
|
|
sb.AppendLine(" " + StatPopup.RaiseFakeGrowthLevelUp(7, 30, 12d));
|
|||
|
|
sb.AppendLine(" rows=" + sp.LastRowCount + " 포인트줄=" + sp.UsedPointLine +
|
|||
|
|
" visible=" + sp.Visible + " level=" + sp.LastLevel);
|
|||
|
|
sb.AppendLine(" text = " + sp.LastText);
|
|||
|
|
|
|||
|
|
sb.AppendLine();
|
|||
|
|
sb.AppendLine("[2] 813k 실제 Dispatch — 스탯 변화 0(원본 기본값 · 813k 보고 ①) → \"포인트\" 줄");
|
|||
|
|
sb.AppendLine(" " + StatPopup.RaiseFakeGrowthLevelUp(8, 35, 0d));
|
|||
|
|
sb.AppendLine(" rows=" + sp.LastRowCount + " 포인트줄=" + sp.UsedPointLine +
|
|||
|
|
" statPointTotal=" + sp.LastStatPointTotal + " levelsGained=" + sp.LastLevelsGained);
|
|||
|
|
sb.AppendLine(" text = " + sp.LastText);
|
|||
|
|
sb.AppendLine(" 포맷 = \"" + s.statPopupPointFormat + "\" (SO · C8)");
|
|||
|
|
|
|||
|
|
sb.AppendLine();
|
|||
|
|
sb.AppendLine("[3] 811b 코어 축은 이제 안 문다 — CombatEvents.LevelUp 을 쏴도 무반응(이중 팝업 0)");
|
|||
|
|
int before = sp.LevelUpSeen;
|
|||
|
|
sb.AppendLine(" " + StatPopup.RaiseFakeLevelUp(9));
|
|||
|
|
sb.AppendLine(" levelUpSeen " + before + "→" + sp.LevelUpSeen + " lastLevel=" + sp.LastLevel + "(8 이어야 한다)");
|
|||
|
|
|
|||
|
|
sb.AppendLine();
|
|||
|
|
sb.AppendLine("[4] 최종 덤프");
|
|||
|
|
sb.Append(sp.Dump());
|
|||
|
|
}
|
|||
|
|
finally
|
|||
|
|
{
|
|||
|
|
if (sp != null) sp.Subscribe(false);
|
|||
|
|
PrefabUtility.UnloadPrefabContents(root);
|
|||
|
|
}
|
|||
|
|
sb.AppendLine();
|
|||
|
|
sb.AppendLine("해제 후 구독자 growth=" + WL.Combat.Growth.GrowthEvents.LevelUp.Count +
|
|||
|
|
" core=" + WL.Combat.Core.CombatEvents.LevelUp.Count + " (0/0 이어야 한다)");
|
|||
|
|
var body = sb.ToString();
|
|||
|
|
return body + "\n→ " + Write("WL813y_stat.txt", body);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ═══ ⓑ ③④ 토스트 가시성 · 텍스트 아웃라인 (발주서 §1-3 · §1-4) ═════════
|
|||
|
|
public static string Text()
|
|||
|
|
{
|
|||
|
|
var sb = new StringBuilder();
|
|||
|
|
var root = PrefabUtility.LoadPrefabContents(kPrefab);
|
|||
|
|
LootToast lt = null; KillChainText kc = null; StatPopup sp = null;
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
var hud = Find(root.transform, kHud);
|
|||
|
|
var s = WLCombatTextSettings.Instance;
|
|||
|
|
if (s == null) return "🔴 WLCombatTextSettings 에셋 없음";
|
|||
|
|
lt = hud.Find("WL_LootToast").GetComponent<LootToast>();
|
|||
|
|
kc = hud.Find("WL_KillChainText").GetComponent<KillChainText>();
|
|||
|
|
sp = hud.Find("WL_StatPopup").GetComponent<StatPopup>();
|
|||
|
|
|
|||
|
|
float u = WLVignetteUtil.UnitsPerPx(hud.GetComponentInParent<Canvas>());
|
|||
|
|
sb.AppendLine("[0] 기준 — 설계 " + s.designWidthPx + "×" + WLHudLayoutSettings.Instance.designHeightPx +
|
|||
|
|
" · unitsPerPx=" + u.ToString("F4") + " · textEdgeEnabled=" + s.textEdgeEnabled);
|
|||
|
|
|
|||
|
|
sb.AppendLine();
|
|||
|
|
sb.AppendLine("[1] 토스트 배치 (Q3 결함 D-6 ② · 15회 발생 · 육안 실패)");
|
|||
|
|
sb.AppendLine(" 지속 " + s.lootToastSeconds + "s (발주서 1.2 → 2.0) · 글자 " + s.lootToastFontPx +
|
|||
|
|
"px · 줄높이 " + s.lootToastLineHeightPx + "px · 폭 " + s.lootToastWidthPx +
|
|||
|
|
"px · 우측여백 " + s.lootToastRightMarginPx + "px · 중심오프셋 " + s.lootToastCenterOffsetPx + "px");
|
|||
|
|
sb.AppendLine(" " + lt.Initialize());
|
|||
|
|
sb.AppendLine(" " + lt.ApplyLayout());
|
|||
|
|
var ltRt = lt.GetComponent<RectTransform>();
|
|||
|
|
sb.AppendLine(" 루트 pos" + ltRt.anchoredPosition + " size" + ltRt.sizeDelta +
|
|||
|
|
" aMin" + ltRt.anchorMin + " aMax" + ltRt.anchorMax +
|
|||
|
|
" · SafeArea 안(부모 WL_HUD SafeAreaFitter=" +
|
|||
|
|
(hud.GetComponent<SafeAreaFitter>() != null) + ")");
|
|||
|
|
sb.AppendLine(" 등급 색 보정: 등급1 " + s.GradeColorTag(1) + " → " + s.GradeColorTagBright(1) +
|
|||
|
|
" · 등급2 " + s.GradeColorTag(2) + " → " + s.GradeColorTagBright(2) +
|
|||
|
|
" (밝기하한 " + s.lootToastMinBrightness + ")");
|
|||
|
|
sb.AppendLine(" " + lt.Push(1, 3));
|
|||
|
|
sb.AppendLine(" " + lt.Push(2, 1));
|
|||
|
|
sb.Append(lt.Dump());
|
|||
|
|
|
|||
|
|
sb.AppendLine();
|
|||
|
|
sb.AppendLine("[2] 아웃라인 · 그림자 — TMP 머티리얼 실측값(uGUI Outline/Shadow 는 TMP 에 안 먹는다)");
|
|||
|
|
sb.AppendLine(" [연쇄] 값 " + s.Edge(s.killChainEdge));
|
|||
|
|
sb.AppendLine(" " + kc.Initialize());
|
|||
|
|
sb.AppendLine(" 실측 " + kc.LastEdge);
|
|||
|
|
sb.AppendLine(" [스탯] 값 " + s.Edge(s.statPopupEdge));
|
|||
|
|
sb.AppendLine(" " + sp.Initialize());
|
|||
|
|
sb.AppendLine(" 실측 " + sp.LastEdge);
|
|||
|
|
sb.AppendLine(" [토스트] 값 " + s.Edge(s.lootToastEdge));
|
|||
|
|
sb.AppendLine(" 실측 " + lt.LastEdge);
|
|||
|
|
sb.AppendLine(" [데미지] 값 " + s.Edge(s.damageEdge));
|
|||
|
|
sb.AppendLine(" 풀 인스턴스 없음: " + HUDDMGUI.RefreshEdges());
|
|||
|
|
// 데미지 숫자는 InGameInfo.cs:110 이 Addressables 로 Res_Addr/Ingame/HUDDMGUI.prefab 을 12개 복제한다
|
|||
|
|
// (Systems 소유 · **읽기만** — 프로브에서 1개만 인스턴스화해 머티리얼 경로를 확인하고 즉시 파기한다).
|
|||
|
|
var dmgSrc = AssetDatabase.LoadAssetAtPath<GameObject>("Assets/Res_Addr/Ingame/HUDDMGUI.prefab");
|
|||
|
|
if (dmgSrc == null) sb.AppendLine(" 🔴 HUDDMGUI.prefab 없음");
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
var inst = (GameObject)PrefabUtility.InstantiatePrefab(dmgSrc);
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
var d = inst.GetComponent<HUDDMGUI>();
|
|||
|
|
sb.AppendLine(" prefab 인스턴스 1개(dmgs=" + (d != null && d.dmgs != null ? d.dmgs.Length : 0) + "라벨) → " + HUDDMGUI.RefreshEdges());
|
|||
|
|
if (d != null && d.dmgs != null)
|
|||
|
|
for (int i = 0; i < d.dmgs.Length; i++)
|
|||
|
|
if (d.dmgs[i] != null)
|
|||
|
|
sb.AppendLine(" dmgs[" + i + "] mat=" + d.dmgs[i].fontSharedMaterial.name +
|
|||
|
|
" outlineW=" + d.dmgs[i].fontSharedMaterial.GetFloat("_OutlineWidth").ToString("F3") +
|
|||
|
|
" UNDERLAY_ON=" + d.dmgs[i].fontSharedMaterial.IsKeywordEnabled("UNDERLAY_ON"));
|
|||
|
|
}
|
|||
|
|
finally { UnityEngine.Object.DestroyImmediate(inst); }
|
|||
|
|
sb.AppendLine(" 🔴 HUDDMGUI.prefab 은 **읽기 전용** — 인스턴스만 만들고 파기(에셋 저장 0 · Systems 소유)");
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
sb.AppendLine();
|
|||
|
|
sb.AppendLine("[3] 배칭 — 변형 머티리얼은 (원본 머티리얼 + 값) 조합마다 1장 공유(라벨별 인스턴스 0)");
|
|||
|
|
var mats = new Dictionary<int, int>();
|
|||
|
|
var matName = new Dictionary<int, string>();
|
|||
|
|
foreach (var t in root.GetComponentsInChildren<TMP_Text>(true))
|
|||
|
|
{
|
|||
|
|
var m = t.fontSharedMaterial;
|
|||
|
|
if (m == null || m.name.IndexOf("WL813y") < 0) continue;
|
|||
|
|
int id = m.GetInstanceID();
|
|||
|
|
int n; mats.TryGetValue(id, out n); mats[id] = n + 1;
|
|||
|
|
matName[id] = m.name + " outlineW=" + m.GetFloat("_OutlineWidth").ToString("F3") +
|
|||
|
|
" underlayOff(" + m.GetFloat("_UnderlayOffsetX").ToString("F2") + ")";
|
|||
|
|
}
|
|||
|
|
if (mats.Count == 0) sb.AppendLine(" 변형 머티리얼 0 (edge off)");
|
|||
|
|
sb.AppendLine(" 서로 다른 머티리얼 " + mats.Count + "장 (값 조합 3종 = 연쇄 0.30 / 스탯 0.26 / 토스트 0.24)");
|
|||
|
|
foreach (var kv in mats) sb.AppendLine(" · " + matName[kv.Key] + " ← 라벨 " + kv.Value + "개 공유");
|
|||
|
|
}
|
|||
|
|
finally
|
|||
|
|
{
|
|||
|
|
if (lt != null) lt.Subscribe(false);
|
|||
|
|
if (kc != null) kc.Subscribe(false);
|
|||
|
|
if (sp != null) sp.Subscribe(false);
|
|||
|
|
PrefabUtility.UnloadPrefabContents(root);
|
|||
|
|
}
|
|||
|
|
var body = sb.ToString();
|
|||
|
|
return body + "\n→ " + Write("WL813y_text.txt", body);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ═══ ⓑ ⑤ 보스 HP 바 · 배너 늦은 구독 보정 (발주서 §1-5) ════════════════
|
|||
|
|
public static string BossLate()
|
|||
|
|
{
|
|||
|
|
var sb = new StringBuilder();
|
|||
|
|
var root = PrefabUtility.LoadPrefabContents(kPrefab);
|
|||
|
|
BossHpBar bar = null; BossBanner ban = null; MobActor boss = null;
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
var hud = Find(root.transform, kHud);
|
|||
|
|
bar = hud.Find("WL_BossHpBar").GetComponent<BossHpBar>();
|
|||
|
|
ban = hud.Find("WL_BossBanner").GetComponent<BossBanner>();
|
|||
|
|
|
|||
|
|
sb.AppendLine("[0] Q3 결함 D-3 재현 — 보스가 **먼저** 스폰되고 HUD 가 **나중에** 켜진다");
|
|||
|
|
sb.AppendLine(" (Q3 실측: SpawnedSeen=232 · _bound=False — Spawned(isBoss) 가 구독 전에 지나갔다)");
|
|||
|
|
boss = MakeBoss();
|
|||
|
|
sb.AppendLine(" 가짜 보스 = " + boss.name + " m_SubRole=" + boss.m_SubRole +
|
|||
|
|
" IsSubRole(Boss)=" + boss.IsSubRole(eSubRol.Boss) + " IsDead=" + boss.IsDead() +
|
|||
|
|
" activeInHierarchy=" + boss.gameObject.activeInHierarchy);
|
|||
|
|
|
|||
|
|
sb.AppendLine();
|
|||
|
|
sb.AppendLine("[1] 경로 ① BossArena.Boss (813d 게이트가 잡아 둔 보스)");
|
|||
|
|
WL.Combat.Boss.BossArena.SetBossForProbe(boss);
|
|||
|
|
sb.AppendLine(" BossArena.Boss=" + (WL.Combat.Boss.BossArena.Boss != null ? WL.Combat.Boss.BossArena.Boss.name : "없음"));
|
|||
|
|
sb.AppendLine(" 보스바 " + bar.Initialize());
|
|||
|
|
sb.AppendLine(" → visible=" + bar.Visible + " ratio=" + bar.LastRatio.ToString("F3") +
|
|||
|
|
" 늦은구독=" + bar.LateBound + " (기대 True)");
|
|||
|
|
sb.AppendLine(" 배너 " + ban.Initialize());
|
|||
|
|
ban.Tick(Time.unscaledTime + 0.2f);
|
|||
|
|
sb.AppendLine(" → visible=" + ban.Visible + " shows=" + ban.ShowCount +
|
|||
|
|
" 늦은구독=" + ban.LateTriggered + " α=" + ban.BannerAlpha.ToString("F3") + " (기대 True)");
|
|||
|
|
|
|||
|
|
sb.AppendLine();
|
|||
|
|
sb.AppendLine("[2] 경로 ② 씬 1회 스캔 (게이트 이전 = 맵 로드 시 스폰 · BossArena 비어 있음)");
|
|||
|
|
bar.Subscribe(false); ban.Subscribe(false);
|
|||
|
|
WL.Combat.Boss.BossArena.SetBossForProbe(null);
|
|||
|
|
var bar2 = hud.Find("WL_BossHpBar").GetComponent<BossHpBar>();
|
|||
|
|
typeof(BossHpBar).GetField("_bound", NP).SetValue(bar2, false);
|
|||
|
|
sb.AppendLine(" BossArena.Boss=없음 · " + bar2.BindExistingBoss());
|
|||
|
|
sb.AppendLine(" → visible=" + bar2.Visible + " 늦은구독=" + bar2.LateBound + " 스캔=" + bar2.LateScanCount);
|
|||
|
|
sb.AppendLine(" 배너 " + ban.TriggerExistingBoss());
|
|||
|
|
|
|||
|
|
sb.AppendLine();
|
|||
|
|
sb.AppendLine("[3] 살아 있는 보스가 없으면 아무 일도 없어야 한다(오탐 0)");
|
|||
|
|
boss.gameObject.SetActive(false);
|
|||
|
|
var bar3 = hud.Find("WL_BossHpBar").GetComponent<BossHpBar>();
|
|||
|
|
typeof(BossHpBar).GetField("_bound", NP).SetValue(bar3, false);
|
|||
|
|
sb.AppendLine(" 보스 비활성 → " + bar3.BindExistingBoss());
|
|||
|
|
boss.gameObject.SetActive(true);
|
|||
|
|
|
|||
|
|
sb.AppendLine();
|
|||
|
|
sb.AppendLine("[4] C8 롤백 — bossBarBindExisting / bannerTriggerExisting = false 면 생략");
|
|||
|
|
var hs = WLHudLayoutSettings.Instance; var bs = WLBossUiSettings.Instance;
|
|||
|
|
bool h0 = hs.bossBarBindExisting, b0 = bs.bannerTriggerExisting;
|
|||
|
|
hs.bossBarBindExisting = false; bs.bannerTriggerExisting = false;
|
|||
|
|
var bar4 = hud.Find("WL_BossHpBar").GetComponent<BossHpBar>();
|
|||
|
|
typeof(BossHpBar).GetField("_bound", NP).SetValue(bar4, false);
|
|||
|
|
sb.AppendLine(" " + bar4.BindExistingBoss());
|
|||
|
|
sb.AppendLine(" " + ban.TriggerExistingBoss());
|
|||
|
|
hs.bossBarBindExisting = h0; bs.bannerTriggerExisting = b0;
|
|||
|
|
|
|||
|
|
sb.AppendLine();
|
|||
|
|
sb.AppendLine("[5] 최종 덤프");
|
|||
|
|
sb.Append(bar.Dump());
|
|||
|
|
sb.Append(ban.Dump());
|
|||
|
|
}
|
|||
|
|
finally
|
|||
|
|
{
|
|||
|
|
if (bar != null) bar.Subscribe(false);
|
|||
|
|
if (ban != null) ban.Subscribe(false);
|
|||
|
|
WL.Combat.Boss.BossArena.SetBossForProbe(null);
|
|||
|
|
if (boss != null) UnityEngine.Object.DestroyImmediate(boss.gameObject);
|
|||
|
|
PrefabUtility.UnloadPrefabContents(root);
|
|||
|
|
}
|
|||
|
|
sb.AppendLine();
|
|||
|
|
sb.AppendLine("해제 후 구독자 Spawned=" + WL.Combat.Core.CombatEvents.Spawned.Count +
|
|||
|
|
" BossPhase=" + WL.Combat.Boss.BossEvents.BossPhase.Count + " (0/0 이어야 한다)" +
|
|||
|
|
" · BossArena.Boss=" + (WL.Combat.Boss.BossArena.Boss != null ? "남음🔴" : "없음"));
|
|||
|
|
var body = sb.ToString();
|
|||
|
|
return body + "\n→ " + Write("WL813y_bosslate.txt", body);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
static string MenuBlocks(Transform root, WLHudLayoutSettings s)
|
|||
|
|
{
|
|||
|
|
var m = WLVignetteUtil.FindUiPath(root, s.bottomMenuPath);
|
|||
|
|
if (m == null) return "메뉴 없음";
|
|||
|
|
var cg = m.GetComponent<CanvasGroup>();
|
|||
|
|
return cg == null ? "CanvasGroup 없음🔴" : cg.blocksRaycasts.ToString();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
static MobActor MakeBoss()
|
|||
|
|
{
|
|||
|
|
var go = new GameObject("__WL813y_Boss");
|
|||
|
|
var m = go.AddComponent<MobActor>();
|
|||
|
|
m.m_Role = eRole.Mob; m.m_SubRole = eSubRol.Boss;
|
|||
|
|
var stat = new ActorStatInfo(eRole.Mob);
|
|||
|
|
stat.Set_Stat(eStat.MaxHP, 50000d); stat.Set_Stat(eStat.HP, 50000d);
|
|||
|
|
typeof(Actor).GetField("m_Stat", NP).SetValue(m, stat);
|
|||
|
|
typeof(Actor).GetField("m_Enemy", NP).SetValue(m, true);
|
|||
|
|
return m;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ═══ ⓑ ⑥ 전투 중 하단 메뉴 숨김 + 패드 원점 복귀 (발주서 §1-6) ══════════
|
|||
|
|
public static string Hud()
|
|||
|
|
{
|
|||
|
|
var sb = new StringBuilder();
|
|||
|
|
var root = PrefabUtility.LoadPrefabContents(kPrefab);
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
var s = WLHudLayoutSettings.Instance;
|
|||
|
|
if (s == null) return "🔴 WLHudLayoutSettings 에셋 없음";
|
|||
|
|
var padT = Find(root.transform, kPad);
|
|||
|
|
var pad = padT != null ? padT.GetComponent<WLBattlePadLayout>() : null;
|
|||
|
|
if (pad == null) pad = root.GetComponentInChildren<WLBattlePadLayout>(true);
|
|||
|
|
if (pad == null) return "🔴 WLBattlePadLayout 없음";
|
|||
|
|
|
|||
|
|
sb.AppendLine("[0] 에셋 값 (C8/C45 · 코드 상수 0)");
|
|||
|
|
sb.AppendLine(" 전투(메뉴 숨김) fanOrigin=" + s.fanOriginPx + " attackCenter=" + s.attackCenterPx);
|
|||
|
|
sb.AppendLine(" idle(메뉴 보임) fanOrigin=" + s.idleFanOriginPx + " attackCenter=" + s.idleAttackCenterPx);
|
|||
|
|
sb.AppendLine(" fanRadius=" + s.fanRadiusPx + " slot⌀=" + s.slotDiameterPx +
|
|||
|
|
" reserveRadius=" + s.reserveRadiusPx + " reserve⌀=" + s.reserveDiameterPx +
|
|||
|
|
" attack⌀=" + s.attackDiameterPx + " 목표반경=" + s.thumbReachRadiusPx);
|
|||
|
|
sb.AppendLine(" combatHideBottomMenu=" + s.combatHideBottomMenu + " path=\"" + s.bottomMenuPath +
|
|||
|
|
"\" exit=" + s.combatExitSeconds + "s enter=" + s.combatEnterDelaySeconds +
|
|||
|
|
"s fade=" + s.bottomMenuFadeSeconds + "s canvasGroup=" + s.bottomMenuUseCanvasGroup);
|
|||
|
|
|
|||
|
|
sb.AppendLine();
|
|||
|
|
sb.AppendLine("[1] 하단 메뉴 연결 + 복귀 버튼 생성(런타임 · 프리팹 diff 0)");
|
|||
|
|
HudCombatVisibility.Teardown();
|
|||
|
|
HudCombatVisibility.ResetState();
|
|||
|
|
sb.AppendLine(" " + HudCombatVisibility.Bind(root.transform));
|
|||
|
|
sb.AppendLine(" " + HudCombatVisibility.Subscribe(true));
|
|||
|
|
|
|||
|
|
sb.AppendLine();
|
|||
|
|
sb.AppendLine("[2] idle(메뉴 보임) → 전투(메뉴 숨김) → 다시 idle · 도달 px 실측");
|
|||
|
|
// 🔴 Signal() 은 Time.unscaledTime 을 쓴다 — 프로브 클록도 같은 축이어야 한다(임의 t 를 넣으면 since 가 수천 초로 뜬다).
|
|||
|
|
float t = Time.unscaledTime;
|
|||
|
|
sb.AppendLine(" ⓪ idle " + HudCombatVisibility.Tick(t));
|
|||
|
|
sb.AppendLine(" pad " + pad.Apply());
|
|||
|
|
float idleReach = pad.LastActionReachPx, idleMax = pad.LastMaxReachPx;
|
|||
|
|
sb.AppendLine(" ① 전투 신호 " + HudCombatVisibility.Signal("probe:attack"));
|
|||
|
|
t = Time.unscaledTime;
|
|||
|
|
sb.AppendLine(" tick " + HudCombatVisibility.Tick(t));
|
|||
|
|
sb.AppendLine(" pad " + pad.Apply());
|
|||
|
|
float fightReach = pad.LastActionReachPx, fightMax = pad.LastMaxReachPx;
|
|||
|
|
sb.AppendLine(" 메뉴 α=" + HudCombatVisibility.MenuAlpha.ToString("F2") + "(fade " + s.bottomMenuFadeSeconds + "s 시작)" +
|
|||
|
|
" 복귀버튼 표시=" + HudCombatVisibility.RestoreButtonVisible +
|
|||
|
|
" 메뉴 blocksRaycasts=" + MenuBlocks(root.transform, s));
|
|||
|
|
HudCombatVisibility.Tick(t + s.bottomMenuFadeSeconds + 0.01f);
|
|||
|
|
sb.AppendLine(" +" + s.bottomMenuFadeSeconds + "s → 메뉴 α=" + HudCombatVisibility.MenuAlpha.ToString("F2") +
|
|||
|
|
"(기대 0.00) blocksRaycasts=" + MenuBlocks(root.transform, s));
|
|||
|
|
sb.AppendLine(" ② 전투 종료(" + s.combatExitSeconds + "s 무신호) " + HudCombatVisibility.Tick(t + s.combatExitSeconds + 0.01f));
|
|||
|
|
HudCombatVisibility.Tick(t + s.combatExitSeconds + s.bottomMenuFadeSeconds + 0.02f);
|
|||
|
|
sb.AppendLine(" 메뉴 α=" + HudCombatVisibility.MenuAlpha.ToString("F2") + "(기대 1.00) menuVisible=" + HudCombatVisibility.BottomMenuVisible);
|
|||
|
|
sb.AppendLine(" pad " + pad.Apply());
|
|||
|
|
sb.AppendLine(" ③ 복귀 버튼 클릭(전투 중이어도 되돌린다)");
|
|||
|
|
HudCombatVisibility.Signal("probe:attack2");
|
|||
|
|
t = Time.unscaledTime;
|
|||
|
|
HudCombatVisibility.Tick(t);
|
|||
|
|
sb.AppendLine(" 숨김 확인 menuVisible=" + HudCombatVisibility.BottomMenuVisible + "(기대 False) 복귀버튼 표시=" + HudCombatVisibility.RestoreButtonVisible);
|
|||
|
|
sb.AppendLine(" " + HudCombatVisibility.OnRestoreClicked());
|
|||
|
|
sb.AppendLine(" menuVisible=" + HudCombatVisibility.BottomMenuVisible + " (기대 True)");
|
|||
|
|
HudCombatVisibility.Tick(t + 0.01f);
|
|||
|
|
sb.AppendLine(" hold " + s.restoreHoldSeconds + "s 안에는 전투여도 유지 → menuVisible=" + HudCombatVisibility.BottomMenuVisible);
|
|||
|
|
|
|||
|
|
sb.AppendLine();
|
|||
|
|
sb.AppendLine("[3] 엄지 도달 실측 (발주서 §1-6 목표 ≤ 490 px · 813m 오버레이 747 px 대비)");
|
|||
|
|
sb.AppendLine(" idle(메뉴 보임) actionReach=" + idleReach.ToString("F1") + " px · maxReach(자동토글 포함)=" + idleMax.ToString("F1") + " px");
|
|||
|
|
sb.AppendLine(" 전투(메뉴 숨김) actionReach=" + fightReach.ToString("F1") + " px · maxReach(자동토글 포함)=" + fightMax.ToString("F1") + " px");
|
|||
|
|
sb.AppendLine(" 판정: 전투 중 " + fightReach.ToString("F1") + " ≤ 490 → " + (fightReach <= 490f ? "PASS" : "FAIL") +
|
|||
|
|
" (813m 실측 747 px 대비 " + (747f - fightReach).ToString("F1") + " px 감소)");
|
|||
|
|
|
|||
|
|
sb.AppendLine();
|
|||
|
|
sb.AppendLine("[4] C8 롤백 — combatHideBottomMenu=false 면 메뉴를 건드리지 않고 패드도 idle 자리(813c+Lead 핫픽스 상태)");
|
|||
|
|
bool k0 = s.combatHideBottomMenu;
|
|||
|
|
s.combatHideBottomMenu = false;
|
|||
|
|
HudCombatVisibility.Signal("probe:rollback");
|
|||
|
|
sb.AppendLine(" " + HudCombatVisibility.Tick(Time.unscaledTime));
|
|||
|
|
sb.AppendLine(" " + pad.Apply());
|
|||
|
|
sb.AppendLine(" menuVisible=" + HudCombatVisibility.BottomMenuVisible + "(기대 True · 전투 신호가 있어도 안 숨긴다)" +
|
|||
|
|
" 메뉴 α=" + HudCombatVisibility.MenuAlpha.ToString("F2") +
|
|||
|
|
" actionReach=" + pad.LastActionReachPx.ToString("F1") + " px(= 롤백 전 746.8)");
|
|||
|
|
s.combatHideBottomMenu = k0;
|
|||
|
|
|
|||
|
|
sb.AppendLine();
|
|||
|
|
sb.AppendLine("[5] 최종 덤프");
|
|||
|
|
sb.Append(HudCombatVisibility.Dump());
|
|||
|
|
sb.Append(pad.Dump());
|
|||
|
|
}
|
|||
|
|
finally
|
|||
|
|
{
|
|||
|
|
HudCombatVisibility.Teardown();
|
|||
|
|
KillRunners();
|
|||
|
|
PrefabUtility.UnloadPrefabContents(root);
|
|||
|
|
}
|
|||
|
|
sb.AppendLine();
|
|||
|
|
sb.AppendLine("정리: 구독=" + HudCombatVisibility.Subscribed + " 연결=" + HudCombatVisibility.Bound +
|
|||
|
|
" · AttackStarted 구독자=" + WL.Combat.Core.CombatEvents.AttackStarted.Count +
|
|||
|
|
" Damaged=" + WL.Combat.Core.CombatEvents.Damaged.Count + " (0 이어야 한다)");
|
|||
|
|
var body = sb.ToString();
|
|||
|
|
return body + "\n→ " + Write("WL813y_hud.txt", body);
|
|||
|
|
}
|
|||
|
|
}
|