fixed scripts not creating bug

main
Justin Barnett 2025-03-18 10:01:51 -04:00
parent 3feecb09af
commit 015774b469
3 changed files with 151 additions and 79 deletions

View File

@ -49,19 +49,52 @@ namespace MCPServer.Editor.Commands
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"];
string scriptFolder = (string)@params["script_folder"];
string content = (string)@params["content"];
// Ensure script name ends with .cs // Ensure script name ends with .cs
if (!scriptName.EndsWith(".cs")) if (!scriptName.EndsWith(".cs"))
scriptName += ".cs"; scriptName += ".cs";
string scriptPath;
// If content is provided, use it directly
if (!string.IsNullOrEmpty(content))
{
// Use specified folder or default to Scripts
scriptPath = string.IsNullOrEmpty(scriptFolder) ? "Scripts" : scriptFolder;
// Ensure folder exists
string folderPath = Path.Combine(Application.dataPath, scriptPath);
if (!Directory.Exists(folderPath))
{
Directory.CreateDirectory(folderPath);
AssetDatabase.Refresh();
}
// Create the script file with provided content
string fullPath = Path.Combine(Application.dataPath, scriptPath, scriptName);
File.WriteAllText(fullPath, content);
// Refresh the AssetDatabase
AssetDatabase.Refresh();
return new { message = $"Created script: {Path.Combine(scriptPath, scriptName)}" };
}
// Otherwise generate content based on template and parameters
// Ensure Scripts folder exists // Ensure Scripts folder exists
EnsureScriptsFolderExists(); EnsureScriptsFolderExists();
// Create namespace-based folder structure if namespace is specified // Create namespace-based folder structure if namespace is specified
string scriptPath = "Scripts"; scriptPath = string.IsNullOrEmpty(scriptFolder) ? "Scripts" : scriptFolder;
if (!string.IsNullOrEmpty(namespaceName)) if (!string.IsNullOrEmpty(namespaceName))
{ {
scriptPath = Path.Combine(scriptPath, namespaceName.Replace('.', '/')); if (scriptPath == "Scripts") // Only modify path if we're using the default
{
scriptPath = Path.Combine(scriptPath, namespaceName.Replace('.', '/'));
}
string namespaceFolderPath = Path.Combine(Application.dataPath, scriptPath); string namespaceFolderPath = Path.Combine(Application.dataPath, scriptPath);
if (!Directory.Exists(namespaceFolderPath)) if (!Directory.Exists(namespaceFolderPath))
{ {
@ -71,52 +104,56 @@ namespace MCPServer.Editor.Commands
} }
// Create the script content // Create the script content
StringBuilder content = new StringBuilder(); StringBuilder contentBuilder = new StringBuilder();
// Add using directives
contentBuilder.AppendLine("using UnityEngine;");
contentBuilder.AppendLine();
// Add namespace if specified // Add namespace if specified
if (!string.IsNullOrEmpty(namespaceName)) if (!string.IsNullOrEmpty(namespaceName))
{ {
content.AppendLine($"namespace {namespaceName}"); contentBuilder.AppendLine($"namespace {namespaceName}");
content.AppendLine("{"); contentBuilder.AppendLine("{");
} }
// Add class definition // Add class definition
content.AppendLine($" public class {Path.GetFileNameWithoutExtension(scriptName)} : {scriptType}"); contentBuilder.AppendLine($" public class {Path.GetFileNameWithoutExtension(scriptName)} : {scriptType}");
content.AppendLine(" {"); contentBuilder.AppendLine(" {");
// Add default Unity methods based on script type // Add default Unity methods based on script type
if (scriptType == "MonoBehaviour") if (scriptType == "MonoBehaviour")
{ {
content.AppendLine(" private void Start()"); contentBuilder.AppendLine(" private void Start()");
content.AppendLine(" {"); contentBuilder.AppendLine(" {");
content.AppendLine(" // Initialize your component here"); contentBuilder.AppendLine(" // Initialize your component here");
content.AppendLine(" }"); contentBuilder.AppendLine(" }");
content.AppendLine(); contentBuilder.AppendLine();
content.AppendLine(" private void Update()"); contentBuilder.AppendLine(" private void Update()");
content.AppendLine(" {"); contentBuilder.AppendLine(" {");
content.AppendLine(" // Update your component here"); contentBuilder.AppendLine(" // Update your component here");
content.AppendLine(" }"); contentBuilder.AppendLine(" }");
} }
else if (scriptType == "ScriptableObject") else if (scriptType == "ScriptableObject")
{ {
content.AppendLine(" private void OnEnable()"); contentBuilder.AppendLine(" private void OnEnable()");
content.AppendLine(" {"); contentBuilder.AppendLine(" {");
content.AppendLine(" // Initialize your ScriptableObject here"); contentBuilder.AppendLine(" // Initialize your ScriptableObject here");
content.AppendLine(" }"); contentBuilder.AppendLine(" }");
} }
// Close class // Close class
content.AppendLine(" }"); contentBuilder.AppendLine(" }");
// Close namespace if specified // Close namespace if specified
if (!string.IsNullOrEmpty(namespaceName)) if (!string.IsNullOrEmpty(namespaceName))
{ {
content.AppendLine("}"); contentBuilder.AppendLine("}");
} }
// Create the script file in the Scripts folder // Create the script file in the Scripts folder
string fullPath = Path.Combine(Application.dataPath, scriptPath, scriptName); string fullFilePath = Path.Combine(Application.dataPath, scriptPath, scriptName);
File.WriteAllText(fullPath, content.ToString()); File.WriteAllText(fullFilePath, contentBuilder.ToString());
// Refresh the AssetDatabase // Refresh the AssetDatabase
AssetDatabase.Refresh(); AssetDatabase.Refresh();
@ -131,13 +168,39 @@ namespace MCPServer.Editor.Commands
{ {
string scriptPath = (string)@params["script_path"] ?? throw new System.Exception("Parameter 'script_path' is required."); string scriptPath = (string)@params["script_path"] ?? throw new System.Exception("Parameter 'script_path' is required.");
string content = (string)@params["content"] ?? throw new System.Exception("Parameter 'content' is required."); string content = (string)@params["content"] ?? throw new System.Exception("Parameter 'content' is required.");
bool createIfMissing = (bool?)@params["create_if_missing"] ?? false;
bool createFolderIfMissing = (bool?)@params["create_folder_if_missing"] ?? false;
string fullPath = Path.Combine(Application.dataPath, scriptPath); string fullPath = Path.Combine(Application.dataPath, scriptPath);
string directory = Path.GetDirectoryName(fullPath);
// Check if file exists, create if requested
if (!File.Exists(fullPath)) if (!File.Exists(fullPath))
throw new System.Exception($"Script file not found: {scriptPath}"); {
if (createIfMissing)
{
// Create the directory if requested and needed
if (!Directory.Exists(directory) && createFolderIfMissing)
{
Directory.CreateDirectory(directory);
}
else if (!Directory.Exists(directory))
{
throw new System.Exception($"Directory does not exist: {Path.GetDirectoryName(scriptPath)}");
}
// Write new content // Create the file with content
File.WriteAllText(fullPath, content);
AssetDatabase.Refresh();
return new { message = $"Created script: {scriptPath}" };
}
else
{
throw new System.Exception($"Script file not found: {scriptPath}");
}
}
// Update existing script
File.WriteAllText(fullPath, content); File.WriteAllText(fullPath, content);
// Refresh the AssetDatabase // Refresh the AssetDatabase
@ -152,7 +215,24 @@ namespace MCPServer.Editor.Commands
public static object ListScripts(JObject @params) public static object ListScripts(JObject @params)
{ {
string folderPath = (string)@params["folder_path"] ?? "Assets"; string folderPath = (string)@params["folder_path"] ?? "Assets";
string fullPath = Path.Combine(Application.dataPath, folderPath);
// Special handling for "Assets" path since it's already the root
string fullPath;
if (folderPath.Equals("Assets", StringComparison.OrdinalIgnoreCase))
{
fullPath = Application.dataPath;
}
else if (folderPath.StartsWith("Assets/", StringComparison.OrdinalIgnoreCase))
{
// Remove "Assets/" from the path since Application.dataPath already points to it
string relativePath = folderPath.Substring(7);
fullPath = Path.Combine(Application.dataPath, relativePath);
}
else
{
// Assume it's a relative path from Assets
fullPath = Path.Combine(Application.dataPath, folderPath);
}
if (!Directory.Exists(fullPath)) if (!Directory.Exists(fullPath))
throw new System.Exception($"Folder not found: {folderPath}"); throw new System.Exception($"Folder not found: {folderPath}");

View File

@ -26,6 +26,19 @@ public static partial class UnityMCPBridge
// Add public property to expose running state // Add public property to expose running state
public static bool IsRunning => isRunning; public static bool IsRunning => isRunning;
// Add method to check existence of a folder
public static bool FolderExists(string path)
{
if (string.IsNullOrEmpty(path))
return false;
if (path.Equals("Assets", StringComparison.OrdinalIgnoreCase))
return true;
string fullPath = Path.Combine(Application.dataPath, path.StartsWith("Assets/") ? path.Substring(7) : path);
return Directory.Exists(fullPath);
}
static UnityMCPBridge() static UnityMCPBridge()
{ {
LoadServerConfig(); LoadServerConfig();
@ -84,7 +97,14 @@ public static partial class UnityMCPBridge
try try
{ {
var client = await listener.AcceptTcpClientAsync(); var client = await listener.AcceptTcpClientAsync();
_ = HandleClientAsync(client); // Fire and forget each client connection // Enable basic socket keepalive
client.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true);
// Set longer receive timeout to prevent quick disconnections
client.ReceiveTimeout = 60000; // 60 seconds
// Fire and forget each client connection
_ = HandleClientAsync(client);
} }
catch (Exception ex) catch (Exception ex)
{ {

View File

@ -96,61 +96,33 @@ def register_script_tools(mcp: FastMCP):
try: try:
unity = get_unity_connection() unity = get_unity_connection()
# Check if the script exists first # Parse script path (for potential creation)
existing_script_response = unity.send_command("VIEW_SCRIPT", { script_name = script_path.split("/")[-1].replace(".cs", "")
"script_path": script_path script_folder = "/".join(script_path.split("/")[:-1])
})
# If the script doesn't exist if create_if_missing:
if "content" not in existing_script_response: # When create_if_missing is true, we'll just try to update directly,
if not create_if_missing: # and let Unity handle the creation if needed
return f"Script at '{script_path}' not found. Use create_if_missing=True to create it." params = {
"script_path": script_path,
"content": content,
"create_if_missing": True
}
# If we should create the missing script # Add folder creation flag if requested
script_name = script_path.split("/")[-1].replace(".cs", "") if create_folder_if_missing:
script_folder = "/".join(script_path.split("/")[:-1]) params["create_folder_if_missing"] = True
# Check if the parent directory exists # Send command to Unity to update/create the script
if script_folder: response = unity.send_command("UPDATE_SCRIPT", params)
folder_exists = False return response.get("message", "Script updated successfully")
try: else:
# Try to list scripts in the folder to see if it exists # Standard update without creation flags
folder_response = unity.send_command("LIST_SCRIPTS", { response = unity.send_command("UPDATE_SCRIPT", {
"folder_path": script_folder "script_path": script_path,
})
# 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 "content": content
}) })
return response.get("message", "Script created successfully") return response.get("message", "Script updated successfully")
# Send command to Unity to update the script
response = unity.send_command("UPDATE_SCRIPT", {
"script_path": script_path,
"content": content
})
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)}"