Skip to content

Commit f423c2f

Browse files
committed
Revert "Update for Custom_Tool Fix and Detection"
This reverts commit ae8cfe5.
1 parent ae8cfe5 commit f423c2f

19 files changed

+348
-846
lines changed

CustomTools/RoslynRuntimeCompilation/ManageRuntimeCompilation.cs

Lines changed: 54 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,9 @@ namespace MCPForUnity.Editor.Tools
1919
{
2020
/// <summary>
2121
/// Runtime compilation tool for MCP Unity.
22-
/// Compiles and loads C# code at runtime without triggering domain reload via Roslyn Runtime Compilation, where in traditional Unity workflow it would take seconds to reload assets and reset script states for each script change.
22+
/// Compiles and loads C# code at runtime without triggering domain reload.
2323
/// </summary>
24-
[McpForUnityTool(
25-
name:"runtime_compilation",
26-
Description = "Enable runtime compilation of C# code within Unity without domain reload via Roslyn.")]
24+
[McpForUnityTool("runtime_compilation")]
2725
public static class ManageRuntimeCompilation
2826
{
2927
private static readonly Dictionary<string, LoadedAssemblyInfo> LoadedAssemblies = new Dictionary<string, LoadedAssemblyInfo>();
@@ -44,7 +42,7 @@ public static object HandleCommand(JObject @params)
4442

4543
if (string.IsNullOrEmpty(action))
4644
{
47-
return new ErrorResponse("Action parameter is required. Valid actions: compile_and_load, list_loaded, get_types, execute_with_roslyn, get_history, save_history, clear_history");
45+
return Response.Error("Action parameter is required. Valid actions: compile_and_load, list_loaded, get_types, execute_with_roslyn, get_history, save_history, clear_history");
4846
}
4947

5048
switch (action)
@@ -71,28 +69,31 @@ public static object HandleCommand(JObject @params)
7169
return ClearCompilationHistory();
7270

7371
default:
74-
return new ErrorResponse($"Unknown action '{action}'. Valid actions: compile_and_load, list_loaded, get_types, execute_with_roslyn, get_history, save_history, clear_history");
72+
return Response.Error($"Unknown action '{action}'. Valid actions: compile_and_load, list_loaded, get_types, execute_with_roslyn, get_history, save_history, clear_history");
7573
}
7674
}
7775

