@@ -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,38 @@ 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+ bool isExplicitDebug = IsExplicitDebugLog ( message ) ;
271+ if ( ! isExplicitDebug && unityType == LogType . Log )
260272 {
261- continue ;
273+ unityType = GetLogTypeFromMode ( mode ) ;
262274 }
263275
276+ bool want ;
277+ // Treat Exception/Assert as errors for filtering convenience
278+ if ( unityType == LogType . Exception )
279+ {
280+ want = types . Contains ( "error" ) || types . Contains ( "exception" ) ;
281+ }
282+ else if ( unityType == LogType . Assert )
283+ {
284+ want = types . Contains ( "error" ) || types . Contains ( "assert" ) ;
285+ }
286+ else
287+ {
288+ want = types . Contains ( unityType . ToString ( ) . ToLowerInvariant ( ) ) ;
289+ }
290+
291+ if ( ! want ) continue ;
292+
264293 // Filter by text (case-insensitive)
265294 if (
266295 ! string . IsNullOrEmpty ( filterText )
@@ -294,7 +323,7 @@ bool includeStacktrace
294323 default :
295324 formattedEntry = new
296325 {
297- type = currentType . ToString ( ) ,
326+ type = unityType . ToString ( ) ,
298327 message = messageOnly ,
299328 file = file ,
300329 line = line ,
@@ -350,15 +379,12 @@ bool includeStacktrace
350379
351380 // --- Internal Helpers ---
352381
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.
382+ // Mapping bits from LogEntry.mode. These may vary by Unity version.
357383 private const int ModeBitError = 1 << 0 ;
358384 private const int ModeBitAssert = 1 << 1 ;
359385 private const int ModeBitWarning = 1 << 2 ;
360386 private const int ModeBitLog = 1 << 3 ;
361- private const int ModeBitException = 1 << 4 ; // Often combined with Error bits
387+ private const int ModeBitException = 1 << 4 ; // often combined with Error bits
362388 private const int ModeBitScriptingError = 1 << 9 ;
363389 private const int ModeBitScriptingWarning = 1 << 10 ;
364390 private const int ModeBitScriptingLog = 1 << 11 ;
@@ -367,46 +393,75 @@ bool includeStacktrace
367393
368394 private static LogType GetLogTypeFromMode ( int mode )
369395 {
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- }
396+ // Preserve Unity's real type (no remapping); bits may vary by version
397+ if ( ( mode & ( ModeBitException | ModeBitScriptingException ) ) != 0 ) return LogType . Exception ;
398+ if ( ( mode & ( ModeBitError | ModeBitScriptingError ) ) != 0 ) return LogType . Error ;
399+ if ( ( mode & ( ModeBitAssert | ModeBitScriptingAssertion ) ) != 0 ) return LogType . Assert ;
400+ if ( ( mode & ( ModeBitWarning | ModeBitScriptingWarning ) ) != 0 ) return LogType . Warning ;
401+ return LogType . Log ;
402+ }
403+
404+ // (Calibration helpers removed)
405+
406+ /// <summary>
407+ /// Classifies severity using message/stacktrace content. Works across Unity versions.
408+ /// </summary>
409+ private static LogType InferTypeFromMessage ( string fullMessage )
410+ {
411+ if ( string . IsNullOrEmpty ( fullMessage ) ) return LogType . Log ;
412+
413+ // Fast path: look for explicit Debug API names in the appended stack trace
414+ // e.g., "UnityEngine.Debug:LogError (object)" or "LogWarning"
415+ if ( fullMessage . IndexOf ( "LogError" , StringComparison . OrdinalIgnoreCase ) >= 0 )
416+ return LogType . Error ;
417+ if ( fullMessage . IndexOf ( "LogWarning" , StringComparison . OrdinalIgnoreCase ) >= 0 )
418+ return LogType . Warning ;
419+
420+ // Compiler diagnostics (C#): "warning CSxxxx" / "error CSxxxx"
421+ if ( fullMessage . IndexOf ( " warning CS" , StringComparison . OrdinalIgnoreCase ) >= 0
422+ || fullMessage . IndexOf ( ": warning CS" , StringComparison . OrdinalIgnoreCase ) >= 0 )
423+ return LogType . Warning ;
424+ if ( fullMessage . IndexOf ( " error CS" , StringComparison . OrdinalIgnoreCase ) >= 0
425+ || fullMessage . IndexOf ( ": error CS" , StringComparison . OrdinalIgnoreCase ) >= 0 )
426+ return LogType . Error ;
427+
428+ // Exceptions (avoid misclassifying compiler diagnostics)
429+ if ( fullMessage . IndexOf ( "Exception" , StringComparison . OrdinalIgnoreCase ) >= 0 )
430+ return LogType . Exception ;
431+
432+ // Unity assertions
433+ if ( fullMessage . IndexOf ( "Assertion" , StringComparison . OrdinalIgnoreCase ) >= 0 )
434+ return LogType . Assert ;
435+
436+ return LogType . Log ;
437+ }
398438
399- // Apply the observed "one level lower" correction
400- switch ( initialType )
439+ private static bool IsExplicitDebugLog ( string fullMessage )
440+ {
441+ if ( string . IsNullOrEmpty ( fullMessage ) ) return false ;
442+ if ( fullMessage . IndexOf ( "Debug:Log (" , StringComparison . OrdinalIgnoreCase ) >= 0 ) return true ;
443+ if ( fullMessage . IndexOf ( "UnityEngine.Debug:Log (" , StringComparison . OrdinalIgnoreCase ) >= 0 ) return true ;
444+ return false ;
445+ }
446+
447+ /// <summary>
448+ /// Applies the "one level lower" remapping for filtering, like the old version.
449+ /// This ensures compatibility with the filtering logic that expects remapped types.
450+ /// </summary>
451+ private static LogType GetRemappedTypeForFiltering ( LogType unityType )
452+ {
453+ switch ( unityType )
401454 {
402455 case LogType . Error :
403456 return LogType . Warning ; // Error becomes Warning
404457 case LogType . Warning :
405458 return LogType . Log ; // Warning becomes Log
406459 case LogType . Assert :
407- return LogType . Assert ; // Assert remains Assert (no lower level defined)
460+ return LogType . Assert ; // Assert remains Assert
408461 case LogType . Log :
409462 return LogType . Log ; // Log remains Log
463+ case LogType . Exception :
464+ return LogType . Warning ; // Exception becomes Warning
410465 default :
411466 return LogType . Log ; // Default fallback
412467 }
0 commit comments