Skip to content

Commit 7c9926e

Browse files
committed
Merge branch 'beta' of https://github.com/Scriptwonder/unity-mcp into beta
2 parents c4dabe6 + a2a5edf commit 7c9926e

8 files changed

Lines changed: 94 additions & 16 deletions

File tree

.github/workflows/beta-release.yml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,21 @@ on:
1313
- "MCPForUnity/**"
1414

1515
jobs:
16+
unity_tests:
17+
name: Unity tests gate
18+
if: github.actor != 'github-actions[bot]'
19+
uses: ./.github/workflows/unity-tests.yml
20+
secrets: inherit
21+
22+
python_tests:
23+
name: Python tests gate
24+
if: github.actor != 'github-actions[bot]'
25+
uses: ./.github/workflows/python-tests.yml
26+
1627
update_unity_beta_version:
1728
name: Update Unity package to beta version
1829
runs-on: ubuntu-latest
30+
needs: [unity_tests, python_tests]
1931
# Avoid running when the workflow's own automation merges the PR
2032
# created by this workflow (prevents a version-bump loop).
2133
if: github.actor != 'github-actions[bot]'
@@ -143,6 +155,7 @@ jobs:
143155
publish_pypi_prerelease:
144156
name: Publish beta to PyPI (pre-release)
145157
runs-on: ubuntu-latest
158+
needs: [unity_tests, python_tests]
146159
# Avoid double-publish when the bot merges the version bump PR
147160
if: github.actor != 'github-actions[bot]'
148161
environment:

