62 lines
3.4 KiB
C#
62 lines
3.4 KiB
C#
// ─────────────────────────────────────────────────────────────────────────────
|
|
// 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<Entry> s_entries = new List<Entry>(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 });
|
|
}
|
|
|
|
/// <summary>최근 항목을 한 문자열로(프로브용). 같은 메시지는 횟수만 센다.</summary>
|
|
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<string, int>();
|
|
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(); }
|
|
}
|
|
}
|