Merge pull request #49 from flashwade03/feature/base64_encoding
add text encoding process(base64) to 'View Script' Command for fixing timeout issue.main
commit
13508f2e56
|
|
@ -1,10 +1,10 @@
|
||||||
using UnityEngine;
|
|
||||||
using UnityEditor;
|
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Text;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
using Newtonsoft.Json.Linq;
|
using Newtonsoft.Json.Linq;
|
||||||
|
using UnityEditor;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
namespace UnityMCP.Editor.Commands
|
namespace UnityMCP.Editor.Commands
|
||||||
{
|
{
|
||||||
|
|
@ -18,7 +18,9 @@ namespace UnityMCP.Editor.Commands
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static object ViewScript(JObject @params)
|
public static object ViewScript(JObject @params)
|
||||||
{
|
{
|
||||||
string scriptPath = (string)@params["script_path"] ?? throw new Exception("Parameter 'script_path' is required.");
|
string scriptPath =
|
||||||
|
(string)@params["script_path"]
|
||||||
|
?? throw new Exception("Parameter 'script_path' is required.");
|
||||||
bool requireExists = (bool?)@params["require_exists"] ?? true;
|
bool requireExists = (bool?)@params["require_exists"] ?? true;
|
||||||
|
|
||||||
// Handle path correctly to avoid double "Assets" folder issue
|
// Handle path correctly to avoid double "Assets" folder issue
|
||||||
|
|
@ -47,7 +49,16 @@ namespace UnityMCP.Editor.Commands
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return new { exists = true, content = File.ReadAllText(fullPath) };
|
string content = File.ReadAllText(fullPath);
|
||||||
|
byte[] contentBytes = System.Text.Encoding.UTF8.GetBytes(content);
|
||||||
|
string base64Content = Convert.ToBase64String(contentBytes);
|
||||||
|
|
||||||
|
return new
|
||||||
|
{
|
||||||
|
exists = true,
|
||||||
|
content = base64Content,
|
||||||
|
encoding = "base64"
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -70,7 +81,9 @@ namespace UnityMCP.Editor.Commands
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static object CreateScript(JObject @params)
|
public static object CreateScript(JObject @params)
|
||||||
{
|
{
|
||||||
string scriptName = (string)@params["script_name"] ?? throw new Exception("Parameter 'script_name' is required.");
|
string scriptName =
|
||||||
|
(string)@params["script_name"]
|
||||||
|
?? throw new Exception("Parameter 'script_name' is required.");
|
||||||
string scriptType = (string)@params["script_type"] ?? "MonoBehaviour";
|
string scriptType = (string)@params["script_type"] ?? "MonoBehaviour";
|
||||||
string namespaceName = (string)@params["namespace"];
|
string namespaceName = (string)@params["namespace"];
|
||||||
string template = (string)@params["template"];
|
string template = (string)@params["template"];
|
||||||
|
|
@ -128,7 +141,9 @@ namespace UnityMCP.Editor.Commands
|
||||||
string fullFilePath = Path.Combine(folderPath, scriptName);
|
string fullFilePath = Path.Combine(folderPath, scriptName);
|
||||||
if (File.Exists(fullFilePath) && !overwrite)
|
if (File.Exists(fullFilePath) && !overwrite)
|
||||||
{
|
{
|
||||||
throw new Exception($"Script file '{scriptName}' already exists in '{scriptPath}' and overwrite is not enabled.");
|
throw new Exception(
|
||||||
|
$"Script file '{scriptName}' already exists in '{scriptPath}' and overwrite is not enabled."
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
|
|
@ -157,7 +172,9 @@ namespace UnityMCP.Editor.Commands
|
||||||
|
|
||||||
// Add class definition with indent based on namespace
|
// Add class definition with indent based on namespace
|
||||||
string indent = string.IsNullOrEmpty(namespaceName) ? "" : " ";
|
string indent = string.IsNullOrEmpty(namespaceName) ? "" : " ";
|
||||||
contentBuilder.AppendLine($"{indent}public class {Path.GetFileNameWithoutExtension(scriptName)} : {scriptType}");
|
contentBuilder.AppendLine(
|
||||||
|
$"{indent}public class {Path.GetFileNameWithoutExtension(scriptName)} : {scriptType}"
|
||||||
|
);
|
||||||
contentBuilder.AppendLine($"{indent}{{");
|
contentBuilder.AppendLine($"{indent}{{");
|
||||||
|
|
||||||
// Add default Unity methods based on script type
|
// Add default Unity methods based on script type
|
||||||
|
|
@ -165,7 +182,9 @@ namespace UnityMCP.Editor.Commands
|
||||||
{
|
{
|
||||||
contentBuilder.AppendLine($"{indent} private void Start()");
|
contentBuilder.AppendLine($"{indent} private void Start()");
|
||||||
contentBuilder.AppendLine($"{indent} {{");
|
contentBuilder.AppendLine($"{indent} {{");
|
||||||
contentBuilder.AppendLine($"{indent} // Initialize your component here");
|
contentBuilder.AppendLine(
|
||||||
|
$"{indent} // Initialize your component here"
|
||||||
|
);
|
||||||
contentBuilder.AppendLine($"{indent} }}");
|
contentBuilder.AppendLine($"{indent} }}");
|
||||||
contentBuilder.AppendLine();
|
contentBuilder.AppendLine();
|
||||||
contentBuilder.AppendLine($"{indent} private void Update()");
|
contentBuilder.AppendLine($"{indent} private void Update()");
|
||||||
|
|
@ -177,7 +196,9 @@ namespace UnityMCP.Editor.Commands
|
||||||
{
|
{
|
||||||
contentBuilder.AppendLine($"{indent} private void OnEnable()");
|
contentBuilder.AppendLine($"{indent} private void OnEnable()");
|
||||||
contentBuilder.AppendLine($"{indent} {{");
|
contentBuilder.AppendLine($"{indent} {{");
|
||||||
contentBuilder.AppendLine($"{indent} // Initialize your ScriptableObject here");
|
contentBuilder.AppendLine(
|
||||||
|
$"{indent} // Initialize your ScriptableObject here"
|
||||||
|
);
|
||||||
contentBuilder.AppendLine($"{indent} }}");
|
contentBuilder.AppendLine($"{indent} }}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -222,8 +243,12 @@ namespace UnityMCP.Editor.Commands
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static object UpdateScript(JObject @params)
|
public static object UpdateScript(JObject @params)
|
||||||
{
|
{
|
||||||
string scriptPath = (string)@params["script_path"] ?? throw new Exception("Parameter 'script_path' is required.");
|
string scriptPath =
|
||||||
string content = (string)@params["content"] ?? throw new Exception("Parameter 'content' is required.");
|
(string)@params["script_path"]
|
||||||
|
?? throw new Exception("Parameter 'script_path' is required.");
|
||||||
|
string content =
|
||||||
|
(string)@params["content"]
|
||||||
|
?? throw new Exception("Parameter 'content' is required.");
|
||||||
bool createIfMissing = (bool?)@params["create_if_missing"] ?? false;
|
bool createIfMissing = (bool?)@params["create_if_missing"] ?? false;
|
||||||
bool createFolderIfMissing = (bool?)@params["create_folder_if_missing"] ?? false;
|
bool createFolderIfMissing = (bool?)@params["create_folder_if_missing"] ?? false;
|
||||||
|
|
||||||
|
|
@ -257,7 +282,9 @@ namespace UnityMCP.Editor.Commands
|
||||||
}
|
}
|
||||||
else if (!Directory.Exists(directory))
|
else if (!Directory.Exists(directory))
|
||||||
{
|
{
|
||||||
throw new Exception($"Directory does not exist: {Path.GetDirectoryName(scriptPath)}");
|
throw new Exception(
|
||||||
|
$"Directory does not exist: {Path.GetDirectoryName(scriptPath)}"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create the file with content
|
// Create the file with content
|
||||||
|
|
@ -308,7 +335,8 @@ namespace UnityMCP.Editor.Commands
|
||||||
if (!Directory.Exists(fullPath))
|
if (!Directory.Exists(fullPath))
|
||||||
throw new Exception($"Folder not found: {folderPath}");
|
throw new Exception($"Folder not found: {folderPath}");
|
||||||
|
|
||||||
string[] scripts = Directory.GetFiles(fullPath, "*.cs", SearchOption.AllDirectories)
|
string[] scripts = Directory
|
||||||
|
.GetFiles(fullPath, "*.cs", SearchOption.AllDirectories)
|
||||||
.Select(path => path.Replace(Application.dataPath, "Assets"))
|
.Select(path => path.Replace(Application.dataPath, "Assets"))
|
||||||
.ToArray();
|
.ToArray();
|
||||||
|
|
||||||
|
|
@ -320,8 +348,12 @@ namespace UnityMCP.Editor.Commands
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static object AttachScript(JObject @params)
|
public static object AttachScript(JObject @params)
|
||||||
{
|
{
|
||||||
string objectName = (string)@params["object_name"] ?? throw new Exception("Parameter 'object_name' is required.");
|
string objectName =
|
||||||
string scriptName = (string)@params["script_name"] ?? throw new Exception("Parameter 'script_name' is required.");
|
(string)@params["object_name"]
|
||||||
|
?? throw new Exception("Parameter 'object_name' is required.");
|
||||||
|
string scriptName =
|
||||||
|
(string)@params["script_name"]
|
||||||
|
?? throw new Exception("Parameter 'script_name' is required.");
|
||||||
string scriptPath = (string)@params["script_path"]; // Optional
|
string scriptPath = (string)@params["script_path"]; // Optional
|
||||||
|
|
||||||
// Find the target object
|
// Find the target object
|
||||||
|
|
@ -343,7 +375,11 @@ namespace UnityMCP.Editor.Commands
|
||||||
if (!string.IsNullOrEmpty(scriptPath))
|
if (!string.IsNullOrEmpty(scriptPath))
|
||||||
{
|
{
|
||||||
// If a specific path is provided, try that first
|
// If a specific path is provided, try that first
|
||||||
if (File.Exists(Path.Combine(Application.dataPath, scriptPath.Replace("Assets/", ""))))
|
if (
|
||||||
|
File.Exists(
|
||||||
|
Path.Combine(Application.dataPath, scriptPath.Replace("Assets/", ""))
|
||||||
|
)
|
||||||
|
)
|
||||||
{
|
{
|
||||||
// Use the direct path if it exists
|
// Use the direct path if it exists
|
||||||
MonoScript scriptAsset = AssetDatabase.LoadAssetAtPath<MonoScript>(scriptPath);
|
MonoScript scriptAsset = AssetDatabase.LoadAssetAtPath<MonoScript>(scriptPath);
|
||||||
|
|
@ -398,8 +434,18 @@ namespace UnityMCP.Editor.Commands
|
||||||
|
|
||||||
// Double check the file name to avoid false matches
|
// Double check the file name to avoid false matches
|
||||||
string foundFileName = Path.GetFileName(path);
|
string foundFileName = Path.GetFileName(path);
|
||||||
if (!string.Equals(foundFileName, scriptFileName, StringComparison.OrdinalIgnoreCase) &&
|
if (
|
||||||
!string.Equals(Path.GetFileNameWithoutExtension(foundFileName), scriptNameWithoutExtension, StringComparison.OrdinalIgnoreCase))
|
!string.Equals(
|
||||||
|
foundFileName,
|
||||||
|
scriptFileName,
|
||||||
|
StringComparison.OrdinalIgnoreCase
|
||||||
|
)
|
||||||
|
&& !string.Equals(
|
||||||
|
Path.GetFileNameWithoutExtension(foundFileName),
|
||||||
|
scriptNameWithoutExtension,
|
||||||
|
StringComparison.OrdinalIgnoreCase
|
||||||
|
)
|
||||||
|
)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
MonoScript scriptAsset = AssetDatabase.LoadAssetAtPath<MonoScript>(path);
|
MonoScript scriptAsset = AssetDatabase.LoadAssetAtPath<MonoScript>(path);
|
||||||
|
|
@ -442,7 +488,9 @@ namespace UnityMCP.Editor.Commands
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we've tried all possibilities and nothing worked
|
// If we've tried all possibilities and nothing worked
|
||||||
throw new Exception($"Could not attach script '{scriptFileName}' to object '{objectName}'. No valid script found or component creation failed.");
|
throw new Exception(
|
||||||
|
$"Could not attach script '{scriptFileName}' to object '{objectName}'. No valid script found or component creation failed."
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
from mcp.server.fastmcp import FastMCP, Context
|
from mcp.server.fastmcp import FastMCP, Context
|
||||||
from typing import List
|
from typing import List
|
||||||
from unity_connection import get_unity_connection
|
from unity_connection import get_unity_connection
|
||||||
|
import base64
|
||||||
|
|
||||||
|
|
||||||
def register_script_tools(mcp: FastMCP):
|
def register_script_tools(mcp: FastMCP):
|
||||||
"""Register all script-related tools with the MCP server."""
|
"""Register all script-related tools with the MCP server."""
|
||||||
|
|
@ -26,12 +28,17 @@ def register_script_tools(mcp: FastMCP):
|
||||||
print(f"ViewScript - Using normalized script path: {script_path}")
|
print(f"ViewScript - Using normalized script path: {script_path}")
|
||||||
|
|
||||||
# Send command to Unity to read the script file
|
# Send command to Unity to read the script file
|
||||||
response = get_unity_connection().send_command("VIEW_SCRIPT", {
|
response = get_unity_connection().send_command(
|
||||||
"script_path": script_path,
|
"VIEW_SCRIPT",
|
||||||
"require_exists": require_exists
|
{"script_path": script_path, "require_exists": require_exists},
|
||||||
})
|
)
|
||||||
|
|
||||||
if response.get("exists", True):
|
if response.get("exists", True):
|
||||||
|
if response.get("encoding", "base64") == "base64":
|
||||||
|
decoded_content = base64.b64decode(response.get("content")).decode(
|
||||||
|
"utf-8"
|
||||||
|
)
|
||||||
|
return decoded_content
|
||||||
return response.get("content", "Script contents not available")
|
return response.get("content", "Script contents not available")
|
||||||
else:
|
else:
|
||||||
return response.get("message", "Script not found")
|
return response.get("message", "Script not found")
|
||||||
|
|
@ -47,7 +54,7 @@ def register_script_tools(mcp: FastMCP):
|
||||||
template: str = None,
|
template: str = None,
|
||||||
script_folder: str = None,
|
script_folder: str = None,
|
||||||
overwrite: bool = False,
|
overwrite: bool = False,
|
||||||
content: str = None
|
content: str = None,
|
||||||
) -> str:
|
) -> str:
|
||||||
"""Create a new Unity script file.
|
"""Create a new Unity script file.
|
||||||
|
|
||||||
|
|
@ -98,7 +105,7 @@ def register_script_tools(mcp: FastMCP):
|
||||||
"script_type": script_type,
|
"script_type": script_type,
|
||||||
"namespace": namespace,
|
"namespace": namespace,
|
||||||
"template": template,
|
"template": template,
|
||||||
"overwrite": overwrite
|
"overwrite": overwrite,
|
||||||
}
|
}
|
||||||
|
|
||||||
# Add script_folder if provided
|
# Add script_folder if provided
|
||||||
|
|
@ -120,7 +127,7 @@ def register_script_tools(mcp: FastMCP):
|
||||||
script_path: str,
|
script_path: str,
|
||||||
content: str,
|
content: str,
|
||||||
create_if_missing: bool = False,
|
create_if_missing: bool = False,
|
||||||
create_folder_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.
|
||||||
|
|
||||||
|
|
@ -157,7 +164,7 @@ def register_script_tools(mcp: FastMCP):
|
||||||
params = {
|
params = {
|
||||||
"script_path": script_path,
|
"script_path": script_path,
|
||||||
"content": content,
|
"content": content,
|
||||||
"create_if_missing": True
|
"create_if_missing": True,
|
||||||
}
|
}
|
||||||
|
|
||||||
# Add folder creation flag if requested
|
# Add folder creation flag if requested
|
||||||
|
|
@ -169,10 +176,9 @@ def register_script_tools(mcp: FastMCP):
|
||||||
return response.get("message", "Script updated successfully")
|
return response.get("message", "Script updated successfully")
|
||||||
else:
|
else:
|
||||||
# Standard update without creation flags
|
# Standard update without creation flags
|
||||||
response = unity.send_command("UPDATE_SCRIPT", {
|
response = unity.send_command(
|
||||||
"script_path": script_path,
|
"UPDATE_SCRIPT", {"script_path": script_path, "content": content}
|
||||||
"content": content
|
)
|
||||||
})
|
|
||||||
return response.get("message", "Script updated successfully")
|
return response.get("message", "Script updated successfully")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
return f"Error updating script: {str(e)}"
|
return f"Error updating script: {str(e)}"
|
||||||
|
|
@ -190,9 +196,9 @@ def register_script_tools(mcp: FastMCP):
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
# Send command to Unity to list scripts
|
# Send command to Unity to list scripts
|
||||||
response = get_unity_connection().send_command("LIST_SCRIPTS", {
|
response = get_unity_connection().send_command(
|
||||||
"folder_path": folder_path
|
"LIST_SCRIPTS", {"folder_path": folder_path}
|
||||||
})
|
)
|
||||||
scripts = response.get("scripts", [])
|
scripts = response.get("scripts", [])
|
||||||
if not scripts:
|
if not scripts:
|
||||||
return "No scripts found in the specified folder"
|
return "No scripts found in the specified folder"
|
||||||
|
|
@ -202,10 +208,7 @@ def register_script_tools(mcp: FastMCP):
|
||||||
|
|
||||||
@mcp.tool()
|
@mcp.tool()
|
||||||
def attach_script(
|
def attach_script(
|
||||||
ctx: Context,
|
ctx: Context, object_name: str, script_name: str, script_path: str = None
|
||||||
object_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.
|
||||||
|
|
||||||
|
|
@ -222,9 +225,9 @@ def register_script_tools(mcp: FastMCP):
|
||||||
unity = get_unity_connection()
|
unity = get_unity_connection()
|
||||||
|
|
||||||
# Check if the object exists
|
# Check if the object exists
|
||||||
object_response = unity.send_command("FIND_OBJECTS_BY_NAME", {
|
object_response = unity.send_command(
|
||||||
"name": object_name
|
"FIND_OBJECTS_BY_NAME", {"name": object_name}
|
||||||
})
|
)
|
||||||
|
|
||||||
objects = object_response.get("objects", [])
|
objects = object_response.get("objects", [])
|
||||||
if not objects:
|
if not objects:
|
||||||
|
|
@ -235,7 +238,7 @@ def register_script_tools(mcp: FastMCP):
|
||||||
script_name = f"{script_name}.cs"
|
script_name = f"{script_name}.cs"
|
||||||
|
|
||||||
# Remove any path information from script_name if it contains slashes
|
# Remove any path information from script_name if it contains slashes
|
||||||
script_basename = script_name.split('/')[-1]
|
script_basename = script_name.split("/")[-1]
|
||||||
|
|
||||||
# Determine the full script path if provided
|
# Determine the full script path if provided
|
||||||
if script_path is not None:
|
if script_path is not None:
|
||||||
|
|
@ -251,9 +254,9 @@ def register_script_tools(mcp: FastMCP):
|
||||||
script_path = f"{script_path}/{script_basename}"
|
script_path = f"{script_path}/{script_basename}"
|
||||||
|
|
||||||
# Check if the script is already attached
|
# Check if the script is already attached
|
||||||
object_props = unity.send_command("GET_OBJECT_PROPERTIES", {
|
object_props = unity.send_command(
|
||||||
"name": object_name
|
"GET_OBJECT_PROPERTIES", {"name": object_name}
|
||||||
})
|
)
|
||||||
|
|
||||||
# Extract script name without .cs and without path for component type checking
|
# Extract script name without .cs and without path for component type checking
|
||||||
script_class_name = script_basename.replace(".cs", "")
|
script_class_name = script_basename.replace(".cs", "")
|
||||||
|
|
@ -265,10 +268,7 @@ def register_script_tools(mcp: FastMCP):
|
||||||
return f"Script '{script_class_name}' is already attached to '{object_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
|
||||||
params = {
|
params = {"object_name": object_name, "script_name": script_basename}
|
||||||
"object_name": object_name,
|
|
||||||
"script_name": script_basename
|
|
||||||
}
|
|
||||||
|
|
||||||
# Add script_path if provided
|
# Add script_path if provided
|
||||||
if script_path:
|
if script_path:
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue