Decompiled source of FieldInjector v2.0.400

FieldInjector.dll

Decompiled 4 months ago
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;
		}
	}
}