Skip to content
Open
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
36 changes: 31 additions & 5 deletions MCPForUnity/Editor/Setup/RoslynInstaller.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using System.IO;
using System.IO.Compression;
using System.Reflection;
using UnityEditor;
using UnityEngine;
using UnityEngine.Networking;
Expand All @@ -13,19 +14,44 @@ public static class RoslynInstaller

private static readonly (string packageId, string version, string dllPath, string dllName)[] NuGetEntries =
{
("microsoft.codeanalysis.common", "4.12.0", "lib/netstandard2.0/Microsoft.CodeAnalysis.dll", "Microsoft.CodeAnalysis.dll"),
("microsoft.codeanalysis.csharp", "4.12.0", "lib/netstandard2.0/Microsoft.CodeAnalysis.CSharp.dll","Microsoft.CodeAnalysis.CSharp.dll"),
("system.collections.immutable", "8.0.0", "lib/netstandard2.0/System.Collections.Immutable.dll", "System.Collections.Immutable.dll"),
("system.reflection.metadata", "8.0.0", "lib/netstandard2.0/System.Reflection.Metadata.dll", "System.Reflection.Metadata.dll"),
("microsoft.codeanalysis.common", "4.12.0", "lib/netstandard2.0/Microsoft.CodeAnalysis.dll", "Microsoft.CodeAnalysis.dll"),
("microsoft.codeanalysis.csharp", "4.12.0", "lib/netstandard2.0/Microsoft.CodeAnalysis.CSharp.dll", "Microsoft.CodeAnalysis.CSharp.dll"),
("system.collections.immutable", "8.0.0", "lib/netstandard2.0/System.Collections.Immutable.dll", "System.Collections.Immutable.dll"),
("system.reflection.metadata", "8.0.0", "lib/netstandard2.0/System.Reflection.Metadata.dll", "System.Reflection.Metadata.dll"),
// Transitive dep of Microsoft.CodeAnalysis.* on netstandard2.0. Without it, Roslyn's StringTable
// static cctor throws FileNotFoundException for v6.0.0.0 and every Roslyn entry point fails to
// initialize. Unity ships a v4.x of this assembly which does NOT satisfy the v6 reference.
("system.runtime.compilerservices.unsafe","6.0.0", "lib/netstandard2.0/System.Runtime.CompilerServices.Unsafe.dll", "System.Runtime.CompilerServices.Unsafe.dll"),
Comment thread
coderabbitai[bot] marked this conversation as resolved.
};

public static bool IsInstalled()
{
string folder = Path.Combine(Application.dataPath, PluginsRelPath);
foreach (var entry in NuGetEntries)
{
if (!File.Exists(Path.Combine(folder, entry.dllName)))
string path = Path.Combine(folder, entry.dllName);
if (!File.Exists(path))
return false;

// Defense-in-depth: a stale DLL whose assembly version is older than what
// Roslyn references (e.g. a v4.x System.Runtime.CompilerServices.Unsafe
// shadowing the v6 we actually need) would still satisfy file-existence but
// leave Roslyn unable to load. Compare the on-disk assembly version against
// each entry's declared NuGet version, treating "older or unreadable" as not
// installed so Install() can rewrite it.
if (Version.TryParse(entry.version, out var requiredVersion))
{
try
{
var actual = AssemblyName.GetAssemblyName(path).Version;
if (actual == null || actual < requiredVersion)
return false;
}
catch
{
return false;
}
}
}
return true;
}
Expand Down
8 changes: 7 additions & 1 deletion MCPForUnity/Editor/Tools/ExecuteCode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -672,7 +672,13 @@ public static Assembly Compile(string source, string[] assemblyPaths, out List<s
}
catch (Exception e)
{
errors.Add($"Roslyn compilation error: {e.Message}");
// Walk to the deepest cause: TargetInvocationException (and friends) wrap the real
// failure inside .InnerException, and reporting only e.Message hides everything
// useful (e.g. a missing transitive dep manifests as the generic "Exception has been
// thrown by the target of an invocation.").
Exception root = e;
while (root.InnerException != null) root = root.InnerException;
errors.Add($"Roslyn compilation error: {root.GetType().Name}: {root.Message}");
return null;
}
}
Expand Down