using System;
using System.Reflection;
using UObject = UnityEngine.Object;
namespace MCPForUnity.Runtime.Helpers
{
// Part of MCP for Unity's compat-shim family. See UnityCompatShims.cs in this
// folder for the full list of shims, the audit policy, and the reflection pattern.
///
/// Version-compatible wrappers for the Object.FindObjectsOfType / FindObjectsByType family.
///
/// API timeline:
/// Pre-2022.3 : FindObjectsOfType / FindObjectOfType
/// 2022.3-6.4 : FindObjectsByType(sortMode) / FindAnyObjectByType
/// 6.5+ : FindObjectsByType() (no sort param) / FindAnyObjectByType
///
/// Notes:
/// - Some Unity 2022.2.x editor versions did not reliably expose FindObjectsByType,
/// so the new APIs are gated at 2022.3+ rather than 2022.2+ (issue with 2022.2.1f1).
/// - On the legacy branch we dispatch to FindObjectsOfType / FindObjectOfType through
/// reflection rather than direct calls. This keeps the file CS0618-clean across all
/// SDKs we compile against and lets the package keep working if Unity ever fully
/// removes the legacy methods (CS0619).
///
public static class UnityFindObjectsCompat
{
/// Find all active objects of type T.
public static T[] FindAll() where T : UObject
{
#if UNITY_6000_5_OR_NEWER
return UObject.FindObjectsByType();
#elif UNITY_2022_3_OR_NEWER
return UObject.FindObjectsByType(UnityEngine.FindObjectsSortMode.None);
#else
var arr = LegacyFindObjectsOfType(typeof(T));
if (arr == null) return Array.Empty();
var typed = new T[arr.Length];
for (int i = 0; i < arr.Length; i++) typed[i] = (T)arr[i];
return typed;
#endif
}
/// Find all active objects of the given runtime type.
public static UObject[] FindAll(Type type)
{
#if UNITY_6000_5_OR_NEWER
return UObject.FindObjectsByType(type, UnityEngine.FindObjectsInactive.Exclude);
#elif UNITY_2022_3_OR_NEWER
return UObject.FindObjectsByType(type, UnityEngine.FindObjectsSortMode.None);
#else
return LegacyFindObjectsOfType(type) ?? Array.Empty();
#endif
}
/// Find all objects of the given runtime type, optionally including inactive.
public static UObject[] FindAll(Type type, bool includeInactive)
{
#if UNITY_6000_5_OR_NEWER
return UObject.FindObjectsByType(type,
includeInactive ? UnityEngine.FindObjectsInactive.Include : UnityEngine.FindObjectsInactive.Exclude);
#elif UNITY_2022_3_OR_NEWER
return UObject.FindObjectsByType(type,
includeInactive ? UnityEngine.FindObjectsInactive.Include : UnityEngine.FindObjectsInactive.Exclude,
UnityEngine.FindObjectsSortMode.None);
#else
return LegacyFindObjectsOfType(type, includeInactive) ?? Array.Empty();
#endif
}
/// Find any single object of the given runtime type (no ordering guarantee).
public static UObject FindAny(Type type)
{
#if UNITY_2022_3_OR_NEWER
return UObject.FindAnyObjectByType(type);
#else
return LegacyFindObjectOfType(type);
#endif
}
#if !UNITY_2022_3_OR_NEWER
// ---------- legacy reflection helpers (pre-2022.3 only) ----------
private static MethodInfo _findObjectsOfTypeByType;
private static bool _findObjectsOfTypeByTypeProbed;
private static MethodInfo _findObjectsOfTypeWithInactive;
private static bool _findObjectsOfTypeWithInactiveProbed;
private static MethodInfo _findObjectOfTypeByType;
private static bool _findObjectOfTypeByTypeProbed;
private static UObject[] LegacyFindObjectsOfType(Type type)
{
if (!_findObjectsOfTypeByTypeProbed)
{
_findObjectsOfTypeByTypeProbed = true;
_findObjectsOfTypeByType = typeof(UObject).GetMethod(
"FindObjectsOfType",
BindingFlags.Public | BindingFlags.Static,
null,
new[] { typeof(Type) },
null);
}
if (_findObjectsOfTypeByType == null) return null;
try { return (UObject[])_findObjectsOfTypeByType.Invoke(null, new object[] { type }); }
catch { return null; }
}
private static UObject[] LegacyFindObjectsOfType(Type type, bool includeInactive)
{
if (!_findObjectsOfTypeWithInactiveProbed)
{
_findObjectsOfTypeWithInactiveProbed = true;
_findObjectsOfTypeWithInactive = typeof(UObject).GetMethod(
"FindObjectsOfType",
BindingFlags.Public | BindingFlags.Static,
null,
new[] { typeof(Type), typeof(bool) },
null);
}
if (_findObjectsOfTypeWithInactive == null)
{
// Older Unity versions only had the (Type) overload — fall back without the flag.
return LegacyFindObjectsOfType(type);
}
try { return (UObject[])_findObjectsOfTypeWithInactive.Invoke(null, new object[] { type, includeInactive }); }
catch { return null; }
}
private static UObject LegacyFindObjectOfType(Type type)
{
if (!_findObjectOfTypeByTypeProbed)
{
_findObjectOfTypeByTypeProbed = true;
_findObjectOfTypeByType = typeof(UObject).GetMethod(
"FindObjectOfType",
BindingFlags.Public | BindingFlags.Static,
null,
new[] { typeof(Type) },
null);
}
if (_findObjectOfTypeByType == null) return null;
try { return (UObject)_findObjectOfTypeByType.Invoke(null, new object[] { type }); }
catch { return null; }
}
#endif
}
}