Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 28 additions & 19 deletions MCPForUnity/Runtime/Helpers/UnityObjectIdCompat.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
using UnityEngine;
#if UNITY_EDITOR
using System.Reflection;
using UnityEditor;
#endif
#if UNITY_6000_6_OR_NEWER
using System.Collections.Generic;
#endif

namespace MCPForUnity.Runtime.Helpers
{
Expand All @@ -16,6 +18,18 @@ namespace MCPForUnity.Runtime.Helpers
/// </summary>
public static class UnityObjectIdCompat
{
#if UNITY_6000_6_OR_NEWER
// 6000.6 stubs out both EditorUtility.InstanceIDToObject(int) and EntityId's
// implicit int->EntityId conversion (both throw NotImplementedException at
// runtime despite existing in the API surface - verified against 6000.6.0f1).
// The only working reverse path is EntityIdToObject(EntityId) fed a value built
// via EntityId.FromULong(ulong), which needs the full 64-bit id, not the
// truncated int this class hands out. So we cache the full value behind the
// truncated int at mint time and look it up here instead of trying to
// reconstruct it from the int alone.
private static readonly Dictionary<int, ulong> _fullIdCache = new Dictionary<int, ulong>();
#endif

/// <summary>
/// Returns a session-scoped int handle for the object. On 6.5+ truncates the
/// EntityId's underlying ulong; lossy but stable within a session and preserves
Expand All @@ -30,40 +44,35 @@ public static int GetInstanceIDCompat(this Object obj)
}

#if UNITY_6000_5_OR_NEWER
return (int)EntityId.ToULong(obj.GetEntityId());
ulong full = EntityId.ToULong(obj.GetEntityId());
int truncated = (int)full;
#if UNITY_6000_6_OR_NEWER
_fullIdCache[truncated] = full;
#endif
return truncated;
#else
return obj.GetInstanceID();
#endif
}

#if UNITY_EDITOR
#if UNITY_6000_6_OR_NEWER
private static MethodInfo _instanceIdToObject;
private static bool _instanceIdToObjectInitialized;
#endif

/// <summary>
/// Resolves an int instance ID handle back to a UnityEngine.Object.
/// Pre-6.0 : EditorUtility.InstanceIDToObject(int)
/// 6.0–6.5 : EditorUtility.EntityIdToObject(int) (implicit int→EntityId cast)
/// 6.6+ : reflection on InstanceIDToObject(int) — the API still exists at runtime
/// but is obsolete-as-error; reflection bypasses CS0619 until the public
/// EntityId(int) ctor stabilizes.
/// 6.6+ : EditorUtility.EntityIdToObject(EntityId.FromULong(full)) using the
/// full 64-bit value cached in GetInstanceIDCompat, since the int-only
/// paths (including the implicit int→EntityId cast) are unimplemented
/// stubs on this Unity version. Only resolves ids minted this session.
/// </summary>
public static Object InstanceIDToObjectCompat(int instanceId)
{
#if UNITY_6000_6_OR_NEWER
if (!_instanceIdToObjectInitialized)
if (_fullIdCache.TryGetValue(instanceId, out ulong full))
{
_instanceIdToObject = typeof(EditorUtility).GetMethod(
"InstanceIDToObject",
BindingFlags.Public | BindingFlags.Static,
null,
new[] { typeof(int) },
null);
_instanceIdToObjectInitialized = true;
return EditorUtility.EntityIdToObject(EntityId.FromULong(full));
}
return _instanceIdToObject?.Invoke(null, new object[] { instanceId }) as Object;
return null;
#elif UNITY_6000_3_OR_NEWER
return EditorUtility.EntityIdToObject(instanceId);
#else
Expand Down