diff --git a/UnityMcpBridge/Editor/Tools/ReadConsole.cs b/UnityMcpBridge/Editor/Tools/ReadConsole.cs
index e3470cf3..4bd40090 100644
--- a/UnityMcpBridge/Editor/Tools/ReadConsole.cs
+++ b/UnityMcpBridge/Editor/Tools/ReadConsole.cs
@@ -16,6 +16,8 @@ namespace UnityMcpBridge.Editor.Tools
///
public static class ReadConsole
{
+ // (Calibration removed)
+
// Reflection members for accessing internal LogEntry data
// private static MethodInfo _getEntriesMethod; // Removed as it's unused and fails reflection
private static MethodInfo _startGettingEntriesMethod;
@@ -41,6 +43,8 @@ static ReadConsole()
);
if (logEntriesType == null)
throw new Exception("Could not find internal type UnityEditor.LogEntries");
+
+
// Include NonPublic binding flags as internal APIs might change accessibility
BindingFlags staticFlags =
@@ -100,6 +104,9 @@ static ReadConsole()
_instanceIdField = logEntryType.GetField("instanceID", instanceFlags);
if (_instanceIdField == null)
throw new Exception("Failed to reflect LogEntry.instanceID");
+
+ // (Calibration removed)
+
}
catch (Exception e)
{
@@ -251,16 +258,38 @@ bool includeStacktrace
// int instanceId = (int)_instanceIdField.GetValue(logEntryInstance);
if (string.IsNullOrEmpty(message))
+ {
continue; // Skip empty messages
+ }
+
+ // (Calibration removed)
// --- Filtering ---
- // Filter by type
- LogType currentType = GetLogTypeFromMode(mode);
- if (!types.Contains(currentType.ToString().ToLowerInvariant()))
+ // Prefer classifying severity from message/stacktrace; fallback to mode bits if needed
+ LogType unityType = InferTypeFromMessage(message);
+ bool isExplicitDebug = IsExplicitDebugLog(message);
+ if (!isExplicitDebug && unityType == LogType.Log)
{
- continue;
+ unityType = GetLogTypeFromMode(mode);
}
+ bool want;
+ // Treat Exception/Assert as errors for filtering convenience
+ if (unityType == LogType.Exception)
+ {
+ want = types.Contains("error") || types.Contains("exception");
+ }
+ else if (unityType == LogType.Assert)
+ {
+ want = types.Contains("error") || types.Contains("assert");
+ }
+ else
+ {
+ want = types.Contains(unityType.ToString().ToLowerInvariant());
+ }
+
+ if (!want) continue;
+
// Filter by text (case-insensitive)
if (
!string.IsNullOrEmpty(filterText)
@@ -294,7 +323,7 @@ bool includeStacktrace
default:
formattedEntry = new
{
- type = currentType.ToString(),
+ type = unityType.ToString(),
message = messageOnly,
file = file,
line = line,
@@ -350,15 +379,12 @@ bool includeStacktrace
// --- Internal Helpers ---
- // Mapping from LogEntry.mode bits to LogType enum
- // Based on decompiled UnityEditor code or common patterns. Precise bits might change between Unity versions.
- // See comments below for LogEntry mode bits exploration.
- // Note: This mapping is simplified and might not cover all edge cases or future Unity versions perfectly.
+ // Mapping bits from LogEntry.mode. These may vary by Unity version.
private const int ModeBitError = 1 << 0;
private const int ModeBitAssert = 1 << 1;
private const int ModeBitWarning = 1 << 2;
private const int ModeBitLog = 1 << 3;
- private const int ModeBitException = 1 << 4; // Often combined with Error bits
+ private const int ModeBitException = 1 << 4; // often combined with Error bits
private const int ModeBitScriptingError = 1 << 9;
private const int ModeBitScriptingWarning = 1 << 10;
private const int ModeBitScriptingLog = 1 << 11;
@@ -367,46 +393,75 @@ bool includeStacktrace
private static LogType GetLogTypeFromMode(int mode)
{
- // First, determine the type based on the original logic (most severe first)
- LogType initialType;
- if (
- (
- mode
- & (
- ModeBitError
- | ModeBitScriptingError
- | ModeBitException
- | ModeBitScriptingException
- )
- ) != 0
- )
- {
- initialType = LogType.Error;
- }
- else if ((mode & (ModeBitAssert | ModeBitScriptingAssertion)) != 0)
- {
- initialType = LogType.Assert;
- }
- else if ((mode & (ModeBitWarning | ModeBitScriptingWarning)) != 0)
- {
- initialType = LogType.Warning;
- }
- else
- {
- initialType = LogType.Log;
- }
+ // Preserve Unity's real type (no remapping); bits may vary by version
+ if ((mode & (ModeBitException | ModeBitScriptingException)) != 0) return LogType.Exception;
+ if ((mode & (ModeBitError | ModeBitScriptingError)) != 0) return LogType.Error;
+ if ((mode & (ModeBitAssert | ModeBitScriptingAssertion)) != 0) return LogType.Assert;
+ if ((mode & (ModeBitWarning | ModeBitScriptingWarning)) != 0) return LogType.Warning;
+ return LogType.Log;
+ }
+
+ // (Calibration helpers removed)
+
+ ///
+ /// Classifies severity using message/stacktrace content. Works across Unity versions.
+ ///
+ private static LogType InferTypeFromMessage(string fullMessage)
+ {
+ if (string.IsNullOrEmpty(fullMessage)) return LogType.Log;
+
+ // Fast path: look for explicit Debug API names in the appended stack trace
+ // e.g., "UnityEngine.Debug:LogError (object)" or "LogWarning"
+ if (fullMessage.IndexOf("LogError", StringComparison.OrdinalIgnoreCase) >= 0)
+ return LogType.Error;
+ if (fullMessage.IndexOf("LogWarning", StringComparison.OrdinalIgnoreCase) >= 0)
+ return LogType.Warning;
+
+ // Compiler diagnostics (C#): "warning CSxxxx" / "error CSxxxx"
+ if (fullMessage.IndexOf(" warning CS", StringComparison.OrdinalIgnoreCase) >= 0
+ || fullMessage.IndexOf(": warning CS", StringComparison.OrdinalIgnoreCase) >= 0)
+ return LogType.Warning;
+ if (fullMessage.IndexOf(" error CS", StringComparison.OrdinalIgnoreCase) >= 0
+ || fullMessage.IndexOf(": error CS", StringComparison.OrdinalIgnoreCase) >= 0)
+ return LogType.Error;
+
+ // Exceptions (avoid misclassifying compiler diagnostics)
+ if (fullMessage.IndexOf("Exception", StringComparison.OrdinalIgnoreCase) >= 0)
+ return LogType.Exception;
+
+ // Unity assertions
+ if (fullMessage.IndexOf("Assertion", StringComparison.OrdinalIgnoreCase) >= 0)
+ return LogType.Assert;
+
+ return LogType.Log;
+ }
- // Apply the observed "one level lower" correction
- switch (initialType)
+ private static bool IsExplicitDebugLog(string fullMessage)
+ {
+ if (string.IsNullOrEmpty(fullMessage)) return false;
+ if (fullMessage.IndexOf("Debug:Log (", StringComparison.OrdinalIgnoreCase) >= 0) return true;
+ if (fullMessage.IndexOf("UnityEngine.Debug:Log (", StringComparison.OrdinalIgnoreCase) >= 0) return true;
+ return false;
+ }
+
+ ///
+ /// Applies the "one level lower" remapping for filtering, like the old version.
+ /// This ensures compatibility with the filtering logic that expects remapped types.
+ ///
+ private static LogType GetRemappedTypeForFiltering(LogType unityType)
+ {
+ switch (unityType)
{
case LogType.Error:
return LogType.Warning; // Error becomes Warning
case LogType.Warning:
return LogType.Log; // Warning becomes Log
case LogType.Assert:
- return LogType.Assert; // Assert remains Assert (no lower level defined)
+ return LogType.Assert; // Assert remains Assert
case LogType.Log:
return LogType.Log; // Log remains Log
+ case LogType.Exception:
+ return LogType.Warning; // Exception becomes Warning
default:
return LogType.Log; // Default fallback
}