mirror of
https://github.com/BepInEx/BepInEx.git
synced 2026-10-19 15:51:45 +00:00
89 lines
3.3 KiB
C#
89 lines
3.3 KiB
C#
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using System.Reflection.Emit;
|
|
using HarmonyLib;
|
|
using Il2CppInterop.Runtime;
|
|
using Il2CppInterop.Runtime.Injection;
|
|
using Il2CppSystem;
|
|
using ArgumentNullException = System.ArgumentNullException;
|
|
using Il2CppIEnumerator = Il2CppSystem.Collections.IEnumerator;
|
|
using IntPtr = System.IntPtr;
|
|
using NotSupportedException = System.NotSupportedException;
|
|
using Type = System.Type;
|
|
|
|
namespace BepInEx.Unity.IL2CPP.Utils.Collections;
|
|
|
|
public class Il2CppManagedEnumerator : Object
|
|
{
|
|
private static readonly Dictionary<Type, System.Func<object, Object>> boxers = new();
|
|
|
|
private readonly IEnumerator enumerator;
|
|
|
|
static Il2CppManagedEnumerator()
|
|
{
|
|
ClassInjector.RegisterTypeInIl2Cpp<Il2CppManagedEnumerator>(new RegisterTypeOptions
|
|
{
|
|
Interfaces = new[] { typeof(Il2CppIEnumerator) }
|
|
});
|
|
}
|
|
|
|
public Il2CppManagedEnumerator(IntPtr ptr) : base(ptr) { }
|
|
|
|
public Il2CppManagedEnumerator(IEnumerator enumerator)
|
|
: base(ClassInjector.DerivedConstructorPointer<Il2CppManagedEnumerator>())
|
|
{
|
|
this.enumerator = enumerator ?? throw new ArgumentNullException(nameof(enumerator));
|
|
ClassInjector.DerivedConstructorBody(this);
|
|
}
|
|
|
|
public Object Current => enumerator.Current switch
|
|
{
|
|
Il2CppIEnumerator i => i.Cast<Object>(),
|
|
IEnumerator e => new Il2CppManagedEnumerator(e),
|
|
Object oo => oo,
|
|
{ } obj => ManagedToIl2CppObject(obj),
|
|
null => null
|
|
};
|
|
|
|
public bool MoveNext() => enumerator.MoveNext();
|
|
|
|
public void Reset() => enumerator.Reset();
|
|
|
|
private static System.Func<object, Object> GetValueBoxer(Type t)
|
|
{
|
|
if (boxers.TryGetValue(t, out var conv))
|
|
return conv;
|
|
|
|
var dm = new DynamicMethod($"Il2CppUnbox_{t.FullDescription()}", typeof(Object),
|
|
new[] { typeof(object) });
|
|
var il = dm.GetILGenerator();
|
|
var loc = il.DeclareLocal(t);
|
|
var classField = typeof(Il2CppClassPointerStore<>).MakeGenericType(t)
|
|
.GetField(nameof(Il2CppClassPointerStore<int>
|
|
.NativeClassPtr));
|
|
il.Emit(OpCodes.Ldsfld, classField);
|
|
il.Emit(OpCodes.Ldarg_0);
|
|
il.Emit(OpCodes.Unbox_Any, t);
|
|
il.Emit(OpCodes.Stloc, loc);
|
|
il.Emit(OpCodes.Ldloca, loc);
|
|
il.Emit(OpCodes.Call,
|
|
typeof(Il2CppInterop.Runtime.IL2CPP).GetMethod(nameof(Il2CppInterop.Runtime.IL2CPP.il2cpp_value_box)));
|
|
il.Emit(OpCodes.Newobj, typeof(Object).GetConstructor(new[] { typeof(IntPtr) }));
|
|
il.Emit(OpCodes.Ret);
|
|
|
|
var converter = dm.CreateDelegate(typeof(System.Func<object, Object>)) as System.Func<object, Object>;
|
|
boxers[t] = converter;
|
|
return converter;
|
|
}
|
|
|
|
private static Object ManagedToIl2CppObject(object obj)
|
|
{
|
|
var t = obj.GetType();
|
|
if (obj is string s)
|
|
return new Object(Il2CppInterop.Runtime.IL2CPP.ManagedStringToIl2Cpp(s));
|
|
if (t.IsPrimitive)
|
|
return GetValueBoxer(t)(obj);
|
|
throw new NotSupportedException($"Type {t} cannot be converted directly to an Il2Cpp object");
|
|
}
|
|
}
|