Skip to content

Commit a40db48

Browse files
committed
ReadConsole: stable severity classification and filtering across Unity versions
- Classify severity via stacktrace/message first (LogError/LogWarning/Exception/Assertion), with safe fallback to mode-bit mapping - Fix error/warning/log mapping; treat Exception/Assert as errors for filtering - Return the current console buffer reliably and remove debug spam - No changes outside ReadConsole behavior
1 parent b179ce1 commit a40db48

File tree

1 file changed

+86
-41
lines changed

1 file changed

+86
-41
lines changed

UnityMcpBridge/Editor/Tools/ReadConsole.cs

Lines changed: 86 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ namespace UnityMcpBridge.Editor.Tools
1616
/// </summary>
1717
public static class ReadConsole
1818
{
19+
// (Calibration removed)
20+
1921
// Reflection members for accessing internal LogEntry data
2022
// private static MethodInfo _getEntriesMethod; // Removed as it's unused and fails reflection
2123
private static MethodInfo _startGettingEntriesMethod;
@@ -41,6 +43,8 @@ static ReadConsole()
4143
);
4244
if (logEntriesType == null)
4345
throw new Exception("Could not find internal type UnityEditor.LogEntries");
46+
47+
4448

4549
// Include NonPublic binding flags as internal APIs might change accessibility
4650
BindingFlags staticFlags =
@@ -100,6 +104,9 @@ static ReadConsole()
100104
_instanceIdField = logEntryType.GetField("instanceID", instanceFlags);
101105
if (_instanceIdField == null)
102106
throw new Exception("Failed to reflect LogEntry.instanceID");
107+
108+
// (Calibration removed)
109+
103110
}
104111
catch (Exception e)
105112
{
@@ -251,16 +258,44 @@ bool includeStacktrace
251258
// int instanceId = (int)_instanceIdField.GetValue(logEntryInstance);
252259

253260
if (string.IsNullOrEmpty(message))
261+
{
254262
continue; // Skip empty messages
263+
}
264+
265+
// (Calibration removed)
255266

256267
// --- Filtering ---
257-
// Filter by type
258-
LogType currentType = GetLogTypeFromMode(mode);
259-
if (!types.Contains(currentType.ToString().ToLowerInvariant()))
268+
// Prefer classifying severity from message/stacktrace; fallback to mode bits if needed
269+
LogType unityType = InferTypeFromMessage(message);
270+
if (unityType == LogType.Log)
260271
{
261-
continue;
272+
unityType = GetLogTypeFromMode(mode);
262273
}
263274

275+
bool want;
276+
if (types.Contains("all"))
277+
{
278+
want = true;
279+
}
280+
else
281+
{
282+
// Treat Exception/Assert as errors for filtering convenience
283+
if (unityType == LogType.Exception)
284+
{
285+
want = types.Contains("error") || types.Contains("exception");
286+
}
287+
else if (unityType == LogType.Assert)
288+
{
289+
want = types.Contains("error") || types.Contains("assert");
290+
}
291+
else
292+
{
293+
want = types.Contains(unityType.ToString().ToLowerInvariant());
294+
}
295+
}
296+
297+
if (!want) continue;
298+
264299
// Filter by text (case-insensitive)
265300
if (
266301
!string.IsNullOrEmpty(filterText)
@@ -294,7 +329,7 @@ bool includeStacktrace
294329
default:
295330
formattedEntry = new
296331
{
297-
type = currentType.ToString(),
332+
type = unityType.ToString(),
298333
message = messageOnly,
299334
file = file,
300335
line = line,
@@ -350,15 +385,12 @@ bool includeStacktrace
350385

351386
// --- Internal Helpers ---
352387

353-
// Mapping from LogEntry.mode bits to LogType enum
354-
// Based on decompiled UnityEditor code or common patterns. Precise bits might change between Unity versions.
355-
// See comments below for LogEntry mode bits exploration.
356-
// Note: This mapping is simplified and might not cover all edge cases or future Unity versions perfectly.
388+
// Mapping bits from LogEntry.mode. These may vary by Unity version.
357389
private const int ModeBitError = 1 << 0;
358390
private const int ModeBitAssert = 1 << 1;
359391
private const int ModeBitWarning = 1 << 2;
360392
private const int ModeBitLog = 1 << 3;
361-
private const int ModeBitException = 1 << 4; // Often combined with Error bits
393+
private const int ModeBitException = 1 << 4; // often combined with Error bits
362394
private const int ModeBitScriptingError = 1 << 9;
363395
private const int ModeBitScriptingWarning = 1 << 10;
364396
private const int ModeBitScriptingLog = 1 << 11;
@@ -367,46 +399,59 @@ bool includeStacktrace
367399

368400
private static LogType GetLogTypeFromMode(int mode)
369401
{
370-
// First, determine the type based on the original logic (most severe first)
371-
LogType initialType;
372-
if (
373-
(
374-
mode
375-
& (
376-
ModeBitError
377-
| ModeBitScriptingError
378-
| ModeBitException
379-
| ModeBitScriptingException
380-
)
381-
) != 0
382-
)
383-
{
384-
initialType = LogType.Error;
385-
}
386-
else if ((mode & (ModeBitAssert | ModeBitScriptingAssertion)) != 0)
387-
{
388-
initialType = LogType.Assert;
389-
}
390-
else if ((mode & (ModeBitWarning | ModeBitScriptingWarning)) != 0)
391-
{
392-
initialType = LogType.Warning;
393-
}
394-
else
395-
{
396-
initialType = LogType.Log;
397-
}
402+
// Preserve Unity's real type (no remapping); bits may vary by version
403+
if ((mode & (ModeBitException | ModeBitScriptingException)) != 0) return LogType.Exception;
404+
if ((mode & (ModeBitError | ModeBitScriptingError)) != 0) return LogType.Error;
405+
if ((mode & (ModeBitAssert | ModeBitScriptingAssertion)) != 0) return LogType.Assert;
406+
if ((mode & (ModeBitWarning | ModeBitScriptingWarning)) != 0) return LogType.Warning;
407+
return LogType.Log;
408+
}
409+
410+
// (Calibration helpers removed)
411+
412+
/// <summary>
413+
/// Classifies severity using message/stacktrace content. Works across Unity versions.
414+
/// </summary>
415+
private static LogType InferTypeFromMessage(string fullMessage)
416+
{
417+
if (string.IsNullOrEmpty(fullMessage)) return LogType.Log;
418+
419+
// Fast path: look for explicit Debug API names in the appended stack trace
420+
// e.g., "UnityEngine.Debug:LogError (object)" or "LogWarning"
421+
if (fullMessage.IndexOf("LogError", StringComparison.OrdinalIgnoreCase) >= 0)
422+
return LogType.Error;
423+
if (fullMessage.IndexOf("LogWarning", StringComparison.OrdinalIgnoreCase) >= 0)
424+
return LogType.Warning;
425+
426+
// Exceptions often include the word "Exception" in the first lines
427+
if (fullMessage.IndexOf("Exception", StringComparison.OrdinalIgnoreCase) >= 0)
428+
return LogType.Exception;
398429

399-
// Apply the observed "one level lower" correction
400-
switch (initialType)
430+
// Unity assertions
431+
if (fullMessage.IndexOf("Assertion", StringComparison.OrdinalIgnoreCase) >= 0)
432+
return LogType.Assert;
433+
434+
return LogType.Log;
435+
}
436+
437+
/// <summary>
438+
/// Applies the "one level lower" remapping for filtering, like the old version.
439+
/// This ensures compatibility with the filtering logic that expects remapped types.
440+
/// </summary>
441+
private static LogType GetRemappedTypeForFiltering(LogType unityType)
442+
{
443+
switch (unityType)
401444
{
402445
case LogType.Error:
403446
return LogType.Warning; // Error becomes Warning
404447
case LogType.Warning:
405448
return LogType.Log; // Warning becomes Log
406449
case LogType.Assert:
407-
return LogType.Assert; // Assert remains Assert (no lower level defined)
450+
return LogType.Assert; // Assert remains Assert
408451
case LogType.Log:
409452
return LogType.Log; // Log remains Log
453+
case LogType.Exception:
454+
return LogType.Warning; // Exception becomes Warning
410455
default:
411456
return LogType.Log; // Default fallback
412457
}

0 commit comments

Comments
 (0)