// ───────────────────────────────────────────────────────────────────────────── // WLErrorTrace.cs — 런타임 에러·예외·「Coroutine couldn't be started」 경고를 **메모리에 보관**한다(최근 40건 · 스택 포함). // // 2026-09-17 PD 「다리가 생성될 때 에러」 실측: 화면 팝업은 보였는데 에디터 콘솔(파이프라인 조회)은 비어 있어 원문·스택을 못 잡았다 // (Play 재시작·Clear 로 사라짐). 이후로는 Lead 프로브가 `WLErrorTrace.Dump()` 로 언제든 읽는다. 원본 코드 0줄 · 화면 출력 없음. // ───────────────────────────────────────────────────────────────────────────── using System.Collections.Generic; using UnityEngine; namespace WL.Island { public static class WLErrorTrace { public struct Entry { public float time; public LogType type; public string message; public string stack; } static readonly List s_entries = new List(64); static bool s_hooked; public static int Total; [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)] static void Hook() { if (s_hooked) return; s_hooked = true; Application.logMessageReceived += OnLog; } static void OnLog(string message, string stack, LogType type) { bool keep = type == LogType.Error || type == LogType.Exception || type == LogType.Assert || (type == LogType.Warning && message != null && message.IndexOf("Coroutine couldn't be started", System.StringComparison.Ordinal) >= 0); if (!keep) return; Total++; if (s_entries.Count >= 40) s_entries.RemoveAt(0); s_entries.Add(new Entry { time = Time.realtimeSinceStartup, type = type, message = message, stack = stack }); } /// 최근 항목을 한 문자열로(프로브용). 같은 메시지는 횟수만 센다. public static string Dump(int maxEach = 400) { var sb = new System.Text.StringBuilder(); sb.Append("total=").Append(Total).Append(" kept=").Append(s_entries.Count); var counts = new Dictionary(); for (int i = 0; i < s_entries.Count; i++) { var e = s_entries[i]; string key = e.message.Length > 100 ? e.message.Substring(0, 100) : e.message; int c; counts.TryGetValue(key, out c); counts[key] = c + 1; if (c > 0) continue; sb.Append("\n[").Append(e.time.ToString("F1")).Append("s ").Append(e.type).Append("] ") .Append(e.message.Length > maxEach ? e.message.Substring(0, maxEach) : e.message); if (!string.IsNullOrEmpty(e.stack)) sb.Append("\n ").Append(e.stack.Length > maxEach ? e.stack.Substring(0, maxEach) : e.stack); } foreach (var kv in counts) if (kv.Value > 1) sb.Append("\n x").Append(kv.Value).Append(" ").Append(kv.Key); return sb.ToString(); } public static void Clear() { s_entries.Clear(); } } }