unity-mcp/MCPForUnity/Editor/Tools/ManageMaterial.cs

600 lines
24 KiB
C#
Raw Normal View History

feat: Add `manage_material` tool for dedicated material manipulation (#440) * WIP: Material management tool implementation and tests - Add ManageMaterial tool for creating and modifying materials - Add MaterialOps helper for material property operations - Add comprehensive test suite for material management - Add string parameter parsing support for material properties - Update related tools (ManageGameObject, manage_asset, etc.) - Add test materials and scenes for material testing * refactor: unify material property logic into MaterialOps - Move and logic from to - Update to delegate to - Update to use enhanced for creation and property setting - Add texture path loading support to * Add parameter aliasing support: accept 'name' as alias for 'target' in manage_gameobject modify action * Refactor ManageMaterial and fix code review issues - Fix Python server tools (redundant imports, exception handling, string formatting) - Clean up documentation and error reports - Improve ManageMaterial.cs (overwrite checks, error handling) - Enhance MaterialOps.cs (robustness, logging, dead code removal) - Update tests (assertions, unused imports) - Fix manifest.json relative path - Remove temporary test artifacts and manual setup scripts * Remove test scene * remove extra mat * Remove unnecessary SceneTemplateSettings.json * Remove unnecessary SceneTemplateSettings.json * Fix MaterialOps issues * Fix: Case-insensitive material property lookup and missing HasProperty checks * Rabbit fixes * Improve material ops logging and test coverage * Fix: NormalizePath now handles backslashes correctly using AssetPathUtility * Fix: Address multiple nitpicks (test robustness, shader resolution, HasProperty checks) * Add manage_material tool documentation and fix MaterialOps texture property checks - Add comprehensive ManageMaterial tool documentation to MCPForUnity/README.md - Add manage_material to tools list in README.md and README-zh.md - Fix MaterialOps.cs to check HasProperty before SetTexture calls to prevent Unity warnings - Ensures consistency with other property setters in MaterialOps * Fix ManageMaterial shader reflection for Unity 6 and improve texture logging
2025-12-08 11:39:52 +08:00
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using MCPForUnity.Editor.Helpers;
using UnityEngine;
using UnityEditor;
namespace MCPForUnity.Editor.Tools
{
[McpForUnityTool("manage_material", AutoRegister = false)]
public static class ManageMaterial
{
public static object HandleCommand(JObject @params)
{
string action = @params["action"]?.ToString();
if (string.IsNullOrEmpty(action))
{
return new { status = "error", message = "Action is required" };
}
try
{
switch (action)
{
case "ping":
return new { status = "success", tool = "manage_material" };
case "create":
return CreateMaterial(@params);
case "set_material_shader_property":
return SetMaterialShaderProperty(@params);
case "set_material_color":
return SetMaterialColor(@params);
case "assign_material_to_renderer":
return AssignMaterialToRenderer(@params);
case "set_renderer_color":
return SetRendererColor(@params);
case "get_material_info":
return GetMaterialInfo(@params);
default:
return new { status = "error", message = $"Unknown action: {action}" };
}
}
catch (Exception ex)
{
return new { status = "error", message = ex.Message, stackTrace = ex.StackTrace };
}
}
private static string NormalizePath(string path)
{
if (string.IsNullOrEmpty(path)) return path;
// Normalize separators and ensure Assets/ root
path = AssetPathUtility.SanitizeAssetPath(path);
// Ensure .mat extension
if (!path.EndsWith(".mat", StringComparison.OrdinalIgnoreCase))
{
path += ".mat";
}
return path;
}
private static object SetMaterialShaderProperty(JObject @params)
{
string materialPath = NormalizePath(@params["materialPath"]?.ToString());
string property = @params["property"]?.ToString();
JToken value = @params["value"];
if (string.IsNullOrEmpty(materialPath) || string.IsNullOrEmpty(property) || value == null)
{
return new { status = "error", message = "materialPath, property, and value are required" };
}
// Find material
var findInstruction = new JObject { ["find"] = materialPath };
Material mat = ManageGameObject.FindObjectByInstruction(findInstruction, typeof(Material)) as Material;
if (mat == null)
{
return new { status = "error", message = $"Could not find material at path: {materialPath}" };
}
Undo.RecordObject(mat, "Set Material Property");
// Normalize alias/casing once for all code paths
property = MaterialOps.ResolvePropertyName(mat, property);
// 1. Try handling Texture instruction explicitly (ManageMaterial special feature)
if (value.Type == JTokenType.Object)
{
// Check if it looks like an instruction
if (value is JObject obj && (obj.ContainsKey("find") || obj.ContainsKey("method")))
{
Texture tex = ManageGameObject.FindObjectByInstruction(obj, typeof(Texture)) as Texture;
if (tex != null && mat.HasProperty(property))
{
mat.SetTexture(property, tex);
EditorUtility.SetDirty(mat);
return new { status = "success", message = $"Set texture property {property} on {mat.name}" };
}
}
}
// 2. Fallback to standard logic via MaterialOps (handles Colors, Floats, Strings->Path)
bool success = MaterialOps.TrySetShaderProperty(mat, property, value, ManageGameObject.InputSerializer);
if (success)
{
EditorUtility.SetDirty(mat);
return new { status = "success", message = $"Set property {property} on {mat.name}" };
}
else
{
return new { status = "error", message = $"Failed to set property {property}. Value format might be unsupported or texture not found." };
}
}
private static object SetMaterialColor(JObject @params)
{
string materialPath = NormalizePath(@params["materialPath"]?.ToString());
JToken colorToken = @params["color"];
string property = @params["property"]?.ToString();
if (string.IsNullOrEmpty(materialPath) || colorToken == null)
{
return new { status = "error", message = "materialPath and color are required" };
}
var findInstruction = new JObject { ["find"] = materialPath };
Material mat = ManageGameObject.FindObjectByInstruction(findInstruction, typeof(Material)) as Material;
if (mat == null)
{
return new { status = "error", message = $"Could not find material at path: {materialPath}" };
}
Color color;
try
{
color = MaterialOps.ParseColor(colorToken, ManageGameObject.InputSerializer);
}
catch (Exception e)
{
return new { status = "error", message = $"Invalid color format: {e.Message}" };
}
Undo.RecordObject(mat, "Set Material Color");
bool foundProp = false;
if (!string.IsNullOrEmpty(property))
{
if (mat.HasProperty(property))
{
mat.SetColor(property, color);
foundProp = true;
}
}
else
{
// Fallback logic: _BaseColor (URP/HDRP) then _Color (Built-in)
if (mat.HasProperty("_BaseColor"))
{
mat.SetColor("_BaseColor", color);
foundProp = true;
property = "_BaseColor";
}
else if (mat.HasProperty("_Color"))
{
mat.SetColor("_Color", color);
foundProp = true;
property = "_Color";
}
}
if (foundProp)
{
EditorUtility.SetDirty(mat);
return new { status = "success", message = $"Set color on {property}" };
}
else
{
return new { status = "error", message = "Could not find suitable color property (_BaseColor or _Color) or specified property does not exist." };
}
}
private static object AssignMaterialToRenderer(JObject @params)
{
string target = @params["target"]?.ToString();
string searchMethod = @params["searchMethod"]?.ToString();
string materialPath = NormalizePath(@params["materialPath"]?.ToString());
int slot = @params["slot"]?.ToObject<int>() ?? 0;
if (string.IsNullOrEmpty(target) || string.IsNullOrEmpty(materialPath))
{
return new { status = "error", message = "target and materialPath are required" };
}
var goInstruction = new JObject { ["find"] = target };
if (!string.IsNullOrEmpty(searchMethod)) goInstruction["method"] = searchMethod;
GameObject go = ManageGameObject.FindObjectByInstruction(goInstruction, typeof(GameObject)) as GameObject;
if (go == null)
{
return new { status = "error", message = $"Could not find target GameObject: {target}" };
}
Renderer renderer = go.GetComponent<Renderer>();
if (renderer == null)
{
return new { status = "error", message = $"GameObject {go.name} has no Renderer component" };
}
var matInstruction = new JObject { ["find"] = materialPath };
Material mat = ManageGameObject.FindObjectByInstruction(matInstruction, typeof(Material)) as Material;
if (mat == null)
{
return new { status = "error", message = $"Could not find material: {materialPath}" };
}
Undo.RecordObject(renderer, "Assign Material");
Material[] sharedMats = renderer.sharedMaterials;
if (slot < 0 || slot >= sharedMats.Length)
{
return new { status = "error", message = $"Slot {slot} out of bounds (count: {sharedMats.Length})" };
}
sharedMats[slot] = mat;
renderer.sharedMaterials = sharedMats;
EditorUtility.SetDirty(renderer);
return new { status = "success", message = $"Assigned material {mat.name} to {go.name} slot {slot}" };
}
private static object SetRendererColor(JObject @params)
{
string target = @params["target"]?.ToString();
string searchMethod = @params["searchMethod"]?.ToString();
JToken colorToken = @params["color"];
int slot = @params["slot"]?.ToObject<int>() ?? 0;
string mode = @params["mode"]?.ToString() ?? "property_block";
if (string.IsNullOrEmpty(target) || colorToken == null)
{
return new { status = "error", message = "target and color are required" };
}
Color color;
try
{
color = MaterialOps.ParseColor(colorToken, ManageGameObject.InputSerializer);
}
catch (Exception e)
{
return new { status = "error", message = $"Invalid color format: {e.Message}" };
}
var goInstruction = new JObject { ["find"] = target };
if (!string.IsNullOrEmpty(searchMethod)) goInstruction["method"] = searchMethod;
GameObject go = ManageGameObject.FindObjectByInstruction(goInstruction, typeof(GameObject)) as GameObject;
if (go == null)
{
return new { status = "error", message = $"Could not find target GameObject: {target}" };
}
Renderer renderer = go.GetComponent<Renderer>();
if (renderer == null)
{
return new { status = "error", message = $"GameObject {go.name} has no Renderer component" };
}
if (mode == "property_block")
{
if (slot < 0 || slot >= renderer.sharedMaterials.Length)
{
return new { status = "error", message = $"Slot {slot} out of bounds (count: {renderer.sharedMaterials.Length})" };
}
MaterialPropertyBlock block = new MaterialPropertyBlock();
renderer.GetPropertyBlock(block, slot);
if (renderer.sharedMaterials[slot] != null)
{
Material mat = renderer.sharedMaterials[slot];
if (mat.HasProperty("_BaseColor")) block.SetColor("_BaseColor", color);
else if (mat.HasProperty("_Color")) block.SetColor("_Color", color);
else block.SetColor("_Color", color);
}
else
{
block.SetColor("_Color", color);
}
renderer.SetPropertyBlock(block, slot);
EditorUtility.SetDirty(renderer);
return new { status = "success", message = $"Set renderer color (PropertyBlock) on slot {slot}" };
}
else if (mode == "shared")
{
if (slot >= 0 && slot < renderer.sharedMaterials.Length)
{
Material mat = renderer.sharedMaterials[slot];
if (mat == null)
{
return new { status = "error", message = $"No material in slot {slot}" };
}
Undo.RecordObject(mat, "Set Material Color");
if (mat.HasProperty("_BaseColor")) mat.SetColor("_BaseColor", color);
else mat.SetColor("_Color", color);
EditorUtility.SetDirty(mat);
return new { status = "success", message = "Set shared material color" };
}
return new { status = "error", message = "Invalid slot" };
}
else if (mode == "instance")
{
if (slot >= 0 && slot < renderer.materials.Length)
{
Material mat = renderer.materials[slot];
if (mat == null)
{
return new { status = "error", message = $"No material in slot {slot}" };
}
// Note: Undo cannot fully revert material instantiation
Undo.RecordObject(mat, "Set Instance Material Color");
if (mat.HasProperty("_BaseColor")) mat.SetColor("_BaseColor", color);
else mat.SetColor("_Color", color);
return new { status = "success", message = "Set instance material color", warning = "Material instance created; Undo cannot fully revert instantiation." };
}
return new { status = "error", message = "Invalid slot" };
}
return new { status = "error", message = $"Unknown mode: {mode}" };
}
private static object GetMaterialInfo(JObject @params)
{
string materialPath = NormalizePath(@params["materialPath"]?.ToString());
if (string.IsNullOrEmpty(materialPath))
{
return new { status = "error", message = "materialPath is required" };
}
var findInstruction = new JObject { ["find"] = materialPath };
Material mat = ManageGameObject.FindObjectByInstruction(findInstruction, typeof(Material)) as Material;
if (mat == null)
{
return new { status = "error", message = $"Could not find material at path: {materialPath}" };
}
Shader shader = mat.shader;
var properties = new List<object>();
#if UNITY_6000_0_OR_NEWER
int propertyCount = shader.GetPropertyCount();
for (int i = 0; i < propertyCount; i++)
{
string name = shader.GetPropertyName(i);
var type = shader.GetPropertyType(i);
string description = shader.GetPropertyDescription(i);
object currentValue = null;
try
{
if (mat.HasProperty(name))
{
switch (type)
{
case UnityEngine.Rendering.ShaderPropertyType.Color:
var c = mat.GetColor(name);
currentValue = new { r = c.r, g = c.g, b = c.b, a = c.a };
break;
case UnityEngine.Rendering.ShaderPropertyType.Vector:
var v = mat.GetVector(name);
currentValue = new { x = v.x, y = v.y, z = v.z, w = v.w };
break;
case UnityEngine.Rendering.ShaderPropertyType.Float:
case UnityEngine.Rendering.ShaderPropertyType.Range:
currentValue = mat.GetFloat(name);
break;
case UnityEngine.Rendering.ShaderPropertyType.Texture:
currentValue = mat.GetTexture(name)?.name ?? "null";
break;
}
}
}
catch (Exception ex)
{
currentValue = $"<error: {ex.Message}>";
}
properties.Add(new
{
name = name,
type = type.ToString(),
description = description,
value = currentValue
});
}
#else
int propertyCount = ShaderUtil.GetPropertyCount(shader);
for (int i = 0; i < propertyCount; i++)
{
string name = ShaderUtil.GetPropertyName(shader, i);
ShaderUtil.ShaderPropertyType type = ShaderUtil.GetPropertyType(shader, i);
string description = ShaderUtil.GetPropertyDescription(shader, i);
object currentValue = null;
try {
if (mat.HasProperty(name))
{
switch (type) {
case ShaderUtil.ShaderPropertyType.Color:
var c = mat.GetColor(name);
currentValue = new { r = c.r, g = c.g, b = c.b, a = c.a };
break;
case ShaderUtil.ShaderPropertyType.Vector:
var v = mat.GetVector(name);
currentValue = new { x = v.x, y = v.y, z = v.z, w = v.w };
break;
case ShaderUtil.ShaderPropertyType.Float: currentValue = mat.GetFloat(name); break;
case ShaderUtil.ShaderPropertyType.Range: currentValue = mat.GetFloat(name); break;
case ShaderUtil.ShaderPropertyType.TexEnv: currentValue = mat.GetTexture(name)?.name ?? "null"; break;
}
}
} catch (Exception ex) {
currentValue = $"<error: {ex.Message}>";
}
properties.Add(new {
name = name,
type = type.ToString(),
description = description,
value = currentValue
});
}
#endif
return new {
status = "success",
material = mat.name,
shader = shader.name,
properties = properties
};
}
private static object CreateMaterial(JObject @params)
{
string materialPath = NormalizePath(@params["materialPath"]?.ToString());
string shaderName = @params["shader"]?.ToString() ?? "Standard";
JToken colorToken = @params["color"];
string colorProperty = @params["property"]?.ToString();
feat: Add `manage_material` tool for dedicated material manipulation (#440) * WIP: Material management tool implementation and tests - Add ManageMaterial tool for creating and modifying materials - Add MaterialOps helper for material property operations - Add comprehensive test suite for material management - Add string parameter parsing support for material properties - Update related tools (ManageGameObject, manage_asset, etc.) - Add test materials and scenes for material testing * refactor: unify material property logic into MaterialOps - Move and logic from to - Update to delegate to - Update to use enhanced for creation and property setting - Add texture path loading support to * Add parameter aliasing support: accept 'name' as alias for 'target' in manage_gameobject modify action * Refactor ManageMaterial and fix code review issues - Fix Python server tools (redundant imports, exception handling, string formatting) - Clean up documentation and error reports - Improve ManageMaterial.cs (overwrite checks, error handling) - Enhance MaterialOps.cs (robustness, logging, dead code removal) - Update tests (assertions, unused imports) - Fix manifest.json relative path - Remove temporary test artifacts and manual setup scripts * Remove test scene * remove extra mat * Remove unnecessary SceneTemplateSettings.json * Remove unnecessary SceneTemplateSettings.json * Fix MaterialOps issues * Fix: Case-insensitive material property lookup and missing HasProperty checks * Rabbit fixes * Improve material ops logging and test coverage * Fix: NormalizePath now handles backslashes correctly using AssetPathUtility * Fix: Address multiple nitpicks (test robustness, shader resolution, HasProperty checks) * Add manage_material tool documentation and fix MaterialOps texture property checks - Add comprehensive ManageMaterial tool documentation to MCPForUnity/README.md - Add manage_material to tools list in README.md and README-zh.md - Fix MaterialOps.cs to check HasProperty before SetTexture calls to prevent Unity warnings - Ensures consistency with other property setters in MaterialOps * Fix ManageMaterial shader reflection for Unity 6 and improve texture logging
2025-12-08 11:39:52 +08:00
JObject properties = null;
JToken propsToken = @params["properties"];
if (propsToken != null)
{
if (propsToken.Type == JTokenType.String)
{
try { properties = JObject.Parse(propsToken.ToString()); }
catch (Exception ex) { return new { status = "error", message = $"Invalid JSON in properties: {ex.Message}" }; }
}
else if (propsToken is JObject obj)
{
properties = obj;
}
}
if (string.IsNullOrEmpty(materialPath))
{
return new { status = "error", message = "materialPath is required" };
}
// Path normalization handled by helper above, explicit check removed
// but we ensure it's valid for CreateAsset
if (!materialPath.StartsWith("Assets/"))
{
return new { status = "error", message = "Path must start with Assets/ (normalization failed)" };
}
Shader shader = RenderPipelineUtility.ResolveShader(shaderName);
if (shader == null)
{
return new { status = "error", message = $"Could not find shader: {shaderName}" };
}
// Check for existing asset to avoid silent overwrite
if (AssetDatabase.LoadAssetAtPath<Material>(materialPath) != null)
{
return new { status = "error", message = $"Material already exists at {materialPath}" };
}
Material material = null;
var shouldDestroyMaterial = true;
try
feat: Add `manage_material` tool for dedicated material manipulation (#440) * WIP: Material management tool implementation and tests - Add ManageMaterial tool for creating and modifying materials - Add MaterialOps helper for material property operations - Add comprehensive test suite for material management - Add string parameter parsing support for material properties - Update related tools (ManageGameObject, manage_asset, etc.) - Add test materials and scenes for material testing * refactor: unify material property logic into MaterialOps - Move and logic from to - Update to delegate to - Update to use enhanced for creation and property setting - Add texture path loading support to * Add parameter aliasing support: accept 'name' as alias for 'target' in manage_gameobject modify action * Refactor ManageMaterial and fix code review issues - Fix Python server tools (redundant imports, exception handling, string formatting) - Clean up documentation and error reports - Improve ManageMaterial.cs (overwrite checks, error handling) - Enhance MaterialOps.cs (robustness, logging, dead code removal) - Update tests (assertions, unused imports) - Fix manifest.json relative path - Remove temporary test artifacts and manual setup scripts * Remove test scene * remove extra mat * Remove unnecessary SceneTemplateSettings.json * Remove unnecessary SceneTemplateSettings.json * Fix MaterialOps issues * Fix: Case-insensitive material property lookup and missing HasProperty checks * Rabbit fixes * Improve material ops logging and test coverage * Fix: NormalizePath now handles backslashes correctly using AssetPathUtility * Fix: Address multiple nitpicks (test robustness, shader resolution, HasProperty checks) * Add manage_material tool documentation and fix MaterialOps texture property checks - Add comprehensive ManageMaterial tool documentation to MCPForUnity/README.md - Add manage_material to tools list in README.md and README-zh.md - Fix MaterialOps.cs to check HasProperty before SetTexture calls to prevent Unity warnings - Ensures consistency with other property setters in MaterialOps * Fix ManageMaterial shader reflection for Unity 6 and improve texture logging
2025-12-08 11:39:52 +08:00
{
material = new Material(shader);
// Apply color param during creation (keeps Python tool signature and C# implementation consistent).
// If "properties" already contains a color property, let properties win.
bool shouldApplyColor = false;
if (colorToken != null)
{
if (properties == null)
{
shouldApplyColor = true;
}
else if (!string.IsNullOrEmpty(colorProperty))
{
// If colorProperty is specified, only check that specific property.
shouldApplyColor = !properties.ContainsKey(colorProperty);
}
else
{
// If colorProperty is not specified, check fallback properties.
shouldApplyColor = !properties.ContainsKey("_BaseColor") && !properties.ContainsKey("_Color");
}
}
if (shouldApplyColor)
{
Color color;
try
{
color = MaterialOps.ParseColor(colorToken, ManageGameObject.InputSerializer);
}
catch (Exception e)
{
return new { status = "error", message = $"Invalid color format: {e.Message}" };
}
if (!string.IsNullOrEmpty(colorProperty))
{
if (material.HasProperty(colorProperty))
{
material.SetColor(colorProperty, color);
}
else
{
return new
{
status = "error",
message = $"Specified color property '{colorProperty}' does not exist on this material."
};
}
}
else if (material.HasProperty("_BaseColor"))
{
material.SetColor("_BaseColor", color);
}
else if (material.HasProperty("_Color"))
{
material.SetColor("_Color", color);
}
else
{
return new
{
status = "error",
message = "Could not find suitable color property (_BaseColor or _Color) on this material's shader."
};
}
}
AssetDatabase.CreateAsset(material, materialPath);
shouldDestroyMaterial = false; // material is now owned by the AssetDatabase
if (properties != null)
{
MaterialOps.ApplyProperties(material, properties, ManageGameObject.InputSerializer);
}
feat: Add `manage_material` tool for dedicated material manipulation (#440) * WIP: Material management tool implementation and tests - Add ManageMaterial tool for creating and modifying materials - Add MaterialOps helper for material property operations - Add comprehensive test suite for material management - Add string parameter parsing support for material properties - Update related tools (ManageGameObject, manage_asset, etc.) - Add test materials and scenes for material testing * refactor: unify material property logic into MaterialOps - Move and logic from to - Update to delegate to - Update to use enhanced for creation and property setting - Add texture path loading support to * Add parameter aliasing support: accept 'name' as alias for 'target' in manage_gameobject modify action * Refactor ManageMaterial and fix code review issues - Fix Python server tools (redundant imports, exception handling, string formatting) - Clean up documentation and error reports - Improve ManageMaterial.cs (overwrite checks, error handling) - Enhance MaterialOps.cs (robustness, logging, dead code removal) - Update tests (assertions, unused imports) - Fix manifest.json relative path - Remove temporary test artifacts and manual setup scripts * Remove test scene * remove extra mat * Remove unnecessary SceneTemplateSettings.json * Remove unnecessary SceneTemplateSettings.json * Fix MaterialOps issues * Fix: Case-insensitive material property lookup and missing HasProperty checks * Rabbit fixes * Improve material ops logging and test coverage * Fix: NormalizePath now handles backslashes correctly using AssetPathUtility * Fix: Address multiple nitpicks (test robustness, shader resolution, HasProperty checks) * Add manage_material tool documentation and fix MaterialOps texture property checks - Add comprehensive ManageMaterial tool documentation to MCPForUnity/README.md - Add manage_material to tools list in README.md and README-zh.md - Fix MaterialOps.cs to check HasProperty before SetTexture calls to prevent Unity warnings - Ensures consistency with other property setters in MaterialOps * Fix ManageMaterial shader reflection for Unity 6 and improve texture logging
2025-12-08 11:39:52 +08:00
EditorUtility.SetDirty(material);
AssetDatabase.SaveAssets();
return new { status = "success", message = $"Created material at {materialPath} with shader {shaderName}" };
}
finally
{
if (shouldDestroyMaterial && material != null)
{
UnityEngine.Object.DestroyImmediate(material);
}
}
feat: Add `manage_material` tool for dedicated material manipulation (#440) * WIP: Material management tool implementation and tests - Add ManageMaterial tool for creating and modifying materials - Add MaterialOps helper for material property operations - Add comprehensive test suite for material management - Add string parameter parsing support for material properties - Update related tools (ManageGameObject, manage_asset, etc.) - Add test materials and scenes for material testing * refactor: unify material property logic into MaterialOps - Move and logic from to - Update to delegate to - Update to use enhanced for creation and property setting - Add texture path loading support to * Add parameter aliasing support: accept 'name' as alias for 'target' in manage_gameobject modify action * Refactor ManageMaterial and fix code review issues - Fix Python server tools (redundant imports, exception handling, string formatting) - Clean up documentation and error reports - Improve ManageMaterial.cs (overwrite checks, error handling) - Enhance MaterialOps.cs (robustness, logging, dead code removal) - Update tests (assertions, unused imports) - Fix manifest.json relative path - Remove temporary test artifacts and manual setup scripts * Remove test scene * remove extra mat * Remove unnecessary SceneTemplateSettings.json * Remove unnecessary SceneTemplateSettings.json * Fix MaterialOps issues * Fix: Case-insensitive material property lookup and missing HasProperty checks * Rabbit fixes * Improve material ops logging and test coverage * Fix: NormalizePath now handles backslashes correctly using AssetPathUtility * Fix: Address multiple nitpicks (test robustness, shader resolution, HasProperty checks) * Add manage_material tool documentation and fix MaterialOps texture property checks - Add comprehensive ManageMaterial tool documentation to MCPForUnity/README.md - Add manage_material to tools list in README.md and README-zh.md - Fix MaterialOps.cs to check HasProperty before SetTexture calls to prevent Unity warnings - Ensures consistency with other property setters in MaterialOps * Fix ManageMaterial shader reflection for Unity 6 and improve texture logging
2025-12-08 11:39:52 +08:00
}
}
}