Decompiled source of XUnity ResourceRedirector v2.1.1

BepInEx/core/XUnity.Common.dll

Decompiled 5 months ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Threading;
using Mono.Cecil;
using Mono.Cecil.Cil;
using MonoMod.Utils;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.SceneManagement;
using XUnity.Common.Constants;
using XUnity.Common.Extensions;
using XUnity.Common.Logging;
using XUnity.Common.Utilities;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: InternalsVisibleTo("XUnity.AutoTranslator.Plugin.Core")]
[assembly: AssemblyCompany("gravydevsupreme")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("Common dependencies shared between XUnity Auto Translator and Resource Redirector.")]
[assembly: AssemblyFileVersion("1.0.3.0")]
[assembly: AssemblyInformationalVersion("1.0.3")]
[assembly: AssemblyProduct("XUnity.Common")]
[assembly: AssemblyTitle("XUnity.Common")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.3.0")]
[module: UnverifiableCode]
namespace XUnity.Common.Utilities
{
	public static class ArrayHelper
	{
		public static T[] Null<T>()
		{
			return null;
		}
	}
	public static class CabHelper
	{
		private static string CreateRandomCab()
		{
			return "CAB-" + Guid.NewGuid().ToString("N");
		}

		public static void RandomizeCab(byte[] assetBundleData)
		{
			string @string = Encoding.ASCII.GetString(assetBundleData, 0, Math.Min(1024, assetBundleData.Length - 4));
			int num = @string.IndexOf("CAB-", StringComparison.Ordinal);
			if (num >= 0)
			{
				int num2 = @string.Substring(num).IndexOf('\0');
				if (num2 >= 0 && num2 <= 36)
				{
					string s = CreateRandomCab();
					Buffer.BlockCopy(Encoding.ASCII.GetBytes(s), 36 - num2, assetBundleData, num, num2);
				}
			}
		}

		public static void RandomizeCabWithAnyLength(byte[] assetBundleData)
		{
			FindAndReplaceCab("CAB-", 0, assetBundleData, 2048);
		}

		private static void FindAndReplaceCab(string ansiStringToStartWith, byte byteToEndWith, byte[] data, int maxIterations = -1)
		{
			int num = Math.Min(data.Length, maxIterations);
			if (num == -1)
			{
				num = data.Length;
			}
			int num2 = 0;
			int length = ansiStringToStartWith.Length;
			string text = Guid.NewGuid().ToString("N");
			int num3 = 0;
			for (int i = 0; i < num; i++)
			{
				char c = (char)data[i];
				if (num2 == length)
				{
					while (data[i] != byteToEndWith && i < num)
					{
						if (num3 >= text.Length)
						{
							num3 = 0;
							text = Guid.NewGuid().ToString("N");
						}
						data[i++] = (byte)text[num3++];
					}
					break;
				}
				num2 = ((c == ansiStringToStartWith[num2]) ? (num2 + 1) : 0);
			}
		}
	}
	internal static class CecilFastReflectionHelper
	{
		private static readonly Type[] DynamicMethodDelegateArgs = new Type[2]
		{
			typeof(object),
			typeof(object[])
		};

		public static FastReflectionDelegate CreateFastDelegate(MethodBase method, bool directBoxValueAccess, bool forceNonVirtcall)
		{
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Expected O, but got Unknown
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_011f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0105: Unknown result type (might be due to invalid IL or missing references)
			//IL_0238: Unknown result type (might be due to invalid IL or missing references)
			//IL_0225: Unknown result type (might be due to invalid IL or missing references)
			//IL_013b: Unknown result type (might be due to invalid IL or missing references)
			//IL_028c: Unknown result type (might be due to invalid IL or missing references)
			//IL_014f: Unknown result type (might be due to invalid IL or missing references)
			//IL_015c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0167: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0297: Unknown result type (might be due to invalid IL or missing references)
			//IL_027d: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_019d: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a7: Expected O, but got Unknown
			//IL_01a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ac: Expected O, but got Unknown
			//IL_01a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b1: Expected O, but got Unknown
			DynamicMethodDefinition val = new DynamicMethodDefinition("FastReflection<" + method.DeclaringType.FullName + "." + method.Name + ">", typeof(object), DynamicMethodDelegateArgs);
			ILProcessor iLProcessor = val.GetILProcessor();
			ParameterInfo[] parameters = method.GetParameters();
			bool flag = true;
			if (!method.IsStatic)
			{
				iLProcessor.Emit(OpCodes.Ldarg_0);
				if (method.DeclaringType.IsValueType)
				{
					Extensions.Emit(iLProcessor, OpCodes.Unbox_Any, method.DeclaringType);
				}
			}
			for (int i = 0; i < parameters.Length; i++)
			{
				Type type = parameters[i].ParameterType;
				bool isByRef = type.IsByRef;
				if (isByRef)
				{
					type = type.GetElementType();
				}
				bool isValueType = type.IsValueType;
				if (isByRef && isValueType && !directBoxValueAccess)
				{
					iLProcessor.Emit(OpCodes.Ldarg_1);
					iLProcessor.Emit(OpCodes.Ldc_I4, i);
				}
				iLProcessor.Emit(OpCodes.Ldarg_1);
				iLProcessor.Emit(OpCodes.Ldc_I4, i);
				if (isByRef && !isValueType)
				{
					Extensions.Emit(iLProcessor, OpCodes.Ldelema, typeof(object));
					continue;
				}
				iLProcessor.Emit(OpCodes.Ldelem_Ref);
				if (!isValueType)
				{
					continue;
				}
				if (!isByRef || !directBoxValueAccess)
				{
					Extensions.Emit(iLProcessor, OpCodes.Unbox_Any, type);
					if (isByRef)
					{
						Extensions.Emit(iLProcessor, OpCodes.Box, type);
						iLProcessor.Emit(OpCodes.Dup);
						Extensions.Emit(iLProcessor, OpCodes.Unbox, type);
						if (flag)
						{
							flag = false;
							val.Definition.Body.Variables.Add(new VariableDefinition((TypeReference)new PinnedType((TypeReference)new PointerType(((MemberReference)val.Definition).Module.TypeSystem.Void))));
						}
						iLProcessor.Emit(OpCodes.Stloc_0);
						iLProcessor.Emit(OpCodes.Stelem_Ref);
						iLProcessor.Emit(OpCodes.Ldloc_0);
					}
				}
				else
				{
					Extensions.Emit(iLProcessor, OpCodes.Unbox, type);
				}
			}
			if (method.IsConstructor)
			{
				Extensions.Emit(iLProcessor, OpCodes.Newobj, (MethodBase)(method as ConstructorInfo));
			}
			else if (method.IsFinal || !method.IsVirtual || forceNonVirtcall)
			{
				Extensions.Emit(iLProcessor, OpCodes.Call, (MethodBase)(method as MethodInfo));
			}
			else
			{
				Extensions.Emit(iLProcessor, OpCodes.Callvirt, (MethodBase)(method as MethodInfo));
			}
			Type type2 = (method.IsConstructor ? method.DeclaringType : (method as MethodInfo).ReturnType);
			if ((object)type2 != typeof(void))
			{
				if (type2.IsValueType)
				{
					Extensions.Emit(iLProcessor, OpCodes.Box, type2);
				}
			}
			else
			{
				iLProcessor.Emit(OpCodes.Ldnull);
			}
			iLProcessor.Emit(OpCodes.Ret);
			return (FastReflectionDelegate)Extensions.CreateDelegate((MethodBase)val.Generate(), typeof(FastReflectionDelegate));
		}

		public static Func<T, F> CreateFastFieldGetter<T, F>(FieldInfo fieldInfo)
		{
			//IL_00db: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_011b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0114: Unknown result type (might be due to invalid IL or missing references)
			//IL_0154: Unknown result type (might be due to invalid IL or missing references)
			//IL_0143: Unknown result type (might be due to invalid IL or missing references)
			if ((object)fieldInfo == null)
			{
				throw new ArgumentNullException("fieldInfo");
			}
			if (!typeof(F).IsAssignableFrom(fieldInfo.FieldType))
			{
				throw new ArgumentException("FieldInfo type does not match return type.");
			}
			if ((object)typeof(T) != typeof(object) && ((object)fieldInfo.DeclaringType == null || !fieldInfo.DeclaringType.IsAssignableFrom(typeof(T))))
			{
				throw new MissingFieldException(typeof(T).Name, fieldInfo.Name);
			}
			DynamicMethodDefinition val = new DynamicMethodDefinition("FastReflection<" + typeof(T).FullName + ".Get_" + fieldInfo.Name + ">", typeof(F), new Type[1] { typeof(T) });
			ILProcessor iLProcessor = val.GetILProcessor();
			if (!fieldInfo.IsStatic)
			{
				iLProcessor.Emit(OpCodes.Ldarg_0);
				Extensions.Emit(iLProcessor, OpCodes.Castclass, fieldInfo.DeclaringType);
			}
			Extensions.Emit(iLProcessor, fieldInfo.IsStatic ? OpCodes.Ldsfld : OpCodes.Ldfld, fieldInfo);
			if (fieldInfo.FieldType.IsValueType != typeof(F).IsValueType)
			{
				Extensions.Emit(iLProcessor, OpCodes.Box, fieldInfo.FieldType);
			}
			iLProcessor.Emit(OpCodes.Ret);
			return (Func<T, F>)Extensions.CreateDelegate((MethodBase)val.Generate(), typeof(Func<T, F>));
		}

		public static Action<T, F> CreateFastFieldSetter<T, F>(FieldInfo fieldInfo)
		{
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0110: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_019c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0195: Unknown result type (might be due to invalid IL or missing references)
			//IL_017c: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0169: Unknown result type (might be due to invalid IL or missing references)
			//IL_0156: Unknown result type (might be due to invalid IL or missing references)
			if ((object)fieldInfo == null)
			{
				throw new ArgumentNullException("fieldInfo");
			}
			if (!typeof(F).IsAssignableFrom(fieldInfo.FieldType))
			{
				throw new ArgumentException("FieldInfo type does not match argument type.");
			}
			if ((object)typeof(T) != typeof(object) && ((object)fieldInfo.DeclaringType == null || !fieldInfo.DeclaringType.IsAssignableFrom(typeof(T))))
			{
				throw new MissingFieldException(typeof(T).Name, fieldInfo.Name);
			}
			DynamicMethodDefinition val = new DynamicMethodDefinition("FastReflection<" + typeof(T).FullName + ".Set_" + fieldInfo.Name + ">", (Type)null, new Type[2]
			{
				typeof(T),
				typeof(F)
			});
			ILProcessor iLProcessor = val.GetILProcessor();
			if (!fieldInfo.IsStatic)
			{
				iLProcessor.Emit(OpCodes.Ldarg_0);
				Extensions.Emit(iLProcessor, OpCodes.Castclass, fieldInfo.DeclaringType);
			}
			iLProcessor.Emit(OpCodes.Ldarg_1);
			if ((object)fieldInfo.FieldType != typeof(F))
			{
				if (fieldInfo.FieldType.IsValueType != typeof(F).IsValueType)
				{
					if (fieldInfo.FieldType.IsValueType)
					{
						Extensions.Emit(iLProcessor, OpCodes.Unbox_Any, fieldInfo.FieldType);
					}
					else
					{
						Extensions.Emit(iLProcessor, OpCodes.Box, fieldInfo.FieldType);
					}
				}
				else
				{
					Extensions.Emit(iLProcessor, OpCodes.Castclass, fieldInfo.FieldType);
				}
			}
			Extensions.Emit(iLProcessor, fieldInfo.IsStatic ? OpCodes.Stsfld : OpCodes.Stfld, fieldInfo);
			iLProcessor.Emit(OpCodes.Ret);
			return (Action<T, F>)Extensions.CreateDelegate((MethodBase)val.Generate(), typeof(Action<T, F>));
		}
	}
	public static class CustomFastReflectionHelper
	{
		private struct FastReflectionDelegateKey
		{
			public MethodBase Method { get; }

			public bool DirectBoxValueAccess { get; }

			public bool ForceNonVirtCall { get; }

			public FastReflectionDelegateKey(MethodBase method, bool directBoxValueAccess, bool forceNonVirtCall)
			{
				Method = method;
				DirectBoxValueAccess = directBoxValueAccess;
				ForceNonVirtCall = forceNonVirtCall;
			}

			public override bool Equals(object obj)
			{
				if (obj is FastReflectionDelegateKey fastReflectionDelegateKey && EqualityComparer<MethodBase>.Default.Equals(Method, fastReflectionDelegateKey.Method) && DirectBoxValueAccess == fastReflectionDelegateKey.DirectBoxValueAccess)
				{
					return ForceNonVirtCall == fastReflectionDelegateKey.ForceNonVirtCall;
				}
				return false;
			}

			public override int GetHashCode()
			{
				return ((1017116076 * -1521134295 + EqualityComparer<MethodBase>.Default.GetHashCode(Method)) * -1521134295 + DirectBoxValueAccess.GetHashCode()) * -1521134295 + ForceNonVirtCall.GetHashCode();
			}
		}

		private static readonly Dictionary<FastReflectionDelegateKey, FastReflectionDelegate> MethodCache = new Dictionary<FastReflectionDelegateKey, FastReflectionDelegate>();

		public static FastReflectionDelegate CreateFastDelegate(this MethodBase method, bool directBoxValueAccess = true, bool forceNonVirtCall = false)
		{
			FastReflectionDelegateKey key = new FastReflectionDelegateKey(method, directBoxValueAccess, forceNonVirtCall);
			if (MethodCache.TryGetValue(key, out var value))
			{
				return value;
			}
			value = (((object)ClrTypes.DynamicMethodDefinition == null) ? GetFastDelegateForSRE(method, directBoxValueAccess, forceNonVirtCall) : GetFastDelegateForCecil(method, directBoxValueAccess, forceNonVirtCall));
			MethodCache.Add(key, value);
			return value;
		}

		public static Func<T, F> CreateFastFieldGetter<T, F>(FieldInfo fieldInfo)
		{
			if ((object)ClrTypes.DynamicMethodDefinition != null)
			{
				return CreateFastFieldGetterForCecil<T, F>(fieldInfo);
			}
			return CreateFastFieldGetterForSRE<T, F>(fieldInfo);
		}

		public static Action<T, F> CreateFastFieldSetter<T, F>(FieldInfo fieldInfo)
		{
			if ((object)ClrTypes.DynamicMethodDefinition != null)
			{
				return CreateFastFieldSetterForCecil<T, F>(fieldInfo);
			}
			return CreateFastFieldSetterForSRE<T, F>(fieldInfo);
		}

		private static FastReflectionDelegate GetFastDelegateForCecil(MethodBase method, bool directBoxValueAccess, bool forceNonVirtCall)
		{
			try
			{
				return CecilFastReflectionHelper.CreateFastDelegate(method, directBoxValueAccess, forceNonVirtCall);
			}
			catch (Exception e)
			{
				try
				{
					XuaLogger.Common.Warn(e, "Failed creating fast reflection delegate through with cecil. Retrying with reflection emit...");
					return ReflectionEmitFastReflectionHelper.CreateFastDelegate(method, directBoxValueAccess, forceNonVirtCall);
				}
				catch (Exception e2)
				{
					XuaLogger.Common.Warn(e2, "Failed creating fast reflection delegate through with reflection emit. Falling back to standard reflection...");
					return (object target, object[] args) => method.Invoke(target, args);
				}
			}
		}

		private static Func<T, F> CreateFastFieldGetterForCecil<T, F>(FieldInfo fieldInfo)
		{
			try
			{
				return CecilFastReflectionHelper.CreateFastFieldGetter<T, F>(fieldInfo);
			}
			catch (Exception e)
			{
				try
				{
					XuaLogger.Common.Warn(e, "Failed creating fast reflection delegate through with cecil. Retrying with reflection emit...");
					return ReflectionEmitFastReflectionHelper.CreateFastFieldGetter<T, F>(fieldInfo);
				}
				catch (Exception e2)
				{
					XuaLogger.Common.Warn(e2, "Failed creating fast reflection delegate through with reflection emit. Falling back to standard reflection...");
					return (T target) => (F)fieldInfo.GetValue(target);
				}
			}
		}

		private static Action<T, F> CreateFastFieldSetterForCecil<T, F>(FieldInfo fieldInfo)
		{
			try
			{
				return CecilFastReflectionHelper.CreateFastFieldSetter<T, F>(fieldInfo);
			}
			catch (Exception e)
			{
				try
				{
					XuaLogger.Common.Warn(e, "Failed creating fast reflection delegate through with cecil. Retrying with reflection emit...");
					return ReflectionEmitFastReflectionHelper.CreateFastFieldSetter<T, F>(fieldInfo);
				}
				catch (Exception e2)
				{
					XuaLogger.Common.Warn(e2, "Failed creating fast reflection delegate through with reflection emit. Falling back to standard reflection...");
					return delegate(T target, F value)
					{
						fieldInfo.SetValue(target, value);
					};
				}
			}
		}

		private static FastReflectionDelegate GetFastDelegateForSRE(MethodBase method, bool directBoxValueAccess, bool forceNonVirtCall)
		{
			try
			{
				return ReflectionEmitFastReflectionHelper.CreateFastDelegate(method, directBoxValueAccess, forceNonVirtCall);
			}
			catch (Exception e)
			{
				XuaLogger.Common.Warn(e, "Failed creating fast reflection delegate through with reflection emit. Falling back to standard reflection...");
				return (object target, object[] args) => method.Invoke(target, args);
			}
		}

		private static Func<T, F> CreateFastFieldGetterForSRE<T, F>(FieldInfo fieldInfo)
		{
			try
			{
				return ReflectionEmitFastReflectionHelper.CreateFastFieldGetter<T, F>(fieldInfo);
			}
			catch (Exception e)
			{
				XuaLogger.Common.Warn(e, "Failed creating fast reflection delegate through with reflection emit. Falling back to standard reflection...");
				return (T target) => (F)fieldInfo.GetValue(target);
			}
		}

		private static Action<T, F> CreateFastFieldSetterForSRE<T, F>(FieldInfo fieldInfo)
		{
			try
			{
				return ReflectionEmitFastReflectionHelper.CreateFastFieldSetter<T, F>(fieldInfo);
			}
			catch (Exception e)
			{
				XuaLogger.Common.Warn(e, "Failed creating fast reflection delegate through with reflection emit. Falling back to standard reflection...");
				return delegate(T target, F value)
				{
					fieldInfo.SetValue(target, value);
				};
			}
		}
	}
	public static class DiacriticHelper
	{
		public static string RemoveAllDiacritics(this string input)
		{
			return new string((from c in input.SafeNormalize(NormalizationForm.FormD)
				where CharUnicodeInfo.GetUnicodeCategory(c) != UnicodeCategory.NonSpacingMark
				select c).ToArray()).SafeNormalize();
		}

		private static string SafeNormalize(this string input, NormalizationForm normalizationForm = NormalizationForm.FormC)
		{
			return ReplaceNonCharacters(input, '?').Normalize(normalizationForm);
		}

		private static string ReplaceNonCharacters(string input, char replacement)
		{
			StringBuilder stringBuilder = new StringBuilder(input.Length);
			for (int i = 0; i < input.Length; i++)
			{
				if (char.IsSurrogatePair(input, i))
				{
					int num = char.ConvertToUtf32(input, i);
					i++;
					if (IsValidCodePoint(num))
					{
						stringBuilder.Append(char.ConvertFromUtf32(num));
					}
					else
					{
						stringBuilder.Append(replacement);
					}
				}
				else
				{
					char c = input[i];
					if (IsValidCodePoint(c))
					{
						stringBuilder.Append(c);
					}
					else
					{
						stringBuilder.Append(replacement);
					}
				}
			}
			return stringBuilder.ToString();
		}

		private static bool IsValidCodePoint(int point)
		{
			if (point >= 64976)
			{
				if (point >= 65008 && (point & 0xFFFF) != 65535 && (point & 0xFFFE) != 65534)
				{
					return point <= 1114111;
				}
				return false;
			}
			return true;
		}
	}
	public static class ExpressionHelper
	{
		public static Delegate CreateTypedFastInvoke(MethodBase method)
		{
			if ((object)method == null)
			{
				throw new ArgumentNullException("method");
			}
			return CreateTypedFastInvokeUnchecked(method);
		}

		public static Delegate CreateTypedFastInvokeUnchecked(MethodBase method)
		{
			if ((object)method == null)
			{
				return null;
			}
			if (method.IsGenericMethod)
			{
				throw new ArgumentException("The provided method must not be generic.", "method");
			}
			if (method is MethodInfo methodInfo)
			{
				Expression[] arguments;
				if (method.IsStatic)
				{
					ParameterExpression[] array = (from p in methodInfo.GetParameters()
						select Expression.Parameter(p.ParameterType, p.Name)).ToArray();
					arguments = array;
					return Expression.Lambda(Expression.Call(null, methodInfo, arguments), array).Compile();
				}
				List<ParameterExpression> list = (from p in methodInfo.GetParameters()
					select Expression.Parameter(p.ParameterType, p.Name)).ToList();
				list.Insert(0, Expression.Parameter(methodInfo.DeclaringType, "instance"));
				ParameterExpression instance = list[0];
				arguments = list.Skip(1).ToArray();
				return Expression.Lambda(Expression.Call(instance, methodInfo, arguments), list.ToArray()).Compile();
			}
			if (method is ConstructorInfo constructorInfo)
			{
				ParameterExpression[] array2 = (from p in constructorInfo.GetParameters()
					select Expression.Parameter(p.ParameterType, p.Name)).ToArray();
				Expression[] arguments = array2;
				return Expression.Lambda(Expression.New(constructorInfo, arguments), array2).Compile();
			}
			throw new ArgumentException("method", "This method only supports MethodInfo and ConstructorInfo.");
		}
	}
	public static class ExtensionDataHelper
	{
		private static readonly object Sync;

		private static readonly WeakDictionary<object, object> WeakDynamicFields;

		public static int WeakReferenceCount
		{
			get
			{
				lock (Sync)
				{
					return WeakDynamicFields.Count;
				}
			}
		}

		static ExtensionDataHelper()
		{
			Sync = new object();
			WeakDynamicFields = new WeakDictionary<object, object>();
			MaintenanceHelper.AddMaintenanceFunction(Cull, 12);
		}

		public static void SetExtensionData<T>(this object obj, T t)
		{
			lock (Sync)
			{
				if (WeakDynamicFields.TryGetValue(obj, out var value))
				{
					if (value is Dictionary<Type, object> dictionary)
					{
						dictionary[typeof(T)] = t;
						return;
					}
					Dictionary<Type, object> dictionary2 = new Dictionary<Type, object>();
					dictionary2.Add(value.GetType(), value);
					dictionary2[typeof(T)] = t;
					WeakDynamicFields[obj] = dictionary2;
				}
				else
				{
					WeakDynamicFields[obj] = t;
				}
			}
		}

		public static T GetOrCreateExtensionData<T>(this object obj) where T : new()
		{
			if (obj == null)
			{
				return default(T);
			}
			lock (Sync)
			{
				if (WeakDynamicFields.TryGetValue(obj, out var value))
				{
					if (value is Dictionary<Type, object> dictionary)
					{
						if (dictionary.TryGetValue(typeof(T), out value))
						{
							return (T)value;
						}
						T val = new T();
						dictionary[typeof(T)] = val;
						return val;
					}
					if (!(value is T result))
					{
						Dictionary<Type, object> dictionary2 = new Dictionary<Type, object>();
						dictionary2.Add(value.GetType(), value);
						T val2 = new T();
						dictionary2[typeof(T)] = val2;
						WeakDynamicFields[obj] = dictionary2;
						return val2;
					}
					return result;
				}
				T val3 = new T();
				WeakDynamicFields[obj] = val3;
				return val3;
			}
		}

		public static T GetExtensionData<T>(this object obj)
		{
			if (obj == null)
			{
				return default(T);
			}
			lock (Sync)
			{
				if (WeakDynamicFields.TryGetValue(obj, out var value))
				{
					if (value is Dictionary<Type, object> dictionary && dictionary.TryGetValue(typeof(T), out value))
					{
						if (!(value is T result))
						{
							return default(T);
						}
						return result;
					}
					if (!(value is T result2))
					{
						return default(T);
					}
					return result2;
				}
			}
			return default(T);
		}

		public static void Cull()
		{
			lock (Sync)
			{
				WeakDynamicFields.RemoveCollectedEntries();
			}
		}

		public static List<KeyValuePair<object, object>> GetAllRegisteredObjects()
		{
			lock (Sync)
			{
				return IterateAllPairs().ToList();
			}
		}

		public static void Remove(object obj)
		{
			lock (Sync)
			{
				WeakDynamicFields.Remove(obj);
			}
		}

		private static IEnumerable<KeyValuePair<object, object>> IterateAllPairs()
		{
			foreach (KeyValuePair<object, object> kvp in WeakDynamicFields)
			{
				if (kvp.Value is Dictionary<Type, object> dictionary)
				{
					foreach (KeyValuePair<Type, object> item in dictionary)
					{
						yield return new KeyValuePair<object, object>(kvp.Key, item.Value);
					}
				}
				else
				{
					yield return kvp;
				}
			}
		}
	}
	public delegate object FastReflectionDelegate(object target, params object[] args);
	public static class HookingHelper
	{
		private static readonly MethodInfo PatchMethod12;

		private static readonly MethodInfo PatchMethod20;

		private static readonly object Harmony;

		private static bool _loggedHarmonyError;

		static HookingHelper()
		{
			PatchMethod12 = ClrTypes.HarmonyInstance?.GetMethod("Patch", new Type[4]
			{
				ClrTypes.MethodBase,
				ClrTypes.HarmonyMethod,
				ClrTypes.HarmonyMethod,
				ClrTypes.HarmonyMethod
			});
			PatchMethod20 = ClrTypes.Harmony?.GetMethod("Patch", new Type[5]
			{
				ClrTypes.MethodBase,
				ClrTypes.HarmonyMethod,
				ClrTypes.HarmonyMethod,
				ClrTypes.HarmonyMethod,
				ClrTypes.HarmonyMethod
			});
			_loggedHarmonyError = false;
			try
			{
				if ((object)ClrTypes.HarmonyInstance != null)
				{
					Harmony = ClrTypes.HarmonyInstance.GetMethod("Create", BindingFlags.Static | BindingFlags.Public).Invoke(null, new object[1] { "xunity.common.hookinghelper" });
				}
				else if ((object)ClrTypes.Harmony != null)
				{
					Harmony = ClrTypes.Harmony.GetConstructor(new Type[1] { typeof(string) }).Invoke(new object[1] { "xunity.common.hookinghelper" });
				}
				else
				{
					XuaLogger.Common.Error("An unexpected exception occurred during harmony initialization, likely caused by unknown Harmony version. Harmony hooks will be unavailable!");
				}
			}
			catch (Exception e)
			{
				XuaLogger.Common.Error(e, "An unexpected exception occurred during harmony initialization. Harmony hooks will be unavailable!");
			}
		}

		public static void PatchAll(IEnumerable<Type> types, bool forceExternHooks)
		{
			foreach (Type type in types)
			{
				PatchType(type, forceExternHooks);
			}
		}

		public static void PatchAll(IEnumerable<Type[]> types, bool forceMonoModHooks)
		{
			foreach (Type[] type in types)
			{
				for (int i = 0; i < type.Length && !PatchType(type[i], forceMonoModHooks); i++)
				{
				}
			}
		}

		public static bool PatchType(Type type, bool forceExternHooks)
		{
			MethodBase methodBase = null;
			IntPtr intPtr = IntPtr.Zero;
			try
			{
				if (Harmony == null && !_loggedHarmonyError)
				{
					_loggedHarmonyError = true;
					XuaLogger.Common.Warn("Harmony is not loaded or could not be initialized. Using fallback hooks instead.");
				}
				BindingFlags bindingAttr = BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;
				MethodInfo method = type.GetMethod("Prepare", bindingAttr);
				if ((object)method == null || (bool)method.Invoke(null, new object[1] { Harmony }))
				{
					try
					{
						methodBase = (MethodBase)(type.GetMethod("TargetMethod", bindingAttr)?.Invoke(null, new object[1] { Harmony }));
					}
					catch
					{
					}
					try
					{
						intPtr = ((IntPtr?)type.GetMethod("TargetMethodPointer", bindingAttr)?.Invoke(null, null)) ?? IntPtr.Zero;
					}
					catch
					{
					}
					if ((object)methodBase == null && intPtr == IntPtr.Zero)
					{
						if ((object)methodBase != null)
						{
							XuaLogger.Common.Warn("Could not hook '" + methodBase.DeclaringType.FullName + "." + methodBase.Name + "'. Likely due differences between different versions of the engine or text framework.");
						}
						else
						{
							XuaLogger.Common.Warn("Could not hook '" + type.Name + "'. Likely due differences between different versions of the engine or text framework.");
						}
						return false;
					}
					MethodInfo method2 = type.GetMethod("Prefix", bindingAttr);
					MethodInfo method3 = type.GetMethod("Postfix", bindingAttr);
					MethodInfo method4 = type.GetMethod("Finalizer", bindingAttr);
					if ((object)methodBase == null || forceExternHooks || Harmony == null || ((object)method2 == null && (object)method3 == null && (object)method4 == null))
					{
						return PatchWithExternHooks(type, methodBase, intPtr, forced: true);
					}
					if ((object)methodBase != null)
					{
						try
						{
							int? priority = type.GetCustomAttributes(typeof(HookingHelperPriorityAttribute), inherit: false).OfType<HookingHelperPriorityAttribute>().FirstOrDefault()?.priority;
							object obj3 = (((object)method2 != null) ? CreateHarmonyMethod(method2, priority) : null);
							object obj4 = (((object)method3 != null) ? CreateHarmonyMethod(method3, priority) : null);
							object obj5 = (((object)method4 != null) ? CreateHarmonyMethod(method4, priority) : null);
							if ((object)PatchMethod12 != null)
							{
								PatchMethod12.Invoke(Harmony, new object[4] { methodBase, obj3, obj4, null });
							}
							else
							{
								PatchMethod20.Invoke(Harmony, new object[5] { methodBase, obj3, obj4, null, obj5 });
							}
							XuaLogger.Common.Debug("Hooked " + methodBase.DeclaringType.FullName + "." + methodBase.Name + " through Harmony hooks.");
							return true;
						}
						catch (Exception e) when (((Func<bool>)delegate
						{
							// Could not convert BlockContainer to single expression
							System.Runtime.CompilerServices.Unsafe.SkipInit(out int num);
							if (e.FirstInnerExceptionOfType<PlatformNotSupportedException>() == null)
							{
								ArgumentException ex = e.FirstInnerExceptionOfType<ArgumentException>();
								num = ((ex != null && ex.Message?.Contains("no body") == true) ? 1 : 0);
							}
							else
							{
								num = 1;
							}
							return num != 0;
						}).Invoke())
						{
							return PatchWithExternHooks(type, methodBase, intPtr, forced: false);
						}
					}
					XuaLogger.Common.Warn("Could not hook '" + type.Name + "'. Likely due differences between different versions of the engine or text framework.");
				}
			}
			catch (Exception e2)
			{
				if ((object)methodBase != null)
				{
					XuaLogger.Common.Warn(e2, "An error occurred while patching property/method '" + methodBase.DeclaringType.FullName + "." + methodBase.Name + "'. Failing hook: '" + type.Name + "'.");
				}
				else
				{
					XuaLogger.Common.Warn(e2, "An error occurred while patching property/method. Failing hook: '" + type.Name + "'.");
				}
			}
			return false;
		}

		private static bool PatchWithExternHooks(Type type, MethodBase original, IntPtr originalPtr, bool forced)
		{
			BindingFlags bindingAttr = BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;
			if ((object)ClrTypes.Imports != null)
			{
				if (originalPtr == IntPtr.Zero)
				{
					XuaLogger.Common.Warn("Could not hook '" + type.Name + "'. Likely due differences between different versions of the engine or text framework.");
					return false;
				}
				IntPtr? intPtr = type.GetMethod("ML_Detour", bindingAttr)?.MethodHandle.GetFunctionPointer();
				if (intPtr.HasValue && intPtr.Value != IntPtr.Zero)
				{
					ClrTypes.Imports.GetMethod("Hook", bindingAttr).Invoke(null, new object[2] { originalPtr, intPtr.Value });
					XuaLogger.Common.Debug("Hooked " + type.Name + " through MelonMod Imports.Hook method.");
					return true;
				}
				XuaLogger.Common.Warn("Could not hook '" + type.Name + "' because no detour method was found.");
			}
			else
			{
				if ((object)original == null)
				{
					XuaLogger.Common.Warn("Cannot hook '" + type.Name + "'. Could not locate the original method. Failing hook: '" + type.Name + "'.");
					return false;
				}
				if ((object)ClrTypes.Hook == null || (object)ClrTypes.NativeDetour == null)
				{
					XuaLogger.Common.Warn("Cannot hook '" + original.DeclaringType.FullName + "." + original.Name + "'. MonoMod hooks is not supported in this runtime as MonoMod is not loaded. Failing hook: '" + type.Name + "'.");
					return false;
				}
				object obj = type.GetMethod("Get_MM_Detour", bindingAttr)?.Invoke(null, null) ?? type.GetMethod("MM_Detour", bindingAttr);
				if (obj != null)
				{
					string text = "(managed)";
					object obj2;
					try
					{
						obj2 = ClrTypes.Hook.GetConstructor(new Type[2]
						{
							typeof(MethodBase),
							typeof(MethodInfo)
						}).Invoke(new object[2] { original, obj });
						obj2.GetType().GetMethod("Apply").Invoke(obj2, null);
					}
					catch (Exception e) when (((Func<bool>)delegate
					{
						// Could not convert BlockContainer to single expression
						System.Runtime.CompilerServices.Unsafe.SkipInit(out int num);
						if (e.FirstInnerExceptionOfType<NullReferenceException>() == null)
						{
							NotSupportedException ex = e.FirstInnerExceptionOfType<NotSupportedException>();
							num = ((ex != null && ex.Message?.Contains("Body-less") == true) ? 1 : 0);
						}
						else
						{
							num = 1;
						}
						return num != 0;
					}).Invoke())
					{
						text = "(native)";
						obj2 = ClrTypes.NativeDetour.GetConstructor(new Type[2]
						{
							typeof(MethodBase),
							typeof(MethodBase)
						}).Invoke(new object[2] { original, obj });
						obj2.GetType().GetMethod("Apply").Invoke(obj2, null);
					}
					type.GetMethod("MM_Init", bindingAttr)?.Invoke(null, new object[1] { obj2 });
					if (forced)
					{
						XuaLogger.Common.Debug("Hooked " + original.DeclaringType.FullName + "." + original.Name + " through forced MonoMod hooks. " + text);
					}
					else
					{
						XuaLogger.Common.Debug("Hooked " + original.DeclaringType.FullName + "." + original.Name + " through MonoMod hooks. " + text);
					}
					return true;
				}
				if (forced)
				{
					XuaLogger.Common.Warn("Cannot hook '" + original.DeclaringType.FullName + "." + original.Name + "'. Harmony is not supported in this runtime and no alternate MonoMod hook has been implemented. Failing hook: '" + type.Name + "'.");
				}
				else
				{
					XuaLogger.Common.Warn("Cannot hook '" + original.DeclaringType.FullName + "." + original.Name + "'. Harmony is not supported in this runtime and no alternate MonoMod hook has been implemented. Failing hook: '" + type.Name + "'.");
				}
			}
			return false;
		}

		private static object CreateHarmonyMethod(MethodInfo method, int? priority)
		{
			object obj = ClrTypes.HarmonyMethod.GetConstructor(new Type[1] { typeof(MethodInfo) }).Invoke(new object[1] { method });
			if (priority.HasValue)
			{
				(ClrTypes.HarmonyMethod.GetField("priority", BindingFlags.Instance | BindingFlags.Public) ?? ClrTypes.HarmonyMethod.GetField("prioritiy", BindingFlags.Instance | BindingFlags.Public)).SetValue(obj, priority.Value);
			}
			return obj;
		}
	}
	public class HookingHelperPriorityAttribute : Attribute
	{
		public int priority;

		public HookingHelperPriorityAttribute(int priority)
		{
			this.priority = priority;
		}
	}
	public static class HookPriority
	{
		public const int Last = 0;

		public const int VeryLow = 100;

		public const int Low = 200;

		public const int LowerThanNormal = 300;

		public const int Normal = 400;

		public const int HigherThanNormal = 500;

		public const int High = 600;

		public const int VeryHigh = 700;

		public const int First = 800;
	}
	public static class ListExtensions
	{
		public static void BinarySearchInsert<T>(this List<T> items, T item) where T : IComparable<T>
		{
			int num = items.BinarySearch(item);
			if (num < 0)
			{
				items.Insert(~num, item);
			}
			else
			{
				items.Insert(num, item);
			}
		}
	}
	public static class MaintenanceHelper
	{
		private class ActionRegistration
		{
			public Action Action { get; }

			public int Filter { get; }

			public ActionRegistration(Action action, int filter)
			{
				Action = action;
				Filter = filter;
			}
		}

		private static readonly object Sync = new object();

		private static readonly List<ActionRegistration> RegisteredActions = new List<ActionRegistration>();

		private static bool _initialized;

		public static void AddMaintenanceFunction(Action action, int filter)
		{
			lock (Sync)
			{
				if (!_initialized)
				{
					_initialized = true;
					StartMaintenance();
				}
				ActionRegistration item = new ActionRegistration(action, filter);
				RegisteredActions.Add(item);
			}
		}

		private static void StartMaintenance()
		{
			Thread thread = new Thread(MaintenanceLoop);
			thread.IsBackground = true;
			thread.Start();
		}

		private static void MaintenanceLoop(object state)
		{
			int num = 0;
			while (true)
			{
				lock (Sync)
				{
					foreach (ActionRegistration registeredAction in RegisteredActions)
					{
						if (num % registeredAction.Filter == 0)
						{
							try
							{
								registeredAction.Action();
							}
							catch (Exception e)
							{
								XuaLogger.Common.Error(e, "An unexpected error occurred during maintenance.");
							}
						}
					}
				}
				num++;
				Thread.Sleep(5000);
			}
		}
	}
	public static class Paths
	{
		private static string _gameRoot;

		public static string GameRoot
		{
			get
			{
				return _gameRoot ?? GetAndSetGameRoot();
			}
			set
			{
				_gameRoot = value;
			}
		}

		public static void Initialize()
		{
			GetAndSetGameRoot();
		}

		private static string GetAndSetGameRoot()
		{
			return _gameRoot = new DirectoryInfo(Application.dataPath).Parent.FullName;
		}
	}
	public static class ReflectionCache
	{
		private struct MemberLookupKey
		{
			public Type Type { get; set; }

			public string MemberName { get; set; }

			public MemberLookupKey(Type type, string memberName)
			{
				Type = type;
				MemberName = memberName;
			}

			public override bool Equals(object obj)
			{
				if (obj is MemberLookupKey memberLookupKey)
				{
					if ((object)Type == memberLookupKey.Type)
					{
						return MemberName == memberLookupKey.MemberName;
					}
					return false;
				}
				return false;
			}

			public override int GetHashCode()
			{
				return Type.GetHashCode() + MemberName.GetHashCode();
			}
		}

		private static Dictionary<MemberLookupKey, CachedMethod> Methods = new Dictionary<MemberLookupKey, CachedMethod>();

		private static Dictionary<MemberLookupKey, CachedProperty> Properties = new Dictionary<MemberLookupKey, CachedProperty>();

		private static Dictionary<MemberLookupKey, CachedField> Fields = new Dictionary<MemberLookupKey, CachedField>();

		public static CachedMethod CachedMethod(this Type type, string name)
		{
			return type.CachedMethod(name, (Type[])null);
		}

		public static CachedMethod CachedMethod(this Type type, string name, params Type[] types)
		{
			MemberLookupKey key = new MemberLookupKey(type, name);
			if (!Methods.TryGetValue(key, out var value))
			{
				Type type2 = type;
				MethodInfo methodInfo = null;
				while ((object)methodInfo == null && (object)type2 != null)
				{
					methodInfo = ((types != null && types.Length != 0) ? type2.GetMethod(name, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, types, null) : type2.GetMethod(name, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic));
					type2 = type2.BaseType;
				}
				if ((object)methodInfo != null)
				{
					value = new CachedMethod(methodInfo);
				}
				Methods[key] = value;
			}
			return value;
		}

		public static CachedProperty CachedProperty(this Type type, string name)
		{
			MemberLookupKey key = new MemberLookupKey(type, name);
			if (!Properties.TryGetValue(key, out var value))
			{
				Type type2 = type;
				PropertyInfo propertyInfo = null;
				while ((object)propertyInfo == null && (object)type2 != null)
				{
					propertyInfo = type2.GetProperty(name, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
					type2 = type2.BaseType;
				}
				if ((object)propertyInfo != null)
				{
					value = new CachedProperty(propertyInfo);
				}
				Properties[key] = value;
			}
			return value;
		}

		public static CachedField CachedField(this Type type, string name)
		{
			MemberLookupKey key = new MemberLookupKey(type, name);
			if (!Fields.TryGetValue(key, out var value))
			{
				Type type2 = type;
				FieldInfo fieldInfo = null;
				while ((object)fieldInfo == null && (object)type2 != null)
				{
					fieldInfo = type2.GetField(name, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
					type2 = type2.BaseType;
				}
				if ((object)fieldInfo != null)
				{
					value = new CachedField(fieldInfo);
				}
				Fields[key] = value;
			}
			return value;
		}

		public static CachedField CachedFieldByIndex(this Type type, int index, Type fieldType, BindingFlags flags)
		{
			FieldInfo[] array = (from x in type.GetFields(flags)
				where (object)x.FieldType == fieldType
				select x).ToArray();
			if (index < array.Length)
			{
				return new CachedField(array[index]);
			}
			return null;
		}
	}
	public class CachedMethod
	{
		private static readonly object[] Args0 = new object[0];

		private static readonly object[] Args1 = new object[1];

		private static readonly object[] Args2 = new object[2];

		private FastReflectionDelegate _invoke;

		internal CachedMethod(MethodInfo method)
		{
			_invoke = method.CreateFastDelegate();
		}

		public object Invoke(object instance, object[] arguments)
		{
			return _invoke(instance, arguments);
		}

		public object Invoke(object instance)
		{
			return _invoke(instance, Args0);
		}

		public object Invoke(object instance, object arg1)
		{
			try
			{
				Args1[0] = arg1;
				return _invoke(instance, Args1);
			}
			finally
			{
				Args1[0] = null;
			}
		}

		public object Invoke(object instance, object arg1, object arg2)
		{
			try
			{
				Args2[0] = arg1;
				Args2[1] = arg2;
				return _invoke(instance, Args2);
			}
			finally
			{
				Args2[0] = null;
				Args2[1] = null;
			}
		}
	}
	public class CachedProperty
	{
		private static readonly object[] Args0 = new object[0];

		private static readonly object[] Args1 = new object[1];

		private FastReflectionDelegate _set;

		private FastReflectionDelegate _get;

		public Type PropertyType { get; }

		internal CachedProperty(PropertyInfo propertyInfo)
		{
			if (propertyInfo.CanRead)
			{
				_get = propertyInfo.GetGetMethod(nonPublic: true).CreateFastDelegate();
			}
			if (propertyInfo.CanWrite)
			{
				_set = propertyInfo.GetSetMethod(nonPublic: true).CreateFastDelegate();
			}
			PropertyType = propertyInfo.PropertyType;
		}

		public void Set(object instance, object[] arguments)
		{
			if (_set != null)
			{
				_set(instance, arguments);
			}
		}

		public void Set(object instance, object arg1)
		{
			if (_set == null)
			{
				return;
			}
			try
			{
				Args1[0] = arg1;
				_set(instance, Args1);
			}
			finally
			{
				Args1[0] = null;
			}
		}

		public object Get(object instance, object[] arguments)
		{
			if (_get == null)
			{
				return null;
			}
			return _get(instance, arguments);
		}

		public object Get(object instance)
		{
			if (_get == null)
			{
				return null;
			}
			return _get(instance, Args0);
		}
	}
	public class CachedField
	{
		private Func<object, object> _get;

		private Action<object, object> _set;

		public Type FieldType { get; }

		internal CachedField(FieldInfo fieldInfo)
		{
			_get = CustomFastReflectionHelper.CreateFastFieldGetter<object, object>(fieldInfo);
			_set = CustomFastReflectionHelper.CreateFastFieldSetter<object, object>(fieldInfo);
			FieldType = fieldInfo.FieldType;
		}

		public void Set(object instance, object value)
		{
			if (_set != null)
			{
				_set(instance, value);
			}
		}

		public object Get(object instance)
		{
			if (_get == null)
			{
				return null;
			}
			return _get(instance);
		}
	}
	internal static class ReflectionEmitFastReflectionHelper
	{
		private static readonly Type[] DynamicMethodDelegateArgs = new Type[2]
		{
			typeof(object),
			typeof(object[])
		};

		public static FastReflectionDelegate CreateFastDelegate(MethodBase method, bool directBoxValueAccess, bool forceNonVirtcall)
		{
			DynamicMethod dynamicMethod = new DynamicMethod("FastReflection<" + method.DeclaringType.FullName + "." + method.Name + ">", typeof(object), DynamicMethodDelegateArgs, method.DeclaringType.Module, skipVisibility: true);
			ILGenerator iLGenerator = dynamicMethod.GetILGenerator();
			ParameterInfo[] parameters = method.GetParameters();
			bool flag = true;
			if (!method.IsStatic)
			{
				iLGenerator.Emit(OpCodes.Ldarg_0);
				if (method.DeclaringType.IsValueType)
				{
					iLGenerator.Emit(OpCodes.Unbox_Any, method.DeclaringType);
				}
			}
			for (int i = 0; i < parameters.Length; i++)
			{
				Type type = parameters[i].ParameterType;
				bool isByRef = type.IsByRef;
				if (isByRef)
				{
					type = type.GetElementType();
				}
				bool isValueType = type.IsValueType;
				if (isByRef && isValueType && !directBoxValueAccess)
				{
					iLGenerator.Emit(OpCodes.Ldarg_1);
					iLGenerator.Emit(OpCodes.Ldc_I4, i);
				}
				iLGenerator.Emit(OpCodes.Ldarg_1);
				iLGenerator.Emit(OpCodes.Ldc_I4, i);
				if (isByRef && !isValueType)
				{
					iLGenerator.Emit(OpCodes.Ldelema, typeof(object));
					continue;
				}
				iLGenerator.Emit(OpCodes.Ldelem_Ref);
				if (!isValueType)
				{
					continue;
				}
				if (!isByRef || !directBoxValueAccess)
				{
					iLGenerator.Emit(OpCodes.Unbox_Any, type);
					if (isByRef)
					{
						iLGenerator.Emit(OpCodes.Box, type);
						iLGenerator.Emit(OpCodes.Dup);
						iLGenerator.Emit(OpCodes.Unbox, type);
						if (flag)
						{
							flag = false;
							throw new NotImplementedException("No idea how to implement this...");
						}
						iLGenerator.Emit(OpCodes.Stloc_0);
						iLGenerator.Emit(OpCodes.Stelem_Ref);
						iLGenerator.Emit(OpCodes.Ldloc_0);
					}
				}
				else
				{
					iLGenerator.Emit(OpCodes.Unbox, type);
				}
			}
			if (method.IsConstructor)
			{
				iLGenerator.Emit(OpCodes.Newobj, method as ConstructorInfo);
			}
			else if (method.IsFinal || !method.IsVirtual || forceNonVirtcall)
			{
				iLGenerator.Emit(OpCodes.Call, method as MethodInfo);
			}
			else
			{
				iLGenerator.Emit(OpCodes.Callvirt, method as MethodInfo);
			}
			Type type2 = (method.IsConstructor ? method.DeclaringType : (method as MethodInfo).ReturnType);
			if ((object)type2 != typeof(void))
			{
				if (type2.IsValueType)
				{
					iLGenerator.Emit(OpCodes.Box, type2);
				}
			}
			else
			{
				iLGenerator.Emit(OpCodes.Ldnull);
			}
			iLGenerator.Emit(OpCodes.Ret);
			return (FastReflectionDelegate)dynamicMethod.CreateDelegate(typeof(FastReflectionDelegate));
		}

		public static Func<T, F> CreateFastFieldGetter<T, F>(FieldInfo fieldInfo)
		{
			if ((object)fieldInfo == null)
			{
				throw new ArgumentNullException("fieldInfo");
			}
			if (!typeof(F).IsAssignableFrom(fieldInfo.FieldType))
			{
				throw new ArgumentException("FieldInfo type does not match return type.");
			}
			if ((object)typeof(T) != typeof(object) && ((object)fieldInfo.DeclaringType == null || !fieldInfo.DeclaringType.IsAssignableFrom(typeof(T))))
			{
				throw new MissingFieldException(typeof(T).Name, fieldInfo.Name);
			}
			DynamicMethod dynamicMethod = new DynamicMethod("FastReflection<" + typeof(T).FullName + ".Get_" + fieldInfo.Name + ">", typeof(F), new Type[1] { typeof(T) }, fieldInfo.DeclaringType.Module, skipVisibility: true);
			ILGenerator iLGenerator = dynamicMethod.GetILGenerator();
			if (!fieldInfo.IsStatic)
			{
				iLGenerator.Emit(OpCodes.Ldarg_0);
				iLGenerator.Emit(OpCodes.Castclass, fieldInfo.DeclaringType);
			}
			iLGenerator.Emit(fieldInfo.IsStatic ? OpCodes.Ldsfld : OpCodes.Ldfld, fieldInfo);
			if (fieldInfo.FieldType.IsValueType != typeof(F).IsValueType)
			{
				iLGenerator.Emit(OpCodes.Box, fieldInfo.FieldType);
			}
			iLGenerator.Emit(OpCodes.Ret);
			return (Func<T, F>)dynamicMethod.CreateDelegate(typeof(Func<T, F>));
		}

		public static Action<T, F> CreateFastFieldSetter<T, F>(FieldInfo fieldInfo)
		{
			if ((object)fieldInfo == null)
			{
				throw new ArgumentNullException("fieldInfo");
			}
			if (!typeof(F).IsAssignableFrom(fieldInfo.FieldType))
			{
				throw new ArgumentException("FieldInfo type does not match argument type.");
			}
			if ((object)typeof(T) != typeof(object) && ((object)fieldInfo.DeclaringType == null || !fieldInfo.DeclaringType.IsAssignableFrom(typeof(T))))
			{
				throw new MissingFieldException(typeof(T).Name, fieldInfo.Name);
			}
			DynamicMethod dynamicMethod = new DynamicMethod("FastReflection<" + typeof(T).FullName + ".Set_" + fieldInfo.Name + ">", null, new Type[2]
			{
				typeof(T),
				typeof(F)
			}, fieldInfo.DeclaringType.Module, skipVisibility: true);
			ILGenerator iLGenerator = dynamicMethod.GetILGenerator();
			if (!fieldInfo.IsStatic)
			{
				iLGenerator.Emit(OpCodes.Ldarg_0);
				iLGenerator.Emit(OpCodes.Castclass, fieldInfo.DeclaringType);
			}
			iLGenerator.Emit(OpCodes.Ldarg_1);
			if ((object)fieldInfo.FieldType != typeof(F))
			{
				if (fieldInfo.FieldType.IsValueType != typeof(F).IsValueType)
				{
					if (fieldInfo.FieldType.IsValueType)
					{
						iLGenerator.Emit(OpCodes.Unbox, fieldInfo.FieldType);
					}
					else
					{
						iLGenerator.Emit(OpCodes.Box, fieldInfo.FieldType);
					}
				}
				else
				{
					iLGenerator.Emit(OpCodes.Castclass, fieldInfo.FieldType);
				}
			}
			iLGenerator.Emit(fieldInfo.IsStatic ? OpCodes.Stsfld : OpCodes.Stfld, fieldInfo);
			iLGenerator.Emit(OpCodes.Ret);
			return (Action<T, F>)dynamicMethod.CreateDelegate(typeof(Action<T, F>));
		}
	}
	public static class TimeHelper
	{
		public static float realtimeSinceStartup => Time.realtimeSinceStartup;
	}
	public class UnityObjectReferenceComparer : IEqualityComparer<object>
	{
		public static readonly UnityObjectReferenceComparer Default = new UnityObjectReferenceComparer();

		public new bool Equals(object x, object y)
		{
			return x == y;
		}

		public int GetHashCode(object obj)
		{
			return obj.GetHashCode();
		}
	}
	public class WeakReference<T> : WeakReference where T : class
	{
		public new T Target => (T)base.Target;

		public static WeakReference<T> Create(T target)
		{
			if (target == null)
			{
				return WeakNullReference<T>.Singleton;
			}
			return new WeakReference<T>(target);
		}

		protected WeakReference(T target)
			: base(target, trackResurrection: false)
		{
		}
	}
	internal class WeakNullReference<T> : WeakReference<T> where T : class
	{
		public static readonly WeakNullReference<T> Singleton = new WeakNullReference<T>();

		public override bool IsAlive => true;

		private WeakNullReference()
			: base((T)null)
		{
		}
	}
	internal sealed class WeakKeyReference<T> : WeakReference<T> where T : class
	{
		public readonly int HashCode;

		public WeakKeyReference(T key, WeakKeyComparer<T> comparer)
			: base(key)
		{
			HashCode = comparer.GetHashCode(key);
		}
	}
	internal sealed class WeakKeyComparer<T> : IEqualityComparer<object> where T : class
	{
		private IEqualityComparer<T> comparer;

		internal WeakKeyComparer(IEqualityComparer<T> comparer)
		{
			if (comparer == null)
			{
				comparer = EqualityComparer<T>.Default;
			}
			this.comparer = comparer;
		}

		public int GetHashCode(object obj)
		{
			if (obj is WeakKeyReference<T> weakKeyReference)
			{
				return weakKeyReference.HashCode;
			}
			return comparer.GetHashCode((T)obj);
		}

		public new bool Equals(object x, object y)
		{
			bool isDead;
			T target = GetTarget(x, out isDead);
			bool isDead2;
			T target2 = GetTarget(y, out isDead2);
			if (isDead)
			{
				if (!isDead2)
				{
					return false;
				}
				return x == y;
			}
			if (isDead2)
			{
				return false;
			}
			return comparer.Equals(target, target2);
		}

		private static T GetTarget(object obj, out bool isDead)
		{
			T result;
			if (obj is WeakKeyReference<T> weakKeyReference)
			{
				result = weakKeyReference.Target;
				isDead = !weakKeyReference.IsAlive;
			}
			else
			{
				result = (T)obj;
				isDead = false;
			}
			return result;
		}
	}
	public sealed class WeakDictionary<TKey, TValue> : BaseDictionary<TKey, TValue> where TKey : class
	{
		private Dictionary<object, TValue> dictionary;

		private WeakKeyComparer<TKey> comparer;

		public override int Count => dictionary.Count;

		public WeakDictionary()
			: this(0, (IEqualityComparer<TKey>)null)
		{
		}

		public WeakDictionary(int capacity)
			: this(capacity, (IEqualityComparer<TKey>)null)
		{
		}

		public WeakDictionary(IEqualityComparer<TKey> comparer)
			: this(0, comparer)
		{
		}

		public WeakDictionary(int capacity, IEqualityComparer<TKey> comparer)
		{
			this.comparer = new WeakKeyComparer<TKey>(comparer);
			dictionary = new Dictionary<object, TValue>(capacity, this.comparer);
		}

		public override void Add(TKey key, TValue value)
		{
			if (key == null)
			{
				throw new ArgumentNullException("key");
			}
			WeakReference<TKey> key2 = new WeakKeyReference<TKey>(key, comparer);
			dictionary.Add(key2, value);
		}

		public override bool ContainsKey(TKey key)
		{
			return dictionary.ContainsKey(key);
		}

		public override bool Remove(TKey key)
		{
			return dictionary.Remove(key);
		}

		public override bool TryGetValue(TKey key, out TValue value)
		{
			if (dictionary.TryGetValue(key, out value))
			{
				return true;
			}
			value = default(TValue);
			return false;
		}

		protected override void SetValue(TKey key, TValue value)
		{
			WeakReference<TKey> key2 = new WeakKeyReference<TKey>(key, comparer);
			dictionary[key2] = value;
		}

		public override void Clear()
		{
			dictionary.Clear();
		}

		public override IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
		{
			foreach (KeyValuePair<object, TValue> item in dictionary)
			{
				WeakReference<TKey> obj = (WeakReference<TKey>)item.Key;
				TValue value = item.Value;
				TKey target = obj.Target;
				if (obj.IsAlive)
				{
					yield return new KeyValuePair<TKey, TValue>(target, value);
				}
			}
		}

		public void RemoveCollectedEntries()
		{
			List<object> list = null;
			foreach (KeyValuePair<object, TValue> item in dictionary)
			{
				WeakReference<TKey> weakReference = (WeakReference<TKey>)item.Key;
				if (!weakReference.IsAlive)
				{
					if (list == null)
					{
						list = new List<object>();
					}
					list.Add(weakReference);
				}
			}
			if (list == null)
			{
				return;
			}
			foreach (object item2 in list)
			{
				dictionary.Remove(item2);
			}
		}
	}
	[DebuggerDisplay("Count = {Count}")]
	[DebuggerTypeProxy("System.Collections.Generic.Mscorlib_DictionaryDebugView`2,mscorlib,Version=2.0.0.0,Culture=neutral,PublicKeyToken=b77a5c561934e089")]
	public abstract class BaseDictionary<TKey, TValue> : IDictionary<TKey, TValue>, ICollection<KeyValuePair<TKey, TValue>>, IEnumerable<KeyValuePair<TKey, TValue>>, IEnumerable
	{
		private abstract class Collection<T> : ICollection<T>, IEnumerable<T>, IEnumerable
		{
			protected readonly IDictionary<TKey, TValue> dictionary;

			public int Count => dictionary.Count;

			public bool IsReadOnly => true;

			protected Collection(IDictionary<TKey, TValue> dictionary)
			{
				this.dictionary = dictionary;
			}

			public void CopyTo(T[] array, int arrayIndex)
			{
				BaseDictionary<TKey, TValue>.Copy((ICollection<T>)this, array, arrayIndex);
			}

			public virtual bool Contains(T item)
			{
				using (IEnumerator<T> enumerator = GetEnumerator())
				{
					while (enumerator.MoveNext())
					{
						T current = enumerator.Current;
						if (EqualityComparer<T>.Default.Equals(current, item))
						{
							return true;
						}
					}
				}
				return false;
			}

			public IEnumerator<T> GetEnumerator()
			{
				foreach (KeyValuePair<TKey, TValue> item in dictionary)
				{
					yield return GetItem(item);
				}
			}

			protected abstract T GetItem(KeyValuePair<TKey, TValue> pair);

			public bool Remove(T item)
			{
				throw new NotSupportedException("Collection is read-only.");
			}

			public void Add(T item)
			{
				throw new NotSupportedException("Collection is read-only.");
			}

			public void Clear()
			{
				throw new NotSupportedException("Collection is read-only.");
			}

			IEnumerator IEnumerable.GetEnumerator()
			{
				return GetEnumerator();
			}
		}

		[DebuggerDisplay("Count = {Count}")]
		[DebuggerTypeProxy("System.Collections.Generic.Mscorlib_DictionaryKeyCollectionDebugView`2,mscorlib,Version=2.0.0.0,Culture=neutral,PublicKeyToken=b77a5c561934e089")]
		private class KeyCollection : Collection<TKey>
		{
			public KeyCollection(IDictionary<TKey, TValue> dictionary)
				: base(dictionary)
			{
			}

			protected override TKey GetItem(KeyValuePair<TKey, TValue> pair)
			{
				return pair.Key;
			}

			public override bool Contains(TKey item)
			{
				return dictionary.ContainsKey(item);
			}
		}

		[DebuggerDisplay("Count = {Count}")]
		[DebuggerTypeProxy("System.Collections.Generic.Mscorlib_DictionaryValueCollectionDebugView`2,mscorlib,Version=2.0.0.0,Culture=neutral,PublicKeyToken=b77a5c561934e089")]
		private class ValueCollection : Collection<TValue>
		{
			public ValueCollection(IDictionary<TKey, TValue> dictionary)
				: base(dictionary)
			{
			}

			protected override TValue GetItem(KeyValuePair<TKey, TValue> pair)
			{
				return pair.Value;
			}
		}

		private const string PREFIX = "System.Collections.Generic.Mscorlib_";

		private const string SUFFIX = ",mscorlib,Version=2.0.0.0,Culture=neutral,PublicKeyToken=b77a5c561934e089";

		private KeyCollection keys;

		private ValueCollection values;

		public abstract int Count { get; }

		public bool IsReadOnly => false;

		public ICollection<TKey> Keys
		{
			get
			{
				if (keys == null)
				{
					keys = new KeyCollection(this);
				}
				return keys;
			}
		}

		public ICollection<TValue> Values
		{
			get
			{
				if (values == null)
				{
					values = new ValueCollection(this);
				}
				return values;
			}
		}

		public TValue this[TKey key]
		{
			get
			{
				if (!TryGetValue(key, out var value))
				{
					throw new KeyNotFoundException();
				}
				return value;
			}
			set
			{
				SetValue(key, value);
			}
		}

		public abstract void Clear();

		public abstract void Add(TKey key, TValue value);

		public abstract bool ContainsKey(TKey key);

		public abstract bool Remove(TKey key);

		public abstract bool TryGetValue(TKey key, out TValue value);

		public abstract IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator();

		protected abstract void SetValue(TKey key, TValue value);

		public void Add(KeyValuePair<TKey, TValue> item)
		{
			Add(item.Key, item.Value);
		}

		public bool Contains(KeyValuePair<TKey, TValue> item)
		{
			if (!TryGetValue(item.Key, out var value))
			{
				return false;
			}
			return EqualityComparer<TValue>.Default.Equals(value, item.Value);
		}

		public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
		{
			Copy(this, array, arrayIndex);
		}

		public bool Remove(KeyValuePair<TKey, TValue> item)
		{
			if (!Contains(item))
			{
				return false;
			}
			return Remove(item.Key);
		}

		IEnumerator IEnumerable.GetEnumerator()
		{
			return GetEnumerator();
		}

		private static void Copy<T>(ICollection<T> source, T[] array, int arrayIndex)
		{
			if (array == null)
			{
				throw new ArgumentNullException("array");
			}
			if (arrayIndex < 0 || arrayIndex > array.Length)
			{
				throw new ArgumentOutOfRangeException("arrayIndex");
			}
			if (array.Length - arrayIndex < source.Count)
			{
				throw new ArgumentException("Destination array is not large enough. Check array.Length and arrayIndex.");
			}
			foreach (T item in source)
			{
				array[arrayIndex++] = item;
			}
		}
	}
}
namespace XUnity.Common.MonoMod
{
	public static class DetourExtensions
	{
		public static T GenerateTrampolineEx<T>(this object detour)
		{
			return (T)(from x in detour.GetType().GetMethods()
				where x.Name == "GenerateTrampoline" && x.IsGenericMethod
				select x).FirstOrDefault().MakeGenericMethod(typeof(T)).Invoke(detour, null);
		}
	}
}
namespace XUnity.Common.Logging
{
	internal class ConsoleLogger : XuaLogger
	{
		public ConsoleLogger(string source)
			: base(source)
		{
		}

		protected override void Log(LogLevel level, string message)
		{
			Console.WriteLine(GetDefaultPrefix(level) + " " + message);
		}
	}
	public enum LogLevel
	{
		Debug,
		Info,
		Warn,
		Error
	}
	internal class ModLoaderSpecificLogger : XuaLogger
	{
		public static class BepInExLogLevel
		{
			public const int None = 0;

			public const int Fatal = 1;

			public const int Error = 2;

			public const int Warning = 4;

			public const int Message = 8;

			public const int Info = 16;

			public const int Debug = 32;

			public const int All = 63;
		}

		private static Action<LogLevel, string> _logMethod;

		public ModLoaderSpecificLogger(string source)
			: base(source)
		{
			if (_logMethod != null)
			{
				return;
			}
			BindingFlags bindingAttr = BindingFlags.Static | BindingFlags.Public;
			BindingFlags bindingAttr2 = BindingFlags.Instance | BindingFlags.Public;
			Type type = Type.GetType("BepInEx.Logging.LogLevel, BepInEx", throwOnError: false) ?? Type.GetType("BepInEx.Logging.LogLevel, BepInEx.Core", throwOnError: false);
			if ((object)type != null)
			{
				if ((object)(Type.GetType("BepInEx.Logging.ManualLogSource, BepInEx", throwOnError: false) ?? Type.GetType("BepInEx.Logging.ManualLogSource, BepInEx.Core", throwOnError: false)) != null)
				{
					MethodInfo method = (Type.GetType("BepInEx.Logging.Logger, BepInEx", throwOnError: false) ?? Type.GetType("BepInEx.Logging.Logger, BepInEx.Core", throwOnError: false)).GetMethod("CreateLogSource", bindingAttr, null, new Type[1] { typeof(string) }, null);
					object logInstance2 = method.Invoke(null, new object[1] { base.Source });
					MethodInfo method2 = logInstance2.GetType().GetMethod("Log", bindingAttr2, null, new Type[2]
					{
						type,
						typeof(object)
					}, null);
					FastReflectionDelegate log2 = method2.CreateFastDelegate();
					_logMethod = delegate(LogLevel level, string msg)
					{
						int num2 = Convert(level);
						log2(logInstance2, num2, msg);
					};
				}
				else
				{
					Type type2 = Type.GetType("BepInEx.Logger, BepInEx", throwOnError: false);
					object logInstance = type2.GetProperty("CurrentLogger", bindingAttr).GetValue(null, null);
					MethodInfo method3 = logInstance.GetType().GetMethod("Log", bindingAttr2, null, new Type[2]
					{
						type,
						typeof(object)
					}, null);
					FastReflectionDelegate log = method3.CreateFastDelegate();
					_logMethod = delegate(LogLevel level, string msg)
					{
						int num = Convert(level);
						log(logInstance, num, msg);
					};
				}
			}
			else
			{
				Type type3 = Type.GetType("MelonLoader.MelonLogger, MelonLoader.ModHandler", throwOnError: false);
				if ((object)type3 != null)
				{
					MethodInfo method4 = type3.GetMethod("Log", bindingAttr, null, new Type[2]
					{
						typeof(ConsoleColor),
						typeof(string)
					}, null);
					MethodInfo method5 = type3.GetMethod("Log", bindingAttr, null, new Type[1] { typeof(string) }, null);
					MethodInfo method6 = type3.GetMethod("LogWarning", bindingAttr, null, new Type[1] { typeof(string) }, null);
					MethodInfo method7 = type3.GetMethod("LogError", bindingAttr, null, new Type[1] { typeof(string) }, null);
					FastReflectionDelegate logDebug = method4.CreateFastDelegate();
					FastReflectionDelegate logInfo = method5.CreateFastDelegate();
					FastReflectionDelegate logWarning = method6.CreateFastDelegate();
					FastReflectionDelegate logError = method7.CreateFastDelegate();
					_logMethod = delegate(LogLevel level, string msg)
					{
						switch (level)
						{
						case LogLevel.Debug:
							logDebug(null, ConsoleColor.Gray, msg);
							break;
						case LogLevel.Info:
							logInfo(null, msg);
							break;
						case LogLevel.Warn:
							logWarning(null, msg);
							break;
						case LogLevel.Error:
							logError(null, msg);
							break;
						default:
							throw new ArgumentException("level");
						}
					};
				}
			}
			if (_logMethod != null)
			{
				return;
			}
			throw new Exception("Did not recognize any mod loader!");
		}

		protected override void Log(LogLevel level, string message)
		{
			_logMethod(level, message);
		}

		public static int Convert(LogLevel level)
		{
			return level switch
			{
				LogLevel.Debug => 32, 
				LogLevel.Info => 16, 
				LogLevel.Warn => 4, 
				LogLevel.Error => 2, 
				_ => 0, 
			};
		}
	}
	public abstract class XuaLogger
	{
		private static XuaLogger _default;

		private static XuaLogger _common;

		private static XuaLogger _resourceRedirector;

		public static XuaLogger AutoTranslator
		{
			get
			{
				if (_default == null)
				{
					_default = CreateLogger("XUnity.AutoTranslator");
				}
				return _default;
			}
			set
			{
				_default = value ?? throw new ArgumentNullException("value");
			}
		}

		public static XuaLogger Common
		{
			get
			{
				if (_common == null)
				{
					_common = CreateLogger("XUnity.Common");
				}
				return _common;
			}
			set
			{
				_common = value ?? throw new ArgumentNullException("value");
			}
		}

		public static XuaLogger ResourceRedirector
		{
			get
			{
				if (_resourceRedirector == null)
				{
					_resourceRedirector = CreateLogger("XUnity.ResourceRedirector");
				}
				return _resourceRedirector;
			}
			set
			{
				_resourceRedirector = value ?? throw new ArgumentNullException("value");
			}
		}

		public string Source { get; set; }

		internal static XuaLogger CreateLogger(string source)
		{
			try
			{
				return new ModLoaderSpecificLogger(source);
			}
			catch (Exception)
			{
				return new ConsoleLogger(source);
			}
		}

		public XuaLogger(string source)
		{
			Source = source;
		}

		public void Error(Exception e, string message)
		{
			Log(LogLevel.Error, message + Environment.NewLine + e);
		}

		public void Error(string message)
		{
			Log(LogLevel.Error, message);
		}

		public void Warn(Exception e, string message)
		{
			Log(LogLevel.Warn, message + Environment.NewLine + e);
		}

		public void Warn(string message)
		{
			Log(LogLevel.Warn, message);
		}

		public void Info(Exception e, string message)
		{
			Log(LogLevel.Info, message + Environment.NewLine + e);
		}

		public void Info(string message)
		{
			Log(LogLevel.Info, message);
		}

		public void Debug(Exception e, string message)
		{
			Log(LogLevel.Debug, message + Environment.NewLine + e);
		}

		public void Debug(string message)
		{
			Log(LogLevel.Debug, message);
		}

		protected abstract void Log(LogLevel level, string message);

		protected string GetDefaultPrefix(LogLevel level)
		{
			return level switch
			{
				LogLevel.Debug => "[DEBUG][" + Source + "]: ", 
				LogLevel.Info => "[INFO][" + Source + "]: ", 
				LogLevel.Warn => "[WARN][" + Source + "]: ", 
				LogLevel.Error => "[ERROR][" + Source + "]: ", 
				_ => "[UNKNOW][" + Source + "]: ", 
			};
		}
	}
}
namespace XUnity.Common.Harmony
{
	public static class AccessToolsShim
	{
		private static readonly BindingFlags All;

		private static readonly Func<Type, string, Type[], Type[], MethodInfo> AccessTools_Method;

		private static readonly Func<Type, string, PropertyInfo> AccessTools_Property;

		static AccessToolsShim()
		{
			All = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;
			MethodInfo method = ClrTypes.AccessTools.GetMethod("Method", All, null, new Type[4]
			{
				typeof(Type),
				typeof(string),
				typeof(Type[]),
				typeof(Type[])
			}, null);
			MethodInfo? method2 = ClrTypes.AccessTools.GetMethod("Property", All, null, new Type[2]
			{
				typeof(Type),
				typeof(string)
			}, null);
			AccessTools_Method = (Func<Type, string, Type[], Type[], MethodInfo>)ExpressionHelper.CreateTypedFastInvoke(method);
			AccessTools_Property = (Func<Type, string, PropertyInfo>)ExpressionHelper.CreateTypedFastInvoke(method2);
		}

		public static MethodInfo Method(Type type, string name, params Type[] parameters)
		{
			return AccessTools_Method(type, name, parameters, null);
		}

		public static PropertyInfo Property(Type type, string name)
		{
			return AccessTools_Property(type, name);
		}
	}
}
namespace XUnity.Common.Extensions
{
	public static class ExceptionExtensions
	{
		public static TException FirstInnerExceptionOfType<TException>(this Exception e) where TException : Exception
		{
			for (Exception ex = e; ex != null; ex = ex.InnerException)
			{
				if (ex is TException)
				{
					return (TException)ex;
				}
			}
			return null;
		}
	}
	public static class ObjectExtensions
	{
		public static Type GetUnityType(this object obj)
		{
			return obj.GetType();
		}

		public static bool TryCastTo<TObject>(this object obj, out TObject castedObject)
		{
			if (obj is TObject val)
			{
				castedObject = val;
				return true;
			}
			castedObject = default(TObject);
			return false;
		}
	}
	public static class StreamExtensions
	{
		public static byte[] ReadFully(this Stream stream, int initialLength)
		{
			if (initialLength < 1)
			{
				initialLength = 32768;
			}
			byte[] array = new byte[initialLength];
			int num = 0;
			int num2;
			while ((num2 = stream.Read(array, num, array.Length - num)) > 0)
			{
				num += num2;
				if (num == array.Length)
				{
					int num3 = stream.ReadByte();
					if (num3 == -1)
					{
						return array;
					}
					byte[] array2 = new byte[array.Length * 2];
					Array.Copy(array, array2, array.Length);
					array2[num] = (byte)num3;
					array = array2;
					num++;
				}
			}
			byte[] array3 = new byte[num];
			Array.Copy(array, array3, num);
			return array3;
		}
	}
	public static class StringExtensions
	{
		private static readonly HashSet<char> InvalidFileNameChars = new HashSet<char>(Path.GetInvalidFileNameChars());

		public static string UseCorrectDirectorySeparators(this string path)
		{
			if (Path.DirectorySeparatorChar == '\\')
			{
				return path.Replace('/', Path.DirectorySeparatorChar);
			}
			if (Path.DirectorySeparatorChar == '/')
			{
				return path.Replace('\\', Path.DirectorySeparatorChar);
			}
			return path;
		}

		public static bool IsNullOrWhiteSpace(this string value)
		{
			if (value == null)
			{
				return true;
			}
			for (int i = 0; i < value.Length; i++)
			{
				if (!char.IsWhiteSpace(value[i]))
				{
					return false;
				}
			}
			return true;
		}

		public static string MakeRelativePath(this string fullOrRelativePath, string basePath)
		{
			StringBuilder stringBuilder = new StringBuilder();
			int i = 0;
			bool flag = false;
			string[] array = basePath.Split(':', '\\', '/');
			List<string> list = fullOrRelativePath.Split(':', '\\', '/').ToList();
			if (array.Length == 0 || list.Count <= 0 || array[0] != list[0])
			{
				flag = true;
			}
			bool flag2 = false;
			for (int j = 0; j < list.Count; j++)
			{
				if (list[j] == "..")
				{
					if (flag2)
					{
						int num = j - 1;
						if (num >= 0)
						{
							list.RemoveAt(j);
							list.RemoveAt(num);
							j -= 2;
						}
					}
				}
				else
				{
					flag2 = true;
				}
			}
			if (!flag)
			{
				for (i = 1; i < array.Length && !(array[i] != list[i]); i++)
				{
				}
				for (int k = 0; k < array.Length - i; k++)
				{
					char directorySeparatorChar = Path.DirectorySeparatorChar;
					stringBuilder.Append(".." + directorySeparatorChar);
				}
			}
			for (int l = i; l < list.Count - 1; l++)
			{
				string value = list[l];
				stringBuilder.Append(value).Append(Path.DirectorySeparatorChar);
			}
			string value2 = list[^1];
			stringBuilder.Append(value2);
			return stringBuilder.ToString();
		}

		public static string SanitizeForFileSystem(this string path)
		{
			StringBuilder stringBuilder = new StringBuilder(path.Length);
			foreach (char c in path)
			{
				if (!InvalidFileNameChars.Contains(c))
				{
					stringBuilder.Append(c);
				}
			}
			return stringBuilder.ToString();
		}

		public static string SplitToLines(this string text, int maxStringLength, params char[] splitOnCharacters)
		{
			StringBuilder stringBuilder = new StringBuilder();
			int num;
			for (int i = 0; text.Length > i; i += num)
			{
				if (i != 0)
				{
					stringBuilder.Append('\n');
				}
				num = ((i + maxStringLength <= text.Length) ? text.Substring(i, maxStringLength).LastIndexOfAny(splitOnCharacters) : (text.Length - i));
				num = ((num == -1) ? maxStringLength : num);
				stringBuilder.Append(text.Substring(i, num).Trim());
			}
			return stringBuilder.ToString();
		}

		public static bool StartsWithStrict(this string str, string prefix)
		{
			int num = Math.Min(str.Length, prefix.Length);
			if (num < prefix.Length)
			{
				return false;
			}
			for (int i = 0; i < num; i++)
			{
				if (str[i] != prefix[i])
				{
					return false;
				}
			}
			return true;
		}

		public static string GetBetween(this string strSource, string strStart, string strEnd)
		{
			int num = strSource.IndexOf(strStart);
			if (num != -1)
			{
				num += strStart.Length;
				int num2 = strSource.IndexOf(strEnd, num);
				if (num2 > num)
				{
					return strSource.Substring(num, num2 - num);
				}
			}
			return string.Empty;
		}

		public static bool RemindsOf(this string that, string other)
		{
			if (!that.StartsWith(other) && !other.StartsWith(that) && !that.EndsWith(other))
			{
				return other.EndsWith(that);
			}
			return true;
		}
	}
}
namespace XUnity.Common.Constants
{
	public static class ClrTypes
	{
		public static readonly Type AccessTools = FindTypeStrict("Harmony.AccessTools, 0Harmony") ?? FindTypeStrict("HarmonyLib.AccessTools, 0Harmony") ?? FindTypeStrict("Harmony.AccessTools, MelonLoader.ModHandler") ?? FindTypeStrict("HarmonyLib.AccessTools, MelonLoader.ModHandler");

		public static readonly Type HarmonyMethod = FindTypeStrict("Harmony.HarmonyMethod, 0Harmony") ?? FindTypeStrict("HarmonyLib.HarmonyMethod, 0Harmony") ?? FindTypeStrict("Harmony.HarmonyMethod, MelonLoader.ModHandler") ?? FindTypeStrict("HarmonyLib.HarmonyMethod, MelonLoader.ModHandler");

		public static readonly Type HarmonyInstance = FindTypeStrict("Harmony.HarmonyInstance, 0Harmony") ?? FindTypeStrict("Harmony.HarmonyInstance, MelonLoader.ModHandler");

		public static readonly Type Harmony = FindTypeStrict("HarmonyLib.Harmony, 0Harmony") ?? FindTypeStrict("HarmonyLib.Harmony, MelonLoader.ModHandler");

		public static readonly Type Hook = FindTypeStrict("MonoMod.RuntimeDetour.Hook, MonoMod.RuntimeDetour");

		public static readonly Type Detour = FindTypeStrict("MonoMod.RuntimeDetour.Detour, MonoMod.RuntimeDetour");

		public static readonly Type NativeDetour = FindTypeStrict("MonoMod.RuntimeDetour.NativeDetour, MonoMod.RuntimeDetour");

		public static readonly Type DynamicMethodDefinition = FindTypeStrict("MonoMod.Utils.DynamicMethodDefinition, MonoMod.Utils");

		public static readonly Type Imports = FindTypeStrict("MelonLoader.Imports, MelonLoader.ModHandler");

		public static readonly Type MethodBase = FindType("System.Reflection.MethodBase");

		public static readonly Type Task = FindType("System.Threading.Tasks.Task");

		private static Type FindType(string name)
		{
			Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
			foreach (Assembly assembly in assemblies)
			{
				try
				{
					Type type = assembly.GetType(name, throwOnError: false);
					if ((object)type != null)
					{
						return type;
					}
				}
				catch
				{
				}
			}
			return null;
		}

		private static Type FindTypeStrict(string name)
		{
			return Type.GetType(name, throwOnError: false);
		}
	}
	public class TypeContainer
	{
		public Type ClrType { get; }

		public Type UnityType { get; }

		public TypeContainer(Type type)
		{
			UnityType = type;
			ClrType = type;
		}

		public bool IsAssignableFrom(Type unityType)
		{
			if ((object)UnityType != null)
			{
				return UnityType.IsAssignableFrom(unityType);
			}
			return false;
		}
	}
	public static class UnityFeatures
	{
		private static readonly BindingFlags All;

		public static bool SupportsMouseScrollDelta { get; }

		public static bool SupportsClipboard { get; }

		public static bool SupportsCustomYieldInstruction { get; }

		public static bool SupportsSceneManager { get; }

		public static bool SupportsWaitForSecondsRealtime { get; set; }

		static UnityFeatures()
		{
			All = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;
			SupportsMouseScrollDelta = false;
			SupportsClipboard = false;
			SupportsCustomYieldInstruction = false;
			SupportsSceneManager = false;
			SupportsWaitForSecondsRealtime = false;
			try
			{
				SupportsClipboard = (object)UnityTypes.TextEditor?.ClrType.GetProperty("text")?.GetSetMethod() != null;
			}
			catch (Exception)
			{
			}
			try
			{
				SupportsCustomYieldInstruction = UnityTypes.CustomYieldInstruction != null;
			}
			catch (Exception)
			{
			}
			try
			{
				SupportsSceneManager = UnityTypes.Scene != null && UnityTypes.SceneManager != null && (object)UnityTypes.SceneManager.ClrType.GetMethod("add_sceneLoaded", All) != null;
			}
			catch (Exception)
			{
			}
			try
			{
				SupportsMouseScrollDelta = (object)UnityTypes.Input?.ClrType.GetProperty("mouseScrollDelta") != null;
			}
			catch (Exception)
			{
			}
			try
			{
				SupportsWaitForSecondsRealtime = UnityTypes.WaitForSecondsRealtime != null;
			}
			catch (Exception)
			{
			}
		}
	}
	public static class UnityTypes
	{
		public static class TMP_Settings_Properties
		{
			public static CachedProperty Version = TMP_Settings?.ClrType.CachedProperty("version");

			public static CachedProperty FallbackFontAssets = TMP_Settings?.ClrType.CachedProperty("fallbackFontAssets");
		}

		public static class TMP_FontAsset_Properties
		{
			public static CachedProperty Version = TMP_FontAsset?.ClrType.CachedProperty("version");
		}

		public static class AdvScenarioData_Properties
		{
			public static CachedProperty ScenarioLabels = AdvScenarioData?.ClrType.CachedProperty("ScenarioLabels");
		}

		public static class UguiNovelText_Properties
		{
			public static CachedProperty TextGenerator = UguiNovelText?.ClrType.CachedProperty("TextGenerator");
		}

		public static class UguiNovelText_Methods
		{
			public static CachedMethod SetAllDirty = UguiNovelText?.ClrType.CachedMethod("SetAllDirty");
		}

		public static class UguiNovelTextGenerator_Methods
		{
			public static CachedMethod Refresh = UguiNovelTextGenerator?.ClrType.CachedMethod("Refresh");
		}

		public static class AdvUguiMessageWindow_Properties
		{
			public static CachedProperty Text = AdvUguiMessageWindow?.ClrType.CachedProperty("Text");

			public static CachedProperty Engine = AdvUguiMessageWindow?.ClrType.CachedProperty("Engine");
		}

		public static class AdvUiMessageWindow_Fields
		{
			public static CachedField text = AdvUiMessageWindow?.ClrType.CachedField("text");

			public static CachedField nameText = AdvUiMessageWindow?.ClrType.CachedField("nameText");
		}

		public static class AdvUguiMessageWindow_Fields
		{
			public static FieldInfo text = AdvUguiMessageWindow?.ClrType.GetField("text", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);

			public static FieldInfo nameText = AdvUguiMessageWindow?.ClrType.GetField("nameText", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);

			public static FieldInfo engine = AdvUguiMessageWindow?.ClrType.GetField("engine", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
		}

		public static class AdvEngine_Properties
		{
			public static CachedProperty Page = AdvEngine?.ClrType.CachedProperty("Page");
		}

		public static class AdvPage_Methods
		{
			public static CachedMethod RemakeTextData = AdvPage?.ClrType.CachedMethod("RemakeTextData");

			public static CachedMethod RemakeText = AdvPage?.ClrType.CachedMethod("RemakeText");

			public static CachedMethod ChangeMessageWindowText = AdvPage?.ClrType.CachedMethod("ChangeMessageWindowText", typeof(string), typeof(string), typeof(string), typeof(string));
		}

		public static class UILabel_Properties
		{
			public static CachedProperty MultiLine = UILabel?.ClrType.CachedProperty("multiLine");

			public static CachedProperty OverflowMethod = UILabel?.ClrType.CachedProperty("overflowMethod");

			public static CachedProperty SpacingX = UILabel?.ClrType.CachedProperty("spacingX");

			public static CachedProperty UseFloatSpacing = UILabel?.ClrType.CachedProperty("useFloatSpacing");
		}

		public static class Text_Properties
		{
			public static CachedProperty Font = Text?.ClrType.CachedProperty("font");

			public static CachedProperty FontSize = Text?.ClrType.CachedProperty("fontSize");

			public static CachedProperty HorizontalOverflow = Text?.ClrType.CachedProperty("horizontalOverflow");

			public static CachedProperty VerticalOverflow = Text?.ClrType.CachedProperty("verticalOverflow");

			public static CachedProperty LineSpacing = Text?.ClrType.CachedProperty("lineSpacing");

			public static CachedProperty ResizeTextForBestFit = Text?.ClrType.CachedProperty("resizeTextForBestFit");

			public static CachedProperty ResizeTextMinSize = Text?.ClrType.CachedProperty("resizeTextMinSize");

			public static CachedProperty ResizeTextMaxSize = Text?.ClrType.CachedProperty("resizeTextMaxSize");
		}

		public static class InputField_Properties
		{
			public static CachedProperty Placeholder = InputField?.ClrType.CachedProperty("placeholder");
		}

		public static class TMP_InputField_Properties
		{
			public static CachedProperty Placeholder = TMP_InputField?.ClrType.CachedProperty("placeholder");
		}

		public static class Font_Properties
		{
			public static CachedProperty FontSize = Font?.ClrType.CachedProperty("fontSize");
		}

		public static class AssetBundle_Methods
		{
			public static CachedMethod LoadAll = AssetBundle?.ClrType.CachedMethod("LoadAll", typeof(Type));

			public static CachedMethod LoadAllAssets = AssetBundle?.ClrType.CachedMethod("LoadAllAssets", typeof(Type));

			public static CachedMethod LoadFromFile = AssetBundle?.ClrType.CachedMethod("LoadFromFile", typeof(string));

			public static CachedMethod CreateFromFile = AssetBundle?.ClrType.CachedMethod("CreateFromFile", typeof(string));
		}

		public static class TextExpansion_Methods
		{
			public static CachedMethod SetMessageType = TextExpansion?.ClrType.CachedMethod("SetMessageType");

			public static CachedMethod SkipTypeWriter = TextExpansion?.ClrType.CachedMethod("SkipTypeWriter");
		}

		public static class GameObject_Methods
		{
		}

		public static class TextMesh_Methods
		{
		}

		public static class Text_Methods
		{
		}

		public static class InputField_Methods
		{
		}

		public static class TMP_Text_Methods
		{
		}

		public static class TMP_InputField_Methods
		{
		}

		public static class TextMeshPro_Methods
		{
		}

		public static class TextMeshProUGUI_Methods
		{
		}

		public static class UILabel_Methods
		{
		}

		public static class UIRect_Methods
		{
		}

		public static class SceneManager_Methods
		{
			public static readonly Action<UnityAction<Scene, LoadSceneMode>> add_sceneLoaded = (Action<UnityAction<Scene, LoadSceneMode>>)ExpressionHelper.CreateTypedFastInvokeUnchecked(typeof(SceneManager).GetMethod("add_sceneLoaded", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[1] { typeof(UnityAction<Scene, LoadSceneMode>) }, null));
		}

		public static class Texture2D_Methods
		{
			public static readonly Func<Texture2D, byte[], bool> LoadImage = (Func<Texture2D, byte[], bool>)ExpressionHelper.CreateTypedFastInvokeUnchecked(typeof(Texture2D).GetMethod("LoadImage", BindingFlags.Instance | BindingFlags.Public, null, new Type[1] { typeof(byte[]) }, null));

			public static readonly Func<Texture2D, byte[]> EncodeToPNG = (Func<Texture2D, byte[]>)ExpressionHelper.CreateTypedFastInvokeUnchecked(typeof(Texture2D).GetMethod("EncodeToPNG", BindingFlags.Instance | BindingFlags.Public, null, new Type[0], null));
		}

		public static class ImageConversion_Methods
		{
			public static readonly Func<Texture2D, byte[], bool, bool> LoadImage = (Func<Texture2D, byte[], bool, bool>)ExpressionHelper.CreateTypedFastInvokeUnchecked(ImageConversion?.ClrType.GetMethod("LoadImage", BindingFlags.Static | BindingFlags.Public, null, new Type[3]
			{
				typeof(Texture2D),
				typeof(byte[]),
				typeof(bool)
			}, null));

			public static readonly Func<Texture2D, byte[]> EncodeToPNG = (Func<Texture2D, byte[]>)ExpressionHelper.CreateTypedFastInvokeUnchecked(ImageConversion?.ClrType.GetMethod("EncodeToPNG", BindingFlags.Static | BindingFlags.Public, null, new Type[1] { typeof(Texture2D) }, null));
		}

		public static readonly TypeContainer UILabel = FindType("UILabel");

		public static readonly TypeContainer UIWidget = FindType("UIWidget");

		public static readonly TypeContainer UIAtlas = FindType("UIAtlas");

		public static readonly TypeContainer UISprite = FindType("UISprite");

		public static readonly TypeContainer UITexture = FindType("UITexture");

		public static readonly TypeContainer UI2DSprite = FindType("UI2DSprite");

		public static readonly TypeContainer UIFont = FindType("UIFont");

		public static readonly TypeContainer UIPanel = FindType("UIPanel");

		public static readonly TypeContainer UIRect = FindType("UIRect");

		public static readonly TypeContainer UIInput = FindType("UIInput");

		public static readonly TypeContainer TextField = FindType("FairyGUI.TextField");

		public static readonly TypeContainer TMP_InputField = FindType("TMPro.TMP_InputField");

		public static readonly TypeContainer TMP_Text = FindType("TMPro.TMP_Text");

		public static readonly TypeContainer TextMeshProUGUI = FindType("TMPro.TextMeshProUGUI");

		public static readonly TypeContainer TextMeshPro = FindType("TMPro.TextMeshPro");

		public static readonly TypeContainer TMP_FontAsset = FindType("TMPro.TMP_FontAsset");

		public static readonly TypeContainer TMP_Settings = FindType("TMPro.TMP_Settings");

		public static readonly TypeContainer GameObject = FindType("UnityEngine.GameObject");

		public static readonly TypeContainer Transform = FindType("UnityEngine.Transform");

		public static readonly TypeContainer TextMesh = FindType("UnityEngine.TextMesh");

		public static readonly TypeContainer Text = FindType("UnityEngine.UI.Text");

		public static readonly TypeContainer Image = FindType("UnityEngine.UI.Image");

		public static readonly TypeContainer RawImage = FindType("UnityEngine.UI.RawImage");

		public static readonly TypeContainer MaskableGraphic = FindType("UnityEngine.UI.MaskableGraphic");

		public static readonly TypeContainer Graphic = FindType("UnityEngine.UI.Graphic");

		public static readonly TypeContainer GUIContent = FindType("UnityEngine.GUIContent");

		public static readonly TypeContainer WWW = FindType("UnityEngine.WWW");

		public static readonly TypeContainer InputField = FindType("UnityEngine.UI.InputField");

		public static readonly TypeContainer GUI = FindType("UnityEngine.GUI");

		public static readonly TypeContainer GUI_ToolbarButtonSize = FindType("UnityEngine.GUI+ToolbarButtonSize");

		public static readonly TypeContainer GUIStyle = FindType("UnityEngine.GUIStyle");

		public static readonly TypeContainer ImageConversion = FindType("UnityEngine.ImageConversion");

		public static readonly TypeContainer Texture2D = FindType("UnityEngine.Texture2D");

		public static readonly TypeContainer Texture = FindType("UnityEngine.Texture");

		public static readonly TypeContainer SpriteRenderer = FindType("UnityEngine.SpriteRenderer");

		public static readonly TypeContainer Sprite = FindType("UnityEngine.Sprite");

		public static readonly TypeContainer Object = FindType("UnityEngine.Object");

		public static readonly TypeContainer TextEditor = FindType("UnityEngine.TextEditor");

		public static readonly TypeContainer CustomYieldInstruction = FindType("UnityEngine.CustomYieldInstruction");

		public static readonly TypeContainer SceneManager = FindType("UnityEngine.SceneManagement.SceneManager");

		public static readonly TypeContainer Scene = FindType("UnityEngine.SceneManagement.Scene");

		public static readonly TypeContainer UnityEventBase = FindType("UnityEngine.Events.UnityEventBase");

		public static readonly TypeContainer BaseInvokableCall = FindType("UnityEngine.Events.BaseInvokableCall");

		public static readonly TypeContainer Font = FindType("UnityEngine.Font");

		public static readonly TypeContainer WaitForSecondsRealtime = FindType("UnityEngine.WaitForSecondsRealtime");

		public static readonly TypeContainer Input = FindType("UnityEngine.Input");

		public static readonly TypeContainer AssetBundleCreateRequest = FindType("UnityEngine.AssetBundleCreateRequest");

		public static readonly TypeContainer AssetBundle = FindType("UnityEngine.AssetBundle");

		public static readonly TypeContainer AssetBundleRequest = FindType("UnityEngine.AssetBundleRequest");

		public static readonly TypeContainer Resources = FindType("UnityEngine.Resources");

		public static readonly TypeContainer AsyncOperation = FindType("UnityEngine.AsyncOperation");

		public static readonly TypeContainer TextAsset = FindType("UnityEngine.TextAsset");

		public static readonly Type HorizontalWrapMode = FindClrType("UnityEngine.HorizontalWrapMode");

		public static readonly Type TextOverflowModes = FindClrType("TMPro.TextOverflowModes");

		public static readonly Type TextAlignmentOptions = FindClrType("TMPro.TextAlignmentOptions");

		public static readonly Type VerticalWrapMode = FindClrType("UnityEngine.VerticalWrapMode");

		public static readonly TypeContainer TextExpansion = FindType("UnityEngine.UI.TextExpansion");

		public static readonly TypeContainer Typewriter = FindType("Typewriter");

		public static readonly TypeContainer UguiNovelText = FindType("Utage.UguiNovelText");

		public static readonly TypeContainer UguiNovelTextGenerator = FindType("Utage.UguiNovelTextGenerator");

		public static readonly TypeContainer AdvEngine = FindType("Utage.AdvEngine");

		public static readonly TypeContainer AdvPage = FindType("Utage.AdvPage");

		public static readonly TypeContainer TextData = FindType("Utage.TextData");

		public static readonly TypeContainer AdvUguiMessageWindow = FindType("Utage.AdvUguiMessageWindow") ?? FindType("AdvUguiMessageWindow");

		public static readonly TypeContainer AdvUiMessageWindow = FindType("AdvUiMessageWindow");

		public static readonly TypeContainer AdvDataManager = FindType("Utage.AdvDataManager");

		public static readonly TypeContainer AdvScenarioData = FindType("Utage.AdvScenarioData");

		public static readonly TypeContainer AdvScenarioLabelData = FindType("Utage.AdvScenarioLabelData");

		public static readonly TypeContainer DicingTextures = FindType("Utage.DicingTextures");

		public static readonly TypeContainer DicingImage = FindType("Utage.DicingImage");

		public static readonly TypeContainer TextArea2D = FindType("Utage.TextArea2D");

		public static readonly TypeContainer CubismRenderer = FindType("Live2D.Cubism.Rendering.CubismRenderer");

		public static readonly TypeContainer TextWindow = FindType("Assets.System.Text.TextWindow");

		private static Type FindClrType(string name)
		{
			Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
			foreach (Assembly assembly in assemblies)
			{
				try
				{
					Type type = assembly.GetType(name, throwOnError: false);
					if ((object)type != null)
					{
						return type;
					}
				}
				catch
				{
				}
			}
			return null;
		}

		private static TypeContainer FindType(string name)
		{
			Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
			foreach (Assembly assembly in assemblies)
			{
				try
				{
					Type type = assembly.GetType(name, throwOnError: false);
					if ((object)type != null)
					{
						return new TypeContainer(type);
					}
				}
				catch
				{
				}
			}
			return null;
		}
	}
}

BepInEx/plugins/XUnity.ResourceRedirector/XUnity.ResourceRedirector.BepInEx.dll

Decompiled 5 months ago
using System;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using BepInEx;
using BepInEx.Configuration;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyCompany("XUnity.ResourceRedirector.BepInEx")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("2.1.0.0")]
[assembly: AssemblyInformationalVersion("2.1.0")]
[assembly: AssemblyProduct("XUnity.ResourceRedirector.BepInEx")]
[assembly: AssemblyTitle("XUnity.ResourceRedirector.BepInEx")]
[assembly: AssemblyVersion("2.1.0.0")]
namespace XUnity.ResourceRedirector.BepInEx;

[BepInPlugin("gravydevsupreme.xunity.resourceredirector", "XUnity Resource Redirector", "2.1.0")]
public class ResourceRedirectorPlugin : BaseUnityPlugin
{
	public static ConfigEntry<bool> LogAllLoadedResources { get; set; }

	public static ConfigEntry<bool> LogCallbackOrder { get; set; }

	private void Awake()
	{
		//IL_0010: Unknown result type (might be due to invalid IL or missing references)
		//IL_001c: Expected O, but got Unknown
		//IL_0069: Unknown result type (might be due to invalid IL or missing references)
		//IL_0075: Expected O, but got Unknown
		LogAllLoadedResources = ((BaseUnityPlugin)this).Config.Bind<bool>(new ConfigDefinition("Diagnostics", "Log all loaded resources"), false, (ConfigDescription)null);
		ResourceRedirection.LogAllLoadedResources = LogAllLoadedResources.Value;
		LogAllLoadedResources.SettingChanged += delegate
		{
			ResourceRedirection.LogAllLoadedResources = LogAllLoadedResources.Value;
		};
		LogCallbackOrder = ((BaseUnityPlugin)this).Config.Bind<bool>(new ConfigDefinition("Diagnostics", "Log callback order"), false, (ConfigDescription)null);
		ResourceRedirection.LogCallbackOrder = LogCallbackOrder.Value;
		LogCallbackOrder.SettingChanged += delegate
		{
			ResourceRedirection.LogCallbackOrder = LogCallbackOrder.Value;
		};
		((BaseUnityPlugin)this).Config.ConfigReloaded += Config_ConfigReloaded;
	}

	private static void Config_ConfigReloaded(object sender, EventArgs e)
	{
		ResourceRedirection.LogAllLoadedResources = LogAllLoadedResources.Value;
		ResourceRedirection.LogCallbackOrder = LogCallbackOrder.Value;
	}
}

BepInEx/plugins/XUnity.ResourceRedirector/XUnity.ResourceRedirector.dll

Decompiled 5 months ago
using System;
using System.CodeDom.Compiler;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Resources;
using System.Runtime.CompilerServices;
using Microsoft.CodeAnalysis;
using UnityEngine;
using XUnity.Common.Constants;
using XUnity.Common.Extensions;
using XUnity.Common.Harmony;
using XUnity.Common.Logging;
using XUnity.Common.MonoMod;
using XUnity.Common.Utilities;
using XUnity.ResourceRedirector.Constants;
using XUnity.ResourceRedirector.Hooks;
using XUnity.ResourceRedirector.Properties;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyCompany("gravydevsupreme")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("Main development dependency for XUnity Resource Redirector.")]
[assembly: AssemblyFileVersion("2.1.0.0")]
[assembly: AssemblyInformationalVersion("2.1.0")]
[assembly: AssemblyProduct("XUnity.ResourceRedirector")]
[assembly: AssemblyTitle("XUnity.ResourceRedirector")]
[assembly: AssemblyVersion("2.1.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace XUnity.ResourceRedirector
{
	internal class AssetBundleExtensionData
	{
		private string _normalizedPath;

		private string _path;

		public string NormalizedPath
		{
			get
			{
				if (Path != null && _normalizedPath == null)
				{
					_normalizedPath = StringExtensions.MakeRelativePath(Path.ToLowerInvariant(), EnvironmentEx.LoweredCurrentDirectory);
				}
				return _normalizedPath;
			}
		}

		public string Path
		{
			get
			{
				return _path;
			}
			set
			{
				if (_path != value)
				{
					_path = value;
					_normalizedPath = null;
				}
			}
		}
	}
	public static class AssetBundleHelper
	{
		internal static string PathForLoadedInMemoryBundle;

		public static AssetBundle CreateEmptyAssetBundle()
		{
			byte[] empty = Resources.empty;
			CabHelper.RandomizeCab(empty);
			return AssetBundle.LoadFromMemory(empty);
		}

		public static AssetBundleCreateRequest CreateEmptyAssetBundleRequest()
		{
			byte[] empty = Resources.empty;
			CabHelper.RandomizeCab(empty);
			return AssetBundle.LoadFromMemoryAsync(empty);
		}

		public static AssetBundle LoadFromMemory(string path, byte[] binary, uint crc)
		{
			try
			{
				PathForLoadedInMemoryBundle = path;
				return AssetBundle.LoadFromMemory(binary, crc);
			}
			finally
			{
				PathForLoadedInMemoryBundle = null;
			}
		}

		public static AssetBundleCreateRequest LoadFromMemoryAsync(string path, byte[] binary, uint crc)
		{
			try
			{
				PathForLoadedInMemoryBundle = path;
				return AssetBundle.LoadFromMemoryAsync(binary, crc);
			}
			finally
			{
				PathForLoadedInMemoryBundle = null;
			}
		}

		public static AssetBundle LoadFromFileWithRandomizedCabIfRequired(string path, uint crc, ulong offset)
		{
			return LoadFromFileWithRandomizedCabIfRequired(path, crc, offset, confirmFileExists: true);
		}

		internal static AssetBundle LoadFromFileWithRandomizedCabIfRequired(string path, uint crc, ulong offset, bool confirmFileExists)
		{
			AssetBundle val = AssetBundle.LoadFromFile(path, crc, offset);
			if ((Object)(object)val == (Object)null && (!confirmFileExists || File.Exists(path)))
			{
				byte[] array;
				using (FileStream fileStream = new FileStream(path, FileMode.Open, FileAccess.Read))
				{
					long num = fileStream.Length - (long)offset;
					fileStream.Seek((long)offset, SeekOrigin.Begin);
					array = StreamExtensions.ReadFully((Stream)fileStream, (int)num);
				}
				CabHelper.RandomizeCabWithAnyLength(array);
				XuaLogger.ResourceRedirector.Warn("Randomized CAB for '" + path + "' in order to load it because another asset bundle already uses its CAB-string. You can ignore the previous error message, but this is likely caused by two mods incorrectly using the same CAB-string.");
				return AssetBundle.LoadFromMemory(array);
			}
			return val;
		}
	}
	public class AssetBundleLoadedContext
	{
		private string _normalizedPath;

		public AssetBundleLoadingParameters Parameters { get; }

		public AssetBundle Bundle { get; set; }

		internal bool SkipRemainingPostfixes { get; private set; }

		internal AssetBundleLoadedContext(AssetBundleLoadingParameters parameters, AssetBundle bundle)
		{
			Parameters = parameters;
			Bundle = bundle;
		}

		public string GetNormalizedPath()
		{
			if (_normalizedPath == null && Parameters.Path != null)
			{
				_normalizedPath = StringExtensions.MakeRelativePath(StringExtensions.UseCorrectDirectorySeparators(Parameters.Path.ToLowerInvariant()), EnvironmentEx.LoweredCurrentDirectory);
			}
			return _normalizedPath;
		}

		public void Complete(bool skipRemainingPostfixes = true)
		{
			SkipRemainingPostfixes = skipRemainingPostfixes;
		}

		public void DisableRecursion()
		{
			ResourceRedirection.RecursionEnabled = false;
		}
	}
	public class AssetBundleLoadingContext : IAssetBundleLoadingContext
	{
		private string _normalizedPath;

		public AssetBundleLoadingParameters Parameters { get; }

		public AssetBundle Bundle { get; set; }

		internal bool SkipRemainingPrefixes { get; private set; }

		internal bool SkipOriginalCall { get; private set; }

		internal bool SkipAllPostfixes { get; private set; }

		internal AssetBundleLoadingContext(AssetBundleLoadingParameters parameters)
		{
			Parameters = parameters;
		}

		public string GetNormalizedPath()
		{
			if (_normalizedPath == null && Parameters.Path != null)
			{
				_normalizedPath = StringExtensions.MakeRelativePath(StringExtensions.UseCorrectDirectorySeparators(Parameters.Path.ToLowerInvariant()), EnvironmentEx.LoweredCurrentDirectory);
			}
			return _normalizedPath;
		}

		public void Complete()
		{
			Complete(skipRemainingPrefixes: true, true, true);
		}

		public void Complete(bool skipRemainingPrefixes = true, bool? skipOriginalCall = true)
		{
			Complete(skipRemainingPrefixes, skipOriginalCall, true);
		}

		public void Complete(bool skipRemainingPrefixes = true, bool? skipOriginalCall = true, bool? skipAllPostfixes = true)
		{
			SkipRemainingPrefixes = skipRemainingPrefixes;
			if (skipOriginalCall.HasValue)
			{
				SkipOriginalCall = skipOriginalCall.Value;
			}
			if (skipAllPostfixes.HasValue)
			{
				SkipAllPostfixes = skipAllPostfixes.Value;
			}
		}

		public void DisableRecursion()
		{
			ResourceRedirection.RecursionEnabled = false;
		}
	}
	public class AssetBundleLoadingParameters
	{
		public string Path { get; set; }

		public uint Crc { get; set; }

		public ulong Offset { get; set; }

		public Stream Stream { get; set; }

		public uint ManagedReadBufferSize { get; }

		public byte[] Binary { get; set; }

		public AssetBundleLoadType LoadType { get; }

		internal AssetBundleLoadingParameters(byte[] data, string path, uint crc, ulong offset, Stream stream, uint managedReadBufferSize, AssetBundleLoadType loadType)
		{
			Binary = data;
			Path = path;
			Crc = crc;
			Offset = offset;
			Stream = stream;
			ManagedReadBufferSize = managedReadBufferSize;
			LoadType = loadType;
		}
	}
	public enum AssetBundleLoadType
	{
		LoadFromFile = 1,
		LoadFromMemory,
		LoadFromStream
	}
	public class AssetLoadedContext : IAssetOrResourceLoadedContext
	{
		private AssetBundleExtensionData _ext;

		private bool _lookedForExt;

		private BackingFieldOrArray _backingField;

		public AssetLoadedParameters Parameters { get; }

		public AssetBundle Bundle { get; }

		public Object[] Assets
		{
			get
			{
				return _backingField.Array;
			}
			set
			{
				_backingField.Array = value;
			}
		}

		public Object Asset
		{
			get
			{
				return _backingField.Field;
			}
			set
			{
				_backingField.Field = value;
			}
		}

		internal bool SkipRemainingPostfixes { get; private set; }

		internal AssetLoadedContext(AssetLoadedParameters parameters, AssetBundle bundle, Object[] assets)
		{
			Parameters = parameters;
			Bundle = bundle;
			_backingField = new BackingFieldOrArray(assets);
		}

		internal AssetLoadedContext(AssetLoadedParameters parameters, AssetBundle bundle, Object asset)
		{
			Parameters = parameters;
			Bundle = bundle;
			_backingField = new BackingFieldOrArray(asset);
		}

		public bool HasReferenceBeenRedirectedBefore(Object asset)
		{
			return ExtensionDataHelper.GetExtensionData<ResourceExtensionData>((object)asset)?.HasBeenRedirected ?? false;
		}

		public string GetUniqueFileSystemAssetPath(Object asset)
		{
			ResourceExtensionData orCreateExtensionData = ExtensionDataHelper.GetOrCreateExtensionData<ResourceExtensionData>((object)asset);
			if (orCreateExtensionData.FullFileSystemAssetPath == null)
			{
				string text = ExtensionDataHelper.GetExtensionData<AssetBundleExtensionData>((object)Bundle)?.NormalizedPath;
				string path = (string.IsNullOrEmpty(text) ? "unnamed_assetbundle" : text.ToLowerInvariant());
				string name = asset.name;
				if (!string.IsNullOrEmpty(name))
				{
					path = Path.Combine(path, name.ToLowerInvariant());
				}
				else
				{
					string text2 = null;
					if (Assets.Length > 1)
					{
						int num = Array.IndexOf(Assets, asset);
						text2 = ((num != -1) ? ("_" + num.ToString(CultureInfo.InvariantCulture)) : "_with_unknown_index");
					}
					path = Path.Combine(path, (Parameters.LoadType == AssetLoadType.LoadMainAsset) ? "main_asset" : ("unnamed_asset" + text2));
				}
				path = StringExtensions.UseCorrectDirectorySeparators(path);
				orCreateExtensionData.FullFileSystemAssetPath = path;
			}
			return orCreateExtensionData.FullFileSystemAssetPath;
		}

		public string GetAssetBundlePath()
		{
			if (!_lookedForExt)
			{
				_lookedForExt = true;
				_ext = ExtensionDataHelper.GetExtensionData<AssetBundleExtensionData>((object)Bundle);
			}
			return _ext?.Path;
		}

		public string GetNormalizedAssetBundlePath()
		{
			if (!_lookedForExt)
			{
				_lookedForExt = true;
				_ext = ExtensionDataHelper.GetExtensionData<AssetBundleExtensionData>((object)Bundle);
			}
			return _ext?.NormalizedPath;
		}

		public void Complete(bool skipRemainingPostfixes = true)
		{
			SkipRemainingPostfixes = skipRemainingPostfixes;
		}

		public void DisableRecursion()
		{
			ResourceRedirection.RecursionEnabled = false;
		}
	}
	public class AssetLoadedParameters
	{
		public string Name { get; }

		public Type Type { get; }

		public AssetLoadType LoadType { get; }

		internal AssetLoadedParameters(string name, Type type, AssetLoadType loadType)
		{
			Name = name;
			Type = type;
			LoadType = loadType;
		}
	}
	public class AssetLoadingContext : IAssetLoadingContext
	{
		private AssetBundleExtensionData _ext;

		private bool _lookedForExt;

		private BackingFieldOrArray _backingField;

		public AssetLoadingParameters Parameters { get; }

		public AssetBundle Bundle { get; }

		public Object[] Assets
		{
			get
			{
				return _backingField.Array;
			}
			set
			{
				_backingField.Array = value;
			}
		}

		public Object Asset
		{
			get
			{
				return _backingField.Field;
			}
			set
			{
				_backingField.Field = value;
			}
		}

		internal bool SkipRemainingPrefixes { get; private set; }

		internal bool SkipOriginalCall { get; private set; }

		internal bool SkipAllPostfixes { get; private set; }

		internal AssetLoadingContext(AssetLoadingParameters parameters, AssetBundle bundle)
		{
			Parameters = parameters;
			Bundle = bundle;
		}

		public string GetAssetBundlePath()
		{
			if (!_lookedForExt)
			{
				_lookedForExt = true;
				_ext = ExtensionDataHelper.GetExtensionData<AssetBundleExtensionData>((object)Bundle);
			}
			return _ext?.Path;
		}

		public string GetNormalizedAssetBundlePath()
		{
			if (!_lookedForExt)
			{
				_lookedForExt = true;
				_ext = ExtensionDataHelper.GetExtensionData<AssetBundleExtensionData>((object)Bundle);
			}
			return _ext?.NormalizedPath;
		}

		public void Complete(bool skipRemainingPrefixes = true, bool? skipOriginalCall = true, bool? skipAllPostfixes = true)
		{
			SkipRemainingPrefixes = skipRemainingPrefixes;
			if (skipOriginalCall.HasValue)
			{
				SkipOriginalCall = skipOriginalCall.Value;
			}
			if (skipAllPostfixes.HasValue)
			{
				SkipAllPostfixes = skipAllPostfixes.Value;
			}
		}

		public void DisableRecursion()
		{
			ResourceRedirection.RecursionEnabled = false;
		}
	}
	public class AssetLoadingParameters
	{
		public string Name { get; set; }

		public Type Type { get; set; }

		public AssetLoadType LoadType { get; }

		internal AssetLoadingParameters(string name, Type type, AssetLoadType loadType)
		{
			Name = name;
			Type = type;
			LoadType = loadType;
		}

		internal AssetLoadedParameters ToAssetLoadedParameters()
		{
			return new AssetLoadedParameters(Name, Type, LoadType);
		}
	}
	public enum AssetLoadType
	{
		LoadMainAsset = 1,
		LoadByType,
		LoadNamed,
		LoadNamedWithSubAssets
	}
	internal class AsyncAssetBundleLoadInfo
	{
		public AssetBundleLoadingParameters Parameters { get; }

		public AssetBundle Bundle { get; }

		public bool SkipAllPostfixes { get; }

		public AsyncAssetBundleLoadingResolve ResolveType { get; }

		public AsyncAssetBundleLoadInfo(AssetBundleLoadingParameters parameters, AssetBundle bundle, bool skipAllPostfixes, AsyncAssetBundleLoadingResolve resolveType)
		{
			Parameters = parameters;
			Bundle = bundle;
			SkipAllPostfixes = skipAllPostfixes;
			ResolveType = resolveType;
		}
	}
	public class AsyncAssetBundleLoadingContext : IAssetBundleLoadingContext
	{
		private string _normalizedPath;

		private AssetBundle _bundle;

		private AssetBundleCreateRequest _request;

		public AssetBundleLoadingParameters Parameters { get; }

		public AssetBundleCreateRequest Request
		{
			get
			{
				return _request;
			}
			set
			{
				_request = value;
				ResolveType = AsyncAssetBundleLoadingResolve.ThroughRequest;
			}
		}

		public AssetBundle Bundle
		{
			get
			{
				return _bundle;
			}
			set
			{
				if (!ResourceRedirection.SyncOverAsyncEnabled)
				{
					throw new InvalidOperationException("Trying to set the Bundle property in async load operation while 'SyncOverAsyncAssetLoads' is disabled is not allowed. Consider settting the Request property instead if possible or enabling 'SyncOverAsyncAssetLoads' through the method 'ResourceRedirection.EnableSyncOverAsyncAssetLoads()'.");
				}
				_bundle = value;
				ResolveType = AsyncAssetBundleLoadingResolve.ThroughBundle;
			}
		}

		public AsyncAssetBundleLoadingResolve ResolveType { get; set; }

		internal bool SkipRemainingPrefixes { get; private set; }

		internal bool SkipOriginalCall { get; set; }

		internal bool SkipAllPostfixes { get; private set; }

		internal AsyncAssetBundleLoadingContext(AssetBundleLoadingParameters parameters)
		{
			Parameters = parameters;
		}

		public string GetNormalizedPath()
		{
			if (_normalizedPath == null && Parameters.Path != null)
			{
				_normalizedPath = StringExtensions.MakeRelativePath(StringExtensions.UseCorrectDirectorySeparators(Parameters.Path.ToLowerInvariant()), EnvironmentEx.LoweredCurrentDirectory);
			}
			return _normalizedPath;
		}

		public void Complete()
		{
			Complete(skipRemainingPrefixes: true, true, true);
		}

		public void Complete(bool skipRemainingPrefixes = true, bool? skipOriginalCall = true)
		{
			Complete(skipRemainingPrefixes, skipOriginalCall, true);
		}

		public void Complete(bool skipRemainingPrefixes = true, bool? skipOriginalCall = true, bool? skipAllPostfixes = true)
		{
			SkipRemainingPrefixes = skipRemainingPrefixes;
			if (skipOriginalCall.HasValue)
			{
				SkipOriginalCall = skipOriginalCall.Value;
			}
			if (skipAllPostfixes.HasValue)
			{
				SkipAllPostfixes = skipAllPostfixes.Value;
			}
		}

		public void DisableRecursion()
		{
			ResourceRedirection.RecursionEnabled = false;
		}
	}
	public enum AsyncAssetBundleLoadingResolve
	{
		ThroughRequest,
		ThroughBundle
	}
	internal class AsyncAssetLoadInfo
	{
		public AssetLoadingParameters Parameters { get; }

		public AssetBundle Bundle { get; }

		public bool SkipAllPostfixes { get; }

		public AsyncAssetLoadingResolve ResolveType { get; }

		public Object[] Assets { get; }

		public AsyncAssetLoadInfo(AssetLoadingParameters parameters, AssetBundle bundle, bool skipAllPostfixes, AsyncAssetLoadingResolve resolveType, Object[] assets)
		{
			Parameters = parameters;
			Bundle = bundle;
			SkipAllPostfixes = skipAllPostfixes;
			ResolveType = resolveType;
			Assets = assets;
		}
	}
	public class AsyncAssetLoadingContext : IAssetLoadingContext
	{
		private AssetBundleExtensionData _ext;

		private bool _lookedForExt;

		private Object[] _assets;

		private AssetBundleRequest _request;

		private BackingFieldOrArray _backingField;

		public AssetLoadingParameters Parameters { get; }

		public AssetBundle Bundle { get; }

		public AssetBundleRequest Request
		{
			get
			{
				return _request;
			}
			set
			{
				_request = value;
				ResolveType = AsyncAssetLoadingResolve.ThroughRequest;
			}
		}

		public Object[] Assets
		{
			get
			{
				return _backingField.Array;
			}
			set
			{
				if (!ResourceRedirection.SyncOverAsyncEnabled)
				{
					throw new InvalidOperationException("Trying to set the Assets/Asset property in async load operation while 'SyncOverAsyncAssetLoads' is disabled is not allowed. Consider settting the Request property instead if possible or enabling 'SyncOverAsyncAssetLoads' through the method 'ResourceRedirection.EnableSyncOverAsyncAssetLoads()'.");
				}
				_backingField.Array = value;
				ResolveType = AsyncAssetLoadingResolve.ThroughAssets;
			}
		}

		public Object Asset
		{
			get
			{
				return _backingField.Field;
			}
			set
			{
				if (!ResourceRedirection.SyncOverAsyncEnabled)
				{
					throw new InvalidOperationException("Trying to set the Assets/Asset property in async load operation while 'SyncOverAsyncAssetLoads' is disabled is not allowed. Consider settting the Request property instead if possible or enabling 'SyncOverAsyncAssetLoads' through the method 'ResourceRedirection.EnableSyncOverAsyncAssetLoads()'.");
				}
				_backingField.Field = value;
				ResolveType = AsyncAssetLoadingResolve.ThroughAssets;
			}
		}

		public AsyncAssetLoadingResolve ResolveType { get; set; }

		internal bool SkipRemainingPrefixes { get; private set; }

		internal bool SkipOriginalCall { get; set; }

		internal bool SkipAllPostfixes { get; private set; }

		internal AsyncAssetLoadingContext(AssetLoadingParameters parameters, AssetBundle bundle)
		{
			Parameters = parameters;
			Bundle = bundle;
		}

		public string GetAssetBundlePath()
		{
			if (!_lookedForExt)
			{
				_lookedForExt = true;
				_ext = ExtensionDataHelper.GetExtensionData<AssetBundleExtensionData>((object)Bundle);
			}
			return _ext?.Path;
		}

		public string GetNormalizedAssetBundlePath()
		{
			if (!_lookedForExt)
			{
				_lookedForExt = true;
				_ext = ExtensionDataHelper.GetExtensionData<AssetBundleExtensionData>((object)Bundle);
			}
			return _ext?.NormalizedPath;
		}

		public void Complete(bool skipRemainingPrefixes = true, bool? skipOriginalCall = true, bool? skipAllPostfixes = true)
		{
			SkipRemainingPrefixes = skipRemainingPrefixes;
			if (skipOriginalCall.HasValue)
			{
				SkipOriginalCall = skipOriginalCall.Value;
			}
			if (skipAllPostfixes.HasValue)
			{
				SkipAllPostfixes = skipAllPostfixes.Value;
			}
		}

		public void DisableRecursion()
		{
			ResourceRedirection.RecursionEnabled = false;
		}
	}
	public enum AsyncAssetLoadingResolve
	{
		ThroughRequest,
		ThroughAssets
	}
	internal struct BackingFieldOrArray
	{
		private Object _field;

		private Object[] _array;

		private BackingSource _source;

		public Object Field
		{
			get
			{
				if (_source == BackingSource.None)
				{
					return null;
				}
				if (_source == BackingSource.SingleField)
				{
					return _field;
				}
				if (_array == null || _array.Length == 0)
				{
					return null;
				}
				return _array[0];
			}
			set
			{
				_field = value;
				_array = null;
				_source = BackingSource.SingleField;
			}
		}

		public Object[] Array
		{
			get
			{
				if (_source == BackingSource.Array)
				{
					return _array;
				}
				if (_field == (Object)null)
				{
					Array = (Object[])(object)new Object[0];
				}
				else
				{
					Array = (Object[])(object)new Object[1] { _field };
				}
				return _array;
			}
			set
			{
				_field = null;
				_array = value;
				_source = BackingSource.Array;
			}
		}

		public BackingFieldOrArray(Object field)
		{
			_field = field;
			_array = null;
			_source = BackingSource.SingleField;
		}

		public BackingFieldOrArray(Object[] array)
		{
			_field = null;
			_array = array;
			_source = BackingSource.Array;
		}

		public IEnumerable<Object> IterateObjects()
		{
			if (_array != null)
			{
				Object[] array = _array;
				for (int i = 0; i < array.Length; i++)
				{
					yield return array[i];
				}
			}
			else if (_field != (Object)null)
			{
				yield return _field;
			}
		}
	}
	internal enum BackingSource : byte
	{
		None,
		SingleField,
		Array
	}
	public static class CallbackPriority
	{
		public const int Default = 0;
	}
	public enum HookBehaviour
	{
		OneCallbackPerLoadCall = 1,
		OneCallbackPerResourceLoaded
	}
	public interface IAssetBundleLoadingContext
	{
		AssetBundleLoadingParameters Parameters { get; }

		AssetBundle Bundle { get; set; }

		string GetNormalizedPath();

		void Complete();

		void Complete(bool skipRemainingPrefixes = true, bool? skipOriginalCall = true);

		void Complete(bool skipRemainingPrefixes = true, bool? skipOriginalCall = true, bool? skipAllPostfixes = true);

		void DisableRecursion();
	}
	public interface IAssetLoadingContext
	{
		AssetLoadingParameters Parameters { get; }

		AssetBundle Bundle { get; }

		Object[] Assets { get; set; }

		Object Asset { get; set; }

		string GetAssetBundlePath();

		string GetNormalizedAssetBundlePath();

		void Complete(bool skipRemainingPrefixes = true, bool? skipOriginalCall = true, bool? skipAllPostfixes = true);

		void DisableRecursion();
	}
	public interface IAssetOrResourceLoadedContext
	{
		Object[] Assets { get; set; }

		Object Asset { get; set; }

		bool HasReferenceBeenRedirectedBefore(Object asset);

		string GetUniqueFileSystemAssetPath(Object asset);

		void Complete(bool skipRemainingPostfixes = true);

		void DisableRecursion();
	}
	internal class PrioritizedCallback
	{
		public static PrioritizedCallback<TCallback> Create<TCallback>(TCallback item, int priority) where TCallback : Delegate
		{
			return new PrioritizedCallback<TCallback>(item, priority);
		}
	}
	internal class PrioritizedCallback<TCallback> : PrioritizedCallback, IComparable<PrioritizedCallback<TCallback>>, IEquatable<PrioritizedCallback<TCallback>> where TCallback : Delegate
	{
		public TCallback Callback { get; }

		public int Priority { get; }

		public Type TargetType { get; set; }

		public bool IsBeingCalled { get; set; }

		public PrioritizedCallback(TCallback callback, int priority)
		{
			Callback = callback;
			Priority = priority;
			TargetType = callback.Target?.GetType();
		}

		public int CompareTo(PrioritizedCallback<TCallback> other)
		{
			return other.Priority.CompareTo(Priority);
		}

		public override bool Equals(object obj)
		{
			return Equals(obj as PrioritizedCallback<TCallback>);
		}

		public bool Equals(PrioritizedCallback<TCallback> other)
		{
			return EqualityComparer<TCallback>.Default.Equals(Callback, other.Callback);
		}

		public override int GetHashCode()
		{
			return -1406788065 * -1521134295 + EqualityComparer<TCallback>.Default.GetHashCode(Callback);
		}

		public override string ToString()
		{
			return "[" + Priority + "] " + (TargetType?.Name ?? Callback.Method.DeclaringType?.Name) + "." + Callback.Method?.Name;
		}
	}
	internal class ResourceExtensionData
	{
		public bool HasBeenRedirected { get; set; }

		public string FullFileSystemAssetPath { get; set; }
	}
	public class ResourceLoadedContext : IAssetOrResourceLoadedContext
	{
		private BackingFieldOrArray _backingField;

		public ResourceLoadedParameters Parameters { get; }

		public Object[] Assets
		{
			get
			{
				return _backingField.Array;
			}
			set
			{
				_backingField.Array = value;
			}
		}

		public Object Asset
		{
			get
			{
				return _backingField.Field;
			}
			set
			{
				_backingField.Field = value;
			}
		}

		internal bool SkipRemainingPostfixes { get; set; }

		internal ResourceLoadedContext(ResourceLoadedParameters parameters, Object[] assets)
		{
			Parameters = parameters;
			_backingField = new BackingFieldOrArray(assets);
		}

		internal ResourceLoadedContext(ResourceLoadedParameters parameters, Object asset)
		{
			Parameters = parameters;
			_backingField = new BackingFieldOrArray(asset);
		}

		public bool HasReferenceBeenRedirectedBefore(Object asset)
		{
			return ExtensionDataHelper.GetExtensionData<ResourceExtensionData>((object)asset)?.HasBeenRedirected ?? false;
		}

		public string GetUniqueFileSystemAssetPath(Object asset)
		{
			ResourceExtensionData orCreateExtensionData = ExtensionDataHelper.GetOrCreateExtensionData<ResourceExtensionData>((object)asset);
			if (orCreateExtensionData.FullFileSystemAssetPath == null)
			{
				string text = string.Empty;
				if (!string.IsNullOrEmpty(Parameters.Path))
				{
					text = Parameters.Path.ToLowerInvariant();
				}
				if (Parameters.LoadType == ResourceLoadType.LoadByType)
				{
					string name = asset.name;
					if (!string.IsNullOrEmpty(name))
					{
						text = Path.Combine(text, name.ToLowerInvariant());
					}
					else
					{
						string text2 = null;
						if (Assets.Length > 1)
						{
							int num = Array.IndexOf(Assets, asset);
							text2 = ((num != -1) ? ("_" + num.ToString(CultureInfo.InvariantCulture)) : "_with_unknown_index");
						}
						text = Path.Combine(text, "unnamed_asset" + text2);
					}
				}
				text = StringExtensions.UseCorrectDirectorySeparators(text);
				orCreateExtensionData.FullFileSystemAssetPath = text;
			}
			return orCreateExtensionData.FullFileSystemAssetPath;
		}

		public void Complete(bool skipRemainingPostfixes = true)
		{
			SkipRemainingPostfixes = skipRemainingPostfixes;
		}

		public void DisableRecursion()
		{
			ResourceRedirection.RecursionEnabled = false;
		}
	}
	public class ResourceLoadedParameters
	{
		public string Path { get; set; }

		public Type Type { get; set; }

		public ResourceLoadType LoadType { get; }

		internal ResourceLoadedParameters(string path, Type type, ResourceLoadType loadType)
		{
			Path = path;
			Type = type;
			LoadType = loadType;
		}
	}
	public enum ResourceLoadType
	{
		LoadByType = 1,
		LoadNamed,
		LoadNamedBuiltIn
	}
	public static class ResourceRedirection
	{
		private static readonly List<PrioritizedCallback<Action<AssetLoadedContext>>> PostfixRedirectionsForAssetsPerCall = new List<PrioritizedCallback<Action<AssetLoadedContext>>>();

		private static readonly List<PrioritizedCallback<Action<AssetLoadedContext>>> PostfixRedirectionsForAssetsPerResource = new List<PrioritizedCallback<Action<AssetLoadedContext>>>();

		private static readonly List<PrioritizedCallback<Action<ResourceLoadedContext>>> PostfixRedirectionsForResourcesPerCall = new List<PrioritizedCallback<Action<ResourceLoadedContext>>>();

		private static readonly List<PrioritizedCallback<Action<ResourceLoadedContext>>> PostfixRedirectionsForResourcesPerResource = new List<PrioritizedCallback<Action<ResourceLoadedContext>>>();

		private static readonly List<PrioritizedCallback<Delegate>> PrefixRedirectionsForAssetsPerCall = new List<PrioritizedCallback<Delegate>>();

		private static readonly List<PrioritizedCallback<Delegate>> PrefixRedirectionsForAsyncAssetsPerCall = new List<PrioritizedCallback<Delegate>>();

		private static readonly List<PrioritizedCallback<Delegate>> PrefixRedirectionsForAssetBundles = new List<PrioritizedCallback<Delegate>>();

		private static readonly List<PrioritizedCallback<Delegate>> PrefixRedirectionsForAsyncAssetBundles = new List<PrioritizedCallback<Delegate>>();

		private static readonly List<PrioritizedCallback<Action<AssetBundleLoadedContext>>> PostfixRedirectionsForAssetBundles = new List<PrioritizedCallback<Action<AssetBundleLoadedContext>>>();

		private static Action<AssetBundleLoadingContext> _emulateAssetBundles;

		private static Action<AsyncAssetBundleLoadingContext> _emulateAssetBundlesAsync;

		private static Action<AssetBundleLoadingContext> _redirectionMissingAssetBundlesToEmpty;

		private static Action<AsyncAssetBundleLoadingContext> _redirectionMissingAssetBundlesToEmptyAsync;

		private static bool _enabledRandomizeCabIfConflict = false;

		private static Action<AssetBundleLoadingContext> _enableCabRandomizationPrefix;

		private static Action<AsyncAssetBundleLoadingContext> _enableCabRandomizationPrefixAsync;

		private static Action<AssetBundleLoadedContext> _enableCabRandomizationPostfix;

		private static bool _initialized = false;

		private static bool _initializedSyncOverAsyncEnabled = false;

		private static bool _logAllLoadedResources = false;

		private static bool _isFiringAssetBundle;

		private static bool _isFiringResource;

		private static bool _isFiringAsset;

		private static bool _isRecursionDisabledPermanently;

		internal static bool RecursionEnabled = true;

		internal static bool SyncOverAsyncEnabled = false;

		public static bool LogAllLoadedResources
		{
			get
			{
				return _logAllLoadedResources;
			}
			set
			{
				if (value)
				{
					Initialize();
				}
				_logAllLoadedResources = value;
			}
		}

		public static bool LogCallbackOrder { get; set; }

		public static void Initialize()
		{
			if (!_initialized)
			{
				_initialized = true;
				HookingHelper.PatchAll((IEnumerable<Type>)ResourceAndAssetHooks.GeneralHooks, false);
			}
		}

		public static void EnableSyncOverAsyncAssetLoads()
		{
			Initialize();
			if (!_initializedSyncOverAsyncEnabled)
			{
				_initializedSyncOverAsyncEnabled = true;
				SyncOverAsyncEnabled = true;
				HookingHelper.PatchAll((IEnumerable<Type>)ResourceAndAssetHooks.SyncOverAsyncHooks, false);
			}
		}

		public static void DisableRecursionPermanently()
		{
			_isRecursionDisabledPermanently = true;
		}

		public static void EnableEmulateAssetBundles(int priority, string emulationDirectory)
		{
			if (_emulateAssetBundles == null && _emulateAssetBundlesAsync == null)
			{
				_emulateAssetBundles = delegate(AssetBundleLoadingContext ctx)
				{
					HandleAssetBundleEmulation<AssetBundleLoadingContext>(ctx, SetBundle);
				};
				_emulateAssetBundlesAsync = delegate(AsyncAssetBundleLoadingContext ctx)
				{
					HandleAssetBundleEmulation<AsyncAssetBundleLoadingContext>(ctx, SetRequest);
				};
				RegisterAssetBundleLoadingHook(priority, _emulateAssetBundles);
				RegisterAsyncAssetBundleLoadingHook(priority, _emulateAssetBundlesAsync);
			}
			void HandleAssetBundleEmulation<T>(T context, Action<T, string> changeBundle) where T : IAssetBundleLoadingContext
			{
				if (context.Parameters.LoadType == AssetBundleLoadType.LoadFromFile)
				{
					string normalizedPath = context.GetNormalizedPath();
					string text = Path.Combine(emulationDirectory, normalizedPath);
					if (File.Exists(text))
					{
						changeBundle(context, text);
						ref T reference = ref context;
						T val = default(T);
						if (val == null)
						{
							val = reference;
							reference = ref val;
						}
						reference.Complete(skipRemainingPrefixes: true, true);
						XuaLogger.ResourceRedirector.Debug("Redirected asset bundle: '" + context.Parameters.Path + "' => '" + text + "'");
					}
				}
			}
			static void SetBundle(AssetBundleLoadingContext context, string path)
			{
				context.Bundle = AssetBundle.LoadFromFile(path, context.Parameters.Crc, context.Parameters.Offset);
			}
			static void SetRequest(AsyncAssetBundleLoadingContext context, string path)
			{
				context.Request = AssetBundle.LoadFromFileAsync(path, context.Parameters.Crc, context.Parameters.Offset);
			}
		}

		public static void DisableEmulateAssetBundles()
		{
			if (_emulateAssetBundles != null && _emulateAssetBundlesAsync != null)
			{
				UnregisterAssetBundleLoadingHook(_emulateAssetBundles);
				UnregisterAsyncAssetBundleLoadingHook(_emulateAssetBundlesAsync);
				_emulateAssetBundles = null;
				_emulateAssetBundlesAsync = null;
			}
		}

		public static void EnableRedirectMissingAssetBundlesToEmptyAssetBundle(int priority)
		{
			if (_redirectionMissingAssetBundlesToEmpty == null && _redirectionMissingAssetBundlesToEmptyAsync == null)
			{
				_redirectionMissingAssetBundlesToEmpty = delegate(AssetBundleLoadingContext ctx)
				{
					HandleMissingBundle<AssetBundleLoadingContext>(ctx, SetBundle);
				};
				_redirectionMissingAssetBundlesToEmptyAsync = delegate(AsyncAssetBundleLoadingContext ctx)
				{
					HandleMissingBundle<AsyncAssetBundleLoadingContext>(ctx, SetRequest);
				};
				RegisterAssetBundleLoadingHook(priority, _redirectionMissingAssetBundlesToEmpty);
				RegisterAsyncAssetBundleLoadingHook(priority, _redirectionMissingAssetBundlesToEmptyAsync);
			}
			static void HandleMissingBundle<TContext>(TContext context, Action<TContext, byte[]> changeBundle) where TContext : IAssetBundleLoadingContext
			{
				if (context.Parameters.LoadType == AssetBundleLoadType.LoadFromFile && !File.Exists(context.Parameters.Path))
				{
					byte[] empty = Resources.empty;
					CabHelper.RandomizeCab(empty);
					changeBundle(context, empty);
					ref TContext reference = ref context;
					TContext val = default(TContext);
					if (val == null)
					{
						val = reference;
						reference = ref val;
					}
					reference.Complete(skipRemainingPrefixes: true, true);
					XuaLogger.ResourceRedirector.Warn("Tried to load non-existing asset bundle: " + context.Parameters.Path);
				}
			}
			static void SetBundle(AssetBundleLoadingContext context, byte[] assetBundleData)
			{
				AssetBundle bundle = AssetBundle.LoadFromMemory(assetBundleData);
				context.Bundle = bundle;
			}
			static void SetRequest(AsyncAssetBundleLoadingContext context, byte[] assetBundleData)
			{
				AssetBundleCreateRequest request = AssetBundle.LoadFromMemoryAsync(assetBundleData);
				context.Request = request;
			}
		}

		public static void EnableRandomizeCabIfConflict(int priority, bool forceRandomizeWhenInMemory)
		{
			if (_enabledRandomizeCabIfConflict)
			{
				return;
			}
			_enabledRandomizeCabIfConflict = true;
			if (forceRandomizeWhenInMemory)
			{
				_enableCabRandomizationPrefix = delegate(AssetBundleLoadingContext ctx)
				{
					HandleCabRandomizePrefix(ctx);
				};
				_enableCabRandomizationPrefixAsync = delegate(AsyncAssetBundleLoadingContext ctx)
				{
					HandleCabRandomizePrefix(ctx);
				};
				RegisterAssetBundleLoadingHook(priority, _enableCabRandomizationPrefix);
				RegisterAsyncAssetBundleLoadingHook(priority, _enableCabRandomizationPrefixAsync);
			}
			_enableCabRandomizationPostfix = delegate(AssetBundleLoadedContext ctx)
			{
				HandleCabRandomizePostfix(ctx);
			};
			RegisterAssetBundleLoadedHook(priority, _enableCabRandomizationPostfix);
			void HandleCabRandomizePostfix(AssetBundleLoadedContext context)
			{
				if (context.Parameters.LoadType == AssetBundleLoadType.LoadFromFile)
				{
					if ((Object)(object)context.Bundle == (Object)null && File.Exists(context.Parameters.Path))
					{
						XuaLogger.ResourceRedirector.Warn("The asset bundle '" + context.Parameters.Path + "' could not be loaded likely due to conflicting CAB-string. Retrying in-memory with randomized CAB-string.");
						byte[] array;
						using (FileStream fileStream = new FileStream(context.Parameters.Path, FileMode.Open, FileAccess.Read))
						{
							long length = fileStream.Length;
							long offset = (long)context.Parameters.Offset;
							long num = length - offset;
							fileStream.Seek(offset, SeekOrigin.Begin);
							array = StreamExtensions.ReadFully((Stream)fileStream, (int)num);
						}
						if (!forceRandomizeWhenInMemory)
						{
							CabHelper.RandomizeCabWithAnyLength(array);
						}
						AssetBundle val = AssetBundle.LoadFromMemory(array, 0u);
						if ((Object)(object)val != (Object)null)
						{
							context.Bundle = val;
							context.Complete();
						}
					}
				}
				else if (context.Parameters.LoadType == AssetBundleLoadType.LoadFromMemory)
				{
					if ((Object)(object)context.Bundle == (Object)null && !forceRandomizeWhenInMemory)
					{
						string text = AssetBundleHelper.PathForLoadedInMemoryBundle ?? "Unnamed";
						XuaLogger.ResourceRedirector.Warn("Could not load an in-memory asset bundle (" + text + ") likely due to conflicting CAB-string. Retrying with randomized CAB-string.");
						CabHelper.RandomizeCabWithAnyLength(context.Parameters.Binary);
						AssetBundle val2 = AssetBundle.LoadFromMemory(context.Parameters.Binary, 0u);
						if ((Object)(object)val2 != (Object)null)
						{
							context.Bundle = val2;
							context.Complete();
						}
					}
				}
				else if (context.Parameters.LoadType == AssetBundleLoadType.LoadFromStream && (Object)(object)context.Bundle == (Object)null)
				{
					string text2 = AssetBundleHelper.PathForLoadedInMemoryBundle ?? "Unnamed";
					XuaLogger.ResourceRedirector.Warn("Could not load a stream asset bundle (" + text2 + ") likely due to conflicting CAB-string. Retrying with randomized CAB-string.");
					byte[] array2 = StreamExtensions.ReadFully(context.Parameters.Stream, 0);
					if (!forceRandomizeWhenInMemory)
					{
						CabHelper.RandomizeCabWithAnyLength(array2);
					}
					AssetBundle val3 = AssetBundle.LoadFromMemory(array2, 0u);
					if ((Object)(object)val3 != (Object)null)
					{
						context.Bundle = val3;
						context.Complete();
					}
				}
			}
			static void HandleCabRandomizePrefix(IAssetBundleLoadingContext context)
			{
				if (context.Parameters.LoadType == AssetBundleLoadType.LoadFromMemory)
				{
					CabHelper.RandomizeCabWithAnyLength(context.Parameters.Binary);
				}
			}
		}

		public static void DisableRandomizeCabIfConflict()
		{
			if (_enabledRandomizeCabIfConflict)
			{
				_enabledRandomizeCabIfConflict = false;
				if (_enableCabRandomizationPrefix != null)
				{
					UnregisterAssetBundleLoadingHook(_enableCabRandomizationPrefix);
					_enableCabRandomizationPrefix = null;
				}
				if (_enableCabRandomizationPrefixAsync != null)
				{
					UnregisterAsyncAssetBundleLoadingHook(_enableCabRandomizationPrefixAsync);
					_enableCabRandomizationPrefixAsync = null;
				}
				if (_enableCabRandomizationPostfix != null)
				{
					UnregisterAssetBundleLoadedHook(_enableCabRandomizationPostfix);
					_enableCabRandomizationPostfix = null;
				}
			}
		}

		public static void DisableRedirectMissingAssetBundlesToEmptyAssetBundle()
		{
			if (_redirectionMissingAssetBundlesToEmpty != null && _redirectionMissingAssetBundlesToEmptyAsync != null)
			{
				UnregisterAssetBundleLoadingHook(_redirectionMissingAssetBundlesToEmpty);
				UnregisterAsyncAssetBundleLoadingHook(_redirectionMissingAssetBundlesToEmptyAsync);
				_redirectionMissingAssetBundlesToEmpty = null;
				_redirectionMissingAssetBundlesToEmptyAsync = null;
			}
		}

		internal static bool TryGetAssetBundleLoadInfo(AssetBundleRequest request, out AsyncAssetLoadInfo result)
		{
			result = ExtensionDataHelper.GetExtensionData<AsyncAssetLoadInfo>((object)request);
			return result != null;
		}

		internal static bool TryGetAssetBundle(AssetBundleCreateRequest request, out AsyncAssetBundleLoadInfo result)
		{
			result = ExtensionDataHelper.GetExtensionData<AsyncAssetBundleLoadInfo>((object)request);
			return result != null;
		}

		internal static bool ShouldBlockAsyncOperationMethods(AssetBundleRequest operation)
		{
			if (TryGetAssetBundleLoadInfo(operation, out var result))
			{
				return result.ResolveType == AsyncAssetLoadingResolve.ThroughAssets;
			}
			return false;
		}

		internal static bool ShouldBlockAsyncOperationMethods(AssetBundleCreateRequest operation)
		{
			if (TryGetAssetBundle(operation, out var result))
			{
				return result.ResolveType == AsyncAssetBundleLoadingResolve.ThroughBundle;
			}
			return false;
		}

		internal static bool ShouldBlockAsyncOperationMethods(AsyncOperation operation)
		{
			if (SyncOverAsyncEnabled)
			{
				AssetBundleRequest operation2 = default(AssetBundleRequest);
				if (!ObjectExtensions.TryCastTo<AssetBundleRequest>((object)operation, ref operation2) || !ShouldBlockAsyncOperationMethods(operation2))
				{
					AssetBundleCreateRequest operation3 = default(AssetBundleCreateRequest);
					if (ObjectExtensions.TryCastTo<AssetBundleCreateRequest>((object)operation, ref operation3))
					{
						return ShouldBlockAsyncOperationMethods(operation3);
					}
					return false;
				}
				return true;
			}
			return false;
		}

		internal static AssetBundleLoadingContext Hook_AssetBundleLoading_Prefix(AssetBundleLoadingParameters parameters, out AssetBundle bundle)
		{
			AssetBundleLoadingContext assetBundleLoadingContext = new AssetBundleLoadingContext(parameters);
			if (_isFiringAssetBundle && (_isRecursionDisabledPermanently || !RecursionEnabled))
			{
				bundle = null;
				return assetBundleLoadingContext;
			}
			try
			{
				_isFiringAssetBundle = true;
				if (_logAllLoadedResources)
				{
					XuaLogger.ResourceRedirector.Debug("Loading Asset Bundle: (" + assetBundleLoadingContext.GetNormalizedPath() + ").");
				}
				List<PrioritizedCallback<Delegate>> prefixRedirectionsForAssetBundles = PrefixRedirectionsForAssetBundles;
				int count = prefixRedirectionsForAssetBundles.Count;
				for (int i = 0; i < count; i++)
				{
					PrioritizedCallback<Delegate> prioritizedCallback = prefixRedirectionsForAssetBundles[i];
					if (prioritizedCallback.IsBeingCalled)
					{
						continue;
					}
					try
					{
						prioritizedCallback.IsBeingCalled = true;
						if (prioritizedCallback.Callback is Action<AssetBundleLoadingContext> action)
						{
							action(assetBundleLoadingContext);
						}
						else if (prioritizedCallback.Callback is Action<IAssetBundleLoadingContext> action2)
						{
							action2(assetBundleLoadingContext);
						}
						if (assetBundleLoadingContext.SkipRemainingPrefixes)
						{
							break;
						}
					}
					catch (Exception ex)
					{
						XuaLogger.ResourceRedirector.Error(ex, "An error occurred while invoking AssetBundleLoading event.");
					}
					finally
					{
						RecursionEnabled = true;
						prioritizedCallback.IsBeingCalled = false;
					}
				}
			}
			catch (Exception ex2)
			{
				XuaLogger.ResourceRedirector.Error(ex2, "An error occurred while invoking AssetBundleLoading event.");
			}
			finally
			{
				_isFiringAssetBundle = false;
			}
			bundle = assetBundleLoadingContext.Bundle;
			return assetBundleLoadingContext;
		}

		internal static AssetBundleLoadedContext Hook_AssetBundleLoaded_Postfix(AssetBundleLoadingParameters parameters, ref AssetBundle bundle)
		{
			AssetBundleLoadedContext assetBundleLoadedContext = new AssetBundleLoadedContext(parameters, bundle);
			if (_isFiringAssetBundle && (_isRecursionDisabledPermanently || !RecursionEnabled))
			{
				bundle = null;
				return assetBundleLoadedContext;
			}
			try
			{
				_isFiringAssetBundle = true;
				List<PrioritizedCallback<Action<AssetBundleLoadedContext>>> postfixRedirectionsForAssetBundles = PostfixRedirectionsForAssetBundles;
				int count = postfixRedirectionsForAssetBundles.Count;
				for (int i = 0; i < count; i++)
				{
					PrioritizedCallback<Action<AssetBundleLoadedContext>> prioritizedCallback = postfixRedirectionsForAssetBundles[i];
					if (prioritizedCallback.IsBeingCalled)
					{
						continue;
					}
					try
					{
						prioritizedCallback.IsBeingCalled = true;
						prioritizedCallback.Callback(assetBundleLoadedContext);
						if (assetBundleLoadedContext.SkipRemainingPostfixes)
						{
							break;
						}
					}
					catch (Exception ex)
					{
						XuaLogger.ResourceRedirector.Error(ex, "An error occurred while invoking AssetBundleLoaded event.");
					}
					finally
					{
						RecursionEnabled = true;
						prioritizedCallback.IsBeingCalled = false;
					}
				}
			}
			catch (Exception ex2)
			{
				XuaLogger.ResourceRedirector.Error(ex2, "An error occurred while invoking AssetBundleLoaded event.");
			}
			finally
			{
				_isFiringAssetBundle = false;
			}
			bundle = assetBundleLoadedContext.Bundle;
			return assetBundleLoadedContext;
		}

		internal static AsyncAssetBundleLoadingContext Hook_AssetBundleLoading_Prefix(AssetBundleLoadingParameters parameters, out AssetBundleCreateRequest request)
		{
			//IL_0129: Unknown result type (might be due to invalid IL or missing references)
			//IL_012f: Expected O, but got Unknown
			AsyncAssetBundleLoadingContext asyncAssetBundleLoadingContext = new AsyncAssetBundleLoadingContext(parameters);
			if (_isFiringAssetBundle && (_isRecursionDisabledPermanently || !RecursionEnabled))
			{
				request = null;
				return asyncAssetBundleLoadingContext;
			}
			try
			{
				_isFiringAssetBundle = true;
				if (_logAllLoadedResources)
				{
					XuaLogger.ResourceRedirector.Debug("Loading Asset Bundle (async): (" + asyncAssetBundleLoadingContext.GetNormalizedPath() + ").");
				}
				List<PrioritizedCallback<Delegate>> prefixRedirectionsForAsyncAssetBundles = PrefixRedirectionsForAsyncAssetBundles;
				int count = prefixRedirectionsForAsyncAssetBundles.Count;
				for (int i = 0; i < count; i++)
				{
					PrioritizedCallback<Delegate> prioritizedCallback = prefixRedirectionsForAsyncAssetBundles[i];
					if (prioritizedCallback.IsBeingCalled)
					{
						continue;
					}
					try
					{
						prioritizedCallback.IsBeingCalled = true;
						if (prioritizedCallback.Callback is Action<AsyncAssetBundleLoadingContext> action)
						{
							action(asyncAssetBundleLoadingContext);
						}
						else if (prioritizedCallback.Callback is Action<IAssetBundleLoadingContext> action2)
						{
							action2(asyncAssetBundleLoadingContext);
						}
						if (asyncAssetBundleLoadingContext.SkipRemainingPrefixes)
						{
							break;
						}
					}
					catch (Exception ex)
					{
						XuaLogger.ResourceRedirector.Error(ex, "An error occurred while invoking AssetBundleLoading event.");
					}
					finally
					{
						RecursionEnabled = true;
						prioritizedCallback.IsBeingCalled = false;
					}
				}
			}
			catch (Exception ex2)
			{
				XuaLogger.ResourceRedirector.Error(ex2, "An error occurred while invoking AsyncAssetBundleLoading event.");
			}
			finally
			{
				_isFiringAssetBundle = false;
			}
			if (asyncAssetBundleLoadingContext.ResolveType == AsyncAssetBundleLoadingResolve.ThroughRequest)
			{
				request = asyncAssetBundleLoadingContext.Request;
			}
			else
			{
				if (asyncAssetBundleLoadingContext.ResolveType != AsyncAssetBundleLoadingResolve.ThroughBundle)
				{
					throw new InvalidOperationException("Found invalid ResolveType on context: " + asyncAssetBundleLoadingContext.ResolveType);
				}
				request = new AssetBundleCreateRequest();
				if (!asyncAssetBundleLoadingContext.SkipOriginalCall)
				{
					XuaLogger.ResourceRedirector.Warn("Resolving sync over async asset load, but 'SkipOriginalCall' was not set to true. Forcing it to true.");
					asyncAssetBundleLoadingContext.SkipOriginalCall = true;
				}
			}
			return asyncAssetBundleLoadingContext;
		}

		internal static void Hook_AssetBundleLoading_Postfix(AsyncAssetBundleLoadingContext context, AssetBundleCreateRequest request)
		{
			if (request != null)
			{
				ExtensionDataHelper.SetExtensionData<AsyncAssetBundleLoadInfo>((object)request, new AsyncAssetBundleLoadInfo(context.Parameters, context.Bundle, context.SkipAllPostfixes, context.ResolveType));
			}
		}

		internal static void Hook_AssetLoading_Postfix(AsyncAssetLoadingContext context, AssetBundleRequest request)
		{
			if (request != null)
			{
				ExtensionDataHelper.SetExtensionData<AsyncAssetLoadInfo>((object)request, new AsyncAssetLoadInfo(context.Parameters, context.Bundle, context.SkipAllPostfixes, context.ResolveType, context.Assets));
			}
		}

		internal static AssetLoadingContext Hook_AssetLoading_Prefix(AssetLoadingParameters parameters, AssetBundle parentBundle, ref Object asset)
		{
			Object[] assets = null;
			AssetLoadingContext result = Hook_AssetLoading_Prefix(parameters, parentBundle, ref assets);
			if (assets == null || assets.Length == 0)
			{
				asset = null;
				return result;
			}
			if (assets.Length > 1)
			{
				XuaLogger.ResourceRedirector.Warn("Illegal behaviour by redirection handler in AssetLoadeding event. Returned more than one asset to call requiring only a single asset.");
				asset = assets[0];
				return result;
			}
			if (assets.Length == 1)
			{
				asset = assets[0];
			}
			return result;
		}

		internal static AssetLoadingContext Hook_AssetLoading_Prefix(AssetLoadingParameters parameters, AssetBundle bundle, ref Object[] assets)
		{
			AssetLoadingContext assetLoadingContext = new AssetLoadingContext(parameters, bundle);
			try
			{
				if (_isFiringAsset && (_isRecursionDisabledPermanently || !RecursionEnabled))
				{
					return assetLoadingContext;
				}
				_isFiringAsset = true;
				List<PrioritizedCallback<Delegate>> prefixRedirectionsForAssetsPerCall = PrefixRedirectionsForAssetsPerCall;
				int count = prefixRedirectionsForAssetsPerCall.Count;
				for (int i = 0; i < count; i++)
				{
					PrioritizedCallback<Delegate> prioritizedCallback = prefixRedirectionsForAssetsPerCall[i];
					if (prioritizedCallback.IsBeingCalled)
					{
						continue;
					}
					try
					{
						prioritizedCallback.IsBeingCalled = true;
						if (prioritizedCallback.Callback is Action<AssetLoadingContext> action)
						{
							action(assetLoadingContext);
						}
						else if (prioritizedCallback.Callback is Action<IAssetLoadingContext> action2)
						{
							action2(assetLoadingContext);
						}
						if (assetLoadingContext.SkipRemainingPrefixes)
						{
							break;
						}
					}
					catch (Exception ex)
					{
						XuaLogger.ResourceRedirector.Error(ex, "An error occurred while invoking AssetLoading event.");
					}
					finally
					{
						RecursionEnabled = true;
						prioritizedCallback.IsBeingCalled = false;
					}
				}
				assets = assetLoadingContext.Assets;
			}
			catch (Exception ex2)
			{
				XuaLogger.ResourceRedirector.Error(ex2, "An error occurred while invoking AssetLoading event.");
			}
			finally
			{
				_isFiringAsset = false;
			}
			return assetLoadingContext;
		}

		internal static AsyncAssetLoadingContext Hook_AsyncAssetLoading_Prefix(AssetLoadingParameters parameters, AssetBundle bundle, ref AssetBundleRequest request)
		{
			//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f2: Expected O, but got Unknown
			AsyncAssetLoadingContext asyncAssetLoadingContext = new AsyncAssetLoadingContext(parameters, bundle);
			try
			{
				if (_isFiringAsset && (_isRecursionDisabledPermanently || !RecursionEnabled))
				{
					return asyncAssetLoadingContext;
				}
				_isFiringAsset = true;
				List<PrioritizedCallback<Delegate>> prefixRedirectionsForAsyncAssetsPerCall = PrefixRedirectionsForAsyncAssetsPerCall;
				int count = prefixRedirectionsForAsyncAssetsPerCall.Count;
				for (int i = 0; i < count; i++)
				{
					PrioritizedCallback<Delegate> prioritizedCallback = prefixRedirectionsForAsyncAssetsPerCall[i];
					if (prioritizedCallback.IsBeingCalled)
					{
						continue;
					}
					try
					{
						prioritizedCallback.IsBeingCalled = true;
						if (prioritizedCallback.Callback is Action<AsyncAssetLoadingContext> action)
						{
							action(asyncAssetLoadingContext);
						}
						else if (prioritizedCallback.Callback is Action<IAssetLoadingContext> action2)
						{
							action2(asyncAssetLoadingContext);
						}
						if (asyncAssetLoadingContext.SkipRemainingPrefixes)
						{
							break;
						}
					}
					catch (Exception ex)
					{
						XuaLogger.ResourceRedirector.Error(ex, "An error occurred while invoking AsyncAssetLoading event.");
					}
					finally
					{
						RecursionEnabled = true;
						prioritizedCallback.IsBeingCalled = false;
					}
				}
				if (asyncAssetLoadingContext.ResolveType == AsyncAssetLoadingResolve.ThroughRequest)
				{
					request = asyncAssetLoadingContext.Request;
				}
				else
				{
					if (asyncAssetLoadingContext.ResolveType != AsyncAssetLoadingResolve.ThroughAssets)
					{
						throw new InvalidOperationException("Found invalid ResolveType on context: " + asyncAssetLoadingContext.ResolveType);
					}
					request = new AssetBundleRequest();
					if (!asyncAssetLoadingContext.SkipOriginalCall)
					{
						XuaLogger.ResourceRedirector.Warn("Resolving sync over async asset load, but 'SkipOriginalCall' was not set to true. Forcing it to true.");
						asyncAssetLoadingContext.SkipOriginalCall = true;
					}
				}
			}
			catch (Exception ex2)
			{
				XuaLogger.ResourceRedirector.Error(ex2, "An error occurred while invoking AsyncAssetLoading event.");
			}
			finally
			{
				_isFiringAsset = false;
			}
			return asyncAssetLoadingContext;
		}

		internal static void Hook_AssetLoaded_Postfix(AssetLoadingParameters parameters, AssetBundle parentBundle, ref Object asset)
		{
			Object[] assets = (Object[])(object)((!(asset == (Object)null)) ? new Object[1] { asset } : new Object[0]);
			Hook_AssetLoaded_Postfix(parameters, parentBundle, ref assets);
			if (assets == null || assets.Length == 0)
			{
				asset = null;
			}
			else if (assets.Length > 1)
			{
				XuaLogger.ResourceRedirector.Warn("Illegal behaviour by redirection handler in AssetLoaded event. Returned more than one asset to call requiring only a single asset.");
				asset = assets[0];
			}
			else if (assets.Length == 1)
			{
				asset = assets[0];
			}
		}

		internal static void Hook_AssetLoaded_Postfix(AssetLoadingParameters parameters, AssetBundle bundle, ref Object[] assets)
		{
			FireAssetLoadedEvent(parameters.ToAssetLoadedParameters(), bundle, ref assets);
		}

		internal static void Hook_ResourceLoaded_Postfix(ResourceLoadedParameters parameters, ref Object asset)
		{
			Object[] assets = (Object[])(object)((!(asset == (Object)null)) ? new Object[1] { asset } : new Object[0]);
			Hook_ResourceLoaded_Postfix(parameters, ref assets);
			if (assets == null || assets.Length == 0)
			{
				asset = null;
			}
			else if (assets.Length > 1)
			{
				XuaLogger.ResourceRedirector.Warn("Illegal behaviour by redirection handler in ResourceLoaded event. Returned more than one asset to call requiring only a single asset.");
				asset = assets[0];
			}
			else if (assets.Length == 1)
			{
				asset = assets[0];
			}
		}

		internal static void Hook_ResourceLoaded_Postfix(ResourceLoadedParameters parameters, ref Object[] assets)
		{
			FireResourceLoadedEvent(parameters, ref assets);
		}

		internal static void FireAssetLoadedEvent(AssetLoadedParameters parameters, AssetBundle assetBundle, ref Object[] assets)
		{
			Object[] array = assets?.ToArray();
			try
			{
				AssetLoadedContext assetLoadedContext = new AssetLoadedContext(parameters, assetBundle, assets);
				if (_isFiringAsset && (_isRecursionDisabledPermanently || !RecursionEnabled))
				{
					return;
				}
				_isFiringAsset = true;
				if (_logAllLoadedResources && assets != null)
				{
					for (int i = 0; i < assets.Length; i++)
					{
						Object val = assets[i];
						if (val != (Object)null)
						{
							string uniqueFileSystemAssetPath = assetLoadedContext.GetUniqueFileSystemAssetPath(val);
							XuaLogger.ResourceRedirector.Debug("Loaded Asset: '" + ObjectExtensions.GetUnityType((object)val).FullName + "', Load Type: '" + parameters.LoadType.ToString() + "', Unique Path: (" + uniqueFileSystemAssetPath + ").");
						}
					}
				}
				List<PrioritizedCallback<Action<AssetLoadedContext>>> postfixRedirectionsForAssetsPerCall = PostfixRedirectionsForAssetsPerCall;
				int count = postfixRedirectionsForAssetsPerCall.Count;
				for (int j = 0; j < count; j++)
				{
					PrioritizedCallback<Action<AssetLoadedContext>> prioritizedCallback = postfixRedirectionsForAssetsPerCall[j];
					if (prioritizedCallback.IsBeingCalled)
					{
						continue;
					}
					try
					{
						prioritizedCallback.IsBeingCalled = true;
						prioritizedCallback.Callback(assetLoadedContext);
						if (assetLoadedContext.SkipRemainingPostfixes)
						{
							break;
						}
					}
					catch (Exception ex)
					{
						XuaLogger.ResourceRedirector.Error(ex, "An error occurred while invoking AssetLoaded event.");
					}
					finally
					{
						RecursionEnabled = true;
						prioritizedCallback.IsBeingCalled = false;
					}
				}
				assets = assetLoadedContext.Assets;
				if (assetLoadedContext.SkipRemainingPostfixes || assets == null)
				{
					return;
				}
				int num = assets.Length;
				for (int k = 0; k < num; k++)
				{
					Object val2 = assets[k];
					if (val2 != (Object)null)
					{
						AssetLoadedContext assetLoadedContext2 = new AssetLoadedContext(parameters, assetBundle, val2);
						List<PrioritizedCallback<Action<AssetLoadedContext>>> postfixRedirectionsForAssetsPerResource = PostfixRedirectionsForAssetsPerResource;
						int count2 = postfixRedirectionsForAssetsPerResource.Count;
						for (int l = 0; l < count2; l++)
						{
							PrioritizedCallback<Action<AssetLoadedContext>> prioritizedCallback2 = postfixRedirectionsForAssetsPerResource[l];
							if (prioritizedCallback2.IsBeingCalled)
							{
								continue;
							}
							try
							{
								prioritizedCallback2.IsBeingCalled = true;
								prioritizedCallback2.Callback(assetLoadedContext2);
								if (assetLoadedContext2.Asset != (Object)null)
								{
									assets[k] = assetLoadedContext2.Asset;
								}
								else
								{
									XuaLogger.ResourceRedirector.Warn($"Illegal behaviour by redirection handler in AssetLoaded event. You must not remove an asset reference when hooking with behaviour {HookBehaviour.OneCallbackPerResourceLoaded}.");
								}
								if (assetLoadedContext2.SkipRemainingPostfixes)
								{
									break;
								}
							}
							catch (Exception ex2)
							{
								XuaLogger.ResourceRedirector.Error(ex2, "An error occurred while invoking AssetLoaded event.");
							}
							finally
							{
								RecursionEnabled = true;
								prioritizedCallback2.IsBeingCalled = false;
							}
						}
					}
					else
					{
						XuaLogger.ResourceRedirector.Error("Found unexpected null asset during AssetLoaded event.");
					}
				}
			}
			catch (Exception ex3)
			{
				XuaLogger.ResourceRedirector.Error(ex3, "An error occurred while invoking AssetLoaded event.");
			}
			finally
			{
				_isFiringAsset = false;
				if (array != null)
				{
					Object[] array2 = array;
					for (int m = 0; m < array2.Length; m++)
					{
						ExtensionDataHelper.GetOrCreateExtensionData<ResourceExtensionData>((object)array2[m]).HasBeenRedirected = true;
					}
				}
			}
		}

		internal static void FireResourceLoadedEvent(ResourceLoadedParameters parameters, ref Object[] assets)
		{
			Object[] array = assets?.ToArray();
			try
			{
				ResourceLoadedContext resourceLoadedContext = new ResourceLoadedContext(parameters, assets);
				if (_isFiringResource && (_isRecursionDisabledPermanently || !RecursionEnabled))
				{
					return;
				}
				_isFiringResource = true;
				if (_logAllLoadedResources && assets != null)
				{
					for (int i = 0; i < assets.Length; i++)
					{
						Object val = assets[i];
						if (val != (Object)null)
						{
							string uniqueFileSystemAssetPath = resourceLoadedContext.GetUniqueFileSystemAssetPath(val);
							XuaLogger.ResourceRedirector.Debug("Loaded Asset: '" + ObjectExtensions.GetUnityType((object)val).FullName + "', Load Type: '" + parameters.LoadType.ToString() + "', Unique Path: (" + uniqueFileSystemAssetPath + ").");
						}
					}
				}
				List<PrioritizedCallback<Action<ResourceLoadedContext>>> postfixRedirectionsForResourcesPerCall = PostfixRedirectionsForResourcesPerCall;
				int count = postfixRedirectionsForResourcesPerCall.Count;
				for (int j = 0; j < count; j++)
				{
					PrioritizedCallback<Action<ResourceLoadedContext>> prioritizedCallback = postfixRedirectionsForResourcesPerCall[j];
					if (prioritizedCallback.IsBeingCalled)
					{
						continue;
					}
					try
					{
						prioritizedCallback.IsBeingCalled = true;
						prioritizedCallback.Callback(resourceLoadedContext);
						if (resourceLoadedContext.SkipRemainingPostfixes)
						{
							break;
						}
					}
					catch (Exception ex)
					{
						XuaLogger.ResourceRedirector.Error(ex, "An error occurred while invoking ResourceLoaded event.");
					}
					finally
					{
						RecursionEnabled = true;
						prioritizedCallback.IsBeingCalled = false;
					}
				}
				assets = resourceLoadedContext.Assets;
				if (resourceLoadedContext.SkipRemainingPostfixes || assets == null)
				{
					return;
				}
				int num = assets.Length;
				for (int k = 0; k < num; k++)
				{
					Object val2 = assets[k];
					if (val2 != (Object)null)
					{
						ResourceLoadedContext resourceLoadedContext2 = new ResourceLoadedContext(parameters, val2);
						List<PrioritizedCallback<Action<ResourceLoadedContext>>> postfixRedirectionsForResourcesPerResource = PostfixRedirectionsForResourcesPerResource;
						int count2 = postfixRedirectionsForResourcesPerResource.Count;
						for (int l = 0; l < count2; l++)
						{
							PrioritizedCallback<Action<ResourceLoadedContext>> prioritizedCallback2 = postfixRedirectionsForResourcesPerResource[l];
							if (prioritizedCallback2.IsBeingCalled)
							{
								continue;
							}
							try
							{
								prioritizedCallback2.IsBeingCalled = true;
								prioritizedCallback2.Callback(resourceLoadedContext2);
								if (resourceLoadedContext2.Asset != (Object)null)
								{
									assets[k] = resourceLoadedContext2.Asset;
								}
								else
								{
									XuaLogger.ResourceRedirector.Warn($"Illegal behaviour by redirection handler in ResourceLoaded event. You must not remove an asset reference when hooking with behaviour {HookBehaviour.OneCallbackPerResourceLoaded}.");
								}
								if (resourceLoadedContext2.SkipRemainingPostfixes)
								{
									break;
								}
							}
							catch (Exception ex2)
							{
								XuaLogger.ResourceRedirector.Error(ex2, "An error occurred while invoking ResourceLoaded event.");
							}
							finally
							{
								RecursionEnabled = true;
								prioritizedCallback2.IsBeingCalled = false;
							}
						}
					}
					else
					{
						XuaLogger.ResourceRedirector.Error("Found unexpected null asset during ResourceLoaded event.");
					}
				}
			}
			catch (Exception ex3)
			{
				XuaLogger.ResourceRedirector.Error(ex3, "An error occurred while invoking ResourceLoaded event.");
			}
			finally
			{
				_isFiringResource = false;
				if (array != null)
				{
					Object[] array2 = array;
					for (int m = 0; m < array2.Length; m++)
					{
						ExtensionDataHelper.GetOrCreateExtensionData<ResourceExtensionData>((object)array2[m]).HasBeenRedirected = true;
					}
				}
			}
		}

		private static void LogEventRegistration(string eventType, IEnumerable callbacks)
		{
			XuaLogger.ResourceRedirector.Debug("Registered new callback for " + eventType + ".");
			LogNewCallbackOrder(eventType, callbacks);
		}

		private static void LogEventUnregistration(string eventType, IEnumerable callbacks)
		{
			XuaLogger.ResourceRedirector.Debug("Unregistered callback for " + eventType + ".");
			LogNewCallbackOrder(eventType, callbacks);
		}

		private static void LogNewCallbackOrder(string eventType, IEnumerable callbacks)
		{
			if (!LogCallbackOrder)
			{
				return;
			}
			XuaLogger.ResourceRedirector.Debug("New callback order for " + eventType + ":");
			foreach (object callback in callbacks)
			{
				XuaLogger.ResourceRedirector.Debug(callback.ToString());
			}
		}

		public static void RegisterAssetBundleLoadedHook(int priority, Action<AssetBundleLoadedContext> action)
		{
			if (action == null)
			{
				throw new ArgumentNullException("action");
			}
			PrioritizedCallback<Action<AssetBundleLoadedContext>> prioritizedCallback = PrioritizedCallback.Create(action, priority);
			if (PostfixRedirectionsForAssetBundles.Contains(prioritizedCallback))
			{
				throw new ArgumentException("This callback has already been registered.", "action");
			}
			Initialize();
			ListExtensions.BinarySearchInsert<PrioritizedCallback<Action<AssetBundleLoadedContext>>>(PostfixRedirectionsForAssetBundles, prioritizedCallback);
			LogEventRegistration("AssetBundleLoaded", PostfixRedirectionsForAssetBundles);
		}

		public static void RegisterAssetBundleLoadedHook(Action<AssetBundleLoadedContext> action)
		{
			RegisterAssetBundleLoadedHook(0, action);
		}

		public static void UnregisterAssetBundleLoadedHook(Action<AssetBundleLoadedContext> action)
		{
			if (action == null)
			{
				throw new ArgumentNullException("action");
			}
			PostfixRedirectionsForAssetBundles.RemoveAll((PrioritizedCallback<Action<AssetBundleLoadedContext>> x) => object.Equals(x.Callback, action));
			LogEventUnregistration("AssetBundleLoaded", PostfixRedirectionsForAssetBundles);
		}

		public static void RegisterAssetLoadingHook(int priority, Action<AssetLoadingContext> action)
		{
			if (action == null)
			{
				throw new ArgumentNullException("action");
			}
			PrioritizedCallback<Delegate> prioritizedCallback = PrioritizedCallback.Create((Delegate)action, priority);
			if (PrefixRedirectionsForAssetsPerCall.Contains(prioritizedCallback))
			{
				throw new ArgumentException("This callback has already been registered.", "action");
			}
			Initialize();
			ListExtensions.BinarySearchInsert<PrioritizedCallback<Delegate>>(PrefixRedirectionsForAssetsPerCall, prioritizedCallback);
			LogEventRegistration("AssetLoading", PrefixRedirectionsForAssetsPerCall);
		}

		public static void RegisterAssetLoadingHook(Action<AssetLoadingContext> action)
		{
			RegisterAssetLoadingHook(0, action);
		}

		public static void UnregisterAssetLoadingHook(Action<AssetLoadingContext> action)
		{
			if (action == null)
			{
				throw new ArgumentNullException("action");
			}
			PrefixRedirectionsForAssetsPerCall.RemoveAll((PrioritizedCallback<Delegate> x) => object.Equals(x.Callback, action));
			LogEventUnregistration("AssetLoading", PrefixRedirectionsForAssetsPerCall);
		}

		public static void RegisterAsyncAssetLoadingHook(int priority, Action<AsyncAssetLoadingContext> action)
		{
			if (action == null)
			{
				throw new ArgumentNullException("action");
			}
			PrioritizedCallback<Delegate> prioritizedCallback = PrioritizedCallback.Create((Delegate)action, priority);
			if (PrefixRedirectionsForAsyncAssetsPerCall.Contains(prioritizedCallback))
			{
				throw new ArgumentException("This callback has already been registered.", "action");
			}
			Initialize();
			ListExtensions.BinarySearchInsert<PrioritizedCallback<Delegate>>(PrefixRedirectionsForAsyncAssetsPerCall, prioritizedCallback);
			LogEventRegistration("AsyncAssetLoading", PrefixRedirectionsForAsyncAssetsPerCall);
		}

		public static void RegisterAsyncAssetLoadingHook(Action<AsyncAssetLoadingContext> action)
		{
			RegisterAsyncAssetLoadingHook(0, action);
		}

		public static void UnregisterAsyncAssetLoadingHook(Action<AsyncAssetLoadingContext> action)
		{
			if (action == null)
			{
				throw new ArgumentNullException("action");
			}
			PrefixRedirectionsForAsyncAssetsPerCall.RemoveAll((PrioritizedCallback<Delegate> x) => object.Equals(x.Callback, action));
			LogEventUnregistration("AsyncAssetLoading", PrefixRedirectionsForAsyncAssetsPerCall);
		}

		public static void RegisterAsyncAndSyncAssetLoadingHook(int priority, Action<IAssetLoadingContext> action)
		{
			if (action == null)
			{
				throw new ArgumentNullException("action");
			}
			PrioritizedCallback<Delegate> prioritizedCallback = PrioritizedCallback.Create((Delegate)action, priority);
			if (PrefixRedirectionsForAsyncAssetsPerCall.Contains(prioritizedCallback))
			{
				throw new ArgumentException("This callback has already been registered.", "action");
			}
			Initialize();
			ListExtensions.BinarySearchInsert<PrioritizedCallback<Delegate>>(PrefixRedirectionsForAsyncAssetsPerCall, prioritizedCallback);
			LogEventRegistration("AsyncAssetLoading", PrefixRedirectionsForAsyncAssetsPerCall);
			ListExtensions.BinarySearchInsert<PrioritizedCallback<Delegate>>(PrefixRedirectionsForAssetsPerCall, prioritizedCallback);
			LogEventRegistration("AssetLoading", PrefixRedirectionsForAssetsPerCall);
		}

		public static void RegisterAsyncAndSyncAssetLoadingHook(Action<IAssetLoadingContext> action)
		{
			RegisterAsyncAndSyncAssetLoadingHook(0, action);
		}

		public static void UnregisterAsyncAndSyncAssetLoadingHook(Action<IAssetLoadingContext> action)
		{
			if (action == null)
			{
				throw new ArgumentNullException("action");
			}
			PrefixRedirectionsForAsyncAssetsPerCall.RemoveAll((PrioritizedCallback<Delegate> x) => object.Equals(x.Callback, action));
			LogEventUnregistration("AsyncAssetLoading", PrefixRedirectionsForAsyncAssetsPerCall);
			PrefixRedirectionsForAssetsPerCall.RemoveAll((PrioritizedCallback<Delegate> x) => object.Equals(x.Callback, action));
			LogEventUnregistration("AssetLoading", PrefixRedirectionsForAssetsPerCall);
		}

		public static void RegisterAssetLoadedHook(HookBehaviour behaviour, int priority, Action<AssetLoadedContext> action)
		{
			if (action == null)
			{
				throw new ArgumentNullException("action");
			}
			PrioritizedCallback<Action<AssetLoadedContext>> prioritizedCallback = PrioritizedCallback.Create(action, priority);
			if (PostfixRedirectionsForAssetsPerCall.Contains(prioritizedCallback) || PostfixRedirectionsForAssetsPerResource.Contains(prioritizedCallback))
			{
				throw new ArgumentException("This callback has already been registered.", "action");
			}
			Initialize();
			switch (behaviour)
			{
			case HookBehaviour.OneCallbackPerLoadCall:
				ListExtensions.BinarySearchInsert<PrioritizedCallback<Action<AssetLoadedContext>>>(PostfixRedirectionsForAssetsPerCall, prioritizedCallback);
				LogEventRegistration("AssetLoaded (" + behaviour.ToString() + ")", PostfixRedirectionsForAssetsPerCall);
				break;
			case HookBehaviour.OneCallbackPerResourceLoaded:
				ListExtensions.BinarySearchInsert<PrioritizedCallback<Action<AssetLoadedContext>>>(PostfixRedirectionsForAssetsPerResource, prioritizedCallback);
				LogEventRegistration("AssetLoaded (" + behaviour.ToString() + ")", PostfixRedirectionsForAssetsPerResource);
				break;
			}
		}

		public static void RegisterAssetLoadedHook(HookBehaviour behaviour, Action<AssetLoadedContext> action)
		{
			RegisterAssetLoadedHook(behaviour, 0, action);
		}

		public static void UnregisterAssetLoadedHook(Action<AssetLoadedContext> action)
		{
			if (action == null)
			{
				throw new ArgumentNullException("action");
			}
			if (PostfixRedirectionsForAssetsPerCall.RemoveAll((PrioritizedCallback<Action<AssetLoadedContext>> x) => x.Callback == action) > 0)
			{
				LogEventRegistration("AssetLoaded (" + HookBehaviour.OneCallbackPerLoadCall.ToString() + ")", PostfixRedirectionsForAssetsPerCall);
			}
			if (PostfixRedirectionsForAssetsPerResource.RemoveAll((PrioritizedCallback<Action<AssetLoadedContext>> x) => x.Callback == action) > 0)
			{
				LogEventRegistration("AssetLoaded (" + HookBehaviour.OneCallbackPerResourceLoaded.ToString() + ")", PostfixRedirectionsForAssetsPerResource);
			}
		}

		public static void RegisterAssetBundleLoadingHook(int priority, Action<AssetBundleLoadingContext> action)
		{
			if (action == null)
			{
				throw new ArgumentNullException("action");
			}
			PrioritizedCallback<Delegate> prioritizedCallback = PrioritizedCallback.Create((Delegate)action, priority);
			if (PrefixRedirectionsForAssetBundles.Contains(prioritizedCallback))
			{
				throw new ArgumentException("This callback has already been registered.", "action");
			}
			Initialize();
			ListExtensions.BinarySearchInsert<PrioritizedCallback<Delegate>>(PrefixRedirectionsForAssetBundles, prioritizedCallback);
			LogEventRegistration("AssetBundleLoading", PrefixRedirectionsForAssetBundles);
		}

		public static void RegisterAssetBundleLoadingHook(Action<AssetBundleLoadingContext> action)
		{
			RegisterAssetBundleLoadingHook(0, action);
		}

		public static void UnregisterAssetBundleLoadingHook(Action<AssetBundleLoadingContext> action)
		{
			if (action == null)
			{
				throw new ArgumentNullException("action");
			}
			PrefixRedirectionsForAssetBundles.RemoveAll((PrioritizedCallback<Delegate> x) => object.Equals(x.Callback, action));
			LogEventUnregistration("AssetBundleLoading", PrefixRedirectionsForAssetBundles);
		}

		public static void RegisterAsyncAssetBundleLoadingHook(int priority, Action<AsyncAssetBundleLoadingContext> action)
		{
			if (action == null)
			{
				throw new ArgumentNullException("action");
			}
			PrioritizedCallback<Delegate> prioritizedCallback = PrioritizedCallback.Create((Delegate)action, priority);
			if (PrefixRedirectionsForAsyncAssetBundles.Contains(prioritizedCallback))
			{
				throw new ArgumentException("This callback has already been registered.", "action");
			}
			Initialize();
			ListExtensions.BinarySearchInsert<PrioritizedCallback<Delegate>>(PrefixRedirectionsForAsyncAssetBundles, prioritizedCallback);
			LogEventRegistration("AsyncAssetBundleLoading", PrefixRedirectionsForAsyncAssetBundles);
		}

		public static void RegisterAsyncAssetBundleLoadingHook(Action<AsyncAssetBundleLoadingContext> action)
		{
			RegisterAsyncAssetBundleLoadingHook(0, action);
		}

		public static void UnregisterAsyncAssetBundleLoadingHook(Action<AsyncAssetBundleLoadingContext> action)
		{
			if (action == null)
			{
				throw new ArgumentNullException("action");
			}
			PrefixRedirectionsForAsyncAssetBundles.RemoveAll((PrioritizedCallback<Delegate> x) => object.Equals(x.Callback, action));
			LogEventUnregistration("AsyncAssetBundleLoading", PrefixRedirectionsForAsyncAssetBundles);
		}

		public static void RegisterAsyncAndSyncAssetBundleLoadingHook(int priority, Action<IAssetBundleLoadingContext> action)
		{
			if (action == null)
			{
				throw new ArgumentNullException("action");
			}
			PrioritizedCallback<Delegate> prioritizedCallback = PrioritizedCallback.Create((Delegate)action, priority);
			if (PrefixRedirectionsForAssetBundles.Contains(prioritizedCallback))
			{
				throw new ArgumentException("This callback has already been registered.", "action");
			}
			Initialize();
			ListExtensions.BinarySearchInsert<PrioritizedCallback<Delegate>>(PrefixRedirectionsForAssetBundles, prioritizedCallback);
			LogEventRegistration("AssetBundleLoading", PrefixRedirectionsForAssetBundles);
			ListExtensions.BinarySearchInsert<PrioritizedCallback<Delegate>>(PrefixRedirectionsForAsyncAssetBundles, prioritizedCallback);
			LogEventRegistration("AsyncAssetBundleLoading", PrefixRedirectionsForAsyncAssetBundles);
		}

		public static void RegisterAsyncAndSyncAssetBundleLoadingHook(Action<IAssetBundleLoadingContext> action)
		{
			RegisterAsyncAndSyncAssetBundleLoadingHook(0, action);
		}

		public static void UnregisterAsyncAndSyncAssetBundleLoadingHook(Action<IAssetBundleLoadingContext> action)
		{
			if (action == null)
			{
				throw new ArgumentNullException("action");
			}
			PrefixRedirectionsForAssetBundles.RemoveAll((PrioritizedCallback<Delegate> x) => object.Equals(x.Callback, action));
			LogEventUnregistration("AssetBundleLoading", PrefixRedirectionsForAssetBundles);
			PrefixRedirectionsForAsyncAssetBundles.RemoveAll((PrioritizedCallback<Delegate> x) => object.Equals(x.Callback, action));
			LogEventUnregistration("AsyncAssetBundleLoading", PrefixRedirectionsForAsyncAssetBundles);
		}

		public static void RegisterResourceLoadedHook(HookBehaviour behaviour, int priority, Action<ResourceLoadedContext> action)
		{
			if (action == null)
			{
				throw new ArgumentNullException("action");
			}
			PrioritizedCallback<Action<ResourceLoadedContext>> prioritizedCallback = PrioritizedCallback.Create(action, priority);
			if (PostfixRedirectionsForResourcesPerCall.Contains(prioritizedCallback) || PostfixRedirectionsForResourcesPerResource.Contains(prioritizedCallback))
			{
				throw new ArgumentException("This callback has already been registered.", "action");
			}
			Initialize();
			switch (behaviour)
			{
			case HookBehaviour.OneCallbackPerLoadCall:
				ListExtensions.BinarySearchInsert<PrioritizedCallback<Action<ResourceLoadedContext>>>(PostfixRedirectionsForResourcesPerCall, prioritizedCallback);
				LogEventRegistration("ResourceLoaded (" + behaviour.ToString() + ")", PostfixRedirectionsForResourcesPerCall);
				break;
			case HookBehaviour.OneCallbackPerResourceLoaded:
				ListExtensions.BinarySearchInsert<PrioritizedCallback<Action<ResourceLoadedContext>>>(PostfixRedirectionsForResourcesPerResource, prioritizedCallback);
				LogEventRegistration("ResourceLoaded (" + behaviour.ToString() + ")", PostfixRedirectionsForResourcesPerResource);
				break;
			}
		}

		public static void RegisterResourceLoadedHook(HookBehaviour behaviour, Action<ResourceLoadedContext> action)
		{
			RegisterResourceLoadedHook(behaviour, 0, action);
		}

		public static void UnregisterResourceLoadedHook(Action<ResourceLoadedContext> action)
		{
			if (action == null)
			{
				throw new ArgumentNullException("action");
			}
			if (PostfixRedirectionsForResourcesPerCall.RemoveAll((PrioritizedCallback<Action<ResourceLoadedContext>> x) => x.Callback == action) > 0)
			{
				LogEventRegistration("ResourceLoaded (" + HookBehaviour.OneCallbackPerLoadCall.ToString() + ")", PostfixRedirectionsForResourcesPerCall);
			}
			if (PostfixRedirectionsForResourcesPerResource.RemoveAll((PrioritizedCallback<Action<ResourceLoadedContext>> x) => x.Callback == action) > 0)
			{
				LogEventRegistration("ResourceLoaded (" + HookBehaviour.OneCallbackPerResourceLoaded.ToString() + ")", PostfixRedirectionsForResourcesPerResource);
			}
		}
	}
}
namespace XUnity.ResourceRedirector.Properties
{
	[GeneratedCode("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")]
	[DebuggerNonUserCode]
	[CompilerGenerated]
	internal class Resources
	{
		private static ResourceManager resourceMan;

		private static CultureInfo resourceCulture;

		[EditorBrowsable(EditorBrowsableState.Advanced)]
		internal static ResourceManager ResourceManager
		{
			get
			{
				if (resourceMan == null)
				{
					resourceMan = new ResourceManager("XUnity.ResourceRedirector.Properties.Resources", typeof(Resources).Assembly);
				}
				return resourceMan;
			}
		}

		[EditorBrowsable(EditorBrowsableState.Advanced)]
		internal static CultureInfo Culture
		{
			get
			{
				return resourceCulture;
			}
			set
			{
				resourceCulture = value;
			}
		}

		internal static byte[] empty => (byte[])ResourceManager.GetObject("empty", resourceCulture);

		internal Resources()
		{
		}
	}
}
namespace XUnity.ResourceRedirector.Hooks
{
	internal static class ResourceAndAssetHooks
	{
		public static readonly Type[] GeneralHooks = new Type[21]
		{
			typeof(AssetBundle_LoadFromFileAsync_Hook),
			typeof(AssetBundle_LoadFromFile_Hook),
			typeof(AssetBundle_LoadFromMemoryAsync_Hook),
			typeof(AssetBundle_LoadFromMemory_Hook),
			typeof(AssetBundle_LoadFromStreamAsync_Hook),
			typeof(AssetBundle_LoadFromStream_Hook),
			typeof(AssetBundle_mainAsset_Hook),
			typeof(AssetBundle_returnMainAsset_Hook),
			typeof(AssetBundle_Load_Hook),
			typeof(AssetBundle_LoadAsync_Hook),
			typeof(AssetBundle_LoadAll_Hook),
			typeof(AssetBundle_LoadAsset_Internal_Hook),
			typeof(AssetBundle_LoadAssetAsync_Internal_Hook),
			typeof(AssetBundle_LoadAssetWithSubAssets_Internal_Hook),
			typeof(AssetBundle_LoadAssetWithSubAssetsAsync_Internal_Hook),
			typeof(AssetBundleRequest_asset_Hook),
			typeof(AssetBundleRequest_allAssets_Hook),
			typeof(Resources_Load_Hook),
			typeof(Resources_LoadAll_Hook),
			typeof(Resources_GetBuiltinResource_Old_Hook),
			typeof(Resources_GetBuiltinResource_New_Hook)
		};

		public static readonly Type[] SyncOverAsyncHooks = new Type[10]
		{
			typeof(AssetBundleCreateRequest_assetBundle_Hook),
			typeof(AssetBundleCreateRequest_DisableCompatibilityChecks_Hook),
			typeof(AssetBundleCreateRequest_SetEnableCompatibilityChecks_Hook),
			typeof(AsyncOperation_isDone_Hook),
			typeof(AsyncOperation_progress_Hook),
			typeof(AsyncOperation_priority_Hook),
			typeof(AsyncOperation_set_priority_Hook),
			typeof(AsyncOperation_allowSceneActivation_Hook),
			typeof(AsyncOperation_set_allowSceneActivation_Hook),
			typeof(AsyncOperation_Finalize_Hook)
		};
	}
	internal static class AssetBundleCreateRequest_assetBundle_Hook
	{
		private delegate AssetBundle OriginalMethod(AssetBundleCreateRequest __instance);

		private static OriginalMethod _original;

		private static bool Prepare(object instance)
		{
			return UnityTypes.AssetBundleCreateRequest != null;
		}

		private static MethodBase TargetMethod(object instance)
		{
			TypeContainer assetBundleCreateRequest = UnityTypes.AssetBundleCreateRequest;
			return AccessToolsShim.Property((assetBundleCreateRequest != null) ? assetBundleCreateRequest.ClrType : null, "assetBundle")?.GetGetMethod();
		}

		private static bool Prefix(AssetBundleCreateRequest __instance, ref AssetBundle __result, ref AsyncAssetBundleLoadInfo __state)
		{
			if (ResourceRedirection.TryGetAssetBundle(__instance, out __state))
			{
				if (__state.ResolveType == AsyncAssetBundleLoadingResolve.ThroughBundle)
				{
					__result = __state.Bundle;
					return false;
				}
				return true;
			}
			return true;
		}

		private static void Postfix(ref AssetBundle __result, ref AsyncAssetBundleLoadInfo __state)
		{
			if (__state == null)
			{
				return;
			}
			if (!__state.SkipAllPostfixes)
			{
				ResourceRedirection.Hook_AssetBundleLoaded_Postfix(__state.Parameters, ref __result);
			}
			if ((Object)(object)__result != (Object)null && __state != null)
			{
				string path = __state.Parameters.Path;
				if (path != null)
				{
					ExtensionDataHelper.GetOrCreateExtensionData<AssetBundleExtensionData>((object)__result).Path = path;
				}
			}
		}

		private static void MM_Init(object detour)
		{
			_original = DetourExtensions.GenerateTrampolineEx<OriginalMethod>(detour);
		}

		private static AssetBundle MM_Detour(AssetBundleCreateRequest __instance)
		{
			AssetBundle __result = null;
			AsyncAssetBundleLoadInfo __state = null;
			if (Prefix(__instance, ref __result, ref __state))
			{
				__result = _original(__instance);
			}
			Postfix(ref __result, ref __state);
			return __result;
		}
	}
	internal static class AssetBundleCreateRequest_DisableCompatibilityChecks_Hook
	{
		private delegate void OriginalMethod(AssetBundleCreateRequest __instance);

		private static OriginalMethod _original;

		private static bool Prepare(object instance)
		{
			TypeContainer assetBundleCreateRequest = UnityTypes.AssetBundleCreateRequest;
			return (object)AccessToolsShim.Method((assetBundleCreateRequest != null) ? assetBundleCreateRequest.ClrType : null, "SetEnableCompatibilityChecks", new Type[1] { typeof(bool) }) == null;
		}

		private static MethodBase TargetMethod(object instance)
		{
			TypeContainer assetBundleCreateRequest = UnityTypes.AssetBundleCreateRequest;
			return AccessToolsShim.Method((assetBundleCreateRequest != null) ? assetBundleCreateRequest.ClrType : null, "DisableCompatibilityChecks", new Type[0]);
		}

		private static bool Prefix(AssetBundleCreateRequest __instance)
		{
			return !ResourceRedirection.ShouldBlockAsyncOperationMethods(__instance);
		}

		private static void MM_Init(object detour)
		{
			_original = DetourExtensions.GenerateTrampolineEx<OriginalMethod>(detour);
		}

		private static void MM_Detour(AssetBundleCreateRequest __instance)
		{
			if (Prefix(__instance))
			{
				_original(__instance);
			}
		}
	}
	internal static class AssetBundleCreateRequest_SetEnableCompatibilityChecks_Hook
	{
		private delegate void OriginalMethod(AssetBundleCreateRequest __instance, bool set);

		private static OriginalMethod _original;

		private static bool Prepare(object instance)
		{
			TypeContainer assetBundleCreateRequest = UnityTypes.AssetBundleCreateRequest;
			return (object)AccessToolsShim.Method((assetBundleCreateRequest != null) ? assetBundleCreateRequest.ClrType : null, "SetEnableCompatibilityChecks", new Type[1] { typeof(bool) }) != null;
		}

		private static MethodBase TargetMethod(object instance)
		{
			TypeContainer assetBundleCreateRequest = UnityTypes.AssetBundleCreateRequest;
			return AccessToolsShim.Method((assetBundleCreateRequest != null) ? assetBundleCreateRequest.ClrType : null, "SetEnableCompatibilityChecks", new Type[1] { typeof(bool) });
		}

		private static bool Prefix(AssetBundleCreateRequest __instance, bool set)
		{
			return !ResourceRedirection.ShouldBlockAsyncOperationMethods(__instance);
		}

		private static void MM_Init(object detour)
		{
			_original = DetourExtensions.GenerateTrampolineEx<OriginalMethod>(detour);
		}

		private static void MM_Detour(AssetBundleCreateRequest __instance, bool set)
		{
			if (Prefix(__instance, set))
			{
				_original(__instance, set);
			}
		}
	}
	internal static class AssetBundle_LoadFromFileAsync_Hook
	{
		private delegate AssetBundleCreateRequest OriginalMethod(string path, uint crc, ulong offset);

		private static OriginalMethod _original;

		private static bool Prepare(object instance)
		{
			return UnityTypes.AssetBundle != null;
		}

		private static MethodBase TargetMethod(object instance)
		{
			TypeContainer assetBundle = UnityTypes.AssetBundle;
			MethodInfo methodInfo = AccessToolsShim.Method((assetBundle != null) ? assetBundle.ClrType : null, "LoadFromFileAsync_Internal", new Type[3]
			{
				typeof(string),
				typeof(uint),
				typeof(ulong)
			});
			if ((object)methodInfo == null)
			{
				TypeContainer assetBundle2 = UnityTypes.AssetBundle;
				methodInfo = AccessToolsShim.Method((assetBundle2 != null) ? assetBundle2.ClrType : null, "LoadFromFileAsync", new Type[3]
				{
					typeof(string),
					typeof(uint),
					typeof(ulong)
				});
			}
			return methodInfo;
		}

		private static bool Prefix(ref string path, ref uint crc, ref ulong offset, ref AssetBundleCreateRequest __result, ref AsyncAssetBundleLoadingContext __state)
		{
			AssetBundleLoadingParameters parameters = new AssetBundleLoadingParameters(null, path, crc, offset, null, 0u, AssetBundleLoadType.LoadFromFile);
			__state = ResourceRedirection.Hook_AssetBundleLoading_Prefix(parameters, out __result);
			AssetBundleLoadingParameters parameters2 = __state.Parameters;
			path = parameters2.Path;
			crc = parameters2.Crc;
			offset = parameters2.Offset;
			return !__state.SkipOriginalCall;
		}

		private static void Postfix(ref AssetBundleCreateRequest __result, ref AsyncAssetBundleLoadingContext __state)
		{
			ResourceRedirection.Hook_AssetBundleLoading_Postfix(__state, __result);
		}

		private static void MM_Init(object detour)
		{
			_original = DetourExtensions.GenerateTrampolineEx<OriginalMethod>(detour);
		}

		private static AssetBundleCreateRequest MM_Detour(string path, uint crc, ulong offset)
		{
			AssetBundleCreateRequest __result = null;
			AsyncAssetBundleLoadingContext __state = null;
			if (Prefix(ref path, ref crc, ref offset, ref __result, ref __state))
			{
				__result = _original(path, crc, offset);
			}
			Postfix(ref __result, ref __state);
			return __result;
		}
	}
	internal static class AssetBundle_LoadFromFile_Hook
	{
		private delegate AssetBundle OriginalMethod(string path, uint crc, ulong offset);

		private static OriginalMethod _original;

		private static bool Prepare(object instance)
		{
			return UnityTypes.AssetBundle != null;
		}

		private static MethodBase TargetMethod(object instance)
		{
			TypeContainer assetBundle = UnityTypes.AssetBundle;
			MethodInfo methodInfo = AccessToolsShim.Method((assetBundle != null) ? assetBundle.ClrType : null, "LoadFromFile_Internal", new Type[3]
			{
				typeof(string),
				typeof(uint),
				typeof(ulong)
			});
			if ((object)methodInfo == null)
			{
				TypeContainer assetBundle2 = UnityTypes.AssetBundle;
				methodInfo = AccessToolsShim.Method((assetBundle2 != null) ? assetBundle2.ClrType : null, "LoadFromFile", new Type[3]
				{
					typeof(string),
					typeof(uint),
					typeof(ulong)
				});
			}
			return methodInfo;
		}

		private static bool Prefix(ref string path, ref uint crc, ref ulong offset, ref AssetBundle __result, ref AssetBundleLoadingContext __state)
		{
			AssetBundleLoadingParameters parameters = new AssetBundleLoadingParameters(null, path, crc, offset, null, 0u, AssetBundleLoadType.LoadFromFile);
			__state = ResourceRedirection.Hook_AssetBundleLoading_Prefix(parameters, out __result);
			AssetBundleLoadingParameters parameters2 = __state.Parameters;
			path = parameters2.Path;
			crc = parameters2.Crc;
			offset = parameters2.Offset;
			return !__state.SkipOriginalCall;
		}

		private static void Postfix(ref AssetBundle __result, ref AssetBundleLoadingContext __state)
		{
			if (!__state.SkipAllPostfixes)
			{
				ResourceRedirection.Hook_AssetBundleLoaded_Postfix(__state.Parameters, ref __result);
			}
			if ((Object)(object)__result != (Object)null && __state.Parameters.Path != null)
			{
				ExtensionDataHelper.GetOrCreateExtensionData<AssetBundleExtensionData>((object)__result).Path = __state.Parameters.Path;
			}
		}

		private static void MM_Init(object detour)
		{
			_original = DetourExtensions.GenerateTrampolineEx<OriginalMethod>(detour);
		}

		private static AssetBundle MM_Detour(string path, uint crc, ulong offset)
		{
			AssetBundle __result = null;
			AssetBundleLoadingContext __state = null;
			if (Prefix(ref path, ref crc, ref offset, ref __result, ref __state))
			{
				__result = _original(path, crc, offset);
			}
			Postfix(ref __result, ref __state);
			return __result;
		}
	}
	internal static class AssetBundle_LoadFromMemoryAsync_Hook
	{
		private delegate AssetBundleCreateRequest OriginalMethod(byte[] binary, uint crc);

		private static OriginalMethod _original;

		private static bool Prepare(object instance)
		{
			return UnityTypes.AssetBundle != null;
		}

		private static MethodBase TargetMethod(object instance)
		{
			TypeContainer assetBundle = UnityTypes.AssetBundle;
			MethodInfo methodInfo = AccessToolsShim.Method((assetBundle != null) ? assetBundle.ClrType : null, "LoadFromMemoryAsync_Internal", new Type[2]
			{
				typeof(byte[]),
				typeof(uint)
			});
			if ((object)methodInfo == null)
			{
				TypeContainer assetBundle2 = UnityTypes.AssetBundle;
				methodInfo = AccessToolsShim.Method((assetBundle2 != null) ? assetBundle2.ClrType : null, "LoadFromMemoryAsync", new Type[2]
				{
					typeof(byte[]),
					typeof(uint)
				});
			}
			return methodInfo;
		}

		private static bool Prefix(ref byte[] binary, ref uint crc, ref AssetBundleCreateRequest __result, ref AsyncAssetBundleLoadingContext __state)
		{
			AssetBundleLoadingParameters parameters = new AssetBundleLoadingParameters(binary, null, crc, 0uL, null, 0u, AssetBundleLoadType.LoadFromMemory);
			__state = ResourceRedirection.Hook_AssetBundleLoading_Prefix(parameters, out __result);
			AssetBundleLoadingParameters parameters2 = __state.Parameters;
			binary = parameters2.Binary;
			crc = parameters2.Crc;
			return !__state.SkipOriginalCall;
		}

		private static void Postfix(ref AssetBundleCreateRequest __result, ref AsyncAssetBundleLoadingContext __state)
		{
			ResourceRedirection.Hook_AssetBundleLoading_Postfix(__state, __result);
		}

		private static void MM_Init(object detour)
		{
			_original = DetourExtensions.GenerateTrampolineEx<OriginalMethod>(detour);
		}

		private static AssetBundleCreateRequest MM_Detour(byte[] binary, uint crc)
		{
			AssetBundleCreateRequest __result = null;
			AsyncAssetBundleLoadingContext __state = null;
			if (Prefix(ref binary, ref crc, ref __result, ref __state))
			{
				__result = _original(binary, crc);
			}
			Postfix(ref __result, ref __state);
			return __result;
		}
	}
	internal static class AssetBundle_LoadFromMemory_Hook
	{
		private delegate AssetBundle OriginalMethod(byte[] binary, uint crc);

		private static OriginalMethod _original;

		private static bool Prepare(object instance)
		{
			return UnityTypes.AssetBundle != null;
		}

		private static MethodBase TargetMethod(object instance)
		{
			TypeContainer assetBundle = UnityTypes.AssetBundle;
			MethodInfo methodInfo = AccessToolsShim.Method((assetBundle != null) ? assetBundle.ClrType : null, "LoadFromMemory_Internal", new Type[2]
			{
				typeof(byte[]),
				typeof(uint)
			});
			if ((object)methodInfo == null)
			{
				TypeContainer assetBundle2 = UnityTypes.AssetBundle;
				methodInfo = AccessToolsShim.Method((assetBundle2 != null) ? assetBundle2.ClrType : null, "LoadFromMemory", new Type[2]
				{
					typeof(byte[]),
					typeof(uint)
				});
			}
			return methodInfo;
		}

		private static bool Prefix(ref byte[] binary, ref uint crc, ref AssetBundle __result, ref AssetBundleLoadingContext __state)
		{
			AssetBundleLoadingParameters parameters = new AssetBundleLoadingParameters(binary, null, crc, 0uL, null, 0u, AssetBundleLoadType.LoadFromMemory);
			__state = ResourceRedirection.Hook_AssetBundleLoading_Prefix(parameters, out __result);
			AssetBundleLoadingParameters parameters2 = __state.Parameters;
			binary = parameters2.Binary;
			crc = parameters2.Crc;
			return !__state.SkipOriginalCall;
		}

		private static void Postfix(ref AssetBundle __result, ref AssetBundleLoadingContext __state)
		{
			if (!__state.SkipAllPostfixes)
			{
				ResourceRedirection.Hook_AssetBundleLoaded_Postfix(__state.Parameters, ref __result);
			}
			if ((Object)(object)__result != (Object)null && __state.Parameters.Path != null)
			{
				ExtensionDataHelper.GetOrCreateExtensionData<AssetBundleExtensionData>((object)__result).Path = __state.Parameters.Path;
			}
		}

		private static void MM_Init(object detour)
		{
			_original = DetourExtensions.GenerateTrampolineEx<OriginalMethod>(detour);
		}

		private static AssetBundle MM_Detour(byte[] binary, uint crc)
		{
			AssetBundle __result = null;
			AssetBundleLoadingContext __state = null;
			if (Prefix(ref binary, ref crc, ref __result, ref __state))
			{
				__result = _original(binary, crc);
			}
			Postfix(ref __result, ref __state);
			return __result;
		}
	}
	internal static class AssetBundle_LoadFromStreamAsync_Hook
	{
		private delegate AssetBundleCreateRequest OriginalMethod(Stream stream, uint crc, uint managedReadBufferSize);

		private static OriginalMethod _original;

		private static bool Prepare(object instance)
		{
			return UnityTypes.AssetBundle != null;
		}

		private static MethodBase TargetMethod(object instance)
		{
			TypeContainer assetBundle = UnityTypes.AssetBundle;
			MethodInfo methodInfo = AccessToolsShim.Method((assetBundle != null) ? assetBundle.ClrType : null, "LoadFromStreamAsyncInternal", new Type[3]
			{
				typeof(Stream),
				typeof(uint),
				typeof(uint)
			});
			if ((object)methodInfo == null)
			{
				TypeContainer assetBundle2 = UnityTypes.AssetBundle;
				methodInfo = AccessToolsShim.Method((assetBundle2 != null) ? assetBundle2.ClrType : null, "LoadFromStreamAsync", new Type[3]
				{
					typeof(Stream),
					typeof(uint),
					typeof(uint)
				});
			}
			return methodInfo;
		}

		private static bool Prefix(ref Stream stream, ref uint crc, ref uint managedReadBufferSize, ref AssetBundleCreateRequest __result, ref AsyncAssetBundleLoadingContext __state)
		{
			AssetBundleLoadingParameters parameters = new AssetBundleLoadingParameters(null, null, crc, 0uL, stream, managedReadBufferSize, AssetBundleLoadType.LoadFromMemory);
			__state = ResourceRedirection.Hook_AssetBundleLoading_Prefix(parameters, out __result);
			AssetBundleLoadingParameters parameters2 = __state.Parameters;
			stream = parameters2.Stream;
			crc = parameters2.Crc;
			managedReadBufferSize = parameters2.ManagedReadBufferSize;
			return !__state.SkipOriginalCall;
		}

		private static void Postfix(ref AssetBundleCreateRequest __result, ref AsyncAssetBundleLoadingContext __state)
		{
			ResourceRedirection.Hook_AssetBundleLoading_Postfix(__state, __result);
		}

		private static void MM_Init(object detour)
		{
			_original = DetourExtensions.GenerateTrampolineEx<OriginalMethod>(detour);
		}

		private static AssetBundleCreateRequest MM_Detour(Stream stream, uint crc, uint managedReadBufferSize)
		{
			AssetBundleCreateRequest __result = null;
			AsyncAssetBundleLoadingContext __state = null;
			if (Prefix(ref stream, ref crc, ref managedReadBufferSize, ref __result, ref __state))
			{
				__result = _original(stream, crc, managedReadBufferSize);
			}
			Postfix(ref __result, ref __state);
			return __result;
		}
	}
	internal static class AssetBundle_LoadFromStream_Hook
	{
		private delegate AssetBundle OriginalMethod(Stream stream, uint crc, uint managedReadBufferSize);

		private static OriginalMethod _original;

		private static bool Prepare(object instance)
		{
			return UnityTypes.AssetBundle != null;
		}

		private static MethodBase TargetMethod(object instance)
		{
			TypeContainer assetBundle = UnityTypes.AssetBundle;
			MethodInfo methodInfo = AccessToolsShim.Method((assetBundle != null) ? assetBundle.ClrType : null, "LoadFromStreamInternal", new Type[3]
			{
				typeof(Stream),
				typeof(uint),
				typeof(uint)
			});
			if ((object)methodInfo == null)
			{
				TypeContainer assetBundle2 = UnityTypes.AssetBundle;
				methodInfo = AccessToolsShim.Method((assetBundle2 != null) ? assetBundle2.ClrType : null, "LoadFromStream", new Type[3]
				{
					typeof(Stream),
					typeof(uint),
					typeof(uint)
				});
			}
			return methodInfo;
		}

		private static bool Prefix(ref Stream stream, ref uint crc, ref uint managedReadBufferSize, ref AssetBundle __result, ref AssetBundleLoadingContext __state)
		{
			AssetBundleLoadingParameters parameters = new AssetBundleLoadingParameters(null, null, crc, 0uL, stream, managedReadBufferSize, AssetBundleLoadType.LoadFromMemory);
			__state = ResourceRedirection.Hook_AssetBundleLoading_Prefix(parameters, out __result);
			AssetBundleLoadingParameters parameters2 = __state.Parameters;
			stream = parameters2.Stream;
			crc = parameters2.Crc;
			managedReadBufferSize = parameters2.ManagedReadBufferSize;
			return !__state.SkipOriginalCall;
		}

		private static void Postfix(ref AssetBundle __result, ref AssetBundleLoadingContext __state)
		{
			if (!__state.SkipAllPostfixes)
			{
				ResourceRedirection.Hook_AssetBundleLoaded_Postfix(__state.Parameters, ref __result);
			}
			if ((Object)(object)__result != (Object)null && __state.Parameters.Path != null)
			{
				ExtensionDataHelper.GetOrCreateExtensionData<AssetBundleExtensionData>((object)__result).Path = __state.Parameters.Path;
			}
		}

		private static void MM_Init(object detour)
		{
			_original = DetourExtensions.GenerateTrampolineEx<OriginalMethod>(detour);
		}

		private static AssetBundle MM_Detour(Stream stream, uint crc, uint managedReadBufferSize)
		{
			AssetBundle __result = null;
			AssetBundleLoadingContext __state = null;
			if (Prefix(ref stream, ref crc, ref managedReadBufferSize, ref __result, ref __state))
			{
				__result = _original(stream, crc, managedReadBufferSize);
			}
			Postfix(ref __result, ref __state);
			return __result;
		}
	}
	internal static class AssetBundle_mainAsset_Hook
	{
		private delegate Object OriginalMethod(AssetBundle __instance);

		private static OriginalMethod _original;

		private static bool Prepare(object instance)
		{
			TypeContainer assetBundle = UnityTypes.AssetBundle;
			return (object)AccessToolsShim.Method((assetBundle != null) ? assetBundle.ClrType : null, "returnMainAsset", new Type[1] { typeof(AssetBundle) }) == null;
		}

		private static MethodBase TargetMethod(object instance)
		{
			TypeContainer assetBundle = UnityTypes.AssetBundle;
			return AccessToolsShim.Property((assetBundle != null) ? assetBundle.ClrType : null, "mainAsset")?.GetGetMethod();
		}

		private static bool Prefix(AssetBundle __instance, ref Object __result, ref AssetLoadingContext __state)
		{
			AssetLoadingParameters parameters = new AssetLoadingParameters(null, null, AssetLoadType.LoadMainAsset);
			__state = ResourceRedirection.Hook_AssetLoading_Prefix(parameters, __instance, ref __result);
			return !__state.SkipOriginalCall;
		}

		private static void Postfix(AssetBundle __instance, ref Object __result, ref AssetLoadingContext __state)
		{
			if (!__state.SkipAllPostfixes)
			{
				ResourceRedirection.Hook_AssetLoaded_Postfix(__state.Parameters, __instance, ref __result);
			}
		}

		private static void MM_Init(object detour)
		{
			_original = DetourExtensions.GenerateTrampolineEx<OriginalMethod>(detour);
		}

		private static Object MM_Detour(AssetBundle __instance)
		{
			Object __result = null;
			AssetLoadingContext __state = null;
			if (Prefix(__instance, ref __result, ref __state))
			{
				__result = _original(__instance);
			}
			Postfix(__instance, ref __result, ref __state);
			return __result;
		}
	}
	internal static class AssetBundle_returnMainAsset_Hook
	{
		private delegate Object OriginalMethod(AssetBundle __instance);

		private static OriginalMethod _original;

		private static bool Prepare(object instance)
		{
			TypeContainer assetBundle = UnityTypes.AssetBundle;
			return (object)AccessToolsShim.Method((assetBundle != null) ? assetBundle.ClrType : null, "returnMainAsset", new Type[1] { typeof(AssetBundle) }) != null;
		}

		private static MethodBase TargetMethod(object instance)
		{
			TypeContainer assetBundle = UnityTypes.AssetBundle;
			return AccessToolsShim.Method((assetBundle != null) ? assetBu