252 lines
13 KiB
C#
252 lines
13 KiB
C#
// WL796_Apply.cs — PD 지시 #796 적용 (에디트 모드 전용 · 프리팹/설정 에셋 수정)
|
|
// unity command run_script --file AgentScripts/WL796_Apply.cs --entry WL796_Apply.ApplyAll
|
|
// unity command run_script --file AgentScripts/WL796_Apply.cs --entry WL796_Apply.Report
|
|
//
|
|
// 1) NewGameUI.prefab / IngameUIs/WL_HUD/HUD_BottomMenu
|
|
// - 바 폭 = 캔버스 폭(1920 단위) / 스케일 1.55 = 1238.71 → 좌우를 가득 채운다
|
|
// - 바 바닥 y = 10 단위(≈5.6px) — 가운데 전투 버튼의 ProgressText 가 -5.9 단위까지 내려가 잘리지 않게 하는 최소 여유
|
|
// - 버튼 5개: 셀 중심 앵커(0.1/0.3/0.5/0.7/0.9 — 원본 그대로) · 셀 폭 = 바폭/5 - 간격 2
|
|
// - 일반 버튼 높이 140 → 200 (아이콘이 rect 위로 42 단위 튀어나와 터치가 안 되던 것을 rect 안으로 넣는다)
|
|
// - 자식은 "부모 피벗(하단 중앙) 기준 localPosition" 을 기록/복원해 시각적 위치를 그대로 유지한다
|
|
// - BottomBarFitter 부착(해상도·Safe Area 변화 시 런타임 재계산)
|
|
// 2) WLGameplaySettings.asset : hideIngameChat = true · ingameHideCanvasGroupPaths = [MessageInfo/Chat]
|
|
//
|
|
// 🔴 Play 중 실행 금지(에셋을 디스크에 쓴다). 백업 = 공유/개발팀_백업/WL/Hud2_20260907_0143/
|
|
using System.Collections.Generic;
|
|
using System.Text;
|
|
using UnityEditor;
|
|
using UnityEngine;
|
|
// WL.Settings / WL.UI 를 using 하지 않는다 — run_script 어셈블리가 Assembly-CSharp 최신 스냅샷을 못 볼 수 있어
|
|
// 새로 추가한 타입·필드는 전부 SerializedObject/리플렉션으로 접근한다.
|
|
|
|
public static class WL796_Apply
|
|
{
|
|
const string PrefabPath = "Assets/Res_Addr/MainUI/NewGameUI.prefab";
|
|
const string MenuPath = "IngameUIs/WL_HUD/HUD_BottomMenu";
|
|
|
|
// 캔버스 폭(세로 화면에서 항상 1920 단위) / HUD_BottomMenu localScale.x(1.55)
|
|
const float CanvasWidthUnits = 1920f;
|
|
const float BarBottomY = 10f; // Safe Area 바닥에서 띄우는 최소 여유(단위)
|
|
const float BarHeight = 280f; // 244 px @1080x1920 — 사양 230~260 px 창 안
|
|
const float CellGap = 2f; // ≈1.1 px — 인접 사각형 겹침 0 보장
|
|
const float NormalButtonHeight = 200f;
|
|
|
|
/// <summary>WL.UI.BottomBarFitter 타입을 로드된 어셈블리에서 찾는다(컴파일 타임 참조 회피).</summary>
|
|
static System.Type FitterType()
|
|
{
|
|
var t = System.Type.GetType("WL.UI.BottomBarFitter, Assembly-CSharp");
|
|
if (t != null) return t;
|
|
foreach (var asm in System.AppDomain.CurrentDomain.GetAssemblies())
|
|
{
|
|
t = asm.GetType("WL.UI.BottomBarFitter");
|
|
if (t != null) return t;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
static Transform FindByPath(Transform root, string path)
|
|
{
|
|
var cur = root;
|
|
foreach (var raw in path.Split('/'))
|
|
{
|
|
var name = raw.Trim();
|
|
if (name.Length == 0) continue;
|
|
Transform next = null;
|
|
for (int c = 0; c < cur.childCount; c++)
|
|
if (cur.GetChild(c).name == name) { next = cur.GetChild(c); break; }
|
|
if (next == null) return null;
|
|
cur = next;
|
|
}
|
|
return cur;
|
|
}
|
|
|
|
public static object ApplyAll()
|
|
{
|
|
if (EditorApplication.isPlaying) return "ABORT: Play 중에는 실행하지 않는다(에셋 디스크 쓰기).";
|
|
var sb = new StringBuilder();
|
|
sb.AppendLine(ApplyPrefabInternal());
|
|
sb.AppendLine(ApplySettingsInternal());
|
|
AssetDatabase.SaveAssets();
|
|
AssetDatabase.Refresh();
|
|
return sb.ToString();
|
|
}
|
|
|
|
static string ApplyPrefabInternal()
|
|
{
|
|
var sb = new StringBuilder();
|
|
var root = PrefabUtility.LoadPrefabContents(PrefabPath);
|
|
if (root == null) return "prefab load 실패: " + PrefabPath;
|
|
try
|
|
{
|
|
var menuT = FindByPath(root.transform, MenuPath);
|
|
if (menuT == null) { return "HUD_BottomMenu 없음: " + MenuPath; }
|
|
var menu = menuT as RectTransform;
|
|
|
|
float scale = menu.localScale.x;
|
|
float barWidth = CanvasWidthUnits / scale;
|
|
int n = menu.childCount;
|
|
if (n <= 0) return "버튼 없음";
|
|
int center = n / 2;
|
|
float cellW = barWidth / n;
|
|
|
|
sb.AppendLine("[before] bar sizeDelta=" + menu.sizeDelta + " anchoredPos=" + menu.anchoredPosition + " scale=" + scale);
|
|
|
|
// ── 1) 바 ────────────────────────────────────────────────────────
|
|
menu.sizeDelta = new Vector2(barWidth, BarHeight);
|
|
menu.anchoredPosition = new Vector2(0f, BarBottomY);
|
|
|
|
// ── 2) 버튼 5개 ──────────────────────────────────────────────────
|
|
for (int i = 0; i < n; i++)
|
|
{
|
|
var b = menu.GetChild(i) as RectTransform;
|
|
if (b == null) continue;
|
|
|
|
// 자식들의 "버튼 피벗(하단 중앙) 기준" 위치를 기록 → rect 를 키운 뒤 그대로 복원한다.
|
|
var keep = new List<KeyValuePair<Transform, Vector3>>();
|
|
for (int c = 0; c < b.childCount; c++)
|
|
keep.Add(new KeyValuePair<Transform, Vector3>(b.GetChild(c), b.GetChild(c).localPosition));
|
|
|
|
var before = b.sizeDelta;
|
|
|
|
float mid = (i + 0.5f) / n;
|
|
var aMin = b.anchorMin; var aMax = b.anchorMax;
|
|
aMin.x = mid; aMax.x = mid;
|
|
b.anchorMin = aMin; b.anchorMax = aMax;
|
|
var ap = b.anchoredPosition; ap.x = 0f; b.anchoredPosition = ap;
|
|
|
|
float h = (i == center) ? b.sizeDelta.y : NormalButtonHeight;
|
|
b.sizeDelta = new Vector2(cellW - CellGap, h);
|
|
|
|
foreach (var kv in keep) kv.Key.localPosition = kv.Value; // 시각 위치 그대로
|
|
|
|
sb.AppendLine(" " + b.name + " : size " + before + " -> " + b.sizeDelta +
|
|
" anchorX=" + mid.ToString("F2") + " children=" + keep.Count);
|
|
}
|
|
|
|
// ── 3) 런타임 보정 컴포넌트 ──────────────────────────────────────
|
|
// run_script 어셈블리가 Assembly-CSharp 의 최신 스냅샷을 못 볼 수 있어 타입 참조 대신 리플렉션으로 붙인다.
|
|
var fitterType = FitterType();
|
|
if (fitterType == null) sb.AppendLine(" ⚠ BottomBarFitter 타입 없음 — 프리팹 값만 적용(런타임 보정 미부착)");
|
|
else
|
|
{
|
|
var fitter = menu.GetComponent(fitterType);
|
|
if (fitter == null) { fitter = menu.gameObject.AddComponent(fitterType); sb.AppendLine(" BottomBarFitter 추가"); }
|
|
else sb.AppendLine(" BottomBarFitter 이미 있음");
|
|
var so = new SerializedObject(fitter);
|
|
so.FindProperty("fitWidthToParent").boolValue = true;
|
|
so.FindProperty("centerCellMultiplier").floatValue = 1f; // 옵션 A(균등 5등분) 기본
|
|
so.FindProperty("cellGap").floatValue = CellGap;
|
|
so.FindProperty("uniformButtonHeight").floatValue = 0f; // 프리팹 높이 유지
|
|
so.ApplyModifiedPropertiesWithoutUndo();
|
|
}
|
|
|
|
sb.AppendLine("[after] bar sizeDelta=" + menu.sizeDelta + " anchoredPos=" + menu.anchoredPosition +
|
|
" cellW=" + cellW.ToString("F2") + " (px@1080=" + (cellW * scale * 0.5625f).ToString("F1") + ")");
|
|
|
|
PrefabUtility.SaveAsPrefabAsset(root, PrefabPath);
|
|
sb.AppendLine("saved prefab");
|
|
}
|
|
finally { PrefabUtility.UnloadPrefabContents(root); }
|
|
return sb.ToString();
|
|
}
|
|
|
|
const string SettingsPath = "Assets/WL/Settings/Resources/WL/WLGameplaySettings.asset";
|
|
|
|
static string ApplySettingsInternal()
|
|
{
|
|
var s = AssetDatabase.LoadAssetAtPath<ScriptableObject>(SettingsPath);
|
|
if (s == null) return "WLGameplaySettings.asset 없음";
|
|
var so = new SerializedObject(s);
|
|
var p = so.FindProperty("hideIngameChat");
|
|
var arr = so.FindProperty("ingameHideCanvasGroupPaths");
|
|
if (p == null || arr == null)
|
|
return "⚠ 설정 필드 미인식(WLGameplaySettings.cs 컴파일 반영 대기) — hideIngameChat/ingameHideCanvasGroupPaths 미기록";
|
|
p.boolValue = true;
|
|
arr.arraySize = 1;
|
|
arr.GetArrayElementAtIndex(0).stringValue = "MessageInfo/Chat";
|
|
so.ApplyModifiedPropertiesWithoutUndo();
|
|
EditorUtility.SetDirty(s);
|
|
return "settings: hideIngameChat=true paths=[MessageInfo/Chat]";
|
|
}
|
|
|
|
/// <summary>적용 결과 확인(프리팹 값 · 설정 에셋 값).</summary>
|
|
public static object Report()
|
|
{
|
|
var sb = new StringBuilder();
|
|
var go = AssetDatabase.LoadAssetAtPath<GameObject>(PrefabPath);
|
|
var menu = go != null ? FindByPath(go.transform, MenuPath) as RectTransform : null;
|
|
if (menu == null) return "HUD_BottomMenu 없음";
|
|
float scale = menu.localScale.x, k = scale * 0.5625f; // 1080x1920 기준 px 환산
|
|
sb.AppendLine("bar sizeDelta=" + menu.sizeDelta + " anchoredPos=" + menu.anchoredPosition + " scale=" + scale +
|
|
" => px w=" + (menu.sizeDelta.x * k).ToString("F0") + " h=" + (menu.sizeDelta.y * k).ToString("F0") +
|
|
" bottom=" + (menu.anchoredPosition.y * 0.5625f).ToString("F0"));
|
|
var ft = FitterType();
|
|
sb.AppendLine("fitter=" + (ft != null && menu.GetComponent(ft) != null));
|
|
for (int i = 0; i < menu.childCount; i++)
|
|
{
|
|
var b = menu.GetChild(i) as RectTransform;
|
|
sb.AppendLine(" " + b.name + " anchorX=" + b.anchorMin.x.ToString("F2") + " size=" + b.sizeDelta +
|
|
" => px w=" + (b.sizeDelta.x * k).ToString("F0") + " h=" + (b.sizeDelta.y * k).ToString("F0"));
|
|
}
|
|
var s = AssetDatabase.LoadAssetAtPath<ScriptableObject>(SettingsPath);
|
|
if (s != null)
|
|
{
|
|
var so2 = new SerializedObject(s);
|
|
var p = so2.FindProperty("hideIngameChat");
|
|
var arr = so2.FindProperty("ingameHideCanvasGroupPaths");
|
|
var pad = so2.FindProperty("hideBattlePad");
|
|
var paths = new List<string>();
|
|
if (arr != null) for (int i = 0; i < arr.arraySize; i++) paths.Add(arr.GetArrayElementAtIndex(i).stringValue);
|
|
sb.AppendLine("settings hideIngameChat=" + (p != null ? p.boolValue.ToString() : "(필드없음)") +
|
|
" paths=[" + string.Join(",", paths.ToArray()) + "]" +
|
|
" hideBattlePad=" + (pad != null ? pad.boolValue.ToString() : "?"));
|
|
}
|
|
return sb.ToString();
|
|
}
|
|
|
|
/// <summary>옵션 B(가운데 셀 1.3배)로 전환. 프리팹의 앵커·폭을 다시 계산한다.</summary>
|
|
public static object SetCenterMultiplier(float mul)
|
|
{
|
|
if (EditorApplication.isPlaying) return "ABORT: Play 중";
|
|
var root = PrefabUtility.LoadPrefabContents(PrefabPath);
|
|
if (root == null) return "prefab load 실패";
|
|
var sb = new StringBuilder();
|
|
try
|
|
{
|
|
var menu = FindByPath(root.transform, MenuPath) as RectTransform;
|
|
if (menu == null) return "HUD_BottomMenu 없음";
|
|
int n = menu.childCount, center = n / 2;
|
|
float barWidth = menu.sizeDelta.x;
|
|
float total = 0f;
|
|
for (int i = 0; i < n; i++) total += (i == center ? mul : 1f);
|
|
float cursor = 0f;
|
|
for (int i = 0; i < n; i++)
|
|
{
|
|
var b = menu.GetChild(i) as RectTransform;
|
|
float w = (i == center ? mul : 1f) / total;
|
|
float mid = cursor + w * 0.5f; cursor += w;
|
|
var keep = new List<KeyValuePair<Transform, Vector3>>();
|
|
for (int c = 0; c < b.childCount; c++) keep.Add(new KeyValuePair<Transform, Vector3>(b.GetChild(c), b.GetChild(c).localPosition));
|
|
var aMin = b.anchorMin; var aMax = b.anchorMax; aMin.x = mid; aMax.x = mid;
|
|
b.anchorMin = aMin; b.anchorMax = aMax;
|
|
var ap = b.anchoredPosition; ap.x = 0f; b.anchoredPosition = ap;
|
|
b.sizeDelta = new Vector2(barWidth * w - CellGap, b.sizeDelta.y);
|
|
foreach (var kv in keep) kv.Key.localPosition = kv.Value;
|
|
sb.AppendLine(" " + b.name + " anchorX=" + mid.ToString("F3") + " w=" + b.sizeDelta.x.ToString("F1"));
|
|
}
|
|
var ft = FitterType();
|
|
var fitter = ft != null ? menu.GetComponent(ft) : null;
|
|
if (fitter != null)
|
|
{
|
|
var so = new SerializedObject(fitter);
|
|
so.FindProperty("centerCellMultiplier").floatValue = mul;
|
|
so.ApplyModifiedPropertiesWithoutUndo();
|
|
}
|
|
PrefabUtility.SaveAsPrefabAsset(root, PrefabPath);
|
|
}
|
|
finally { PrefabUtility.UnloadPrefabContents(root); }
|
|
AssetDatabase.SaveAssets();
|
|
return "centerCellMultiplier=" + mul + "\n" + sb;
|
|
}
|
|
}
|