7876
private static object CompileAndLoad(JObject @params)
7977
{
8078
#if !USE_ROSLYN
81-
return new ErrorResponse(
79+
return Response.Error(
8280
"Runtime compilation requires Roslyn. Please install Microsoft.CodeAnalysis.CSharp NuGet package and add USE_ROSLYN to Scripting Define Symbols. " +
8381
"See ManageScript.cs header for installation instructions."
8482
);
8583
#else
8684
try
8785
{
8886
string code = @params["code"]?.ToString();
89-
string assemblyName = @params["assembly_name"]?.ToString() ?? $"DynamicAssembly_{DateTime.Now.Ticks}";
87+
var assemblyToken = @params["assembly_name"];
88+
string assemblyName = assemblyToken == null || string.IsNullOrWhiteSpace(assemblyToken.ToString())
89+
? $"DynamicAssembly_{DateTime.Now.Ticks}"
90+
: assemblyToken.ToString().Trim();
9091
string attachTo = @params["attach_to"]?.ToString();
9192
bool loadImmediately = @params["load_immediately"]?.ToObject<bool>() ?? true;
9293

9394
if (string.IsNullOrEmpty(code))
9495
{
95-
return new ErrorResponse("'code' parameter is required");
96+
return Response.Error("'code' parameter is required");
9697
}
9798

9899
// Ensure unique assembly name
@@ -103,8 +104,21 @@ private static object CompileAndLoad(JObject @params)
103104

104105
// Create output directory
105106
Directory.CreateDirectory(DynamicAssembliesPath);
106-
string dllPath = Path.Combine(DynamicAssembliesPath, $"{assemblyName}.dll");
107-
107+
string basePath = Path.GetFullPath(DynamicAssembliesPath);
108+
Directory.CreateDirectory(basePath);
109+
string safeFileName = SanitizeAssemblyFileName(assemblyName);
110+
string dllPath = Path.GetFullPath(Path.Combine(basePath, $"{safeFileName}.dll"));
111+
112+
if (!dllPath.StartsWith(basePath, StringComparison.Ordinal))
113+
{
114+
return Response.Error("Assembly name must resolve inside the dynamic assemblies directory.");
115+
}
116+
117+
if (File.Exists(dllPath))
118+
{
119+
dllPath = Path.GetFullPath(Path.Combine(basePath, $"{safeFileName}_{DateTime.Now.Ticks}.dll"));
120+
}
121+
108122
// Parse code
109123
var syntaxTree = CSharpSyntaxTree.ParseText(code);
110124

@@ -123,7 +137,7 @@ private static object CompileAndLoad(JObject @params)
123137

124138
// Emit to file
125139
EmitResult emitResult;
126-
using (var stream = new FileStream(dllPath, FileMode.Create))
140+
using (var stream = new FileStream(dllPath, FileMode.Create, FileAccess.Write, FileShare.None))
127141
{
128142
emitResult = compilation.Emit(stream);
129143
}
@@ -142,7 +156,7 @@ private static object CompileAndLoad(JObject @params)
142156
})
143157
.ToList();
144158

145-
return new ErrorResponse("Compilation failed", new
159+
return Response.Error("Compilation failed", new
146160
{
147161
errors = errors,
148162
error_count = errors.Count
@@ -208,7 +222,7 @@ private static object CompileAndLoad(JObject @params)
208222
}
209223
}
210224

211-
return new SuccessResponse("Runtime compilation completed successfully", new
225+
return Response.Success("Runtime compilation completed successfully", new
212226
{
213227
assembly_name = assemblyName,
214228
dll_path = dllPath,
@@ -221,15 +235,15 @@ private static object CompileAndLoad(JObject @params)
221235
}
222236
catch (Exception ex)
223237
{
224-
return new ErrorResponse($"Runtime compilation failed: {ex.Message}", new
238+
return Response.Error($"Runtime compilation failed: {ex.Message}", new
225239
{
226240
exception = ex.GetType().Name,
227241
stack_trace = ex.StackTrace
228242
});
229243
}
230244
#endif
231245
}
232-
246+
233247
private static object ListLoadedAssemblies()
234248
{
235249
var assemblies = LoadedAssemblies.Values.Select(info => new
@@ -240,26 +254,33 @@ private static object ListLoadedAssemblies()
240254
type_count = info.TypeNames.Count,
241255
types = info.TypeNames
242256
}).ToList();
243-
244-
return new SuccessResponse($"Found {assemblies.Count} loaded dynamic assemblies", new
257+
258+
return Response.Success($"Found {assemblies.Count} loaded dynamic assemblies", new
245259
{
246260
count = assemblies.Count,
247261
assemblies = assemblies
248262
});
249263
}
250264

265+
private static string SanitizeAssemblyFileName(string assemblyName)
266+
{
267+
var invalidChars = Path.GetInvalidFileNameChars();
268+
var sanitized = new string(assemblyName.Where(c => !invalidChars.Contains(c)).ToArray());
269+
return string.IsNullOrWhiteSpace(sanitized) ? $"DynamicAssembly_{DateTime.Now.Ticks}" : sanitized;
270+
}
271+
251272
private static object GetAssemblyTypes(JObject @params)
252273
{
253274
string assemblyName = @params["assembly_name"]?.ToString();
254275

255276
if (string.IsNullOrEmpty(assemblyName))
256277
{
257-
return new ErrorResponse("'assembly_name' parameter is required");
278+
return Response.Error("'assembly_name' parameter is required");
258279
}
259280

260281
if (!LoadedAssemblies.TryGetValue(assemblyName, out var info))
261282
{
262-
return new ErrorResponse($"Assembly '{assemblyName}' not found in loaded assemblies");
283+
return Response.Error($"Assembly '{assemblyName}' not found in loaded assemblies");
263284
}
264285

265286
var types = info.Assembly.GetTypes().Select(t => new
@@ -273,7 +294,7 @@ private static object GetAssemblyTypes(JObject @params)
273294
base_type = t.BaseType?.FullName
274295
}).ToList();
275296

276-
return new SuccessResponse($"Retrieved {types.Count} types from {assemblyName}", new
297+
return Response.Success($"Retrieved {types.Count} types from {assemblyName}", new
277298
{
278299
assembly_name = assemblyName,
279300
type_count = types.Count,
@@ -297,7 +318,7 @@ private static object ExecuteWithRoslyn(JObject @params)
297318

298319
if (string.IsNullOrEmpty(code))
299320
{
300-
return new ErrorResponse("'code' parameter is required");
321+
return Response.Error("'code' parameter is required");
301322
}
302323

303324
// Get or create the RoslynRuntimeCompiler instance
@@ -315,7 +336,7 @@ private static object ExecuteWithRoslyn(JObject @params)
315336

316337
if (targetObject == null)
317338
{
318-
return new ErrorResponse($"Target GameObject '{targetObjectName}' not found");
339+
return Response.Error($"Target GameObject '{targetObjectName}' not found");
319340
}
320341
}
321342

@@ -331,7 +352,7 @@ out string errorMessage
331352

332353
if (success)
333354
{
334-
return new SuccessResponse($"Code compiled and executed successfully", new
355+
return Response.Success($"Code compiled and executed successfully", new
335356
{
336357
class_name = className,
337358
method_name = methodName,
@@ -342,15 +363,15 @@ out string errorMessage
342363
}
343364
else
344365
{
345-
return new ErrorResponse($"Execution failed: {errorMessage}", new
366+
return Response.Error($"Execution failed: {errorMessage}", new
346367
{
347368
diagnostics = compiler.lastCompileDiagnostics
348369
});
349370
}
350371
}
351372
catch (Exception ex)
352373
{
353-
return new ErrorResponse($"Failed to execute with Roslyn: {ex.Message}", new
374+
return Response.Error($"Failed to execute with Roslyn: {ex.Message}", new
354375
{
355376
exception = ex.GetType().Name,
356377
stack_trace = ex.StackTrace
@@ -381,15 +402,15 @@ private static object GetCompilationHistory()
381402
: entry.sourceCode
382403
}).ToList();
383404

384-
return new SuccessResponse($"Retrieved {historyData.Count} history entries", new
405+
return Response.Success($"Retrieved {historyData.Count} history entries", new
385406
{
386407
count = historyData.Count,
387408
history = historyData
388409
});
389410
}
390411
catch (Exception ex)
391412
{
392-
return new ErrorResponse($"Failed to get history: {ex.Message}");
413+
return Response.Error($"Failed to get history: {ex.Message}");
393414
}
394415
}
395416

@@ -404,20 +425,20 @@ private static object SaveCompilationHistory()
404425

405426
if (compiler.SaveHistoryToFile(out string savedPath, out string error))
406427
{
407-
return new SuccessResponse($"History saved successfully", new
428+
return Response.Success($"History saved successfully", new
408429
{
409430
path = savedPath,
410431
entry_count = compiler.CompilationHistory.Count
411432
});
412433
}
413434
else
414435
{
415-
return new ErrorResponse($"Failed to save history: {error}");
436+
return Response.Error($"Failed to save history: {error}");
416437
}
417438
}
418439
catch (Exception ex)
419440
{
420-
return new ErrorResponse($"Failed to save history: {ex.Message}");
441+
return Response.Error($"Failed to save history: {ex.Message}");
421442
}
422443
}
423444

@@ -432,11 +453,11 @@ private static object ClearCompilationHistory()
432453
int count = compiler.CompilationHistory.Count;
433454
compiler.ClearHistory();
434455

435-
return new SuccessResponse($"Cleared {count} history entries");
456+
return Response.Success($"Cleared {count} history entries");
436457
}
437458
catch (Exception ex)
438459
{
439-
return new ErrorResponse($"Failed to clear history: {ex.Message}");
460+
return Response.Error($"Failed to clear history: {ex.Message}");
440461
}
441462
}
442463

MCPForUnity/Editor/Windows/Components/Tools.meta renamed to CustomTools/RoslynRuntimeCompilation/PythonTools.asset.meta

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# Roslyn Runtime Compilation Tool
2+
3+
This custom tool uses Roslyn Runtime Compilation to have users run script generation and compilation during Playmode in realtime, where in traditional Unity workflow it would take seconds to reload assets and reset script states for each script change.

0 commit comments

Comments
 (0)