Update for ManageShader

Bug fix and error handling check for the PR. Great work and I love what I built!
main
Scriptwonder 2025-07-14 01:42:16 -04:00
parent d4bd504e31
commit 55f7c55389
5 changed files with 79 additions and 46 deletions

View File

@ -25,6 +25,7 @@ Unity MCP acts as a bridge, allowing AI assistants (like Claude, Cursor) to inte
* `manage_editor`: Controls and queries the editor's state and settings. * `manage_editor`: Controls and queries the editor's state and settings.
* `manage_scene`: Manages scenes (load, save, create, get hierarchy, etc.). * `manage_scene`: Manages scenes (load, save, create, get hierarchy, etc.).
* `manage_asset`: Performs asset operations (import, create, modify, delete, etc.). * `manage_asset`: Performs asset operations (import, create, modify, delete, etc.).
* `manage_shader`: Performs shader CRUD operations (create, read, modify, delete).
* `manage_gameobject`: Manages GameObjects: create, modify, delete, find, and component operations. * `manage_gameobject`: Manages GameObjects: create, modify, delete, find, and component operations.
* `execute_menu_item`: Executes a menu item via its path (e.g., "File/Save Project"). * `execute_menu_item`: Executes a menu item via its path (e.g., "File/Save Project").
</details> </details>
@ -81,7 +82,9 @@ Unity MCP connects your tools using two components:
Connect your MCP Client (Claude, Cursor, etc.) to the Python server you installed in Step 1. Connect your MCP Client (Claude, Cursor, etc.) to the Python server you installed in Step 1.
**Option A: Auto-Configure (Recommended for Claude/Cursor)** <img width="609" alt="image" src="https://github.com/user-attachments/assets/cef3a639-4677-4fd8-84e7-2d82a04d55bb" />
**Option A: Auto-Configure (Recommended for Claude/Cursor/VSC Copilot)**
1. In Unity, go to `Window > Unity MCP`. 1. In Unity, go to `Window > Unity MCP`.
2. Click `Auto Configure Claude` or `Auto Configure Cursor`. 2. Click `Auto Configure Claude` or `Auto Configure Cursor`.

View File

@ -20,6 +20,7 @@ namespace UnityMcpBridge.Editor.Tools
{ "HandleManageAsset", ManageAsset.HandleCommand }, { "HandleManageAsset", ManageAsset.HandleCommand },
{ "HandleReadConsole", ReadConsole.HandleCommand }, { "HandleReadConsole", ReadConsole.HandleCommand },
{ "HandleExecuteMenuItem", ExecuteMenuItem.HandleCommand }, { "HandleExecuteMenuItem", ExecuteMenuItem.HandleCommand },
{ "HandleManageShader", ManageShader.HandleCommand},
}; };
/// <summary> /// <summary>

View File

@ -89,7 +89,12 @@ namespace UnityMcpBridge.Editor.Tools
{ {
try try
{ {
Directory.CreateDirectory(fullPathDir); if (!Directory.Exists(fullPathDir))
{
Directory.CreateDirectory(fullPathDir);
// Refresh AssetDatabase to recognize new folders
AssetDatabase.Refresh();
}
} }
catch (Exception e) catch (Exception e)
{ {
@ -150,6 +155,14 @@ namespace UnityMcpBridge.Editor.Tools
); );
} }
// Add validation for shader name conflicts in Unity
if (Shader.Find(name) != null)
{
return Response.Error(
$"A shader with name '{name}' already exists in the project. Choose a different name."
);
}
// Generate default content if none provided // Generate default content if none provided
if (string.IsNullOrEmpty(contents)) if (string.IsNullOrEmpty(contents))
{ {
@ -184,6 +197,7 @@ namespace UnityMcpBridge.Editor.Tools
string contents = File.ReadAllText(fullPath); string contents = File.ReadAllText(fullPath);
// Return both normal and encoded contents for larger files // Return both normal and encoded contents for larger files
//TODO: Consider a threshold for large files
bool isLarge = contents.Length > 10000; // If content is large, include encoded version bool isLarge = contents.Length > 10000; // If content is large, include encoded version
var responseData = new var responseData = new
{ {
@ -227,6 +241,7 @@ namespace UnityMcpBridge.Editor.Tools
{ {
File.WriteAllText(fullPath, contents); File.WriteAllText(fullPath, contents);
AssetDatabase.ImportAsset(relativePath); AssetDatabase.ImportAsset(relativePath);
AssetDatabase.Refresh();
return Response.Success( return Response.Success(
$"Shader '{Path.GetFileName(relativePath)}' updated successfully.", $"Shader '{Path.GetFileName(relativePath)}' updated successfully.",
new { path = relativePath } new { path = relativePath }
@ -268,58 +283,60 @@ namespace UnityMcpBridge.Editor.Tools
} }
} }
//This is a CGProgram template
//TODO: making a HLSL template as well?
private static string GenerateDefaultShaderContent(string name) private static string GenerateDefaultShaderContent(string name)
{ {
return @"Shader """ + name + @""" return @"Shader """ + name + @"""
{
Properties
{
_MainTex (""Texture"", 2D) = ""white"" {}
}
SubShader
{
Tags { ""RenderType""=""Opaque"" }
LOD 100
Pass
{ {
CGPROGRAM Properties
#pragma vertex vert
#pragma fragment frag
#include ""UnityCG.cginc""
struct appdata
{ {
float4 vertex : POSITION; _MainTex (""Texture"", 2D) = ""white"" {}
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
};
sampler2D _MainTex;
float4 _MainTex_ST;
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
return o;
} }
SubShader
fixed4 frag (v2f i) : SV_Target
{ {
fixed4 col = tex2D(_MainTex, i.uv); Tags { ""RenderType""=""Opaque"" }
return col; LOD 100
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include ""UnityCG.cginc""
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
};
sampler2D _MainTex;
float4 _MainTex_ST;
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
return o;
}
fixed4 frag (v2f i) : SV_Target
{
fixed4 col = tex2D(_MainTex, i.uv);
return col;
}
ENDCG
}
} }
ENDCG }";
}
}
}";
} }
} }
} }

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: bcf4f1f3110494344b2af9324cf5c571
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -378,6 +378,7 @@ namespace UnityMcpBridge.Editor
"manage_editor" => ManageEditor.HandleCommand(paramsObject), "manage_editor" => ManageEditor.HandleCommand(paramsObject),
"manage_gameobject" => ManageGameObject.HandleCommand(paramsObject), "manage_gameobject" => ManageGameObject.HandleCommand(paramsObject),
"manage_asset" => ManageAsset.HandleCommand(paramsObject), "manage_asset" => ManageAsset.HandleCommand(paramsObject),
"manage_shader" => ManageShader.HandleCommand(paramsObject),
"read_console" => ReadConsole.HandleCommand(paramsObject), "read_console" => ReadConsole.HandleCommand(paramsObject),
"execute_menu_item" => ExecuteMenuItem.HandleCommand(paramsObject), "execute_menu_item" => ExecuteMenuItem.HandleCommand(paramsObject),
_ => throw new ArgumentException( _ => throw new ArgumentException(