Skip to content
Merged
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
29 changes: 12 additions & 17 deletions MCPForUnity/Editor/Services/EditorStateCache.cs
Original file line number Diff line number Diff line change
Expand Up @@ -260,8 +260,8 @@ static EditorStateCache()
EditorApplication.playModeStateChanged += _ => ForceUpdate("playmode");

// Tracks whether an assembly compilation is actually running, for
// GetActualIsCompiling's Play-mode check. Statics reset on domain reload
// and this [InitializeOnLoad] ctor re-subscribes, so the flag is per-domain.
// GetActualIsCompiling. Statics reset on domain reload and this
// [InitializeOnLoad] ctor re-subscribes, so the flag is per-domain.
UnityEditor.Compilation.CompilationPipeline.compilationStarted += _ => _pipelineCompilationRunning = true;
UnityEditor.Compilation.CompilationPipeline.compilationFinished += _ => _pipelineCompilationRunning = false;

Expand All @@ -288,7 +288,7 @@ private static void OnUpdate()
{
// Throttle to reduce overhead while keeping the snapshot fresh enough for polling clients.
double now = EditorApplication.timeSinceStartup;
// Use GetActualIsCompiling() to avoid Play mode false positives (issue #582)
// Use GetActualIsCompiling() to avoid isCompiling false positives (issues #549, #1276)
bool isCompiling = GetActualIsCompiling();

// Check for compilation edge transitions (always update on these)
Expand Down Expand Up @@ -543,10 +543,12 @@ public static JObject GetSnapshot()
private static bool _pipelineCompilationRunning;

/// <summary>
/// Returns the actual compilation state, working around a known Unity quirk where
/// EditorApplication.isCompiling can return false positives in Play mode (e.g. a
/// recompile deferred by Recompile-After-Finished-Playing keeps it true for the
/// whole play session). See: https://github.com/CoplayDev/unity-mcp/issues/549
/// Returns the actual compilation state, working around known Unity quirks where
/// EditorApplication.isCompiling reports false positives while no compilation is
/// running: a recompile deferred by Recompile-After-Finished-Playing keeps it true
/// for the whole play session (issue #549), and a project holding
/// EditorApplication.LockReloadAssemblies keeps it true until the lock is released
/// (issue #1276). In both cases the event-tracked pipeline flag is authoritative.
/// </summary>
internal static bool GetActualIsCompiling()
{
Expand All @@ -556,16 +558,9 @@ internal static bool GetActualIsCompiling()
return false;
}

// In Play mode, trust the event-tracked pipeline state instead: a deferred
// recompile keeps EditorApplication.isCompiling true without any compilation
// actually running.
if (EditorApplication.isPlaying)
{
return _pipelineCompilationRunning;
}

// Outside Play mode the raw signal is reliable.
return true;
// Otherwise trust the event-tracked pipeline state: isCompiling stays true for as
// long as an assembly reload is deferred, with no compilation actually running.
return _pipelineCompilationRunning;
}
}
}
Expand Down
10 changes: 2 additions & 8 deletions MCPForUnity/Editor/Services/StdioBridgeReloadHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -114,14 +114,8 @@ private static void OnAfterAssemblyReload()
}

// If the editor is not compiling, attempt an immediate restart without relying on editor focus.
bool isCompiling = EditorApplication.isCompiling;
try
{
var pipeline = Type.GetType("UnityEditor.Compilation.CompilationPipeline, UnityEditor");
var prop = pipeline?.GetProperty("isCompiling", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static);
if (prop != null) isCompiling |= (bool)prop.GetValue(null);
}
catch { }
// Routed through EditorStateCache so a deferred reload (issue #1276) does not block resume.
bool isCompiling = EditorStateCache.GetActualIsCompiling();

