using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Threading;
using FieldInjector;
using FieldInjector.FieldSerialisers;
using HarmonyLib;
using Iced.Intel;
using Il2CppInterop.Runtime;
using Il2CppInterop.Runtime.Injection;
using Il2CppInterop.Runtime.InteropTypes;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppInterop.Runtime.Runtime;
using Il2CppInterop.Runtime.Runtime.VersionSpecific.Assembly;
using Il2CppInterop.Runtime.Runtime.VersionSpecific.Class;
using Il2CppInterop.Runtime.Runtime.VersionSpecific.FieldInfo;
using Il2CppInterop.Runtime.Runtime.VersionSpecific.Image;
using Il2CppInterop.Runtime.Runtime.VersionSpecific.MethodInfo;
using Il2CppInterop.Runtime.Runtime.VersionSpecific.Type;
using Il2CppSystem;
using MelonLoader;
using MelonLoader.NativeUtils;
using Microsoft.CodeAnalysis;
using UnityEngine;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: ComVisible(false)]
[assembly: Guid("82c7a0e0-36ec-4675-bb8c-ededa0f92dfa")]
[assembly: MelonInfo(typeof(Mod), "FieldInjector", "2.1.0", "WNP78", null)]
[assembly: MelonPriority(-100)]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("FieldInjector")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+68ed5a077bc64bc99644e89a02dbea7b94a9182e")]
[assembly: AssemblyProduct("FieldInjector")]
[assembly: AssemblyTitle("FieldInjector")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
namespace Microsoft.CodeAnalysis
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
internal sealed class EmbeddedAttribute : Attribute
{
}
}
namespace System.Runtime.CompilerServices
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
internal sealed class NullableAttribute : Attribute
{
public readonly byte[] NullableFlags;
public NullableAttribute(byte P_0)
{
NullableFlags = new byte[1] { P_0 };
}
public NullableAttribute(byte[] P_0)
{
NullableFlags = P_0;
}
}
[AttributeUsage(AttributeTargets.All, Inherited = false, AllowMultiple = true)]
internal sealed class IsUnmanagedAttribute : Attribute
{
}
}
namespace FieldInjector
{
internal struct DynamicArrayOfPtrs
{
public unsafe void** m_ptr;
public int memLabelId;
public ulong size;
public ulong capacity;
public ulong Capacity
{
get
{
return capacity >> 1;
}
set
{
capacity = (value << 1) | (capacity & 1);
}
}
public unsafe void InsertReplaceNull(IntPtr value)
{
for (ulong num = 0uL; num < size; num++)
{
if (m_ptr[num] == null)
{
m_ptr[num] = (void*)value;
return;
}
}
MelonLogger.Error($"ERROR: scanned {size} images and no null pointer found, cannot insert ours! Struct injection will probably not work. Go tell WNP78 on discord and let someone know that he was wrong");
}
}
internal struct MyIl2CppFieldInfo
{
public IntPtr name;
public unsafe Il2CppTypeStruct* type;
public unsafe Il2CppClass* parent;
public int offset;
public uint token;
}
internal struct MyIl2CppClass
{
[Flags]
public enum ClassFlags : ushort
{
None = 0,
initialized_and_no_error = 1,
initialized = 2,
enumtype = 4,
nullabletype = 8,
is_generic = 0x10,
has_references = 0x20,
init_pending = 0x40,
size_init_pending = 0x80,
size_inited = 0x100,
has_finalize = 0x200,
has_cctor = 0x400,
is_blittable = 0x800,
is_import_or_windows_runtime = 0x1000,
is_vtable_initialized = 0x2000,
is_byref_like = 0x4000
}
public unsafe Il2CppImage* image;
public IntPtr gc_desc;
public IntPtr name;
public IntPtr namespaze;
public MyIl2CppType byval_arg;
public MyIl2CppType this_arg;
public unsafe Il2CppClass* element_class;
public unsafe Il2CppClass* castClass;
public unsafe Il2CppClass* declaringType;
public unsafe Il2CppClass* parent;
public IntPtr generic_class;
public IntPtr typeDefinition;
public IntPtr interopData;
public unsafe Il2CppClass* klass;
public unsafe MyIl2CppFieldInfo* fields;
public unsafe Il2CppEventInfo* events;
public unsafe Il2CppPropertyInfo* properties;
public unsafe Il2CppMethodInfo** methods;
public unsafe Il2CppClass** nestedTypes;
public unsafe Il2CppClass** implementedInterfaces;
public unsafe Il2CppRuntimeInterfaceOffsetPair* interfaceOffsets;
public IntPtr static_fields;
public IntPtr rgctx_data;
public unsafe Il2CppClass** typeHierarchy;
public IntPtr unity_user_data;
public uint initializationExceptionGCHandle;
public uint cctor_started;
public uint cctor_finished;
private ulong cctor_thread;
public IntPtr genericContainerIndex;
public uint instance_size;
public uint actualSize;
public uint element_size;
public int native_size;
public uint static_fields_size;
public uint thread_static_fields_size;
public int thread_static_fields_offset;
public Il2CppClassAttributes flags;
public uint token;
public ushort method_count;
public ushort property_count;
public ushort field_count;
public ushort event_count;
public ushort nested_type_count;
public ushort vtable_count;
public ushort interfaces_count;
public ushort interface_offsets_count;
public byte typeHierarchyDepth;
public byte genericRecursionDepth;
public byte rank;
public byte minimumAlignment;
public byte naturalAligment;
public byte packingSize;
public ClassFlags bitfield;
public unsafe static string ToStringClass(IntPtr ptr)
{
if (ptr == IntPtr.Zero)
{
return "Il2CppClass:nullptr";
}
try
{
return $"Il2CppClass:{Marshal.PtrToStringAnsi(((MyIl2CppClass*)(void*)ptr)->name)} ({ptr})";
}
catch
{
return $"Il2CppClass:invalid ({ptr})";
}
}
private unsafe static void PrintFields(StringBuilder s, MyIl2CppFieldInfo* ptr, int count)
{
for (int i = 0; i < count; i++)
{
MyIl2CppFieldInfo* ptr2 = ptr + i;
s.Append(" field:\n");
StringBuilder stringBuilder = s;
StringBuilder stringBuilder2 = stringBuilder;
StringBuilder.AppendInterpolatedStringHandler handler = new StringBuilder.AppendInterpolatedStringHandler(12, 1, stringBuilder);
handler.AppendLiteral(" name = ");
handler.AppendFormatted(Marshal.PtrToStringAnsi(ptr2->name));
handler.AppendLiteral("\n");
stringBuilder2.Append(ref handler);
stringBuilder = s;
StringBuilder stringBuilder3 = stringBuilder;
handler = new StringBuilder.AppendInterpolatedStringHandler(12, 1, stringBuilder);
handler.AppendLiteral(" type = ");
handler.AppendFormatted(((MyIl2CppType*)ptr2->type)->ToString(" "));
handler.AppendLiteral("\n");
stringBuilder3.Append(ref handler);
stringBuilder = s;
StringBuilder stringBuilder4 = stringBuilder;
handler = new StringBuilder.AppendInterpolatedStringHandler(14, 1, stringBuilder);
handler.AppendLiteral(" parent = ");
handler.AppendFormatted(ToStringClass((IntPtr)ptr2->parent));
handler.AppendLiteral("\n");
stringBuilder4.Append(ref handler);
stringBuilder = s;
StringBuilder stringBuilder5 = stringBuilder;
handler = new StringBuilder.AppendInterpolatedStringHandler(14, 1, stringBuilder);
handler.AppendLiteral(" offset = ");
handler.AppendFormatted(ptr2->offset);
handler.AppendLiteral("\n");
stringBuilder5.Append(ref handler);
stringBuilder = s;
StringBuilder stringBuilder6 = stringBuilder;
handler = new StringBuilder.AppendInterpolatedStringHandler(13, 1, stringBuilder);
handler.AppendLiteral(" token = ");
handler.AppendFormatted(ptr2->token);
handler.AppendLiteral("\n");
stringBuilder6.Append(ref handler);
}
}
public unsafe string Debug()
{
//IL_08c9: Unknown result type (might be due to invalid IL or missing references)
StringBuilder stringBuilder = new StringBuilder("Il2CppClass:\n");
StringBuilder stringBuilder2 = stringBuilder;
StringBuilder stringBuilder3 = stringBuilder2;
StringBuilder.AppendInterpolatedStringHandler handler = new StringBuilder.AppendInterpolatedStringHandler(9, 1, stringBuilder2);
handler.AppendLiteral("image = ");
handler.AppendFormatted((IntPtr)image);
handler.AppendLiteral("\n");
stringBuilder3.Append(ref handler);
stringBuilder2 = stringBuilder;
StringBuilder stringBuilder4 = stringBuilder2;
handler = new StringBuilder.AppendInterpolatedStringHandler(11, 1, stringBuilder2);
handler.AppendLiteral("gc_desc = ");
handler.AppendFormatted(gc_desc);
handler.AppendLiteral("\n");
stringBuilder4.Append(ref handler);
stringBuilder2 = stringBuilder;
StringBuilder stringBuilder5 = stringBuilder2;
handler = new StringBuilder.AppendInterpolatedStringHandler(8, 1, stringBuilder2);
handler.AppendLiteral("name = ");
handler.AppendFormatted(str(name));
handler.AppendLiteral("\n");
stringBuilder5.Append(ref handler);
stringBuilder2 = stringBuilder;
StringBuilder stringBuilder6 = stringBuilder2;
handler = new StringBuilder.AppendInterpolatedStringHandler(13, 1, stringBuilder2);
handler.AppendLiteral("namespaze = ");
handler.AppendFormatted(str(namespaze));
handler.AppendLiteral("\n");
stringBuilder6.Append(ref handler);
stringBuilder2 = stringBuilder;
StringBuilder stringBuilder7 = stringBuilder2;
handler = new StringBuilder.AppendInterpolatedStringHandler(13, 1, stringBuilder2);
handler.AppendLiteral("byval_arg = ");
handler.AppendFormatted(byval_arg.ToString());
handler.AppendLiteral("\n");
stringBuilder7.Append(ref handler);
stringBuilder2 = stringBuilder;
StringBuilder stringBuilder8 = stringBuilder2;
handler = new StringBuilder.AppendInterpolatedStringHandler(12, 1, stringBuilder2);
handler.AppendLiteral("this_arg = ");
handler.AppendFormatted(this_arg.ToString());
handler.AppendLiteral("\n");
stringBuilder8.Append(ref handler);
stringBuilder2 = stringBuilder;
StringBuilder stringBuilder9 = stringBuilder2;
handler = new StringBuilder.AppendInterpolatedStringHandler(18, 1, stringBuilder2);
handler.AppendLiteral("element_class = ");
handler.AppendFormatted(ToStringClass((IntPtr)element_class));
handler.AppendLiteral(")\n");
stringBuilder9.Append(ref handler);
stringBuilder2 = stringBuilder;
StringBuilder stringBuilder10 = stringBuilder2;
handler = new StringBuilder.AppendInterpolatedStringHandler(13, 1, stringBuilder2);
handler.AppendLiteral("castClass = ");
handler.AppendFormatted(ToStringClass((IntPtr)castClass));
handler.AppendLiteral("\n");
stringBuilder10.Append(ref handler);
stringBuilder2 = stringBuilder;
StringBuilder stringBuilder11 = stringBuilder2;
handler = new StringBuilder.AppendInterpolatedStringHandler(17, 1, stringBuilder2);
handler.AppendLiteral("declaringType = ");
handler.AppendFormatted(ToStringClass((IntPtr)declaringType));
handler.AppendLiteral("\n");
stringBuilder11.Append(ref handler);
stringBuilder2 = stringBuilder;
StringBuilder stringBuilder12 = stringBuilder2;
handler = new StringBuilder.AppendInterpolatedStringHandler(10, 1, stringBuilder2);
handler.AppendLiteral("parent = ");
handler.AppendFormatted(ToStringClass((IntPtr)parent));
handler.AppendLiteral("\n");
stringBuilder12.Append(ref handler);
stringBuilder2 = stringBuilder;
StringBuilder stringBuilder13 = stringBuilder2;
handler = new StringBuilder.AppendInterpolatedStringHandler(17, 1, stringBuilder2);
handler.AppendLiteral("generic_class = ");
handler.AppendFormatted(generic_class);
handler.AppendLiteral("\n");
stringBuilder13.Append(ref handler);
stringBuilder2 = stringBuilder;
StringBuilder stringBuilder14 = stringBuilder2;
handler = new StringBuilder.AppendInterpolatedStringHandler(18, 1, stringBuilder2);
handler.AppendLiteral("typeDefinition = ");
handler.AppendFormatted(typeDefinition);
handler.AppendLiteral("\n");
stringBuilder14.Append(ref handler);
stringBuilder2 = stringBuilder;
StringBuilder stringBuilder15 = stringBuilder2;
handler = new StringBuilder.AppendInterpolatedStringHandler(15, 1, stringBuilder2);
handler.AppendLiteral("interopData = ");
handler.AppendFormatted(interopData);
handler.AppendLiteral("\n");
stringBuilder15.Append(ref handler);
stringBuilder2 = stringBuilder;
StringBuilder stringBuilder16 = stringBuilder2;
handler = new StringBuilder.AppendInterpolatedStringHandler(9, 1, stringBuilder2);
handler.AppendLiteral("klass = ");
handler.AppendFormatted((IntPtr)klass);
handler.AppendLiteral("\n");
stringBuilder16.Append(ref handler);
stringBuilder.Append("fields = \n");
PrintFields(stringBuilder, fields, field_count);
stringBuilder2 = stringBuilder;
StringBuilder stringBuilder17 = stringBuilder2;
handler = new StringBuilder.AppendInterpolatedStringHandler(10, 1, stringBuilder2);
handler.AppendLiteral("events = ");
handler.AppendFormatted((IntPtr)events);
handler.AppendLiteral("\n");
stringBuilder17.Append(ref handler);
stringBuilder2 = stringBuilder;
StringBuilder stringBuilder18 = stringBuilder2;
handler = new StringBuilder.AppendInterpolatedStringHandler(14, 1, stringBuilder2);
handler.AppendLiteral("properties = ");
handler.AppendFormatted((IntPtr)properties);
handler.AppendLiteral("\n");
stringBuilder18.Append(ref handler);
stringBuilder2 = stringBuilder;
StringBuilder stringBuilder19 = stringBuilder2;
handler = new StringBuilder.AppendInterpolatedStringHandler(11, 1, stringBuilder2);
handler.AppendLiteral("methods = ");
handler.AppendFormatted((IntPtr)methods);
handler.AppendLiteral("\n");
stringBuilder19.Append(ref handler);
stringBuilder2 = stringBuilder;
StringBuilder stringBuilder20 = stringBuilder2;
handler = new StringBuilder.AppendInterpolatedStringHandler(15, 1, stringBuilder2);
handler.AppendLiteral("nestedTypes = ");
handler.AppendFormatted((IntPtr)nestedTypes);
handler.AppendLiteral("\n");
stringBuilder20.Append(ref handler);
stringBuilder2 = stringBuilder;
StringBuilder stringBuilder21 = stringBuilder2;
handler = new StringBuilder.AppendInterpolatedStringHandler(25, 1, stringBuilder2);
handler.AppendLiteral("implementedInterfaces = ");
handler.AppendFormatted((IntPtr)implementedInterfaces);
handler.AppendLiteral("\n");
stringBuilder21.Append(ref handler);
stringBuilder2 = stringBuilder;
StringBuilder stringBuilder22 = stringBuilder2;
handler = new StringBuilder.AppendInterpolatedStringHandler(20, 1, stringBuilder2);
handler.AppendLiteral("interfaceOffsets = ");
handler.AppendFormatted((IntPtr)interfaceOffsets);
handler.AppendLiteral("\n");
stringBuilder22.Append(ref handler);
stringBuilder2 = stringBuilder;
StringBuilder stringBuilder23 = stringBuilder2;
handler = new StringBuilder.AppendInterpolatedStringHandler(17, 1, stringBuilder2);
handler.AppendLiteral("static_fields = ");
handler.AppendFormatted(static_fields);
handler.AppendLiteral("\n");
stringBuilder23.Append(ref handler);
stringBuilder2 = stringBuilder;
StringBuilder stringBuilder24 = stringBuilder2;
handler = new StringBuilder.AppendInterpolatedStringHandler(14, 1, stringBuilder2);
handler.AppendLiteral("rgctx_data = ");
handler.AppendFormatted(rgctx_data);
handler.AppendLiteral("\n");
stringBuilder24.Append(ref handler);
stringBuilder2 = stringBuilder;
StringBuilder stringBuilder25 = stringBuilder2;
handler = new StringBuilder.AppendInterpolatedStringHandler(17, 1, stringBuilder2);
handler.AppendLiteral("typeHierarchy = ");
handler.AppendFormatted((IntPtr)typeHierarchy);
handler.AppendLiteral("\n");
stringBuilder25.Append(ref handler);
stringBuilder2 = stringBuilder;
StringBuilder stringBuilder26 = stringBuilder2;
handler = new StringBuilder.AppendInterpolatedStringHandler(19, 1, stringBuilder2);
handler.AppendLiteral("unity_user_data = ");
handler.AppendFormatted(unity_user_data);
handler.AppendLiteral("\n");
stringBuilder26.Append(ref handler);
stringBuilder2 = stringBuilder;
StringBuilder stringBuilder27 = stringBuilder2;
handler = new StringBuilder.AppendInterpolatedStringHandler(35, 1, stringBuilder2);
handler.AppendLiteral("initializationExceptionGCHandle = ");
handler.AppendFormatted(initializationExceptionGCHandle);
handler.AppendLiteral("\n");
stringBuilder27.Append(ref handler);
stringBuilder2 = stringBuilder;
StringBuilder stringBuilder28 = stringBuilder2;
handler = new StringBuilder.AppendInterpolatedStringHandler(17, 1, stringBuilder2);
handler.AppendLiteral("cctor_started = ");
handler.AppendFormatted(cctor_started);
handler.AppendLiteral("\n");
stringBuilder28.Append(ref handler);
stringBuilder2 = stringBuilder;
StringBuilder stringBuilder29 = stringBuilder2;
handler = new StringBuilder.AppendInterpolatedStringHandler(18, 1, stringBuilder2);
handler.AppendLiteral("cctor_finished = ");
handler.AppendFormatted(cctor_finished);
handler.AppendLiteral("\n");
stringBuilder29.Append(ref handler);
stringBuilder2 = stringBuilder;
StringBuilder stringBuilder30 = stringBuilder2;
handler = new StringBuilder.AppendInterpolatedStringHandler(25, 1, stringBuilder2);
handler.AppendLiteral("genericContainerIndex = ");
handler.AppendFormatted(genericContainerIndex);
handler.AppendLiteral("\n");
stringBuilder30.Append(ref handler);
stringBuilder2 = stringBuilder;
StringBuilder stringBuilder31 = stringBuilder2;
handler = new StringBuilder.AppendInterpolatedStringHandler(17, 1, stringBuilder2);
handler.AppendLiteral("instance_size = ");
handler.AppendFormatted(instance_size);
handler.AppendLiteral("\n");
stringBuilder31.Append(ref handler);
stringBuilder2 = stringBuilder;
StringBuilder stringBuilder32 = stringBuilder2;
handler = new StringBuilder.AppendInterpolatedStringHandler(14, 1, stringBuilder2);
handler.AppendLiteral("actualSize = ");
handler.AppendFormatted(actualSize);
handler.AppendLiteral("\n");
stringBuilder32.Append(ref handler);
stringBuilder2 = stringBuilder;
StringBuilder stringBuilder33 = stringBuilder2;
handler = new StringBuilder.AppendInterpolatedStringHandler(16, 1, stringBuilder2);
handler.AppendLiteral("element_size = ");
handler.AppendFormatted(element_size);
handler.AppendLiteral("\n");
stringBuilder33.Append(ref handler);
stringBuilder2 = stringBuilder;
StringBuilder stringBuilder34 = stringBuilder2;
handler = new StringBuilder.AppendInterpolatedStringHandler(15, 1, stringBuilder2);
handler.AppendLiteral("native_size = ");
handler.AppendFormatted(native_size);
handler.AppendLiteral("\n");
stringBuilder34.Append(ref handler);
stringBuilder2 = stringBuilder;
StringBuilder stringBuilder35 = stringBuilder2;
handler = new StringBuilder.AppendInterpolatedStringHandler(22, 1, stringBuilder2);
handler.AppendLiteral("static_fields_size = ");
handler.AppendFormatted(static_fields_size);
handler.AppendLiteral("\n");
stringBuilder35.Append(ref handler);
stringBuilder2 = stringBuilder;
StringBuilder stringBuilder36 = stringBuilder2;
handler = new StringBuilder.AppendInterpolatedStringHandler(29, 1, stringBuilder2);
handler.AppendLiteral("thread_static_fields_size = ");
handler.AppendFormatted(thread_static_fields_size);
handler.AppendLiteral("\n");
stringBuilder36.Append(ref handler);
stringBuilder2 = stringBuilder;
StringBuilder stringBuilder37 = stringBuilder2;
handler = new StringBuilder.AppendInterpolatedStringHandler(31, 1, stringBuilder2);
handler.AppendLiteral("thread_static_fields_offset = ");
handler.AppendFormatted(thread_static_fields_offset);
handler.AppendLiteral("\n");
stringBuilder37.Append(ref handler);
stringBuilder2 = stringBuilder;
StringBuilder stringBuilder38 = stringBuilder2;
handler = new StringBuilder.AppendInterpolatedStringHandler(9, 1, stringBuilder2);
handler.AppendLiteral("flags = ");
handler.AppendFormatted<Il2CppClassAttributes>(flags);
handler.AppendLiteral("\n");
stringBuilder38.Append(ref handler);
stringBuilder2 = stringBuilder;
StringBuilder stringBuilder39 = stringBuilder2;
handler = new StringBuilder.AppendInterpolatedStringHandler(9, 1, stringBuilder2);
handler.AppendLiteral("token = ");
handler.AppendFormatted(token);
handler.AppendLiteral("\n");
stringBuilder39.Append(ref handler);
stringBuilder2 = stringBuilder;
StringBuilder stringBuilder40 = stringBuilder2;
handler = new StringBuilder.AppendInterpolatedStringHandler(16, 1, stringBuilder2);
handler.AppendLiteral("method_count = ");
handler.AppendFormatted(method_count);
handler.AppendLiteral("\n");
stringBuilder40.Append(ref handler);
stringBuilder2 = stringBuilder;
StringBuilder stringBuilder41 = stringBuilder2;
handler = new StringBuilder.AppendInterpolatedStringHandler(18, 1, stringBuilder2);
handler.AppendLiteral("property_count = ");
handler.AppendFormatted(property_count);
handler.AppendLiteral("\n");
stringBuilder41.Append(ref handler);
stringBuilder2 = stringBuilder;
StringBuilder stringBuilder42 = stringBuilder2;
handler = new StringBuilder.AppendInterpolatedStringHandler(15, 1, stringBuilder2);
handler.AppendLiteral("field_count = ");
handler.AppendFormatted(field_count);
handler.AppendLiteral("\n");
stringBuilder42.Append(ref handler);
stringBuilder2 = stringBuilder;
StringBuilder stringBuilder43 = stringBuilder2;
handler = new StringBuilder.AppendInterpolatedStringHandler(15, 1, stringBuilder2);
handler.AppendLiteral("event_count = ");
handler.AppendFormatted(event_count);
handler.AppendLiteral("\n");
stringBuilder43.Append(ref handler);
stringBuilder2 = stringBuilder;
StringBuilder stringBuilder44 = stringBuilder2;
handler = new StringBuilder.AppendInterpolatedStringHandler(21, 1, stringBuilder2);
handler.AppendLiteral("nested_type_count = ");
handler.AppendFormatted(nested_type_count);
handler.AppendLiteral("\n");
stringBuilder44.Append(ref handler);
stringBuilder2 = stringBuilder;
StringBuilder stringBuilder45 = stringBuilder2;
handler = new StringBuilder.AppendInterpolatedStringHandler(16, 1, stringBuilder2);
handler.AppendLiteral("vtable_count = ");
handler.AppendFormatted(vtable_count);
handler.AppendLiteral("\n");
stringBuilder45.Append(ref handler);
stringBuilder2 = stringBuilder;
StringBuilder stringBuilder46 = stringBuilder2;
handler = new StringBuilder.AppendInterpolatedStringHandler(20, 1, stringBuilder2);
handler.AppendLiteral("interfaces_count = ");
handler.AppendFormatted(interfaces_count);
handler.AppendLiteral("\n");
stringBuilder46.Append(ref handler);
stringBuilder2 = stringBuilder;
StringBuilder stringBuilder47 = stringBuilder2;
handler = new StringBuilder.AppendInterpolatedStringHandler(27, 1, stringBuilder2);
handler.AppendLiteral("interface_offsets_count = ");
handler.AppendFormatted(interface_offsets_count);
handler.AppendLiteral("\n");
stringBuilder47.Append(ref handler);
stringBuilder2 = stringBuilder;
StringBuilder stringBuilder48 = stringBuilder2;
handler = new StringBuilder.AppendInterpolatedStringHandler(22, 1, stringBuilder2);
handler.AppendLiteral("typeHierarchyDepth = ");
handler.AppendFormatted(typeHierarchyDepth);
handler.AppendLiteral("\n");
stringBuilder48.Append(ref handler);
stringBuilder2 = stringBuilder;
StringBuilder stringBuilder49 = stringBuilder2;
handler = new StringBuilder.AppendInterpolatedStringHandler(25, 1, stringBuilder2);
handler.AppendLiteral("genericRecursionDepth = ");
handler.AppendFormatted(genericRecursionDepth);
handler.AppendLiteral("\n");
stringBuilder49.Append(ref handler);
stringBuilder2 = stringBuilder;
StringBuilder stringBuilder50 = stringBuilder2;
handler = new StringBuilder.AppendInterpolatedStringHandler(8, 1, stringBuilder2);
handler.AppendLiteral("rank = ");
handler.AppendFormatted(rank);
handler.AppendLiteral("\n");
stringBuilder50.Append(ref handler);
stringBuilder2 = stringBuilder;
StringBuilder stringBuilder51 = stringBuilder2;
handler = new StringBuilder.AppendInterpolatedStringHandler(20, 1, stringBuilder2);
handler.AppendLiteral("minimumAlignment = ");
handler.AppendFormatted(minimumAlignment);
handler.AppendLiteral("\n");
stringBuilder51.Append(ref handler);
stringBuilder2 = stringBuilder;
StringBuilder stringBuilder52 = stringBuilder2;
handler = new StringBuilder.AppendInterpolatedStringHandler(19, 1, stringBuilder2);
handler.AppendLiteral("naturalAligment = ");
handler.AppendFormatted(naturalAligment);
handler.AppendLiteral("\n");
stringBuilder52.Append(ref handler);
stringBuilder2 = stringBuilder;
StringBuilder stringBuilder53 = stringBuilder2;
handler = new StringBuilder.AppendInterpolatedStringHandler(15, 1, stringBuilder2);
handler.AppendLiteral("packingSize = ");
handler.AppendFormatted(packingSize);
handler.AppendLiteral("\n");
stringBuilder53.Append(ref handler);
stringBuilder2 = stringBuilder;
StringBuilder stringBuilder54 = stringBuilder2;
handler = new StringBuilder.AppendInterpolatedStringHandler(12, 1, stringBuilder2);
handler.AppendLiteral("bitfield = ");
handler.AppendFormatted(bitfield);
handler.AppendLiteral("\n");
stringBuilder54.Append(ref handler);
stringBuilder2 = stringBuilder;
StringBuilder stringBuilder55 = stringBuilder2;
handler = new StringBuilder.AppendInterpolatedStringHandler(17, 1, stringBuilder2);
handler.AppendLiteral("bitfield(raw) = ");
handler.AppendFormatted((ushort)bitfield);
handler.AppendLiteral("\n");
stringBuilder55.Append(ref handler);
stringBuilder2 = stringBuilder;
StringBuilder stringBuilder56 = stringBuilder2;
handler = new StringBuilder.AppendInterpolatedStringHandler(25, 1, stringBuilder2);
handler.AppendLiteral("implementedInterfaces[");
handler.AppendFormatted(interfaces_count);
handler.AppendLiteral("]:\n");
stringBuilder56.Append(ref handler);
for (int i = 0; i < interfaces_count; i++)
{
MyIl2CppClass* ptr = (MyIl2CppClass*)implementedInterfaces[i];
stringBuilder2 = stringBuilder;
StringBuilder stringBuilder57 = stringBuilder2;
handler = new StringBuilder.AppendInterpolatedStringHandler(5, 2, stringBuilder2);
handler.AppendLiteral(" ");
handler.AppendFormatted(Marshal.PtrToStringAnsi(ptr->namespaze));
handler.AppendLiteral("::");
handler.AppendFormatted(Marshal.PtrToStringAnsi(ptr->name));
handler.AppendLiteral("\n");
stringBuilder57.Append(ref handler);
}
return stringBuilder.ToString();
static string str(IntPtr p)
{
if (p == IntPtr.Zero)
{
return "nullptr";
}
return Marshal.PtrToStringAnsi(p);
}
}
}
internal struct MyIl2CppType
{
public IntPtr data;
public ushort attrs;
public Il2CppTypeEnum type;
public byte mods_byref_pin;
public byte num_mods
{
get
{
return (byte)(mods_byref_pin & 0x1Fu);
}
set
{
mods_byref_pin = (byte)((value & 0x1Fu) | (mods_byref_pin & 0xFFFFFFE0u));
}
}
public bool byref
{
get
{
return (mods_byref_pin & 0x20) != 0;
}
set
{
mods_byref_pin = (byte)(value ? (mods_byref_pin | 0x20u) : (mods_byref_pin & 0xFFFFFFDFu));
}
}
public bool pinned
{
get
{
return (mods_byref_pin & 0x40) != 0;
}
set
{
mods_byref_pin = (byte)(value ? (mods_byref_pin | 0x40u) : (mods_byref_pin & 0xFFFFFFBFu));
}
}
public bool valuetype
{
get
{
return (mods_byref_pin & 0x80) != 0;
}
set
{
mods_byref_pin = (byte)(value ? (mods_byref_pin | 0x80u) : (mods_byref_pin & 0xFFFFFF7Fu));
}
}
public string ToString(string indent = "")
{
//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
return $"Il2CppType:\n{indent} data = {data}\n{indent} attrs = {attrs}\n{indent} attrs (field) = {attrs}\n{indent} attrs (param) = {attrs}\n{indent} type = {type}\n{indent} mods_byref_pin = {Convert.ToString(mods_byref_pin, 2).PadLeft(8, '0')}\n{indent} num_mods = {num_mods}\n{indent} byref = {byref}\n{indent} pinned = {pinned}\n{indent} valuetype = {valuetype}";
}
}
[Flags]
internal enum FieldAttributes : ushort
{
None = 0,
FIELD_ACCESS_MASK = 7,
COMPILER_CONTROLLED = 0,
PRIVATE = 1,
FAM_AND_ASSEM = 2,
ASSEMBLY = 3,
FAMILY = 4,
FAM_OR_ASSEM = 5,
PUBLIC = 6,
STATIC = 0x10,
INIT_ONLY = 0x20,
LITERAL = 0x40,
NOT_SERIALIZED = 0x80,
SPECIAL_NAME = 0x200,
PINVOKE_IMPL = 0x2000,
RESERVED_MASK = 0x9500,
RT_SPECIAL_NAME = 0x400,
HAS_FIELD_MARSHAL = 0x1000,
HAS_DEFAULT = 0x8000,
HAS_FIELD_RVA = 0x100
}
[Flags]
internal enum ParamAttributes : ushort
{
IN = 1,
OUT = 2,
OPTIONAL = 0x10,
RESERVED_MASK = 0xF000,
HAS_DEFAULT = 0x1000,
HAS_FIELD_MARSHAL = 0x2000,
UNUSED = 0xCFE0
}
internal struct MyIl2CppParameterInfo
{
public IntPtr name;
public int position;
public uint token;
public unsafe Il2CppTypeStruct* parameter_type;
}
internal interface IStructSerialiser
{
Type Type { get; }
bool IsBlittable { get; }
Delegate MarshalFunction { get; }
Expression GenerateSerialiser(Expression managedStruct, Expression targetPtr);
Expression GenerateDeserialiser(Expression nativeStructPtr);
unsafe void WriteFields(MyIl2CppClass* klass);
}
internal class Mod : MelonMod
{
}
public static class SerialisationHandler
{
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private unsafe delegate IntPtr InvokerDelegate(IntPtr methodPointer, Il2CppMethodInfo* methodInfo, IntPtr obj, IntPtr* args);
private delegate void StaticVoidIntPtrDelegate(IntPtr intPtr);
private struct InjectionProgress
{
public bool Failed;
public unsafe MyIl2CppClass* ClassPtr;
public SerialisedField[] Result;
}
private delegate IntPtr GetManagerFromContextDelegate(int index);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private unsafe delegate MyIl2CppClass* GetTypeInfoFromTypeDelegate(MyIl2CppType* type);
private static readonly IntPtr invokerPtr;
private static readonly Dictionary<Type, InjectionProgress> injection;
private static long myTokenOverride;
private static ConcurrentDictionary<long, IntPtr> _fakeTokenClasses;
internal static IntPtr _fakeImage;
private static IntPtr _fakeAssembly;
private static bool _initImage;
internal static Dictionary<Type, IntPtr> _injectedStructs;
private static Action<Type, IntPtr> AddTypeToLookup;
private static readonly Dictionary<Type, SerialisedField[]> serialisationCache;
private static readonly StaticVoidIntPtrDelegate FinalizeDelegate;
private static NativeHook<GetTypeInfoFromTypeDelegate> getTypeInfoHook;
private static bool _typeInfoPatched;
private static IntPtr FakeImage
{
get
{
if (!_initImage)
{
InitImage();
}
return _fakeImage;
}
}
private static IntPtr FakeAssembly
{
get
{
if (!_initImage)
{
InitImage();
}
return _fakeAssembly;
}
}
private static ConcurrentDictionary<long, IntPtr> FakeTokenClasses
{
get
{
if (_fakeTokenClasses == null)
{
_fakeTokenClasses = (AccessTools.Field("Il2CppInterop.Runtime.Injection.InjectorHelpers:s_InjectedClasses")?.GetValue(null) as ConcurrentDictionary<long, IntPtr>) ?? throw new Exception("Can't find fake token classes dictionary");
}
return _fakeTokenClasses;
}
}
unsafe static SerialisationHandler()
{
injection = new Dictionary<Type, InjectionProgress>();
myTokenOverride = -9223372036854775807L;
_injectedStructs = new Dictionary<Type, IntPtr>();
AddTypeToLookup = (Action<Type, IntPtr>)Delegate.CreateDelegate(typeof(Action<Type, IntPtr>), AccessTools.Method("Il2CppInterop.Runtime.Injection.InjectorHelpers:AddTypeToLookup", new Type[2]
{
typeof(Type),
typeof(IntPtr)
}, (Type[])null));
serialisationCache = new Dictionary<Type, SerialisedField[]>();
FinalizeDelegate = Finalize;
_typeInfoPatched = false;
InvokerDelegate invokerDelegate = StaticVoidIntPtrInvoker;
GCHandle.Alloc(invokerDelegate, GCHandleType.Normal);
invokerPtr = Marshal.GetFunctionPointerForDelegate(invokerDelegate);
}
private unsafe static IntPtr StaticVoidIntPtrInvoker(IntPtr methodPointer, Il2CppMethodInfo* methodInfo, IntPtr obj, IntPtr* args)
{
Marshal.GetDelegateForFunctionPointer<StaticVoidIntPtrDelegate>(methodPointer)(obj);
return IntPtr.Zero;
}
private static bool IsTypeInjected(Type t)
{
return Util.GetClassPointerForType(t) != IntPtr.Zero;
}
public static void Inject<T>(int debugLevel = 0)
{
Inject(debugLevel, typeof(T));
}
public static void Inject(Type type, int debugLevel = 0)
{
Inject(debugLevel, type);
}
public static void Inject(int debugLevel = 0, params Type[] t)
{
Util.LogLevel = debugLevel;
HashSet<Type> typesToInject = new HashSet<Type>();
foreach (Type ft2 in t)
{
CollectDependencies(ProcessType(ft2));
}
int num = 0;
int num2 = 0;
foreach (Type item in typesToInject)
{
if (item.IsValueType)
{
num2++;
}
else
{
num++;
}
}
Type[] array = new Type[num];
Type[] array2 = new Type[num2];
int num3 = 0;
int num4 = 0;
foreach (Type item2 in typesToInject)
{
if (!item2.IsValueType)
{
array[num3++] = item2;
}
else
{
array2[num4++] = item2;
}
}
InjectBatch(array, array2);
void CollectDependencies(Type ct)
{
if (ct == null || serialisationCache.ContainsKey(ct) || typesToInject.Contains(ct))
{
return;
}
typesToInject.Add(ct);
if (!ct.IsValueType && ct.BaseType != null)
{
CollectDependencies(ProcessType(ct.BaseType));
}
foreach (Type item3 in from field in ct.GetFields(BindingFlags.Instance | BindingFlags.Public)
where !field.IsNotSerialized
select ProcessType(field.FieldType) into r
where r != null
select r)
{
CollectDependencies(item3);
}
}
Type ProcessType(Type ft)
{
if (ft.IsEnum)
{
ft = ft.GetEnumUnderlyingType();
}
if (ft.IsPrimitive)
{
return null;
}
if (typesToInject.Contains(ft))
{
return null;
}
if (ft.IsArray)
{
return ProcessType(ft.GetElementType());
}
if (ft.IsGenericType)
{
Type genericTypeDefinition = ft.GetGenericTypeDefinition();
if (genericTypeDefinition == typeof(List<>) || genericTypeDefinition == typeof(Nullable))
{
return ProcessType(ft.GetGenericArguments()[0]);
}
}
if (IsTypeInjected(ft))
{
return null;
}
return ft;
}
}
internal unsafe static void InitImage()
{
if (!_initImage)
{
INativeImageStruct val = UnityVersionHandler.NewImage();
INativeAssemblyStruct val2 = UnityVersionHandler.NewAssembly();
IntPtr intPtr = Marshal.StringToHGlobalAnsi("InjectedStructs");
val2.Name.Name = intPtr;
val.Assembly = val2.AssemblyPointer;
val.Dynamic = 1;
val.Name = intPtr;
if (val.HasNameNoExt)
{
val.NameNoExt = val.Name;
}
_fakeImage = ((INativeStruct)val).Pointer;
_fakeAssembly = ((INativeStruct)val2).Pointer;
_initImage = true;
DynamicArrayOfPtrs* ptr = (DynamicArrayOfPtrs*)(void*)(Marshal.GetDelegateForFunctionPointer<GetManagerFromContextDelegate>(XrefScannerLowLevelCustom.JumpTargets(XrefScannerLowLevelCustom.JumpTargets(IL2CPP.il2cpp_resolve_icall("UnityEngine.LayerMask::LayerToName")).First()).Single())(5) + 552);
ptr->InsertReplaceNull(_fakeImage);
Util.Log($"Added fake image to script manager: 0x{(long)_fakeImage:X}, new size {ptr->size}", 2);
}
}
private unsafe static IntPtr InjectStruct(Type type)
{
//IL_0115: Unknown result type (might be due to invalid IL or missing references)
//IL_0164: Unknown result type (might be due to invalid IL or missing references)
//IL_038c: Unknown result type (might be due to invalid IL or missing references)
//IL_03fc: Unknown result type (might be due to invalid IL or missing references)
//IL_0401: Unknown result type (might be due to invalid IL or missing references)
HookGetTypeInfo();
IntPtr classPointerForType = Util.GetClassPointerForType(type);
if (classPointerForType != IntPtr.Zero)
{
return classPointerForType;
}
if (type.IsGenericType || type.IsEnum || !type.IsValueType)
{
throw new InvalidOperationException($"Type {type} is not valid for struct injection");
}
IntPtr classPointerForType2 = Util.GetClassPointerForType<ValueType>();
MyIl2CppClass* ptr = (MyIl2CppClass*)(void*)classPointerForType2;
MyIl2CppClass* ptr2 = (MyIl2CppClass*)(void*)((INativeStruct)UnityVersionHandler.NewClass((int)ptr->vtable_count)).Pointer;
long num = Interlocked.Increment(ref myTokenOverride);
FakeTokenClasses[num] = (IntPtr)ptr2;
ptr2->image = (Il2CppImage*)(void*)FakeImage;
ptr2->gc_desc = IntPtr.Zero;
ptr2->name = Marshal.StringToHGlobalAnsi(type.Name);
ptr2->namespaze = Marshal.StringToHGlobalAnsi(type.Namespace ?? string.Empty);
Unsafe.Write(&ptr2->byval_arg, new MyIl2CppType
{
data = (IntPtr)num,
attrs = 0,
type = (Il2CppTypeEnum)17,
num_mods = 0,
byref = false,
pinned = false,
valuetype = true
});
Unsafe.Write(&ptr2->this_arg, new MyIl2CppType
{
data = (IntPtr)num,
attrs = 0,
type = (Il2CppTypeEnum)17,
num_mods = 0,
byref = true,
pinned = false,
valuetype = false
});
ptr2->element_class = (Il2CppClass*)ptr2;
ptr2->castClass = (Il2CppClass*)ptr2;
ptr2->declaringType = (Il2CppClass*)(void*)IntPtr.Zero;
ptr2->parent = (Il2CppClass*)(void*)classPointerForType2;
ptr2->generic_class = IntPtr.Zero;
ptr2->typeDefinition = (IntPtr)num;
ptr2->interopData = IntPtr.Zero;
ptr2->klass = (Il2CppClass*)ptr2;
ptr2->events = (Il2CppEventInfo*)(void*)IntPtr.Zero;
ptr2->event_count = 0;
ptr2->properties = (Il2CppPropertyInfo*)(void*)IntPtr.Zero;
ptr2->property_count = 0;
ptr2->methods = ptr->methods;
ptr2->method_count = ptr->method_count;
ptr2->nestedTypes = (Il2CppClass**)(void*)IntPtr.Zero;
ptr2->nested_type_count = 0;
ptr2->implementedInterfaces = (Il2CppClass**)(void*)IntPtr.Zero;
ptr2->interfaces_count = 0;
ptr2->interfaceOffsets = (Il2CppRuntimeInterfaceOffsetPair*)(void*)IntPtr.Zero;
ptr2->interface_offsets_count = 0;
ptr2->static_fields = IntPtr.Zero;
ptr2->static_fields_size = 0u;
ptr2->thread_static_fields_size = 0u;
ptr2->thread_static_fields_offset = 0;
ptr2->rgctx_data = IntPtr.Zero;
int num2 = ptr->typeHierarchyDepth + 1;
ptr2->typeHierarchyDepth = (byte)num2;
ptr2->typeHierarchy = (Il2CppClass**)(void*)Marshal.AllocHGlobal(num2 * IntPtr.Size);
ptr2->typeHierarchy[num2 - 1] = (Il2CppClass*)(void*)classPointerForType2;
for (int i = 0; i < num2; i++)
{
ptr2->typeHierarchy[i] = ptr->typeHierarchy[i];
}
ptr2->unity_user_data = IntPtr.Zero;
ptr2->initializationExceptionGCHandle = 0u;
ptr2->cctor_started = 1u;
ptr2->cctor_finished = 1u;
ptr2->native_size = 0;
ptr2->instance_size = (uint)Unsafe.SizeOf<Il2CppObject>();
ptr2->actualSize = (uint)Unsafe.SizeOf<Il2CppObject>();
ptr2->genericContainerIndex = IntPtr.Zero;
ptr2->element_size = 0u;
ptr2->token = 0u;
ptr2->vtable_count = ptr->vtable_count;
ptr2->genericRecursionDepth = 1;
ptr2->rank = 0;
Unsafe.Write(&ptr2->flags, (Il2CppClassAttributes)8457);
ptr2->minimumAlignment = 8;
ptr2->naturalAligment = 8;
ptr2->packingSize = 0;
ptr2->bitfield = MyIl2CppClass.ClassFlags.initialized_and_no_error | MyIl2CppClass.ClassFlags.initialized | MyIl2CppClass.ClassFlags.is_vtable_initialized;
VirtualInvokeData* ptr3 = (VirtualInvokeData*)(void*)UnityVersionHandler.Wrap((Il2CppClass*)ptr2).VTable;
VirtualInvokeData* ptr4 = (VirtualInvokeData*)(void*)UnityVersionHandler.Wrap((Il2CppClass*)(void*)classPointerForType2).VTable;
for (int j = 0; j < ptr->vtable_count; j++)
{
Unsafe.Write((byte*)ptr3 + (nint)j * (nint)Unsafe.SizeOf<VirtualInvokeData>(), ((byte*)ptr4)[(nint)j * (nint)Unsafe.SizeOf<VirtualInvokeData>()]);
Util.Log($"vtablePtr = {(IntPtr)((byte*)ptr3 + (nint)j * (nint)Unsafe.SizeOf<VirtualInvokeData>())}", 5);
Util.Log($"vtablePtr method = {(IntPtr)((VirtualInvokeData)((byte*)ptr3 + (nint)j * (nint)Unsafe.SizeOf<VirtualInvokeData>())).method}", 5);
if (((VirtualInvokeData)((byte*)ptr3 + (nint)j * (nint)Unsafe.SizeOf<VirtualInvokeData>())).method != null)
{
Util.Log("copying vtable " + Marshal.PtrToStringAnsi(UnityVersionHandler.Wrap(((VirtualInvokeData)((byte*)ptr3 + (nint)j * (nint)Unsafe.SizeOf<VirtualInvokeData>())).method).Name), 5);
}
}
AddTypeToLookup(type, (IntPtr)ptr2);
_injectedStructs[type] = (IntPtr)ptr2;
RuntimeSpecificsStore.SetClassInfo((IntPtr)ptr2, true);
Util.SetClassPointerForType(type, (IntPtr)ptr2);
return (IntPtr)ptr2;
}
private unsafe static void InjectStructFields(Type type, MyIl2CppClass* klass)
{
IStructSerialiser serialiser = StructSerialiser<float>.GetSerialiser(type);
if (serialiser.IsBlittable)
{
klass->bitfield |= MyIl2CppClass.ClassFlags.is_blittable;
}
serialiser.WriteFields(klass);
}
private unsafe static void InjectBatch(Type[] classes, Type[] structs)
{
//IL_0330: Unknown result type (might be due to invalid IL or missing references)
//IL_0337: Expected O, but got Unknown
injection.Clear();
int num = classes.Length;
int num2 = structs.Length;
Dictionary<Type, List<Type>> dictionary = new Dictionary<Type, List<Type>>();
Type[] array = structs;
foreach (Type type in array)
{
List<Type> list = null;
FieldInfo[] fields = type.GetFields(BindingFlags.Instance | BindingFlags.Public);
foreach (FieldInfo fieldInfo in fields)
{
if (!fieldInfo.IsNotSerialized && structs.Contains(fieldInfo.FieldType))
{
if (list == null)
{
list = new List<Type>();
}
list.Add(fieldInfo.FieldType);
}
}
if (list != null)
{
dictionary.Add(type, list);
}
}
for (int k = 0; k < num2; k++)
{
if (!dictionary.TryGetValue(structs[k], out var value))
{
continue;
}
foreach (Type item in value)
{
int num3 = Array.IndexOf(structs, item);
if (num3 > k)
{
array = structs;
int i = k;
int j = num3;
Type type2 = structs[num3];
Type type3 = structs[k];
array[i] = type2;
structs[j] = type3;
k--;
break;
}
}
}
for (int l = 0; l < num; l++)
{
int num4 = Array.IndexOf<Type>(classes, classes[l].BaseType);
if (num4 != -1 && num4 < l)
{
array = classes;
int j = l;
int i = num4;
Type type3 = classes[num4];
Type type2 = classes[l];
array[j] = type3;
classes[i] = type2;
}
}
Util.Log($"Serialising a batch of {num} classes and {num2} structs:", 1);
if (Util.LogLevel >= 1)
{
array = structs;
foreach (Type type4 in array)
{
MelonLogger.Msg(" " + type4.FullName);
}
array = classes;
foreach (Type type5 in array)
{
MelonLogger.Msg(" " + type5.FullName);
}
}
IntPtr[] array2 = new IntPtr[num2];
for (int m = 0; m < num2; m++)
{
Type type6 = structs[m];
try
{
Util.Log("Initial injection for struct " + type6.Name, 2);
array2[m] = InjectStruct(type6);
Util.Log($"Struct {type6.Name} injected at 0x{(long)array2[m]:X}", 3);
}
catch (Exception ex)
{
MelonLogger.Error($"Struct initial injection failed for {type6}:", ex);
}
}
array = classes;
foreach (Type type7 in array)
{
try
{
Util.Log("Initial injection for " + type7.Name, 2);
RegisterTypeOptions val = new RegisterTypeOptions();
val.set_Interfaces(Il2CppInterfaceCollection.op_Implicit(new Type[1] { typeof(ISerializationCallbackReceiver) }));
ClassInjector.RegisterTypeInIl2Cpp(type7, val);
Util.Log("Get ptr for " + type7.Name, 3);
MyIl2CppClass* ptr = (MyIl2CppClass*)(void*)Util.GetClassPointerForType(type7, bypassEnums: true);
INativeClassStruct klass = UnityVersionHandler.Wrap((Il2CppClass*)ptr);
if (ptr->namespaze == IntPtr.Zero)
{
ptr->namespaze = Marshal.StringToHGlobalAnsi(string.Empty);
}
FixFinaliser(klass);
injection[type7] = new InjectionProgress
{
Failed = false,
ClassPtr = ptr
};
}
catch (Exception value2)
{
Util.Log($"Failed to do initial injection on type {type7.Name}: {value2}", 0);
injection[type7] = new InjectionProgress
{
Failed = true
};
}
}
for (int n = 0; n < num2; n++)
{
Type type8 = structs[n];
try
{
Util.Log("Writing struct fields for " + type8.FullName, 2);
IntPtr intPtr = array2[n];
InjectStructFields(type8, (MyIl2CppClass*)(void*)intPtr);
}
catch (Exception ex2)
{
MelonLogger.Error($"Struct field injection failed for {type8}:", ex2);
}
}
array = classes;
foreach (Type type9 in array)
{
InjectionProgress value3 = injection[type9];
try
{
Util.Log("Start field injection for " + type9.Name, 3);
MyIl2CppClass* classPtr = value3.ClassPtr;
INativeClassStruct val2 = UnityVersionHandler.Wrap((Il2CppClass*)classPtr);
MyIl2CppClass* ptr2 = (MyIl2CppClass*)(void*)Util.GetClassPointerForType(type9.BaseType);
Util.Log("Initial field serialisation for " + type9.Name, 4);
BindingFlags bindingFlags = BindingFlags.DeclaredOnly | BindingFlags.Instance;
SerialisedField[] array3 = (from field in type9.GetFields(bindingFlags | BindingFlags.Public)
where !field.IsNotSerialized
select TrySerialise(field) into field
where field != null
select field).ToArray();
Util.Log("Finding base fields for " + type9.Name, 3);
SerialisedField[] value4 = null;
if (injection.TryGetValue(type9.BaseType, out var value5))
{
value4 = value5.Result;
}
else
{
serialisationCache.TryGetValue(type9.BaseType, out value4);
}
Util.Log("Compiling fields for " + type9.Name, 4);
int num5 = ((value4 != null) ? value4.Length : 0);
SerialisedField[] array4 = new SerialisedField[num5 + array3.Length];
value4?.CopyTo(array4, 0);
array3.CopyTo(array4, num5);
int offset = (int)val2.ActualSize - IntPtr.Size;
Util.Log("Allocating field info for " + type9.Name, 4);
MyIl2CppFieldInfo* ptr3 = (MyIl2CppFieldInfo*)(void*)Marshal.AllocHGlobal(array4.Length * Marshal.SizeOf(typeof(MyIl2CppFieldInfo)));
for (int num6 = 0; num6 < num5; num6++)
{
ptr3[num6] = ptr2->fields[num6];
}
for (int num7 = 0; num7 < array3.Length; num7++)
{
SerialisedField serialisedField = array3[num7];
Util.Log($"[{offset}] Converting field {serialisedField.ManagedField} as {serialisedField}", 2);
INativeFieldInfoStruct val3 = UnityVersionHandler.Wrap((Il2CppFieldInfo*)(ptr3 + num5 + num7));
serialisedField.FillFieldInfoStruct(val3, (Il2CppClass*)classPtr, ref offset);
serialisedField.NativeField = ((INativeStruct)val3).Pointer;
}
classPtr->field_count = (ushort)array4.Length;
classPtr->fields = ptr3;
Util.Log($"Injected {array3.Length} fields (for a total of {array4.Length}), changing class size from {val2.ActualSize} to {offset + IntPtr.Size}", 2);
val2.ActualSize = (val2.InstanceSize = (uint)(offset + IntPtr.Size));
classPtr->gc_desc = IntPtr.Zero;
Il2CppClass* ptr4 = (Il2CppClass*)(void*)Il2CppClassPointerStore<ISerializationCallbackReceiver>.NativeClassPtr;
INativeClassStruct iface = UnityVersionHandler.Wrap(ptr4);
int num8;
for (num8 = 0; num8 < val2.InterfaceCount && val2.ImplementedInterfaces[num8] != ptr4; num8++)
{
}
if (num8 == val2.InterfaceCount)
{
throw new InvalidOperationException("Could not find serialisation callbacks interface!");
}
if (num8 >= val2.InterfaceOffsetsCount)
{
throw new InvalidOperationException("interface is >= interface offsets count!");
}
int offset2 = ((Il2CppRuntimeInterfaceOffsetPair)((byte*)val2.InterfaceOffsets + (nint)num8 * (nint)Unsafe.SizeOf<Il2CppRuntimeInterfaceOffsetPair>())).offset;
ParameterExpression nativePtr = Expression.Parameter(typeof(IntPtr), "nativeObjPtr");
ParameterExpression managedObj = Expression.Variable(type9, "managedObj");
ParameterExpression fieldPtr = Expression.Variable(typeof(IntPtr), "fieldPtr");
MethodInfo method = new Func<IntPtr, object>(ClassInjectorBase.GetMonoObjectFromIl2CppPointer).Method;
_ = new Func<IntPtr, IntPtr>(ClassInjectorBase.GetGcHandlePtrFromIl2CppObject).Method;
Expression[] first = new Expression[1] { Expression.Assign(managedObj, Expression.Convert(Expression.Call(method, nativePtr), type9)) };
IEnumerable<Expression> enumerable = first.Concat(array4.SelectMany((SerialisedField field) => field.GetDeserialiseExpression(managedObj, nativePtr, fieldPtr)));
if (Util.LogLevel >= 3)
{
enumerable = enumerable.Prepend(Util.LogExpression($"Deserialise {type9}:", nativePtr));
enumerable = enumerable.Append(Util.LogExpression("Deserialise complete: ", nativePtr));
}
BlockExpression blockExpression = Expression.Block(new ParameterExpression[2] { managedObj, fieldPtr }, enumerable);
Util.Log("Generated deserialiser method:\n" + string.Join("\n", blockExpression.Expressions), 3);
EmitSerialiserMethod(Expression.Lambda<StaticVoidIntPtrDelegate>(blockExpression, new ParameterExpression[1] { nativePtr }), type9, val2, "OnAfterDeserialize", iface, offset2, Util.LogLevel);
enumerable = first.Concat(array4.SelectMany((SerialisedField field) => field.GetSerialiseExpression(managedObj, nativePtr)));
if (Util.LogLevel >= 3)
{
enumerable = enumerable.Prepend(Util.LogExpression($"Serialise {type9}:", nativePtr));
enumerable = enumerable.Append(Util.LogExpression("Serialise complete: ", nativePtr));
}
BlockExpression blockExpression2 = Expression.Block(new ParameterExpression[1] { managedObj }, enumerable);
Util.Log("Generated serialiser method: \n" + string.Join("\n", blockExpression2.Expressions), 3);
EmitSerialiserMethod(Expression.Lambda<StaticVoidIntPtrDelegate>(blockExpression2, new ParameterExpression[1] { nativePtr }), type9, val2, "OnBeforeSerialize", iface, offset2, Util.LogLevel);
serialisationCache[type9] = array4;
Util.Log($"Completed serialisation injection for type {type9}", 2);
}
catch (Exception value6)
{
Util.Log($"Failed to do field injection on type {type9.Name}: {value6}", 0);
value3.Failed = true;
}
injection[type9] = value3;
}
}
private unsafe static void FixFinaliser(INativeClassStruct klass)
{
if (klass.HasFinalize)
{
INativeMethodInfoStruct obj = UnityVersionHandler.Wrap(*klass.Methods);
obj.MethodPointer = Marshal.GetFunctionPointerForDelegate(FinalizeDelegate);
obj.InvokerMethod = invokerPtr;
}
}
private unsafe static void EmitSerialiserMethod(LambdaExpression lambda, Type monoType, INativeClassStruct klass, string name, INativeClassStruct iface, int interfaceOffset, int debugLevel)
{
VirtualInvokeData* ptr = default(VirtualInvokeData*);
INativeMethodInfoStruct val = null;
VirtualInvokeData* ptr2 = (VirtualInvokeData*)(void*)klass.VTable;
for (int i = 0; i < iface.MethodCount; i++)
{
val = UnityVersionHandler.Wrap(iface.Methods[i]);
if (Marshal.PtrToStringAnsi(val.Name) == name)
{
ptr = (VirtualInvokeData*)((byte*)ptr2 + (nint)(i + interfaceOffset) * (nint)Unsafe.SizeOf<VirtualInvokeData>());
if (debugLevel > 3)
{
MelonLogger.Msg($"Injecting {name} in vtable slot {i + interfaceOffset}");
}
break;
}
}
if (ptr2 == null)
{
throw new InvalidOperationException("Can't find interface method " + name);
}
Delegate @delegate = lambda.Compile();
GCHandle.Alloc(@delegate, GCHandleType.Normal);
INativeMethodInfoStruct val2 = UnityVersionHandler.NewMethod();
val2.Name = Marshal.StringToHGlobalAnsi(name);
val2.Class = klass.ClassPointer;
val2.ReturnType = val.ReturnType;
val2.Flags = (Il2CppMethodFlags)134;
val2.InvokerMethod = invokerPtr;
val2.MethodPointer = Marshal.GetFunctionPointerForDelegate(@delegate);
((VirtualInvokeData)ptr).method = val2.MethodInfoPointer;
((VirtualInvokeData)ptr).methodPtr = val2.MethodPointer;
}
private static SerialisedField TrySerialise(FieldInfo field)
{
try
{
SerialisedField serialisedField = SerialisedField.InferFromField(field);
Util.Log($"Created field of type {serialisedField.GetType().Name} for field {field.FieldType.Name} {field.Name}", 5);
return serialisedField;
}
catch (Exception ex)
{
MelonLogger.Warning($"Not serialising field {field} due to error: {ex.Message}\n{ex.StackTrace}");
}
return null;
}
private static void Finalize(IntPtr ptr)
{
IntPtr gcHandlePtrFromIl2CppObject = ClassInjectorBase.GetGcHandlePtrFromIl2CppObject(ptr);
if (!(gcHandlePtrFromIl2CppObject == IntPtr.Zero))
{
GCHandle.FromIntPtr(gcHandlePtrFromIl2CppObject).Free();
}
}
[DllImport("kernel32", CharSet = CharSet.Ansi, ExactSpelling = true, SetLastError = true)]
internal static extern IntPtr GetProcAddress(IntPtr hModule, string procName);
[DllImport("kernel32", CharSet = CharSet.Ansi, SetLastError = true)]
internal static extern IntPtr LoadLibrary([MarshalAs(UnmanagedType.LPStr)] string lpFileName);
[UnmanagedCallersOnly(CallConvs = new Type[] { typeof(CallConvCdecl) })]
private unsafe static MyIl2CppClass* GetTypeInfoFromTypePatch(MyIl2CppType* type)
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_0008: Invalid comparison between Unknown and I4
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
//IL_0012: Invalid comparison between Unknown and I4
if (((int)type->type == 17 || (int)type->type == 18) && _fakeTokenClasses.TryGetValue((long)type->data, out var value))
{
return (MyIl2CppClass*)(void*)value;
}
while (getTypeInfoHook == null)
{
Thread.Sleep(1);
}
return getTypeInfoHook.Trampoline(type);
}
private unsafe static void HookGetTypeInfo()
{
if (!_typeInfoPatched)
{
_typeInfoPatched = true;
Util.Log("Patching get type from info", 3);
IntPtr hModule = LoadLibrary("GameAssembly.dll");
IntPtr procAddress = GetProcAddress(hModule, "il2cpp_class_from_il2cpp_type");
IntPtr procAddress2 = GetProcAddress(hModule, "il2cpp_type_get_class_or_element_class");
IntPtr classFromType = XrefScannerLowLevelCustom.JumpTargets(procAddress).Single();
Util.Log($"classFromType = 0x{(long)classFromType:X}", 4);
IntPtr intPtr = XrefScannerLowLevelCustom.JumpTargets(procAddress2).Single();
Util.Log($"getClassOrElementClass = 0x{(long)intPtr:X}", 4);
Util.Log("jumptargets: " + string.Join(", ", from p in XrefScannerLowLevelCustom.JumpTargets(intPtr)
select ((long)p).ToString("X")), 5);
IntPtr intPtr2 = (from tgt in XrefScannerLowLevelCustom.JumpTargets(intPtr)
where tgt != classFromType
select tgt).Single();
Util.Log($"cacheGetTypeInfoFromType = 0x{(long)intPtr2:X}", 4);
IntPtr intPtr3 = XrefScannerLowLevelCustom.JumpTargets(intPtr2).Single();
Util.Log($"metadataGetTypeInfoFromType = 0x{(long)intPtr3:X}", 4);
delegate* unmanaged[Cdecl]<MyIl2CppType*, MyIl2CppClass*> delegate* = (delegate* unmanaged[Cdecl]<MyIl2CppType*, MyIl2CppClass*>)(delegate*<MyIl2CppType*, MyIl2CppClass*>)(&GetTypeInfoFromTypePatch);
getTypeInfoHook = new NativeHook<GetTypeInfoFromTypeDelegate>(intPtr3, (IntPtr)delegate*);
getTypeInfoHook.Attach();
}
}
}
internal abstract class SerialisedField
{
protected FieldInfo field;
public abstract IntPtr FieldType { get; }
public IntPtr NativeField { get; set; }
public FieldInfo ManagedField => field;
protected virtual Type TargetType => field.FieldType;
protected SerialisedField(FieldInfo field)
{
this.field = field;
}
public abstract Expression GetNativeToManagedExpression(Expression nativePtr);
public abstract Expression GetManagedToNativeExpression(Expression monoObj);
public virtual IEnumerable<Expression> GetDeserialiseExpression(Expression monoObj, Expression nativePtr, Expression fieldPtr)
{
if (NativeField == IntPtr.Zero)
{
throw new InvalidOperationException("Something went very wrong");
}
Expression right = Expression.Call(new Func<IntPtr, IntPtr, IntPtr>(IL2CPP.il2cpp_field_get_value_object).Method, Expression.Constant(NativeField), nativePtr);
yield return Expression.Assign(fieldPtr, right);
Expression test = Expression.NotEqual(fieldPtr, Expression.Constant(IntPtr.Zero));
yield return Expression.Assign(Expression.Field(monoObj, field), Expression.Condition(test, GetNativeToManagedExpression(fieldPtr), Expression.Default(field.FieldType)));
}
public virtual IEnumerable<Expression> GetSerialiseExpression(Expression monoObj, Expression nativePtr)
{
if (NativeField == IntPtr.Zero)
{
throw new InvalidOperationException("Something went very wrong");
}
MethodInfo method = new Action<IntPtr, IntPtr, IntPtr>(field_set_value_object).Method;
Expression expression = Expression.Field(monoObj, field);
Expression expression2 = GetManagedToNativeExpression(expression);
if (!field.FieldType.IsValueType)
{
expression2 = Expression.Condition(Expression.NotEqual(expression, Expression.Constant(null)), expression2, Expression.Constant(IntPtr.Zero));
}
yield return Expression.Call(method, nativePtr, Expression.Constant(NativeField), expression2);
}
protected unsafe static void field_set_value_object(IntPtr instance, IntPtr field, IntPtr obj)
{
IL2CPP.il2cpp_field_set_value(instance, field, (void*)obj);
}
public static SerialisedField InferFromField(FieldInfo field)
{
Type fieldType = field.FieldType;
if (typeof(Object).IsAssignableFrom(fieldType))
{
return new ObjectField(field);
}
if (fieldType == typeof(string))
{
return new StringField(field);
}
if (fieldType.IsValueType)
{
if (SerialisationHandler._injectedStructs.ContainsKey(fieldType))
{
return (SerialisedField)Activator.CreateInstance(typeof(CustomStructField<>).MakeGenericType(fieldType), field);
}
if (!fieldType.IsEnum)
{
Util.GetClassPointerForType(fieldType);
}
return new StructField(field);
}
if (fieldType.IsArray && fieldType.GetArrayRank() == 1)
{
return new ArrayField(field);
}
if (fieldType.IsGenericType && fieldType.GetGenericTypeDefinition() == typeof(List<>))
{
return new ListField(field);
}
throw new NotSupportedException($"Field type not supported: {field}");
}
public abstract int GetFieldSize(out int align);
public unsafe void FillFieldInfoStruct(INativeFieldInfoStruct infoOut, Il2CppClass* klassPtr, ref int offset)
{
infoOut.Name = Marshal.StringToHGlobalAnsi(field.Name);
infoOut.Parent = klassPtr;
MyIl2CppType* ptr = (MyIl2CppType*)(void*)Marshal.AllocHGlobal(Marshal.SizeOf<MyIl2CppType>());
Unsafe.Write(ptr, Unsafe.Read<MyIl2CppType>((void*)FieldType));
ptr->attrs = 6;
infoOut.Type = (Il2CppTypeStruct*)ptr;
int align;
int fieldSize = GetFieldSize(out align);
offset = Util.AlignTo(offset, align);
infoOut.Offset = offset;
offset += fieldSize;
}
public override string ToString()
{
return GetType().Name + ":" + TargetType;
}
}
internal class StructSerialiser<T> : IStructSerialiser where T : struct
{
private struct BlitField
{
public FieldInfo field;
public int length;
public int offset;
}
private struct PointerMarshalField
{
public FieldInfo field;
public SerialisedField marshaller;
public int offset;
}
private struct SubStructField
{
public FieldInfo field;
public int length;
public IStructSerialiser serialiser;
public int offset;
}
private delegate void DeserialiseDelegate(ref T obj, IntPtr src);
private delegate void SerialiseDelegate(ref T obj, IntPtr tgt);
public static StructSerialiser<T> Cache;
private Type t;
private BlitField[] blitFields;
private PointerMarshalField[] pointerMarshalFields;
private SubStructField[] subStructFields;
private bool offsetsSet;
private DeserialiseDelegate marshalFunction;
private SerialiseDelegate serialiserFunction;
private int nativeSize;
public static StructSerialiser<T> Instance
{
get
{
if (Cache == null)
{
Cache = new StructSerialiser<T>();
}
return Cache;
}
}
public Delegate MarshalFunction => GetMarshalFunction();
public Type Type => t;
public bool IsBlittable { get; private set; }
private StructSerialiser()
{
Cache = this;
Type type = (t = typeof(T));
List<BlitField> list = new List<BlitField>();
List<SubStructField> list2 = new List<SubStructField>();
List<PointerMarshalField> list3 = new List<PointerMarshalField>();
FieldInfo[] fields = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
FieldInfo[] array = fields;
foreach (FieldInfo fieldInfo in array)
{
Type type2 = fieldInfo.FieldType;
if (fieldInfo.IsNotSerialized)
{
continue;
}
if (type2.IsPrimitive || type2.IsEnum)
{
if (type2.IsEnum)
{
type2 = type2.GetEnumUnderlyingType();
}
list.Add(new BlitField
{
field = fieldInfo,
length = Marshal.SizeOf(type2)
});
continue;
}
if (type2.IsValueType)
{
IStructSerialiser serialiser = GetSerialiser(type2);
if (serialiser.IsBlittable)
{
list.Add(new BlitField
{
field = fieldInfo,
length = Marshal.SizeOf(type2)
});
}
else
{
list2.Add(new SubStructField
{
field = fieldInfo,
length = Marshal.SizeOf(type2),
serialiser = serialiser
});
}
continue;
}
try
{
list3.Add(new PointerMarshalField
{
field = fieldInfo,
marshaller = SerialisedField.InferFromField(fieldInfo)
});
}
catch (Exception value)
{
MelonLogger.Warning($"Not serialising struct field {fieldInfo.FieldType.Name} {fieldInfo.Name} on struct {type.Name} due to error:\n{value}");
}
}
IsBlittable = list.Count == fields.Length;
blitFields = list.ToArray();
if (!IsBlittable)
{
pointerMarshalFields = list3.ToArray();
subStructFields = list2.ToArray();
}
else
{
pointerMarshalFields = new PointerMarshalField[0];
subStructFields = new SubStructField[0];
}
}
private unsafe static IntPtr GetPtrValue(IntPtr pp)
{
return *(IntPtr*)(void*)pp;
}
private SerialiseDelegate GetSerialiseFunction()
{
if (!offsetsSet)
{
throw new NotSupportedException($"fields haven't been written yet for {typeof(T)}");
}
if (serialiserFunction != null)
{
return serialiserFunction;
}
ParameterExpression parameterExpression = Expression.Parameter(typeof(T).MakeByRefType(), "obj");
ParameterExpression parameterExpression2 = Expression.Parameter(typeof(IntPtr), "tgt");
serialiserFunction = Expression.Lambda<SerialiseDelegate>(GenerateSerialiser(parameterExpression, parameterExpression2), new ParameterExpression[2] { parameterExpression, parameterExpression2 }).Compile();
return serialiserFunction;
}
private DeserialiseDelegate GetMarshalFunction()
{
if (!offsetsSet)
{
throw new NotSupportedException($"fields haven't been written yet for {typeof(T)}");
}
if (marshalFunction != null)
{
return marshalFunction;
}
if (IsBlittable)
{
marshalFunction = BlitHere;
}
else
{
List<Expression> expressions = new List<Expression>();
ParameterExpression parameterExpression = Expression.Parameter(typeof(T).MakeByRefType(), "tgt");
ParameterExpression parameterExpression2 = Expression.Parameter(typeof(IntPtr), "inPtr");
BlitField[] array = blitFields;
for (int i = 0; i < array.Length; i++)
{
BlitField blitField = array[i];
MethodInfo method = new Func<IntPtr, float>(BlitHere<float>).Method.GetGenericMethodDefinition().MakeGenericMethod(blitField.field.FieldType);
expressions.Add(Expression.Assign(Expression.Field(parameterExpression, blitField.field), Expression.Call(method, Expression.Add(parameterExpression2, Expression.Constant(blitField.offset)))));
}
PointerMarshalField[] array2 = pointerMarshalFields;
for (int i = 0; i < array2.Length; i++)
{
PointerMarshalField pointerMarshalField = array2[i];
Expression expression = Expression.Call(new Func<IntPtr, IntPtr>(GetPtrValue).Method, Expression.Add(parameterExpression2, Expression.Constant(pointerMarshalField.offset)));
expressions.Add(Expression.Assign(Expression.Field(parameterExpression, pointerMarshalField.field), Expression.Condition(Expression.Equal(expression, Expression.Constant(IntPtr.Zero)), Expression.Default(pointerMarshalField.field.FieldType), pointerMarshalField.marshaller.GetNativeToManagedExpression(expression))));
if (pointerMarshalField.field.Name == "objectList")
{
MelonLogger.Msg(Util.DumpExpressionTree(expressions[expressions.Count - 1]));
}
}
SubStructField[] array3 = subStructFields;
for (int i = 0; i < array3.Length; i++)
{
SubStructField subStructField = array3[i];
expressions.Add(Expression.Invoke(Expression.Constant(GetSerialiser(subStructField.field.FieldType).MarshalFunction), Expression.Field(parameterExpression, subStructField.field), Expression.Add(parameterExpression2, Expression.Constant(subStructField.offset))));
}
marshalFunction = Expression.Lambda<DeserialiseDelegate>(Expression.Block(expressions), new ParameterExpression[2] { parameterExpression, parameterExpression2 }).Compile();
}
return marshalFunction;
}
public unsafe void WriteFields(MyIl2CppClass* klass)
{
int num = blitFields.Length + pointerMarshalFields.Length + subStructFields.Length;
int offset = (int)klass->actualSize;
int initialOffset = offset;
int fieldsAdded = 0;
MyIl2CppFieldInfo* fields;
if (num > 0)
{
fields = (MyIl2CppFieldInfo*)(void*)Marshal.AllocHGlobal(sizeof(MyIl2CppFieldInfo) * num);
for (int i = 0; i < blitFields.Length; i++)
{
ref BlitField reference = ref blitFields[i];
Type type2 = reference.field.FieldType;
if (type2.IsEnum)
{
type2 = type2.GetEnumUnderlyingType();
}
IntPtr type3 = IL2CPP.il2cpp_class_get_type(Util.GetClassPointerForType(type2));
AddField(reference.field.Name, type3, reference.length, out reference.offset);
}
for (int j = 0; j < subStructFields.Length; j++)
{
ref SubStructField reference2 = ref subStructFields[j];
IntPtr type4 = IL2CPP.il2cpp_class_get_type(Util.GetClassPointerForType(reference2.field.FieldType));
AddField(reference2.field.Name, type4, reference2.length, out reference2.offset);
}
for (int k = 0; k < pointerMarshalFields.Length; k++)
{
ref PointerMarshalField reference3 = ref pointerMarshalFields[k];
int align2;
int fieldSize = reference3.marshaller.GetFieldSize(out align2);
reference3.marshaller.NativeField = AddField(reference3.field.Name, reference3.marshaller.FieldType, fieldSize, out reference3.offset, align2);
}
klass->fields = fields;
}
else
{
klass->fields = (MyIl2CppFieldInfo*)(void*)IntPtr.Zero;
}
offsetsSet = true;
int num2 = offset - initialOffset;
klass->field_count = (ushort)fieldsAdded;
klass->actualSize += (uint)num2;
klass->instance_size += (uint)num2;
klass->native_size += num2;
klass->bitfield |= MyIl2CppClass.ClassFlags.size_inited;
nativeSize = num2;
unsafe IntPtr AddField(string name, IntPtr type, int length, out int structOffset, int align = 0)
{
MyIl2CppType* ptr = (MyIl2CppType*)(void*)Marshal.AllocHGlobal(Marshal.SizeOf<MyIl2CppType>());
Unsafe.Write(ptr, Unsafe.Read<MyIl2CppType>((void*)type));
ptr->attrs = 6;
offset = Util.AlignTo(offset, align);
MyIl2CppFieldInfo* num3 = fields + fieldsAdded++;
*num3 = new MyIl2CppFieldInfo
{
name = Marshal.StringToHGlobalAnsi(name),
offset = offset,
parent = (Il2CppClass*)klass,
type = (Il2CppTypeStruct*)ptr
};
structOffset = offset - initialOffset;
offset += length;
return (IntPtr)num3;
}
}
public static IStructSerialiser GetSerialiser(Type t1)
{
return (IStructSerialiser)typeof(StructSerialiser<>).MakeGenericType(t1).GetProperty("Instance").GetValue(null);
}
public Expression GenerateDeserialiser(Expression nativeStructPtr)
{
ParameterExpression parameterExpression = Expression.Variable(typeof(T), "res");
return Expression.Block(new ParameterExpression[1] { parameterExpression }, Expression.Invoke(Expression.Constant(GetMarshalFunction()), parameterExpression, nativeStructPtr), parameterExpression);
}
public void DeserialiseArray(IntPtr nativeData, T[] tgt)
{
DeserialiseDelegate deserialiseDelegate = GetMarshalFunction();
for (int i = 0; i < tgt.Length; i++)
{
IntPtr src = nativeData + nativeSize * i;
deserialiseDelegate(ref tgt[i], src);
}
}
public void SerialiseArray(IntPtr nativeData, T[] src)
{
SerialiseDelegate serialiseFunction = GetSerialiseFunction();
for (int i = 0; i < src.Length; i++)
{
IntPtr tgt = nativeData + nativeSize * i;
serialiseFunction(ref src[i], tgt);
}
}
public Expression GenerateSerialiser(Expression managedStruct, Expression targetPtr)
{
if (!offsetsSet)
{
throw new NotSupportedException("fields haven't been written yet");
}
if (IsBlittable)
{
return Expression.Call(typeof(StructSerialiser<T>).GetMethod("BlitThere", BindingFlags.Static | BindingFlags.NonPublic).MakeGenericMethod(t), managedStruct, targetPtr);
}
List<Expression> list = new List<Expression>();
BlitField[] array = blitFields;
for (int i = 0; i < array.Length; i++)
{
BlitField blitField = array[i];
MethodInfo method = typeof(StructSerialiser<T>).GetMethod("BlitThere", BindingFlags.Static | BindingFlags.NonPublic).MakeGenericMethod(blitField.field.FieldType);
list.Add(Expression.Call(method, Expression.Field(managedStruct, blitField.field), Expression.Add(targetPtr, Expression.Constant(blitField.offset))));
}
SubStructField[] array2 = subStructFields;
for (int i = 0; i < array2.Length; i++)
{
SubStructField subStructField = array2[i];
Expression item = subStructField.serialiser.GenerateSerialiser(Expression.Field(managedStruct, subStructField.field), Expression.Add(targetPtr, Expression.Constant(subStructField.offset)));
list.Add(item);
}
if (pointerMarshalFields.Length != 0)
{
MethodInfo method2 = typeof(StructSerialiser<T>).GetMethod("AssignPtr", BindingFlags.Static | BindingFlags.NonPublic);
PointerMarshalField[] array3 = pointerMarshalFields;
for (int i = 0; i < array3.Length; i++)
{
PointerMarshalField pointerMarshalField = array3[i];
BinaryExpression arg = Expression.Add(targetPtr, Expression.Constant(pointerMarshalField.offset));
Expression managedToNativeExpression = pointerMarshalField.marshaller.GetManagedToNativeExpression(Expression.Field(managedStruct, pointerMarshalField.field));
list.Add(Expression.Call(method2, arg, managedToNativeExpression));
}
}
return Expression.Block(list);
}
private unsafe static void AssignPtr(IntPtr target, IntPtr value)
{
*(IntPtr*)(void*)target = value;
}
private unsafe static void BlitThere<T2>(T2 value, IntPtr destObj) where T2 : unmanaged
{
*(T2*)(void*)destObj = value;
}
private unsafe static T2 BlitHere<T2>(IntPtr ptr) where T2 : unmanaged
{
return *(T2*)(void*)ptr;
}
private unsafe static void BlitHere(ref T me, IntPtr src)
{
me = Unsafe.Read<T>((void*)src);
}
}
internal static class Util
{
public static int LogLevel;
public static string DumpExpressionTree(Expression root)
{
StringBuilder builder = new StringBuilder("Expression dump");
dump(root, " ");
return builder.ToString();
void dump(Expression exp, string indent)
{
builder.Append(indent);
if (exp is BlockExpression blockExpression)
{
StringBuilder stringBuilder = builder;
StringBuilder.AppendInterpolatedStringHandler handler = new StringBuilder.AppendInterpolatedStringHandler(8, 1, stringBuilder);
handler.AppendLiteral("Block: ");
handler.AppendFormatted(string.Join(", ", blockExpression.Variables.Select((ParameterExpression v) => $"[{v.Type} {v.Name}]")));
handler.AppendLiteral("\n");
stringBuilder.Append(ref handler);
indent += " ";
{
foreach (Expression expression in blockExpression.Expressions)
{
_ = expression;
dump(exp, indent);
}
return;
}
}
builder.Append(exp.ToString());
builder.Append('\n');
}
}
public static void Log(string message, int level)
{
if (LogLevel >= level)
{
MelonLogger.Msg(message);
}
}
public static Expression LogExpression(string msg, Expression ex)
{
MethodInfo method = new Action<string>(MelonLogger.Msg).Method;
MethodInfo method2 = typeof(object).GetMethod("ToString", new Type[0]);
MethodInfo method3 = new Func<string, string, string>(string.Concat).Method;
Expression expression = Expression.Call(Expression.Convert(ex, typeof(object)), method2);
if (!ex.Type.IsValueType)
{
expression = Expression.Condition(Expression.Equal(ex, Expression.Constant(null)), Expression.Constant("null"), expression);
}
return Expression.Call(method, Expression.Call(method3, Expression.Constant(msg), expression));
}
public static int AlignTo(int value, int alignment)
{
if (alignment > 0)
{
int num = value % alignment;
if (num > 0)
{
value += alignment - num;
}
}
return value;
}
[Obsolete]
public unsafe static int GetTypeSize(INativeTypeStruct type, out uint align)
{
//IL_0007: Unknown result type (might be due to invalid IL or missing references)
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
//IL_000d: Unknown result type (might be due to invalid IL or missing references)
//IL_0083: Expected I4, but got Unknown
//IL_01ce: Unknown result type (might be due to invalid IL or missing references)
//IL_01d3: Unknown result type (might be due to invalid IL or missing references)
Il2CppTypeEnum val = type.Type;
align = 0u;
while (true)
{
INativeClassStruct val2;
switch (val - 2)
{
case 0:
case 2:
case 3:
return 1;
case 4:
case 5:
return 2;
case 1:
return 2;
case 6:
case 7:
case 10:
return 4;
case 8:
case 9:
case 11:
return 8;
case 22:
case 23:
return 8;
case 12:
case 13:
case 16:
case 18:
case 25:
case 26:
case 27:
return IntPtr.Size;
case 15:
val2 = UnityVersionHandler.Wrap((Il2CppClass*)(void*)IL2CPP.il2cpp_class_from_il2cpp_type(((INativeStruct)type).Pointer));
if ((int)type.Type != 17 || !val2.EnumType)
{
return IL2CPP.il2cpp_class_value_size(IL2CPP.il2cpp_class_from_il2cpp_type(((INativeStruct)type).Pointer), ref align);
}
break;
default:
throw new NotImplementedException();
}
byte* ptr = (byte*)(void*)val2.Name;
MelonLogger.Msg($"Enum Basetype debug: {((INativeStruct)val2).Pointer}, {(IntPtr)ptr}, {Marshal.StringToHGlobalAnsi("test")}");
MelonLogger.Msg($"Chr: {*ptr}");
MelonLogger.Msg($"elemt={(IntPtr)val2.ElementClass}");
MelonLogger.Msg("elemtname=" + Marshal.PtrToStringAnsi(IL2CPP.il2cpp_type_get_name((IntPtr)val2.ElementClass)));
val = ((MyIl2CppType*)(void*)IL2CPP.il2cpp_class_enum_basetype(((INativeStruct)val2).Pointer))->type;
}
}
public static IntPtr GetClassPointerForType<T>()
{
if (typeof(T) == typeof(void))
{
return Il2CppClassPointerStore<Void>.NativeClassPtr;
}
return Il2CppClassPointerStore<T>.NativeClassPtr;
}
public static IntPtr GetClassPointerForType(Type type, bool bypassEnums = false)
{
if (type == typeof(void))
{
return Il2CppClassPointerStore<Void>.NativeClassPtr;
}
if (type.IsEnum && !bypassEnums)
{
throw new NotSupportedException("Trying to get pointer for enum type");
}
if (type.ContainsGenericParameters)
{
MelonLogger.Error($"tried to get class ptr for incomplete generic: {type}");
}
return (IntPtr)typeof(Il2CppClassPointerStore<>).MakeGenericType(type).GetField("NativeClassPtr").GetValue(null);
}
public static void SetClassPointerForType(Type type, IntPtr value)
{
typeof(Il2CppClassPointerStore<>).MakeGenericType(type).GetField("NativeClassPtr").SetValue(null, value);
}
}
internal static class XrefScannerLowLevelCustom
{
public unsafe static IEnumerable<IntPtr> JumpTargets(IntPtr codeStart)
{
//IL_0030: Unknown result type (might be due to invalid IL or missing references)
//IL_0036: Expected O, but got Unknown
if (codeStart == IntPtr.Zero)
{
throw new NullReferenceException("codeStart");
}
StreamCodeReader val = new StreamCodeReader((Stream)new UnmanagedMemoryStream((byte*)(void*)codeStart, 1000L, 1000L, FileAccess.Read));
Decoder obj = Decoder.Create(IntPtr.Size * 8, (CodeReader)(object)val, (DecoderOptions)0);
obj.IP = (ulong)(long)codeStart;
return JumpTargetsImpl(obj);
}
private static IEnumerable<IntPtr> JumpTargetsImpl(Decoder myDecoder)
{
Instruction instruction = default(Instruction);
while (true)
{
myDecoder.Decode(ref instruction);
if ((int)myDecoder.LastError == 2 || (int)((Instruction)(ref instruction)).Mnemonic == 1620)
{
break;
}
if ((int)((Instruction)(ref instruction)).FlowControl == 1 || (int)((Instruction)(ref instruction)).FlowControl == 5)
{
yield return (IntPtr)(long)ExtractTargetAddress(in instruction);
}
}
}
private static ulong ExtractTargetAddress(in Instruction instruction)
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
//IL_0007: Unknown result type (might be due to invalid IL or missing references)
//IL_0009: Unknown result type (might be due to invalid IL or missing references)
//IL_0023: Expected I4, but got Unknown
OpKind op0Kind = ((Instruction)(ref instruction)).Op0Kind;
return (op0Kind - 1) switch
{
0 => ((Instruction)(ref instruction)).NearBranch16,
1 => ((Instruction)(ref instruction)).NearBranch32,
2 => ((Instruction)(ref instruction)).NearBranch64,
3 => ((Instruction)(ref instruction)).FarBranch16,
4 => ((Instruction)(ref instruction)).FarBranch32,
_ => throw new ArgumentOutOfRangeException(),
};
}
}
}
namespace FieldInjector.FieldSerialisers
{
internal class ArrayField : SerialisedField
{
protected IntPtr _fieldType;
protected Type _proxyType;
protected Type _elementType;
public override IntPtr FieldType => _fieldType;
public unsafe override int GetFieldSize(out int align)
{
align = sizeof(IntPtr);
return sizeof(IntPtr);
}
protected ArrayField(Type elementType, FieldInfo field)
: base(field)
{
_elementType = elementType;
if (elementType.IsEnum)
{
elementType = elementType.GetEnumUnderlyingType();
}
if (elementType.IsValueType)
{
_proxyType = typeof(Il2CppStructArray<>).MakeGenericType(elementType);
}
else if (elementType == typeof(string))
{
_proxyType = typeof(Il2CppStringArray);
}
else
{
_proxyType = typeof(Il2CppReferenceArray<>).MakeGenericType(elementType);
}
IntPtr intPtr = IL2CPP.il2cpp_array_class_get(Util.GetClassPointerForType(elementType), 1u);
_fieldType = IL2CPP.il2cpp_class_get_type(intPtr);
}
public ArrayField(FieldInfo field)
: this(field.FieldType.GetElementType(), field)
{
}
public override Expression GetManagedToNativeExpression(Expression managedObj)
{
Type elementType = _elementType;
Expression expression;
if (_proxyType == typeof(Il2CppStringArray))
{
expression = Expression.New(_proxyType.GetConstructor(new Type[1] { typeof(string[]) }), managedObj);
}
else if (elementType.IsValueType)
{
Type type = _proxyType.BaseType.GetGenericArguments()[0];
expression = Expression.Call(new Func<float[], Il2CppStructArray<float>>(ConvertArray<float, float>).Method.GetGenericMethodDefinition().MakeGenericMethod(elementType, type), managedObj);
}
else
{
MelonLogger.Msg($"managedElementType = {elementType}, _proxyType = {_proxyType}");
expression = Expression.New(_proxyType.GetConstructor(new Type[1] { elementType.MakeArrayType() }), managedObj);
}
return Expression.Property(expression, "Pointer");
}
public override Expression GetNativeToManagedExpression(Expression nativePtr)
{
return ConvertArrayToManaged(Expression.New(_proxyType.GetConstructor(new Type[1] { typeof(IntPtr) }), nativePtr), _elementType.MakeArrayType());
}
public static Expression ConvertArrayToManaged(Expression cppArray, Type managedType)
{
if (!managedType.IsArray)
{
throw new ArgumentException("managedType is not an array!");
}
Type elementType = managedType.GetElementType();
Type type = cppArray.Type.BaseType.GetGenericArguments()[0];
if (elementType.IsValueType)
{
return Expression.Call(new Func<Il2CppStructArray<float>, float[]>(ConvertStructArray<float, float>).Method.GetGenericMethodDefinition().MakeGenericMethod(elementType, type), cppArray);
}
if (type == elementType)
{
return Expression.Call(new Func<Il2CppArrayBase<float>, float[]>(ConvertArray<float>).Method.GetGenericMethodDefinition().MakeGenericMethod(elementType), cppArray);
}
throw new NotImplementedException();
}
public static T[] ConvertArray<T>(Il2CppArrayBase<T> array)
{
T[] array2 = new T[array.Length];
array.CopyTo(array2, 0);
return array2;
}
public unsafe static TM[] ConvertStructArray<TM, TC>(Il2CppStructArray<TC> array) where TM : unmanaged where TC : unmanaged
{
TM[] array2 = new TM[((Il2CppArrayBase<TC>)(object)array).Length];
StructSerialiser<TM> cache = StructSerialiser<TM>.Cache;
if (cache == null)
{
MelonLogger.Msg("Deserialising array of " + typeof(TM).Name + " without serialiser");
fixed (TM* ptr = array2)
{
for (int i = 0; i < array2.Length; i++)
{
*(TC*)(ptr + i) = ((Il2CppArrayBase<TC>)(object)array)[i];
}
}
}
else
{
MelonLogger.Msg("Deserialising array of " + typeof(TM).Name + " with serialiser");
IntPtr nativeData = ((Il2CppObjectBase)array).Pointer + 4 * IntPtr.Size;
cache.DeserialiseArray(nativeData, array2);
}
return array2;
}
public unsafe static Il2CppStructArray<TC> ConvertArray<TM, TC>(TM[] array) where TM : unmanaged where TC : unmanaged
{
Il2CppStructArray<TC> val = new Il2CppStructArray<TC>((long)array.Length);
StructSerialiser<TM> cache = StructSerialiser<TM>.Cache;
if (cache == null)
{
MelonLogger.Msg("Serialising array of " + typeof(TM).Name + " without serialiser");
fixed (TM* ptr = array)
{
for (int i = 0; i < array.Length; i++)
{
((Il2CppArrayBase<TC>)(object)val)[i] = *(TC*)(ptr + i);
}
}
}
else
{
MelonLogger.Msg("Serialising array of " + typeof(TM).Name + " with serialiser");
IntPtr nativeData = ((Il2CppObjectBase)val).Pointer + 4 * IntPtr.Size;
cache.SerialiseArray(nativeData, array);
}
return val;
}
}
internal class CustomStructField<T> : SerialisedField where T : struct
{
private readonly IntPtr fieldType;
private readonly IntPtr fieldClass;
private int fieldLength;
private uint fieldAlign;
public override IntPtr FieldType => fieldType;
internal unsafe int Offset => ((MyIl2CppFieldInfo*)(void*)base.NativeField)->offset;
public CustomStructField(FieldInfo field)
: base(field)
{
if (field.FieldType != typeof(T))
{
throw new ArgumentException("CustomStructField field type does not match T");
}
if (!SerialisationHandler._injectedStructs.TryGetValue(field.FieldType, out fieldClass))
{
throw new InvalidOperationException("Tried to create CustomStructField for non-injected struct");
}
fieldType = IL2CPP.il2cpp_class_get_type(fieldClass);
fieldLength = IL2CPP.il2cpp_class_value_size(fieldClass, ref fieldAlign);
MelonLogger.Msg($"CSF Length: {fieldLength}");
}
public override int GetFieldSize(out int align)
{
align = (int)fieldAlign;
return fieldLength;
}
internal unsafe static void ClearMem(IntPtr target, int length)
{
if (length % 8 == 0)
{
for (int i = 0; i < length / 8; i++)
{
*(long*)((byte*)(void*)target + (nint)i * (nint)8) = 0L;
}
}
else if (length % 4 == 0)
{
for (int j = 0; j < length / 4; j++)
{
*(int*)((byte*)(void*)target + (nint)j * (nint)4) = 0;
}
}
else if (length % 2 == 0)
{
for (int k = 0; k < length / 2; k++)
{
*(short*)((byte*)(void*)target + (nint)k * (nint)2) = 0;
}
}
else
{
for (int l = 0; l < length; l++)
{
((byte*)(void*)target)[l] = 0;
}
}
}
internal unsafe static IntPtr GetFieldPtrAndClear(IntPtr obj, IntPtr field, int length)
{
int offset = ((MyIl2CppFieldInfo*)(void*)field)->offset;
IntPtr intPtr = obj + offset;
ClearMem(intPtr, length);
return intPtr;
}
internal unsafe static IntPtr GetFieldPtr(IntPtr obj, IntPtr field)
{
int offset = ((MyIl2CppFieldInfo*)(void*)field)->offset;
return obj + offset;
}
public override IEnumerable<Expression> GetSerialiseExpression(Expression monoObj, Expression nativePtr)
{
if (base.NativeField == IntPtr.Zero)
{
throw new InvalidOperationException("Something went very wrong");
}
Expression right = Expression.Field(monoObj, field);
MethodInfo method = new Func<IntPtr, IntPtr, int, IntPtr>(GetFieldPtrAndClear).Method;
ParameterExpression parameterExpression = Expression.Variable(typeof(IntPtr), "fieldPtr");
ParameterExpression parameterExpression2 = Expression.Variable(typeof(T), "managedValue");
Expression right2 = Expression.Call(method, nativePtr, Expression.Constant(base.NativeField), Expression.Constant(fieldLength));
yield return Expression.Block(new ParameterExpression[2] { parameterExpression, parameterExpression2 }, Expression.Assign(parameterExpression, right2), Expression.Assign(parameterExpression2, right), StructSerialiser<T>.Instance.GenerateSerialiser(parameterExpression2, parameterExpression));
}
public override IEnumerable<Expression> GetDeserialiseExpression(Expression monoObj, Expression nativePtr, Expression fieldPtr)
{
_ = new Func<IntPtr, IntPtr, IntPtr>(GetFieldPtr).Method;
BinaryExpression nativeStructPtr = Expression.Add(nativePtr, Expression.Constant(Offset));
Expression right = StructSerialiser<T>.Instance.GenerateDeserialiser(nativeStructPtr);
yield return Expression.Assign(Expression.Field(monoObj, field), right);
}
public override Expression GetManagedToNativeExpression(Expression monoObj)
{
throw new NotImplementedException();
}
public override Expression GetNativeToManagedExpression(Expression nativePtr)
{
throw new NotImplementedException();
}
}
internal class ListField : ArrayField
{
public ListField(FieldInfo field)
: base(field.FieldType.GetGenericArguments()[0], field)
{
}
public override Expression GetManagedToNativeExpression(Expression monoObj)
{
MethodInfo method = monoObj.Type.GetMethod("ToArray", BindingFlags.Instance | BindingFlags.Public);
return base.GetManagedToNativeExpression((Expression)Expression.Call(monoObj, method));
}
public override Expression GetNativeToManagedExpression(Expression nativePtr)
{
Expression nativeToManagedExpression = base.GetNativeToManagedExpression(nativePtr);
return Expression.New(field.FieldType.GetConstructor(new Type[1] { typeof(IEnumerable<>).MakeGenericType(_elementType) }), nativeToManagedExpression);
}
}
internal class ObjectField : SerialisedField
{
public override IntPtr FieldType => IL2CPP.il2cpp_class_get_type(Util.GetClassPointerForType(TargetType));
public unsafe override int GetFieldSize(out int align)
{
align = sizeof(IntPtr);
return sizeof(IntPtr);
}
public ObjectField(FieldInfo field)
: base(field)
{
}
public override Expression GetNativeToManagedExpression(Expression nativePtr)
{
return Expression.New(TargetType.GetConstructor(new Type[1] { typeof(IntPtr) }), nativePtr);
}
public override Expression GetManagedToNativeExpression(Expression monoObj)
{
PropertyInfo property = typeof(Object).GetProperty("Pointer");
return Expression.Property(monoObj, property);
}
}
internal class StringField : SerialisedField
{
public override IntPtr FieldType => IL2CPP.il2cpp_class_get_type(Il2CppClassPointerStore<string>.NativeClassPtr);
public StringField(FieldInfo field)
: base(field)
{
}
public unsafe override int GetFieldSize(out int align)
{
align = sizeof(IntPtr);
return sizeof(IntPtr);
}
public override Expression GetNativeToManagedExpression(Expression nativePtr)
{
return Expression.Call(new Func<IntPtr, string>(IL2CPP.Il2CppStringToManaged).Method, nativePtr);
}
public override Expression GetManagedToNativeExpression(Expression monoObj)
{
return Expression.Call(new Func<string, IntPtr>(IL2CPP.ManagedStringToIl2Cpp).Method, monoObj);
}
}
internal class StructField : SerialisedField
{
private readonly IntPtr fieldClass;
private readonly IntPtr _fieldType;
private readonly Type _serialisedType;
public override IntPtr FieldType => _fieldType;
protected override Type TargetType => _serialisedType;
public StructField(FieldInfo field)
: base(field)
{
if (base.TargetType.IsEnum)
{
_serialisedType = base.TargetType.GetEnumUnderlyingType();
}
else
{
_serialisedType = base.TargetType;
}
fieldClass = Util.GetClassPointerForType(TargetType);
_fieldType = IL2CPP.il2cpp_class_get_type(fieldClass);
}
public unsafe override int GetFieldSize(out int align)
{
align = 0;
return (int)(UnityVersionHandler.Wrap((Il2CppClass*)(void*)fieldClass).ActualSize - Marshal.SizeOf<Il2CppObject>());
}
public unsafe static T GetValue<T>(IntPtr obj, IntPtr field) where T : unmanaged
{
MyIl2CppFieldInfo* ptr = (MyIl2CppFieldInfo*)(void*)field;
void* ptr2 = (byte*)(void*)obj + (nint)ptr->offset * (nint)2;
return *(T*)ptr2;
}
public override Expression GetManagedToNativeExpression(Expression monoValue)
{
throw new NotImplementedException();
}
internal unsafe static void SetValue<T>(T value, IntPtr obj, IntPtr field) where T : unmanaged
{
MyIl2CppFieldInfo* ptr = (MyIl2CppFieldInfo*)(void*)field;
void* ptr2 = (byte*)(void*)obj + ptr->offset;
*(T*)ptr2 = value;
}
public override IEnumerable<Expression> GetSerialiseExpression(Expression monoObj, Expression nativePtr)
{
if (base.NativeField == IntPtr.Zero)
{
throw new InvalidOperationException("Something went very wrong");
}
Expression expression = Expression.Field(monoObj, field);
MethodInfo method = new Action<int, IntPtr, IntPtr>(SetValue).Method.GetGenericMethodDefinition().MakeGenericMethod(expression.Type);
yield return Expression.Call(method, expression, nativePtr, Expression.Constant(base.NativeField));
}
public override Expression GetNativeToManagedExpression(Expression nativePtr)
{
ConstructorInfo constructor = typeof(Object).GetConstructor(new Type[1] { typeof(IntPtr) });
MethodInfo method = typeof(Object).GetMethod("Unbox").MakeGenericMethod(TargetType);
Expression expression = Expression.Call(Expression.New(constructor, nativePtr), method);
if (expression.Type != field.FieldType)
{
expression = Expression.Convert(expression, field.FieldType);
}
return expression;
}
}
}