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
2 changes: 1 addition & 1 deletion MCPForUnity/Editor/Resources/Project/ProjectInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ public static object HandleCommand(JObject @params)
textmeshpro = IsPackageInstalled("com.unity.textmeshpro"),
inputsystem = IsPackageInstalled("com.unity.inputsystem"),
uiToolkit = true,
screenCapture = MCPForUnity.Runtime.Helpers.ScreenshotUtility.IsScreenCaptureModuleAvailable,
screenCapture = true,
}
};

Expand Down
19 changes: 2 additions & 17 deletions MCPForUnity/Editor/Tools/ManageScene.cs
Original file line number Diff line number Diff line change
Expand Up @@ -678,24 +678,9 @@ private static object CaptureScreenshot(SceneCommand cmd)
return new SuccessResponse(message, BuildScreenshotResponseData(result, targetCamera.name, includeImage));
}

// Default path: use ScreenCapture API if available, camera fallback otherwise
bool screenCaptureAvailable = ScreenshotUtility.IsScreenCaptureModuleAvailable;
// Default path: ScreenCapture API for 2022.1+, camera fallback required on older versions.
#if !UNITY_2022_1_OR_NEWER
bool hasCameraFallback = Camera.main != null || UnityFindObjectsCompat.FindAll<Camera>().Length > 0;

#if UNITY_2022_1_OR_NEWER
if (!screenCaptureAvailable && !hasCameraFallback)
{
return new ErrorResponse(
"Cannot capture screenshot. The Screen Capture module is not enabled and no Camera was found in the scene. " +
"Please either: (1) Enable the Screen Capture module: Window > Package Manager > Built-in > Screen Capture > Enable, " +
"or (2) Add a Camera to your scene for camera-based fallback capture."
);
}
if (!screenCaptureAvailable)
{
McpLog.Warn("[ManageScene] Screen Capture module not enabled. Using camera-based fallback.");
}
#else
if (!hasCameraFallback)
{
return new ErrorResponse(
Expand Down
6 changes: 0 additions & 6 deletions MCPForUnity/Editor/Tools/ManageUI.cs
Original file line number Diff line number Diff line change
Expand Up @@ -927,12 +927,6 @@ private static object RenderUI(JObject @params)
}

// ── Case 2: start a new capture ───────────────────────────────────
// Verify the ScreenCapture module is enabled before attempting capture.
if (!ScreenshotUtility.IsScreenCaptureModuleAvailable)
{
return new ErrorResponse(ScreenshotUtility.ScreenCaptureModuleNotAvailableError);
}

// Only one capture in flight at a time. If one is already pending,
// reject rather than silently overwriting the state.
if (s_pendingCaptureStarted)
Expand Down
4 changes: 0 additions & 4 deletions MCPForUnity/Editor/Tools/Vfx/TrailControl.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,9 @@ public static object Emit(JObject @params)

RendererHelpers.EnsureMaterial(tr);

#if UNITY_2021_1_OR_NEWER
Vector3 pos = ManageVfxCommon.ParseVector3(@params["position"]);
tr.AddPosition(pos);
return new { success = true, message = $"Emitted at ({pos.x}, {pos.y}, {pos.z})" };
#else
return new { success = false, message = "AddPosition requires Unity 2021.1+" };
#endif
}
}
}
111 changes: 8 additions & 103 deletions MCPForUnity/Runtime/Helpers/ScreenshotUtility.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,57 +50,6 @@ public static class ScreenshotUtility
/// or globally via <c>ScreenshotPreferences</c> in the Editor assembly.
/// </summary>
public const string DefaultFolder = "Assets/Screenshots";
private static bool s_loggedLegacyScreenCaptureFallback;
private static bool? s_screenCaptureModuleAvailable;
private static System.Reflection.MethodInfo s_captureScreenshotMethod;
private static System.Reflection.MethodInfo s_captureScreenshotAsTextureMethod;

