diff --git a/MCPForUnity/Editor/Tools/Prefabs/ManagePrefabs.cs b/MCPForUnity/Editor/Tools/Prefabs/ManagePrefabs.cs index 65d158a5d..8e4733fe1 100644 --- a/MCPForUnity/Editor/Tools/Prefabs/ManagePrefabs.cs +++ b/MCPForUnity/Editor/Tools/Prefabs/ManagePrefabs.cs @@ -60,11 +60,15 @@ public static object HandleCommand(JObject @params) return OpenPrefabStage(prefabPath); } case ACTION_SAVE_PREFAB_STAGE: - return SavePrefabStage(); + { + bool refresh = @params["refresh"]?.ToObject() ?? true; + return SavePrefabStage(refresh); + } case ACTION_CLOSE_PREFAB_STAGE: { bool saveBeforeClose = @params["saveBeforeClose"]?.ToObject() ?? false; - return ClosePrefabStage(saveBeforeClose); + bool refresh = @params["refresh"]?.ToObject() ?? true; + return ClosePrefabStage(saveBeforeClose, refresh); } default: return new ErrorResponse($"Unknown action: '{action}'. Valid actions are: {SupportedActions}."); @@ -1338,7 +1342,7 @@ private static object OpenPrefabStage(string requestedPath) } } - private static object SavePrefabStage() + private static object SavePrefabStage(bool refreshAfterSave = true) { try { @@ -1348,12 +1352,12 @@ private static object SavePrefabStage() return new ErrorResponse("Not currently in prefab editing mode. Open a prefab stage first with open_prefab_stage."); } - if (!TrySavePrefabStage(prefabStage, out string prefabPath, out string errorMessage)) + if (!TrySavePrefabStage(prefabStage, refreshAfterSave, out string prefabPath, out string errorMessage)) { return new ErrorResponse(errorMessage); } - return new SuccessResponse($"Saved prefab stage changes for '{prefabPath}'.", new { prefabPath, saved = true }); + return new SuccessResponse($"Saved prefab stage changes for '{prefabPath}'.", new { prefabPath, saved = true, refreshed = refreshAfterSave }); } catch (Exception e) { @@ -1361,7 +1365,7 @@ private static object SavePrefabStage() } } - private static object ClosePrefabStage(bool saveBeforeClose = false) + private static object ClosePrefabStage(bool saveBeforeClose = false, bool refreshAfterSave = true) { try { @@ -1373,7 +1377,7 @@ private static object ClosePrefabStage(bool saveBeforeClose = false) if (saveBeforeClose) { - if (!TrySavePrefabStage(prefabStage, out _, out string errorMessage)) + if (!TrySavePrefabStage(prefabStage, refreshAfterSave, out _, out string errorMessage)) { return new ErrorResponse(errorMessage); } @@ -1389,7 +1393,7 @@ private static object ClosePrefabStage(bool saveBeforeClose = false) } } - private static bool TrySavePrefabStage(PrefabStage prefabStage, out string prefabPath, out string errorMessage) + private static bool TrySavePrefabStage(PrefabStage prefabStage, bool refreshAfterSave, out string prefabPath, out string errorMessage) { prefabPath = prefabStage.assetPath; errorMessage = null; @@ -1410,7 +1414,10 @@ private static bool TrySavePrefabStage(PrefabStage prefabStage, out string prefa prefabStage.ClearDirtiness(); AssetDatabase.SaveAssets(); - AssetDatabase.Refresh(); + if (refreshAfterSave) + { + AssetDatabase.Refresh(); + } return true; } diff --git a/Server/src/services/tools/manage_prefabs.py b/Server/src/services/tools/manage_prefabs.py index de7373c92..c76da08e6 100644 --- a/Server/src/services/tools/manage_prefabs.py +++ b/Server/src/services/tools/manage_prefabs.py @@ -38,7 +38,8 @@ "Use component_properties with modify_contents to set serialized fields on existing components " "(e.g. component_properties={\"Rigidbody\": {\"mass\": 5.0}, \"MyScript\": {\"health\": 100}}). " "Supports object references via {\"guid\": \"...\"}, {\"path\": \"Assets/...\"}, or {\"instanceID\": 123}. " - "Use manage_asset action=search filterType=Prefab to list prefabs." + "Use manage_asset action=search filterType=Prefab to list prefabs. " + "Performance tip: for save_prefab_stage, pass refresh=false to skip the trailing AssetDatabase.Refresh() (often ~1s on large projects); SaveAssets() still runs so dirty assets are flushed. Call refresh_unity yourself when you actually need the asset database to reimport." ), annotations=ToolAnnotations( title="Manage Prefabs", @@ -78,6 +79,7 @@ async def manage_prefabs( create_child: Annotated[dict[str, Any] | list[dict[str, Any]], "Create child GameObject(s) in the prefab. Single object or array of objects, each with: name (required), parent (optional, defaults to target), source_prefab_path (optional: asset path to instantiate as nested prefab, e.g. 'Assets/Prefabs/Bullet.prefab'), primitive_type (optional: Cube, Sphere, Capsule, Cylinder, Plane, Quad), position, rotation, scale, components_to_add, tag, layer, set_active. source_prefab_path and primitive_type are mutually exclusive."] | None = None, delete_child: Annotated[str | list[str], "Child name(s) or path(s) to remove from the prefab. Supports single string or array for batch deletion (e.g. 'Child1' or ['Child1', 'Child1/Grandchild'])."] | None = None, component_properties: Annotated[dict[str, dict[str, Any]], "Set properties on existing components in modify_contents. Keys are component type names, values are dicts of property name to value. Example: {\"Rigidbody\": {\"mass\": 5.0}, \"MyScript\": {\"health\": 100}}. Supports object references via {\"guid\": \"...\"}, {\"path\": \"Assets/...\"}, or {\"instanceID\": 123}. For Sprite sub-assets: {\"guid\": \"...\", \"spriteName\": \"\"}. Single-sprite textures auto-resolve."] | None = None, + refresh: Annotated[bool, "For save_prefab_stage: run AssetDatabase.Refresh() after writing the prefab (default true). Set false to skip the ~1s trailing import; SaveAssets() still runs so dirty assets are flushed. Call refresh_unity yourself when needed."] | None = None, ) -> dict[str, Any]: # Back-compat: map 'name' → 'target' for create_from_gameobject (Unity accepts both) if action == "create_from_gameobject" and target is None and name is not None: @@ -198,6 +200,10 @@ def normalize_child_params(child: Any, index: int | None = None) -> tuple[dict | if delete_child is not None: params["deleteChild"] = delete_child + refresh_val = coerce_bool(refresh) + if refresh_val is not None: + params["refresh"] = refresh_val + # Send command to Unity response = await send_with_unity_instance( async_send_command_with_retry, unity_instance, "manage_prefabs", params