214 lines
14 KiB
C#
214 lines
14 KiB
C#
|
|
// WL802c_FitterDiag.cs — 발주서 WL-802c ⓖ: BottomBarFitter.cs 가 Assembly-CSharp 에 없는 원인 진단
|
||
|
|
//
|
||
|
|
// 실행 (CLAUDE.md §1: using 금지 · 네임스페이스 풀어 쓰기)
|
||
|
|
// unity command run_script --file AgentScripts/WL802c_FitterDiag.cs --entry WL802c_FitterDiag.Run --timeout 300
|
||
|
|
//
|
||
|
|
// 재는 것 — 전부 읽기 전용(하나만 예외: (4) 비파괴 재현이 더미 파일 1개를 만들고 즉시 지운다):
|
||
|
|
// (1) AssetDatabase.FindAssets("BottomBarFitter") 경로 · 디스크 전수 탐색(Assets 안팎)
|
||
|
|
// (2) Assembly-CSharp / Assembly-CSharp-Editor 의 Location · WL.* 네임스페이스 타입 목록 · 직접 GetType
|
||
|
|
// (3) CompilationPipeline 이 보는 Assembly-CSharp 소스 파일에 BottomBarFitter 가 있는가 +
|
||
|
|
// "임포트 대상 판정" = 경로가 Assets/(또는 Packages/) 아래인가 · 확장자가 .cs 인가 · MonoScript 로 임포트됐는가
|
||
|
|
// (4) 비파괴 재현: Assets/WL/Tools/ 에 같은 이름 규칙의 더미(.cs.draft)를 두고 Refresh →
|
||
|
|
// 임포트/컴파일 대상이 되는지 확인 후 **즉시 삭제**(컴파일을 일으키지 않는 확장자라 리컴파일 0)
|
||
|
|
//
|
||
|
|
// 경로·이름 외의 상수는 두지 않는다. 판정은 전부 에디터 API 실측이다.
|
||
|
|
|
||
|
|
public static class WL802c_FitterDiag
|
||
|
|
{
|
||
|
|
const string kName = "BottomBarFitter";
|
||
|
|
const string kDraft = "AgentScripts/staging/BottomBarFitter.cs.draft";
|
||
|
|
const string kProbeDir = "Assets/WL/Tools";
|
||
|
|
const string kProbeDraft = "Assets/WL/Tools/WL802c_ImportProbe.cs.draft";
|
||
|
|
|
||
|
|
public static object Run()
|
||
|
|
{
|
||
|
|
var sb = new System.Text.StringBuilder();
|
||
|
|
string root = System.IO.Path.GetDirectoryName(UnityEngine.Application.dataPath).Replace("\\", "/");
|
||
|
|
sb.AppendLine("projectRoot = " + root);
|
||
|
|
sb.AppendLine("dataPath = " + UnityEngine.Application.dataPath.Replace("\\", "/"));
|
||
|
|
|
||
|
|
// ── (1) 에셋 DB 검색 + 디스크 전수 탐색
|
||
|
|
sb.AppendLine();
|
||
|
|
sb.AppendLine("== (1) 자산 검색 ==");
|
||
|
|
var guids = UnityEditor.AssetDatabase.FindAssets(kName);
|
||
|
|
sb.AppendLine("AssetDatabase.FindAssets(\"" + kName + "\") = " + guids.Length + "건");
|
||
|
|
foreach (var g in guids)
|
||
|
|
sb.AppendLine(" " + UnityEditor.AssetDatabase.GUIDToAssetPath(g));
|
||
|
|
var g2 = UnityEditor.AssetDatabase.FindAssets(kName + " t:MonoScript");
|
||
|
|
sb.AppendLine("FindAssets(\"" + kName + " t:MonoScript\") = " + g2.Length + "건");
|
||
|
|
|
||
|
|
sb.AppendLine("-- 디스크 전수(Library/Temp/.git 제외) --");
|
||
|
|
int hits = 0;
|
||
|
|
foreach (var f in System.IO.Directory.GetFiles(root, "*" + kName + "*", System.IO.SearchOption.AllDirectories))
|
||
|
|
{
|
||
|
|
string rel = f.Replace("\\", "/").Substring(root.Length + 1);
|
||
|
|
if (rel.StartsWith("Library/") || rel.StartsWith("Temp/") || rel.StartsWith(".git/") || rel.StartsWith("obj/")) continue;
|
||
|
|
var fi = new System.IO.FileInfo(f);
|
||
|
|
sb.AppendLine(" " + rel + " (" + fi.Length + " B · " + fi.LastWriteTime.ToString("yyyy-MM-dd HH:mm") + ")");
|
||
|
|
hits++;
|
||
|
|
}
|
||
|
|
sb.AppendLine(" 디스크 히트 = " + hits + "건");
|
||
|
|
|
||
|
|
// ── (2) 어셈블리 · 타입
|
||
|
|
sb.AppendLine();
|
||
|
|
sb.AppendLine("== (2) 어셈블리 · 타입 ==");
|
||
|
|
foreach (var asm in System.AppDomain.CurrentDomain.GetAssemblies())
|
||
|
|
{
|
||
|
|
string an = asm.GetName().Name;
|
||
|
|
if (!an.StartsWith("Assembly-CSharp")) continue;
|
||
|
|
sb.AppendLine("asm = " + an + " loc = " + asm.Location);
|
||
|
|
System.Type[] types;
|
||
|
|
try { types = asm.GetTypes(); }
|
||
|
|
catch (System.Reflection.ReflectionTypeLoadException e) { types = System.Linq.Enumerable.ToArray(System.Linq.Enumerable.Where(e.Types, t => t != null)); }
|
||
|
|
var wl = System.Linq.Enumerable.ToArray(System.Linq.Enumerable.OrderBy(
|
||
|
|
System.Linq.Enumerable.Select(
|
||
|
|
System.Linq.Enumerable.Where(types, t => t != null && t.Namespace != null && t.Namespace.StartsWith("WL.")),
|
||
|
|
t => t.Namespace + "." + t.Name), x => x));
|
||
|
|
sb.AppendLine(" WL.* 타입 " + wl.Length + "개: " + string.Join(", ", wl));
|
||
|
|
}
|
||
|
|
sb.AppendLine("Type.GetType(\"WL.UI." + kName + ", Assembly-CSharp\") = " +
|
||
|
|
(System.Type.GetType("WL.UI." + kName + ", Assembly-CSharp") != null));
|
||
|
|
|
||
|
|
// ── (3) 컴파일 파이프라인 + 임포트 대상 판정
|
||
|
|
sb.AppendLine();
|
||
|
|
sb.AppendLine("== (3) 컴파일 파이프라인 · 임포트 대상 판정 ==");
|
||
|
|
foreach (var a in UnityEditor.Compilation.CompilationPipeline.GetAssemblies(UnityEditor.Compilation.AssembliesType.Editor))
|
||
|
|
{
|
||
|
|
if (!a.name.StartsWith("Assembly-CSharp")) continue;
|
||
|
|
int n = a.sourceFiles.Length;
|
||
|
|
int match = 0;
|
||
|
|
foreach (var s in a.sourceFiles) if (s.Contains(kName)) match++;
|
||
|
|
sb.AppendLine(a.name + ": sourceFiles = " + n + "개 · \"" + kName + "\" 포함 = " + match + "개 · outputPath = " + a.outputPath);
|
||
|
|
}
|
||
|
|
|
||
|
|
string draftAbs = root + "/" + kDraft;
|
||
|
|
bool draftExists = System.IO.File.Exists(draftAbs);
|
||
|
|
sb.AppendLine("draft = " + kDraft + " · 존재 = " + draftExists);
|
||
|
|
sb.AppendLine(" 확장자 = \"" + System.IO.Path.GetExtension(kDraft) + "\" (스크립트 컴파일 대상은 \".cs\" 만)");
|
||
|
|
sb.AppendLine(" Assets/ 아래인가 = " + kDraft.StartsWith("Assets/"));
|
||
|
|
sb.AppendLine(" AssetPathToGUID = \"" + UnityEditor.AssetDatabase.AssetPathToGUID(kDraft) + "\" (빈 문자열 = 에셋 DB 가 모르는 파일)");
|
||
|
|
sb.AppendLine(" .meta 존재 = " + System.IO.File.Exists(draftAbs + ".meta"));
|
||
|
|
sb.AppendLine(" LoadAssetAtPath = " + (UnityEditor.AssetDatabase.LoadAssetAtPath<UnityEngine.Object>(kDraft) != null));
|
||
|
|
sb.AppendLine(" IsValidFolder(AgentScripts) = " + UnityEditor.AssetDatabase.IsValidFolder("AgentScripts"));
|
||
|
|
|
||
|
|
// 배치 후보(UI 소유 · W2)에 같은 이름의 스크립트가 있는지
|
||
|
|
sb.AppendLine("-- 배치 후보 폴더의 실제 .cs 목록 --");
|
||
|
|
foreach (var dir in new[] { "Assets/WL/UI/Scripts", "Assets/WL/Tools" })
|
||
|
|
{
|
||
|
|
if (!System.IO.Directory.Exists(root + "/" + dir)) { sb.AppendLine(" " + dir + " : 폴더 없음"); continue; }
|
||
|
|
var cs = System.IO.Directory.GetFiles(root + "/" + dir, "*.cs", System.IO.SearchOption.TopDirectoryOnly);
|
||
|
|
var names = new System.Collections.Generic.List<string>();
|
||
|
|
foreach (var c in cs) names.Add(System.IO.Path.GetFileName(c));
|
||
|
|
sb.AppendLine(" " + dir + " : " + names.Count + "개 — " + string.Join(", ", names.ToArray()));
|
||
|
|
}
|
||
|
|
|
||
|
|
// ── (4) 비파괴 재현 — Assets 안이어도 .cs.draft 는 스크립트가 아니다
|
||
|
|
sb.AppendLine();
|
||
|
|
sb.AppendLine("== (4) 비파괴 재현(더미 1개 · 즉시 삭제) ==");
|
||
|
|
string probeAbs = root + "/" + kProbeDraft;
|
||
|
|
bool made = false;
|
||
|
|
try
|
||
|
|
{
|
||
|
|
if (!System.IO.Directory.Exists(root + "/" + kProbeDir)) System.IO.Directory.CreateDirectory(root + "/" + kProbeDir);
|
||
|
|
System.IO.File.WriteAllText(probeAbs, "namespace WL.Tools { internal class WL802c_ImportProbeDummy { } }\n");
|
||
|
|
made = true;
|
||
|
|
UnityEditor.AssetDatabase.Refresh(UnityEditor.ImportAssetOptions.ForceSynchronousImport);
|
||
|
|
|
||
|
|
sb.AppendLine("더미 = " + kProbeDraft + " (Assets/ **안**, 확장자 .cs.draft)");
|
||
|
|
sb.AppendLine(" AssetPathToGUID = \"" + UnityEditor.AssetDatabase.AssetPathToGUID(kProbeDraft) + "\"");
|
||
|
|
sb.AppendLine(" LoadAssetAtPath = " + (UnityEditor.AssetDatabase.LoadAssetAtPath<UnityEngine.Object>(kProbeDraft) != null));
|
||
|
|
sb.AppendLine(" MonoScript 로 임포트 = " + (UnityEditor.AssetDatabase.LoadAssetAtPath<UnityEditor.MonoScript>(kProbeDraft) != null));
|
||
|
|
sb.AppendLine(" .meta 생성 = " + System.IO.File.Exists(probeAbs + ".meta"));
|
||
|
|
int inSrc = 0;
|
||
|
|
foreach (var a in UnityEditor.Compilation.CompilationPipeline.GetAssemblies(UnityEditor.Compilation.AssembliesType.Editor))
|
||
|
|
{
|
||
|
|
if (!a.name.StartsWith("Assembly-CSharp")) continue;
|
||
|
|
foreach (var s in a.sourceFiles) if (s.Contains("WL802c_ImportProbe")) inSrc++;
|
||
|
|
}
|
||
|
|
sb.AppendLine(" Assembly-CSharp sourceFiles 포함 = " + inSrc + "개 (0 이면 컴파일 대상 아님 = 재현 성공)");
|
||
|
|
}
|
||
|
|
catch (System.Exception ex) { sb.AppendLine(" 재현 실패: " + ex.Message); }
|
||
|
|
finally
|
||
|
|
{
|
||
|
|
if (made)
|
||
|
|
{
|
||
|
|
try { UnityEditor.AssetDatabase.DeleteAsset(kProbeDraft); } catch { }
|
||
|
|
if (System.IO.File.Exists(probeAbs)) System.IO.File.Delete(probeAbs);
|
||
|
|
if (System.IO.File.Exists(probeAbs + ".meta")) System.IO.File.Delete(probeAbs + ".meta");
|
||
|
|
UnityEditor.AssetDatabase.Refresh();
|
||
|
|
sb.AppendLine(" 더미 삭제 완료 · 잔존 = " + System.IO.File.Exists(probeAbs));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// ── (5) 이번 태스크가 추가한 명령 파일이 실제로 컴파일 대상인지(대조군)
|
||
|
|
sb.AppendLine();
|
||
|
|
sb.AppendLine("== (5) 대조군: Assets/WL/Tools/WLPipelineCommands.cs ==");
|
||
|
|
const string kCmd = "Assets/WL/Tools/WLPipelineCommands.cs";
|
||
|
|
sb.AppendLine(" AssetPathToGUID = \"" + UnityEditor.AssetDatabase.AssetPathToGUID(kCmd) + "\"");
|
||
|
|
sb.AppendLine(" MonoScript = " + (UnityEditor.AssetDatabase.LoadAssetAtPath<UnityEditor.MonoScript>(kCmd) != null));
|
||
|
|
int cmdSrc = 0;
|
||
|
|
foreach (var a in UnityEditor.Compilation.CompilationPipeline.GetAssemblies(UnityEditor.Compilation.AssembliesType.Editor))
|
||
|
|
{
|
||
|
|
if (!a.name.StartsWith("Assembly-CSharp")) continue;
|
||
|
|
foreach (var s in a.sourceFiles) if (s.Contains("WLPipelineCommands")) cmdSrc++;
|
||
|
|
}
|
||
|
|
sb.AppendLine(" Assembly-CSharp sourceFiles 포함 = " + cmdSrc + "개");
|
||
|
|
sb.AppendLine(" Type.GetType(\"WL.Tools.WLPipelineCommands, Assembly-CSharp\") = " +
|
||
|
|
(System.Type.GetType("WL.Tools.WLPipelineCommands, Assembly-CSharp") != null));
|
||
|
|
|
||
|
|
return sb.ToString();
|
||
|
|
}
|
||
|
|
|
||
|
|
// ── 발주서 WL-802c ⓗ: TMP 경고(#751) 조치안 근거 실측. 읽기 전용 — 아무것도 고치지 않는다.
|
||
|
|
// unity command run_script --file AgentScripts/WL802c_FitterDiag.cs --entry WL802c_FitterDiag.Tmp --timeout 300
|
||
|
|
public static object Tmp()
|
||
|
|
{
|
||
|
|
var sb = new System.Text.StringBuilder();
|
||
|
|
const string kAsset = "Assets/ThirdParty/TextMesh Pro/Resources/TMP Settings.asset";
|
||
|
|
string root = System.IO.Path.GetDirectoryName(UnityEngine.Application.dataPath).Replace("\\", "/");
|
||
|
|
|
||
|
|
sb.AppendLine("== TMP Settings 자산 ==");
|
||
|
|
sb.AppendLine("path = " + kAsset);
|
||
|
|
sb.AppendLine("exists = " + System.IO.File.Exists(root + "/" + kAsset));
|
||
|
|
foreach (var line in System.IO.File.ReadAllLines(root + "/" + kAsset))
|
||
|
|
if (line.Contains("assetVersion") || line.Contains("m_Name:") || line.Contains("m_warningsDisabled"))
|
||
|
|
sb.AppendLine(" yaml> " + line.Trim());
|
||
|
|
|
||
|
|
sb.AppendLine();
|
||
|
|
sb.AppendLine("== 런타임 판정 (TMP_Settings.cs:459 조건) ==");
|
||
|
|
var so = UnityEngine.Resources.Load("TMP Settings");
|
||
|
|
sb.AppendLine("Resources.Load(\"TMP Settings\") = " + (so != null ? so.GetType().FullName : "null") + " → isTMPSettingsNull = " + (so == null));
|
||
|
|
if (so != null)
|
||
|
|
{
|
||
|
|
var t = so.GetType();
|
||
|
|
var fi = t.GetField("assetVersion", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Public);
|
||
|
|
var cur = t.GetField("s_CurrentAssetVersion", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Public);
|
||
|
|
string a = fi != null ? (string)fi.GetValue(so) : "(필드 없음)";
|
||
|
|
string c = cur != null ? (string)cur.GetValue(null) : "(필드 없음)";
|
||
|
|
sb.AppendLine("assetVersion(직렬화 값) = \"" + a + "\" s_CurrentAssetVersion = \"" + c + "\" 같음 = " + (a == c));
|
||
|
|
sb.AppendLine("→ 임포터 창 조건 (assetVersion != s_CurrentAssetVersion) = " + (a != c));
|
||
|
|
sb.AppendLine(" asm = " + t.Assembly.GetName().Name + " · " + t.Assembly.Location);
|
||
|
|
}
|
||
|
|
|
||
|
|
sb.AppendLine();
|
||
|
|
sb.AppendLine("== TMP Essentials 리소스 존재 여부(재임포트 = (b) 안의 영향 범위) ==");
|
||
|
|
foreach (var d in new[] { "Assets/ThirdParty/TextMesh Pro", "Assets/TextMesh Pro" })
|
||
|
|
{
|
||
|
|
string abs = root + "/" + d;
|
||
|
|
if (!System.IO.Directory.Exists(abs)) { sb.AppendLine(" " + d + " : 폴더 없음"); continue; }
|
||
|
|
var files = System.IO.Directory.GetFiles(abs, "*", System.IO.SearchOption.AllDirectories);
|
||
|
|
long bytes = 0; int metas = 0;
|
||
|
|
foreach (var f in files) { if (f.EndsWith(".meta")) metas++; else bytes += new System.IO.FileInfo(f).Length; }
|
||
|
|
sb.AppendLine(" " + d + " : 파일 " + files.Length + "개(.meta " + metas + ") · " + System.Math.Round(bytes / 1048576.0, 1) + " MB");
|
||
|
|
}
|
||
|
|
|
||
|
|
sb.AppendLine();
|
||
|
|
sb.AppendLine("== 이 프로젝트에서 TMP 를 실제로 쓰는 자산 수(재임포트 위험 범위) ==");
|
||
|
|
sb.AppendLine(" t:TMP_FontAsset = " + UnityEditor.AssetDatabase.FindAssets("t:TMP_FontAsset").Length + "개");
|
||
|
|
sb.AppendLine(" t:TMP_SpriteAsset= " + UnityEditor.AssetDatabase.FindAssets("t:TMP_SpriteAsset").Length + "개");
|
||
|
|
sb.AppendLine(" t:TMP_StyleSheet = " + UnityEditor.AssetDatabase.FindAssets("t:TMP_StyleSheet").Length + "개");
|
||
|
|
|
||
|
|
return sb.ToString();
|
||
|
|
}
|
||
|
|
}
|