Skip to content

Commit

Permalink
Add CastToEnumerable extension; Fix Buttons breaking UI in IL2CPP
Browse files Browse the repository at this point in the history
  • Loading branch information
ManlyMarco committed Sep 26, 2024
1 parent b32b137 commit 5662fd1
Show file tree
Hide file tree
Showing 4 changed files with 69 additions and 14 deletions.
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using System.Collections;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
#if IL2CPP
Expand Down
42 changes: 42 additions & 0 deletions RuntimeUnityEditor.Core/Utils/Extensions.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
Expand Down Expand Up @@ -223,5 +224,46 @@ public static void SetActiveWithSceneChangeWarning(this GameObject o, bool value
if (sceneBak != o.scene)
RuntimeUnityEditorCore.Logger.Log(LogLevel.Warning | LogLevel.Message, $"Scene of GameObject [{o.name}] changed from [{sceneBak.name ?? "NULL"}] to [{o.scene.name ?? "NULL"}]");
}

/// <summary>
/// Turn anything with a GetEnumerator method to an IEnumerable with a casted type.
/// Will throw on failure at start, or throw during enumeration if casting fails.
/// </summary>
public static IEnumerable<T> CastToEnumerable<T>(this object obj)
{
if (obj is IEnumerable<T> ie)
return ie;

return CastToEnumerable(obj).Cast<T>();
}

/// <summary>
/// Turn anything with a GetEnumerator method to an IEnumerable.
/// Will throw on failure at start.
/// </summary>
public static IEnumerable CastToEnumerable(this object obj)
{
if (obj is IEnumerable ie2)
return ie2;

return DynamicAsEnumerable(obj);

IEnumerable DynamicAsEnumerable(object targetObj)
{
// Enumerate through reflection since mono version doesn't have dynamic keyword
// In IL2CPP using foreach with dynamic targetObj throws cast exceptions because of IL2CPP types
var mGetEnumerator = targetObj.GetType().GetMethod("GetEnumerator");
if (mGetEnumerator == null) throw new ArgumentNullException(nameof(mGetEnumerator));
var enumerator = mGetEnumerator.Invoke(targetObj, null);
if (enumerator == null) throw new ArgumentNullException(nameof(enumerator));
var enumeratorType = enumerator.GetType();
var mMoveNext = enumeratorType.GetMethod("MoveNext");
if (mMoveNext == null) throw new ArgumentNullException(nameof(mMoveNext));
var mCurrent = enumeratorType.GetProperty("Current");
if (mCurrent == null) throw new ArgumentNullException(nameof(mCurrent));
while ((bool)mMoveNext.Invoke(enumerator, null))
yield return mCurrent.GetValue(enumerator, null);
}
}
}
}
16 changes: 12 additions & 4 deletions RuntimeUnityEditor.Core/Utils/ReflectionUtils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using System.Text;
using HarmonyLib;
using RuntimeUnityEditor.Core.Clipboard;
using RuntimeUnityEditor.Core.Utils.Abstractions;
using UnityEngine.Events;

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

var calls = (IList)eventObj.GetPrivateExplicit("m_Calls").GetPrivate("m_RuntimeCalls");
foreach (var call in calls)
try
{
if (call.GetPrivate("Delegate") is Delegate d)
mList.Add(new KeyValuePair<object, MethodInfo>(d.Target, d.Method));
var calls = eventObj.GetPrivateExplicit("m_Calls").GetPrivate("m_RuntimeCalls").CastToEnumerable();
foreach (var call in calls)
{
if (call.GetPrivate("Delegate") is Delegate d)
mList.Add(new KeyValuePair<object, MethodInfo>(d.Target, d.Method));
}
}
catch (Exception e)
{
RuntimeUnityEditorCore.Logger.Log(LogLevel.Error, e);
}

var sb = new StringBuilder();
Expand Down
21 changes: 12 additions & 9 deletions RuntimeUnityEditor.Core/Windows/ObjectTree/ObjectTreeViewer.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
Expand Down Expand Up @@ -489,13 +488,15 @@ private void DrawSingleComponent(Component component)

try
{
var calls = (IList)eventObj.GetPrivateExplicit<UnityEventBase>("m_Calls").GetPrivate("m_RuntimeCalls");
var calls = eventObj.GetPrivateExplicit<UnityEventBase>("m_Calls").GetPrivate("m_RuntimeCalls").CastToEnumerable();
foreach (var call in calls)
GUILayout.Label(ToStringConverter.ObjectToString(call.GetPrivate("Delegate")));
}
catch (NullReferenceException)
{
}
catch (NullReferenceException) { }
#if IL2CPP
catch (HarmonyLib.MemberNotFoundException) { /* IL2CPP stripped it probably */ }
#endif
catch (Exception e) { RuntimeUnityEditorCore.Logger.Log(LogLevel.Error, e); }

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

try
{
var calls = (IList)b.onValueChanged.GetPrivateExplicit<UnityEventBase>("m_Calls").GetPrivate("m_RuntimeCalls");
var calls = b.onValueChanged.GetPrivateExplicit<UnityEventBase>("m_Calls").GetPrivate("m_RuntimeCalls").CastToEnumerable();
foreach (var call in calls)
GUILayout.Label(ToStringConverter.ObjectToString(call.GetPrivate("Delegate")));
}
catch (NullReferenceException)
{
}
catch (NullReferenceException) { }
#if IL2CPP
catch (HarmonyLib.MemberNotFoundException) { /* IL2CPP stripped it probably */ }
#endif
catch (Exception e) { RuntimeUnityEditorCore.Logger.Log(LogLevel.Error, e); }

GUILayout.FlexibleSpace();
if (GUILayout.Button("?"))
Expand Down

0 comments on commit 5662fd1

Please sign in to comment.