Skip to content

feat: Add Unity 6 enhanced console log service with improved reliability #47

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -121,3 +121,6 @@ log.txt
log.txt.meta
Server~/build/*
Server~/node_modules/*

# Claude settings
.claude/settings.local.json
385 changes: 385 additions & 0 deletions Editor/Services/ConsoleLogsServiceUnity6.cs

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions Editor/Services/ConsoleLogsServiceUnity6.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

60 changes: 60 additions & 0 deletions Editor/Services/LogEntryModeFlags.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
namespace McpUnity.Services
{
/// <summary>
/// Unity LogEntry mode flags constants
/// Based on Unity's internal LogMessageFlags from UnityCsReference
/// https://github.com/Unity-Technologies/UnityCsReference/blob/master/Editor/Mono/LogEntries.bindings.cs
/// </summary>
public static class LogEntryModeFlags
{
// Basic log type flags (bits 0-4)
public const int kModeError = 1 << 0; // 1 (0x1)
public const int kModeAssert = 1 << 1; // 2 (0x2)
public const int kModeLog = 1 << 2; // 4 (0x4)
public const int kModeWarning = 1 << 3; // 8 (0x8)
public const int kModeException = 1 << 4; // 16 (0x10)

// Scripting related flags (bits 8-12)
public const int kScriptingError = 1 << 8; // 256 (0x100)
public const int kScriptingWarning = 1 << 9; // 512 (0x200)
public const int kScriptingLog = 1 << 10; // 1024 (0x400)
public const int kScriptCompileError = 1 << 11; // 2048 (0x800)
public const int kScriptCompileWarning = 1 << 12; // 4096 (0x1000)

// Observed composite values from debugging
// These include additional undocumented high bits
public const int ObservedCompilerWarning = 266240; // 0x41000 (bits: 18, 10)
public const int ObservedCompilerError = 272384; // 0x42800 (bits: 18, 14, 10)
public const int ObservedShaderError = 262212; // 0x40044 (bits: 18, 6, 2)
public const int ObservedRuntimeWarning = 8405504; // 0x804200 (bits: 23, 18, 9)
public const int ObservedRuntimeError = 8405248; // 0x804100 (bits: 23, 18, 8)
Comment on lines +29 to +30
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Add handling for unused runtime flag constants.

The ObservedRuntimeWarning and ObservedRuntimeError constants are defined but not used in the GetLogTypeFromMode method. This appears to be an oversight.

Add the missing runtime flag checks:

 public static string GetLogTypeFromMode(int mode)
 {
     // Check for observed compiler/shader message patterns first
     if (mode == ObservedCompilerError) return "Error";
     if (mode == ObservedCompilerWarning) return "Warning";
     if (mode == ObservedShaderError) return "Error";
+    if (mode == ObservedRuntimeError) return "Error";
+    if (mode == ObservedRuntimeWarning) return "Warning";
     
     // Check for script compile errors/warnings

Also applies to: 35-58

🤖 Prompt for AI Agents
In Editor/Services/LogEntryModeFlags.cs around lines 29-30 and 35-58, the
constants ObservedRuntimeWarning and ObservedRuntimeError are defined but not
checked in the GetLogTypeFromMode method. To fix this, add conditions in
GetLogTypeFromMode to detect these flags and return the appropriate log types
for runtime warnings and errors, ensuring these constants are properly handled
in the method's logic.


/// <summary>
/// Determine log type from mode flags
/// </summary>
public static string GetLogTypeFromMode(int mode)
{
// Check for observed compiler/shader message patterns first
if (mode == ObservedCompilerError) return "Error";
if (mode == ObservedCompilerWarning) return "Warning";
if (mode == ObservedShaderError) return "Error";

// Check for script compile errors/warnings
if ((mode & kScriptCompileError) != 0) return "Error";
if ((mode & kScriptCompileWarning) != 0) return "Warning";

// Check for scripting errors/warnings
if ((mode & kScriptingError) != 0) return "Error";
if ((mode & kScriptingWarning) != 0) return "Warning";

// Then check standard flags
if ((mode & kModeError) != 0) return "Error";
if ((mode & kModeAssert) != 0) return "Assert";
if ((mode & kModeException) != 0) return "Exception";
if ((mode & kModeWarning) != 0) return "Warning";
if ((mode & kModeLog) != 0) return "Log";

return "Log"; // Default to Log instead of Unknown
}
}
}
11 changes: 11 additions & 0 deletions Editor/Services/LogEntryModeFlags.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

84 changes: 84 additions & 0 deletions Editor/Services/Unity6InternalAPIReference.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
# Unity 6 Internal API Reference

## LogEntry Structure

Unity's internal `LogEntry` structure contains the following fields:

### Fields
| Field Name | Type | Description |
|------------|------|-------------|
| message | String | Full message including stack trace |
| file | String | Source file path |
| line | Int32 | Line number |
| column | Int32 | Column number (-1 if not available) |
| mode | Int32 | Log type flags (see Mode Flags section) |
| instanceID | Int32 | Instance ID of the object |
| identifier | Int32 | Unique identifier |
| globalLineIndex | Int32 | Global line index in console |
| callstackTextStartUTF8 | Int32 | UTF-8 byte position where stack trace starts |
| callstackTextStartUTF16 | Int32 | UTF-16 character position where stack trace starts |

## Mode Flags

### Standard Unity Log Flags (from UnityCsReference)
```csharp
// Basic log types
const int kModeError = 1 << 0; // 1 (0x1)
const int kModeAssert = 1 << 1; // 2 (0x2)
const int kModeLog = 1 << 2; // 4 (0x4)
const int kModeWarning = 1 << 3; // 8 (0x8)
const int kModeException = 1 << 4; // 16 (0x10)

// Scripting related flags
const int kScriptingError = 1 << 8; // 256 (0x100)
const int kScriptingWarning = 1 << 9; // 512 (0x200)
const int kScriptingLog = 1 << 10; // 1024 (0x400)
const int kScriptCompileError = 1 << 11; // 2048 (0x800)
const int kScriptCompileWarning = 1 << 12; // 4096 (0x1000)
```

### Observed Compiler/Shader Message Values (from debugging)
```csharp
// These are composite values with multiple flags set
const int ObservedCompilerWarning = 266240; // 0x41000 (bits: 18, 10)
const int ObservedCompilerError = 272384; // 0x42800 (bits: 18, 14, 10)
const int ObservedShaderError = 262212; // 0x40044 (bits: 18, 6, 2)
```

Note: The observed values include additional high bits (2, 6, 10, 14, 18) beyond the documented flags, suggesting Unity may be using undocumented internal flags.

## Important Findings

1. **Compiler messages use special mode values**
- C# compilation errors (e.g., `error CS0103`) have mode = 272384
- C# compilation warnings (e.g., `warning CS0414`) have mode = 266240
- These do NOT use the standard error/warning flags!

2. **Shader errors**
- Shader compilation errors appear to use standard Log mode (4)
- Need message content analysis to properly classify

3. **Stack trace separation**
- Use `callstackTextStartUTF16` for C# strings (preferred)
- Fallback to `callstackTextStartUTF8` if needed
- Unity provides exact position where stack trace begins

## Usage Notes

- Always check special compiler flags before standard flags
- Message content analysis may still be needed for some error types
- The mode field alone is not sufficient for all classification needs

## Example Mode Analysis

```
Warning CS0414: mode = 266240 = 0x41000
Binary: 1000001000000000000
Bits set: 18, 10

Error CS0103: mode = 272384 = 0x42800
Binary: 1000010100000000000
Bits set: 18, 14, 10
```

The high bits (10, 14, 18) appear to indicate compiler-related messages.
7 changes: 7 additions & 0 deletions Editor/Services/Unity6InternalAPIReference.md.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

24 changes: 24 additions & 0 deletions Editor/UnityBridge/McpUnityEditorWindow.cs
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,30 @@ private void DrawServerTab()
settings.SaveSettings();
}

EditorGUILayout.Space();

// Console log service selection
ConsoleLogServiceType newConsoleLogService = (ConsoleLogServiceType)EditorGUILayout.EnumPopup(
new GUIContent("Console Log Service", "Select console log service implementation. EventBased is safe but may miss some logs. Unity6Enhanced uses internal APIs for better reliability but requires Unity 6+. Server restart required when changed."),
settings.ConsoleLogService);
if (newConsoleLogService != settings.ConsoleLogService)
{
settings.ConsoleLogService = newConsoleLogService;
settings.SaveSettings();

// Show warning for Unity6Enhanced
if (newConsoleLogService == ConsoleLogServiceType.Unity6Enhanced)
{
#if UNITY_6000_0_OR_NEWER
EditorUtility.DisplayDialog("Console Log Service Changed",
"Unity 6 enhanced console log service selected. This uses internal Unity APIs for better reliability but may break in future Unity versions.\n\nRestart the MCP server for changes to take effect.", "OK");
#else
EditorUtility.DisplayDialog("Console Log Service Warning",
$"Unity 6 enhanced console log service selected but current Unity version is {Application.unityVersion}. The service will fall back to event-based implementation.\n\nRestart the MCP server for changes to take effect.", "OK");
#endif
}
}

EditorGUILayout.Space();

// Server control buttons
Expand Down
24 changes: 21 additions & 3 deletions Editor/UnityBridge/McpUnityServer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public class McpUnityServer
private WebSocketServer _webSocketServer;
private CancellationTokenSource _cts;
private TestRunnerService _testRunnerService;
private ConsoleLogsService _consoleLogsService;
private IConsoleLogsService _consoleLogsService;

/// <summary>
/// Static constructor that gets called when Unity loads due to InitializeOnLoad attribute
Expand Down Expand Up @@ -249,8 +249,26 @@ private void InitializeServices()
// Initialize the test runner service
_testRunnerService = new TestRunnerService();

// Initialize the console logs service
_consoleLogsService = new ConsoleLogsService();
// Initialize the console logs service based on settings and Unity version
// Default to safe event-based implementation
var consoleLogService = McpUnitySettings.Instance.ConsoleLogService;

if (consoleLogService == ConsoleLogServiceType.Unity6Enhanced)
{
#if UNITY_6000_0_OR_NEWER
_consoleLogsService = new ConsoleLogsServiceUnity6();
McpLogger.LogInfo($"[MCP Unity] Console Log Service: Unity 6 Enhanced (experimental, uses internal APIs)");
#else
McpLogger.LogWarning($"[MCP Unity] Console Log Service: Unity 6 Enhanced requested but Unity version is {Application.unityVersion}. Falling back to Event-Based service.");
_consoleLogsService = new ConsoleLogsService();
#endif
}
else
{
// Default to safe event-based implementation
_consoleLogsService = new ConsoleLogsService();
McpLogger.LogInfo($"[MCP Unity] Console Log Service: Event-Based (default, safe)");
}
}
}
}
15 changes: 15 additions & 0 deletions Editor/UnityBridge/McpUnitySettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,18 @@

namespace McpUnity.Unity
{
/// <summary>
/// Console log service implementation options
/// </summary>
public enum ConsoleLogServiceType
{
[Tooltip("Event-based implementation (default, safe) - may occasionally miss logs")]
EventBased,

[Tooltip("Unity 6 enhanced implementation (experimental) - uses internal APIs for better reliability")]
Unity6Enhanced
}

/// <summary>
/// Handles persistence of MCP Unity settings
/// </summary>
Expand Down Expand Up @@ -36,6 +48,9 @@ public class McpUnitySettings

[Tooltip("Optional: Full path to the npm executable (e.g., /Users/user/.asdf/shims/npm or C:\\path\\to\\npm.cmd). If not set, 'npm' from the system PATH will be used.")]
public string NpmExecutablePath = string.Empty;

[Tooltip("Console log service implementation to use. EventBased (default, safe) may occasionally miss logs. Unity6Enhanced uses internal APIs for better reliability but requires Unity 6+ and should only be used when explicitly needed. Server restart required when changed.")]
public ConsoleLogServiceType ConsoleLogService = ConsoleLogServiceType.EventBased;

/// <summary>
/// Singleton instance of settings
Expand Down