/// <summary>
/// Checks if the Screen Capture module (com.unity.modules.screencapture) is enabled.
/// This module can be disabled in Package Manager > Built-in, which removes the ScreenCapture class.
/// </summary>
public static bool IsScreenCaptureModuleAvailable
{
get
{
if (!s_screenCaptureModuleAvailable.HasValue)
{
// Check if ScreenCapture type exists (module might be disabled in Package Manager > Built-in)
var screenCaptureType = Type.GetType("UnityEngine.ScreenCapture, UnityEngine.ScreenCaptureModule")
?? Type.GetType("UnityEngine.ScreenCapture, UnityEngine.CoreModule");
s_screenCaptureModuleAvailable = screenCaptureType != null;
if (screenCaptureType != null)
{
s_captureScreenshotMethod = screenCaptureType.GetMethod("CaptureScreenshot",
new Type[] { typeof(string), typeof(int) });
s_captureScreenshotAsTextureMethod = screenCaptureType.GetMethod("CaptureScreenshotAsTexture",
new Type[] { typeof(int) });
}
}
return s_screenCaptureModuleAvailable.Value;
}
}

/// <summary>
/// Reflective invocation of ScreenCapture.CaptureScreenshotAsTexture(int). Returns
/// null when the Screen Capture module is disabled. Centralised so the only direct
/// reference to ScreenCapture lives here.
/// </summary>
internal static Texture2D InvokeCaptureScreenshotAsTexture(int superSize)
{
if (!IsScreenCaptureModuleAvailable || s_captureScreenshotAsTextureMethod == null)
return null;
return s_captureScreenshotAsTextureMethod.Invoke(null, new object[] { superSize }) as Texture2D;
}

/// <summary>
/// Error message to display when Screen Capture module is not available.
/// </summary>
public const string ScreenCaptureModuleNotAvailableError =
"The Screen Capture module (com.unity.modules.screencapture) is not enabled. " +
"To use screenshot capture with ScreenCapture API, please enable it in Unity: " +
"Window > Package Manager > Built-in > Screen Capture > Enable. " +
"Alternatively, MCP for Unity will use camera-based capture as a fallback if a Camera exists in the scene.";