if (!isCompiling)
{
Expand Down
4 changes: 2 additions & 2 deletions MCPForUnity/Editor/Services/TestJobManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -502,7 +502,7 @@ internal static TestJob GetJob(string jobId)
{
long now = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
long initTimeout = job.InitTimeoutMs > 0 ? job.InitTimeoutMs : DefaultInitializationTimeoutMs;
if (!EditorApplication.isCompiling && !EditorApplication.isUpdating && now - job.StartedUnixMs > initTimeout)
if (!EditorStateCache.GetActualIsCompiling() && !EditorApplication.isUpdating && now - job.StartedUnixMs > initTimeout)
{
McpLog.Warn($"[TestJobManager] Job {jobId} failed to initialize within {initTimeout}ms, auto-failing");
job.Status = TestJobStatus.Failed;
Expand Down Expand Up @@ -589,7 +589,7 @@ private static string GetBlockedReason(TestJob job)
return "editor_unfocused";
}

if (EditorApplication.isCompiling)
if (EditorStateCache.GetActualIsCompiling())
{
return "compiling";
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -237,24 +237,10 @@ private static void EnsureStartedOnEditorIdle()
}
}

private static bool IsCompiling()
{
if (EditorApplication.isCompiling)
{
return true;
}
try
{
Type pipeline = Type.GetType("UnityEditor.Compilation.CompilationPipeline, UnityEditor");
var prop = pipeline?.GetProperty("isCompiling", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static);
if (prop != null)
{
return (bool)prop.GetValue(null);
}
}
catch { }
return false;
}
// Routed through EditorStateCache so a deferred domain reload (issue #1276) does not
// pin the bridge off: raw EditorApplication.isCompiling stays true for as long as the
// reload is held, and this gates bridge startup.
private static bool IsCompiling() => EditorStateCache.GetActualIsCompiling();

public static void Start()
{
Expand Down
3 changes: 2 additions & 1 deletion MCPForUnity/Editor/Tools/ManageScriptableObject.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using System.Linq;
using System.Text.RegularExpressions;
using MCPForUnity.Editor.Helpers;
using MCPForUnity.Editor.Services;
using Newtonsoft.Json.Linq;
using UnityEditor;
using UnityEngine;
Expand Down Expand Up @@ -44,7 +45,7 @@ public static object HandleCommand(JObject @params)
return new ErrorResponse(CodeInvalidParams);
}

if (EditorApplication.isCompiling || EditorApplication.isUpdating)
if (EditorStateCache.GetActualIsCompiling() || EditorApplication.isUpdating)
{
// Unity is transient; treat as retryable on the client side.
return new ErrorResponse(CodeCompilingOrReloading, new { hint = "retry" });
Expand Down
4 changes: 2 additions & 2 deletions MCPForUnity/Editor/Tools/RefreshUnity.cs
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ await WaitForUnityReadyAsync(
}
}

string resultingState = EditorApplication.isCompiling
string resultingState = EditorStateCache.GetActualIsCompiling()
? "compiling"
: (EditorApplication.isUpdating ? "asset_import" : "idle");

Expand Down Expand Up @@ -146,7 +146,7 @@ void Tick()
return;
}

if (!EditorApplication.isCompiling
if (!EditorStateCache.GetActualIsCompiling()
&& !EditorApplication.isUpdating
&& !TestRunStatus.IsRunning
&& !EditorApplication.isPlayingOrWillChangePlaymode)
Expand Down
3 changes: 2 additions & 1 deletion MCPForUnity/Editor/Tools/UnityReflect.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using System.Runtime.CompilerServices;
using System.Text.RegularExpressions;
using MCPForUnity.Editor.Helpers;
using MCPForUnity.Editor.Services;
using MCPForUnity.Runtime.Helpers;
using Newtonsoft.Json.Linq;
using UnityEditor;
Expand Down Expand Up @@ -99,7 +100,7 @@ private static Dictionary<string, Type[]> GetAssemblyTypeCache()

public static object HandleCommand(JObject @params)
{
if (EditorApplication.isCompiling)
if (EditorStateCache.GetActualIsCompiling())
return new ErrorResponse("Cannot reflect while Unity is compiling. Wait for domain reload to complete.");

if (@params == null)
Expand Down
Loading