From 4b5ae0fecd97e23bc42b9143b1ed6c71dfeb3943 Mon Sep 17 00:00:00 2001 From: Doug Frazier Date: Sun, 26 Apr 2026 15:57:01 -0700 Subject: [PATCH] fix: resolve Roslyn assemblies on macOS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On macOS, EditorApplication.applicationPath points to the Unity.app bundle itself (e.g. /Applications/Unity/Hub/Editor/2022.3.62f2/Unity.app). The previous code called Path.GetDirectoryName() on that path and then appended 'Data/...' — a layout that only exists on Windows and Linux. On macOS the Roslyn DLLs live inside Unity.app/Contents/..., so TryLoadRoslyn() never found them and ExecuteCode always returned the 'Roslyn is not available' error. Fix: detect when applicationPath ends in '.app' and add Unity.app/Contents as an additional data root alongside the existing Windows/Linux root. Also adds Tools/ScriptUpdater as a search location (ships Mono-compatible Roslyn assemblies in all 2022.3.x builds). Tested on macOS (Unity 2022.3.62f2, Apple Silicon). --- Editor/MCPEditorCommands.cs | 45 +++++++++++++++++++++++++++---------- 1 file changed, 33 insertions(+), 12 deletions(-) diff --git a/Editor/MCPEditorCommands.cs b/Editor/MCPEditorCommands.cs index 3022d49..562b9d0 100755 --- a/Editor/MCPEditorCommands.cs +++ b/Editor/MCPEditorCommands.cs @@ -95,18 +95,39 @@ private static bool TryLoadRoslyn() // If not already loaded, try to find and load them from the Unity editor directory if (_roslynCSharpAsm == null || _roslynCoreAsm == null) { - string editorDir = Path.GetDirectoryName(EditorApplication.applicationPath); - string managedDir = Path.Combine(editorDir, "Data", "Managed"); - string toolsDir = Path.Combine(editorDir, "Data", "Tools", "Roslyn"); - // Mono-compatible Roslyn assemblies (preferred for Unity's Mono runtime) - string monoDir = Path.Combine(editorDir, "Data", "MonoBleedingEdge", "lib", "mono", "4.5"); - string msbuildRoslynDir = Path.Combine(editorDir, "Data", "MonoBleedingEdge", "lib", "mono", "msbuild", "Current", "bin", "Roslyn"); - // ApiUpdater has full Roslyn assemblies - string apiUpdaterDir = Path.Combine(editorDir, "Data", "Tools", "BuildPipeline", "Compilation", "ApiUpdater"); - // DotNetSdkRoslyn contains .NET Core assemblies — may fail on Mono, tried last - string sdkRoslynDir = Path.Combine(editorDir, "Data", "DotNetSdkRoslyn"); - - foreach (var searchDir in new[] { managedDir, toolsDir, monoDir, msbuildRoslynDir, apiUpdaterDir, sdkRoslynDir, editorDir }) + // Resolve the editor's "Data" directory across platforms. + // Windows: /Data/... + // macOS: EditorApplication.applicationPath ends in "Unity.app"; Data lives at Unity.app/Contents + // Linux: /Data/... (same as Windows) + string appPath = EditorApplication.applicationPath; + string editorDir = Path.GetDirectoryName(appPath); + var dataRoots = new List(); + // Windows / Linux layout + if (!string.IsNullOrEmpty(editorDir)) + dataRoots.Add(Path.Combine(editorDir, "Data")); + // macOS layout: Unity.app/Contents + if (!string.IsNullOrEmpty(appPath) && appPath.EndsWith(".app", StringComparison.OrdinalIgnoreCase)) + dataRoots.Add(Path.Combine(appPath, "Contents")); + + var searchDirs = new List(); + foreach (var data in dataRoots) + { + searchDirs.Add(Path.Combine(data, "Managed")); + searchDirs.Add(Path.Combine(data, "Tools", "Roslyn")); + // Mono-compatible Roslyn assemblies (preferred for Unity's Mono runtime) + searchDirs.Add(Path.Combine(data, "MonoBleedingEdge", "lib", "mono", "4.5")); + searchDirs.Add(Path.Combine(data, "MonoBleedingEdge", "lib", "mono", "msbuild", "Current", "bin", "Roslyn")); + // ApiUpdater has full Roslyn assemblies + searchDirs.Add(Path.Combine(data, "Tools", "BuildPipeline", "Compilation", "ApiUpdater")); + // ScriptUpdater also ships Roslyn (Mono-compatible) + searchDirs.Add(Path.Combine(data, "Tools", "ScriptUpdater")); + // DotNetSdkRoslyn contains .NET Core assemblies — may fail on Mono, tried last + searchDirs.Add(Path.Combine(data, "DotNetSdkRoslyn")); + } + if (!string.IsNullOrEmpty(editorDir)) + searchDirs.Add(editorDir); + + foreach (var searchDir in searchDirs) { if (!Directory.Exists(searchDir)) continue; if (_roslynCoreAsm == null)