239 lines
9.7 KiB
C#
239 lines
9.7 KiB
C#
#nullable disable
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using MCPForUnity.Editor.Helpers;
|
|
using MCPForUnity.Editor.Tools;
|
|
using Newtonsoft.Json.Linq;
|
|
using UnityEditor.SceneManagement;
|
|
using UnityEngine;
|
|
using UnityEngine.SceneManagement;
|
|
|
|
namespace MCPForUnity.Editor.Tools.GameObjects
|
|
{
|
|
internal static class ManageGameObjectCommon
|
|
{
|
|
internal static GameObject FindObjectInternal(JToken targetToken, string searchMethod, JObject findParams = null)
|
|
{
|
|
bool findAll = findParams?["findAll"]?.ToObject<bool>() ?? false;
|
|
|
|
if (
|
|
targetToken?.Type == JTokenType.Integer
|
|
|| (searchMethod == "by_id" && int.TryParse(targetToken?.ToString(), out _))
|
|
)
|
|
{
|
|
findAll = false;
|
|
}
|
|
|
|
List<GameObject> results = FindObjectsInternal(targetToken, searchMethod, findAll, findParams);
|
|
return results.Count > 0 ? results[0] : null;
|
|
}
|
|
|
|
internal static List<GameObject> FindObjectsInternal(
|
|
JToken targetToken,
|
|
string searchMethod,
|
|
bool findAll,
|
|
JObject findParams = null
|
|
)
|
|
{
|
|
List<GameObject> results = new List<GameObject>();
|
|
string searchTerm = findParams?["searchTerm"]?.ToString() ?? targetToken?.ToString();
|
|
bool searchInChildren = findParams?["searchInChildren"]?.ToObject<bool>() ?? false;
|
|
bool searchInactive = findParams?["searchInactive"]?.ToObject<bool>() ?? false;
|
|
|
|
if (string.IsNullOrEmpty(searchMethod))
|
|
{
|
|
if (targetToken?.Type == JTokenType.Integer)
|
|
searchMethod = "by_id";
|
|
else if (!string.IsNullOrEmpty(searchTerm) && searchTerm.Contains('/'))
|
|
searchMethod = "by_path";
|
|
else
|
|
searchMethod = "by_name";
|
|
}
|
|
|
|
GameObject rootSearchObject = null;
|
|
if (searchInChildren && targetToken != null)
|
|
{
|
|
rootSearchObject = FindObjectInternal(targetToken, "by_id_or_name_or_path");
|
|
if (rootSearchObject == null)
|
|
{
|
|
McpLog.Warn($"[ManageGameObject.Find] Root object '{targetToken}' for child search not found.");
|
|
return results;
|
|
}
|
|
}
|
|
|
|
switch (searchMethod)
|
|
{
|
|
case "by_id":
|
|
if (int.TryParse(searchTerm, out int instanceId))
|
|
{
|
|
var allObjects = GetAllSceneObjects(searchInactive);
|
|
GameObject obj = allObjects.FirstOrDefault(go => go.GetInstanceID() == instanceId);
|
|
if (obj != null)
|
|
results.Add(obj);
|
|
}
|
|
break;
|
|
|
|
case "by_name":
|
|
var searchPoolName = rootSearchObject
|
|
? rootSearchObject
|
|
.GetComponentsInChildren<Transform>(searchInactive)
|
|
.Select(t => t.gameObject)
|
|
: GetAllSceneObjects(searchInactive);
|
|
results.AddRange(searchPoolName.Where(go => go.name == searchTerm));
|
|
break;
|
|
|
|
case "by_path":
|
|
if (rootSearchObject != null)
|
|
{
|
|
Transform foundTransform = rootSearchObject.transform.Find(searchTerm);
|
|
if (foundTransform != null)
|
|
results.Add(foundTransform.gameObject);
|
|
}
|
|
else
|
|
{
|
|
var prefabStage = PrefabStageUtility.GetCurrentPrefabStage();
|
|
if (prefabStage != null || searchInactive)
|
|
{
|
|
// In Prefab Stage, GameObject.Find() doesn't work, need to search manually
|
|
var allObjects = GetAllSceneObjects(searchInactive);
|
|
foreach (var go in allObjects)
|
|
{
|
|
if (GameObjectLookup.MatchesPath(go, searchTerm))
|
|
{
|
|
results.Add(go);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
var found = GameObject.Find(searchTerm);
|
|
if (found != null)
|
|
results.Add(found);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case "by_tag":
|
|
var searchPoolTag = rootSearchObject
|
|
? rootSearchObject
|
|
.GetComponentsInChildren<Transform>(searchInactive)
|
|
.Select(t => t.gameObject)
|
|
: GetAllSceneObjects(searchInactive);
|
|
results.AddRange(searchPoolTag.Where(go => go.CompareTag(searchTerm)));
|
|
break;
|
|
|
|
case "by_layer":
|
|
var searchPoolLayer = rootSearchObject
|
|
? rootSearchObject
|
|
.GetComponentsInChildren<Transform>(searchInactive)
|
|
.Select(t => t.gameObject)
|
|
: GetAllSceneObjects(searchInactive);
|
|
if (int.TryParse(searchTerm, out int layerIndex))
|
|
{
|
|
results.AddRange(searchPoolLayer.Where(go => go.layer == layerIndex));
|
|
}
|
|
else
|
|
{
|
|
int namedLayer = LayerMask.NameToLayer(searchTerm);
|
|
if (namedLayer != -1)
|
|
results.AddRange(searchPoolLayer.Where(go => go.layer == namedLayer));
|
|
}
|
|
break;
|
|
|
|
case "by_component":
|
|
Type componentType = FindType(searchTerm);
|
|
if (componentType != null)
|
|
{
|
|
IEnumerable<GameObject> searchPoolComp;
|
|
if (rootSearchObject)
|
|
{
|
|
searchPoolComp = rootSearchObject
|
|
.GetComponentsInChildren(componentType, searchInactive)
|
|
.Select(c => (c as Component).gameObject);
|
|
}
|
|
else
|
|
{
|
|
#if UNITY_2023_1_OR_NEWER
|
|
var inactive = searchInactive ? FindObjectsInactive.Include : FindObjectsInactive.Exclude;
|
|
searchPoolComp = UnityEngine.Object.FindObjectsByType(componentType, inactive, FindObjectsSortMode.None)
|
|
.Cast<Component>()
|
|
.Select(c => c.gameObject);
|
|
#else
|
|
searchPoolComp = UnityEngine.Object.FindObjectsOfType(componentType, searchInactive)
|
|
.Cast<Component>()
|
|
.Select(c => c.gameObject);
|
|
#endif
|
|
}
|
|
results.AddRange(searchPoolComp.Where(go => go != null));
|
|
}
|
|
else
|
|
{
|
|
McpLog.Warn($"[ManageGameObject.Find] Component type not found: {searchTerm}");
|
|
}
|
|
break;
|
|
|
|
case "by_id_or_name_or_path":
|
|
if (int.TryParse(searchTerm, out int id))
|
|
{
|
|
var allObjectsId = GetAllSceneObjects(true);
|
|
GameObject objById = allObjectsId.FirstOrDefault(go => go.GetInstanceID() == id);
|
|
if (objById != null)
|
|
{
|
|
results.Add(objById);
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Try path search - in Prefab Stage, GameObject.Find() doesn't work
|
|
var allObjectsForPath = GetAllSceneObjects(true);
|
|
GameObject objByPath = allObjectsForPath.FirstOrDefault(go =>
|
|
{
|
|
return GameObjectLookup.MatchesPath(go, searchTerm);
|
|
});
|
|
if (objByPath != null)
|
|
{
|
|
results.Add(objByPath);
|
|
break;
|
|
}
|
|
|
|
var allObjectsName = GetAllSceneObjects(true);
|
|
results.AddRange(allObjectsName.Where(go => go.name == searchTerm));
|
|
break;
|
|
|
|
default:
|
|
McpLog.Warn($"[ManageGameObject.Find] Unknown search method: {searchMethod}");
|
|
break;
|
|
}
|
|
|
|
if (!findAll && results.Count > 1)
|
|
{
|
|
return new List<GameObject> { results[0] };
|
|
}
|
|
|
|
return results.Distinct().ToList();
|
|
}
|
|
|
|
private static IEnumerable<GameObject> GetAllSceneObjects(bool includeInactive)
|
|
{
|
|
// Delegate to GameObjectLookup to avoid code duplication and ensure consistent behavior
|
|
return GameObjectLookup.GetAllSceneObjects(includeInactive);
|
|
}
|
|
|
|
private static Type FindType(string typeName)
|
|
{
|
|
if (ComponentResolver.TryResolve(typeName, out Type resolvedType, out string error))
|
|
{
|
|
return resolvedType;
|
|
}
|
|
|
|
if (!string.IsNullOrEmpty(error))
|
|
{
|
|
McpLog.Warn($"[FindType] {error}");
|
|
}
|
|
|
|
return null;
|
|
}
|
|
}
|
|
}
|