Skip to content

Commit 5662fd1

Browse files
committed
Add CastToEnumerable extension; Fix Buttons breaking UI in IL2CPP
1 parent b32b137 commit 5662fd1

File tree

4 files changed

+69
-14
lines changed

4 files changed

+69
-14
lines changed

RuntimeUnityEditor.Core/Utils/Abstractions/IL2CppAbstractions.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
using System.Collections;
1+
using System;
2+
using System.Collections;
3+
using System.Collections.Generic;
24
using System.Linq;
35
using UnityEngine;
46
#if IL2CPP

RuntimeUnityEditor.Core/Utils/Extensions.cs

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System;
2+
using System.Collections;
23
using System.Collections.Generic;
34
using System.Linq;
45
using System.Reflection;
@@ -223,5 +224,46 @@ public static void SetActiveWithSceneChangeWarning(this GameObject o, bool value
223224
if (sceneBak != o.scene)
224225
RuntimeUnityEditorCore.Logger.Log(LogLevel.Warning | LogLevel.Message, $"Scene of GameObject [{o.name}] changed from [{sceneBak.name ?? "NULL"}] to [{o.scene.name ?? "NULL"}]");
225226
}
227+
228+
/// <summary>
229+
/// Turn anything with a GetEnumerator method to an IEnumerable with a casted type.
230+
/// Will throw on failure at start, or throw during enumeration if casting fails.
231+
/// </summary>
232+
public static IEnumerable<T> CastToEnumerable<T>(this object obj)
233+
{
234+
if (obj is IEnumerable<T> ie)
235+
return ie;
236+
237+
return CastToEnumerable(obj).Cast<T>();
238+
}
239+
240+
/// <summary>
241+
/// Turn anything with a GetEnumerator method to an IEnumerable.
242+
/// Will throw on failure at start.
243+
/// </summary>
244+
public static IEnumerable CastToEnumerable(this object obj)
245+
{
246+
if (obj is IEnumerable ie2)
247+
return ie2;
248+
249+
return DynamicAsEnumerable(obj);
250+
251+
IEnumerable DynamicAsEnumerable(object targetObj)
252+
{
253+
// Enumerate through reflection since mono version doesn't have dynamic keyword
254+
// In IL2CPP using foreach with dynamic targetObj throws cast exceptions because of IL2CPP types
255+
var mGetEnumerator = targetObj.GetType().GetMethod("GetEnumerator");
256+
if (mGetEnumerator == null) throw new ArgumentNullException(nameof(mGetEnumerator));
257+
var enumerator = mGetEnumerator.Invoke(targetObj, null);
258+
if (enumerator == null) throw new ArgumentNullException(nameof(enumerator));
259+
var enumeratorType = enumerator.GetType();
260+
var mMoveNext = enumeratorType.GetMethod("MoveNext");
261+
if (mMoveNext == null) throw new ArgumentNullException(nameof(mMoveNext));
262+
var mCurrent = enumeratorType.GetProperty("Current");
263+
if (mCurrent == null) throw new ArgumentNullException(nameof(mCurrent));
264+
while ((bool)mMoveNext.Invoke(enumerator, null))
265+
yield return mCurrent.GetValue(enumerator, null);
266+
}
267+
}
226268
}
227269
}

RuntimeUnityEditor.Core/Utils/ReflectionUtils.cs

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
using System.Text;
77
using HarmonyLib;
88
using RuntimeUnityEditor.Core.Clipboard;
9+
using RuntimeUnityEditor.Core.Utils.Abstractions;
910
using UnityEngine.Events;
1011

1112
namespace RuntimeUnityEditor.Core.Utils
@@ -52,11 +53,18 @@ public static string GetEventDetails(UnityEventBase eventObj)
5253
if (m != null) mList.Add(new KeyValuePair<object, MethodInfo>(target, m));
5354
}
5455

55-
var calls = (IList)eventObj.GetPrivateExplicit("m_Calls").GetPrivate("m_RuntimeCalls");
56-
foreach (var call in calls)
56+
try
5757
{
58-
if (call.GetPrivate("Delegate") is Delegate d)
59-
mList.Add(new KeyValuePair<object, MethodInfo>(d.Target, d.Method));
58+
var calls = eventObj.GetPrivateExplicit("m_Calls").GetPrivate("m_RuntimeCalls").CastToEnumerable();
59+
foreach (var call in calls)
60+
{
61+
if (call.GetPrivate("Delegate") is Delegate d)
62+
mList.Add(new KeyValuePair<object, MethodInfo>(d.Target, d.Method));
63+
}
64+
}
65+
catch (Exception e)
66+
{
67+
RuntimeUnityEditorCore.Logger.Log(LogLevel.Error, e);
6068
}
6169

6270
var sb = new StringBuilder();

RuntimeUnityEditor.Core/Windows/ObjectTree/ObjectTreeViewer.cs

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
using System;
2-
using System.Collections;
32
using System.Collections.Generic;
43
using System.Globalization;
54
using System.Linq;
@@ -489,13 +488,15 @@ private void DrawSingleComponent(Component component)
489488

490489
try
491490
{
492-
var calls = (IList)eventObj.GetPrivateExplicit<UnityEventBase>("m_Calls").GetPrivate("m_RuntimeCalls");
491+
var calls = eventObj.GetPrivateExplicit<UnityEventBase>("m_Calls").GetPrivate("m_RuntimeCalls").CastToEnumerable();
493492
foreach (var call in calls)
494493
GUILayout.Label(ToStringConverter.ObjectToString(call.GetPrivate("Delegate")));
495494
}
496-
catch (NullReferenceException)
497-
{
498-
}
495+
catch (NullReferenceException) { }
496+
#if IL2CPP
497+
catch (HarmonyLib.MemberNotFoundException) { /* IL2CPP stripped it probably */ }
498+
#endif
499+
catch (Exception e) { RuntimeUnityEditorCore.Logger.Log(LogLevel.Error, e); }
499500

500501
GUILayout.FlexibleSpace();
501502
if (GUILayout.Button("?"))
@@ -510,13 +511,15 @@ private void DrawSingleComponent(Component component)
510511

511512
try
512513
{
513-
var calls = (IList)b.onValueChanged.GetPrivateExplicit<UnityEventBase>("m_Calls").GetPrivate("m_RuntimeCalls");
514+
var calls = b.onValueChanged.GetPrivateExplicit<UnityEventBase>("m_Calls").GetPrivate("m_RuntimeCalls").CastToEnumerable();
514515
foreach (var call in calls)
515516
GUILayout.Label(ToStringConverter.ObjectToString(call.GetPrivate("Delegate")));
516517
}
517-
catch (NullReferenceException)
518-
{
519-
}
518+
catch (NullReferenceException) { }
519+
#if IL2CPP
520+
catch (HarmonyLib.MemberNotFoundException) { /* IL2CPP stripped it probably */ }
521+
#endif
522+
catch (Exception e) { RuntimeUnityEditorCore.Logger.Log(LogLevel.Error, e); }
520523

521524
GUILayout.FlexibleSpace();
522525
if (GUILayout.Button("?"))

0 commit comments

Comments
 (0)