@@ -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