added object existance validation
parent
276ac8166f
commit
36b5b224b3
|
|
@ -108,31 +108,38 @@ def asset_creation_strategy() -> str:
|
||||||
|
|
||||||
## Best Practices
|
## Best Practices
|
||||||
|
|
||||||
1. **Error Handling**:
|
1. **Existence Checking**:
|
||||||
|
|
||||||
|
- ALWAYS check if objects, scripts, assets, or materials exist before creating or updating them
|
||||||
|
- Use appropriate search tools (`find_objects_by_name`, `list_scripts`, `get_asset_list`) to verify existence
|
||||||
|
- Handle both cases: creation when it doesn't exist and updating when it does
|
||||||
|
- Implement proper error handling when an expected resource is not found
|
||||||
|
|
||||||
|
2. **Error Handling**:
|
||||||
|
|
||||||
- Always include try-catch blocks in Python tools
|
- Always include try-catch blocks in Python tools
|
||||||
- Validate parameters in C# handlers
|
- Validate parameters in C# handlers
|
||||||
- Return meaningful error messages
|
- Return meaningful error messages
|
||||||
|
|
||||||
2. **Documentation**:
|
3. **Documentation**:
|
||||||
|
|
||||||
- Add XML documentation to C# handlers
|
- Add XML documentation to C# handlers
|
||||||
- Include detailed docstrings in Python tools
|
- Include detailed docstrings in Python tools
|
||||||
- Update the prompt with clear usage instructions
|
- Update the prompt with clear usage instructions
|
||||||
|
|
||||||
3. **Parameter Validation**:
|
4. **Parameter Validation**:
|
||||||
|
|
||||||
- Validate parameters on both Python and C# sides
|
- Validate parameters on both Python and C# sides
|
||||||
- Use appropriate types (str, int, float, List, etc.)
|
- Use appropriate types (str, int, float, List, etc.)
|
||||||
- Provide default values when appropriate
|
- Provide default values when appropriate
|
||||||
|
|
||||||
4. **Testing**:
|
5. **Testing**:
|
||||||
|
|
||||||
- Test the tool in both Unity Editor and Python environments
|
- Test the tool in both Unity Editor and Python environments
|
||||||
- Verify error handling works as expected
|
- Verify error handling works as expected
|
||||||
- Check that the tool integrates well with existing functionality
|
- Check that the tool integrates well with existing functionality
|
||||||
|
|
||||||
5. **Code Organization**:
|
6. **Code Organization**:
|
||||||
- Group related tools in appropriate handler classes
|
- Group related tools in appropriate handler classes
|
||||||
- Keep tools focused and single-purpose
|
- Keep tools focused and single-purpose
|
||||||
- Follow existing naming conventions
|
- Follow existing naming conventions
|
||||||
|
|
@ -150,14 +157,29 @@ public static class ExampleHandler
|
||||||
{
|
{
|
||||||
string prefabName = (string)@params["prefab_name"];
|
string prefabName = (string)@params["prefab_name"];
|
||||||
string template = (string)@params["template"];
|
string template = (string)@params["template"];
|
||||||
|
bool overwrite = @params["overwrite"] != null ? (bool)@params["overwrite"] : false;
|
||||||
|
|
||||||
|
// Check if the prefab already exists
|
||||||
|
string prefabPath = $"Assets/Prefabs/{prefabName}.prefab";
|
||||||
|
bool prefabExists = System.IO.File.Exists(prefabPath);
|
||||||
|
|
||||||
|
if (prefabExists && !overwrite)
|
||||||
|
{
|
||||||
|
return new {
|
||||||
|
message = $"Prefab already exists: {prefabName}. Use overwrite=true to replace it.",
|
||||||
|
exists = true,
|
||||||
|
path = prefabPath
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
// Implementation
|
// Implementation
|
||||||
GameObject prefab = new GameObject(prefabName);
|
GameObject prefab = new GameObject(prefabName);
|
||||||
// ... setup prefab ...
|
// ... setup prefab ...
|
||||||
|
|
||||||
return new {
|
return new {
|
||||||
message = $"Created prefab: {prefabName}",
|
message = prefabExists ? $"Updated prefab: {prefabName}" : $"Created prefab: {prefabName}",
|
||||||
path = $"Assets/Prefabs/{prefabName}.prefab"
|
exists = prefabExists,
|
||||||
|
path = prefabPath
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -170,33 +192,51 @@ public static class ExampleHandler
|
||||||
def create_prefab(
|
def create_prefab(
|
||||||
ctx: Context,
|
ctx: Context,
|
||||||
prefab_name: str,
|
prefab_name: str,
|
||||||
template: str = "default"
|
template: str = "default",
|
||||||
|
overwrite: bool = False
|
||||||
) -> str:
|
) -> str:
|
||||||
"""Create a new prefab in the project.
|
"""Create a new prefab in the project or update if it exists.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
ctx: The MCP context
|
ctx: The MCP context
|
||||||
prefab_name: Name for the new prefab
|
prefab_name: Name for the new prefab
|
||||||
template: Template to use (default: "default")
|
template: Template to use (default: "default")
|
||||||
|
overwrite: Whether to overwrite an existing prefab (default: False)
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
str: Success message or error details
|
str: Success message or error details
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
|
# First check if the prefab already exists
|
||||||
|
assets = get_unity_connection().send_command("GET_ASSET_LIST", {
|
||||||
|
"type": "Prefab",
|
||||||
|
"search_pattern": prefab_name,
|
||||||
|
"folder": "Assets/Prefabs"
|
||||||
|
}).get("assets", [])
|
||||||
|
|
||||||
|
prefab_exists = any(asset.get("name") == prefab_name for asset in assets)
|
||||||
|
|
||||||
|
if prefab_exists and not overwrite:
|
||||||
|
return f"Prefab '{prefab_name}' already exists. Use overwrite=True to replace it."
|
||||||
|
|
||||||
|
# Create or update the prefab
|
||||||
response = get_unity_connection().send_command("CREATE_PREFAB", {
|
response = get_unity_connection().send_command("CREATE_PREFAB", {
|
||||||
"prefab_name": prefab_name,
|
"prefab_name": prefab_name,
|
||||||
"template": template
|
"template": template,
|
||||||
|
"overwrite": overwrite
|
||||||
})
|
})
|
||||||
return response.get("message", "Prefab created successfully")
|
|
||||||
|
return response.get("message", "Prefab operation completed successfully")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
return f"Error creating prefab: {str(e)}"
|
return f"Error with prefab operation: {str(e)}"
|
||||||
```
|
```
|
||||||
|
|
||||||
3. **Update Prompt**:
|
3. **Update Prompt**:
|
||||||
|
|
||||||
```python
|
```python
|
||||||
"1. **Prefab Management**:\n"
|
"1. **Prefab Management**:\n"
|
||||||
" - Create prefabs with `create_prefab(prefab_name, template)`\n"
|
" - ALWAYS check if a prefab exists before creating it\n"
|
||||||
|
" - Create or update prefabs with `create_prefab(prefab_name, template, overwrite=False)`\n"
|
||||||
```
|
```
|
||||||
|
|
||||||
## Troubleshooting
|
## Troubleshooting
|
||||||
|
|
|
||||||
|
|
@ -56,6 +56,7 @@ def asset_creation_strategy() -> str:
|
||||||
" - `open_scene(path)`, `save_scene(path)` - Open/save scenes\n"
|
" - `open_scene(path)`, `save_scene(path)` - Open/save scenes\n"
|
||||||
" - `new_scene(path)`, `change_scene(path, save_current)` - Create/switch scenes\n\n"
|
" - `new_scene(path)`, `change_scene(path, save_current)` - Create/switch scenes\n\n"
|
||||||
"3. **Object Management**\n"
|
"3. **Object Management**\n"
|
||||||
|
" - ALWAYS use `find_objects_by_name(name)` to check if an object exists before creating or modifying it\n"
|
||||||
" - `create_object(name, type)` - Create objects (e.g. `CUBE`, `SPHERE`, `EMPTY`, `CAMERA`)\n"
|
" - `create_object(name, type)` - Create objects (e.g. `CUBE`, `SPHERE`, `EMPTY`, `CAMERA`)\n"
|
||||||
" - `delete_object(name)` - Remove objects\n"
|
" - `delete_object(name)` - Remove objects\n"
|
||||||
" - `set_object_transform(name, location, rotation, scale)` - Modify object position, rotation, and scale\n"
|
" - `set_object_transform(name, location, rotation, scale)` - Modify object position, rotation, and scale\n"
|
||||||
|
|
@ -65,11 +66,13 @@ def asset_creation_strategy() -> str:
|
||||||
" - `find_objects_by_name(name)` - Find objects by name\n"
|
" - `find_objects_by_name(name)` - Find objects by name\n"
|
||||||
" - `get_hierarchy()` - Get object hierarchy\n"
|
" - `get_hierarchy()` - Get object hierarchy\n"
|
||||||
"4. **Script Management**\n"
|
"4. **Script Management**\n"
|
||||||
|
" - ALWAYS use `list_scripts(folder_path)` or `view_script(path)` to check if a script exists before creating or updating it\n"
|
||||||
" - `create_script(name, type, namespace, template)` - Create scripts\n"
|
" - `create_script(name, type, namespace, template)` - Create scripts\n"
|
||||||
" - `view_script(path)`, `update_script(path, content)` - View/modify scripts\n"
|
" - `view_script(path)`, `update_script(path, content)` - View/modify scripts\n"
|
||||||
" - `attach_script(object_name, script_name)` - Add scripts to objects\n"
|
" - `attach_script(object_name, script_name)` - Add scripts to objects\n"
|
||||||
" - `list_scripts(folder_path)` - List scripts in folder\n\n"
|
" - `list_scripts(folder_path)` - List scripts in folder\n\n"
|
||||||
"5. **Asset Management**\n"
|
"5. **Asset Management**\n"
|
||||||
|
" - ALWAYS use `get_asset_list(type, search_pattern, folder)` to check if an asset exists before creating or importing it\n"
|
||||||
" - `import_asset(source_path, target_path)` - Import external assets\n"
|
" - `import_asset(source_path, target_path)` - Import external assets\n"
|
||||||
" - `instantiate_prefab(path, pos_x, pos_y, pos_z, rot_x, rot_y, rot_z)` - Create prefab instances\n"
|
" - `instantiate_prefab(path, pos_x, pos_y, pos_z, rot_x, rot_y, rot_z)` - Create prefab instances\n"
|
||||||
" - `create_prefab(object_name, path)`, `apply_prefab(object_name, path)` - Manage prefabs\n"
|
" - `create_prefab(object_name, path)`, `apply_prefab(object_name, path)` - Manage prefabs\n"
|
||||||
|
|
@ -77,9 +80,11 @@ def asset_creation_strategy() -> str:
|
||||||
" - Use relative paths for Unity assets (e.g., 'Assets/Models/MyModel.fbx')\n"
|
" - Use relative paths for Unity assets (e.g., 'Assets/Models/MyModel.fbx')\n"
|
||||||
" - Use absolute paths for external files\n\n"
|
" - Use absolute paths for external files\n\n"
|
||||||
"6. **Material Management**\n"
|
"6. **Material Management**\n"
|
||||||
|
" - ALWAYS check if a material exists before creating or modifying it\n"
|
||||||
" - `set_material(object_name, material_name, color)` - Apply/create materials\n"
|
" - `set_material(object_name, material_name, color)` - Apply/create materials\n"
|
||||||
" - Use RGB colors (0.0-1.0 range)\n\n"
|
" - Use RGB colors (0.0-1.0 range)\n\n"
|
||||||
"7. **Best Practices**\n"
|
"7. **Best Practices**\n"
|
||||||
|
" - ALWAYS verify existence before creating or updating any objects, scripts, assets, or materials\n"
|
||||||
" - Use meaningful names for objects and scripts\n"
|
" - Use meaningful names for objects and scripts\n"
|
||||||
" - Keep scripts organized in folders with namespaces\n"
|
" - Keep scripts organized in folders with namespaces\n"
|
||||||
" - Verify changes after modifications\n"
|
" - Verify changes after modifications\n"
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,8 @@ def register_asset_tools(mcp: FastMCP):
|
||||||
def import_asset(
|
def import_asset(
|
||||||
ctx: Context,
|
ctx: Context,
|
||||||
source_path: str,
|
source_path: str,
|
||||||
target_path: str
|
target_path: str,
|
||||||
|
overwrite: bool = False
|
||||||
) -> str:
|
) -> str:
|
||||||
"""Import an asset (e.g., 3D model, texture) into the Unity project.
|
"""Import an asset (e.g., 3D model, texture) into the Unity project.
|
||||||
|
|
||||||
|
|
@ -17,21 +18,45 @@ def register_asset_tools(mcp: FastMCP):
|
||||||
ctx: The MCP context
|
ctx: The MCP context
|
||||||
source_path: Path to the source file on disk
|
source_path: Path to the source file on disk
|
||||||
target_path: Path where the asset should be imported in the Unity project (relative to Assets folder)
|
target_path: Path where the asset should be imported in the Unity project (relative to Assets folder)
|
||||||
|
overwrite: Whether to overwrite if an asset already exists at the target path (default: False)
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
str: Success message or error details
|
str: Success message or error details
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
|
unity = get_unity_connection()
|
||||||
|
|
||||||
# Parameter validation
|
# Parameter validation
|
||||||
if not source_path or not isinstance(source_path, str):
|
if not source_path or not isinstance(source_path, str):
|
||||||
return f"Error importing asset: source_path must be a valid string"
|
return f"Error importing asset: source_path must be a valid string"
|
||||||
|
|
||||||
if not target_path or not isinstance(target_path, str):
|
if not target_path or not isinstance(target_path, str):
|
||||||
return f"Error importing asset: target_path must be a valid string"
|
return f"Error importing asset: target_path must be a valid string"
|
||||||
|
|
||||||
|
# Check if the source file exists (on local disk)
|
||||||
|
import os
|
||||||
|
if not os.path.exists(source_path):
|
||||||
|
return f"Error importing asset: Source file '{source_path}' does not exist"
|
||||||
|
|
||||||
|
# Extract the target directory and filename
|
||||||
|
target_dir = '/'.join(target_path.split('/')[:-1])
|
||||||
|
target_filename = target_path.split('/')[-1]
|
||||||
|
|
||||||
|
# Check if an asset already exists at the target path
|
||||||
|
existing_assets = unity.send_command("GET_ASSET_LIST", {
|
||||||
|
"search_pattern": target_filename,
|
||||||
|
"folder": target_dir or "Assets"
|
||||||
|
}).get("assets", [])
|
||||||
|
|
||||||
|
# Check if any asset matches the exact path
|
||||||
|
asset_exists = any(asset.get("path") == target_path for asset in existing_assets)
|
||||||
|
if asset_exists and not overwrite:
|
||||||
|
return f"Asset already exists at '{target_path}'. Use overwrite=True to replace it."
|
||||||
|
|
||||||
response = get_unity_connection().send_command("IMPORT_ASSET", {
|
response = unity.send_command("IMPORT_ASSET", {
|
||||||
"source_path": source_path,
|
"source_path": source_path,
|
||||||
"target_path": target_path
|
"target_path": target_path,
|
||||||
|
"overwrite": overwrite
|
||||||
})
|
})
|
||||||
|
|
||||||
if not response.get("success", False):
|
if not response.get("success", False):
|
||||||
|
|
@ -68,6 +93,8 @@ def register_asset_tools(mcp: FastMCP):
|
||||||
str: Success message or error details
|
str: Success message or error details
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
|
unity = get_unity_connection()
|
||||||
|
|
||||||
# Parameter validation
|
# Parameter validation
|
||||||
if not prefab_path or not isinstance(prefab_path, str):
|
if not prefab_path or not isinstance(prefab_path, str):
|
||||||
return f"Error instantiating prefab: prefab_path must be a valid string"
|
return f"Error instantiating prefab: prefab_path must be a valid string"
|
||||||
|
|
@ -86,7 +113,26 @@ def register_asset_tools(mcp: FastMCP):
|
||||||
if not isinstance(param_value, (int, float)):
|
if not isinstance(param_value, (int, float)):
|
||||||
return f"Error instantiating prefab: {param_name} must be a number"
|
return f"Error instantiating prefab: {param_name} must be a number"
|
||||||
|
|
||||||
response = get_unity_connection().send_command("INSTANTIATE_PREFAB", {
|
# Check if the prefab exists
|
||||||
|
prefab_dir = '/'.join(prefab_path.split('/')[:-1]) or "Assets"
|
||||||
|
prefab_name = prefab_path.split('/')[-1]
|
||||||
|
|
||||||
|
# Ensure prefab has .prefab extension for searching
|
||||||
|
if not prefab_name.lower().endswith('.prefab'):
|
||||||
|
prefab_name = f"{prefab_name}.prefab"
|
||||||
|
prefab_path = f"{prefab_path}.prefab"
|
||||||
|
|
||||||
|
prefab_assets = unity.send_command("GET_ASSET_LIST", {
|
||||||
|
"type": "Prefab",
|
||||||
|
"search_pattern": prefab_name,
|
||||||
|
"folder": prefab_dir
|
||||||
|
}).get("assets", [])
|
||||||
|
|
||||||
|
prefab_exists = any(asset.get("path") == prefab_path for asset in prefab_assets)
|
||||||
|
if not prefab_exists:
|
||||||
|
return f"Prefab '{prefab_path}' not found in the project."
|
||||||
|
|
||||||
|
response = unity.send_command("INSTANTIATE_PREFAB", {
|
||||||
"prefab_path": prefab_path,
|
"prefab_path": prefab_path,
|
||||||
"position_x": position_x,
|
"position_x": position_x,
|
||||||
"position_y": position_y,
|
"position_y": position_y,
|
||||||
|
|
@ -107,7 +153,8 @@ def register_asset_tools(mcp: FastMCP):
|
||||||
def create_prefab(
|
def create_prefab(
|
||||||
ctx: Context,
|
ctx: Context,
|
||||||
object_name: str,
|
object_name: str,
|
||||||
prefab_path: str
|
prefab_path: str,
|
||||||
|
overwrite: bool = False
|
||||||
) -> str:
|
) -> str:
|
||||||
"""Create a new prefab asset from a GameObject in the scene.
|
"""Create a new prefab asset from a GameObject in the scene.
|
||||||
|
|
||||||
|
|
@ -115,25 +162,51 @@ def register_asset_tools(mcp: FastMCP):
|
||||||
ctx: The MCP context
|
ctx: The MCP context
|
||||||
object_name: Name of the GameObject in the scene to create prefab from
|
object_name: Name of the GameObject in the scene to create prefab from
|
||||||
prefab_path: Path where the prefab should be saved (relative to Assets folder)
|
prefab_path: Path where the prefab should be saved (relative to Assets folder)
|
||||||
|
overwrite: Whether to overwrite if a prefab already exists at the path (default: False)
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
str: Success message or error details
|
str: Success message or error details
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
|
unity = get_unity_connection()
|
||||||
|
|
||||||
# Parameter validation
|
# Parameter validation
|
||||||
if not object_name or not isinstance(object_name, str):
|
if not object_name or not isinstance(object_name, str):
|
||||||
return f"Error creating prefab: object_name must be a valid string"
|
return f"Error creating prefab: object_name must be a valid string"
|
||||||
|
|
||||||
if not prefab_path or not isinstance(prefab_path, str):
|
if not prefab_path or not isinstance(prefab_path, str):
|
||||||
return f"Error creating prefab: prefab_path must be a valid string"
|
return f"Error creating prefab: prefab_path must be a valid string"
|
||||||
|
|
||||||
|
# Check if the GameObject exists
|
||||||
|
found_objects = unity.send_command("FIND_OBJECTS_BY_NAME", {
|
||||||
|
"name": object_name
|
||||||
|
}).get("objects", [])
|
||||||
|
|
||||||
|
if not found_objects:
|
||||||
|
return f"GameObject '{object_name}' not found in the scene."
|
||||||
|
|
||||||
# Verify prefab path has proper extension
|
# Verify prefab path has proper extension
|
||||||
if not prefab_path.lower().endswith('.prefab'):
|
if not prefab_path.lower().endswith('.prefab'):
|
||||||
prefab_path = f"{prefab_path}.prefab"
|
prefab_path = f"{prefab_path}.prefab"
|
||||||
|
|
||||||
response = get_unity_connection().send_command("CREATE_PREFAB", {
|
# Check if a prefab already exists at this path
|
||||||
|
prefab_dir = '/'.join(prefab_path.split('/')[:-1]) or "Assets"
|
||||||
|
prefab_name = prefab_path.split('/')[-1]
|
||||||
|
|
||||||
|
prefab_assets = unity.send_command("GET_ASSET_LIST", {
|
||||||
|
"type": "Prefab",
|
||||||
|
"search_pattern": prefab_name,
|
||||||
|
"folder": prefab_dir
|
||||||
|
}).get("assets", [])
|
||||||
|
|
||||||
|
prefab_exists = any(asset.get("path") == prefab_path for asset in prefab_assets)
|
||||||
|
if prefab_exists and not overwrite:
|
||||||
|
return f"Prefab already exists at '{prefab_path}'. Use overwrite=True to replace it."
|
||||||
|
|
||||||
|
response = unity.send_command("CREATE_PREFAB", {
|
||||||
"object_name": object_name,
|
"object_name": object_name,
|
||||||
"prefab_path": prefab_path
|
"prefab_path": prefab_path,
|
||||||
|
"overwrite": overwrite
|
||||||
})
|
})
|
||||||
|
|
||||||
if not response.get("success", False):
|
if not response.get("success", False):
|
||||||
|
|
@ -158,7 +231,27 @@ def register_asset_tools(mcp: FastMCP):
|
||||||
str: Success message or error details
|
str: Success message or error details
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
response = get_unity_connection().send_command("APPLY_PREFAB", {
|
unity = get_unity_connection()
|
||||||
|
|
||||||
|
# Check if the GameObject exists
|
||||||
|
found_objects = unity.send_command("FIND_OBJECTS_BY_NAME", {
|
||||||
|
"name": object_name
|
||||||
|
}).get("objects", [])
|
||||||
|
|
||||||
|
if not found_objects:
|
||||||
|
return f"GameObject '{object_name}' not found in the scene."
|
||||||
|
|
||||||
|
# Check if the object is a prefab instance
|
||||||
|
object_props = unity.send_command("GET_OBJECT_PROPERTIES", {
|
||||||
|
"name": object_name
|
||||||
|
})
|
||||||
|
|
||||||
|
# Try to extract prefab status from properties
|
||||||
|
is_prefab_instance = object_props.get("isPrefabInstance", False)
|
||||||
|
if not is_prefab_instance:
|
||||||
|
return f"GameObject '{object_name}' is not a prefab instance."
|
||||||
|
|
||||||
|
response = unity.send_command("APPLY_PREFAB", {
|
||||||
"object_name": object_name
|
"object_name": object_name
|
||||||
})
|
})
|
||||||
return response.get("message", "Prefab changes applied successfully")
|
return response.get("message", "Prefab changes applied successfully")
|
||||||
|
|
|
||||||
|
|
@ -92,6 +92,34 @@ def register_editor_tools(mcp: FastMCP):
|
||||||
str: Success message or error details
|
str: Success message or error details
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
|
# Validate platform
|
||||||
|
valid_platforms = ["windows", "mac", "linux", "android", "ios", "webgl"]
|
||||||
|
if platform.lower() not in valid_platforms:
|
||||||
|
return f"Error: '{platform}' is not a valid platform. Valid platforms are: {', '.join(valid_platforms)}"
|
||||||
|
|
||||||
|
# Check if build_path exists and is writable
|
||||||
|
import os
|
||||||
|
|
||||||
|
# Check if the directory exists
|
||||||
|
build_dir = os.path.dirname(build_path)
|
||||||
|
if not os.path.exists(build_dir):
|
||||||
|
return f"Error: Build directory '{build_dir}' does not exist. Please create it first."
|
||||||
|
|
||||||
|
# Check if the directory is writable
|
||||||
|
if not os.access(build_dir, os.W_OK):
|
||||||
|
return f"Error: Build directory '{build_dir}' is not writable."
|
||||||
|
|
||||||
|
# If the build path itself exists, check if it's a file or directory
|
||||||
|
if os.path.exists(build_path):
|
||||||
|
if os.path.isfile(build_path):
|
||||||
|
# If it's a file, check if it's writable
|
||||||
|
if not os.access(build_path, os.W_OK):
|
||||||
|
return f"Error: Existing build file '{build_path}' is not writable."
|
||||||
|
elif os.path.isdir(build_path):
|
||||||
|
# If it's a directory, check if it's writable
|
||||||
|
if not os.access(build_path, os.W_OK):
|
||||||
|
return f"Error: Existing build directory '{build_path}' is not writable."
|
||||||
|
|
||||||
response = get_unity_connection().send_command("EDITOR_CONTROL", {
|
response = get_unity_connection().send_command("EDITOR_CONTROL", {
|
||||||
"command": "BUILD",
|
"command": "BUILD",
|
||||||
"params": {
|
"params": {
|
||||||
|
|
@ -104,17 +132,41 @@ def register_editor_tools(mcp: FastMCP):
|
||||||
return f"Error building project: {str(e)}"
|
return f"Error building project: {str(e)}"
|
||||||
|
|
||||||
@mcp.tool()
|
@mcp.tool()
|
||||||
def execute_command(ctx: Context, command_name: str) -> str:
|
def execute_command(ctx: Context, command_name: str, validate_command: bool = True) -> str:
|
||||||
"""Execute a specific editor command or custom script within the Unity editor.
|
"""Execute a specific editor command or custom script within the Unity editor.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
command_name: Name of the editor command to execute (e.g., "Edit/Preferences")
|
command_name: Name of the editor command to execute (e.g., "Edit/Preferences")
|
||||||
|
validate_command: Whether to validate the command existence before executing (default: True)
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
str: Success message or error details
|
str: Success message or error details
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
response = get_unity_connection().send_command("EDITOR_CONTROL", {
|
unity = get_unity_connection()
|
||||||
|
|
||||||
|
# Optionally validate if the command exists
|
||||||
|
if validate_command:
|
||||||
|
# Get a list of available commands from Unity
|
||||||
|
available_commands = unity.send_command("EDITOR_CONTROL", {
|
||||||
|
"command": "GET_AVAILABLE_COMMANDS"
|
||||||
|
}).get("commands", [])
|
||||||
|
|
||||||
|
# Check if the command exists in the list
|
||||||
|
if available_commands and command_name not in available_commands:
|
||||||
|
# If command doesn't exist, try to find similar commands as suggestions
|
||||||
|
similar_commands = [cmd for cmd in available_commands if command_name.lower() in cmd.lower()]
|
||||||
|
suggestion_msg = ""
|
||||||
|
if similar_commands:
|
||||||
|
suggestion_msg = f" Did you mean one of these: {', '.join(similar_commands[:5])}"
|
||||||
|
if len(similar_commands) > 5:
|
||||||
|
suggestion_msg += " or others?"
|
||||||
|
else:
|
||||||
|
suggestion_msg += "?"
|
||||||
|
|
||||||
|
return f"Error: Command '{command_name}' not found.{suggestion_msg}"
|
||||||
|
|
||||||
|
response = unity.send_command("EDITOR_CONTROL", {
|
||||||
"command": "EXECUTE_COMMAND",
|
"command": "EXECUTE_COMMAND",
|
||||||
"params": {
|
"params": {
|
||||||
"commandName": command_name
|
"commandName": command_name
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,8 @@ def register_material_tools(mcp: FastMCP):
|
||||||
ctx: Context,
|
ctx: Context,
|
||||||
object_name: str,
|
object_name: str,
|
||||||
material_name: str = None,
|
material_name: str = None,
|
||||||
color: List[float] = None
|
color: List[float] = None,
|
||||||
|
create_if_missing: bool = True
|
||||||
) -> str:
|
) -> str:
|
||||||
"""
|
"""
|
||||||
Apply or create a material for a game object.
|
Apply or create a material for a game object.
|
||||||
|
|
@ -19,14 +20,56 @@ def register_material_tools(mcp: FastMCP):
|
||||||
object_name: Target game object.
|
object_name: Target game object.
|
||||||
material_name: Optional material name.
|
material_name: Optional material name.
|
||||||
color: Optional [R, G, B] values (0.0-1.0).
|
color: Optional [R, G, B] values (0.0-1.0).
|
||||||
|
create_if_missing: Whether to create the material if it doesn't exist (default: True).
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
unity = get_unity_connection()
|
unity = get_unity_connection()
|
||||||
|
|
||||||
|
# Check if the object exists
|
||||||
|
object_response = unity.send_command("FIND_OBJECTS_BY_NAME", {
|
||||||
|
"name": object_name
|
||||||
|
})
|
||||||
|
|
||||||
|
objects = object_response.get("objects", [])
|
||||||
|
if not objects:
|
||||||
|
return f"GameObject '{object_name}' not found in the scene."
|
||||||
|
|
||||||
|
# If a material name is specified, check if it exists
|
||||||
|
if material_name:
|
||||||
|
material_assets = unity.send_command("GET_ASSET_LIST", {
|
||||||
|
"type": "Material",
|
||||||
|
"search_pattern": material_name,
|
||||||
|
"folder": "Assets/Materials"
|
||||||
|
}).get("assets", [])
|
||||||
|
|
||||||
|
material_exists = any(asset.get("name") == material_name for asset in material_assets)
|
||||||
|
|
||||||
|
if not material_exists and not create_if_missing:
|
||||||
|
return f"Material '{material_name}' not found. Use create_if_missing=True to create it."
|
||||||
|
|
||||||
|
# Validate color values if provided
|
||||||
|
if color:
|
||||||
|
# Check if color has the right number of components (RGB or RGBA)
|
||||||
|
if not (len(color) == 3 or len(color) == 4):
|
||||||
|
return f"Error: Color must have 3 (RGB) or 4 (RGBA) components, but got {len(color)}."
|
||||||
|
|
||||||
|
# Check if all color values are in the 0-1 range
|
||||||
|
for i, value in enumerate(color):
|
||||||
|
if not isinstance(value, (int, float)):
|
||||||
|
return f"Error: Color component at index {i} is not a number."
|
||||||
|
|
||||||
|
if value < 0.0 or value > 1.0:
|
||||||
|
channel = "RGBA"[i] if i < 4 else f"component {i}"
|
||||||
|
return f"Error: Color {channel} value must be in the range 0.0-1.0, but got {value}."
|
||||||
|
|
||||||
|
# Set up parameters for the command
|
||||||
params = {"object_name": object_name}
|
params = {"object_name": object_name}
|
||||||
if material_name:
|
if material_name:
|
||||||
params["material_name"] = material_name
|
params["material_name"] = material_name
|
||||||
|
params["create_if_missing"] = create_if_missing
|
||||||
if color:
|
if color:
|
||||||
params["color"] = color
|
params["color"] = color
|
||||||
|
|
||||||
result = unity.send_command("SET_MATERIAL", params)
|
result = unity.send_command("SET_MATERIAL", params)
|
||||||
return f"Applied material to {object_name}: {result.get('material_name', 'unknown')}"
|
return f"Applied material to {object_name}: {result.get('material_name', 'unknown')}"
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,19 @@ def register_scene_tools(mcp: FastMCP):
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
unity = get_unity_connection()
|
unity = get_unity_connection()
|
||||||
|
|
||||||
|
# Check if the scene exists in the project
|
||||||
|
scenes = unity.send_command("GET_ASSET_LIST", {
|
||||||
|
"type": "Scene",
|
||||||
|
"search_pattern": scene_path.split('/')[-1],
|
||||||
|
"folder": '/'.join(scene_path.split('/')[:-1]) or "Assets"
|
||||||
|
}).get("assets", [])
|
||||||
|
|
||||||
|
# Check if any scene matches the exact path
|
||||||
|
scene_exists = any(scene.get("path") == scene_path for scene in scenes)
|
||||||
|
if not scene_exists:
|
||||||
|
return f"Scene at '{scene_path}' not found in the project."
|
||||||
|
|
||||||
result = unity.send_command("OPEN_SCENE", {"scene_path": scene_path})
|
result = unity.send_command("OPEN_SCENE", {"scene_path": scene_path})
|
||||||
return result.get("message", "Scene opened successfully")
|
return result.get("message", "Scene opened successfully")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|
@ -48,19 +61,36 @@ def register_scene_tools(mcp: FastMCP):
|
||||||
return f"Error saving scene: {str(e)}"
|
return f"Error saving scene: {str(e)}"
|
||||||
|
|
||||||
@mcp.tool()
|
@mcp.tool()
|
||||||
def new_scene(ctx: Context, scene_path: str) -> str:
|
def new_scene(ctx: Context, scene_path: str, overwrite: bool = False) -> str:
|
||||||
"""Create a new empty scene in the Unity editor.
|
"""Create a new empty scene in the Unity editor.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
scene_path: Full path where the new scene should be saved (e.g., "Assets/Scenes/NewScene.unity")
|
scene_path: Full path where the new scene should be saved (e.g., "Assets/Scenes/NewScene.unity")
|
||||||
|
overwrite: Whether to overwrite if scene already exists (default: False)
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
str: Success message or error details
|
str: Success message or error details
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
unity = get_unity_connection()
|
unity = get_unity_connection()
|
||||||
|
|
||||||
|
# Check if a scene with this path already exists
|
||||||
|
scenes = unity.send_command("GET_ASSET_LIST", {
|
||||||
|
"type": "Scene",
|
||||||
|
"search_pattern": scene_path.split('/')[-1],
|
||||||
|
"folder": '/'.join(scene_path.split('/')[:-1]) or "Assets"
|
||||||
|
}).get("assets", [])
|
||||||
|
|
||||||
|
# Check if any scene matches the exact path
|
||||||
|
scene_exists = any(scene.get("path") == scene_path for scene in scenes)
|
||||||
|
if scene_exists and not overwrite:
|
||||||
|
return f"Scene at '{scene_path}' already exists. Use overwrite=True to replace it."
|
||||||
|
|
||||||
# Create new scene
|
# Create new scene
|
||||||
result = unity.send_command("NEW_SCENE", {"scene_path": scene_path})
|
result = unity.send_command("NEW_SCENE", {
|
||||||
|
"scene_path": scene_path,
|
||||||
|
"overwrite": overwrite
|
||||||
|
})
|
||||||
|
|
||||||
# Save the scene to ensure it's properly created
|
# Save the scene to ensure it's properly created
|
||||||
unity.send_command("SAVE_SCENE")
|
unity.send_command("SAVE_SCENE")
|
||||||
|
|
@ -115,7 +145,8 @@ def register_scene_tools(mcp: FastMCP):
|
||||||
name: str = None,
|
name: str = None,
|
||||||
location: List[float] = None,
|
location: List[float] = None,
|
||||||
rotation: List[float] = None,
|
rotation: List[float] = None,
|
||||||
scale: List[float] = None
|
scale: List[float] = None,
|
||||||
|
replace_if_exists: bool = False
|
||||||
) -> str:
|
) -> str:
|
||||||
"""
|
"""
|
||||||
Create a game object in the Unity scene.
|
Create a game object in the Unity scene.
|
||||||
|
|
@ -126,12 +157,27 @@ def register_scene_tools(mcp: FastMCP):
|
||||||
location: [x, y, z] position (defaults to [0, 0, 0]).
|
location: [x, y, z] position (defaults to [0, 0, 0]).
|
||||||
rotation: [x, y, z] rotation in degrees (defaults to [0, 0, 0]).
|
rotation: [x, y, z] rotation in degrees (defaults to [0, 0, 0]).
|
||||||
scale: [x, y, z] scale factors (defaults to [1, 1, 1]).
|
scale: [x, y, z] scale factors (defaults to [1, 1, 1]).
|
||||||
|
replace_if_exists: Whether to replace if an object with the same name exists (default: False)
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Confirmation message with the created object's name.
|
Confirmation message with the created object's name.
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
unity = get_unity_connection()
|
unity = get_unity_connection()
|
||||||
|
|
||||||
|
# Check if an object with the specified name already exists (if name is provided)
|
||||||
|
if name:
|
||||||
|
found_objects = unity.send_command("FIND_OBJECTS_BY_NAME", {
|
||||||
|
"name": name
|
||||||
|
}).get("objects", [])
|
||||||
|
|
||||||
|
if found_objects and not replace_if_exists:
|
||||||
|
return f"Object with name '{name}' already exists. Use replace_if_exists=True to replace it."
|
||||||
|
elif found_objects and replace_if_exists:
|
||||||
|
# Delete the existing object
|
||||||
|
unity.send_command("DELETE_OBJECT", {"name": name})
|
||||||
|
|
||||||
|
# Create the new object
|
||||||
params = {
|
params = {
|
||||||
"type": type.upper(),
|
"type": type.upper(),
|
||||||
"location": location or [0, 0, 0],
|
"location": location or [0, 0, 0],
|
||||||
|
|
@ -140,6 +186,7 @@ def register_scene_tools(mcp: FastMCP):
|
||||||
}
|
}
|
||||||
if name:
|
if name:
|
||||||
params["name"] = name
|
params["name"] = name
|
||||||
|
|
||||||
result = unity.send_command("CREATE_OBJECT", params)
|
result = unity.send_command("CREATE_OBJECT", params)
|
||||||
return f"Created {type} game object: {result['name']}"
|
return f"Created {type} game object: {result['name']}"
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|
@ -180,6 +227,48 @@ def register_scene_tools(mcp: FastMCP):
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
unity = get_unity_connection()
|
unity = get_unity_connection()
|
||||||
|
|
||||||
|
# Check if the object exists
|
||||||
|
found_objects = unity.send_command("FIND_OBJECTS_BY_NAME", {
|
||||||
|
"name": name
|
||||||
|
}).get("objects", [])
|
||||||
|
|
||||||
|
if not found_objects:
|
||||||
|
return f"Object with name '{name}' not found in the scene."
|
||||||
|
|
||||||
|
# If set_parent is provided, check if parent object exists
|
||||||
|
if set_parent is not None:
|
||||||
|
parent_objects = unity.send_command("FIND_OBJECTS_BY_NAME", {
|
||||||
|
"name": set_parent
|
||||||
|
}).get("objects", [])
|
||||||
|
|
||||||
|
if not parent_objects:
|
||||||
|
return f"Parent object '{set_parent}' not found in the scene."
|
||||||
|
|
||||||
|
# If we're adding a component, we could also check if it's already attached
|
||||||
|
if add_component is not None:
|
||||||
|
object_props = unity.send_command("GET_OBJECT_PROPERTIES", {
|
||||||
|
"name": name
|
||||||
|
})
|
||||||
|
|
||||||
|
components = object_props.get("components", [])
|
||||||
|
component_exists = any(comp.get("type") == add_component for comp in components)
|
||||||
|
|
||||||
|
if component_exists:
|
||||||
|
return f"Component '{add_component}' is already attached to '{name}'."
|
||||||
|
|
||||||
|
# If we're removing a component, check if it exists
|
||||||
|
if remove_component is not None:
|
||||||
|
object_props = unity.send_command("GET_OBJECT_PROPERTIES", {
|
||||||
|
"name": name
|
||||||
|
})
|
||||||
|
|
||||||
|
components = object_props.get("components", [])
|
||||||
|
component_exists = any(comp.get("type") == remove_component for comp in components)
|
||||||
|
|
||||||
|
if not component_exists:
|
||||||
|
return f"Component '{remove_component}' is not attached to '{name}'."
|
||||||
|
|
||||||
params = {"name": name}
|
params = {"name": name}
|
||||||
|
|
||||||
# Add basic transform properties
|
# Add basic transform properties
|
||||||
|
|
@ -212,15 +301,31 @@ def register_scene_tools(mcp: FastMCP):
|
||||||
return f"Error modifying game object: {str(e)}"
|
return f"Error modifying game object: {str(e)}"
|
||||||
|
|
||||||
@mcp.tool()
|
@mcp.tool()
|
||||||
def delete_object(ctx: Context, name: str) -> str:
|
def delete_object(ctx: Context, name: str, ignore_missing: bool = False) -> str:
|
||||||
"""
|
"""
|
||||||
Remove a game object from the scene.
|
Remove a game object from the scene.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
name: Name of the game object to delete.
|
name: Name of the game object to delete.
|
||||||
|
ignore_missing: Whether to silently ignore if the object doesn't exist (default: False)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
str: Success message or error details
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
unity = get_unity_connection()
|
unity = get_unity_connection()
|
||||||
|
|
||||||
|
# Check if the object exists
|
||||||
|
found_objects = unity.send_command("FIND_OBJECTS_BY_NAME", {
|
||||||
|
"name": name
|
||||||
|
}).get("objects", [])
|
||||||
|
|
||||||
|
if not found_objects:
|
||||||
|
if ignore_missing:
|
||||||
|
return f"No object named '{name}' found to delete. Ignoring."
|
||||||
|
else:
|
||||||
|
return f"Error: Object '{name}' not found in the scene."
|
||||||
|
|
||||||
result = unity.send_command("DELETE_OBJECT", {"name": name})
|
result = unity.send_command("DELETE_OBJECT", {"name": name})
|
||||||
return f"Deleted game object: {name}"
|
return f"Deleted game object: {name}"
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,8 @@ def register_script_tools(mcp: FastMCP):
|
||||||
script_name: str,
|
script_name: str,
|
||||||
script_type: str = "MonoBehaviour",
|
script_type: str = "MonoBehaviour",
|
||||||
namespace: str = None,
|
namespace: str = None,
|
||||||
template: str = None
|
template: str = None,
|
||||||
|
overwrite: bool = False
|
||||||
) -> str:
|
) -> str:
|
||||||
"""Create a new Unity script file.
|
"""Create a new Unity script file.
|
||||||
|
|
||||||
|
|
@ -41,17 +42,32 @@ def register_script_tools(mcp: FastMCP):
|
||||||
script_type: Type of script (e.g., MonoBehaviour, ScriptableObject)
|
script_type: Type of script (e.g., MonoBehaviour, ScriptableObject)
|
||||||
namespace: Optional namespace for the script
|
namespace: Optional namespace for the script
|
||||||
template: Optional custom template to use
|
template: Optional custom template to use
|
||||||
|
overwrite: Whether to overwrite if script already exists (default: False)
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
str: Success message or error details
|
str: Success message or error details
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
|
# First check if a script with this name already exists
|
||||||
|
unity = get_unity_connection()
|
||||||
|
script_path = f"Assets/Scripts/{script_name}.cs"
|
||||||
|
|
||||||
|
# Try to view the script to check if it exists
|
||||||
|
existing_script_response = unity.send_command("VIEW_SCRIPT", {
|
||||||
|
"script_path": script_path
|
||||||
|
})
|
||||||
|
|
||||||
|
# If the script exists and overwrite is False, return a message
|
||||||
|
if "content" in existing_script_response and not overwrite:
|
||||||
|
return f"Script '{script_name}.cs' already exists. Use overwrite=True to replace it."
|
||||||
|
|
||||||
# Send command to Unity to create the script
|
# Send command to Unity to create the script
|
||||||
response = get_unity_connection().send_command("CREATE_SCRIPT", {
|
response = unity.send_command("CREATE_SCRIPT", {
|
||||||
"script_name": script_name,
|
"script_name": script_name,
|
||||||
"script_type": script_type,
|
"script_type": script_type,
|
||||||
"namespace": namespace,
|
"namespace": namespace,
|
||||||
"template": template
|
"template": template,
|
||||||
|
"overwrite": overwrite
|
||||||
})
|
})
|
||||||
return response.get("message", "Script created successfully")
|
return response.get("message", "Script created successfully")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|
@ -61,7 +77,9 @@ def register_script_tools(mcp: FastMCP):
|
||||||
def update_script(
|
def update_script(
|
||||||
ctx: Context,
|
ctx: Context,
|
||||||
script_path: str,
|
script_path: str,
|
||||||
content: str
|
content: str,
|
||||||
|
create_if_missing: bool = False,
|
||||||
|
create_folder_if_missing: bool = False
|
||||||
) -> str:
|
) -> str:
|
||||||
"""Update the contents of an existing Unity script.
|
"""Update the contents of an existing Unity script.
|
||||||
|
|
||||||
|
|
@ -69,13 +87,66 @@ def register_script_tools(mcp: FastMCP):
|
||||||
ctx: The MCP context
|
ctx: The MCP context
|
||||||
script_path: Path to the script file relative to the Assets folder
|
script_path: Path to the script file relative to the Assets folder
|
||||||
content: New content for the script
|
content: New content for the script
|
||||||
|
create_if_missing: Whether to create the script if it doesn't exist (default: False)
|
||||||
|
create_folder_if_missing: Whether to create the parent directory if it doesn't exist (default: False)
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
str: Success message or error details
|
str: Success message or error details
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
|
unity = get_unity_connection()
|
||||||
|
|
||||||
|
# Check if the script exists first
|
||||||
|
existing_script_response = unity.send_command("VIEW_SCRIPT", {
|
||||||
|
"script_path": script_path
|
||||||
|
})
|
||||||
|
|
||||||
|
# If the script doesn't exist
|
||||||
|
if "content" not in existing_script_response:
|
||||||
|
if not create_if_missing:
|
||||||
|
return f"Script at '{script_path}' not found. Use create_if_missing=True to create it."
|
||||||
|
|
||||||
|
# If we should create the missing script
|
||||||
|
script_name = script_path.split("/")[-1].replace(".cs", "")
|
||||||
|
script_folder = "/".join(script_path.split("/")[:-1])
|
||||||
|
|
||||||
|
# Check if the parent directory exists
|
||||||
|
if script_folder:
|
||||||
|
folder_exists = False
|
||||||
|
try:
|
||||||
|
# Try to list scripts in the folder to see if it exists
|
||||||
|
folder_response = unity.send_command("LIST_SCRIPTS", {
|
||||||
|
"folder_path": script_folder
|
||||||
|
})
|
||||||
|
# If we didn't get an error, the folder exists
|
||||||
|
folder_exists = "error" not in folder_response
|
||||||
|
except:
|
||||||
|
folder_exists = False
|
||||||
|
|
||||||
|
if not folder_exists:
|
||||||
|
if not create_folder_if_missing:
|
||||||
|
return f"Parent directory '{script_folder}' does not exist. Use create_folder_if_missing=True to create it."
|
||||||
|
|
||||||
|
# Create the directory structure
|
||||||
|
try:
|
||||||
|
response = unity.send_command("CREATE_FOLDER", {
|
||||||
|
"folder_path": script_folder
|
||||||
|
})
|
||||||
|
if "error" in response:
|
||||||
|
return f"Error creating directory '{script_folder}': {response.get('error')}"
|
||||||
|
except Exception as folder_error:
|
||||||
|
return f"Error creating directory '{script_folder}': {str(folder_error)}"
|
||||||
|
|
||||||
|
# Create the script with the provided content
|
||||||
|
response = unity.send_command("CREATE_SCRIPT", {
|
||||||
|
"script_name": script_name,
|
||||||
|
"script_folder": script_folder,
|
||||||
|
"content": content
|
||||||
|
})
|
||||||
|
return response.get("message", "Script created successfully")
|
||||||
|
|
||||||
# Send command to Unity to update the script
|
# Send command to Unity to update the script
|
||||||
response = get_unity_connection().send_command("UPDATE_SCRIPT", {
|
response = unity.send_command("UPDATE_SCRIPT", {
|
||||||
"script_path": script_path,
|
"script_path": script_path,
|
||||||
"content": content
|
"content": content
|
||||||
})
|
})
|
||||||
|
|
@ -110,7 +181,8 @@ def register_script_tools(mcp: FastMCP):
|
||||||
def attach_script(
|
def attach_script(
|
||||||
ctx: Context,
|
ctx: Context,
|
||||||
object_name: str,
|
object_name: str,
|
||||||
script_name: str
|
script_name: str,
|
||||||
|
script_path: str = None
|
||||||
) -> str:
|
) -> str:
|
||||||
"""Attach a script component to a GameObject.
|
"""Attach a script component to a GameObject.
|
||||||
|
|
||||||
|
|
@ -118,15 +190,85 @@ def register_script_tools(mcp: FastMCP):
|
||||||
ctx: The MCP context
|
ctx: The MCP context
|
||||||
object_name: Name of the target GameObject in the scene
|
object_name: Name of the target GameObject in the scene
|
||||||
script_name: Name of the script to attach (with or without .cs extension)
|
script_name: Name of the script to attach (with or without .cs extension)
|
||||||
|
script_path: Optional full path to the script (if not in the default Scripts folder)
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
str: Success message or error details
|
str: Success message or error details
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
|
unity = get_unity_connection()
|
||||||
|
|
||||||
|
# Check if the object exists
|
||||||
|
object_response = unity.send_command("FIND_OBJECTS_BY_NAME", {
|
||||||
|
"name": object_name
|
||||||
|
})
|
||||||
|
|
||||||
|
objects = object_response.get("objects", [])
|
||||||
|
if not objects:
|
||||||
|
return f"GameObject '{object_name}' not found in the scene."
|
||||||
|
|
||||||
|
# Ensure script_name has .cs extension
|
||||||
|
if not script_name.lower().endswith(".cs"):
|
||||||
|
script_name = f"{script_name}.cs"
|
||||||
|
|
||||||
|
# Determine the full script path
|
||||||
|
if script_path is None:
|
||||||
|
# Use default Scripts folder if no path provided
|
||||||
|
script_path = f"Assets/Scripts/{script_name}"
|
||||||
|
elif not script_path.endswith(script_name):
|
||||||
|
# If path is just a directory, append the script name
|
||||||
|
if script_path.endswith("/"):
|
||||||
|
script_path = f"{script_path}{script_name}"
|
||||||
|
else:
|
||||||
|
script_path = f"{script_path}/{script_name}"
|
||||||
|
|
||||||
|
# Check if the script exists by trying to view it
|
||||||
|
existing_script_response = unity.send_command("VIEW_SCRIPT", {
|
||||||
|
"script_path": script_path
|
||||||
|
})
|
||||||
|
|
||||||
|
if "content" not in existing_script_response:
|
||||||
|
# If not found at the specific path, try to search for it in the project
|
||||||
|
script_found = False
|
||||||
|
try:
|
||||||
|
# Search in the entire Assets folder
|
||||||
|
script_assets = unity.send_command("LIST_SCRIPTS", {
|
||||||
|
"folder_path": "Assets"
|
||||||
|
}).get("scripts", [])
|
||||||
|
|
||||||
|
# Look for matching script name in any folder
|
||||||
|
matching_scripts = [path for path in script_assets if path.endswith(f"/{script_name}") or path == script_name]
|
||||||
|
|
||||||
|
if matching_scripts:
|
||||||
|
script_path = matching_scripts[0]
|
||||||
|
script_found = True
|
||||||
|
if len(matching_scripts) > 1:
|
||||||
|
return f"Multiple scripts named '{script_name}' found in the project. Please specify script_path parameter."
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
if not script_found:
|
||||||
|
return f"Script '{script_name}' not found in the project."
|
||||||
|
|
||||||
|
# Check if the script is already attached
|
||||||
|
object_props = unity.send_command("GET_OBJECT_PROPERTIES", {
|
||||||
|
"name": object_name
|
||||||
|
})
|
||||||
|
|
||||||
|
# Extract script name without .cs and without path
|
||||||
|
script_class_name = script_name.replace(".cs", "")
|
||||||
|
|
||||||
|
# Check if component is already attached
|
||||||
|
components = object_props.get("components", [])
|
||||||
|
for component in components:
|
||||||
|
if component.get("type") == script_class_name:
|
||||||
|
return f"Script '{script_class_name}' is already attached to '{object_name}'."
|
||||||
|
|
||||||
# Send command to Unity to attach the script
|
# Send command to Unity to attach the script
|
||||||
response = get_unity_connection().send_command("ATTACH_SCRIPT", {
|
response = unity.send_command("ATTACH_SCRIPT", {
|
||||||
"object_name": object_name,
|
"object_name": object_name,
|
||||||
"script_name": script_name
|
"script_name": script_name,
|
||||||
|
"script_path": script_path
|
||||||
})
|
})
|
||||||
return response.get("message", "Script attached successfully")
|
return response.get("message", "Script attached successfully")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue