|
5 | 5 | using UnityEditor; |
6 | 6 | using UnityEditor.SceneManagement; |
7 | 7 | using UnityEditorInternal; // Required for tag management |
| 8 | +using UnityEngine; |
8 | 9 |
|
9 | 10 | namespace MCPForUnity.Editor.Tools |
10 | 11 | { |
@@ -46,6 +47,7 @@ public static object HandleCommand(JObject @params) |
46 | 47 | // Parameters for specific actions |
47 | 48 | string tagName = p.Get("tagName"); |
48 | 49 | string layerName = p.Get("layerName"); |
| 50 | + string prefabPath = p.Get("prefabPath") ?? p.Get("path"); |
49 | 51 |
|
50 | 52 | // Route action |
51 | 53 | switch (action) |
@@ -136,6 +138,8 @@ public static object HandleCommand(JObject @params) |
136 | 138 | // return SetQualityLevel(@params["qualityLevel"]); |
137 | 139 |
|
138 | 140 | // Prefab Stage |
| 141 | + case "open_prefab_stage": |
| 142 | + return OpenPrefabStage(prefabPath); |
139 | 143 | case "close_prefab_stage": |
140 | 144 | return ClosePrefabStage(); |
141 | 145 |
|
@@ -176,7 +180,7 @@ public static object HandleCommand(JObject @params) |
176 | 180 |
|
177 | 181 | default: |
178 | 182 | return new ErrorResponse( |
179 | | - $"Unknown action: '{action}'. Supported actions: play, pause, stop, set_active_tool, add_tag, remove_tag, add_layer, remove_layer, close_prefab_stage, deploy_package, restore_package, undo, redo. Use MCP resources for reading editor state, project info, tags, layers, selection, windows, prefab stage, and active tool." |
| 183 | + $"Unknown action: '{action}'. Supported actions: play, pause, stop, set_active_tool, add_tag, remove_tag, add_layer, remove_layer, open_prefab_stage, close_prefab_stage, deploy_package, restore_package, undo, redo. Use MCP resources for reading editor state, project info, tags, layers, selection, windows, prefab stage, and active tool." |
180 | 184 | ); |
181 | 185 | } |
182 | 186 | } |
@@ -398,6 +402,64 @@ private static object RemoveLayer(string layerName) |
398 | 402 |
|
399 | 403 | // --- Prefab Stage Methods --- |
400 | 404 |
|
| 405 | + private static object OpenPrefabStage(string requestedPath) |
| 406 | + { |
| 407 | + if (string.IsNullOrWhiteSpace(requestedPath)) |
| 408 | + { |
| 409 | + return new ErrorResponse("'prefabPath' parameter is required for open_prefab_stage."); |
| 410 | + } |
| 411 | + |
| 412 | + string sanitizedPath = AssetPathUtility.SanitizeAssetPath(requestedPath); |
| 413 | + if (sanitizedPath == null) |
| 414 | + { |
| 415 | + return new ErrorResponse($"Invalid prefab path (path traversal detected): '{requestedPath}'."); |
| 416 | + } |
| 417 | + |
| 418 | + if (!sanitizedPath.StartsWith("Assets/", StringComparison.OrdinalIgnoreCase)) |
| 419 | + { |
| 420 | + return new ErrorResponse($"Prefab path must be within the Assets folder. Got: '{sanitizedPath}'."); |
| 421 | + } |
| 422 | + |
| 423 | + if (!sanitizedPath.EndsWith(".prefab", StringComparison.OrdinalIgnoreCase)) |
| 424 | + { |
| 425 | + return new ErrorResponse($"Prefab path must end with '.prefab'. Got: '{sanitizedPath}'."); |
| 426 | + } |
| 427 | + |
| 428 | + try |
| 429 | + { |
| 430 | + GameObject prefabAsset = AssetDatabase.LoadAssetAtPath<GameObject>(sanitizedPath); |
| 431 | + if (prefabAsset == null) |
| 432 | + { |
| 433 | + return new ErrorResponse($"Prefab asset not found at '{sanitizedPath}'."); |
| 434 | + } |
| 435 | + |
| 436 | + var prefabStage = PrefabStageUtility.OpenPrefab(sanitizedPath); |
| 437 | + bool enteredStage = prefabStage != null |
| 438 | + && string.Equals(prefabStage.assetPath, sanitizedPath, StringComparison.OrdinalIgnoreCase) |
| 439 | + && prefabStage.prefabContentsRoot != null; |
| 440 | + |
| 441 | + if (!enteredStage) |
| 442 | + { |
| 443 | + return new ErrorResponse($"Failed to open prefab stage for '{sanitizedPath}'. PrefabStageUtility.OpenPrefab did not enter the requested prefab stage."); |
| 444 | + } |
| 445 | + |
| 446 | + return new SuccessResponse( |
| 447 | + $"Opened prefab stage for '{sanitizedPath}'.", |
| 448 | + new |
| 449 | + { |
| 450 | + prefabPath = sanitizedPath, |
| 451 | + openedPrefabPath = prefabStage.assetPath, |
| 452 | + rootName = prefabStage.prefabContentsRoot.name, |
| 453 | + enteredPrefabStage = enteredStage |
| 454 | + } |
| 455 | + ); |
| 456 | + } |
| 457 | + catch (Exception e) |
| 458 | + { |
| 459 | + return new ErrorResponse($"Error opening prefab stage: {e.Message}"); |
| 460 | + } |
| 461 | + } |
| 462 | + |
401 | 463 | private static object ClosePrefabStage() |
402 | 464 | { |
403 | 465 | try |
|
0 commit comments