.github/workflows/python-tests.yml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,19 @@ on:
66
paths:
77
- Server/**
88
- .github/workflows/python-tests.yml
9+
pull_request:
10+
branches: [main, beta]
11+
paths:
12+
- Server/**
13+
- .github/workflows/python-tests.yml
914
workflow_dispatch: {}
15+
workflow_call:
16+
inputs:
17+
ref:
18+
description: "Git ref to test (defaults to the triggering ref)."
19+
type: string
20+
required: false
21+
default: ""
1022

1123
jobs:
1224
test:
@@ -15,6 +27,8 @@ jobs:
1527
steps:
1628
- name: Checkout repository
1729
uses: actions/checkout@v4
30+
with:
31+
ref: ${{ inputs.ref || github.ref }}
1832

1933
- name: Install uv
2034
uses: astral-sh/setup-uv@v4

.github/workflows/release.yml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,23 @@ on:
1919
required: true
2020

2121
jobs:
22+
unity_tests:
23+
name: Unity tests gate
24+
uses: ./.github/workflows/unity-tests.yml
25+
with:
26+
ref: beta
27+
secrets: inherit
28+
29+
python_tests:
30+
name: Python tests gate
31+
uses: ./.github/workflows/python-tests.yml
32+
with:
33+
ref: beta
34+
2235
bump:
2336
name: Bump version, tag, and create release
2437
runs-on: ubuntu-latest
38+
needs: [unity_tests, python_tests]
2539
permissions:
2640
contents: write
2741
pull-requests: write

.github/workflows/unity-tests.yml

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,43 @@ name: Unity Tests
22

33
on:
44
workflow_dispatch: {}
5+
workflow_call:
6+
inputs:
7+
ref:
8+
description: "Git ref to test (defaults to the triggering ref)."
9+
type: string
10+
required: false
11+
default: ""
512
push:
613
branches: ["**"]
714
paths:
815
- TestProjects/UnityMCPTests/**
916
- MCPForUnity/Editor/**
17+
- MCPForUnity/Runtime/**
18+
- .github/workflows/unity-tests.yml
19+
# Fork PRs: maintainer applies the 'safe-to-test' label after reviewing
20+
# the diff. The workflow runs with UNITY_LICENSE in scope against the
21+
# PR's head SHA. Re-pushed commits do NOT auto-trigger — maintainer must
22+
# remove and re-apply the label to re-run after additional review.
23+
pull_request_target:
24+
types: [labeled]
25+
branches: [main, beta]
26+
paths:
27+
- TestProjects/UnityMCPTests/**
28+
- MCPForUnity/Editor/**
29+
- MCPForUnity/Runtime/**
1030
- .github/workflows/unity-tests.yml
1131

1232
jobs:
1333
testAllModes:
1434
name: Test in ${{ matrix.testMode }}
1535
runs-on: ubuntu-latest
36+
permissions:
37+
contents: read
38+
if: >
39+
github.event_name != 'pull_request_target' ||
40+
(github.event.pull_request.head.repo.full_name != github.repository &&
41+
github.event.label.name == 'safe-to-test')
1642
strategy:
1743
fail-fast: false
1844
matrix:
@@ -27,6 +53,8 @@ jobs:
2753
uses: actions/checkout@v4
2854
with:
2955
lfs: true
56+
ref: ${{ inputs.ref || github.event.pull_request.head.sha || github.ref }}
57+
persist-credentials: false
3058

3159
- name: Detect Unity license secrets
3260
id: detect
@@ -107,7 +135,7 @@ jobs:
107135
fi
108136
109137
- uses: actions/upload-artifact@v4
110-
if: always() && steps.detect.outputs.unity_ok == 'true'
138+
if: always() && steps.detect.outputs.unity_ok == 'true' && steps.tests.outcome != 'skipped'
111139
with:
112140
name: Test results for ${{ matrix.testMode }}
113141
path: ${{ steps.tests.outputs.artifactsPath }}

MCPForUnity/Editor/Tools/ManageScene.cs

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -598,26 +598,32 @@ private static object CaptureScreenshot(SceneCommand cmd)
598598
{
599599
if (!Application.isBatchMode) EnsureGameView();
600600

601-
ScreenshotCaptureResult result = ScreenshotUtility.CaptureFromCameraToAssetsFolder(
601+
string folderOverride = ScreenshotPreferences.Resolve(cmd.outputFolder);
602+
ScreenshotCaptureResult result = ScreenshotUtility.CaptureFromCameraToProjectFolder(
602603
targetCamera, fileName, resolvedSuperSize, ensureUniqueFileName: true,
603-
includeImage: includeImage, maxResolution: maxResolution);
604+
includeImage: includeImage, maxResolution: maxResolution,
605+
folderOverride: folderOverride);
604606

605-
AssetDatabase.ImportAsset(result.AssetsRelativePath, ImportAssetOptions.ForceSynchronousImport);
606-
string message = $"Screenshot captured to '{result.AssetsRelativePath}' (camera: {targetCamera.name}).";
607+
if (ScreenshotUtility.IsUnderAssets(result.ProjectRelativePath))
608+
AssetDatabase.ImportAsset(result.ProjectRelativePath, ImportAssetOptions.ForceSynchronousImport);
609+
string message = $"Screenshot captured to '{result.ProjectRelativePath}' (camera: {targetCamera.name}).";
607610
return new SuccessResponse(message, BuildScreenshotResponseData(result, targetCamera.name, includeImage));
608611
}
609612

610613
if (includeImage && Application.isPlaying)
611614
{
612615
if (!Application.isBatchMode) EnsureGameView();
613616

617+
string folderOverride = ScreenshotPreferences.Resolve(cmd.outputFolder);
614618
ScreenshotCaptureResult result = ScreenshotUtility.CaptureComposited(
615619
fileName, resolvedSuperSize, ensureUniqueFileName: true,
616-
includeImage: true, maxResolution: maxResolution);
620+
includeImage: true, maxResolution: maxResolution,
621+
folderOverride: folderOverride);
617622

618-
AssetDatabase.ImportAsset(result.AssetsRelativePath, ImportAssetOptions.ForceSynchronousImport);
623+
if (ScreenshotUtility.IsUnderAssets(result.ProjectRelativePath))
624+
AssetDatabase.ImportAsset(result.ProjectRelativePath, ImportAssetOptions.ForceSynchronousImport);
619625
string cameraName = Camera.main != null ? Camera.main.name : "composited";
620-
string message = $"Screenshot captured to '{result.AssetsRelativePath}' (camera: {cameraName}).";
626+
string message = $"Screenshot captured to '{result.ProjectRelativePath}' (camera: {cameraName}).";
621627
return new SuccessResponse(message, BuildScreenshotResponseData(result, cameraName, includeImage: true));
622628
}
623629

@@ -747,7 +753,7 @@ private static Dictionary<string, object> BuildScreenshotResponseData(
747753
{
748754
var data = new Dictionary<string, object>
749755
{
750-
{ "path", result.AssetsRelativePath },
756+
{ "path", result.ProjectRelativePath },
751757
{ "fullPath", result.FullPath },
752758
{ "superSize", result.SuperSize },
753759
{ "isAsync", false },

MCPForUnity/Runtime/Helpers/ScreenshotUtility.cs

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -246,18 +246,20 @@ public static ScreenshotCaptureResult CaptureComposited(
246246
int superSize = 1,
247247
bool ensureUniqueFileName = true,
248248
bool includeImage = false,
249-
int maxResolution = 0)
249+
int maxResolution = 0,
250+
string folderOverride = null)
250251
{
251252
if (!IsScreenCaptureModuleAvailable)
252253
{
253254
var fallbackCamera = FindAvailableCamera();
254255
if (fallbackCamera != null)
255-
return CaptureFromCameraToAssetsFolder(fallbackCamera, fileName, superSize, ensureUniqueFileName, includeImage, maxResolution);
256+
return CaptureFromCameraToProjectFolder(fallbackCamera, fileName, superSize, ensureUniqueFileName,
257+
includeImage, maxResolution, folderOverride: folderOverride);
256258

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

260-
ScreenshotCaptureResult result = PrepareCaptureResult(fileName, superSize, ensureUniqueFileName, isAsync: false);
262+
ScreenshotCaptureResult result = PrepareCaptureResult(fileName, superSize, ensureUniqueFileName, folderOverride: folderOverride, isAsync: false);
261263
Texture2D tex = null;
262264
Texture2D downscaled = null;
263265
string imageBase64 = null;
@@ -270,7 +272,8 @@ public static ScreenshotCaptureResult CaptureComposited(
270272
// Fallback to camera-based if ScreenCapture fails
271273
var cam = FindAvailableCamera();
272274
if (cam != null)
273-
return CaptureFromCameraToAssetsFolder(cam, fileName, superSize, ensureUniqueFileName, includeImage, maxResolution);
275+
return CaptureFromCameraToProjectFolder(cam, fileName, superSize, ensureUniqueFileName,
276+
includeImage, maxResolution, folderOverride: folderOverride);
274277
throw new InvalidOperationException("ScreenCapture.CaptureScreenshotAsTexture returned null and no fallback camera available.");
275278
}
276279

@@ -308,7 +311,7 @@ public static ScreenshotCaptureResult CaptureComposited(
308311
if (includeImage && imageBase64 != null)
309312
{
310313
return new ScreenshotCaptureResult(
311-
result.FullPath, result.AssetsRelativePath, result.SuperSize, false,
314+
result.FullPath, result.ProjectRelativePath, result.SuperSize, false,
312315
imageBase64, imgW, imgH);
313316
}
314317
return result;

MCPForUnity/Runtime/Helpers/UnityFindObjectsCompat.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ public static UObject[] FindAll(Type type, bool includeInactive)
5858
#if UNITY_6000_5_OR_NEWER
5959
return UObject.FindObjectsByType(type,
6060
includeInactive ? UnityEngine.FindObjectsInactive.Include : UnityEngine.FindObjectsInactive.Exclude);
61-
#elif UNITY_2023_1_OR_NEWER
61+
#elif UNITY_2022_3_OR_NEWER
6262
return UObject.FindObjectsByType(type,
6363
includeInactive ? UnityEngine.FindObjectsInactive.Include : UnityEngine.FindObjectsInactive.Exclude,
6464
UnityEngine.FindObjectsSortMode.None);

MCPForUnity/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "com.coplaydev.unity-mcp",
3-
"version": "9.6.9-beta.5",
3+
"version": "9.6.9-beta.7",
44
"displayName": "MCP for Unity",
55
"description": "A bridge that connects AI assistants to Unity via the MCP (Model Context Protocol). Allows AI clients like Claude Code, Cursor, and VSCode to directly control your Unity Editor for enhanced development workflows.\n\nFeatures automated setup wizard, cross-platform support, and seamless integration with popular AI development tools.\n\nJoin Our Discord: https://discord.gg/y4p8KfzrN4",
66
"unity": "2021.3",

0 commit comments

Comments
 (0)