private static Camera FindAvailableCamera()
{
Expand All @@ -127,44 +76,10 @@ public static ScreenshotCaptureResult CaptureToProjectFolder(
bool ensureUniqueFileName = true,
string folderOverride = null)
{
// Use reflection to call ScreenCapture.CaptureScreenshot so the code compiles
// even when the Screen Capture module (com.unity.modules.screencapture) is disabled.
if (IsScreenCaptureModuleAvailable && s_captureScreenshotMethod != null)
{
ScreenshotCaptureResult result = PrepareCaptureResult(fileName, superSize, ensureUniqueFileName, folderOverride, isAsync: true);
// ScreenCapture.CaptureScreenshot accepts paths relative to the project root.
s_captureScreenshotMethod.Invoke(null, new object[] { result.ProjectRelativePath, result.SuperSize });
return result;
}
else
{
// Module disabled or unavailable - try camera fallback
Debug.LogWarning("[MCP for Unity] " + ScreenCaptureModuleNotAvailableError);
return CaptureWithCameraFallback(fileName, superSize, ensureUniqueFileName, folderOverride);
}
}

private static ScreenshotCaptureResult CaptureWithCameraFallback(string fileName, int superSize, bool ensureUniqueFileName, string folderOverride)
{
if (!s_loggedLegacyScreenCaptureFallback)
{
Debug.Log("[MCP for Unity] Using camera-based screenshot capture. " +
"This requires a Camera in the scene. For best results on Unity 2022.1+, ensure the Screen Capture module is enabled: " +
"Window > Package Manager > Built-in > Screen Capture > Enable.");
s_loggedLegacyScreenCaptureFallback = true;
}

var cam = FindAvailableCamera();
if (cam == null)
{
throw new InvalidOperationException(
"No camera found to capture screenshot. Camera-based capture requires a Camera in the scene. " +
"Either add a Camera to your scene, or enable the Screen Capture module: " +
"Window > Package Manager > Built-in > Screen Capture > Enable."
);
}

return CaptureFromCameraToProjectFolder(cam, fileName, superSize, ensureUniqueFileName, folderOverride: folderOverride);
ScreenshotCaptureResult result = PrepareCaptureResult(fileName, superSize, ensureUniqueFileName, folderOverride, isAsync: true);
// ScreenCapture.CaptureScreenshot accepts paths relative to the project root.
ScreenCapture.CaptureScreenshot(result.ProjectRelativePath, result.SuperSize);
return result;
}

/// <summary>
Expand Down Expand Up @@ -283,7 +198,7 @@ private static Texture2D CaptureCompositedAfterFrame(int superSize, int timeoutS
/// <summary>
/// Captures a screenshot using ScreenCapture.CaptureScreenshotAsTexture, which captures the
/// final composited frame including UI Toolkit overlays, post-processing, etc.
/// Falls back to camera-based capture if ScreenCapture is unavailable.
/// Falls back to camera-based capture if ScreenCapture returns null at runtime.
/// </summary>
public static ScreenshotCaptureResult CaptureComposited(
string fileName = null,
Expand All @@ -293,16 +208,6 @@ public static ScreenshotCaptureResult CaptureComposited(
int maxResolution = 0,
string folderOverride = null)
{
if (!IsScreenCaptureModuleAvailable || s_captureScreenshotAsTextureMethod == null)
{
var fallbackCamera = FindAvailableCamera();
if (fallbackCamera != null)
return CaptureFromCameraToProjectFolder(fallbackCamera, fileName, superSize, ensureUniqueFileName,
includeImage, maxResolution, folderOverride: folderOverride);

throw new InvalidOperationException("ScreenCapture module is unavailable and no fallback camera found.");
}

ScreenshotCaptureResult result = PrepareCaptureResult(fileName, superSize, ensureUniqueFileName, folderOverride: folderOverride, isAsync: false);
Texture2D tex = null;
Texture2D downscaled = null;
Expand All @@ -315,9 +220,9 @@ public static ScreenshotCaptureResult CaptureComposited(
// composited; route through WaitForEndOfFrame instead.
tex = Application.isPlaying
? CaptureCompositedAfterFrame(result.SuperSize)
: InvokeCaptureScreenshotAsTexture(result.SuperSize);
: ScreenCapture.CaptureScreenshotAsTexture(result.SuperSize);
#else
tex = InvokeCaptureScreenshotAsTexture(result.SuperSize);
tex = ScreenCapture.CaptureScreenshotAsTexture(result.SuperSize);
#endif
if (tex == null)
{
Expand Down Expand Up @@ -857,7 +762,7 @@ private System.Collections.IEnumerator Start()
{
yield return new WaitForEndOfFrame();
Texture2D tex = null;
try { tex = ScreenshotUtility.InvokeCaptureScreenshotAsTexture(_superSize); }
try { tex = ScreenCapture.CaptureScreenshotAsTexture(_superSize); }
catch (Exception ex) { Debug.LogError($"[MCP for Unity] CaptureScreenshotAsTexture failed: {ex.Message}"); }
_onComplete?.Invoke(tex);
Destroy(gameObject);
Expand Down
17 changes: 4 additions & 13 deletions MCPForUnity/Runtime/Helpers/UnityPhysicsCompat.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,10 @@ namespace MCPForUnity.Runtime.Helpers
///
/// We use reflection rather than direct property access so calls stay clean of
/// CS0618 warnings AND survive eventual removal of the obsolete property without
/// a recompile of this package. Type lookups go through <see cref="Type.GetType(string)"/>
/// so this file compiles even when the Physics 2D built-in module is disabled in
/// the Package Manager.
/// a recompile of this package.
/// </summary>
public static class UnityPhysicsCompat
{
// Assembly-qualified name — resolved at runtime so the file compiles when the
// Physics 2D built-in module is disabled in the Package Manager.
private const string Physics2DTypeName = "UnityEngine.Physics2D, UnityEngine.Physics2DModule";
/// <summary>
/// Cross-version description of the 3D physics simulation mode.
/// On 2022.2+ this maps onto <c>UnityEngine.SimulationMode</c>; on older
Expand All @@ -51,13 +46,9 @@ private static PropertyInfo Physics2DAutoSyncProp
if (!_physics2DProbed)
{
_physics2DProbed = true;
var physics2DType = Type.GetType(Physics2DTypeName);
if (physics2DType != null)
{
_physics2DAutoSync = physics2DType.GetProperty(
"autoSyncTransforms",
BindingFlags.Public | BindingFlags.Static);
}
_physics2DAutoSync = typeof(Physics2D).GetProperty(
"autoSyncTransforms",
BindingFlags.Public | BindingFlags.Static);
}
return _physics2DAutoSync;
}
Expand Down
Loading