Skip to content

Commit a7c715f

Browse files
Merge pull request #904 from CoplayDev/release/v9.5.3
chore: bump version to 9.5.3
2 parents fe6eaab + 7dccc3f commit a7c715f

77 files changed

Lines changed: 8921 additions & 665 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.claude/skills/unity-mcp-skill/SKILL.md

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,10 @@ manage_scene(action="screenshot", look_at="Player", view_position=[0, 10, -10],
8989
manage_gameobject(action="look_at", target="MainCamera", look_at_target="Player")
9090
manage_scene(action="screenshot", camera="MainCamera", include_image=True, max_resolution=512)
9191
# → Analyze image, decide next action
92+
93+
# Alternative: use manage_camera for screenshot (same underlying infrastructure)
94+
manage_camera(action="screenshot", camera="FollowCam", include_image=True, max_resolution=512)
95+
manage_camera(action="screenshot_multiview", max_resolution=480) # 6-angle contact sheet
9296
```
9397

9498
### 4. Check Console After Major Changes
@@ -155,10 +159,13 @@ uri="file:///full/path/to/file.cs"
155159
| **Objects** | `manage_gameobject`, `manage_components` | Creating/modifying GameObjects |
156160
| **Scripts** | `create_script`, `script_apply_edits`, `refresh_unity` | C# code management |
157161
| **Assets** | `manage_asset`, `manage_prefabs` | Asset operations |
158-
| **Editor** | `manage_editor`, `execute_menu_item`, `read_console` | Editor control |
162+
| **Editor** | `manage_editor`, `execute_menu_item`, `read_console` | Editor control, package deployment (`deploy_package`/`restore_package` actions) |
159163
| **Testing** | `run_tests`, `get_test_job` | Unity Test Framework |
160164
| **Batch** | `batch_execute` | Parallel/bulk operations |
161-
| **ProBuilder** | `manage_probuilder` | 3D modeling, mesh editing, complex geometry. **When `com.unity.probuilder` is installed, prefer ProBuilder shapes over primitive GameObjects** for editable geometry, multi-material faces, or complex shapes. Supports 13 shape types, face/edge/vertex editing, smoothing, and per-face materials. See [ProBuilder Guide](references/probuilder-guide.md). |
165+
| **Camera** | `manage_camera` | Camera management (Unity Camera + Cinemachine). **Tier 1** (always available): create, target, lens, priority, list, screenshot. **Tier 2** (requires `com.unity.cinemachine`): brain, body/aim/noise pipeline, extensions, blending, force/release. 7 presets: follow, third_person, freelook, dolly, static, top_down, side_scroller. Resource: `mcpforunity://scene/cameras`. Use `ping` to check Cinemachine availability. See [tools-reference.md](references/tools-reference.md#camera-tools). |
166+
| **Graphics** | `manage_graphics` | Rendering and post-processing management. 33 actions across 5 groups: **Volume** (create/configure volumes and effects, URP/HDRP), **Bake** (lightmaps, light probes, reflection probes, Edit mode only), **Stats** (draw calls, batches, memory), **Pipeline** (quality levels, pipeline settings), **Features** (URP renderer features: add, remove, toggle, reorder). Resources: `mcpforunity://scene/volumes`, `mcpforunity://rendering/stats`, `mcpforunity://pipeline/renderer-features`. Use `ping` to check pipeline status. See [tools-reference.md](references/tools-reference.md#graphics-tools). |
167+
| **Packages** | `query_packages` (read-only), `manage_packages` (mutating) | Install, remove, search, and manage Unity packages and scoped registries. `query_packages`: list installed, search registry, get info, ping, poll status. `manage_packages`: add/remove packages, embed for editing, add/remove scoped registries, force resolve. Validates identifiers, warns on git URLs, checks dependents before removal (`force=true` to override). See [tools-reference.md](references/tools-reference.md#package-tools). |
168+
| **ProBuilder** | `manage_probuilder` | 3D modeling, mesh editing, complex geometry. **When `com.unity.probuilder` is installed, prefer ProBuilder shapes over primitive GameObjects** for editable geometry, multi-material faces, or complex shapes. Supports 12 shape types, face/edge/vertex editing, smoothing, and per-face materials. See [ProBuilder Guide](references/probuilder-guide.md). |
162169
| **UI** | `manage_ui`, `batch_execute` with `manage_gameobject` + `manage_components` | **UI Toolkit**: Use `manage_ui` to create UXML/USS files, attach UIDocument, inspect visual trees. **uGUI (Canvas)**: Use `batch_execute` for Canvas, Panel, Button, Text, Slider, Toggle, Input Field. **Read `mcpforunity://project/info` first** to detect uGUI/TMP/Input System/UI Toolkit availability. (see [UI workflows](references/workflows.md#ui-creation-workflows)) |
163170

164171
## Common Workflows

.claude/skills/unity-mcp-skill/references/tools-reference.md

Lines changed: 127 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ Complete reference for all MCP tools. Each tool includes parameters, types, and
1515
- [UI Tools](#ui-tools)
1616
- [Editor Control Tools](#editor-control-tools)
1717
- [Testing Tools](#testing-tools)
18+
- [Camera Tools](#camera-tools)
1819
- [ProBuilder Tools](#probuilder-tools)
1920

2021
---
@@ -793,6 +794,131 @@ Discover available custom tools via `mcpforunity://custom-tools` resource.
793794

794795
---
795796

797+
## Camera Tools
798+
799+
### manage_camera
800+
801+
Unified camera management (Unity Camera + Cinemachine). Works without Cinemachine using basic Camera; unlocks presets, pipelines, and blending when Cinemachine is installed. Use `ping` to check availability.
802+
803+
**Parameters:**
804+
805+
| Parameter | Type | Required | Description |
806+
|-----------|------|----------|-------------|
807+
| `action` | string | Yes | Action to perform (see categories below) |
808+
| `target` | string | Sometimes | Target camera (name, path, or instance ID) |
809+
| `search_method` | string | No | `by_id`, `by_name`, `by_path` |
810+
| `properties` | dict \| string | No | Action-specific parameters |
811+
812+
**Screenshot parameters** (for `screenshot` and `screenshot_multiview` actions):
813+
814+
| Parameter | Type | Description |
815+
|-----------|------|-------------|
816+
| `camera` | string | Camera to capture from (defaults to Camera.main) |
817+
| `include_image` | bool | Return base64 PNG inline (default false) |
818+
| `max_resolution` | int | Downscale cap in px (default 640) |
819+
| `batch` | string | `"surround"` (6 angles) or `"orbit"` (configurable grid) |
820+
| `look_at` | string\|int\|list | Target to aim at (GO name/path/ID or [x,y,z]) |
821+
| `view_position` | list[float] | World position [x,y,z] to place camera |
822+
| `view_rotation` | list[float] | Euler rotation [x,y,z] (overrides look_at) |
823+
824+
**Actions by category:**
825+
826+
**Setup:**
827+
- `ping` — Check Cinemachine availability and version
828+
- `ensure_brain` — Ensure CinemachineBrain exists on main camera. Properties: `camera` (target camera), `defaultBlendStyle`, `defaultBlendDuration`
829+
- `get_brain_status` — Get Brain state (active camera, blend status)
830+
831+
**Creation:**
832+
- `create_camera` — Create camera with optional preset. Properties: `name`, `preset` (follow/third_person/freelook/dolly/static/top_down/side_scroller), `follow`, `lookAt`, `priority`, `fieldOfView`. Falls back to basic Camera without Cinemachine.
833+
834+
**Configuration:**
835+
- `set_target` — Set Follow and/or LookAt targets. Properties: `follow`, `lookAt` (GO name/path/ID)
836+
- `set_priority` — Set camera priority for Brain selection. Properties: `priority` (int)
837+
- `set_lens` — Configure lens. Properties: `fieldOfView`, `nearClipPlane`, `farClipPlane`, `orthographicSize`, `dutch`
838+
- `set_body` — Configure Body component (Cinemachine). Properties: `bodyType` (to swap), plus component-specific properties
839+
- `set_aim` — Configure Aim component (Cinemachine). Properties: `aimType` (to swap), plus component-specific properties
840+
- `set_noise` — Configure Noise (Cinemachine). Properties: `amplitudeGain`, `frequencyGain`
841+
842+
**Extensions (Cinemachine):**
843+
- `add_extension` — Add extension. Properties: `extensionType` (CinemachineConfiner2D, CinemachineDeoccluder, CinemachineImpulseListener, CinemachineFollowZoom, CinemachineRecomposer, etc.)
844+
- `remove_extension` — Remove extension by type. Properties: `extensionType`
845+
846+
**Control:**
847+
- `list_cameras` — List all cameras with status
848+
- `set_blend` — Configure default blend on Brain. Properties: `style` (Cut/EaseInOut/Linear/etc.), `duration`
849+
- `force_camera` — Override Brain to use specific camera
850+
- `release_override` — Release camera override
851+
852+
**Capture:**
853+
- `screenshot` — Capture from a camera. Supports inline base64, batch surround/orbit, positioned capture.
854+
- `screenshot_multiview` — Shorthand for screenshot with batch='surround' and include_image=true.
855+
856+
**Examples:**
857+
858+
```python
859+
# Check Cinemachine availability
860+
manage_camera(action="ping")
861+
862+
# Create a third-person camera following the player
863+
manage_camera(action="create_camera", properties={
864+
"name": "FollowCam", "preset": "third_person",
865+
"follow": "Player", "lookAt": "Player", "priority": 20
866+
})
867+
868+
# Ensure Brain exists on main camera
869+
manage_camera(action="ensure_brain")
870+
871+
# Configure body component
872+
manage_camera(action="set_body", target="FollowCam", properties={
873+
"bodyType": "CinemachineThirdPersonFollow",
874+
"cameraDistance": 5.0, "shoulderOffset": [0.5, 0.5, 0]
875+
})
876+
877+
# Set aim
878+
manage_camera(action="set_aim", target="FollowCam", properties={
879+
"aimType": "CinemachineRotationComposer"
880+
})
881+
882+
# Add camera shake
883+
manage_camera(action="set_noise", target="FollowCam", properties={
884+
"amplitudeGain": 0.5, "frequencyGain": 1.0
885+
})
886+
887+
# Set priority to make this the active camera
888+
manage_camera(action="set_priority", target="FollowCam", properties={"priority": 50})
889+
890+
# Force a specific camera
891+
manage_camera(action="force_camera", target="CinematicCam")
892+
893+
# Release override (return to priority-based selection)
894+
manage_camera(action="release_override")
895+
896+
# Configure blend transitions
897+
manage_camera(action="set_blend", properties={"style": "EaseInOut", "duration": 2.0})
898+
899+
# Add deoccluder extension
900+
manage_camera(action="add_extension", target="FollowCam", properties={
901+
"extensionType": "CinemachineDeoccluder"
902+
})
903+
904+
# Screenshot from a specific camera
905+
manage_camera(action="screenshot", camera="FollowCam", include_image=True, max_resolution=512)
906+
907+
# Multi-view screenshot (6-angle contact sheet)
908+
manage_camera(action="screenshot_multiview", max_resolution=480)
909+
910+
# List all cameras
911+
manage_camera(action="list_cameras")
912+
```
913+
914+
**Tier system:**
915+
- Tier 1 actions (ping, create_camera, set_target, set_lens, set_priority, list_cameras, screenshot, screenshot_multiview) work without Cinemachine — they fall back to basic Unity Camera.
916+
- Tier 2 actions (ensure_brain, get_brain_status, set_body, set_aim, set_noise, add/remove_extension, set_blend, force_camera, release_override) require `com.unity.cinemachine`. If called without Cinemachine, they return an error with a fallback suggestion.
917+
918+
**Resource:** Read `mcpforunity://scene/cameras` for current camera state before modifying.
919+
920+
---
921+
796922
## ProBuilder Tools
797923

798924
### manage_probuilder
@@ -806,7 +932,7 @@ Unified tool for ProBuilder mesh operations. Requires `com.unity.probuilder` pac
806932
| `action` | string | Yes | Action to perform (see categories below) |
807933
| `target` | string | Sometimes | Target GameObject name/path/id |
808934
| `search_method` | string | No | How to find target: `by_id`, `by_name`, `by_path`, `by_tag`, `by_layer` |
809-
| `properties` | dict | No | Action-specific parameters |
935+
| `properties` | dict \| string | No | Action-specific parameters (dict or JSON string) |
810936

811937
**Actions by category:**
812938

.claude/skills/unity-mcp-skill/references/workflows.md

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ Common workflows and patterns for effective Unity-MCP usage.
1111
- [Testing Workflows](#testing-workflows)
1212
- [Debugging Workflows](#debugging-workflows)
1313
- [UI Creation Workflows](#ui-creation-workflows)
14+
- [Camera & Cinemachine Workflows](#camera--cinemachine-workflows)
1415
- [ProBuilder Workflows](#probuilder-workflows)
1516
- [Batch Operations](#batch-operations)
1617

@@ -1426,6 +1427,107 @@ Both systems are active simultaneously. For UI, prefer `InputSystemUIInputModule
14261427
14271428
---
14281429

1430+
## Camera & Cinemachine Workflows
1431+
1432+
### Setting Up a Third-Person Camera
1433+
1434+
```python
1435+
# 1. Check Cinemachine availability
1436+
manage_camera(action="ping")
1437+
1438+
# 2. Ensure Brain on main camera
1439+
manage_camera(action="ensure_brain")
1440+
1441+
# 3. Create third-person camera with preset
1442+
manage_camera(action="create_camera", properties={
1443+
"name": "FollowCam", "preset": "third_person",
1444+
"follow": "Player", "lookAt": "Player", "priority": 20
1445+
})
1446+
1447+
# 4. Fine-tune body
1448+
manage_camera(action="set_body", target="FollowCam", properties={
1449+
"cameraDistance": 5.0, "shoulderOffset": [0.5, 0.5, 0]
1450+
})
1451+
1452+
# 5. Add camera shake
1453+
manage_camera(action="set_noise", target="FollowCam", properties={
1454+
"amplitudeGain": 0.3, "frequencyGain": 0.8
1455+
})
1456+
1457+
# 6. Verify with screenshot
1458+
manage_camera(action="screenshot", camera="FollowCam", include_image=True, max_resolution=512)
1459+
```
1460+
1461+
### Multi-Camera Setup with Blending
1462+
1463+
```python
1464+
# 1. Read current cameras
1465+
# Read mcpforunity://scene/cameras
1466+
1467+
# 2. Create gameplay camera (highest priority = active by default)
1468+
manage_camera(action="create_camera", properties={
1469+
"name": "GameplayCam", "preset": "follow",
1470+
"follow": "Player", "lookAt": "Player", "priority": 10
1471+
})
1472+
1473+
# 3. Create cinematic camera (lower priority, activated on demand)
1474+
manage_camera(action="create_camera", properties={
1475+
"name": "CinematicCam", "preset": "dolly",
1476+
"lookAt": "CutsceneTarget", "priority": 5
1477+
})
1478+
1479+
# 4. Set blend transition
1480+
manage_camera(action="set_blend", properties={"style": "EaseInOut", "duration": 2.0})
1481+
1482+
# 5. Force cinematic camera for a cutscene
1483+
manage_camera(action="force_camera", target="CinematicCam")
1484+
1485+
# 6. Release override to return to priority-based selection
1486+
manage_camera(action="release_override")
1487+
```
1488+
1489+
### Camera Without Cinemachine
1490+
1491+
```python
1492+
# Tier 1 actions work with plain Unity Camera
1493+
manage_camera(action="create_camera", properties={
1494+
"name": "MainCam", "fieldOfView": 50
1495+
})
1496+
1497+
# Set lens
1498+
manage_camera(action="set_lens", target="MainCam", properties={
1499+
"fieldOfView": 60, "nearClipPlane": 0.1, "farClipPlane": 1000
1500+
})
1501+
1502+
# Point camera at target (uses manage_gameobject look_at under the hood)
1503+
manage_camera(action="set_target", target="MainCam", properties={
1504+
"lookAt": "Player"
1505+
})
1506+
1507+
# Screenshot from this camera
1508+
manage_camera(action="screenshot", camera="MainCam", include_image=True, max_resolution=512)
1509+
```
1510+
1511+
### Camera Inspection Workflow
1512+
1513+
```python
1514+
# 1. Read all cameras via resource
1515+
# Read mcpforunity://scene/cameras
1516+
# → Shows brain status, all Cinemachine cameras (priority, pipeline, targets),
1517+
# all Unity cameras (FOV, depth, brain)
1518+
1519+
# 2. Get brain status for blending info
1520+
manage_camera(action="get_brain_status")
1521+
1522+
# 3. List cameras via tool (alternative to resource)
1523+
manage_camera(action="list_cameras")
1524+
1525+
# 4. Multi-view screenshot to see from different angles
1526+
manage_camera(action="screenshot_multiview", max_resolution=480)
1527+
```
1528+
1529+
---
1530+
14291531
## ProBuilder Workflows
14301532

14311533
When `com.unity.probuilder` is installed, prefer ProBuilder shapes over primitive GameObjects for any geometry that needs editing, multi-material faces, or non-trivial shapes. Check availability first with `manage_probuilder(action="ping")`.

MCPForUnity/Editor/Clients/Configurators/QwenCodeConfigurator.cs.meta

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

MCPForUnity/Editor/Helpers/AssetPathUtility.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,10 @@ public static string SanitizeAssetPath(string path)
4747
}
4848

4949
// Ensure path starts with Assets/
50+
if (string.Equals(path, "Assets", StringComparison.OrdinalIgnoreCase))
51+
{
52+
return "Assets";
53+
}
5054
if (!path.StartsWith("Assets/", StringComparison.OrdinalIgnoreCase))
5155
{
5256
return "Assets/" + path.TrimStart('/');

MCPForUnity/Editor/Helpers/ComponentOps.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -564,7 +564,7 @@ private static bool SetObjectReference(SerializedProperty prop, JToken value, ou
564564
if (value.Type == JTokenType.Integer)
565565
{
566566
int id = value.Value<int>();
567-
var resolved = EditorUtility.InstanceIDToObject(id);
567+
var resolved = GameObjectLookup.ResolveInstanceID(id);
568568
if (resolved == null)
569569
{
570570
error = $"No object found with instanceID {id}.";
@@ -580,7 +580,7 @@ private static bool SetObjectReference(SerializedProperty prop, JToken value, ou
580580
if (idToken != null)
581581
{
582582
int id = ParamCoercion.CoerceInt(idToken, 0);
583-
var resolved = EditorUtility.InstanceIDToObject(id);
583+
var resolved = GameObjectLookup.ResolveInstanceID(id);
584584
if (resolved == null)
585585
{
586586
error = $"No object found with instanceID {id}.";

MCPForUnity/Editor/Helpers/GameObjectLookup.cs

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -64,14 +64,24 @@ public static GameObject FindByTarget(JToken target, string searchMethod, bool i
6464
return results.Count > 0 ? FindById(results[0]) : null;
6565
}
6666

67+
/// <summary>
68+
/// Resolves an instance ID to a UnityEngine.Object.
69+
/// </summary>
70+
public static UnityEngine.Object ResolveInstanceID(int instanceId)
71+
{
72+
#if UNITY_6000_3_OR_NEWER
73+
return EditorUtility.EntityIdToObject(instanceId);
74+
#else
75+
return EditorUtility.InstanceIDToObject(instanceId);
76+
#endif
77+
}
78+
6779
/// <summary>
6880
/// Finds a GameObject by its instance ID.
6981
/// </summary>
7082
public static GameObject FindById(int instanceId)
7183
{
72-
#pragma warning disable CS0618 // Type or member is obsolete
73-
return EditorUtility.InstanceIDToObject(instanceId) as GameObject;
74-
#pragma warning restore CS0618
84+
return ResolveInstanceID(instanceId) as GameObject;
7585
}
7686

7787
/// <summary>
@@ -105,9 +115,7 @@ public static List<int> SearchGameObjects(SearchMethod method, string searchTerm
105115
case SearchMethod.ById:
106116
if (int.TryParse(searchTerm, out int instanceId))
107117
{
108-
#pragma warning disable CS0618 // Type or member is obsolete
109-
var obj = EditorUtility.InstanceIDToObject(instanceId) as GameObject;
110-
#pragma warning restore CS0618
118+
var obj = ResolveInstanceID(instanceId) as GameObject;
111119
if (obj != null && (includeInactive || obj.activeInHierarchy))
112120
{
113121
results.Add(instanceId);

MCPForUnity/Editor/Resources/Editor/Selection.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ public static object HandleCommand(JObject @params)
2121
activeObject = UnityEditor.Selection.activeObject?.name,
2222
activeGameObject = UnityEditor.Selection.activeGameObject?.name,
2323
activeTransform = UnityEditor.Selection.activeTransform?.name,
24-
activeInstanceID = UnityEditor.Selection.activeInstanceID,
24+
activeInstanceID = UnityEditor.Selection.activeObject?.GetInstanceID() ?? 0,
2525
count = UnityEditor.Selection.count,
2626
objects = UnityEditor.Selection.objects
2727
.Select(obj => new

0 commit comments

Comments
 (0)