From f8d4915f28c21614e40e2475be5bdd0d7a17e77b Mon Sep 17 00:00:00 2001 From: jfjia Date: Thu, 5 Mar 2026 17:00:29 +0800 Subject: [PATCH 1/3] feat(mcpforunity): support atlas sprite resolution by guid+spriteName/fileID --- MCPForUnity/Editor/Helpers/ComponentOps.cs | 80 ++++++++++++++++++++++ 1 file changed, 80 insertions(+) diff --git a/MCPForUnity/Editor/Helpers/ComponentOps.cs b/MCPForUnity/Editor/Helpers/ComponentOps.cs index e4e456ac4..a3397070f 100644 --- a/MCPForUnity/Editor/Helpers/ComponentOps.cs +++ b/MCPForUnity/Editor/Helpers/ComponentOps.cs @@ -197,11 +197,21 @@ private static bool TrySetViaReflection(object component, Type type, string prop { error = null; + // Skip reflection for UnityEngine.Object types with JObject values + // so SerializedProperty can resolve guid/spriteName/fileID forms. + bool isJObjectValue = value != null && value.Type == JTokenType.Object; + // Try property first PropertyInfo propInfo = type.GetProperty(propertyName, flags) ?? type.GetProperty(normalizedName, flags); if (propInfo != null && propInfo.CanWrite) { + if (isJObjectValue && typeof(UnityEngine.Object).IsAssignableFrom(propInfo.PropertyType)) + { + // Let SerializedProperty path handle complex object references. + return false; + } + try { object convertedValue = PropertyConversion.ConvertToType(value, propInfo.PropertyType); @@ -225,6 +235,12 @@ private static bool TrySetViaReflection(object component, Type type, string prop ?? type.GetField(normalizedName, flags); if (fieldInfo != null && !fieldInfo.IsInitOnly) { + if (isJObjectValue && typeof(UnityEngine.Object).IsAssignableFrom(fieldInfo.FieldType)) + { + // Let SerializedProperty path handle complex object references. + return false; + } + try { object convertedValue = PropertyConversion.ConvertToType(value, fieldInfo.FieldType); @@ -248,6 +264,12 @@ private static bool TrySetViaReflection(object component, Type type, string prop ?? FindSerializedFieldInHierarchy(type, normalizedName); if (fieldInfo != null) { + if (isJObjectValue && typeof(UnityEngine.Object).IsAssignableFrom(fieldInfo.FieldType)) + { + // Let SerializedProperty path handle complex object references. + return false; + } + try { object convertedValue = PropertyConversion.ConvertToType(value, fieldInfo.FieldType); @@ -599,6 +621,47 @@ private static bool SetObjectReference(SerializedProperty prop, JToken value, ou error = $"No asset found for GUID '{guidToken}'."; return false; } + + var spriteNameToken = jObj["spriteName"]; + if (spriteNameToken != null) + { + string spriteName = spriteNameToken.ToString(); + var allAssets = AssetDatabase.LoadAllAssetsAtPath(path); + foreach (var asset in allAssets) + { + if (asset is Sprite sprite && sprite.name == spriteName) + { + prop.objectReferenceValue = sprite; + return true; + } + } + + error = $"Sprite '{spriteName}' not found in atlas '{path}'."; + return false; + } + + var fileIdToken = jObj["fileID"]; + if (fileIdToken != null) + { + long targetFileId = ParamCoercion.CoerceLong(fileIdToken, 0); + if (targetFileId != 0) + { + var allAssets = AssetDatabase.LoadAllAssetsAtPath(path); + foreach (var asset in allAssets) + { + if (asset is Sprite sprite) + { + long spriteFileId = GetSpriteFileId(sprite); + if (spriteFileId == targetFileId) + { + prop.objectReferenceValue = sprite; + return true; + } + } + } + } + } + prop.objectReferenceValue = AssetDatabase.LoadAssetAtPath(path); return true; } @@ -767,6 +830,23 @@ private static bool SetEnum(SerializedProperty prop, JToken value, out string er error = $"Unknown enum name '{s}'."; return false; } + + + private static long GetSpriteFileId(Sprite sprite) + { + if (sprite == null) + return 0; + + try + { + var globalId = GlobalObjectId.GetGlobalObjectIdSlow(sprite); + return (long)globalId.targetObjectId; + } + catch + { + return 0; + } + } } } From 7fd9af2d59eb344bb60342d8d396e3db95ca3eb1 Mon Sep 17 00:00:00 2001 From: Shutong Wu <51266340+Scriptwonder@users.noreply.github.com> Date: Tue, 10 Mar 2026 22:55:10 -0400 Subject: [PATCH 2/3] fix: resolve compilation error and silent fallthrough in atlas sprite resolution - Replace non-existent ParamCoercion.CoerceLong with fileIdToken.Value() - Add error return when fileID matches no sprite (consistent with spriteName branch) - Remove extra blank line before GetSpriteFileId Co-Authored-By: Claude Opus 4.6 --- MCPForUnity/Editor/Helpers/ComponentOps.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/MCPForUnity/Editor/Helpers/ComponentOps.cs b/MCPForUnity/Editor/Helpers/ComponentOps.cs index a3397070f..8b8dc99f3 100644 --- a/MCPForUnity/Editor/Helpers/ComponentOps.cs +++ b/MCPForUnity/Editor/Helpers/ComponentOps.cs @@ -643,7 +643,7 @@ private static bool SetObjectReference(SerializedProperty prop, JToken value, ou var fileIdToken = jObj["fileID"]; if (fileIdToken != null) { - long targetFileId = ParamCoercion.CoerceLong(fileIdToken, 0); + long targetFileId = fileIdToken.Value(); if (targetFileId != 0) { var allAssets = AssetDatabase.LoadAllAssetsAtPath(path); @@ -660,6 +660,9 @@ private static bool SetObjectReference(SerializedProperty prop, JToken value, ou } } } + + error = $"Sprite with fileID '{targetFileId}' not found in atlas '{path}'."; + return false; } prop.objectReferenceValue = AssetDatabase.LoadAssetAtPath(path); @@ -831,7 +834,6 @@ private static bool SetEnum(SerializedProperty prop, JToken value, out string er return false; } - private static long GetSpriteFileId(Sprite sprite) { if (sprite == null) From b61abdc968401ae6445c4efb48118873c04b1c7f Mon Sep 17 00:00:00 2001 From: Shutong Wu <51266340+Scriptwonder@users.noreply.github.com> Date: Tue, 10 Mar 2026 23:21:04 -0400 Subject: [PATCH 3/3] fix: use unchecked cast and log exceptions in GetSpriteFileId - unchecked((long)targetObjectId) prevents OverflowException for large ulong fileIDs - Replace silent catch with McpLog.Warn including sprite name and instanceID Co-Authored-By: Claude Opus 4.6 --- MCPForUnity/Editor/Helpers/ComponentOps.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/MCPForUnity/Editor/Helpers/ComponentOps.cs b/MCPForUnity/Editor/Helpers/ComponentOps.cs index a1b7b3000..57a7a57da 100644 --- a/MCPForUnity/Editor/Helpers/ComponentOps.cs +++ b/MCPForUnity/Editor/Helpers/ComponentOps.cs @@ -842,10 +842,11 @@ private static long GetSpriteFileId(Sprite sprite) try { var globalId = GlobalObjectId.GetGlobalObjectIdSlow(sprite); - return (long)globalId.targetObjectId; + return unchecked((long)globalId.targetObjectId); } - catch + catch (Exception ex) { + McpLog.Warn($"Failed to get fileID for sprite '{sprite.name}' (instanceID={sprite.GetInstanceID()}): {ex.Message}"); return 0; } }